General

Why is the platform called Jason?

Jason initially stood for “Java-based Agentspeak interpreter used with Saci for multi-agent distribution Over the Net”. Since it not based only on SACI anymore (other infrastructures are available) and the acronyms was quite “forced”, we decided the use Jason as a proper name for the interpreter.

The name is also somehow inspired by in Greek mythology. Click here for an entry on Jason in the Perseus Encyclopaedia (Perseus is an excellent source of Classics, maintained by Tufts University).

How to configure Jason?

Jason requires some information about your local configuration, for example, the location of the Java installation. You can change the configuration by double clicking the jason jar file that is located in the libs directory. Alternatively, in a command shell you can run

$ java -jar libs/jason.jar

Internal Actions

How to create a new internal actions?

The following steps will help you to define your internal action (IA). The steps 1-4,6 are automatically done by Jason IDE, see menu Plugin→Jason→New internal action".

  1. In your MAS project directory, create a sub-directory called myLib (user’s internal actions must be placed in a Java package, which provides a library of actions). In case this package directory is under your project directory, Jason automatically sets the classpath.

  2. Copy an existing Jason internal action (Jason/src/stdlib/concat.java, for instance) to the myLib directory. This file will be used as a skeleton for your new IA.

  3. Rename the file myLib/concat.java to myLib/myIA.java.

  4. Edit this file and change the package name to myLib, and the class name to myIA.

    The code will likely look like

    myLib/myIA.java
    package myLib;
    
    import jason.asSemantics.*;
    import jason.asSyntax.*;
    
    public class myIA extends DefaultInternalAction {
       public Object execute(TransitionSystem ts,
                             Unifier un,
                             Term[] args)
                     throws Exception {
          ....
       }
    }
  5. Code the execute method in order to implement the internal action.

  6. Compile the new class

    cd <your project directory>
    javac -classpath ...../Jason/lib/jason.jar:. myLib/myIA.java
  7. Use the new IA in AgentSpeak sources, for example:

    +a(X) : true
       <- ... ;
          myLib.myIA(A,B);
          ... .

Environment

Is it possible to call an internal action from the environment?

Most of the internal actions (IAs) are developed from an agent perspective, since they are conceived to be called by agents. Thus the execute method needs an agent’s TransitionSystem (TS) to be executed (e.g. .myname only makes sense when called by an agent).

How to discover the name of the agents in the environment initialisation?

As the environment is created before the agents, the set of agents is empty when the environment is created and thus the method getEnvironmentInfraTier().getRuntimeServices().getAgentsNames() cannot be used. However, if the set of agents is defined only by the .mas2j project file (i.e., no agent is dynamically created), the name of the agents can be obtained from that file.

For instance, a project file called ag-names.mas2j can be passed as parameter to the environment as in the following example:

MAS ag_names {
     environment: TestEnv("ag-names.mas2j")
     agents:   a #10;   b;
}

The following code (in the environment initialisation) can then get all the names:

public void init(String[] args) {
   // args[0] is the name of the project file
   try {
      // parse that file
      jason.mas2j.parser.mas2j parser =
          new jason.mas2j.parser.mas2j(new FileInputStream(args[0]));
      MAS2JProject project = parser.mas();

      List<String> names = new ArrayList<String>();
      // get the names from the project
      for (AgentParameters ap : project.getAgents()) {
         String agName = ap.name;
         for (int cAg = 0; cAg < ap.qty; cAg++) {
            String numberedAg = agName;
            if (ap.qty > 1) {
               numberedAg += (cAg + 1);
            }
            names.add(numberedAg);
         }
      }
   }
   logger.info("Agents' name: "+names);
   ...
}

MAS Execution

How to delay the MAS execution?

If you have an environment class, the easiest way is simply adding a thread sleep in the executeAction method. For example:

    ...
    public boolean executeAction(String agent, Term action) {
        ...
        try {
          Thread.sleep(500);
        } catch (Exception e) {}
        ...
    }

In case the agents do not act in the environment or there is no environment class, you should write a controller class (see Control Class).

For instance, the controller class could be:

package myPkg;
import ...
public class MyExecutionControl extends ExecutionControl {
    protected void allAgsFinished() {
        try {
          Thread.sleep(500);
        } catch (Exception e) {}
    }
}

To use this controller, the project file must be

MAS test {
    ...
    executionControl: myPkg.MyExecutionControl

    agents:  ...
}

