Practical 1 Introduction to JACK

Practical 1 provides an introduction to JACK agents, plans, events and capabilities. The notes are based on the material in the JACK™ Intelligent Agents Agent Manual and provide a summary of the features that you need to be familiar with to complete the programming exercises. For more details refer to the Agent Manual. When the prerequisite information has been covered for a particular exercise, it is indicated explicitly in the notes. In some cases additional information is provided in the introduction for the exercise. It is assumed that you are familiar with Java and are able to develop and run Java applications in your computing environment.

The Practical exercises will be developed using the JACK Development Environment. It is assumed that the reader is familiar with the overall structure and operation of the JDE. If this is not the case then at least Chapters 1 and 2 of the JACK™ Intelligent Agents Development Environment Manual should be read before commencing the exercises. No additional material regarding the JDE is provided in these notes.


Introductory notes

JACK

JACK™ Intelligent Agents (JACK) is an agent-oriented development environment built on top of and fully integrated with the Java programming language. JACK consists of the key components described below.

The JACK Agent Language

The JACK Agent Language (JAL) is a programming language that can be used to develop agent-based systems. JAL is a 'super-set' of Java – encompassing the full Java syntax while extending it with agent-oriented constructs.

The JACK Agent compiler

The JACK Agent Compiler pre-processes JAL source files and converts them into Java. This Java source code can then be compiled into Java virtual machine code to run on the target system.

The JACK Agent kernel

The JACK Agent kernel is the runtime engine for programs written in JAL. It provides a set of classes that give JAL programs their agent-oriented functionality. Most of these classes run behind the scenes and implement the underlying infrastructure and functionality that agents require. Others are used explicitly in JAL programs. They are inherited from and supplemented with callbacks as required to provide agents with their own unique functionality.

The JACK Development Environment

The JDE is a cross-platform graphical development environment that can be used to develop JACK agent applications. In addition to providing support for code generation, tools are provided to support the design process and the tracing of agent execution.

The JACK Agent Language

JAL extends Java by:

Class-level constructs

Agent, Event, Plan, Beliefset, View and Capability class-level constructs are provided in JACK. Each of these are implemented as Java classes.

To create your own agent, the Agent class is extended and the particular details required for your specific agent are included. A similar approach is used to create your own events, plans, beliefsets and capabilities.

JACK declarations

These provide a set of statements that define properties of a JAL type and declare relationships between the classes above. They are preceded by a # symbol.

JACK reasoning method statements (@-statements)

Reasoning statements are JAL statements that can only appear in reasoning methods. Reasoning methods are found inside a plan. Reasoning method statements are preceded by an @ symbol.

Semantic extensions

JAL provides semantic extensions that support the Belief Desire Intention (BDI) execution model.

JACK execution

When an agent is instantiated in a system, it will wait until it is given a goal or it experiences an event to which it must respond. When it receives an event (or goal), the agent initiates activity to handle the event. If it does not believe that the goal or event has already been handled, it will look for the appropriate plan(s) to handle it. The agent then executes the plan or plans depending on the event type. The handling of the event may be synchronous or asynchronous relative to the posting. The plan execution may involve interaction with an agent's beliefset relations or other Java data structures. The plan being executed can in turn initiate other subtasks, which may in turn initiate further subtasks (and so on). Plans can succeed or fail. Under certain circumstances, if the plan fails, the agent may try another plan.

Within a single process you can have multiple agents and each agent potentially has multiple task queues. A task queue is generated when an asynchronous event is received by the agent (either from itself or from another agent). The task queue contains the processing steps (or tasks) that are required for the agent to handle the event – these steps are specified in a plan. Task execution can result in further event posting. If the event is posted synchronously, the resulting tasks are added to the head of the task queue that generated the event. If the event is posted asynchronously, a new task queue will be generated.

The JACK kernel is responsible for giving each agent a 'turn'. Within an agent, a task manager is responsible for cycling through the task queues (exactly how will depend on the task manager being used by the agent). This is all managed by the JACK kernel within the JACK thread of execution. Note that this does not prevent other threads in the Java program from calling agent methods. You will see examples where an agent method is invoked from the Java main thread in the exercises.

Of course, you can also have agents in different processes and on different machines communicating with one another.

The Agent class

