JAM Agents

in a Nutshell

 

Version 0.65+0.76i[1]

(November 2001)

 

 

Marcus J. Huber, Ph.D.

marcush@home.com

 

Intelligent Reasoning Systems

Oceanside, California

http://members.home.net/marcush/IRS

 

 

 

 

 

 

 

Draft of November 1, 2001


Table of Contents

Table of Contents............................................................................................................................................ 2

1.     INTRODUCTION & BACKGROUND......................................................................................................... 4

1.1.       Overview.............................................................................................................................................. 5

1.2.       Unpacking the JAM Agent distribution.............................................................................. 6

1.3.       Running and building JAM......................................................................................................... 7

2.     BELIEFS............................................................................................................................................................ 9

3.     GOALS............................................................................................................................................................. 11

3.1.       Top-level Goals............................................................................................................................. 11

3.2.       Subgoals............................................................................................................................................ 12

4.     PLANS.............................................................................................................................................................. 14

4.1.       Expressions...................................................................................................................................... 14

4.2.       Plan Body.......................................................................................................................................... 16

4.2.1.    Plan Variables.................................................................................................................................. 18

4.2.2.    Plan Actions...................................................................................................................................... 18

4.2.3.    Plan Comments................................................................................................................................. 30

4.3.       Plan Name.......................................................................................................................................... 30

4.4.       Plan Documentation.................................................................................................................. 30

4.5.       Plan Execution Behavior......................................................................................................... 30

4.5.1.    Plan Goal.......................................................................................................................................... 31

4.5.2.    Plan Conclude.................................................................................................................................. 31

4.6.       Plan Context................................................................................................................................... 31

4.6.1. Predicates.............................................................................................................................................. 33

4.7.       Plan Precondition....................................................................................................................... 34

4.8.       Plan Utility...................................................................................................................................... 34

4.9.       Plan Attributes.............................................................................................................................. 34

4.10.     Plan Effects..................................................................................................................................... 35

4.11.     Plan Failure..................................................................................................................................... 35

5.     CYCLIC FUNCTIONALITY........................................................................................................................ 38

6.     INTENTION STRUCTURE.......................................................................................................................... 39

7.     SOURCE-CODE API..................................................................................................................................... 40

8.     PRIMITIVE FUNCTION INTERFACING................................................................................................ 42

8.1.       PrimitiveAction Interface....................................................................................................... 42

8.2.       UserFunctions.java..................................................................................................................... 44

8.3.       Invoking Legacy Code................................................................................................................ 46

8.4.       Predefined Functions................................................................................................................ 46

9.     THE INTERPRETER.................................................................................................................................... 57

10.        CHECKPOINTING and MOBILITY.................................................................................................. 61

10.1.     Checkpointing................................................................................................................................ 61

10.2.     Mobility.............................................................................................................................................. 61

11.        KNOWN BUGS AND LIMITATIONS................................................................................................... 63

12.        EXAMPLE PLANS................................................................................................................................... 64

blocks-world.jam...................................................................................................................................... 64

ex1.jam............................................................................................................................................................... 64

ex2.jam............................................................................................................................................................... 64

ex3.jam............................................................................................................................................................... 64

ex4.jam............................................................................................................................................................... 64

ex5.jam............................................................................................................................................................... 64

ex6.jam............................................................................................................................................................... 65

ex6b.jam............................................................................................................................................................. 65

ex7.jam............................................................................................................................................................... 65

ex8.jam............................................................................................................................................................... 65

ex9.jam............................................................................................................................................................... 65

exA.jam............................................................................................................................................................... 65

exB.jam............................................................................................................................................................... 65

exC.jam............................................................................................................................................................... 65

exD.jam............................................................................................................................................................... 66

exE.jam............................................................................................................................................................... 66

exF.jam............................................................................................................................................................... 66

exG.jam............................................................................................................................................................... 66

exH.jam............................................................................................................................................................... 66

exI.jam................................................................................................................................................................ 66

exJ.jam................................................................................................................................................................ 66

parseString.jam............................................................................................................................................ 66

sockets-client.jam..................................................................................................................................... 66

sockets-client2.jam................................................................................................................................... 66

sockets-server.jam.................................................................................................................................... 67

sockets-server2.jam.................................................................................................................................. 67

13.        JAM BNF Grammar............................................................................................................................ 68

14.        Comparison to UMPRS................................................................................................................... 71

Similarities...................................................................................................................................................... 71

Differences..................................................................................................................................................... 71

15.        REFERENCES.......................................................................................................................................... 72

16.        ACKNOWLEDGEMENTS...................................................................................................................... 74

 


1.  INTRODUCTION & BACKGROUND

 

JAM is an intelligent agent architecture that grew out of academic research and extended during the last five years of use, development, and application.  JAM combines the best aspects of several leading-edge agent theories and intelligent agent frameworks.  Influences upon JAM include:

·       The Belief-Desire-Intention (BDI) theories [Bratman88:Plans, Georgeff, etc.]

·       The intelligent agent architectures of the Procedural Reasoning System (PRS) of Georgeff, Lansky, Rao, and others (see [Georgeff86:Procedural, Georgeff87:Reactive, Ingrand90:Managing, Ingrand92:Architecture])

·       The University of Michigan’s implementation of PRS called UMPRS [Lee94:UMPRS, Huber93:UMPRS]

·       SRI International's PRS-CL [Myers97:User]

·       SRI International’s ACT plan interlingua [Wilkins95:Common, Myers97a:Act, Myers97b:Act]

·       The Structured Circuit Semantics (SCS) representation of Lee and Durfee [Lee94:Structured, Lee97:Explicit]

·       Mobility aspects from Agent Tcl [Gray97:Agent], Agents for Remote Action (ARA) [Peine97:ARA], Aglets [Lange98:Programming] and others.


JAM’s family tree is illustrated below in Figure 1, where the small arrows indicate derivation and the large arrows indicate approximate development period.

1.1.         Overview

Each JAM agent is composed of five primary components: a world model, a plan library, an interpreter, an intention structure, and an observer.  This is illustrated in Figure 2.  The world model is a database that represents the beliefs of the agent. The plan library is a collection of plans that the agent can use to achieve its goals.  The interpreter is the agent’s “brains” that reason about what the agent should do and when it should do it. The intention structure is an internal model of the goals and activities the agent currently has and keeps track of progress the agent has made toward accomplishing those goals. The observer is a lightweight plan that the agent executes between plan steps in order to perform functionality outside of the scope of its normal goal/plan-based reasoning (e.g., buffer incoming messages).


The JAM execution semantics and behavior is a combination of that of UMPRS and SCS. Changes to the world model or posting of new goals triggers reasoning to search for plans that might be applied to the situation (this list of plans is called the Applicable Plan List, or APL).  The JAM interpreter selects[2] one plan from this list of applicable plans and intends it (i.e., commits itself to execute the plan).  The act of intending the plan places the now-instantiated plan (it has, at this point, a variable binding specific to the current situation) onto the agent’s intention structure, the agent’s multiple-goal runtime stack. The agent may or may not immediately execute the newly intended plan, depending upon the plan’s utility relative to that of intentions already on the intention structure. We discuss this in more depth later in this manual.

The agent developer deals explicitly with the world model, the plan library, the observer, and specification of the agent's initial goals.  In addition to the primary components describe above, there exists a function library and interface for specifying and performing low-level, non-decomposable “primitive” functions.  This document describes the theory behind each component, how the components interact, important representations and semantics, and any files that are necessary.  Samples of files specifying plans, goals, beliefs, and observer procedures are included with the JAM distribution.  Before continuing, we describe how to unpack the files in the JAM agent’s distribution and then how to compile and execute a JAM agent.

1.2.         Unpacking the JAM Agent distribution

 

The first step in building agents is to extract the various files from the downloaded file.  The download file is in the form of a zip file, which is a compressed collection of all of the JAM files.  A utility such as Winzip, unzip, or PKUnzip is necessary to extract the files.  The figure below illustrates the directory structure that is required and used by JAM.


Locate or create a directory in which to uncompress and extract the distribution (<Jam parent directory> in the figure above) and the directories indicated above will be created. The primary JAM source code is located in the jam directory.  This directory also contains several files that are helpful in building a JAM agent, such as make.bat and Makefile, and a todo file that contains a long list of ideas concerning extensions and modifications to the JAM agent architecture.  The examples directory contains a number of agent specification files (the files with the .jam extension) that serve both as examples to programmers as well as a source of regression tests.[3]   The primitives directory contains source code for primitive function definitions that implement the PrimitiveFunction interface (see Section 8). Finally, the JAM manual and class documentation (javadoc) can be found in the docs directory.

1.3.         Running and building JAM

JAM agents can be invoked soon after the downloaded file is uncompressed as described above.  As with all Java applications, the CLASSPATH variable must first be set appropriately.  For JAM, this means that the file jam.jar be added to the CLASSPATH definition.  The jam.jar file can be found in the jam directory in the figure above.  Other Java development environments typically require the equivalent operation to be performed.  If the class files from compiling the Java source code are to be used instead then the head of the JAM distribution (<Jam parent directory> in the figure above) needs to be added to the CLASSPATH definition rather than the JAR file.

JAM agents can be invoked from a command prompt (and via a couple of methods in the JAM class, described later).  The DOS and Unix command prompt lines for doing this have the form:

            java com.irs.jam.JAM <jam-options> <jam-files>

where <jam-files> represents a list of one or more files containing the agents plan library, goal list, Observer definition, and initial world model.  The "com.irs.jam" prefix is required because JAM has been defined to be in the com.irs.jam Java package.  Any of the .jam files in the examples directory can be used right after JAM has been unpacked from the distributed download file.

Following are two examples of JAM agent invocation:

      java com.irs.jam.JAM -w -g examples/blocks-world.jam

java com.irs.jam.JAM basic.jam examples/relations.jam

