home » user manual » events & messages

Agent events and messages

Events are central to the operation of Nuin agents. Events convey signals from the agents' environment, representing the agents' sensing of the world. A particular case is the exchange of messages between agents in a multi-agent system. Events are also used to co-ordinate the operation of the Nuin interpreter loop, and provide one means of interaction between the agent core and the services that the agent is configured with. Patterns of events and messages are used to trigger plans, causing agents to form intentions.

As noted here, detecting an event, or pattern of events, is a key means for agents to form an intention to act. For example, the arrival of an incoming message is such an event. This message might, for example, request the agent to answer a query, and so the agent forms an intention to reply to the message. Responding to an event in this way is such a common pattern in agent programming that Nuin defines message to be a sub-class of event, so a message may be used directly as a component of an event pattern (see examples).

Events are crucial also to the internal operation of agent interpreter. Most of the internal signalling of agent processes occurs with events. Thus, when an intention I0 suspends until sub-intention I1 completes (see section TODO for various means of achieving this), intention I0 will be re-awoken from the dormant intentions queue when the intention-completed or intention-failed event is raised from I1.

Consequently, events and messages are first-class values in the Nuin KS representation language. An event is encoded as a term (TODO hyperlink), which has functor ks:event, and always has arity one. The single term-argument denotes the type of the event. This event type is represented by a symbol or term. If a term is used for the event type, the functor of the term denotes the actual event type, and the term-arguments denote arguments to the event itself. Event arguments may also be specified using the named argument syntax (which is the typical way to encode the arguments of messages).

Because events are central to the Nuin architecture, a special syntax is used to encode events in Nuinscript, rather than the standard term syntax. Specifically, the keyword event is followed directly by the event type, and optionally by the named arguments. Some examples:

 // an event of type e
 event e
 
 // an event of type e with argument 10
 event e( 10 )
 
 // an event of type e with a single named argument
 event e {sender = market:seller}

Messages are encoded as sub-types of events. Specifically, a message is an event whose event type is ks:message. The Nuinscript syntax for a message is the keyword message followed by the message arguments:

 // a message with two fixed (positional) arguments
 message( market:seller, 10 )
 
 // a message with two named arguments
 message() {sender = market:seller, qty = 10}

Messages typically use the named argument syntax, since different messages may have very different roles to play and different content to transmit. While messages may use any encoding scheme, the FIPA ACL standard is a commonly used choice. The FIPA vocabulary is encoded in Nuin via a set of built-in OWL ontologies: faa.owl presenting terms from the FIPA abstract architecture, fipa-acl.owl presenting terms from the FIPA ACL standard, and fipa-sl.owl presenting terms from the FIPA SL content language standard. Important note these terms do not use a FIPA-approved ontology namespace. FIPA has not yet, at the time of writing, defined or formally sanctioned set of OWL-compliant names for the components of messages. The Nuin mappings of FIPA terms may well change in future as this situation changes. The Nuin-Jade gateway (TODO ref) transparently handles mapping between the OWL-encoded FIPA terms used by Nuin agents, and the s-expresion syntax used for message encoding by Jade agents.

The namespace prefixes for the FIPA vocabularies is built-in to the standard prefix mapping, and hence available in Nuinscript. Thus the following shows a message in FIPA ACL s-expression syntax, and the corresponding message in Nuinscript:

 (request
   :sender a@hap
   :receiver (set (agent-identifier :name b@hap)) )
   :content "buy buy buy, bye-bye"
 )
 
  message() {
    acl:performative = acl:request
    acl:sender = a1,
    acl:receiver = [b],
    acl:content = "buy buy buy, bye-bye"
 }
      

Notice in the above example that the agent in Nuinscript is addressed using the name of the agent only. This is in keeping with the principles of the FIPA abstract architecture, but differs from the implementation in Jade, where the current location of the agent is regarded as part of the name. This problem is addressed in detail here.

Using events and messages from Java

While much of the agent's event and message handling can be specified with Nuinscript, there are occasions, e.g. when programming more complex services, when events must be created or accessed from Java. The Javadoc supplies full details of the available methods, but we summarise some of the key points below.

Events are represented by instances of the KsEvent interface, and messages by the KsMessage interface. Both are defined in the org.nuin.ks.values package. As is common throughout Nuin, instances of these interfaces are created by factory objects. While redefining the factories represents a useful extension point for advanced applications, the default value factory (accessed by The.valueFactory()) suffices for most purposes. To create a new event of type "alarm" in some namespace NS but with no event arguments, use:

  KsSymbol alrm = The.valueFactory().newSymbol( NS + "alarm" );
  KsEvent alrmEv = The.valueFactory().newEvent( alrm );
      

Creating a message is similar, noting that message bodies are usually specified using named parameters:

  KsSymbol agentA = ... ; // URI of agent A
  Map params = new Hashmap();
  params.put( FipaACLVocab.RECEIVER, agentA );
  
  KsMessage msg = The.valueFactory().newMessage( params );
      

The built-in vocabularies FipaACLVocab, FipaSLVocab, and FipaVocab provide Java constants that correspond to the symbols defined in the (Nuin versions of) the FIPA ACL, SL and abstract architecture terms respectively.

To deliver an event or message to an agent, use the method deliver. This can be called safely from another thread, and will add the event to the agent's event queue for processing.

Event patterns

An event pattern is used to trigger a plan. It is also used to suspend a current intention until some condition becomes true of the agent's environment. Event patterns are defined from a restricted propositional language, containing only two predicates on and after, and two connectives && for conjunction, and || for disjunction.

The on predicate takes a single event (or message) as argument. It is true exactly if the given event is the current event which is defined as the event object that the agent interpreter is currently processing. There is always one current event. The agent can also record a number of past events in its event history. Each agent has a separate current event and event history. The predicate after also takes an event as argument, and is true exactly if the given event is the current event, or it appears on the event history. This allows event expressions in which events are contextualised by recent events in the event history. For example, a robot might treat the following event pattern with some urgency:

 on event alarm( edgeDetected )  &&
 after event proximityBeacon( cliff )

The length of the event queue can be configured in the agent's initial configuration. The current history queue can also be cleared by the library action lib:clearEventHistory.

Note that matching of event patterns to actual events is performed by unification, so it is possible for non-ground patterns to extract information from concrete events. For example: on event alarm( ?alarmType ). This binds the variable ?alarmType to the event argument. It will unify against event whose type is alarm with one argument. To bind the whole event object, we can use a variable in place of an event term: on event ?e which binds ?e to any detected event. This can be useful, but it is unselective. To bind a variable to an entire event or message object while still performing unification on the event structure, we use the following idiom:

 on ?e as event alarm( ?eventType )

This binds event ?e to the whole event object, and ?eventType to the argument value, assuming the event unifies with the pattern. This idiom is particularly useful with messages. For example, to trigger a plan on any event arriving from a certain named agent (say, 'ex:vendor'), we could use the following event pattern as trigger in a plan:

 on ?msg as message() {acl:sender = ex:vendor}
      

Special events

Some special events are built-in to the agent interpreter. These are specified in events.owl, and available as vocabulary constants in EventVocab. Some of these events are for the internal use of the agent interpreter, and will not be commonly used by agent developers. More useful events include:

« prev: nuinscript | events and messages | next: agent configuration »