Is it possible to add/remove an agent to/from a running MAS?

The internal action .createagent can be used to dynamically add a new agent into the running MAS. For example, when the plan:

+a : true
   <- ... ;
      .create_agent(bob, "myAgent.asl");
      ... .

is executed, it will create a new agent called bob based on the AgentSpeak code available at file myAgent.asl.

Analogously, the internal action .killagent(<agent name>) removes the agent identified by <agent name> from the current MAS. The demos/create-agent project that comes with the Jason distribution files has examples of using these features.

New agents can also be created in the user Java code, for example:

public class myEnv extends Environment {
  ...
  public boolean executeAction(String ag, Term action) {
    ...
    getEnvironmentInfraTier().getRuntimeServices().
     .createAgent(
         "anotherAg",     // agent name
         "ag1.asl",       // AgentSpeak source
         null,            // default agent class
         null,            // default architecture class
         null,            // default belief base parameters
         null);           // default settings
  }
}

The interface, used in the code above, provides useful services transparently from the underlying infrastructure (Centralised, Jade, …​). The interface’s methods include agent creation, agent killing, and halting the system (see the API documentation for more information).

Note that if you’re using the JADE infrastructure, new agents (possibly not Jason agents, see Jade) can enter the MAS using JADE features for open MAS.

How to set the classpath for running a system?

There are three ways to set the classpath of a project:

  1. Create a lib directory in the project and include the jar files there. The ant script created by Jason to run the project (bin/build.xml) includes lib/*.jar in the classpath. This approach is used in examples/gold-miners.

  2. In case you do not want to copy files into the project, the classpath entry in the .mas2j file can be used:

    MAS masid {
       agents: .......
       classpath: "../../jdom.jar";
                  "../../otherproject/classes";
                  "/apache/**/*.jar; // all jar files below /apache
    }

    Several items can be added as strings separated by ;. This approach is used in examples/sniffer.

  3. If a more customised startup is required for your system, create a file named bin/c-build.xml with the template below:

    <project name ="mybuild" basedir="..">
        <import file="build.xml"/>
    
        <target name="user-init">
            <!-- add here all your custom initialisation -->
        </target>
    
        <target name="user-end">
            <!-- add here all your custom termination -->
        </target>
    
        <!-- you can also "override" other tasks from build.xml -->
    </project>

    If a c-build.xml file exists, it is used to run your application instead of the build.xml that is automatically created by Jason.

Which execution modes are available?

Jason is distributed with three execution modes:

  • Asynchronous: all agents run asynchronously. An agent goes to its next reasoning cycle as soon as it has finished its current cycle. This is the default execution mode.

  • Synchronous: all agents perform one reasoning cycle at every global execution step. When an agent finished its reasoning cycle, it informs the Jason controller and waits for a carry on signal. The Jason controller waits until all agents have finished their reasoning cycles and then sends the carry on signal to them.

    To use this execution mode, you have to set up a controller class in the .mas2j configuration, for example:

    MAS test {
        infrastructure: Centralised
        environment: testEnv
    
        executionControl: jason.control.ExecutionControl
    
        agents:  ...
    }

    The jason.control.ExecutionControl class implements exactly the Jason controller for the synchronous execution mode described above.

  • Debug: this execution mode is similar to the synchronous mode, except that the controller will also wait until the user clicks on a Step button before sending the carry on signal to the agents.

    To use this execution mode you can just press the debug button rather than the run button of the IDE, or you can set up a debug controller class in the .mas2j configuration, for example:

    MAS test {
        infrastructure: Centralised
        environment: testEnv
    
        executionControl: jason.control.ExecutionControlGUI
    
        agents:  ...
    }

    The jason.control.ExecutionControlGUI class implements the Jason controlle with a GUI for debugging. This graphical tool is called Jason’s Mind Inspector, as it allows users to observe all changes in agents’ mental attitudes after a (number of) reasoning cycle(s). This also applies to distributed agents (using JADE).

How to run my application without Jason IDE

The Jason IDE (jEdit plugin) creates an Ant script (in the bin sub-directory of your application directory) and then simply runs this script to start your application. You can thus run it in a command prompt as follows:

   cd <the directory of you application>/bin
   ant

You can also run it as a normal Java application:

   cd <the directory of you application>
   export CLASSPATH=<your jars, jason.jar,...>
   java jason.infra.centralised.RunCentralisedMAS <yourproject.mas2j file>