The first step JAM performs when invoked is to parse the text from the agent specification file(s) and create internal representations for this information before proceeding with execution.  If there are any parsing problems, JAM will indicate this with appropriate error messages and will abort execution.  If parsing was successful, JAM will begin to execute plans until the agent achieves all of its goals.

JAM recognizes the following runtime options:

-i        : show changes to the intention structure (e.g., whenever a goal fails and is removed).

-g       : show changes to the agent’s goal list (e.g., when a plan establishes a subgoal).

-f        : display the file name and line number of actions that fail

-p       : specifies a string, rather than a file, to be parsed into the agent's plans, goals, and/or world model.  Any number of -p arguments may be used on a command line.  Note that this is a new use of the -p runtime option.

-a       : show Applicable Plan List generation and selection information.

-s        : same as –a above.

-w      : show the world model whenever a change occurs to the world model (e.g., when a new element is added to the agent’s beliefs).

Warning: Use of the  -i, -g, -a, -s, , -f and -w flags results in copious amounts of information being displayed!

The JAM architecture currently compiles a number of statistics during execution and prints out the final statistics once it completes its execution.  The runtime statistics gathered are: the number of goals that the agent achieved; the number of cycles through the interpreter; the total number of Applicable Plan Lists (APLs) created (includes concrete-level APLS, metalevel APLS, and null APLs); and the number of null APLs generated.

The JAM agent can be built from the included Java source code by using the included Makefile file (for Unix-based systems), and makep.bat and make.bat files (for DOS systems).  For Unix, simply go to the JAM core directory (<JAM parent directory>/com/irs/jam) and type 'make' at the command line prompt.  For DOS systems, go to the JAM core directory and type 'make' at the command line prompt.  In case these make files do not work in your environment, it is a simple process to build the JAM agent manually.  To compile all of the Java source code, use the command:

javac *.java

in the JAM installation directory as well as the primitives and examples subdirectories.  For Integrated Development Environments, the typical steps are to create a new project and then include all of the Java files in the JAM installation directory as well as all the Java files in the primitives and examples subdirectories.

The JavaCC program is required if you wish to modify the JAM parser (to add or remove constructs, change keywords or syntax, etc., all of which are done in the JAMParser.jj file).  JavaCC is not necessary if you wish to use JAM as downloaded.  However, JavaCC must be run whenever any modification to the JAMParser.jj file is made.  The command to do this is:

javacc JAMParser.jj. 

For DOS systems, the batch file makep.bat is provided so that all you need to do is type 'makep' at the command line prompt (and then make in order to compile the resulting parser-related Java files).  Nothing special needs to be done for Unix systems as the Makefile provided should invoke JavaCC (and the javac) appropriately.  After successfully performing the JavaCC command.

Building an application using the JAM architecture consists of extending JAM low-level functionality by writing appropriate primitive functions in Java and then specifying agent behavior by writing plans, an initial world model, initial top-level goals, and an Observer procedure if that is required.  Once the primitive functions are written, the agent is built and invoked as above.

 


2.  BELIEFS

 

The JAM agent’s World Model holds the facts that the agent uses to represent the current state of the world.  Information that might be kept there includes state variables, sensory information, conclusions from deduction or inferencing, modeling information about other agents, etc.  Each world model entry is a simple proposition of the form:

relation_name            argument1 argument2 ... argumentN;

The ordering, semantics, and typing of the arguments is unconstrained and is determined by the programmer.[4]  For example, a relation with the name tree might specify the height, species, and color of a tree, such as in:

tree 20 ”Maple” ”Red”;

with the implicit parameter ordering of height (using an integer), then species (using a string), then color (using another string).  Because the order is unconstrained by JAM, the programmer is free to specify this information in a different order and with different argument types, as in:

tree 123 “maple” 20;

which has an implicit parameter ordering of color (using an integer this time), then species (using a string), then height (using an integer).  The order and content of a world model relation is therefore completely up to the discretion and control of the programmer and the JAM parser does not perform any consistency checking.

World model relation’s arguments are currently limited to the following types: strings (represented internally as a Java String), floating point numbers (represented internally as doubles), integer numbers (represented internally as longs), and native Java objects.

Specification of an agent’s initial world model consists of creating a text file containing the keyword “FACTS:” followed by the list of world model relations.  The agent parses the world model specification before execution begins.  A simple example world model specification, drawn from a robotics application, might be as shown below:

FACTS:

       FACT robot_status "Ok";

       FACT partner_status "Ok";

       FACT robot_initialized "False";

       FACT robot_localized "False";

       FACT robot_registered "False";

       FACT robot_position 10000 10000 0;

       FACT robot_location "Unknown";

       FACT self "CARMEL";

       FACT partner "BORIS";

       FACT object_found "False";

       FACT object_delivered "False";

       FACT communication_status "Ok";

       FACT plan_empty "False";

       FACT destination "Room4";

       FACT next_room "Room3";

       FACT next_node "Node12";

 

A JAM agent manipulates and queries the World Model using a number of actions available for use in plans.  Actions are available for putting entries onto the World Model (assert), removing entries from the World Model (retract), revising information already on the World Model (update), and two forms of queries (fact and retrieve).  We describe these actions in full detail later in Section 4 but we will give a few examples of how they can be used.

As an example, consider the robotics World Model specified above.  If the agent uses its vision system to acquire the scene in front of it, it can add this to its explicit knowledge by using the following action (where $scene represents a variable containing the image and $pose represents the robotic agent’s current pose):

ASSERT scene $scene $pose;

The robot can later remove this fact using one of the following actions (the second one removes all World Model entries with the relation name of scene):

RETRACT scene $scene $pose;

            or

RETRACT scene;

The robot can “remember” what its current destination is by using the following action, where the value of the $dest variable will be set to “Room4”:

RETRIEVE destination $dest;

The fact action can be used in the same manner as the retrieve action above as long as the $dest variable does not already have a value. Variables with bound values are not changed but are used to restrict matching to only those World Model entries that have a matching parameter. In the following example, the fact action will return that it failed to find a match if the $dest variable has any value other than “Room4”.

FACT destination $dest;

If the agent takes a new image, it can revise its knowledge in place rather than retracting and then asserting it.  The agent can do this using the following action:

UPDATE (scene $scene $pose) (scene $new_scene $new_pose);

In the update action, the first parenthetical grouping specifies a World Model pattern to match and replace with the contents of the second parenthetical grouping.

The examples above are just to give a taste of how an agent uses its World Model.  We describe all of these actions and others in more detail in Section 8.

 


3.  GOALS

 

A JAM agent's top-down behavior is invoked by specifying goals that the agent is to achieve, perform, or maintain.  All goals are given to the agent in a text form with the following syntax:

goal_type goal_name parameter1 ... parameterN <:UTILITY expression>;

goal_type is one of: achieve, perform, maintain, query.  The goal_name is a relation label identifying a goal's name, while the parameter arguments are the goal relation's values.  The :utility keyword and expression are optional and provide an opportunity to specify a numeric value or calculation that specifies the goal's utility to the agent.

A JAM agent may have a (possibly large) number of alternative plans for accomplishing a single goal.  It is JAM's built in capability to reason about the alternatives, to select the best alternative given the particular situation, and to switch between alternative goals as utilities for doing each goal change, that are some of its strongest advantages over standard programming paradigms.  The agent checks all the plans that can be applied to the goal are checked to see if any of them are relevant to the current situation by filtering out plans based upon their precondition and context fields.  Those plans that are applicable are collected into what is called the Applicable Plan List (APL - called the Set Of Applicable Plans, or SOAK, in PRS terminology).  A utility value is determined for each plan in the APL and the highest utility plan is selected and intended to the goal.  If the intended goal has the highest utility among all goals with intentions, then its plan is executed.  Otherwise, a previous intention still has a higher utility and that plan is executed.  As the utilities of the various goals change as the situation changes, the agent will switch between goals in order to continually pursue the highest-priority goal.

An agent's goals can be divided into two categories: top-level goals and subgoals.  The description of goals above applies to both top-level goals and subgoals.  We'll discuss each of these categories in more detail below and describe how the two categories differ.

3.1.         Top-level Goals

Top-level goals are the highest-level goals that the agent has. Top-level goals are specified to the agent by using the keyword “goals:” and then a list of goal specifications in the form specified above.  A simple example of a top-level goal specification for an agent might be:

GOALS:

    ACHIEVE robotics_demo_completed :UTILITY 10;

    MAINTAIN obstacles_avoided;

Top-level goal specifications are usually given to the agent within a file specified as a command-line argument (see Section 8), can be communicated to one agent from another agent and parseed (see Section 4.2.2) by the receiving agent, or by many other means.  The key is that the top-level goals must be specified in a text format as described above so that the agent can parse and internalize them. When adding top-level goals in this manner, where the agent parses a text specification, the goal parameters may only contain constant values (integers, floating-point numbers, or strings) as there are no variable bindings yet to establish values for any variables if they were to be used.

A final method for adding top-level goals is to use the post action within plans (see Section 4.2.2).  When using the post action, a single top-level goal can be directly added to the agent's intention structure. When adding top-level goals using a post action, where the agent is in the middle of executing a plan, the goal parameters may contain constant values and variables.  In this case, there may be values bound to variables by the time the post action is reached (actually, some variables may not have values bound to them, but this is dependent upon the agent programmer and is allowed by the JAM architecture).

Top level goals are persistent.  That is, they are pursued until they are satisfied (by successful plan execution or opportunistically by some other means, such as another agent) or are removed explicitly using an unpost action (see Section 4.2.2) within a plan.  In other words, if a plan for a top-level goal fails, then the agent removes its commitment to that goal by removing its intention (the instantiated plan), but leaves the goal on the intention structure.  As will be seen in the next section, subgoals are not persistent by default.  With this operationalization of top-level goals, agent have a low level of commitment to all top-level goals, and a strong level of commitment to goals that have intentions associated with them (which is consistent with, for example [Cohen87:Intention]).