The Agent class embodies the functionality associated with a JACK intelligent agent. To define your own agents, the JACK Agent class is extended by adding members and methods that are applicable to your agent's specific problem domain.

Agent template

In a file called AgentType.agent:

  agent AgentType extends Agent {implements interface}
  {
     // JAL declaration statements - the following declarations may be
     // used in an agent definition (when required).

     #{private,agent,global} data Type Name (arglist);

     // The agent handles events of type EventType.
     #handles event EventType;

     // The agent uses a plan of PlanType.
     #uses plan PlanType;

     // The round robin task manager is to be used - there are others.
     #uses taskManager SimpleRRTaskManager(steps);

     // The agent posts events of type EventType to itself.
     #posts event EventType reference;

     // The agent sends events of type EventType to other agents.
     #sends event EventType reference;

     // The agent has a capability of type CapabilityType.
     #has capability CapabilityType reference;

     // Data members (Java data structures).

     // Constructor method.
     AgentType(arglist)
     {
       super("agent name");
        :
        :
     }

     // Java methods that implement agent functionality.
     // (These may be called from within the agent's plans.)
  }

Agent base members

Timer timer

Specifies which clock the agent uses to measure the passage of time.

Agent base methods

Constructor

To construct an agent, follow the normal convention for constructors used in Java. JACK agents require a name (of type String).

finish()

Used to terminate an agent. It causes all event processing within the agent to be terminated immediately, and removes the agent from the JACK runtime network.

postEvent(EventName)

This allows an agent to post an event to itself. The event is handled asynchronously by the agent. The parameter is an instance of an event. As event posting methods are responsible for the creation of an instance of an event, postEvent() is often invoked with an argument that involves the event's posting method as shown below.

 postEvent(eventRef.eventPostingMethod(args))

