Agent Communication

Agents interact with one another in two basic ways: indirectly through shared resources or directly through some form of messaging service. Examples of indirect interaction include shared maps, tuple spaces, or any other shared resource. Examples of direct interaction are typically based around an Agent Communication Language (ACL) such as FIPA ACL or KQML. This section focuses on how ASTRA supports direct interaction through FIPA ACL-based message passing. ASTRA provides two layer of support for this form of interaction: basic message passing, and conversation-based interaction through ACRE.  ACRE is not covered here.

Types of Message

As was indicated above, ASTRA uses the FIPA ACL message format. This format defines the required contents of a FIPA-compliant message. All messages have a type that is defined by a performative, which must be one of the standard FIPA ACL Performatives:

accept-proposal agree cancel cfp confirm disconfirm
failure inform inform-if inform-ref not-understood propogate
propose proxy query-if query-ref refuse reject-proposal
request request-when request-whenever subscribe

To get started with understanding agent communication, this lesson will initially focus on request and inform messages.

Sending a Message

To send a message in ASTRA, you use the send(…) statement. This statement takes three arguments: a performative, the name of the receiver agent, and the actual content to be sent. For example, the following agent program defines an agent that send itself an “alive” message:

  package examples;
  
  agent Alive {
      module Console C;
      module System S;
      
      initial !init();
      
      rule +!init() {
          send(inform, S.name(), state("alive"));
      }
  }

Receiving a Message

Unfortunately, the agent cannot hear itself at the moment, as all it does is send a message. Messages are received by the agent and converted into events. ASTRA includes a special event to support this called an @message event. This event has three parameters:

  • the performative (type) of the message;
  • the name of the agent that sent the message; and
  • the content that was sent.

In order for the agent to hear the message, it is necessary to write a rule that handles the event:

  package examples;
  
  agent Alive {
      module Console C;
      module System S;
      
      initial !init();
      
      rule +!init() {
          send(inform, S.name(), state("alive"));
      }
      
      rule @message(inform, string sender, state(string X)) {
          C.println("i am alive!");
      }
  }

An Example Interaction

We can build a more interesting example by combining this basic idea of sending an “alive” message with some of the features of the System API that allow an agent to be aware of the agent that created it. In the example below, we define two programs: Master and Slave. The Master agent creates a Slave agent which sends a message back to the Master when it is created indicating that it is alive:

  package examples;
  
  agent Master {
      module Console C;
      module System S;
  
      initial !init();
  
      rule +!init() {
  	    S.createAgent("theslave", "examples.Slave");
      }
  
      rule @message(inform, string sender, state(string X)) {
          C.println(sender + " is alive!");
      }
  }
  
  package examples;
  
  agent Slave {
      module Console C;
      module System S;
  
      initial !init();
  
      rule +!init() {
          send(inform, S.getOwner(), state("alive"));
      }
  }

Running the master results in an agent called “theslave” being created. This agent then sends a message to its owner (the master) informing the master that it has is alive (it has been created). The master is then able to communicate with the slave and to ask it to perform tasks as necessary.