5 Events
5.1 What are Events?
Events motivate an agent to take action. There are a number of event types in JACK, each with different uses. These different event types help model:
Internal stimuli – events that an agent sends to itself, usually as a result of executing reasoning methods in plans that an agent has. These internal events are integral to the ongoing execution of an agent and the reasoning that it undertakes.
External stimuli – such as messages from other agents, or percepts that an agent receives from its environment.
Motivations – that the agent may have, such as goals that the agent is committed to achieving.
Events are the origin of all activity within an agent-oriented system. In the absence of events an agent sits idle. Whenever an event occurs, an agent initiates a task to handle it. This task can be thought of as a thread of activity within the agent. The task causes the agent to choose between the plans it has available, executing a selected plan or plan set (depending on the event processing model chosen) until it succeeds or fails.
If plan execution succeeds, the event that initiated it is said to have succeeded. If plan execution fails, there are two options. Under normal event handling, the event is said to have failed after the first instance of plan failure.
Under BDI event handling, a number of plans can be selected for execution and these are attempted in turn, in order to try to achieve successful plan execution. If the set of chosen plans is exhausted, the event is said to have failed.
Both cases are regarded as successful event handling.
There are a number of event classes in the JACK Agent Language, each representing different types of motivation to act. Additionally, there are event types available that facilitate analysis and debugging of inter-agent communication. In general, these events fall into two broad categories:
- Normal events, and
- BDI events.
5.2 Normal Events
Normal events in JACK are analogous to events in conventional event-driven programming. That is, they represent transitory occurrences that initiate a single, immediate response from an agent.
For example, suppose that an agent is being programmed to play soccer. If the agent receives a message from the simulation environment telling it where the ball is every second, this would be modelled as a normal event. It represents an occurrence that must be acted upon immediately or not at all. If the agent decides to do something (execute a plan instance) and that plan instance fails, it would not make sense to reconsider an alternative because the information that the agent is acting on is now out of date.
5.2.1 How an Agent handles Normal Events
When a normal event is received by an agent, the agent initiates a task to handle it. This task involves the agent selecting and executing the first plan that is both relevant and applicable to this event. These tests for relevance and applicability are performed on plans in the order that the #uses plan statements occur in the agent or capability code.
A plan is relevant to a given event if it has a #handles event declaration that matches the event, and its relevant() method succeeds when executed.
Note: If no plans are found that are relevant to a particular event, the event processing task fails and the system returns to a state where it is ready to process any other incoming events.
The agent then checks if the relevant plan is applicable in the current circumstance. It does this by executing the context() method of the plan. If the context() method succeeds, it is chosen as the plan that the agent will execute in response to the incoming event. If the context() method fails, the agent examines the next relevant plan.
Simple context() methods return either true or false, meaning that a single instance of the plan is either applicable or not applicable. However, more complex context() methods may include cursor expressions and involve binding of logical variables. These expressions attempt to unify a given expression with tuples in one or more beliefset relations. For every tuple that matches, the logical variables are bound. Each such match causes a separate plan instance to be generated.
In the case of normal event processing the first such plan instance is chosen as the plan that the agent will execute in response to the incoming event.
Each normal event is implemented as a JACK Agent Language class. Each event has a number of base members and methods to provide access to their functionality and data. Each of these base classes can be extended and unique members and methods added to events.
5.2.2 Normal Events in the JACK Agent Language
The JACK Agent Language normal event classes are listed below and are described in the following sub-sections:
Event Type | Description |
Event | Base class for all events in JACK. Posted and processed inside an agent to invoke plans, that may in turn post further events. |
MessageEvent | MessageEvents are received by agents from external sources – usually other agents. These are normally sent from one agent to another to facilitate inter-agent communication. |
Table 5-1: JACK normal event classes
5.2.2.1 The Event Class
The base class for all events in JACK is the Event class. This class implements all the core event functionality required by the JACK runtime environment. A normal Event is only ever generated by processing that occurs within an agent.
Events are always posted explicitly by statements within agent code. To say an agent posts an event means that an event is constructed and added to the agents own event queue to await processing. If an agent is idle, no code is being executed and an agent cannot post any events. In this case, an agent can only take action if an external (i.e. MessageEvent) arrives.
Events are posted:
- when an agent executes a @post statement from within a plan;
- when an agent executes either the postEvent() or postEventAndWait() base method from agent code; and
- when an agent modifies a beliefset relation for which a beliefset modification callback has been defined.
In each case, an instance of the event is posted using one of the event's posting methods. The posting method acts as the event's constructor, creating an instance of the event and making it available to the agent's task manager.
5.2.2.2 The MessageEvent Class
MessageEvents represent events that are used to communicate with other agents. Whenever an agent needs to send a question, command or message to another agent, this information is packaged and sent as a MessageEvent. Instead of representing an internal occurrence that initiates activity within the agent, MessageEvents represent an external occurrence that initiates activity within the agent.
MessageEvents can also be used as a mechanism to allow an agent to experience or perceive the environment in which it is executing. That is, anything affecting the agent that does not originate from the agent's own internal processing should be sent to the agent as a MessageEvent.
MessageEvents often represent transient requests that the agent may want to act upon. For example, if an agent is programmed to play a game such as soccer in a simulation environment, the environment may send the agent MessageEvents periodically to tell it where the ball is. Clearly, this is a message that is relevant and applicable only at the moment that it arrives. It serves to inform the agent about an external situation that may concern it. If the agent is a mid-fielder and it is sufficiently close, it may invoke a plan to attempt to intercept the ball. If it is not close enough it may try to cover a designated opponent. Alternatively, if the agent is a goal-keeper, it may attempt to move itself between the ball and the goal.
In each case, the agent is taking action on information that is applicable only at the moment at which it arrives. The agent must decide what to do with the information immediately, and once a course of action is chosen the information is discarded.
MessageEvents are sent to other agents:
- when an agent executes a @send statement from within a plan; or
- when an agent executes its send() base method.
Note: Agents should only execute the send() method in code outside a reasoning method. The @send statement is meant to be used to send message events to other agents from within a reasoning method.
In order for agents running in different processes to send and receive message events, the JACK runtime environment must provide a communication infrastructure with message routing capabilities. This is done using the JACK DCI network. The JACK DCI network enables the establishment of portals between processes, through which agent messages can be directed as needed. Refer to the Inter-agent Communications chapter for further details.
Note: All data fields within a MessageEvent must be serializable.
5.2.2.3 The TracedMessageEvent Class
The TracedMessageEvent class contains information which enables inter-agent communication to be effectively displayed via an Agent Interaction Diagram (refer to the Tracing and Logging Manual for more details on the Agent Interaction Diagram). This information is now available within the message event classes; consequently, TracedMessageEvent was deprecated in JACK version 3.5.
5.3 BDI Events
Belief-Desire-Intention (BDI) events represent a different class of event to the Event and MessageEvent described in the previous section.
One of the important aspects of the BDI reasoning model at a conceptual level is that it models goal-directed behaviour in agents, rather than plan-directed behaviour. That is, an agent commits to the desired outcome, not the method chosen to achieve it. While normal events represent transient information that the agent reacts to (such as the changing of a dial reading, or the location of a ball), BDI events allow an agent to pursue long term goals.
When using the BDI reasoning model, an agent does not simply react to incoming information, but sets itself a goal which it then tries to achieve. Rather than distracting an agent from its goal, incoming events are added to an agents knowledge base and can subtly influence its behaviour.
5.3.1 How an Agent handles BDI Events
The key difference between normal events and BDI events is how an agent selects plans for execution. With normal events, the agent selects the first applicable plan instance for a given event and executes that plan instance only.
The handling of BDI events is more complex and powerful. An agent can assemble a plan set for a given event, apply sophisticated heuristics for plan choice and act intelligently on plan failure. At least one of the following characteristics applies to each type of BDI event under the BDI model:
- Meta-level reasoning – a technique for writing plans about how to select plans. This can help in refining plan selection to allow for selection of the most appropriate plan in a given situation.
- Reconsidering alternative plans on plan failure – if a course of action (plan) fails, this technique allows an agent system to consider other courses of action to achieve the goal that has been set.
- Recalculating the applicable plan set – it is possible when acting on plan failure to assemble a new plan set which excludes any failed plans.
Additionally, it is possible to further control BDI behaviour by setting behaviour attributes. These attributes are described later in this chapter.
5.3.1.1 Meta-level Reasoning
When handling a BDI event, meta-level reasoning allows precise control over how an agent chooses a plan for execution from the set of applicable plans. Whenever there is more than one applicable plan instance for a given BDI event, a PlanChoice event is posted within the agent. By choosing to handle this event, an agent can implement meta-level reasoning.
If the meta-level reasoning plan fails and does not select a plan for execution, the default plan selection method is invoked. This is discussed in more detail in the chapter on meta-level reasoning.
5.3.1.2 Reconsidering Alternative Plans on Plan Failure
When handling BDI events, an agent will not always assume that failure of a chosen plan instance means the goal cannot be achieved. Instead, it may reconsider other applicable plans and try one of them instead.
It is this property that allows agents to avoid many of the pitfalls of more primitive reasoning models. Rather than having 'one shot' at achieving a goal, an agent can try a number of approaches to solving the problem by attempting any number of applicable plans.
5.3.1.3 Recalculating the Applicable Plan Set
This property controls how an agent takes into account the passage of time and changing circumstances when choosing alternative plan instances to handle a BDI event after the previous selected plan has failed. An agent may select an alternative plan in one of the following ways:
- keep track of the plan instances that were initially applicable and select another member of this set; or
- recompute which plan instances are applicable and select one from the new set, excluding plan instances that have already failed.
If circumstances and the agent's beliefs haven't changed, both approaches are equivalent. However, if the applicable plan instances depend on the agent's current set of beliefs and these beliefs have changed, the recomputed set of applicable plans may be different from the original set. This is especially relevant if the agent is using the SimpleRRTaskManager, or if the failed plan itself changed one or more beliefset tuples that affect the context calculations of other relevant plans.
5.3.2 The BDI Events in the JACK Agent Language
The JACK Agent Language event classes are listed below and are described in the following sub-sections:
Event Type | Description |
BDIFactEvent | Base class for all BDI Events in JACK. Only posted internally by an agent for its own use, but allows meta-level reasoning to occur for plan selection. |
BDIMessageEvent | BDIMessageEvents are received by agents from external sources – usually other agents. These are normally sent from one agent to another to facilitate inter-agent communication. Meta-level reasoning can be performed for plan selection on receipt of this event type. |
BDIGoalEvent | A BDIGoalEvent represents an objective that an agent wishes to achieve. Meta-level reasoning, alternative plan selection and plan set recalculation are all available for this event type. |
InferenceGoalEvent | An InferenceGoalEvent uses RuleBehavior, which extends BDIBehavior by processing all applicable plans (rather than only one of them). |
PlanChoice | Posted when there is more than one plan to choose from and optionally handled by the agent to implement meta-level reasoning. |
Table 5-2: BDI event classes
5.3.2.1 The BDIFactEvent Class
BDIFactEvents represent internal events that arise due to the agent's own internal processing.
The main difference between a BDIFactEvent and a normal Event is that when there is more than one applicable plan instance for a given BDIFactEvent, the agent is able to perform meta-level reasoning to determine which instance it should execute. A PlanChoice event is posted to trigger this meta-level reasoning, and if the agent has a plan that can handle it, it will execute this plan to determine which applicable plan instance it should execute.
Once the agent has chosen a plan instance to handle a BDIFactEvent, it will commit to this plan.
If the plan instance succeeds, the BDIFactEvent succeeds and returns to the plan that generated it.
If the plan instance fails, the default behaviour is that the BDIFactEvent fails and returns control to the plan that generated the BDIFactEvent.
BDIFactEvents are usually posted under the following circumstances:
- when the agent executes a @post statement from within a plan,
- when the agent executes either the postEvent() or postEventAndWait() base method from agent code outside plan execution, or
- when the agent modifies a beliefset relation for which a beliefset modification callback has been defined.
For more information on beliefset modification callbacks, refer to the Beliefset Relations chapter.
In each case, an instance of the event is posted using one of the event's posting methods. The posting method acts as the event's constructor, creating an instance of the event and making it available to the agent's task manager.
The BDI event processing properties supported by BDIFactEvents by default are summarised in the following table:
BDI Event Property | Supported by Default |
Allows meta-level reasoning. | Yes. |
Allows reconsideration of alternative plans. | No. |
Recalculates the applicable plan set when reconsidering alternatives. | No. |
Table 5-3: Default BDI event processing properties, supported by BDIFactEvents
5.3.2.2 The BDIMessageEvent Class
BDIMessageEvents are the same as normal MessageEvents but with BDI extensions. They allow the agent more scope when reasoning about how it should respond to a message received from another agent or process.
Like BDIFactEvents, BDIMessageEvents allow the agent to perform meta-level reasoning when more than one plan instance is applicable. This lets the agent choose which of its available set of responses is most appropriate according to given criteria.
For example, suppose an agent programmed to play as a soccer goal keeper in a soccer simulation has three plans that are applicable when defending a penalty – jump to the left, jump to the right and stay in the centre. When a penalty is called (arriving as a message event) all three of these plans would be applicable.
If the message event is of class MessageEvent, the agent can only select the first plan declared in the agent or capability. However, if the message event is a BDIMessageEvent, the agent has the option of performing meta-level reasoning to determine which plan is best. This meta-level reasoning may take into account various statistics from the game and past successes of each approach, then make the selection accordingly.
Once the agent has chosen a plan instance to handle a BDIMessageEvent, it will commit to this plan. If the plan instance succeeds, the BDIMessageEvent succeeds and returns to the plan that generated it.
If the plan instance fails, the default behaviour is that the BDIMessageEvent fails and returns control to the plan that generated the BDIMessageEvent.
This default behaviour can be overridden by adding either of the following to a BDIMessageEvent subclass:
#set behavior Recover repost;
or
#use behavior BDIGoalBehavior();
BDIMessageEvents can be sent by agents or by other Java processes running within a JACK application. Like MessageEvents, they are sent under the following circumstances:
- when an agent executes a @send statement from within a plan; or
- when an agent executes its send() base method.
Note: Agents should only execute the send() method from code outside a reasoning method. This is because the @send statement is meant to be used to post message events to other agents from within a reasoning method.
In order for agents running in different processes to send and receive message events, the JACK runtime environment must provide a communication infrastructure with message routing capabilities. This is done using the JACK DCI network. The JACK DCI network enables the establishment of portals between processes, through which agent messages can be directed as needed. Refer to the Inter-agent Communications chapter for further details.
The BDI event processing properties supported by BDIMessageEvents by default are summarised in the following table:
BDI Event Property | Supported by Default |
Allows meta-level reasoning. | Yes. |
Allows reconsideration of alternative plans. | No. |
Recalculates the applicable plan set when reconsidering alternatives. | No. |
Table 5-4: Default BDI event processing properties, supported by BDIMessageEvents
Like MessageEvents, BDIMessageEvents have a message member and can be displayed on an Agent Interaction Diagram. Refer to the Tracing and Logging Manual for more details on the Agent Interaction Diagram.
Note: All data fields within a BDIMessageEvent must be serializable.
5.3.2.3 The BDITracedMessageEvent Class
The BDITracedMessageEvent class contains information which enables inter-agent communication to be effectively displayed via an Agent Interaction Diagram (refer to the Tracing and Logging Manual for details on the Agent Interaction Diagram. This information is now available within the message event classes and consequently the BDITracedMessageEvent was deprecated in JACK version 3.5.
5.3.2.4 The BDIGoalEvent Class
BDIGoalEvents are unlike the other BDI events described so far. The BDIFactEvent, and BDIMessageEvent extended existing normal events with some of the BDI reasoning capabilities. The BDIGoalEvent, however, is exclusive to the BDI model of agent reasoning. Unlike the other BDI events, it offers all the BDI features by default.
The BDIGoalEvent represents a goal or objective that an agent wishes to achieve. Therefore, instead of representing reactive behaviour, BDIGoalEvents represent pro-active behaviour in an agent. When an agent posts and handles a BDIGoalEvent, it is adopting a goal. It will then use all the reasoning powers at its disposal – the ability to discard and reconsider plans, the ability to reassess which plans are applicable and the ability to choose between the plans that are applicable, in order to satisfy that goal.
An example of this might be a pilot agent adopting a goal to land an aeroplane. This would be posted internally as a BDIGoalEvent. This then becomes an objective that the agent commits to achieving, and the agent should try every applicable plan until one succeeds, and only give up and fail when no more applicable plan instances remain to be tried.
BDIGoalEvents usually arise within an agent as a result of executing specific JACK Agent Language statements in a reasoning method. These statements represent the agent posting the goal for itself, or choosing to undertake a task to satisfy the goal. When an agent adopts a goal, it can do so with the following objectives in mind:
- achieve the goal,
- insist that the goal is achieved, by double-checking that the goal has been met when the agent finished the task,
- test whether the goal can be achieved, or
- determine a situation in which the goal can be achieved.
Each of these objectives is specified by a separate reasoning method statement (@achieve, @insist, @test and @determine). These reasoning methods are described fully in the Plans section.
BDIGoalEvents can also be posted and sub-tasked – they do not arise solely from the reasoning method statements @achieve, @insist, @test and @determine. However, if they do not arise from one of these statements, the mode (discussed in the section on Event members) will be set to null.
The BDI event processing properties supported by BDIGoalEvents by default are summarised in the following table:
BDI Event Property | Supported by Default |
Allows meta-level reasoning. | Yes. |
Allows re-consideration of alternative plans. | Yes. |
Re-calculates the applicable plan set when reconsidering alternatives. | Yes. |
Table 5-5: Default BDI event processing properties, supported by BDIGoalEvents
5.3.2.5 The InferenceGoalEvent Class
An InferenceGoalEvent uses RuleBehavior, which extends BDIBehavior by processing all applicable plans (rather than only one of them). The behaviour is the same as BDIBehavior, except for the following:
- When a plan succeeds, instead of completing the event, the plan is added to the 'tried set' (called 'failed set' for BDIBehavior), and the next applicable plan is processed.
- When a plan fails, the event ignores this and continues with the next plan. This aspect is tunable by means of a behaviour attribute as follows:
– to fail the event with the first failing plan, use
#set behavior RuleFailure fail;
– to fail the event if any of the plans fail, but only after all the applicable plans have been processed, use
#set behavior RuleFailure delay;
– to ignore plan failure (i.e. the event always succeeds) use
#set behavior RuleFailure ignore;
The default behaviour is to ignore plan failure (i.e. the event always succeeds). The RuleFailure attribute only applies to events that use RuleBehavior (e.g. InferenceGoalEvents).
The behaviour of an InferenceGoalEvent is the same as BDIBehavior in terms of forming the applicable set and in terms of meta-level plan choice (although in this case, all plans will be processed). An InferenceGoalEvent can be fine tuned in the same way as other BDI events, using the behaviour attributes. Behaviour attributes are discussed in detail later in this chapter. The default BDIBehavior attribute settings are as follows:
Recover = repost ; //this attribute cannot be changed
ApplicableSet = once ;
ApplicableChoice = first ;
ApplicableExclusion = failed ;
PlanBindings = all ;
OnError = propagate ;
PostPlanChoice = never ;
The default RuleBehavior attribute setting is:
RuleFailure = ignore ;
Note that an InferenceGoalEvent can only be posted. To achieve the same behaviour when sending an event between agents, the #use behavior RuleBehavior; declaration is added to an event which has extended a normal message event. For example:
public event ExampleEvent extends MessageEvent
{
#use behavior RuleBehavior();
#posted as postingMethod()
{
}
}
Note: The applicable plan set only includes the highest ranking plans – not all the plans that are relevant and within context. As InferenceGoalEvents (and events that use RuleBehavior) only calculate the applicable set once, they will only activate the highest ranking plans.
5.3.2.6 The PlanChoice Event Class
PlanChoice events are a separate class of event altogether, but they are included with BDI events because they represent the mechanism whereby an agent performs meta-level reasoning about the handling of BDI events.
Unlike the other event classes in the JACK Agent Language, a user would not explicitly post a PlanChoice event by executing a method or a reasoning method statement in a plan. Instead, PlanChoice events are posted internally by an agent whenever:
- an instance of a BDI event arises within the agent, and
- there is more than one applicable plan instance available to the agent to handle this event.
When this happens, the agent is given an opportunity to choose which of the applicable plan instances it will execute. The task to handle this PlanChoice event proceeds like any other task execution in JACK. The agent looks for plan instances that are relevant to this PlanChoice event and applicable under the current circumstances, selects one and then executes it. The plan should examine the set of applicable plans and select one for the agent to try.
Because an agent handles a PlanChoice event in the same way that it handles a normal event, the processing of PlanChoice events is referred to as meta-level reasoning. It represents reasoning (task execution) that an agent undertakes not to do work, but to decide what is the best approach to doing work.
Plans that are used for meta-level reasoning, as opposed to handling normal or BDI events, are distinguished by the following JACK Agent Language declarations:
#handles event PlanChoice event_handle;
#chooses for event event1 event2 ... ;
#chooses for event ... ;
The plan's #handles event declaration identifies it as one that handles PlanChoice events. Since PlanChoice events cannot be declared, the event_handle component will be assigned a reference to any PlanChoice event that arises. Therefore, plans that include a #handles event PlanChoice event_handle; declaration will handle all PlanChoice events that arise within the agent unless further methods for discrimination are supplied.
This discrimination is provided by the #chooses for event declaration. The #chooses for event declaration identifies the events for which the plan's meta-level reasoning is relevant. Therefore, if a meta-level reasoning plan includes one or more #chooses for event declarations, the plan will only be relevant for a given PlanChoice event if that PlanChoice event was caused by one of the listed events. That is, the agent will only use this meta-level plan to choose between multiple plan instances if those plan instances are all applicable to the listed event.
More information on these declarations is supplied in the Plans section.
5.3.3 Customising BDI Behaviour with Behaviour Attributes
Each BDI event type has a default behaviour that determines what happens with respect to plan reconsideration, plan set recalculation and meta-level reasoning. This default behaviour can be modified by setting the behaviour attributes of the event.
The #set behavior declaration is used in BDI event definitions to define how an agent processes an instance of this event when it arises. Options that can be configured include things such as whether the agent will retry the event if an attempted plan fails and whether or not the agent can reason about which plan it executes in response to the event.
Not all BDI events offer all these properties by default. However, each property is present with one or more BDI event. Furthermore, the #set behavior declaration can be used to customise the properties of BDI events in each particular application.
Changes to behaviour attributes for BDI Events take two basic forms, as follows;
#set behavior attribute value;
#set behavior attribute Type (arg_list);
The first form is the most common and is used to set the behaviour of existing BDI events. The second form is used to define custom plan choice events to use for meta-reasoning with the event being defined. Both types are described in the sections that follow.
Note that the exact behaviour generated by setting a particular behaviour attribute can depend on the setting of another behaviour attribute. For example, the behaviour generated by the Recover attribute is linked to the setting of the ApplicableSet attribute.
With their default values of:
#set behavior Recover repost;
#set behavior ApplicableSet new;
an event will be reposted on plan failure and the applicable set will be recomputed anew (i.e. possibly with different bindings). Another applicable plan will then be tried (any plan instances already tried and failed will be discarded). However, if the ApplicableSet attribute had a value of once, the applicable set would not be recomputed before another plan was selected.
#set behavior Recover <value>;
This attribute can be added to a BDI event to define how plan processing should act upon plan failure. Possible values are listed in the following table:
Value | Effect |
repost | The event should be reposted on failure, or more precisely, another applicable plan should be tried. If no new applicable plan is found, the event processing fails. [DEFAULT] |
never | Event processing should fail rather than recover from plan failure. |
always | The event should always be reposted, even when no new applicable plan is found. |
Table 5-6: Possible values for the Recover attribute
Note: repost is the default Recover value used by BDIGoalEvent and InferenceGoalEvent, while never is the default for BDIFactEvent, BDIMessageEvent and BDITracedMessageEvent.
#set behavior ApplicableSet <value>;
This attribute can be added to a BDI event to define how to form the applicable set during plan processing, and in particular with respect to recovering:
Value | Effect |
new | The applicable set should be computed anew after each plan failure. [DEFAULT] |
once | The applicable set is to be computed only once. On event failure, the next applicable plan is selected from the set computed initially for the event. |
repeat | The applicable set is computed initially, and then reinstated when exhausted. This is designed to work with the Recover always attribute and allows persistent checking of plans in a computed set until one succeeds. |
Table 5-7: Possible values for the ApplicableSet attribute
#set behavior ApplicableChoice <value>;
This attribute can be added to a BDI event to define how an applicable plan should be chosen. This setting is overridden by any meta-level reasoning that is in place:
Value | Effect |
first | The first plan instance generated by the #uses plan declaration in the body of the agent or capability is chosen. [DEFAULT] |
random | A plan is chosen from the applicable set at random. |
Table 5-8: Possible values for the ApplicableChoice attribute
#set behavior ApplicableExclusion <value>;
This attribute can be added to a BDI event to define how plans are excluded from the applicable set:
Value | Effect |
failed | Plans that have failed are excluded from the applicable plan set. [DEFAULT] |
none | Plan failure is forgotten immediately, so that plans that have failed previously can be added to the applicable plan set (if they are still applicable). |
rank | All Plan instances with lesser PlanInstanceInfo.getRank() values are excluded from the applicable plan set. [DEFAULT] |
Table 5-9: Possible values for the ApplicableExclusion attribute
The two default values are;
#set behavior ApplicableExclusion failed;
#set behavior ApplicableExclusion rank;
Note: If the ApplicableExclusion attributes are set to none, the reset plan exclusion properties are effectively reset for this event. After resetting this property, either the failed or the rank property can be selectively added to further refine plan set exclusion characteristics.
#set behavior PlanBindings <value>;
This attribute can be added to a BDI event to define how to process plan context for generating multiple plans instances:
Value | Effect |
all | Generate all applicable plan instances before plan choice. [DEFAULT] |
single | Generate one applicable and not failed instance (if possible). |
first | Try the context once for a relevant plan type. If that fails, or if the first plan instance has been tried before and failed, no new plan instance is generated. |
Table 5-10: Possible values for the PlanBindings attribute
#set behavior OnError <value>;
This attribute can be added to a BDI event to define how to deal with exceptions from plans:
Value | Effect |
propagate | Propagate the error up the task stack to where the event was subtasked. [DEFAULT] |
fail | Capture the error but fail the event processing. |
repost | Treat the error as plan failure. |
Table 5-11: Possible values for the OnError attribute
#set behavior PostPlanChoice <value>;
This attribute can be added to a BDI event to define under which circumstances the PlanChoice event should be posted:
Value | Effect |
never | Never post a PlanChoice event for the event being defined. |
always | Always post a PlanChoice event. |
one_applicable | Post a PlanChoice event if there is only one plan instance in the applicable plan set. |
multiple_applicable | Post a PlanChoice event if there are two or more plan instances in the applicable plan set. [DEFAULT] |
no_applicable | Post a PlanChoice event if there are no plan instances in the applicable plan set i.e. it's empty. |
one_plan | Post a PlanChoice event if there is one relevant plan. |
multiple_plan | Post a PlanChoice event if there are two or more relevant plans. |
no_plan | Post a PlanChoice event if there are no relevant plans. |
Table 5-12: Possible values for the PostPlanChoice attribute
Setting PostPlanChoice to never resets all settings for this attribute. All required attributes can then be added.
Note: Several of the above values may be needed to select the desired nuance. For example, if you like a plan choice for one or more applicable plan instances, the declaration would be as follows:
#set behavior PostPlanChoice one_applicable;
#set behavior PostPlanChoice multiple_applicable;
#set behavior PlanChoiceEvent MyPlanChoice();
This attribute can be added to a BDI event to declare that the event type being defined should use MyPlanChoice which is constructed inline. The class MyPlanChoice needs to be defined and it needs to extend class PlanChoice.
5.4 Automatic Events
The objective of automatic events is to provide a mechanism for an agent to automatically post particular events when certain belief states arise. Automatic events use:
- A #uses data statement. This statement is added to an event definition to provide access to the agent's belief structures.
- A #posted when definition. This definition is added to an event definition to specify the condition which must arise for the event to be automatically posted and optionally, a body which will be used as the posting method if and when the condition should arise.
When an agent or capability declares that it handles an event which has a #posted when definition, it will automatically have the necessary belief monitoring activated. The details are described in the section on the #posted when declaration.
The use of the #uses data and #posted when statements to achieve automatic belief monitoring is illustrated in the following example:
event Example extends Event
{
#uses data ReactorVessels rv;
logical String $vessel;
logical int $x;
#posted when ( rv.get($vessel,$x) && $x.as_int() > 300 ) {
// Any event initialisation goes here
}
}
The block after the #posted when condition is optional. If there are no event fields that need to be initialized when the event is actually posted, it can be omitted as shown below:
#posted when ( rv.get($vessel,$x) && $x.as_int() > 300 );
The condition is evaluated once initially, and subsequently whenever a change occurs that might affect the condition. If the condition evaluates to true, the event is posted with the logical variables bound as they were in the condition. If there are multiple bindings, a separately bound event will normally be posted for each possible binding. The exception occurs when an event with that particular binding has already been posted to signify the condition becoming true and the condition with that binding has not become false in the meantime.
Suppose that in the above example, rv initially contained the following tuples:
("vessel1",400) and
("vessel2",500)
then two separate events would be posted; one with $x = 400 and one with $x = 500.
However, if rv initially contained no facts and the fact
("vessel1",400)
was asserted, an event would be posted with $vessel = "vessel1" and $x = 400. If
("vessel2",500)
was then asserted, another event would be posted with $vessel = "vessel2" and $x = 500. However, note that another event with $vessel = "vessel1" and $x = 400 would not be posted because the condition (with $x = 400) is still true and had never been false in the intervening period.
If the condition was more complicated (e.g. involved more than one beliefset) and the addition of one fact meant that multiple bindings became true, multiple events would be posted.
5.5 Event Definition
JACK Agent Language events not only support the concepts described in the last section, but also provide type safety within agent definitions. This is because both agents and plans need to declare the events that they handle and the message events that they send. As with function prototypes, this ensures that any type mismatches in an event's parameters can be detected and flagged during compilation.
Event definitions follow one of the formats given below:
event EventType extends Event
{
// JACK Agent Language statements specifying
// the event's structure and how the event is
// posted within the agent.
}
event EventType extends MessageEvent
{
// JACK Agent Language statements specifying
// the event's structure and how the event is
// posted to other agents.
}
event EventType extends BDIFactEvent
{
// JACK Agent Language statements specifying
// the event's structure and how the event is
// posted within the agent.
}
event EventType extends BDIMessageEvent
{
// JACK Agent Language statements specifying
// the event's structure and how the event is
// posted to other agents.
}
event EventType extends BDIGoalEvent
{
// JACK Agent Language statements specifying
// the goal's structure and how the goal is
// posted within the agent.
}
event EventType extends InferenceGoalEvent
{
// JACK Agent Language statements specifying
// the goal's structure and how the goal is
// posted within the agent.
}
event EventType extends PlanChoice
{
// JACK Agent Language statements specifying the
// PlanChoice event structure.
// Note: you are unlikely to want to declare your own
// PlanChoice events. You would only do this if you
// want to extend the meta-level reasoning capabilities
// supplied with JACK.
}
Each part of these definition statements is explained in the following table:
Syntax Term | Description |
event | JACK Agent Language keyword that identifies the statement as an event definition. It must always be used to define events. |
EventType | The name that the event will have. The name of an event is analogous to the name of a class in Java. |
extends Event | The same as in normal Java. Each event class defined inherits its underlying properties from a base class. This base class may be: Event, MessageEvent, BDIGoalEvent or InferenceGoalEvent. |
Table 5-13: Event component definitions
5.6 Event Members and Methods
The event classes described earlier in this chapter include a number of base members and methods. These members and methods are described in the following subsections. In each case, the event classes that contain these members and methods are identified.
public Agent getAgent()
The getAgent() method returns the Agent that instantiated the event or in other words, the agent which is processing the event.
public String from
The from member describes the location of the agent that originally posted the event. This will refer to a different agent than the one returned by getAgent() unless the agent posted a message to itself. This member is only available in message events used for inter-agent communication, according to the following table:
Event Type | Member Available |
Event | No. |
MessageEvent | Yes. |
BDIFactEvent | No. |
BDIMessageEvent | Yes. |
BDIGoalEvent | No. |
InferenceGoalEvent | No. |
Table 5-14: Availability of the from member
Whenever a message event is sent from one agent to another, the name and address of the agent that sent it is automatically assigned to this member. This address is a string that represents both the agent's name and the portal at which it is running on the DCI network. Refer to the Inter-agent Communications chapter for further details.
Agents that receive a message event can query the from member to determine where the message came from. If they want to send a response, they can do so using the @reply statement in a reasoning method, or the reply() method in ordinary code. Both of these constructs automatically extract the from member from the supplied event that originated the interaction.
Because all message events extend from the MessageEvent event class, every defined message event class will include this member.
public String message
This member is available only in message events, as shown in the following table:
Event Type | Member Available |
Event | No. |
MessageEvent | Yes. |
BDIFactEvent | No. |
BDIMessageEvent | Yes. |
BDIGoalEvent | No. |
InferenceGoalEvent | No. |
Table 5-15: Availability of the message member
The message member is provided for message events so that they can be traced using the Agent Interaction Diagram (if this JACK option is enabled). Whenever writing a posting method for a message event, a String may be assigned to this member. If so, this text will be propagated to the Agent Interaction Diagram, allowing easy identification of the instance of this message event. Refer to the Tracing and Logging Manual for details on the Agent Interaction Diagram.
public String mode
This member is available in BDIGoalEvents only, as illustrated in the following table:
Event Type | Member Available |
Event | No. |
MessageEvent | No. |
BDIFactEvent | No. |
BDIMessageEvent | No. |
BDIGoalEvent | Yes. |
InferenceGoalEvent | No. |
Table 5-16: Availability of the mode member
This member holds a String that represents the statement used to post a given instance of a BDIGoalEvent. By accessing this method, an agent can determine why it is handling a given BDIGoalEvent instance. This information is stored in the mode member only when @achieve, @determine, @insist or @test are used to post the BDIGoalEvent. If it did not arise from one of these statements, the mode will be set to null.
For example, suppose an agent that drives a networking system needs to derive information about the state of the network before attempting to establish a new connection. When it wants to connect to a new system, it first posts a BDIGoalEvent using a @test statement. Assuming the connection is successful, the agent would post a BDIGoalEvent using the @achieve statement.
The plan that handles this event can query the event's mode member to determine if the agent wants the connection tested or whether a connection should be established. In each instance the strings "test" and "achieve" would be stored in the mode member respectively. In each case, the plan's processing would need to be different.
The strings for each BDIGoalEvent posting mode are given in the following table:
BDIGoalEvent Posted by | mode |
@achieve | achieve |
@insist | insist |
@test | test |
@determine | determine |
Table 5-17: Posting modes
Cursor replied()
This method indicates whether the agent has received any replies to a given message event. It returns a triggered cursor, which will test whether the given message event's reply queue is empty.
A message event can have any number of pending replies. A reply is also a message event, but it must have been sent using a reply() method or an @reply statement.
If the agent has received at least one reply to the MessageEvent that you call this method on, the cursor statement will return true when tested.
If the agent has yet to receive a reply to the MessageEvent that this method was called on, the cursor statement will return false when tested.
Because the cursor is triggered, it can be used in a @wait_for statement to make the agent wait for replies before continuing with a given task. Doing this provides the option of implementing synchronous inter-agent messaging, rather than the default asynchronous method. After sending a message event to another agent, a reasoning method can make the task wait on the returned triggered cursor, effectively blocking it until such a reply arrives.
This method is only provided on message events as shown in the following table:
Event Type | Method Available |
Event | No. |
MessageEvent | Yes. |
BDIFactEvent | No. |
BDIMessageEvent | Yes. |
BDIGoalEvent | No. |
InferenceGoalEvent | No. |
Table 5-18: Availability of replied method
MessageEvent getReply()
This method complements the replied() method described above. It allows retrieval of a reference to a MessageEvent that has been sent as a reply to the MessageEvent that it is called on.
When this method is called, it returns the first reply in the reply queue, removing it from the queue at the same time. If there are no message events in the reply queue, it throws an Error. This method is only provided on message events as per the following table:
Event Type | Method Available |
Event | No. |
MessageEvent | Yes. |
BDIFactEvent | No. |
BDIMessageEvent | Yes. |
BDIGoalEvent | No. |
InferenceGoal | No. |
Table 5-19: Availability of the getReply method
5.7 Event Declarations
Events have a small number of JACK Agent Language specific constructs at the field or member level. These constructs are described in the following subsections.
#posted as methodName(parameters)
This is one of the event's posting methods. A posting method describes how the event can be constructed and posted or sent.
An event's posting method must be used whenever an instance of the event needs to be created. This is normally when agent or beliefset code executes the post() method, or a plan uses the @post or @subtask statements. The posting method describes everything that the agent needs to do to construct an instance of the event.
A posting method declaration is as follows:
#posted as methodName (parameters)
{
// Method Body
}
Each part of this declaration is described in the following table:
Component | Meaning |
#posted as | Indicates that an event's posting method is being defined. All posting method definitions must be identified in this way. |
MethodName | The name by which the posting method is identified. When the agent posts an event, it uses this name to identify the posting method to be used. |
(parameters) | Identifies the number and type of parameters that this posting method requires in order to construct and post the event. |
Method Body | Java code that is used to construct the event. |
Table 5-20: Posting method declaration components
An example event definition including a posting method is given below:
// An example event definition to be used with a
// prospecting agent. The agent models a prospector who
// travels around looking for treasure. This event is
// posted whenever some treasure is found (presumably so
// that the agent will execute a plan to retrieve it).
event FoundTreasureEvent extends Event
{
int latitude;
int longitude;
int value;
#posted as foundTreasure (int lat, int ltd, int val)
{
latitude = lat;
longitude = ltd;
value = value;
}
}
In this example, the posting method's name is foundTreasure. Whenever the agent believes it has found some treasure while executing its own methods, it can use the foundTreasure posting method to create a FoundTreasureEvent which it can post or send to initiate a response.
The foundTreasure posting method requires three arguments if the event is to be posted successfully. These are the treasure's latitude, longitude and value. All that the posting method's body does is populate the event's data members with this information so that it will be included in the posted event.
An event may have as many posting methods as you want. You may use different posting methods when instances of the event should take a different form under different circumstances. In particular, you may want to implement multiple posting methods using the idea of a polymorphic class which allows you to use the same posting method name while defining different versions of the posting method for different arguments.
For example, suppose an agent that keeps track of a racing leaderboard gets messages sent to it by another agent whenever each racer completes a lap. This message may take two forms: one when the racers have completed a lap during the race, and another when the racers have completed the final lap. In each case, the message may convey different information about the racer. The agents can use the same message event for each situation, but a different posting method to propagate the event instance with the required information in each case.
Just as you can extend the base Event classes you can also extend your own event definitions. You may choose to define generic event types and then extend them to more specific cases. For example, a generic FoundTreasureEvent might be used as the base class for a FoundDiamondEvent and a FoundGoldEvent). When you choose to do this, you should only define posting methods for the outermost (leaf) event classes.
You may wish to extend your own event classes if, for example, you require:
- improved efficiency in terms of plan selection (the events are more specific),
- different behaviours (using #set behavior),
- additional members.
#uses data DataType data_name
The #uses data statement in an event definition has the following form:
#uses data DataType data_name;
where the DataType and data_name match the data or beliefset declaration in the enclosing capability or agent. This statement is added to an event definition to provide access to the enclosing capability or agent's belief structures.
#posted when ( condition ) optional_method_body
The #posted when statement has the following form:
#posted when ( condition ) { body }
where the condition is a logical condition of the same form as a condition for a @wait_for statement. In particular, it must be a triggered condition, i.e. include conjuncts that are triggered, such as beliefset cursors etc.
Note that the elapsed() and after() methods are plan methods and thus not available for events – if there is a requirement for issuing a regular recurrent event stream, the use of a plan is recommended.
The body after the condition is optional and consists of any initialisation that should be done if and when the event is posted. The body is the same as that of a normal posting method declared using #posted as. If no initialisation is needed, the entire body (including the braces) may be omitted.
If an event definition includes a #posted when statement, the compiler deals with logical variables in the event by providing a logical environment in which to evaluate the condition, and later providing new logical environments and bound variables for the automatic events being posted.
An event definition may include several #posted when and any number of #posted as statements just like any other event. The former will then issue automatic events according to their conditions, and the latter would be used exactly as before.
#set transport format
The #set transport statement is used to signal which transport format is to be used for message events. It has the following form:
#set transport format
where format is either jacob or java. Since release 4.1, the default format is jacob. Although jacob is generally more efficient for transport, there are some things that jacob does not support (e.g. arrays). In such cases, java format should be specified using the #set transport declaration,
If the #set transport statement is used to specify java format, the event is compiled to use Java serialization.
jacob format provides support for transport in binary, text or XML style. The default style with jacob format is binary. It is possible to specify the style processwide by setting the property JACOB.OutputType to one of (ascii,binary,xml).
5.8 Posting and Sending Events
In JACK, posting methods create instances of the events to be posted or sent. These instances are then provided as arguments to the reasoning statements or methods which are responsible for their posting or sending (e.g. post(), send(), @post ...). The event's posting methods are accessed through the event reference provided in the #sends event or #posts event declaration. Note that there is only one #sends or #posts event declaration for a given event type in any agent or plan. Event instances are created in an agent or plan by using the event's posting method(s). The process is illustrated below.
#sends event MessageEventType mef;
:
:
// create event
MessageEventType me = mef.postingMethod1(arg1, arg2);
// send the event
send(destination1, me);
// create and send another event
send(destination2, mef.postingMethod2(arg3, arg4, arg5));
:
: