Packages

Advanced Self-Optimizing Distributed Multi-Agent System with Quantum Coordination

Current section

Files

Jump to
agents src agent_protocol.erl
Raw

src/agent_protocol.erl

%% agent_protocol.erl
%% Protocol and message format specification for agent communication
-module(agent_protocol).
%% API for message creation
-export([
create_message/3,
create_request/3,
create_response/4,
create_broadcast/2,
create_event/3
]).
%% API for message validation
-export([
validate_message/1,
is_request/1,
is_response/1,
is_broadcast/1,
is_event/1
]).
%% API for message extraction
-export([
get_sender/1,
get_receiver/1,
get_message_id/1,
get_payload/1,
get_type/1,
get_correlation_id/1,
get_timestamp/1
]).
%% Message type constants
-define(TYPE_REQUEST, <<"request">>).
-define(TYPE_RESPONSE, <<"response">>).
-define(TYPE_BROADCAST, <<"broadcast">>).
-define(TYPE_EVENT, <<"event">>).
-define(TYPE_ERROR, <<"error">>).
%% API Functions
%% Create a generic message
-spec create_message(Type, Sender, Payload) -> Message when
Type :: binary(),
Sender :: binary() | atom(),
Payload :: map(),
Message :: map().
create_message(Type, Sender, Payload) ->
#{
type => Type,
id => generate_id(),
sender => ensure_binary(Sender),
timestamp => erlang:system_time(millisecond),
payload => Payload
}.
%% Create a request message
-spec create_request(Sender, Receiver, Payload) -> Message when
Sender :: binary() | atom(),
Receiver :: binary() | atom(),
Payload :: map(),
Message :: map().
create_request(Sender, Receiver, Payload) ->
(create_message(?TYPE_REQUEST, Sender, Payload))#{
receiver => ensure_binary(Receiver)
}.
%% Create a response message
-spec create_response(CorrelationId, Sender, Receiver, Payload) -> Message when
CorrelationId :: binary(),
Sender :: binary() | atom(),
Receiver :: binary() | atom(),
Payload :: map(),
Message :: map().
create_response(CorrelationId, Sender, Receiver, Payload) ->
(create_message(?TYPE_RESPONSE, Sender, Payload))#{
receiver => ensure_binary(Receiver),
correlation_id => CorrelationId
}.
%% Create a broadcast message
-spec create_broadcast(Sender, Payload) -> Message when
Sender :: binary() | atom(),
Payload :: map(),
Message :: map().
create_broadcast(Sender, Payload) ->
create_message(?TYPE_BROADCAST, Sender, Payload).
%% Create an event message
-spec create_event(Sender, EventName, EventData) -> Message when
Sender :: binary() | atom(),
EventName :: binary() | atom(),
EventData :: map(),
Message :: map().
create_event(Sender, EventName, EventData) ->
create_message(?TYPE_EVENT, Sender, #{
event => ensure_binary(EventName),
data => EventData
}).
%% Validate a message
-spec validate_message(Message) -> Result when
Message :: map(),
Result :: ok | {error, Reason},
Reason :: term().
validate_message(Message) when is_map(Message) ->
% Required fields for all messages
RequiredFields = [type, id, sender, timestamp, payload],
% Check if all required fields are present
case lists:all(fun(Field) -> maps:is_key(Field, Message) end, RequiredFields) of
false ->
{error, missing_required_fields};
true ->
% Type-specific validation
Type = maps:get(type, Message),
validate_by_type(Type, Message)
end;
validate_message(_) ->
{error, not_a_map}.
%% Check if a message is a request
-spec is_request(Message) -> boolean() when
Message :: map().
is_request(Message) ->
maps:get(type, Message, undefined) =:= ?TYPE_REQUEST.
%% Check if a message is a response
-spec is_response(Message) -> boolean() when
Message :: map().
is_response(Message) ->
maps:get(type, Message, undefined) =:= ?TYPE_RESPONSE.
%% Check if a message is a broadcast
-spec is_broadcast(Message) -> boolean() when
Message :: map().
is_broadcast(Message) ->
maps:get(type, Message, undefined) =:= ?TYPE_BROADCAST.
%% Check if a message is an event
-spec is_event(Message) -> boolean() when
Message :: map().
is_event(Message) ->
maps:get(type, Message, undefined) =:= ?TYPE_EVENT.
%% Extract sender from a message
-spec get_sender(Message) -> Sender when
Message :: map(),
Sender :: binary().
get_sender(Message) ->
maps:get(sender, Message).
%% Extract receiver from a message
-spec get_receiver(Message) -> Receiver when
Message :: map(),
Receiver :: binary() | undefined.
get_receiver(Message) ->
maps:get(receiver, Message, undefined).
%% Extract message ID
-spec get_message_id(Message) -> Id when
Message :: map(),
Id :: binary().
get_message_id(Message) ->
maps:get(id, Message).
%% Extract payload
-spec get_payload(Message) -> Payload when
Message :: map(),
Payload :: map().
get_payload(Message) ->
maps:get(payload, Message).
%% Extract message type
-spec get_type(Message) -> Type when
Message :: map(),
Type :: binary().
get_type(Message) ->
maps:get(type, Message).
%% Extract correlation ID
-spec get_correlation_id(Message) -> CorrelationId when
Message :: map(),
CorrelationId :: binary() | undefined.
get_correlation_id(Message) ->
maps:get(correlation_id, Message, undefined).
%% Extract timestamp
-spec get_timestamp(Message) -> Timestamp when
Message :: map(),
Timestamp :: integer().
get_timestamp(Message) ->
maps:get(timestamp, Message).
%% Internal Functions
%% Generate a unique message ID
generate_id() ->
erlang:list_to_binary(uuid:uuid_to_string(uuid:get_v4())).
%% Ensure a term is binary
ensure_binary(Term) when is_atom(Term) ->
atom_to_binary(Term, utf8);
ensure_binary(Term) when is_list(Term) ->
list_to_binary(Term);
ensure_binary(Term) when is_binary(Term) ->
Term;
ensure_binary(Term) ->
term_to_binary(Term).
%% Validate a message based on its type
validate_by_type(?TYPE_REQUEST, Message) ->
% Request must have a receiver
case maps:is_key(receiver, Message) of
true -> ok;
false -> {error, missing_receiver}
end;
validate_by_type(?TYPE_RESPONSE, Message) ->
% Response must have a receiver and correlation_id
case {maps:is_key(receiver, Message), maps:is_key(correlation_id, Message)} of
{true, true} -> ok;
{false, _} -> {error, missing_receiver};
{_, false} -> {error, missing_correlation_id}
end;
validate_by_type(?TYPE_BROADCAST, _Message) ->
% Broadcasts only need the common fields
ok;
validate_by_type(?TYPE_EVENT, Message) ->
% Event must have a properly structured payload with event name and data
Payload = maps:get(payload, Message, #{}),
case {maps:is_key(event, Payload), maps:is_key(data, Payload)} of
{true, true} -> ok;
{false, _} -> {error, missing_event_name};
{_, false} -> {error, missing_event_data}
end;
validate_by_type(_, _) ->
{error, invalid_message_type}.