Note that eventRef must have been declared to be an event that is handled by the agent (#handles event EventType eventRef;), and the event must also have a corresponding posting method. The EventName parameter that is found in the methods described below is often replaced by an argument that involves the event's posting method.

postEventAndWait(EventName)

This is similar to postEvent() except that it is posted synchronously. The event is still executed as a separate task, but the calling method must wait until this task has been completed before continuing.


Note: Unlike an agent's other base methods, postEventAndWait() must not be called from any of an agent's tasks as it will block the agent. It can only be used from methods used by normal Java programs or other Java threads that are integrated with your JACK application. While the agent handles this event, the calling thread must wait until the agent returns its result. You will be using postEventAndWait() in the exercises.

send(name, EventName)

This method is used to send messages/events to other agents. The first parameter (name) is of type String and is the name of the destination agent. The second parameter is the message event to be sent to the destination agent. Only certain event types can be used for inter-agent communication. This will be discussed later in this document.

reply(receivedMessageEvent, SendEventName)

reply() is used to send a message back to an agent from which a previous message has been received. reply() does not specify the destination agent – this information is contained in the message that it received.

The reply message arrives as a data object on the reply queue of the original message event. This means that the message event that is sent back using reply does not trigger a new task or plan.

name()

This method can be used to retrieve the agent's name as a String.

An example

In MyAgent.agent:

  agent MyAgent extends Agent
  {
    #handles event MyEvent;
    #uses plan MyPlan;
    #posts event MyEvent myEventRef;

    MyAgent(String name)
    {
      super(name);
    }

    public void method1(String exampleMessage)
    {
      // Java code to do something useful

      // In this example, we illustrate how to post an event from
      // within an agent.
      // The posting method will be discussed in the section on events.
      // In this case, the posting method takes a single argument of
      // type String.
      // Note that myEventRef has been declared earlier in the agent.

      postEvent(myEventRef.myPostingMethod(exampleMessage));
    }
  }


Note: You may attempt exercise 1 now.

The Event class

Events are the originators of all activity within JACK. There are a number of Event classes in JACK. They can be categorised into the two broad categories of normal events and BDI events.

Normal events

Normal events correspond to events in conventional event-driven programming. They are transitory and initiate a single immediate response. On receipt of the event, the agent selects an appropriate plan which either succeeds or fails. If the chosen plan fails, the agent does not try another plan.The normal event classes are:

Event Type Description
Event Base class for all normal events. Can only be posted internally.
MessageEvent Can be used to send events between agents.

BDI events

These are used to represent a change in belief or circumstance that give the agent a sense of purpose. The agent desires not to react to information, but rather to achieve something. By default, all BDI agents can involve meta-level reasoning (i.e. reasoning about plan selection). Depending on the type of BDI event (and the event's behaviour attributes) the agent may try alternative plans and may even perform recalculation of the applicable plan set before selecting another plan to try. The BDI event classes are described in the following table.

Event Type Description
BDIFactEvent This type of event can only arise internally. By default, on receipt of a BDIFactEvent, the agent can perform meta-level reasoning, but it does not allow reconsideration of alternative plans if the plan fails.
BDIMessageEvent This type of event can be used to send BDI events between agents. By default, on receipt of a BDIMessageEvent, the agent can perform meta-level reasoning, but it does not allow reconsideration of alternative plans if the plan fails.
BDIGoalEvent This type of event represents a goal or objective that an agent wishes to achieve. It offers all the BDI features – meta-level reasoning, recalculation of the applicable plan set and plan re-selection if a plan fails. It can originate from within an agent using @post, @subtask etc. In addition, it can originate as a result of executing @achieve, @insist, @test and @determine statements.

Note that there are two other event classes to consider.

Event Type Description
InferenceGoalEvent This is an event that uses Rule behavior which extends BDI behavior by processing all applicable plans.
PlanChoice This is the mechanism the agent uses to perform meta-level reasoning.

The brief descriptions given above of the BDI events are of the default behaviours that occur when the event arises. This default behaviour can be modified by setting the behaviour attributes of an event using #set behavior statements in the event to set the values of particular attributes. InferenceGoalEvents can also be customised by setting behaviour attributes. Details of the attributes can be found in the Agent Manual.

Event template

To define your own events, extend the appropriate JACK event class. Then add any members required as part of the event structure. These members can then be used to convey information to the agent when it receives the event. It is also necessary to specify at least one posting method for the event.

We will illustrate the event template using the base class Event. Note that to define an event to extend one of the other event types described earlier, you would replace Event with the specific event type required: i.e. MessageEvent, BDIFactEvent, BDIMessageEvent, BDIGoalEvent, InferenceGoalEvent or PlanChoice.

In a file called EventType.event:

  event EventType extends Event
  {
    // Any members required as part of the event structure.

    // Any declarations required to give the agent access to data or
    // beliefsets within the enclosing agent or capability.

    #uses data DataType data_name;

    // Any #posted when declarations required so that the event
    // will be posted automatically when certain belief states arise.

    #posted when { condition }

    // Declarations specifying how the event is posted within an agent.
    // You can have as many posting methods as you require.

    #posted as postingMethodName(parameter list)
    {
      // method body
    }
  }

A posting method is executed whenever an instance of the event needs to be created. The posting method describes everything that the agent needs to do to construct an instance of the event.

Event base members

The actual base members will depend on the specific event type. They are:

Member Description
String from This member contains the address of the agent from which the event was sent. It is only present in the events that are used for inter-agent communication e.g. MessageEvents.
String message This member is found in MessageEvent and BDIMessageEvent events. The information in message is used in the interaction diagram display.
String mode This member is only found in BDIGoalEvents. It indicates whether the event arose from @achieve, @insist, @test or @determine.

Event methods

Cursor replied()

This method returns a cursor which can be true or false depending on whether or not an agent has received any replies to a given message event. A cursor is a special type provided by JACK. Cursors can be tested multiple times, and each time they are tested they may return a different truth value. They are discussed in more detail in the Agent Manual, but at this point it is sufficient to understand that this method can allow the agent to wait for a reply to a message before it continues with a given task.

MessageEvent getReply()

This complements replied(). It allows you to retrieve a reference to a message event that has been sent as a reply. If there are no replies it returns null. Again this method is only provided for message events.

An example

In MyEvent.event

  // Compare this with the earlier agent example.

  event MyEvent extends BDIGoalEvent
  {
    String text; // For example.

    #posted as
    myPostingMethod(String s)
    {
      text = s;
    }
  }

The Plan class

A plan describes a sequence of actions that an agent can take when an event occurs. Each plan is capable of handling a single event. When an agent executes a plan, it starts by executing the plan's body() method – i.e. its top level reasoning method.

Reasoning methods are not the same as normal Java methods. Each statement in a reasoning method is treated as a logical statement that can either pass or fail. Unless the plan explicitly caters for the possibility of a statement's failure (through, for example, an if-else construct), failure of a statement causes a reasoning method to fail. If an agent reaches the end of a reasoning method, then the reasoning method has succeeded. If it reaches the end of the body() reasoning method, then the plan has succeeded.

Plan template

The template below can be used for any plans that do not involve meta-level reasoning.

In a file called PlanType.plan

  plan PlanType extends Plan
  {
    // JAL declarations
    #handles event EventType eventref;

    // The following JAL declarations may be used in a plan definition
    // (as required).
    #posts event EventType eventref2;
    #sends event MessageEventType eventref3;
    #uses data Type ref;
    #reads data Type ref;
    #modifies data Type ref;
    #uses agent implementing InterfaceName agentref;
    #uses interface InterfaceName ref;

    #reasoning method methodName(parameter-list)
    {
      //Body of the reasoning method.
    }

    #reasoning method pass()
    {
      // Post-processing and clean up steps when the plan has succeeded.
    }

    #reasoning method fail()
    {
      // Post-processing and clean up steps when the plan has failed.
    }

    static boolean relevant (EventType eventref)
    {
      // Code to determine when the plan is relevant to eventref.
    }

    context()
    {
      // Logical condition to determine which plan instances are
      // applicable.
    }

    // The main reasoning method. All plans must have a body().
    body()
    {
      // The plan body – the actual steps performed when
      // the plan is executed.
    }
  }

Note that reasoning methods can include special reasoning statements preceded by @. They are @achieve, @determine, @insist, @maintain, @post, @reply, @send, @sleep, @subtask, @test and @waitFor. These reasoning statements can only be used inside plans. For more details regarding the reasoning statements, refer to the Agent Manual.

Plan base members

Agent agent

Identifies the agent to which the plan belongs

Plan base methods

Method Description
relevant() This was shown in the template and is discussed in the exercises.
context() This was shown in the template and is discussed in the exercises.
getInstanceInfo() This is used to retrieve information about the instance of the plan it is called on. It has been provided for use in meta-level reasoning plans. It is not discussed further in this practical.

An example

In a file MyPlan.plan

  // Compare this with the example event and agent classes.
  plan MyPlan extends Plan
  {
    #handles event MyEvent me;

    body()
    {
      System.out.println(me.text);
    }
  }

Building our example

We could test the example (which consists of MyAgent.agent, MyEvent.event and MyPlan.plan) with the following main program:

  public class Program
  {
    public static void main(String args[])
    {
      MyAgent agent1 = new MyAgent("agent1");
      agent1.method1("data to be posted");
    }
  }


Note: You may attempt exercises 2 to 5 now.

The Capability class

Capabilities represent functional aspects of an agent that can be 'plugged in' as required. Capabilities are built in a similar fashion to simple agents – constructing them involves declaring the JAL elements required. Events, beliefsets, plans, Java code and other capabilities can all be combined to make a capability.

Capability template

In a file called CapabilityType.cap:

  capability CapabilityType extends Capability [implements Interface]
  {
    // JAL declarations specifying the functionality associated with
    // the capability. The following declarations may be used in a
    // capability definition.
    #handles event EventType;
    #handles external {event} EventType;
    #posts event EventType {reference};
    #posts external event EventType {reference};
    #private data Type name({args});
    #exports data Type name({args});
    #imports data Type name();
    #uses plan PlanType;
    #has capability CapabilityType reference;

    // Other data members and method definitions.
  }

Capability methods

String toString()

Capabilities do not have a name in the sense that agents do, but they can be referred to through the chain of reference names used in the #has capability statements. The reference name can be retrieved by calling the toString() method.

void postEvent( Event event )

The postEvent method is used to post events within capability code.

Agent getAgent()

If this method is called on a capability, it returns the containing agent.

protected void autorun()

This method can be overridden in order to provide some initialisation when the capability is actually brought into being.

An example

In a file called MyCapability.cap:

  capability MyCapability extends Capability
  {
    #handles event MyEvent;
    #uses plan MyPlan;
  }

The Beliefset class

JACK provides a Beliefset class which has been specifically designed to work within the agent-oriented paradigm. The JACK Beliefset class is described in detail in the notes provided with practical 2.


Note: You may now complete the practical 1 exercises 6 to 11.

Exercise 1