3.2.         Subgoals


Subgoals are goals that the agent creates from within plans during plan execution.  The achieve, perform, maintain, and query actions are used in plans (see Section 4.2.2) to invoke subgoaling.  APL generation is performed and an intention is found and intended to a subgoal just as for top-level goals.  Subgoaling can be performed to arbitrary depth levels and can be recursive, where a plan for a particular goal can subgoal to the same goal.

When subgoaling is used  within plans, the utility of the lowest subgoal is used to determine the overall utility of what we call the intention thread.  Switching between highest-utility intentions, therefore, happens due to consideration of the utility of the "leaf" goals within an intention thread.  This is illustrated in the Figure 3.1, where utility calculations of non-leaf intentions are ignored for selection purposes.

A further difference between subgoals and top-level goals is that subgoals are not persistent by default.  If a plan fails for a subgoal, the subgoaling action is considered to have failed as if it were any other type of valid plan action.  The failure semantics of plans is discussed in detail in Section 4.2.

 


4.  PLANS

 

A plan defines a procedural specification for accomplishing a goal.  Its applicability is limited to a particular goal or data-driven conclusion, and may be further constrained to a certain precondition and maintained context.  The procedure to follow in order to accomplish the goal is given in the plan’s procedural body.  Each plan has a unique name that can be used to distinguish between procedures. Each plan has an explicitly or implicitly (i.e., default) defined utility calculation, which is used to influence selection of certain procedures over others through the default utility-based metalevel reasoning mechanism of JAM. Another optional component is the effects field, which is identical in syntax to a plan’s procedural body, but which is executed when the plan completes successfully and is used to perform World Model updating similar to add/delete list attribute in STRIPS plans [Fikes71:STRIPS].  A procedural specification of what the agent should do when a plan fails can be represented in a plan’s optional failure section. Another component of a plan is an optional documentation section, which provides a generic place for the programmer to put commentary related to the plan as a whole. The final possible field that can be defined for a plan is an attributes field, which provides a place for a programmer to put information concerning plan characteristics that can be reasoned about during plan execution and/or metalevel reasoning.

The basic structure of a JAM plan is shown below (optional fields are surrounded with the "<" and ">" symbols):

 

Plan:

{

    GOAL: [goal specification]

       OR

    CONCLUDE: [world model relation]

    NAME: [string]

    BODY: [procedure]

    <DOCUMENTATION: [string]>

    <PRECONDITION: [expression]>

    <CONTEXT: [expression]>

    <UTILITY: [numeric expression]>

    <FAILURE: [non-subgoaling procedure]>

    <EFFECTS: [non-subgoaling procedure]>

    <ATTRIBUTES: [string]>

}

 

Each of the sections of a plan is described below in more detail.  Before this, though, we discuss expressions, an important JAM representational building block.

4.1.         Expressions

Expressions are used in a number of places within JAM.  By definition, all of JAM’s values and variables are expressions.  A value may be an integer, a floating point number, a string, or a Java Object.  JAM and user-defined primitive functions are also considered expressions.

The syntax of function expressions within JAM plans follows the Lisp function format closely, where the first element is the function to perform while the remaining elements are arguments to the function, all enclosed within parenthesis.  For example, (+ 3 1) adds the numbers 3 and 1 together, while (> $x 5) returns a Boolean value True if the variable $x is greater than 5, and False if it is less than or equal to 5.

User-defined functions can be used in expressions in the same manner as built-in expressions.  For example, if you have developed a new primitive function called equals that compares two objects and returns True when the objects are equal and False otherwise, it may be used as follows:

WHEN : TEST (equals $obj1 $obj2) {

    // Process equal objects

};

 

This support extends even to “legacy” Java code that needs JAM’s Java reflection capabilities.  For example, if the equals primitive is defined in the Java class com.foo.bar.UserClass, the following form is acceptable (and must be used in this case):

WHEN : TEST (&& (!= $obj1 0)

                (!= $obj2 0)

                (com.foo.bar.UserClass.equals $obj1 $obj2)) {

    // Process non-null, equal objects

};

 

The following table lists the built-in JAM functions.

 

Function

Description

Function

Description

-

Subtraction

+

Addition or Concatenation

*

Multiplication

/

Division

%

Modulo

abs

Absolute Value

&&

Conjunction

||

Disjunction

!=

Inequality

==

Equality

>

Greater-than

>=

Greater or Equal

<

Less-than

<=

Less or Equal

!

Negation

 

 

 

Note that many functions allow mixed (i.e., integer and floating point) number operations.  Boolean conditionals, however, cannot have mixed argument types, in general.  It is illegal, for example, to compare a string with an integer.  A special allowance has been made for comparing Java objects, where the expressions (== $obj 0) and (!= $obj 0) can be used to determine whether a variable holding a Java object ($obj in the example) is null or not null.


Some examples of valid expressions are shown below.

Furthermore, most functions can have single or multiple arguments, and quite often more than two arguments.  Semantics for expressions with more than two arguments, such as in the ">" example above, is defined such that the relation must hold between the first argument and each of the rest of the arguments.  In the ">" case, the value of the $a variable must be greater than 10 and the value of $b and the value of $c to return True.  For arithmetic functions, the function is applied to each of the arguments.  For the "/" example, 30 is divided first by 2.0, then by 3, and finally by -4.

4.2.         Plan Body

The body of a plan describes the sequence of actions, a procedure, to be taken in order to accomplish a goal.  The body may contain JAM-provided actions, JAM-provided primitive functions, and user-defined primitive functions, and can be organized into any of a number of different constructs (described shortly).  A plan executes until it reaches the end of its encoded procedure.  The plan is also considered to have completed successfully if the plan is an ACHIEVE or MAINTAIN goal and the goal expression becomes true during the middle of execution of the body.

A plan body will fail if an action within the body fails and there are no alternative paths to procedure completion.  For example, a plan body with a simple sequence of actions will fail if any action in the sequence fails (this applies to subgoal actions such as achieve and perform as well).  Branch constructs such as or and do_any can be used to provide alternate execution paths to protect against action failure.

An example of a plan is shown below:[5]

Plan: {

NAME:

        "Example plan"

DOCUMENTATION:

        "This is a nonsensical plan that shows all of the possible actions"

GOAL:

        ACHIEVE plan_example $distance;

PRECONDITION: (< $distance 50);

CONTEXT:

        RETRIEVE task_complete $STATUS;

        (== $STATUS “False”);

BODY:

        QUERY determine_task $task;

        FACT problem_solved $task $solved;

        OR

        {

            TEST (== $solved "YES");

            WAIT user_notified;

            RETRACT working_on_problem "True";

        }

        {

            TEST (== $solved "NO");

            ACHIEVE problem_decomposed;

            ATOMIC

            {

                ASSERT working_on_problem "True";

                MAINTAIN problem_decomposed;

            };

        ASSIGN $result (* 3 5);

        };

 

        UPDATE (task_complete) (task_complete "True");

 

FAILURE:

        UPDATE (plan_example_failed) (plan_example_failed "True");

        EXECUTE print "Example failed.  Bailing out"

ATTRIBUTES: "test 1 cpu-use 3.0";

EFFECTS:

        UPDATE (task_complete) (task_complete “True”);

}

 

Note that JAM (and even its precursor, UMPRS) use structure programming constructs in contrast with previous instantiations of PRS (e.g., PRS-CL and PRS-Lite), which allow unstructured procedures (i.e., procedures with the equivalent of "goto" actions.)

4.2.1.             Plan Variables

Variables are represented in plans by a symbolic identifier preceded by a “$” symbol. In the example plan in the section above, variables are used in the goal, precondition, and body fields. The variables referenced in the goal field of a plan are bound from a parent or top-level goal.  If the plan is invoked through subgoaling from a parent plan, modification of the variable’s value is reflected in the variable binding in the parent plan.  In this manner, parameters can be passed to and returned from subgoals.  In the example above, the variable $distance is used in the precondition expression to constrain the plans initial condition to only those situations where the value of the variable is less than 50.  Another variable is used in the context field of the plan, where the value of the $STATUS variable is set as a result of the retrieve action searching through the agent’s World Model and finding a match.  In the line following the retrieve, the $STATUS variable’s value is compared to the string “False”.

Other than those variables referenced in the goal field and in subgoal actions, which are bound to parent and subgoaled plans, respectively, variables used in a plan are local to a plan instance.  That is, each APL element has its own internal table for keeping track of the plan’s variables and their values.  It is quite common to have an APL with multiple elements formed from the same plan with different variable bindings (e.g., based upon different World Model entries).  What this means is that if more than one instance of a plan is being executed simultaneously[6], changes to the variables in one plan do not affect the values of variables in the other plan.

Variables within a JAM agent’s plans can have values of Java Long integers, Java Double floating points, Java Strings, or arbitrary Java objects.  JAM supports many natural operations with the numeric and string types, such as arithmetic and string concatenation, respectively (see above for complete details), and can parse these types from text files such as those created for the agent’s plans and initial world model.

Java objects are handled internally using references to instances of the Java Object class and are not currently parsable from text files. Java objects must be created and returned by primitive functions.  Variables holding these objects can then be passed as arguments to other primitive actions or subgoals and can even be saved and retrieved to and from the agent’s World Model.  Manipulation of the objects’ inherent functionality from the plan level is currently very limited, however, and must generally be performed within primitive actions.  See the definition of the execute action in the following section for details on how some methods may be invoked directly from the plan level.

4.2.2.             Plan Actions

Actions within plans can be simple, directly specifying a function to perform, or a complex construct containing one or more actions and constructs within it.  For simplicity, we call both actions although it should be pretty clear when reading through the descriptions of the implemented actions which are simple functions and which are constructs.