You find more details about the environment (e.g. classpath) on the generated bin/build.xml file of your application.

A third way to run your application is to create a jar file for it. There is an option for that in the menu Plugins-Jason, or

   cd <the directory of you application>
   ant -f bin/build.xml jar
   java -jar <your application>.jar

How can I control agents’ execution?

If you have other specific needs for controlling agents’ execution, you have to implement an ExecutionControl sub-class and specify it in the .mas2j file.

You will most likely have to override the following methods:

public void receiveFinishedCycle(String agName, boolean breakpoint) {
   super.receiveFinishedCycle(agName, breakpoint);
   ... your code ...
}
protected void allAgsFinished() {
   ... your code ...
}

These methods are called by Jason when one agent has finished its reasoning cycle and when all agents have finished the current global execution step.

To signal the agents to carry on, your class can use the following code:

   fJasonControl.informAllAgsToPerformCycle();

You should have a look at the ExecutionControlGUI class for an example of how to do this, and the API documentation for further available methods inherited from ExecutionControl.

Is it possible to use only the Jason BDI engine?

If you want to use only the Jason interpreter for a variant of AgentSpeak, you can implement your own agent class where the Jason available infrastructures are not used. This class must function as an overall agent architecture for the AgentSpeak interpreter, i.e., it has to send percepts to the interpreter and get the agent actions (which result from the AgentSpeak reasoning cycles).

Suppose you need a simple agent that interprets and reasons according to the following AgentSpeak source:

+x(N) : N < 3  <- do(0).

+x(N) : N >= 3 <- do(50).

The following class implements the required architecture (the complete code is available in the demos directory in the Jason distribution). This code simply adds x(10) into the agent’s belief base through perception and get the output action, in this case do(50).

public class SimpleJasonAgent extends AgArch {
    public static void main(String[] a) {
       ...
       SimpleJasonAgent ag = new SimpleJasonAgent();
       ag.run();
    }

    public SimpleJasonAgent() {
         // set up the Jason agent and the
         // TransitionSystem (the BDI Engine where the AgentSpeak
         // Semantics is implemented)

         Agent ag = new Agent();
         new TransitionSystem(ag, new Circumstance(), new Settings(), this);
         ag.initAg("demo.asl"); // demo.asl is the file containing the code of the agent
    }

    public String getAgName() {
        return "bob";
    }

    public void run() {
        while (isRunning()) {
          // calls the Jason engine to perform one reasoning cycle
          getTS().reasoningCycle();
        }
    }

    // this method just add some perception for the agent
    public List<Literal> perceive() {
        List<Literal> l = new ArrayList<Literal>();
        l.add(Literal.parseLiteral("x(10)"));
        return l;
    }

    // this method gets the agent actions
    public void act(ActionExec action) {
        getTS().getLogger().info("Agent " + getAgName() + " is doing: " + action.getActionTerm());
        // return confirming the action execution was OK
        action.setResult(true);
        actionExecuted(action);
    }

    public boolean canSleep() {
        return true;
    }

    public boolean isRunning() {
        return true;
    }

    public void sleep() {
        try {   Thread.sleep(1000); } catch (InterruptedException e) {}
    }

    public void sendMsg(jason.asSemantics.Message m) throws Exception {
    }

    public void broadcast(jason.asSemantics.Message m) throws Exception {
    }

    public void checkMail() {
    }
}

To run this agent:

export CLASSPATH= ../../lib/jason.jar:.
javac SimpleJasonAgent.java
java  SimpleJasonAgent

The output will be

[bob] Agent bob is doing: do(50)

Of course, the AgentSpeak code in this example cannot use communicative actions, since the specific architecture given above does not implement communication.

Debug tools

How to setup verbosity of an agent?

The verbosity is set in the options defined for the agent in the project file. For instance

   ...
   agents: ag1 [verbose=2];
   ...

A number between 0 and 2 should be specified. The higher the number, the more information about that agent is printed out in the Jason console. The default is in fact 1, not 0; verbose 1 prints out only the actions that agents perform in the environment and the messages exchanged between them. Verbose 2 is for debugging (it corresponds to the java log level FINE).

How to log the overall execution?

Jason uses the Java logging API to output messages into the console (the default console is called MASConsole). To change the log level or device, select the menu Plugins → Jason → Edit Log properties in the jEdit plugin. If you are not using jEdit, you can copy the default configuration file from here to your application directory. The default configuration file has comments that helps you customise your log. For instance, to output messages both into an XML file and in the console, you only need to set the log handler as in the following line:

handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler

To get only console output (without the MASConsole GUI):

handlers = java.util.logging.ConsoleHandler

How to log agents’ mind states?

Besides running the system in debug mode, we can define options for an agent such that the current state of its mind is shown or stored in files.

To show the current mind state in the screen, add the following option in the project:

agents:
       bob [mindinspector="gui(cycle,html)"];

In this case the screen is updated each reasoning cycle. If you want to store all the states in a kind of history, add a third argument as in the example below.

      bob [mindinspector="gui(cycle,html,history)"];

In the place of cycle, you can write the refresh interval in mili-seconds:

      bob [mindinspector="gui(2000,html,history)"];

You can also see the history of minds in a browser with the following configuration:

      bob [mindinspector="web(cycle,html,history)"];

The URL is typically http://locaslhost:3272.

To store the history of minds in files, use the following configuration:

      bob [mindinspector="file(cycle,xml,log)"];

The last parameter is the name of the directory where files will be stored. Each file corresponds to a sample of the mind. They are XML files with suitable style sheets to be viewed in browsers.

Infrastructures

What are infrastructures for?

An infrastructure provides the following services for the MAS:

  • communication (e.g., the centralised infrastructure implements communication based on KQML whilst JADE implements it using FIPA-ACL),

  • control of the agent life cycle (creation, running, destruction).

Which infrastructures are available?

The current distribution has the following infrastructures:

Centralised

this infrastructure runs all agents in the same host. It provides fast startup and high performance for systems that can be executed in a single computer. It is also useful to test and develop (prototype) systems. Centralised is the default infrastructure.

Jade

provides distribution and communication using Jade, which is based on FIPA-ACL. With this infrastructure, all tools available with JADE (e.g., Sniffer and Inspector) are also available to monitor and inspect agents.
Since Jason agents use KQML and JADE uses FIPA-ACL, we opted to translate the messages from KQML to FIPA-ACL and vice-versa to maintain the AgentSpeak programming the same for all infrastructures. The following table summarises the translation of the basic performatives:

FIPA-ACL KQML

inform

tell

query-ref

askOne

request

achieve

You can find more information about this infrastructure in the Jason-JADE tutorial.

How to select an infrastructure?

In the .mas2j project file, use the infrastructure entry to select an infrastructure, for example to use Centralised:

MAS auction {
    infrastructure: Centralised
    agents: ag1; ag2; ag3;
}

and to use Jade:

MAS auction {
    infrastructure: Jade
    agents: ag1; ag2; ag3;
}

Note that the agents do not need to be changed for different infrastructures. The Jason Agent Architecture binds them to the available infrastructure.

When should I use the JADE infrastructures?

The centralised infrastructure does not support:

  • execution of the agents at distributed hosts, and

  • interoperability with non-Jason agents.

If you need any of these features, you should choose the JADE infrastructure (or implement/plug a new infrastructure for/into Jason yourself). The interoperability with non-Jason agents is achieved by JADE through FIPA-ACL communication.

JADE

How to customise the JADE container?

All parameters normally used to start a JADE container can be set in the menu Plugins → Plugins Options → Jason → jade.Boot arguments. For instance, to start a non-main container when running the project, the following arguments can be used (supposing the main container is running at x.com):

-gui -container -host x.com

How to start a Jason agent with jade.Boot?

The JADE agent wrapper should be used to start a Jason agent using jade.Boot, rather than doing it from the Jason IDE. For example, to start a Jason agent called bob based on the AgentSpeak source code in file auctioneer.asl, execute the following command in a shell:

java jade.Boot "bob:jason.infra.jade.JadeAgArch(auctionner.asl)"

To start up also a simulated environment (implemented, for instance, in the Env class):

java jade.Boot -agents "\
 environment:jason.infra.jade.JadeEnvironment(Env) \
 bob:jason.infra.jade.JadeAgArch(auctionner.asl)"

The arguments for the environment have to follow the class name, for example:

java jade.Boot -agents "environment:jason.infra.jade.JadeEnvironment(Env,arg1,arg2)"

In the case you need to start a more customised agent (architecture, belief base, …​), you can write (or reuse) a Jason project file with all the usual agent’s parameters and then start the agent from this file. E.g.

jade.Boot -agents "bob:jason.infra.jade.JadeAgArch(j-project,test.mas2j,bob)"

