The capability concept is a means of structuring reasoning elements of agents into clusters that implement selected reasoning capabilities. This technique simplifies agent system design, allows code reuse, and encapsulation of agent functionality.
Capabilities represent functional aspects of an agent that can be plugged in as required. This capability as component approach allows an agent system architect to build up a library of capabilities over time. These components can then be used to add selected functionality to an agent.
Additionally, capabilities can be structured so that a number of sub-capabilities can be combined to provide complex functionality in a parent capability. This capability can in turn be added to an agent to give it the desired functionality.
Capabilities are built in a similar fashion to simple agents – constructing them is merely a matter of declaring the JACK Agent Language elements required. Events, beliefsets, plans, Java code and other capabilities can all be combined to make a capability.
In this section, the capability concept is described, and capability declarations are explained. Each of the specific #-declarations, members and methods pertaining to capabilities is listed in following sub-sections.
A capability is defined similarly to other type-level concepts as a code block by the keyword capability. A capability definition takes the form shown below:
capability CapabilityType extends Capability
[implements Interface]
{
// JACK Agent Language Statements specifying
// the functionality associated with this
// capability.
}
Each component of this definition is explained in the following table:
Syntax Term |
Description |
capability |
A JACK Agent Language keyword used to introduce a capability definition. |
CapabilityType |
The name of the derived Capability class. |
extends Capability |
This part of the statement plays the same role as in Java – it indicates that the capability being defined inherits from a JACK Agent Language base class called Capability. The Capability base class implements all the underlying methods that provide a capability's core functionality. |
[implements Interface] |
This part of a capability definition is optional. When present, it states that a capability implements a given Java interface. Java interfaces are classes that consist of method prototypes without code. When a capability implements an interface, it provides code to implement each of these methods. |
Table 4-1: Components of a Capability definition
In the body of each capability, events, beliefsets, plans and other capabilities that pertain to the functionality provided by the given capability are declared. Java entities (i.e. methods and members) may be declared in capabilities as in a class. Each capability is instantiated with each agent that contains the corresponding #has capability declaration.
The JACK #-declaration statements used for agents are all available for use in capabilities, except those that refer to task managers. In addition, there are new declarations that allow specifying events and beliefsets as shared with an enclosing capability.
The optional implements Interface component in a capability definition is important when it comes to writing portable JACK programs that allow for code re-use. Interfaces provide a mechanism for agents and capabilities to share plans.
When an agent executes a plan, this plan will often call ordinary Java methods. It is important to remember that when this occurs, these methods must be available to the plan through having been declared in the agent or one of the capabilities that it uses. Therefore, any capability that uses this plan must include the defined methods, or the plan will not be able to run properly.
The JACK Agent Language allows you to package up these dependencies into a Java Interface. Any capability that wishes to include this plan must declare that it implements this interface. If a capability implements the interface, it provides all the methods necessary to run the plan.
A capability should fully describe the functionality it implements via JACK Agent Language declarations. In general, a capability definition will require declarations for the following:
These declarations are provided by statements that occur at the field or member level of a capability definition. By convention, these statements should appear before the definitions of any regular Java data members and methods that the capability may contain.
An example capability template showing some of the declarations that can appear in a capability appears below:
capability CapabilityType extends Capability
[implements InterfaceName]
{
// Knowledge bases used by the capability are declared here.
#private data BeliefType belief_name (arg_list);
#exports data BeliefType belief_name (arg_list);
#imports data BeliefType belief_name ();
// Plans used by the capability are declared here.
// Order is important.
#uses plan PlanType;
// Events posted, sent and handled are declared here.
#handles event EventType;
#handles external [event] EventType;
#posts event EventType reference;
#posts external [event] EventType reference;
#sends event EventType reference;
// Sub-capabilities are declared here.
#has capability CapabilityType reference;
// other Data Member and Method definitions
}
Each JACK Agent Language capability declaration is described in more detail in the following sub-sections.
As for agents, the #handles event statement declares that there are plans within this capability that handle events of the given type. The declaration also implies that these events are local to the capability and its sub-capabilities, which means that the connection between posting and handling does not cross the boundary between this capability and its enclosing capability. In other words, events of type EventType that are posted externally to this capability are not handled within this capability, and the events of type EventType that are posted within the capability are not visible for the enclosing capability. However, the declaration does not make the event type 'invisible' for inner capabilities; rather, this is decided in their definitions.
The #handles external statement declares that there are plans within this capability that handle events of the given type, and that this type is shared with the enclosing capability. This means that event posting and handling does cross the capability boundary upwards. That is, the external keyword declares that the event in question may be handled by the parent capability or any of its sub-capabilities that declare that they handle this external event, and these capabilities' plans, if any, contribute to the plan set assembled to handle this event. Note that the keyword event is optional.
The #posts event statement declares that there are plans or code within this capability that post events of the given type. The declaration also indicates that these events are local to the capability, which means that the connection between posting and handling does not cross the boundary between this capability and its enclosing capability. A reference name is needed only if the event is to be posted from Java code within the capability.
The #posts external statement declares that there are plans or code within this capability that post events of the given type, and that this event type is shared with the enclosing capability. All plans from all capabilities that handle this shared event then compete to handle it. Note that the keyword event is optional.
The #sends event statement declares that there are plans or code within this capability that send events of the given type. It is important to note that events are received at agent level (the addressable entity), which means events cannot be explicitly directed into a capability of another agent.
The #private data statement declares that a Java object or a JACK beliefset of type DataType is local to the capability, and is accessible only from within the capability and its sub-capabilities. Note that the statement results in the instantiation of the beliefset or object using the specified constructor.
When a capability definition includes a statement of this form, it declares a named data, data_name of type DataType. The named data is shared among all agents in the same process that have the same type as the agent in which the capability instance is created. If the same capability type is used by two different agent types, there will be a different instance of the named data created for each of the agent types. Although it is not enforced, agent access should be shared, read-only access. As access to agent data is intended to be read-only, the beliefset or object should be initialised when it is constructed. The first instance of an agent class that uses the beliefset or data object, causes it to be constructed.
When a capability definition includes a statement of this form, it declares a named data, data_name. The named data is shared among all the agents in the same process. Although it is not enforced, agent access should be shared, read-only access. As access to global data is intended to be read-only, the beliefset or object should be initialised when it is constructed. The first instance of an agent class that uses the beliefset or data object, causes it to be constructed.
The #exports data statement declares that a Java object or a JACK beliefset of type DataType is exported from the capability so that it is accessible from its parent capability. The export statement can also be used to make a data object or beliefset available at agent level, and accessible from other capabilities within the agent level. Note that the statement results in the instantiation of the beliefset or object using the specified constructor.
The #imports data statement declares that a Java data object or JACK beliefset of type DataType is shared with this capability and its enclosing agent or capability. Note that no instantiation occurs as a result of this statement.
The #uses plan statement declares that this capability uses plans of the given type. The usage is unique for the capability in the sense that even if the same plan type is used in another capability, the plan instances extending from each use are wholly distinct. This means that even if they are used in a way so as to share a handled event (e.g. used by two 'sibling' capabilities where the handled event is external in both), the usages within the different capabilities generate their own plan instances independently.
The #has capability statement declares use of an inner capability. Note that the reference name is required. The inner capability is then accessible through the reference name.
The remaining step in completing the capability definition is to specify the capability's data members and methods. When defining a capability's methods, it is possible to use some of the base methods that the Capability class provides. Since all capabilities extend the Capability class, these methods are always available. If any of the capability's plans require it to implement a particular interface, all the methods specified by this interface must be included among the capability's methods and be fully implemented.
Note: Capability sub-classes can be defined by extending from other Capability classes, not just from the base Capability class.
Once the desired set of #-declarations has been added to a capability's definition, the event, plan, beliefset and capability components that the capability requires need to be defined. Each of these components contains their own data members and methods.
While capabilities are not explicitly constructed by the user, they are brought into being when the enclosing agent is constructed. They can be initialised by overriding the autorun() method, described below.
Capabilities do not have a name in the same sense that agents do, but can be referred to through the chain of reference names used in the #has capability statements. This reference name can be retrieved by calling the toString() method on the Capability instance in question.
The reference name starts with the agent name, and thereafter the names used for traversing down the capability structure to the instance in question, where each name is separated with ':'. Thus, a capability name like bob@builders:tiling:bathroom_tiling says that this is the capability instance bathroom_tiling of the capability instance tiling of the agent instance bob at portal instance builders.
JACK Agent Language entities (i.e. plans, events and beliefsets) that belong to capabilities are each instantiated in slightly different ways. These differences mean that it is not always possible to determine the name of the capability to which the entities belong. For example, when a plan is instantiated, it is associated with an enclosing NameSpace object, which is either a Capability object or an Agent. This object is accessible through the public Plan member __ns. Event and beliefset instances are not explicitly associated with the enclosing capability instance. This means that a plan cannot query an event or beliefset instance about which capability they belong to.
The postEvent() method is used to post events within capability code. This method is actually just a convenient method that refers to getAgent().postEvent().
See the discussion of the postEvent() method in the Agents section for more details.
The method is called on a capability instance to return the containing agent, which is generically typed.
The autorun() method is invoked before the agent is fully constructed. The invocation is at the end of the construction of the capability after all its sub-capabilities have been fully constructed. The autorun method can be overridden in order to provide some initialisation when the capability is constructed.