There are a large number of predefined JAM actions, all of which are characterized by being written in uppercase letters in plans. Each action in a plan can specify a goal or condition to achieve, wait for, maintain, or query.  In addition, a plan action can be any of the following: a low-level primitive function to execute directly, an assertion of a fact to the world model, a retraction of a fact from the world model, an update of a fact in the world model, a fact or a retrieve statement that retrieves relation values from the world model, or an assign statement that assigns variables the results of run-time computations. Furthermore, iteration, branching, and parallel execution are accomplished through while, do-while, or, and, do_all, do_any, when, and parallel constructs.  For convenience when testing plan failure behavior (or for other reasons) there is also a fail action which is an action that always fails.  An example of quite a few of these actions is included in the example plan above.  Each of the supported actions is listed in the table below and is described in more detail in alphabetical order after the table.

 

Action

Description

Action

Description

ACHIEVE

Subgoal

AND

Do all branches; try in order

ASSERT

Add to world model

ASSIGN

Set variable value

ATOMIC

Perform without interruption

DO-WHILE

Iterate

DO_ALL

Do all branches in random order

DO_ANY

Do one random branch

EXECUTE

Perform primitive action

FACT

Check world model values

FAIL

Unconditionally fail

LOAD

Parse JAM input file

MAINTAIN

Subgoal

NEXTFACT

Get the next matching world model relation retrieved with RETRIEVALL

OR

Do any branch; try in order

 

 

PARALLEL

Execute all branches simultaneously

PERFORM

Subgoal

POST

Add top-level goal

QUERY

Subgoal

RETRACT

Remove from world model

RETRIEVE

Get values from world model

RETRIEVALL

Get all matching world model relations

SUCCEED

Unconditionally succeed

TEST

Check condition

UNPOST

Remove goal

UPDATE

Change world model

WAIT

Wait for condition/goal

WHEN

Conditional execution

WHILE

Iterate

 

ACHIEVE      goal_name parameter1 parameter2 ... parameterN :UTILITY expression;
An achieve action causes the agent to establish a goal achievement subgoal for the currently executing plan.  This then triggers the agent to search for plans in the plan library that can satisfy the goal goal_name given the current context.[7]   Parameters can be used as arguments to the goal to be achieved and can also be used to get return values back from the invoked plan.  If the invoked plan fails and the goal was specified as a subgoal of a plan, then the achieve action fails with ramifications identical to the failure semantics as for any other plan body action that fails.  The failure semantics for top-level goals is different, however, and is explained in Section 3.

An achieve action can optionally specify the utility of the goal using the keyword :UTILITY expression after the parameters.  If the utility is not specified, it has the default utility 0.0. The details of how the goal utility is interpreted will be explained in Sections 9, but in general it is combined additively with a plan’s priority to calculate the overall priority of an executing plan.

achieve subgoals differ from perform subgoals (described below) in several important aspects.

1.     The agent checks to see whether the subgoal has already been accomplished before generating an APL.  If the goal has been accomplished, the plan does not subgoal; it just succeeds.  If the goal has not been accomplished, the plan does subgoal.

2.     The agent only considers plans that have achieve goal specifications during generation of the applicable plan list (APL).  This means that plans with perform goal specifications will not be executed for an achieve goal.

3.     The agent continually monitors for goal achievement. Typically, the plan selected for the subgoal will be the means by which the subgoal is accomplished.  However, if the agent detects (opportunistic) accomplishment of the goal (perhaps by another agent), it will consider the subgoal action successful and discontinue execution of the plan established to achieve the subgoal.

4.     If the plan selected for accomplishment of the achieve goal completes successfully, the agent will assert a relation to the world model.  The world model entry asserted is the goal specification for the goal just achieved.  For example, the first achieve example below would cause JAM to assert the fact robot_homed $x $y $orient for the appropriate grounded values of the variables.

Note that the JAM achieve action differs from the UMPRS version of the achieve action in that UMPRS does not have goal achievement semantics and is therefore like JAM's perform action.

Examples of ACHIEVE actions are shown below:

Example: ACHIEVE robot_homed $x $y $orient;

Example: ACHIEVE robot_homed $x $y $orient :UTILITY (+$x $y 10);

 

AND    { action-sequence1 } ... { action-sequenceN };
where each action-sequence (also called a branch) is one or more of any of the actions or constructs listed here and N > 0.  The semantics of an and action is that the interpreter will execute each of the branches in turn (based on the order in which they appear in the plan definition file), with the first branch in the plan executed first.  If all of the branches succeed, then the and action succeeds.  If any branch fails, then the entire and action fails.[8]

Example:

 

     AND

     {

         ACHIEVE moved_to $x $y;

     }

     {

         ACHIEVE moved_to $x $y;

     };

 

 

ASSERT         relation_name argument1 argument2 ... argumentN;
Information is placed into the world model using an assert action. Assertion causes the agent to search the world model for the given relation name.  If it finds a world model entry with the same relation name and the same argument values, the action does nothing.  Otherwise, the action appends the asserted fact, with all of the arguments evaluated into concrete values, onto the world model. This action always succeeds.

Example:  ASSERT goal_in_view “True”;

NOTE: To modify a relation in the world model, use the update action, described below.

 

ASSIGN         variable expression;
Variables can be assigned values using the assign action.  The given expression is evaluated and the variable is assigned the resulting string, floating-point number, integer number, or Java Object. This action always succeeds.

Example: ASSIGN  $diff (- $x2 $x1);

 

ATOMIC        {action1; action2; ... actionN; )

The sequence of actions action1, action2, ... actionN are all executed before control is given back to the interpreter.  Normally, the interpreter performs several functions between each action (see Section 8.)  This might, in some cases, cause the agent to interrupt execution of a sequence of actions in the middle of the sequence.  Using the atomic action bypasses this interpreter activity, guaranteeing that the sequence of actions will complete.  The atomic action succeeds when the entire sequence executes successfully, and fails if the sequence fails.

Example:

 

     ATOMIC

     {

         UPDATE (debug_mode) (debug_mode "False");

         UPDATE (run_mode) (run_mode "True");

         EXECUTE print "Now entering run mode.\n";

     };

 

 

DO      { action1; action2; ... actionN; } WHILE : action0;

The sequence of actions  action1, action2, ... actionN are executed (N > 0) and then, if action0 (typically a test action) succeeds, the sequence of actions are repeated.  This continues until action0 fails, and the action after the do is then executed, or until one of action1, action2,... actionN fails, whereby the entire do action fails.

Example:

     DO

     {

         EXECUTE print $x;

         ASSIGN $x (+ $x 1);

     } WHILE : TEST (< $x 10);

 

 

DO_ALL        { action-sequence1 } ... { action-sequenceN };
where each action-sequence (also called a branch) is one or more of any of the actions or constructs listed here, and N > 0.  The semantics of a do_all action is that the interpreter will execute the branches in random order.  If all of the branches succeed, then the do_all action succeeds.  If any branch fails, then the do_all action fails.

Example:

 

     DO_ALL

     {

         ACHIEVE moved_to $x $y $orientation;

     }

     {

         ACHIEVE moved_to $x $y $orientation;

     };  

 

 

DO_ANY        { action-sequence1 } ... { action-sequenceN };
where each action-sequence (also called a branch) is one or more of any of the actions or constructs listed here, and N > 0.  The semantics of a do_any action is that the agent will execute the branches in random order.  If any one of the branches succeed, then the do_any action succeeds.  If all branches fail, then the do_any action fails.

Example:

 

     DO_ANY

     {

         ACHIEVE retrieved_bid "Agent1";

     }

     {

         ACHIEVE retrieved_bid "Agent2";

     };  

 

 

EXECUTE     function_name parameter1 parameter2 ... parameterN;
EXECUTE     class_name.execute parameter1 parameter2 ... parameterN;
EXECUTE     class_name.function_name parameter1 parameter2 ... parameterN;
EXECUTE     class_name.function_name[object_ref] parameter1 parameter2 ... parameterN;
Primitive functions are executed by using an execute action. Primitive functions implement the lowest-level (i.e., “native code”) functionality of an agent and therefore are where all the “real” work is done by the agent-based application.  Certain general-purpose primitive functions, such as printing out textual information, are already implemented and are provided as part of the JAM distribution.  We describe these in Section 8.4.  Most application-specific primitive functionality will need to be programmed by an agent programmer, and we describe how to do this in detail in Section 8.  We have tried to support a wide range of implementation and invocation paradigms so the execute action has a number of different syntaxes and semantics.  In particular, there are three syntactic forms of the execute action (of the four forms listed above, the second and third share the same syntax) that have four distinct semantic behaviors. 

Primitive function parameters can be used for input only, output only, and both input and output of values between a plan and native Java code. 

The first semantic form of the execute action is used to perform primitive functions that are encoded in the UserFunctions.java file that comes with the JAM source code distribution.  An agent programmer can add code to this UserFunctions class to perform whatever functionality is required.  The primary advantages of this form are that the reflection capabilities are not required and that it results in relatively terse plan lines since class paths (see below) do not need to be used to specify the function to perform.  The primary disadvantage is that JAM architectural source code must be modified.

The second semantic form of the execute action is used to invoke a member function of a Java class and the class implements the PrimitiveAction interface.  The JAM interpreter dynamically loads and creates an object of the specified class using the Java reflection package (which uses the default constructor for the class).  The interpreter then searches for a member function with a matching method name (in this case, it will always be execute because the specified class implements the PrimitiveAction interface).  Note that this form of execute does not require, nor does it permit, specification of a particular object instance upon which to invoke the method.  The primary advantage of using this form is the ability to write new classes that do not interfere with JAM source code.