The parameter j-project indicates that the following parameter (test.mas2j in the above example) is the Jason project. The third parameter is the name of the agent as defined in the .mas2j file.

The same approach can be used for the environment:

jade.Boot -agents "j_environment:jason.infra.jade.JadeEnvironment(j-project,test.mas2j)"

How can I customise the Jade sniffer?

In the project directory, create a file called c-sniffer.properties with your preferences (see http://www.cs.uta.fi/kurssit/AgO/harj/jade_harkat/doc/tools/sniffer/html/jdoc/jade/tools/sniffer/Sniffer.html for more details). Once started, Jason will copy this file to sniffer.properties to be used by the Jade’s sniffer. If no customisation is provided, Jason creates a default properties file with the names of the agents.

How to run my agents on several machines with JADE?

The play button of jEdit plugin always run all the agents in the current host even using JADE infrastructure. To run them on several machines there are two mechanisms.

Defining a container for each agent

In the project file, you have to setup the host’s name where the main container will run and the container where agents will run, as in the following example (this example is available in the demos directory):

MAS demo_distributed_jade {

    infrastructure: Jade(main_container_host("localhost"))
    // replace localhost by the name or IP of the host where the main container will run

    agents:
        a at "c1";    // agent a will run on the hots where container c1 will run
        b at "c1";    // agent b will run on the host where container c1 will run
        c at "c2" #3; // ....
        d at "c1";
}

Steps to run the system:

  1. Create the Ant script to run the agents by either pressing play in the jEdit plugin or typing

       $ cd <your project directory>
       $ <jason dir>/scripts/mas2j <the .mas2j file>

    The script has the task Main-Container to run the JADE main container and tasks to start each container defined in the project (c1 and c2, in the example above).

  2. Go to host X and run the main container there by starting the main container task of the script:

       $ cd bin
       $ ant Main-Container
  3. Go to host Y and start container c1 there

       $ ant c1
  4. Go to host Z and start container c2 there

       $ ant c2

Defining a class that allocates the agents to containers

In the second mechanism the at primitive of the project isn’t used, in its place a Java class is provided to indicate which containers have to be created and how agents are distributed on to them. The project definition is thus like the following (myAllocator is the name of the Java class and [c1,c2] is the list of containers).

MAS demo_distributed_jade {

    infrastructure: Jade(
        main_container_host("localhost"),    // replace localhost by the name or IP of the host where the main container will run
        container_allocation("myAllocator",  // the name of the class that will allocate the agents to containers
                             "[c1,c2]")      // the name and number of containers
    )


    agents:
        a;
        b;
        c #3;
        d #5;
}

In the above example (available in the demos/distributed-jade/case2 directory), the class myAllocator allocates the same number of agents to each container. You can see the code of this class for details.

To run this system, replace the commands of step 1 of the previous section as follows (the other steps remain the same).

For Unix:

   $ cd <your project directory>
   $ ant -f bin/build.xml compile
   $ <jason dir>/scripts/mas2j <the .mas2j file>

For Windows and other plaforms:

   > cd <your project directory>
   > ant -f bin/build.xml compile
   > set JASONLIB=<the Jason lib directory>
   > java -classpath bin\classes;%JASONLIB%\jason.jar jason.mas2j.parser.mas2j  <the .mas2j file>

AgentSpeak Language

What exactly are the cases where negative events of the forms -!p and -?p are generated?

A test goal ?p in the body of a plan first checks the belief base, and if it fails, it still tries to generate an internal event +?p. This is because the test goal might have been meant to be a more sophisticated query for which the programmer created a whole plan with +?p as triggering event, then that plan could be executed to satisfy the test goal. Events -!p and -?p are only generated if an executing plan for +!g and +?g (respectively) fail. Here’s what the manual says about this:

Events for handling plan failure are already available in Jason, although they are not formalised in the semantics yet. If an action fails or there is no applicable plan for a subgoal in the plan being executed to handle an internal event with a goal addition +!g, then the whole failed plan is removed from the top of the intention and an internal event for -!g associated with that same intention is generated. If the programmer provided a plan that has a triggering event matching -!g and is applicable, such plan will be pushed on top of the intention, so the programmer can specify in the body of such plan how that particular failure is to be handled. If no such plan is available, the whole intention is discarded and a warning is printed out to the console. Effectively, this provides a means for programmers to “clean up” after a failed plan and before backtracking (that is, to make up for actions that had already been executed but left things in an inappropriate state for next attempts to achieve the goal). For example, for an agent that persist on a goal !g for as long as there are applicable plans for +!g, suffices it to include a plan -g! : true ← true. in the plan library. Note that the body can be empty as a goal is only removed from the body of a plan when the intended means chosen for that goal finishes successfully. It is also simple to specify a plan which, under specific condition, chooses to drop the intention altogether (by means of a standard internal action mentioned below).

Does +p (or -p) in a plan body cause two effects, i.e. updating the belief base and generating the events +p (or -p)?

Yes, it causes both effects. Note, importantly, that one of the interpreter configuration options allow the user to choose whether the event (if it is by chance relevant to any plans the agent has) will be treated as internal (pushed on top of that same intention) or external (a new intention – i.e., a new focus of attention – is created).

Does ?p in a plan body cause two effects, i.e. testing p from the belief base and generating the events +?p? Is -?p generated when a test goal ?p fails? When does the test goal ?p fail?

When ?p is executed, first the interpreter tries a simple query to the belief base. If that doesn’t succeed, before failing the intention, first an internal event for +?g is generated, if there are no applicable plans for such event, then the plan fails (fails normally, i.e., for the "no applicable plans" reason) — there could be still a -?g plan to be tried; if there’s none, the intention is discarded and a message printed to the console to let the user know.

It is claimed that open-world assumption is available. What does this mean? Do we have a three-valued logic?

No, we don’t use three-valued logic, strictly speaking. There is a strong negation operator ~. When assuming open world, the user models the environment with a set of propositions known to be explicitly true and a set of propositions known to be explicitly false of the environment at a certain moment in time (the latter are literals preceeded by the ~ operator). Of course, there is still default negation (as usual in logic programming languages), so you can say, in the context of a plan, not p(t) & not ~p(t) to check if the agent is uncertain about p(t). Note that it’s completely up to the user to prevent paraconsistency (or to use it, if they so wish). You could add internal beliefs (or have beliefs from perception of the environment) that p(t) is true and that  p(t) is also true: Jason won’t do consistency checks for you! But you can easily implement such consistency check, or indeed have more elaborate belief revisions algorithms by overriding the belief update and belief revision methods in Jason (the belief revision method by default does nothing). Finally, note that strong negation can also appear in the triggering events, plan body, and anywhere a literal can appear.

What’s the difference between ! and !!?

The difference between ! and !! is that the latter causes the goal to be pursued as a separate intention. Within the body of a plan in one intention, if you have !g1; !g2 the agent will attempt to achieve g2 only after achieving (or finishing executing a plan for) g1. If you say !!g1; !g2 the agent will then have another separate intention to achieve g1 and can immediately start attempting to achieve g2. What will be done first (executing a bit of the intention with g1 or the old intention with g2) will depend on the choices that the intention selection function makes.

You may have noticed !! is often used at the end of recursive plans (when the recursive call does not have free variables to be instantiated) as in the following code:

+!g : end_recursion_context.
+!g : true <- action1; !!g.

In this case, the !! is used to avoid Jason creating long stacks of (empty) plans, so the operator just allows Jason to process the recursion more efficiently.

Jason 1.4.0 implements tail recursion optimisation and thus we don’t need to worry about the stack size anymore. The above code should be written as:

+!g : end_recursion_context.
+!g : true <- action1; !g.

Why is Jason’s plan failure mechanism different from other agent platforms?

Some other platforms handle plan failure in the following way. When a plan is selected as an intended means to achieve a goal (more generally, to handle an event), other applicable plans might be available or indeed other instantiations of the plan’s variables (to make the context a logical consequence of the belief base) might be possible. Those platforms then make a note of all those plans and plan instantiations. If the plan currently being executed fails, another plan is chosen from that set of plans initially recorded as alternative plans for handling that event. This has the great advantage that the platform does not have to check for applicable plans again, and has as disadvantage the fact that possibly the agent’s beliefs have changed and so plans considered applicable at the time the first plan was selected, are actually no longer applicable (yet they will be attempted, which increases the chances of the chosen alternative plan failing as well).

In Jason, we opted for a different approach. When a plan with a triggering event +!g fails, we generate an event -!g and if the programmer provided a plan for that event, and that plan is currently applicable, that plan is pushed on top of the intention where the failed plan is. In the general case, the programmer will have included in that -!g plan another attempt to achieve g. When this happens, all relevant plans will be checked again to find the set of currently applicable plans. Under the assumption that the contexts have been well defined by the programmer, only plans that now stand a chance of succeeding will be applicable. Differently from the above mechanism, here we have the advantage of being better updated on the set of actually applicable plans, but might be less efficient in that more checks need to be done.

Another disadvantage of this approach is that to make sure a plan will only be tried once (if in a particular application this is important, although this is not always the case, surely), as it happens in other platforms, the user will have to use, e.g., the belief base to keep track of the previously attempted plans, or else to have the applicable plan selection function checking the failed plans in the stack of plans forming that intention (note that the failed plans are still there and will only be removed, without executing further, when the respective plan for -!g finishes) to decide which ones not to use anymore. Off course the latter requires considerable Java programming). For the first alternative, there is work on plan patterns and pre-processing directives which take care of automating this for the programmer.

On the other hand, there is an extra advantage of the use of the Jason plan failure handling mechanism. Pure backtracking as used in logic programming might not always make sense in an agent program. Recall that besides sub-goals, plan bodies have actions. These actions, by definition, change something that is outside the agent itself (i.e., the environment), so they cannot automatically be undone by the interpreter in the process of backtracking. It is therefore possible that none of the plans originally written (with a particular set of initial situations in mind) to achieve the goal will be applicable anymore. At least in some cases, it might be sensible to let the -!g plan perform the necessary actions to bring the environment back to a reasonable state in which the original plans to achieve the goal can then be used again, rather than writing more alternative plans for the original goal considering all possible situations in which the agent can find itself when attempting to achieve the goal.

Which information is available for failure handling plans ?

When a plan fails, the plan that handles the corresponding event (that has the form of -!g) may use failure information to provide a suitable solution. This information is provided by two means:

Internal actions

the internal action .current_intention(I) unifies I with a representation of the stack of the current intention. By inspecting this stack, the context of the failure can be discovered.

It follows an example of I (provided by the execution of the example available in demos/failure):

intention(1,
  [
   im(l__6[source(self)], { .current_intention(I); ... },  [map(I,...),...]),
   im(l__5[source(self)], { .fail },                       []),
   im(l__4[source(self)], { !g5(X); .print(endg4) },       [map(X,failure)]),
   im(l__3[source(self)], { !g4(X); .print(endg3) },       [map(X,failure)]),
   im(l__2[source(self)], { !g3(X); .print(endg2) },       [map(X,failure)]),
   im(l__1[source(self)], { !g2(X); .print(endg1) },       [map(X,failure)]),
   im(l__0[source(self)], { !g1(X); .print("End, X=",X) }, [map(X,failure)])
  ]
)