The third semantic form of the execute action is used to invoke a member function of a Java class and the class does not implement the PrimitiveAction interface (e.g., some pre-existing Java class).  In this case the JAM interpreter again dynamically loads and creates an object of the specified class using the Java reflection package (which uses the default constructor for the class).  The interpreter then searches for a member function with a matching method name.  Note that this form of execute does not require, nor does it permit, specification of a particular object instance upon which to invoke the method.  This form operates as if the functionality invoked is a Java static method.  Argument types must match for the search to be successful (i.e., an Integer object or an int will match a JAM ValueLong; a Float, Double, float, or double will match a JAM ValueReal; a string will match a ValueString; and basically anything else will match a ValueObject).  The primary advantage of using this form is the ability to invoke legacy functionality without having to add any special “wrapper” code.  The primary disadvantage of this form is that atomic bidirection parameters (i.e., int, long, float, double) are not currently supported (i.e., arguments that are modified are not reflected back to the agent’s plan level).  Objects that are modified are correctly reflected back to the plan level.

The fourth semantic form of the execute action provides the ability to invoke a method on a Java object.  Reflection is performed only to match the method’s name and parameter types and then the method is invoked on the specified object.  The primary advantage of using this form is the ability to invoke legacy functionality without having to add any special “wrapper” code.  The primary disadvantage of this form is that this form also has the same limitations with bidirection atomic parameters as the third form.  Examples of each of the forms of execute are shown below.

Example of invoking a primitive function defined in UserFunctions.java:

Example: EXECUTE process_image $img $num_objs $objlist;

Example of invoking a primitive function defined in the class RoboticImage that implements the PrimitiveAction interface:

Example: EXECUTE com.irs.util.RoboticImage.execute $img $num_objs $objlist;

Example of invoking a method (processImage) of a “legacy” class (RoboticImage) as a primitive function:

Example: EXECUTE com.irs.util.RoboticImage.processImage $img $num_objs $objlist;

Example of invoking a method (processImage) on an instance of a “legacy” class (whatever $img is) as a primitive function:

Example: EXECUTE processImage[$img] $num_objs $objlist;

 

FACT              relation_name argument1 argument2 ... argumentN;
Information from the world model can be accessed using the fact action.  The world model is searched for the first entry with the given relation name that has matching constant and variable values. Any arguments that are unbound variables are assigned the appropriate values from the matched world model entry.  If no match is found, the fact action fails.

Example: FACT robot_location $x $y $orient;

 

FAIL;
This action always fails.  It can be used to explicitly cause a branch or a plan to fail without having to resort to some more obscure, implicit method.

Example: FAIL;

 

LOAD             file_list

This action provides the functionality of bringing in additional plans, goals, world model facts, etc. from a file during execution, where file_list is a list of filenames to load and parse.  This is not yet implemented in JAM (it is functionality provided by UMPRS that we will implement soon).

Example: LOAD ”file1.jam” ”file2.jam” ”file3.jam”;

 

MAINTAIN    goal_name parameter1 parameter2 ... parameterN;
A maintain goal indicates that the specified goal must be reattained if it ever becomes unsatisfied.  A maintain goal is very similar to an achieve goal except that a maintain goal is never removed from the agent’s goal list automatically.  The only way that a maintain goal is removed from the agent’s intention structure is to perform an explicit unpost action (see below) within a plan or Observer definition.  A maintain goal only make sense as a top-level goal of an agent.

Example: MAINTAIN objects_avoided;

 

NEXTFACT   variable relation_name argument1 argument2 ... argumentN;
The nextfact action retrieves the next world model relation from the set retrieved using a prior retrieveall action. The arguments to nextfact are a variable and a world model relation. The retrieveall action stores the list of world model matches for the relation specified in a variable and it is this variable that should be used in variable (the first argument above).  Each call to nextfact changes the variables in the argument list of the world model relation specified to the next match found in the world model. This action succeeds when another matching world model relation is found and fails when no further world model matches could be made.

Example: NEXTFACT $onfacts ON $blockA $blockB;

 

OR      { action_sequence1} ... { action_sequenceN }; 
where action_sequence (also called a branch) is one or more of any of the actions listed here, and N > 0.  The semantics of an OR action is that the agent will execute each of the branches in turn, with the first branch in the plan executed first.  If any of the branches succeed, then the or action succeeds.  If all branches fail, then the or action fails.

Example:

 

OR

{

TEST (< $z 0);

EXECUTE print "Error: altitude value < 0!\n";

}

{

TEST (>= $z 0);

ASSIGN $altitude $z;

};

 

 

PARALLEL   { action_sequence1 } ... { action_sequenceN };
NOTE: The parallel action no longer works quite as specified below since the advent of Java 2 and seems to vary in behavior depending upon computing architecture.  Use with caution.

For the parallel action, action_sequence (also called a branch) is one or more of any of the actions allowed within JAM plans, and N > 0.  The semantics of a parallel action is that the interpreter will execute each of the branches simultaneously using separate threads.  Precisely, the first action of each branch is executed in parallel, then the second action of each branch is executed in parallel, etc. (as long as there are actions in the branch, of course).  This lock-step parallelism preserves the execution semantics of interleaving action execution with Observer and interpreter execution.  If all of the branches succeed, then the parallel action succeeds.  If any branch fails, then the parallel action fails.

Example:

 

EXECUTE create_proposal $proposal;

PARALLEL

{

EXECUTE send_proposal $proposal "Agent1";

}

{

EXECUTE send_proposal $proposal "Agent2";

};

 

 

PERFORM    goal_name parameter1 parameter2 ... parameterN :UTILITY expression;
An perform action causes the agent to establish a behavior performance subgoal for the currently executing plan.  This then triggers reasoning to search for plans in the plan library that can satisfy the goal goal_name given the current context.[9]   Parameters can be used as arguments to the goal to be performed and may also be used to get return values back from the invoked plan.  If the invoked plan fails, and the perform action was within a plan body, the perform action fails as would any other plan body action.  The failure semantics for top-level goals is different, however, and is explained in Section 3.

A perform action can optionally specify the utility of the goal using the keyword :utility expression after the parameters.  If the utility is not specified, it has the default utility 0.0. The details of how the goal utility is interpreted will be explained in Section 9, but in general, it is combined additively with a plan’s priority to calculate the overall priority of an executing plan.

perform subgoals differ from achieve subgoals (described above) in several important aspects.

1.     The agent does not check to see whether the subgoal has already been accomplished before generating an APL.  An APL will be generated even if the agent’s world model indicates that a goal with the same specification has already been achieved.

2.     The agent considers plans that have achieve goal specifications as well as plans that have perform goal specifications during generation of the applicable plan list (APL).  This means that plans with an achieve goal specifications may be executed for a perform goal.

3.     The agent does not monitor for goal achievement during plan execution.  The plan selected for the perform goal, whether the plan’s goal specification is perform or achieve, will execute until the plan succeeds or fails.

4.     An assertion to the world model entry that the goal has been achieved is only performed if the plan has an achieve goal specification  and the plan selected for accomplishment of the perform subgoal completes successfully.  There is no assertion to the world model if the plan selected for accomplishment of the perform subgoal completes successfully and the plan has a perform goal specification.

 

Example: PERFORM process_incoming_bids $BIDS $AGENTS;

 

POST              goal_expr;
The post action has the effect of adding a top-level goal (i.e., a goal that has no parent goal) to the agent’s intention structure.  The goal expression goal_expr is a standard achieve, perform, query, or maintain plan action consisting of the goal type, goal name, goal arguments, and the optional utility expression.

Examples:

    POST ACHIEVE robot_homed $x $y $orient :UTILITY (+ $x $y 10);

    POST PERFORM process_incoming_bids $BIDS $AGENTS;

 

QUERY          goal_name parameter1 parameter2 ... parameterN; 
A query action is functionally identical to an achieve action.  It is provided to allow the programmer to be more explicit about the semantics of the action’s goal (information acquisition, in particular).  If the invoked plan fails, the query action fails.

Example: QUERY vision_processe_list;

 

RETRACT     relation_name argument1 argument2 ... argumentN; 
One or more entries in the world model can be removed from the database using a retract action.  The agent searches the world model for all entries with the given name, and the given parameter values, and removes them if any exist.  If the arguments do not match, then effectively no action is taken.  This action never fails.

Example: RETRACT goal_in_view “True”;

 

RETRIEVE    relation_name argument1 argument2 ... argumentN;
Information from the world model can be accessed using the retrieve action. The retrieve action gets values from the world model for the variable arguments regardless of the current value of the variables.  Like the fact action, this action searches for the first world model entry, in this case matching only against the relation name. This action should be used carefully because the variable arguments will likely be overwritten with new values.  This action succeeds if there is an entry with the given relation name in the world model, and fails otherwise.

Example: RETRIEVE robot_location $x $y $orient;

 

RETRIEVEALL        variable relation_name argument1 argument2 ... argumentN;
Information from the world model can be accessed using the retrieveall action. The arguments to retrieveall are a variable and a world model relation. The retrieveall action is similar to retrieve but gets all values from the world model (at the time of the call) for the world model relation specified and stores the list of matches in variable.  This action is intended for use with the nextfact action (see above), which can iterate through the world model relation matches. This action always succeeds.

Example: RETRIEVEALL $onfacts ON $blockA $blockB;

 

SUCCEED;
This action always succeeds.  It can be used to explicitly indicate that a branch should succeed (e.g., in a “try-catch” OR construct) without having to resort to some more obscure, implicit method.

Example: SUCCEED;

 

TEST              expression;

The action succeeds if the expression evaluates to true, otherwise it fails.  Note that an expression is considered to be true if it returns Value.TRUE, a non-zero integer or floating-point value, a non-empty string (i.e., length greater than zero), or a non-null Object.

Example: TEST (== $x $y);

 

UNPOST        goal_expr;
The unpost action looks through the agent’s goal list for the goal specified in goal_expr.  If it finds the goal, and the goal is not currently being pursued, it simply removes the goal from the agent's intention structure.  However, if a plan for the goal is being executed, the goal is not immediately removed.  The goal will be removed when the agent’s interpreter tries to execute the goal’s next plan action.  This will result in the goal and all of its subgoals being removed from the agent’s intention structure. Note that this is considered abnormal completion of the goals (i.e., ACHIEVE goals are not achieved nor are PERFORM goals performed) such that the FAILURE section of the intention associated with the goal and the FAILURE sections of any of the UNPOSTed goals subgoals will be executed.