You can find more information in the documentation of the .current_intention pre-defined internal action.

Annotations

every failure event is annotated with at least the following information:

  • error(<atom: error id>): the identification of the type of failure; values used by Jason are:

    • no_applicable: failure caused by no applicable plan;

    • no_relevant: failure caused by no relevant plan;

    • no_option: failure caused by no option being selected by the selectOption function;

    • constraint_failed: failure caused by a constraint in the plan that was not satisfied;

    • ia_failed: failure caused by an error in an internal action (it throws an exception or returned false);

    • action_failed: the failure was caused by a failure in the execution of an action in the environment (i.e., the action execution returned false);

    • ask_failed: the failure is caused by the lack of response to an ask message (with deadline);

    • wrong_arguments: failure caused by wrong number or type of arguments given to an internal action;

    • unknown: other causes;

  • error_msg(<string>): the human readable message of the error

  • code(<literal>): the plan body literal that failed;

  • code_src(<string>): the file name with the source code where the plan that failed is defined;

  • code_line(<int>): the line number within that file.

An example of failure event and its annotations:

-!g[error(ia_failed),
    error_msg("internal action .my_name failed"),
    code(".my_name(bob)"),
    code_src("/tmp/x.asl"),
    code_line(18)]

Note that the plan that handles this event is not obliged to use any these annotations, or it could make use of a subset of them, for example:

-!g[error(ia_failed)]       <- ... plan to handle error of type \ia_failed' ....
-!g[error(no_applicable)]   <- ... plan to handle error of type 'no_applicable'
-!g[code_src("/tmp/x.asl")] <- ... plan to handle error in plans of file x.asl

The internal actions defined by the user can add new annotations to indicate particular types of errors (see the API documentation of JasonException for more information about that).

Developing Jason