The goal expression goal_expr is a standard achieve, perform, query, or maintain plan action.  The goal expression may specify only a subset of the arguments for goals on the agent’s goal list, indicating that any goal(s) matching the partial specification should be removed.  For example, if only the goal name is given in the unpost action, any goals in the agent’s goal list with that name will be removed.  Similarly, if only the goal name and a utility are specified, any goals with identical name and utility, regardless of any arguments, are removed.  Concrete examples are shown below.  This action always succeeds, and merely varies in the number of goals removed from the goal list.

Example:  UNPOST ACHIEVE robot_homed;

This will remove all goals with the name robot_homed

Example: UNPOST ACHIEVE robot_homed $x $y;

This will remove all goals with name robot_homed and with the exact same values for its first two arguments as the values of the variables.

Example:  UNPOST ACHIEVE robot_homed $x $y $orient :UTILITY 10;

This will remove all goals with name robot_homed and with the exact same values for its first two arguments as the values of the variables, and with the exact same utility.

 

UPDATE        (relation_name arg1 arg2 ... argN)  (relation_name arg1 arg2 ... argM);
The agent searches the world model for all entries with the same name and the same parameter values as given in the first relation and removes them if any exist. The second relation is then asserted to the world model.  If no arguments are given in the first relation then all but one of the world model relations with the matching relation name are removed and the remaining relation is updated with the information given in the second relation.  This action never fails.

Example:  UPDATE (goal_in_view) (goal_in_view “False”);

Example:   UPDATE (goal_in_view “True”) (goal_in_view “False”);

 

WAIT             goal_name parameter1 parameter2 ... parameterN;

WAIT             : action;

The wait action causes plan execution to pause until the specified goal is achieved or the specified action returns successfully. Execution of the plan continues "in place", with the agent checking the goal or action every cycle through the interpreter.  This action never fails.

Example: WAIT all_bids_received “:contract 1479” $agent_list;

Example: WAIT : TEST (> $price 40.5);

 

WHEN            : action0 { action1; action2; ... actionN; }; 
The action0 (typically a test action) is executed and, if it succeeds, the sequence of actions action1, action2, ... actionN is executed.  Use of this action simplifies programming many conditional situations.  If more complex conditional branches need to be programmed, use the or construct. This action fails only when an action in its procedural body fails.  Failure of action0 does not cause the when action to fail, but simply causes execution to pass to the next action in the plan.

Example:

WHEN : TEST (< $z 0)

{

     EXECUTE print "Error: value < 0!\n";

}

 

 

WHILE           : action0  { action1; action2; ... actionN;};
The action0 (typically a test action) is executed and, if it succeeds, the sequence of actions action1, action2, ... actionN  is executed.  When actionN has been successfully executed, action0 is again checked.  This continues until eventually action0 fails, and the action after the while is then executed, or until one of action1, action2,... actionN fails, whereby the entire while action fails.

     Example:

     WHILE : TEST (< $x 10)

     {

         EXECUTE print $x;

         ASSIGN $x (+ $x 1);

     };  

4.2.3.             Plan Comments

Comments can be added to any parsed file (those specifying top-level goals, world model entries, plan, etc.) using “//” characters and the pair “/*” “*/”. The “//” characters indicate that the remainder of the line is a comment.  The “/*”  “*/” pairing is interpreted as making a comment out of whatever text is between them and can extend to multiple lines of text. This is identical to the commenting scheme of C++ and Java.

4.3.         Plan Name

Each plan can include a “name:” field that provides a means of specifying a text string identifying the plan. The name is merely a label for the plan.  A JAM convention is to specify a unique label for each plan. The plan’s name is primarily for human perusal and is currently not used by the agent at all during execution.

Example: NAME: “Process incoming bids”;

4.4.         Plan Documentation

Each plan may optionally have a “documentation:” field that may be used to store a descriptive text string.  The string’s contents are completely unconstrained and may contain anything the programmer wishes.  For example, the string may contain notes about special characteristics of the plan, a description of how the plan works, etc.  This field does not currently impact agent execution in any way.

Example: DOCUMENTATION: “This plan processes bids using a simple lowest-cost heuristic.”;

4.5.         Plan Execution Behavior

JAM agents can exhibit both goal-driven and data-driven behavior.  Agents may be goal-driven, where the agent is motivated by high-level statements about a state of the world to achieve or activities to perform. Agents may also be data-driven, where their behavior is motivated by low-level, perhaps transient data states, such as proximity to danger.  The following two sections describe how plans can be written to specify goal-driven or data-driven behavior.

4.5.1.             Plan Goal

Goal-driven behavior is specified by including a “goal:” field in a plan.  This field’s contents specify the goal or activity that successful execution of the plan’s procedural body (described below) will accomplish.  The syntax of the goal field is the same as for a plan body’s achieve, maintain, or query action (i.e., a goal name followed by arguments).  During execution, the interpreter matches this goal expression against the agent’s top-level goals.  If the plan’s goal specification matches and if the plan’s precondition and context expressions pass, the plan may then be instantiated (i.e., have values from the current situation assigned to plan variables) and intended (i.e., added to the agent’s intention structure).

Note that the “goal:” and “conclude:” fields are mutually exclusive.

Example: GOAL: ACHIEVE bids_processed $bids;

Example: GOAL: PERFORM bid_processing $bids $timelimit;

4.5.2.             Plan Conclude

Data-driven behavior is indicated by using a “conclude:” field in a plan.  This specifies a World Model relation that should be monitored for change.  If the given World Model relation changes in some way (i.e., it is asserted or updated), the agent’s interpreter considers the plan for execution. If the plan’s precondition and context expressions pass, the plan may then be instantiated (i.e., have values from the current situation assigned to plan variables) and intended (i.e., added to the agent’s intention structure).  Note that the context may be evaluated more than a single time during each cycle through the interpreter as a plan may be considered at multiple metalevel reasoning levels.

Note that the “goal:” and “conclude:” fields are mutually exclusive.

Example: CONCLUDE: stock_price $PRICE;

4.6.         Plan Context

The agent developer can specify the situations that plans are valid in by including the optional “context:” field of a plan.  A plan’s context specifies one or more expressions that describe the conditions under which the plan will be useful throughout the duration of plan execution.  The context field of a plan is first checked when a plan is being considered for inclusion in an Applicable Plan List (the APL), a list of plans that could be used to solve a goal.  The context field’s conditions are also checked during execution of a plan to make sure that the plan is still applicable even in the face of a changing environment.  In contrast, the precondition field, described later, only specifies the initial conditions that must be met before the plan should be considered.

The context may contain the world model actions retrieve and fact that can be used to:

1.     check for particular world states

2.     bind local plan variables to values in the world model.

The context specification is described in terms of a list of expressions (described above).  Each expression is evaluated in turn, and its return value checked.  Predefined JAM expressions such as <, >=, !=, etc. can be used in the context to check for common relationships.  The user can also define primitive functions that can be used in expressions.  If every expression in the context returns “true” (defined as a non-zero number, a non-empty string, a non-null Object, or the built-in type Value.TRUE), then the context is considered valid.  If any of the expressions returns “false” (zero, a zero-length string, a null Object, or Value.FALSE), then the context expression is considered to have failed.

It is very important that plan programmers understand when components of context expressions fail and when they succeed.  For example, failure for a fact action (whose success and failure semantics are described above) results from the inability of JAM’s interpreter to find a correct match in the world model for the given world model relation taking into account any constant arguments and instantiated variable arguments in the fact action.  The fact action uses the instantiated arguments during matching and does not overwrite those values with new values.[10]  This is important to know because care must be taken that the plan body does not change the value of variables used in facts in the context to values that would cause the context to fail during a subsequent context check.

An example of a context expression is shown below.  It demonstrates the use of the
JAM action fact, the relationship ! =, and the user-defined predicate (a primitive function) task_complete, which might check to see if the given task has been completed.

 

CONTEXT: FACT task $task;

         (!= $task "Do Nothing");

         (task_complete $task);

 

If the context check is not satisfied during APL generation, the plan is not considered applicable to the situation and is dropped from consideration for execution.  Also, if the context of a currently executing plan fails, the entire plan and any of its subgoals are deemed invalid and removed from the agent’s intention structure.

As was mentioned earlier, the list of context entries is implicitly considered a conjunction (an and), so that each of the three context expressions in the example above must evaluate successfully.  The first expression in the example context, the fact action, is the most interesting and complicated.  Two cases exist, depending on whether the variable $task  has a value bound to it:

1)     $task has no value binding: the world model is searched for a relations with the name “task” and, if such a relation exists, a value is bound to the variable from the first such relation found.

2)     $task has a value binding: the context will fail if there are no world model entries with the name “task” and that have a first argument that matches the value of the variable $task, even if there are other world model entries that do share the same relation name of “task” but that do not have the correct first argument.

 

The example context will also fail if the value of the variable $task is the string “Do Nothing”, or if the user-defined function task_complete fails.

Notice that plan variable bindings can be established using the context and subsequently used later in the context and in the plan body.  World model actions such as fact and retrieve can be used to get values from the world model that can then be used in expressions later in the context.  Again, note that particular attention should be paid to the failure semantics of each of the entries in the context.  If the plan starts executing, the context will be checked with the current bindings of the variables.  If the binding for $task ever changes, whether to the string “Do Nothing” or otherwise, the context will fail if a world model entry with a matching value does not exist.  If the variable changes to the string “Do Nothing”, the context will fail too, of course.

Primitive functions may also be used within the context of a plan.  The primitive function will be executed normally.  The return value of the primitive function is used to determine whether the context is satisfied.  A return value of Value.FALSE,  zero, or an empty string are interpreted as a failure of a primitive, so care must be taken when designing primitive functions that may be used in plan contexts so that they do not return these values if that is not the desired interpretation.  The syntax of using a primitive function in this manner is the same as that for other expressions, namely surrounded by parentheses.

An example of a plan context incorporating a primitive function is shown below.  This example demonstrates how a primitive function can bind a value to a variable that is used later in the context (it can be used within the plan body too, of course).  This example context, then, is satisfied when the distance between two points is less than 5.

PLAN {

GOAL: ACHIEVE example_completed $x1 $y1 $x2 $y2;

CONTEXT:

        (calc_distance $x1 $y1 $x2 $y2 $distance);

        (< $distance 5);

BODY:

      EXECUTE print "Within 5 units.\n";

}

4.6.1. Predicates

Within JAM, several actions have semantics different from their “normal” plan body semantics.  This parallel occurs when the actions are used as predicates (i.e. used within an expression rather than as a plan action).  Each predicate returns a Boolean value (i.e. Value.TRUE or Value.FALSE) which can be used in expressions located within contexts or such actions as test or while. The semantics of each predicate is given below.

 

ACHIEVE  goal_name parameter1 parameter2 ... parameterN :UTILITY expression;

This predicate checks for the presence of the given goal in the agent’s intention structure.  It uses the current variable values within the goal’s parameter list and checks for an exact match.  If an exact match is found, the predicate returns true, otherwise it returns false.

Example: TEST (ACHIEVE robot_homed $x $y $orient :UTILITY (+ x y 10));

 

FACT  relation_name argument1 argument2 ... argumentN;

A fact acts as a predicate once variables in the fact action have values bound to them.  This predicate tests to see if the given world model relation with the given arguments exists in the world model. It returns true if one is found, false otherwise.

Example:  TEST (FACT robot_location $x $y $orient);

 

RETRIEVE relation_name argument1 argument2 ... argumentN;

The retrieve action acts as a predicate when found in a context expression or a test action (also in such cases as the test component of a while or do-while action).  This predicate tests to see if there are any world model entries with the given relation name and the correct number of arguments.  If a world model entry exists, this predicate returns true, otherwise it returns false.

Note that a side effect of this predicate is to bind new values to the variables if even a partial world model match is found.  Any variable bindings in the retrieve predicate will be replaced.

Example: TEST (RETRIEVE robot_location $x $y $orient);

4.7.         Plan Precondition

The “precondition:” field is an optional field that is used to specify the initial conditions that must be met before the plan should be considered for execution.  The contents of the precondition are identical in form to the context field.  Note that the precondition of a plan is checked only when a plan is being considered for inclusion in an APL; unlike a plan’s context, the precondition expression is not checked during runtime.  Note also that the precondition may be evaluated more than a single time during each cycle through the interpreter as a plan may be considered at multiple metalevel reasoning levels.

Example: PRECONDITION: (>= (- $CURRENT_PRICE $BUY_PRICE) 5.0);

4.8.         Plan Utility

The optional “utility:” field of a plan specifies a numeric utility of the instantiated plan (i.e., has values from the current situation assigned to plan variables). The utility can be any valid expression that returns a numeric value.  The expression can include plan variables.  A plan has a default utility of 0.0 when it is not explicitly specified.

For goal-based plans, the plan’s utility value is combined with the goal’s utility to determine an overall utility for the instantiated plan.  The combination function used currently is simple addition.  For example, if a top-level goal has a “:utility” expression specified that evaluates to 10.5 and a plan with a matching goal specification has a “utility:” field that evaluates to 1.3, the JAM interpreter considers the plan to have a utility rating of 11.8.

Example: UTILITY: (- 50.0 $DISTANCE);

4.9.         Plan Attributes

Each plan may have an optional “attributes:” field that provides a place to specify characteristics about the plan that metalevel plans can extract and perform reasoning.  The syntax of the attributes field is a simple text string.  JAM places no restrictions upon the contents or structure of the string.  A primitive action provided with the JAM distribution assumes that the string’s contents are in a list of label/value pairing and provides the functionality to extract the appropriate numeric value given an attribute’s label.

Example: ATTRIBUTES: “Cost 10 Time 14.6”

4.10.     Plan Effects

Each plan may have an optional “effects:” field that provides a place to specify a procedure that will be executed when the plan completes successfully.  The syntax of the effects field’s contents is identical to a plan’s body but is typically used to modify the agent's world model (like an add/delete list in STRIPS [Fikes71:STRIPS].  The only limitation the effects field has with respect to a plan’s body field is that there can be no subgoaling within an effects section.   Other than this, everything that can be done within a plan’s body can be done within the plan’s effects.  The procedure of the effects section is executed atomically.  That is, it cannot be interrupted by the agent interpreter (e.g., in order to switch execution to another, perhaps higher utility, plan)

Note that UMPRS plans have a field with the same name but that the semantics of the UMPRS implementation is quite different.  In UMPRS, the effects field is used while the agent is executing in a “simulation” state and is not used during normal execution mode.

Example: EFFECTS: ASSERT ON $BLOCK1 $BLOCK2;

                RETRACT ClEAR $BLOCK2;

4.11.     Plan Failure

The optional “failure:” field of a plan allows the agent designer to specify a procedure to be executed when the plan fails.  If the plan fails, for example because the context fails, the agent interpreter will execute the actions found in the failure section before switching to other plans or goals.  Execution of this section is performed as if the entire procedure were an atomic action.  That is, the procedure is executed without the possibility of interruption by other plans or even from the normal interleaving of execution of actions with normal interpreter activity.

When a plan fails, the agent considers the failed plan and all of the failed plan’s subgoals to have failed.  In this case, the failure sections of each of the failed plan’s subgoal’s plans are executed from the “leaf” plan - the plan for the goal at the bottom of the subgoal stack - back “up” to the failed plan.  The following plans demonstrate the use of failure sections and, when executed, will illustrate how the failure sections are executed when a plan’s context fails.

 

GOALS:

    ACHIEVE testing_done;

 

FACTS:

    test_done "False";

    force_failure   0;

 

 

//------------------------------------

// PLAN

//------------------------------------

PLAN {

NAME:

    "Test Interpreter on subgoal failure"

DOCUMENTATION:

    "Test Interpreter on subgoal failure"

GOAL:

    ACHIEVE testing_done;

CONTEXT:

    FACT test_done "False";

BODY:

    EXECUTE print "Just before top level ACHIEVE.\n";

    OR

    {

        ACHIEVE communicated "In Failure branch1.\n";

        ACHIEVE subgoal_failed1;

    }

    {

        ACHIEVE communicated "In branch2.\n";

    };

}

 

 

//------------------------------------

// PLAN

//------------------------------------

PLAN {

NAME:

    "Subgoal to failure1"

DOCUMENTATION:

    "Intermediate level subgoal failure."

GOAL:

    ACHIEVE subgoal_failed1;

CONTEXT:

    FACT test_done "False";

    FACT force_failure 0;

BODY:

    EXECUTE print "In subgoal_failed1\n";

    ACHIEVE subgoal_failed2;

}

 

 

//------------------------------------

// PLAN

//------------------------------------

PLAN {

NAME:

    "Subgoal to failure"

DOCUMENTATION:

    "Make sure subgoal failure 'works'."

GOAL:

    ACHIEVE subgoal_failed2;

CONTEXT:

    FACT test_done "False";

BODY:

    EXECUTE print "In subgoal_failed2\n";

    OR

    {

        ACHIEVE communicated "In Failure branch1 #2.\n";

        ACHIEVE plan_failed;

    }

    {

        ACHIEVE communicated "In Failure branch2 #2.\n";

        ACHIEVE plan_failed;

    };

FAILURE:

    EXECUTE print "\nsubgoal_failed2 failed.\n\n";

}

 

 

//------------------------------------

// PLAN

//------------------------------------

PLAN {

NAME:

    "Simply fail."

DOCUMENTATION:

    "Make sure that PLAN fails"

GOAL:

    ACHIEVE plan_failed;

CONTEXT:

    FACT test_done "False";

BODY:

    EXECUTE print "Just before failure.\n";

    UPDATE (force_failure) (force_failure 1);

    EXECUTE print "Just after failure.  Should never get here.\n";

FAILURE:

    EXECUTE print "\nplan_failed failed.\n\n";

}

 

 

//------------------------------------

// PLAN

//------------------------------------

PLAN {

NAME:

    "Communicate the text to the user"

DOCUMENTATION:

    "Print and speak the text"

GOAL:

    ACHIEVE communicated $TEXT;

CONTEXT:

    FACT test_done "False";

 

BODY:

    EXECUTE print $TEXT;

    FAILURE:

    EXECUTE print "\ncommunicated failed.\n\n";

}

 

Runtime failure behavior for this set of plans is left to the reader for now. J

 


5.  CYCLIC FUNCTIONALITY

 

In addition to the primitive functions and built-in JAM-defined actions that can be called through execution of plans, the JAM agent architecture supports arbitrary processing to occur every cycle through the interpreter’s internal loop.[11]  This functionality, typically used to update the world model independently from the normal plan execution cycle, is provided in procedural body called the Observer.  The Observer’s behavior is specified in a syntax identical to that of a plan body in one of the files parsed during initialization.  This procedure may contain any plan action or construct that a normal plan body can contain except for subgoaling.  Subgoaling is not supported because execution of the Observer procedure is outside of the normal execution of the interpreter (APL generation, plan selection and intention, etc.).  Subgoal actions are detected during execution and will generate a warning message.  Any subgoal actions will be otherwise ignored.

An example of a complete JAM program, which includes an Observer definition (which simply maintains and prints out the number of times the interpreter has cycled), is shown below:

 

GOALS:

    ACHIEVE cycle_tested;

 

FACTS:

    test_done       "False";

    system_init     "False";

    cycle_number    0;

 

OBSERVER {

    RETRIEVE cycle_number $N ;

    EXECUTE print "\nCycle#" $N "\n";

    UPDATE (cycle_number $N) (cycle_number (+ $N 1));

}

 

PLAN {

NAME:

    "Test CYCLE"

GOAL:

    ACHIEVE cycle_tested;

CONTEXT:

    FACT test_done "False";

BODY:

    EXECUTE print "\nNormal execution started.\n";

    UPDATE (system_init) (system_init "True");

    WHILE : TEST (== 1 1)

    {

        EXECUTE noop;

    };

}

 

More examples of complete JAM programs in which Observer procedures are defined can be found in the com/irs/jam/examples directory.

 


6.  INTENTION STRUCTURE

 

The intention structure maintains information related to the runtime state of progress made toward the agent’s top-level goals.  The agent will typically have more than one of these top-level goals, and each of these goals may invoke subgoals to achieve lower-level goals.  With the current implementation, a goal that is being pursued may be interrupted by a higher utility goal (see Figure 3.1) and then later resumed (if possible, according to the context).  To manage this, the agent’s intention structure keeps track of the top-level goals that are being pursued and the particular action(s) within each plan that is currently being executed.

When a goal is suspended due to a higher utility goal becoming dominant, the current state of execution of the current goal is stored.  When the suspended goal becomes the highest utility goal again, it is “reactivated”, or “resumed”.  There is nothing unusual in the reactivation process; the agent merely switches back to executing the suspended plan.  However, due to the possibility that the world model has been changed during the pursuit of other goals, one or more of the contexts of the resumed top-level goal and its subgoals may no longer be valid.  If they are all still valid, execution resumes at the exact place where it was suspended.  However, if the context of any of the intentions of the resumed goal stack fails, then the goal at the point of failure and all subgoals below it are considered to have failed.  This is the normal behavior for plans whose context fails and simply occurs at the point of resumption simply because attention is directed back to the suspended intention stack.


7.  SOURCE-CODE API

 

The JAM agent architecture was designed to be programmed primarily at the “knowledge level” using text-based files which specify the agent’s beliefs, goals, and plans.  The idea is that agent programmers conceive of and then implement agent constructs using the mentalistic notions of the BDI framework rather than getting bogged down in Java-level coding.  However, it is unlikely that agent programmers will be able to stay exclusively at the knowledge level using only the functionality supplied with the JAM distribution.  The agent programmer will most likely need to implement primitive functions beyond that which is supplied with JAM.  Moreover, it is has become apparent that an application programmers interface (API) to most aspects of JAM would be useful for many agent-based applications.  Such an interface would facilitate an agent programmer embedding one or more JAM agents within an application rather than invoking an agent from a command line.  In any of these cases, knowledge of some details about the code-level implementation of JAM will be necessary.  In this section, we will describe many of the API methods related specifically to agent invocation.  Complete details on JAM classes and methods can be found in the documentation created by javadoc in the com/irs/jam/docs directory. Details on how to use the API to implement primitive function are covered in the next section.

Creating and running a JAM agent from the Java code level is quite simple.  A JAM programmer can create a single JAM agent within Java code using the zero-argument public constructor JAM()or an argument list as given on the java command line in the constructor JAM(String[] argv). The following Java code creates a JAM agent and gets it working:

 

JAM jamAgent = new JAM(argv);

try {

  jamAgent.think();

}

catch (Exception e) {

  e.printStackTrace();

}

 

This uses the constructor that takes standard JAM command line arguments

public JAM(String argv[])

 

There are some alternative constructors that are available and would be used with other JAM methods, i.e.,

public Interpreter(String argv[])

and then

public JAM(Interpreter i)

or just use a default (empty minded) JAM with

public JAM()

 

The various means of invoking the agent is:

public boolean think(String argv[]) throws IOException, ParseException

public boolean think(Interpreter interpreter)

public boolean think()

e.g.,

jamAgent.think()

 

or, if you want to run JAM as a thread, using

jamAgent.start()

 

To add a world model entry (ala the ASSERT action at the JAM plan level) to a JAM agent from the Java level, use the following code snippet:

#include com.irs.jam.*;

ExpList ex = new ExpList();

ex.append(new Value("REQUEST"));

ex.append(new Value(sender()));

ex.append(new Value(aclMsg));

Relation rel = new Relation("message", ex, jam().getInterpreter());

jam().getInterpreter().getWorldModel().assert(rel, null);

 

The jam() method used above is assumed to give you a handle on the instantiated JAM object (you might already have a locally scoped handle on it or you might use an accessor to get to it – it depends on the code you write). A world model entry in JAM is a proposition with a label and a list of values.  The above snippet adds an incoming message (FIPA, KQML, what have you) to the agent's world model.  The first line creates an expression list for storing the list of proposition values.  The next three lines create the actual values for the proposition. The fifth line forms the world model relation. The final line puts in into the JAM agent's brain, so to speak. The second argument of assert() is the variable binding and is null since all arguments in the expression list are fully grounded (and will always be from the Java level).

Anything is permitted in the Value constructor (the appropriate subclass is created).  As many entries can be added to an ExpList as is necessary – there is no limit to the number of elements.  In the above example, the following world model is created (everything between quotes is the final value):

message REQUEST i@iiop://192.168.0.3:44444/acc "(request :sender i@iiop://192.168.0.3:44444/acc :receiver r@iiop://192.168.0.3:44444/acc :content (deposit account 12345789 $123.45) :language tiiera-financial :ontology tiiera-financial)"

 

The same basic process is used to remove one or more world model entries (ala the RETRACT action at the JAM plan level):

#include com.irs.jam.*;
ExpList ex = new ExpList();
ex.append(new Value("REQUEST"));
ex.append(new Value(sender()));
ex.append(new Value(aclMsg));
Relation rel = new Relation("message", ex, jam().getInterpreter());
jam().getInterpreter().getWorldModel().retract(rel, null);

The null in the retract method is the binding list again, in the method

  public void assert(Relation r, Binding b)

To do the equivalent of an UPDATE at the Java level, use the following method

  public void update(Relation oldRel, Relation newRel, Binding b)

so that the code would look like

  jam().getInterpreter().getWorldModel().update(relOld, relNew, null);

You can turn debugging output on and off from the Java level easy enough. Using public methods from the Interpreter object (accessible from the JAM object via the accessor getInterpreter()).  The public API is:

  public boolean setShowWorldModel(boolean flag)
  public boolean setShowGoalList(boolean flag)
  public boolean setShowAPL(boolean flag)
  public boolean setShowIntentionStructure(boolean flag)
  public boolean setShowActionFailure(boolean flag)

and debugging output is turned on if the argument is true and turned off if the argument is false.

 


8.  PRIMITIVE FUNCTION INTERFACING

 

Primitive functions are the primary means by which an agent programmer specifies domain-specific functionality for use in plans and the Observer procedure.  We provide some general-purpose primitive functions with the JAM distribution, but application developers are almost certainly going to want to specify additional functionality.

Each primitive action referenced in an agent’s plan body must have Java code which implements the necessary functionality.  JAM currently supports three mechanisms for specifying primitive function Java code: write a class implementing the PrimitiveAction interface; add code to the UserFunctions.java class; and invocation of already written “legacy” Java code.  We will cover each of these three mechanisms in more detail below.  Many of JAM’s built-in primitive functions are defined in the file SystemFunctions.java and are described later.

8.1.         PrimitiveAction Interface

The first mechanism available for specifying primitive functionality is to write a class that implements the PrimitiveAction interface.  This interface is simple, a single function called execute.  A programmer wishing to add new primitive function capabilities to an agent simply writes a class with the execute method fleshed out to perform the desired behavior.

 

The complete interface definition is

 

public interface PrimitiveAction

{

  public Value execute(String name, int arity, ExpList args,

                       Binding binding, Goal currentGoal);

}

 

A new primitive function is then defined using the following format:

 

public class NewBehavior implements PrimitiveAction

{

  public Value execute(String name, int arity, ExpList args,

                       Binding binding, Goal currentGoal)

  {

     // Behavior specified here

  }

}

 

The execute method’s arguments are:

name (a String) which specifies the primitive function’s label,

arity (a simple integer) which specifies the number of arguments to the primitive function,

args (an object of class ExpList) which are the arguments of the primitive function passed to it from the agent’s plan, and

binding (an object of class Binding) which holds the plan variable bindings associated with the passed-in arguments.

currentGoal (an object of class currentGoal) which holds the goal of the plan which is invoking this primitive action.[12]

A primitive action programmer can perform safety checks by using the arguments to make sure that the function’s arity is correct, that the argument types and values are of the correct type and in bounds, that the function name is correct, etc.

To extract all of the individual arguments from args, the programmer needs to define an object of type ExpListEnumerator to iterate over the argument list (a list of Expression objects).  Each individual argument refers to some native Java type (i.e., long or double) or a Java object (e.g., a String or an Object).  Each call to ExpListEnumerator.nextElement() returns the next argument sequentially until ‘null’ is returned, which indicates that there are no more arguments.  The Expression objects wrap the Java types (for architectural reasons) so primitive functions must first convert from the Expression object to the required Java type.  The Java value wrapped by the argument can be extracted using eval(binding).getX() where “X” stands for Long, String, Real, or Object.  The java type can be checked using the eval(binding).type()method combination.  These methods are demonstrated in the following code segment:

            ExpListEnumerator ele = new ExpListEnumerator(args);

            Expression        exp;

 

            long        aLong;

            String      aString;

            double      aReal;

            Object      anObject;

 

            while ((exp= (Expression) ele.nextElement()) != null) {

              if (exp.eval(binding).type() == Value.VAL_LONG) {

                aLong = exp.eval(binding).getLong();

              }

              if (exp.eval(binding).type() == Value.VAL_STRING) {