diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f24f99b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +.vscode +.idea + +.DS_Store +bin +build +.project +.classpath + +*.class +*.log +.gradle +.settings +.stop___MAS + +doc/faq.html +doc/api +interpreter/doc/api +doc/tech/*Parser.html +readme.html +release-notes.html +doc/tutorials/getting-started/shell-based.html +doc/tech/concurrency.html +doc/tech/annotations.html + +*~ + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +#*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +bookstore.* +doc/index.html + +APDescription.txt +MTPs-Main-Container.txt +demos/persistent-belief-base/bookstore.log +doc/tech/unit-tests.html +doc/tech/patterns.html +doc/tutorials/getting-started/index.html +src/main/resources/np31.zip +src/main/resources/scripts/np31.zip +examples/sniffer/sniff.script +examples/sniffer/sniff.properties +interpreter/doc/tech/jason/asSyntax/parser/AS2JavaParser.html +interpreter/doc/tech/jason/mas2j/parser/MAS2JavaParser.html +jason-cli/docs/vscode/index.html +doc/tech/jason/asSyntax/parser/AS2JavaParser.html +doc/tech/jason/mas2j/parser/MAS2JavaParser.html +doc/jason-cli/commands.html +jason-interpreter/gradle.properties +jason-interpreter/settings.gradle +doc/install.html +doc/index.html +doc/doc.html +doc.html diff --git a/Jason.pdf b/Jason.pdf new file mode 100755 index 00000000..f2153221 Binary files /dev/null and b/Jason.pdf differ diff --git a/adoc-empty.css b/adoc-empty.css new file mode 100644 index 00000000..e69de29b diff --git a/asciidoc-docker b/asciidoc-docker new file mode 100755 index 00000000..f8447e95 --- /dev/null +++ b/asciidoc-docker @@ -0,0 +1,4 @@ +#!/bin/sh +echo asciidoc for $@ +IMAGE=jomifred/adoc +exec docker run --rm -i --user="$(id -u):$(id -g)" --net=none -v "$PWD":/app "$IMAGE" asciidoctor -r /pygments_init.rb "$@" diff --git a/faq.html b/faq.html new file mode 100644 index 00000000..c702d4b5 --- /dev/null +++ b/faq.html @@ -0,0 +1,1848 @@ + + + + + + + + +Jason FAQ + + + + + + + +
+
+
+
+ + + + + +
+ + +This FAQ is not completely update for Jason 3.2, where (1) Gradle is used to handle classpath and Jade (previously these aspects were handled in the .mas2j); (2) jEdit is not supported. If you would like to see this FAQ updated in some question, add an issue at GitHub. +
+
+
+
+
+

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).

+
+
+
+
+
+

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. +
  3. +

    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.

    +
  4. +
  5. +

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

    +
  6. +
  7. +

    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 {
    +      ....
    +   }
    +}
    +
    +
    +
  8. +
  9. +

    Code the execute method in order to implement the internal action.

    +
  10. +
  11. +

    Compile the new class

    +
    +
    +
    cd <your project directory>
    +javac -classpath ...../Jason/lib/jason.jar:. myLib/myIA.java
    +
    +
    +
  12. +
  13. +

    Use the new IA in AgentSpeak sources, for example:

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

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. The interface’s methods include agent creation, agent killing, and +halting the system (see the API documentation for more information).

+
+
+
+

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: Local
    +    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: Local
    +    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).

    +
    +
  • +
+
+
+
+

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, edit the file logging.properties. +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 local 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:

+
+
+
+
Local
+
+

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. Local 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-ACLKQML

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 Local:

+
+
+
+
MAS auction {
+    infrastructure: Local
+    agents: ag1; ag2; ag3;
+}
+
+
+
+

and to use Jade:

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

JADE applications only work with Gradle and must be executed with ./gradlew runJade.

+
+
+

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 local 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 task runJade of file build.gradle.

+
+
+
+

How to start a Jason agent with jade.Boot?

+
+

The JADE agent wrapper should be used to start a Jason agent using jade.Boot. 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)"
+
+
+
+
+
+
+

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 conditions, chooses to drop the intention +altogether (by means of a standard internal action mentioned below).

+
+
+

As from version 2.5, Jason uses a different semantics for failures in +contingency plans. Previously, writing a contingency plan (i.e., a +plan of the form -!g : …​) meant the programmer knew how to control +a goal failure. It might include having other goals which might +themselves fail, but a contingency plan should not itself be allowed +to fail; a failure in the contingency plan would delete the whole +intention stack. However, if a plan for +!g2 failed and there were +no -!g2 plans given, if achieving that instance of g2 was needed +as part of a plan to achieve g1, g1 would in turn fail as well +(possibly triggering -!g1 plans, if there were any).

+
+
+

The new semantics also allows failures in contingency plans to fail +other goals appearing below it in the intention stack. Note that the +fact that there was a failure in the contingency plans remains +explicitly represented in the intention stack, so that the an agent +could, in principle, reason about those failures in deciding on how to +act further. When a contingency plan -!g2 fails, the failure +cascades down the intention stack until a plan for a achieving a goal +!g1 which does have contingency plans -!g1 is found; in that +case, the event -!g1 is posted, so an applicable plan for that event +will be at the top of the intention stack and the failed -!g2 : …​ +plan will be right below it within the stack. Only in case no such +plan is found the whole intention is removed from the intention set +(and a message to say so is printed in the console, as usual).

+
+
+
+

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 +preceded 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).

    +
    +
  • +
+
+
+
+
+
+
+

How can an agent know (and reason about) its own goals?

+
+

Jason provides a set of internal actions to help agents to reason about their intentional state (the list of these internal actions is available here). This topic is also discussed in the BDI Hello World tutorial.

+
+
+

As a simple example, the following code allows the agent to discover the identifier of the current goal and the state of others.

+
+
+
+
// creates 4 intentions
+!start(a).
+!start(b).
+!start(c).
+!start(d).
+
++!start(X) // simple loop printing X
+   <- .print(X);
+      .wait( math.random(1000)+1000 );
+      !inspect(X);
+      !start(X).
+
+// this plan uses BDI internal actions to discover the current goal
++!inspect(X)
+   <- .intention(Id,State,Stack,current); // gets the state of the current intention
+      .print("current intention number is ",Id," and its state is ",State);
+      Stack = [Top|_]; // get the intended means in the top of current intention
+      Top   = im(Label, { +!Goal },PlanBody,Unifier);
+      .print("current goal is ",Goal," being pursued by plan ",Label);
+      Goal  =.. [NameSpace,Functor,Terms,Annots];
+      .print("its functor is '",Functor,"' and terms are ",Terms);
+
+      // prints out all other intentions
+      for ( .intention(_,OtherState,[ im(_, { +!OtherGoal },_,_) |_]) & OtherGoal \== Goal) {
+          .print("another goal of mine is ",OtherGoal," in state ",OtherState);
+      }.
+
+
+
+

The most important internal action used in the example is .intention.

+
+
+

The output is:

+
+
+
+
a
+b
+c
+d
+current intention number is 3 and its state is running
+current goal is inspect(c)[source(self)] being pursued by plan p__2[code_line(14),code_src("file:sample_agent.asl"),source(self)]
+      its functor is 'inspect' and terms are [c]
+
+another goal of mine is start(b)[source(self)] in state waiting[reason(wait(2)[time(1802)])]
+another goal of mine is start(d)[source(self)] in state waiting[reason(wait(4)[time(1965)])]
+another goal of mine is start(a)[source(self)] in state waiting[reason(wait(1)[time(1667)])]
+
+
+
+
+
+
+

Developing Jason

+ +
+
+ + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..b1e5f9e9 --- /dev/null +++ b/index.html @@ -0,0 +1,555 @@ + + + + + + + +Jason Documentation + + + + + +
+
+
+
+

Jason is an interpreter for an extended version of AgentSpeak. It implements the operational semantics of that language, and provides a platform for the development of multi-agent systems, with many user-customisable features. Jason is available as Open Source, and is distributed under GNU LGPL.

+
+
+

Jason is developed by Jomi F. Hübner and Rafael H. Bordini, based on previous work done with many colleagues, in particular Michael Fisher, Joyce Martins, Álvaro Moreira, Renata Vieira, Willem Visser, Mike Wooldridge, but also many others, as acknowledged in the manual (see the Jason web site).

+
+
+
+
+

Installation

+ +
+
+

Tutorials

+ +
+
+

Other

+
+
+ +
+
+
+
+

Technical documents

+ +
+
+ + + \ No newline at end of file diff --git a/install.html b/install.html new file mode 100644 index 00000000..d82a84b0 --- /dev/null +++ b/install.html @@ -0,0 +1,494 @@ + + + + + + + +Jason Installation + + + + + +
+
+
    +
  1. +

    Install Java 21

    +
  2. +
  3. +

    Install Visual Sudio Code

    +
  4. +
  5. +

    [windows] Install a terminal & shell tool like GitBash

    +
  6. +
  7. +

    Install Jason:

    +
    +
    +
    Unix and Windows
    +
    +
    +

    Download a Jason release from here (download the file named jason-bin-…​..zip) and decompress it. The zip file contains documentation, examples, and a sub-directory bin with the file jason. It is a unix executable file, if not, change its properties with chmod +x jason. Finally, adds the directory bin in your machine PATH so that the command jason can be executed in a terminal.

    +
    +
    +
    Linux
    +
    +

    You can use apt-get to install Jason (details here):

    +
    +
    +
    echo "deb [trusted=yes] http://packages.chon.group/ chonos main" | sudo tee /etc/apt/sources.list.d/chonos.list
    +sudo apt update
    +sudo apt install jason-cli
    +
    +
    +
    +
    +
    +
  8. +
+
+
+

To test the installation, run the command jason --version in a terminal. The output should be as follows:

+
+
+
+
Jason CLI 3.3.0
+
+
+
+ + + \ No newline at end of file diff --git a/jason-cli/commands.html b/jason-cli/commands.html new file mode 100644 index 00000000..a4030226 --- /dev/null +++ b/jason-cli/commands.html @@ -0,0 +1,633 @@ + + + + + + + +JasonCLI: List of all commands + + + + + +
+
+
+
+

You can get help for any command with --help. For example:

+
+
+
+
jason mas start --help
+
+
+
+
+
+

Application level

+
+
+

jason app is used to manage the source code of some application.

+
+
+
+
Usage: jason app (create | compile | add-agent | add-gradle | add-ia )
+commands to handle applications
+
+Commands:
+  create      creates the files of a new application
+  compile     compiles the java classes of an application (using Gradle)
+              and produces a jar file with all necessary to run the application
+  add-agent   adds the code of a new agent into the application
+  add-gradle  adds a Gradle script for the application
+  add-ia      adds the source code a new internal action into the application
+
+
+
+
+
+

MAS level

+
+
+

jason mas is used to manage the execution of applications.

+
+
+
+
Usage: jason mas (start | stop | list)
+commands to handle running Multi-Agent Systems
+
+Sub-commands:
+  start  starts a new (empty) MAS
+  stop   stops a MAS
+  list   lists current running MAS
+
+
+
+

MAS start

+
+
+
Usage: jason mas start [--console] [--no-net] [<mas name>]
+starts a new (empty) MAS
+      [<mas name>]   MAS unique identification
+      --console      output will be sent to the console instead of a GUI
+      --no-net       disable all net services (mind inspector, runtime
+                     services, Mbeans, ...)
+      --mas2j=<file> runs jason project without
+                     gradle (offline), java classes should be compiled
+                     before running
+      --use-gradle   executes the MAS defined in a mas2j file using gradle
+      --cp=<classpath> directories where java classes can be found (for
+                     environment implementation, for instance)
+      --env=<env class> class that implements the environment and its
+                     arguments
+
+
+
+

Regarding .mas2j files, they can be executed in two ways:

+
+
+
    +
  • +

    jason x.mas2j: it creates a build.gradle for the project and then uses Gradle to compile and run the project. Gradle will download dependencies, so internet connection is necessary.

    +
  • +
  • +

    jason app start --mas2j=x.mas2j: it executes the MAS without Gradle (it thus runs offline). However, all java code have to be compiled before. The command jason app compile can be used for that (note that this command uses Gradle to compile --- so compile online, run offline).

    +
  • +
+
+
+
+

MAS stop

+
+
+
Usage: jason mas stop [--exit] [--deadline=<deadline>] [<mas name>]
+stops a MAS
+      [<mas name>]   MAS unique identification
+      --deadline=<deadline>
+                     the amount of time (in milliseconds) to wait for stopping the MAS
+      --exit         stops the MAS and terminates the process
+
+
+
+
+
+
+

Agent level

+
+
+

jason agent is used to manage the execution of agents.

+
+
+
+
Usage: jason agent (start | stop | list | run-as | load-into | mind | status)
+commands to handle agents
+
+Commands:
+  start      starts a new (empty) agent
+  stop       kills an agent
+  list       lists running agents
+  run-as     executes commands for an agent
+  mind       inspects the mind of an agent
+  status     shows the status of an agent
+  load-into  loads some ASL code into a running agent
+
+
+
+

Agent start

+
+
+
Usage: jason agent start <agent name>
+starts a new (empty) agent
+
+      <agent name>   agent unique identification
+      --instances=<instances>
+                     how many agents should be created
+      --mas-name=<mas name>
+                     MAS unique identification
+      --source=<source file>
+                     file (or URL) for the source code of the agent
+      --ag-class=<java class>
+                     agent class customization
+      --ag-arch=<java class>
+                     agent architecture customization
+
+
+
+

The source code can be informed at the end of the command enclosed by { and }. For instance:

+
+
+
+
jason agent start bob { +!g <- .print(ok). }
+
+
+
+

Depending on your prompt shell, you should enclose the commands by "":

+
+
+
+
jason agent start bob " { +!g <- .print(ok). } "
+
+
+
+
+

Other agent commands

+
+

Type jason agent stop --help for details of stop command …​

+
+
+
+
+
+ + + \ No newline at end of file diff --git a/jason-cli/figs/s1.png b/jason-cli/figs/s1.png new file mode 100644 index 00000000..b1df197d Binary files /dev/null and b/jason-cli/figs/s1.png differ diff --git a/jason-cli/index.html b/jason-cli/index.html new file mode 100644 index 00000000..ccfc5df6 --- /dev/null +++ b/jason-cli/index.html @@ -0,0 +1,770 @@ + + + + + + + +Command Line Interface (CLI) for Jason + + + + + +
+
+
+
+

The Jason CLI is a command-line interface tool that you use to initialize, develop, and maintain Jason applications directly from a command shell at design and run time.

+
+
+
+

Jason Installation

+
+
    +
  1. +

    Install Java 21

    +
  2. +
  3. +

    Install Visual Sudio Code

    +
  4. +
  5. +

    [windows] Install a terminal & shell tool like GitBash

    +
  6. +
  7. +

    Install Jason:

    +
    +
    +
    Unix and Windows
    +
    +
    +

    Download a Jason release from here (download the file named jason-bin-…​..zip) and decompress it. The zip file contains documentation, examples, and a sub-directory bin with the file jason. It is a unix executable file, if not, change its properties with chmod +x jason. Finally, adds the directory bin in your machine PATH so that the command jason can be executed in a terminal.

    +
    +
    +
    Linux
    +
    +

    You can use apt-get to install Jason (details here):

    +
    +
    +
    echo "deb [trusted=yes] http://packages.chon.group/ chonos main" | sudo tee /etc/apt/sources.list.d/chonos.list
    +sudo apt update
    +sudo apt install jason-cli
    +
    +
    +
    +
    +
    +
  8. +
+
+
+

To test the installation, run the command jason --version in a terminal. The output should be as follows:

+
+
+
+
Jason CLI 3.3.0
+
+
+
+

Create and Execute Applications

+
+
+

New Jason applications can be created and executed with:

+
+
+
+
jason app create app1 --console
+cd app1
+jason app1.mas2j
+
+
+
+

The first command creates a Jason application identified by app1 with two agents and a shared environment. The third command executes the application. The output:

+
+
+
+
[bob] hello world.
+[alice] hello world.
+
+
+
+

This approach uses Gradle to execute the application. Gradle is useful if you are using other packages. However, if you do not have dependencies, the application can be started faster without Gradle:

+
+
+
+
jason mas start --mas2j=app1.mas2j
+
+
+
+

You can add more agents in the project with:

+
+
+
+
jason app add-agent karlos
+
+
+
+

To run agent karlos, there are two options: stop the MAS and run it again; or add karlos in the running MAS:

+
+
+
+
jason agent start --source="src/agt/karlos.asl" --mas-name="app1" karlos
+
+
+
+

You can add a Gradle script for the application with:

+
+
+
+
jason app add-gradle
+
+
+
+

and then run it with ./gradlew run.

+
+
+

More details and commands with (or here):

+
+
+
+
jason app
+
+
+
+

Then use your preferred IDE to edit the sources of the application, which are in the src folder.

+
+
+

The commands of this section are used to help change the source code of some application. To change or monitor the state of running applications, see the commands below.

+
+
+
+
+

Manage (running) MAS

+
+
+

In your preferred terminal, you can start a new empty MAS with:

+
+
+
+
$ jason mas start --console
+
+
+
+

In another terminal, you can start another MAS with:

+
+
+
+
$ jason mas start m1
+
+
+
+

If you have an application with a .mas2j file, you can start it with:

+
+
+
+
$ jason app.mas2j
+
+
+
+

Yet in another terminal we can list currently running MAS and stop them:

+
+
+
+
$ jason mas list
+$ jason mas stop m1 --exit
+
+
+
+

Agent commands:

+
+
+
+
$ jason agent start  bob   --mas-name=mas_1
+$ echo "\!s. +\!s <- .send(bob,tell,hello)." > x.asl
+$ jason agent start  alice --mas-name=mas_1 --source=x.asl
+$ jason agent list         --mas-name=mas_1
+$ jason agent status bob   --mas-name=mas_1
+$ jason agent mind   bob   --mas-name=mas_1
+$ echo "+b <- .print(perceived(b))." > y.asl
+$ jason agent load-into alice --mas-name=mas_1 --source=y.asl
+$ jason agent mind alice   --mas-name=mas_1 --plans
+
+
+
+
+
+

Interactive Shell

+
+
+

To open the Jason shell, simply execute jason:

+
+
+
+
$ jason
+Jason interactive shell with completion and autosuggestions.
+  Hit <TAB> to see available commands.
+  Press Ctrl-D to exit.
+jason>
+
+
+
+

the <TAB> key is your new 'mouse' to explore the system.

+
+
+

Example of use:

+
+
+
+
jason> mas start
+jason> agent start bob
+jason> agent start alice {
+    !start.
+    +!start <- .send(bob,tell,hello).
+}
+jason> agent mind bob
+    hello[source(alice)]
+jason> agent run-as bob { .send(alice,tell,hello) }
+jason> exit
+
+
+
+

In this example,

+
+
+
    +
  • +

    an (empty) MAS is created in the first command,

    +
  • +
  • +

    agent bob is created (second command) — with no beliefs or plans;

    +
  • +
  • +

    agent alice is created (third command) — with an initial goal and plan.

    +
  • +
  • +

    alice achieves the goal !start by sending a message to bob

    +
  • +
  • +

    the beliefs of bob are shown (fourth command).

    +
  • +
  • +

    bob also send a hello message to alice (fifth command).

    +
  • +
  • +

    the MAS is finished (last command).

    +
  • +
+
+
+

The shell provides completion and suggestions (using <TAB>).

+
+
+

screen show

+
+
+
+
+

Scripts

+
+
+

Create a script file, for instance, a file called hello.jcli with content:

+
+
+
+
mas start
+
+# starts bob with a plan
+agent start bob    { +hello[source(A)] <- .print("hello from ",A). }
+
+agent start alice
+agent run-as alice { .send(bob,tell,hello) }  # alice executes the .send...
+
+echo
+echo "beliefs of Bob:"
+agent mind bob         # show beliefs of bob
+
+
+
+

then run the script with

+
+
+
+
$ jason < hello.jcli
+
+
+
+

the output in the MAS Console will be:

+
+
+
+
[alice] done
+[bob] hello from alice
+
+
+
+

and the output in the terminal is:

+
+
+
+
starting MAS mas_1 ...
+MAS mas_1 is running (127.0.0.1:59052).
+agent bob started.
+agent alice started.
+beliefs of Bob:
+    hello[source(alice)]
+<end of script>
+
+
+
+

(the list of all commands is here.)

+
+
+
+
+ + + \ No newline at end of file diff --git a/jason-cli/readme.html b/jason-cli/readme.html new file mode 100644 index 00000000..ccfc5df6 --- /dev/null +++ b/jason-cli/readme.html @@ -0,0 +1,770 @@ + + + + + + + +Command Line Interface (CLI) for Jason + + + + + +
+
+
+
+

The Jason CLI is a command-line interface tool that you use to initialize, develop, and maintain Jason applications directly from a command shell at design and run time.

+
+
+
+

Jason Installation

+
+
    +
  1. +

    Install Java 21

    +
  2. +
  3. +

    Install Visual Sudio Code

    +
  4. +
  5. +

    [windows] Install a terminal & shell tool like GitBash

    +
  6. +
  7. +

    Install Jason:

    +
    +
    +
    Unix and Windows
    +
    +
    +

    Download a Jason release from here (download the file named jason-bin-…​..zip) and decompress it. The zip file contains documentation, examples, and a sub-directory bin with the file jason. It is a unix executable file, if not, change its properties with chmod +x jason. Finally, adds the directory bin in your machine PATH so that the command jason can be executed in a terminal.

    +
    +
    +
    Linux
    +
    +

    You can use apt-get to install Jason (details here):

    +
    +
    +
    echo "deb [trusted=yes] http://packages.chon.group/ chonos main" | sudo tee /etc/apt/sources.list.d/chonos.list
    +sudo apt update
    +sudo apt install jason-cli
    +
    +
    +
    +
    +
    +
  8. +
+
+
+

To test the installation, run the command jason --version in a terminal. The output should be as follows:

+
+
+
+
Jason CLI 3.3.0
+
+
+
+

Create and Execute Applications

+
+
+

New Jason applications can be created and executed with:

+
+
+
+
jason app create app1 --console
+cd app1
+jason app1.mas2j
+
+
+
+

The first command creates a Jason application identified by app1 with two agents and a shared environment. The third command executes the application. The output:

+
+
+
+
[bob] hello world.
+[alice] hello world.
+
+
+
+

This approach uses Gradle to execute the application. Gradle is useful if you are using other packages. However, if you do not have dependencies, the application can be started faster without Gradle:

+
+
+
+
jason mas start --mas2j=app1.mas2j
+
+
+
+

You can add more agents in the project with:

+
+
+
+
jason app add-agent karlos
+
+
+
+

To run agent karlos, there are two options: stop the MAS and run it again; or add karlos in the running MAS:

+
+
+
+
jason agent start --source="src/agt/karlos.asl" --mas-name="app1" karlos
+
+
+
+

You can add a Gradle script for the application with:

+
+
+
+
jason app add-gradle
+
+
+
+

and then run it with ./gradlew run.

+
+
+

More details and commands with (or here):

+
+
+
+
jason app
+
+
+
+

Then use your preferred IDE to edit the sources of the application, which are in the src folder.

+
+
+

The commands of this section are used to help change the source code of some application. To change or monitor the state of running applications, see the commands below.

+
+
+
+
+

Manage (running) MAS

+
+
+

In your preferred terminal, you can start a new empty MAS with:

+
+
+
+
$ jason mas start --console
+
+
+
+

In another terminal, you can start another MAS with:

+
+
+
+
$ jason mas start m1
+
+
+
+

If you have an application with a .mas2j file, you can start it with:

+
+
+
+
$ jason app.mas2j
+
+
+
+

Yet in another terminal we can list currently running MAS and stop them:

+
+
+
+
$ jason mas list
+$ jason mas stop m1 --exit
+
+
+
+

Agent commands:

+
+
+
+
$ jason agent start  bob   --mas-name=mas_1
+$ echo "\!s. +\!s <- .send(bob,tell,hello)." > x.asl
+$ jason agent start  alice --mas-name=mas_1 --source=x.asl
+$ jason agent list         --mas-name=mas_1
+$ jason agent status bob   --mas-name=mas_1
+$ jason agent mind   bob   --mas-name=mas_1
+$ echo "+b <- .print(perceived(b))." > y.asl
+$ jason agent load-into alice --mas-name=mas_1 --source=y.asl
+$ jason agent mind alice   --mas-name=mas_1 --plans
+
+
+
+
+
+

Interactive Shell

+
+
+

To open the Jason shell, simply execute jason:

+
+
+
+
$ jason
+Jason interactive shell with completion and autosuggestions.
+  Hit <TAB> to see available commands.
+  Press Ctrl-D to exit.
+jason>
+
+
+
+

the <TAB> key is your new 'mouse' to explore the system.

+
+
+

Example of use:

+
+
+
+
jason> mas start
+jason> agent start bob
+jason> agent start alice {
+    !start.
+    +!start <- .send(bob,tell,hello).
+}
+jason> agent mind bob
+    hello[source(alice)]
+jason> agent run-as bob { .send(alice,tell,hello) }
+jason> exit
+
+
+
+

In this example,

+
+
+
    +
  • +

    an (empty) MAS is created in the first command,

    +
  • +
  • +

    agent bob is created (second command) — with no beliefs or plans;

    +
  • +
  • +

    agent alice is created (third command) — with an initial goal and plan.

    +
  • +
  • +

    alice achieves the goal !start by sending a message to bob

    +
  • +
  • +

    the beliefs of bob are shown (fourth command).

    +
  • +
  • +

    bob also send a hello message to alice (fifth command).

    +
  • +
  • +

    the MAS is finished (last command).

    +
  • +
+
+
+

The shell provides completion and suggestions (using <TAB>).

+
+
+

screen show

+
+
+
+
+

Scripts

+
+
+

Create a script file, for instance, a file called hello.jcli with content:

+
+
+
+
mas start
+
+# starts bob with a plan
+agent start bob    { +hello[source(A)] <- .print("hello from ",A). }
+
+agent start alice
+agent run-as alice { .send(bob,tell,hello) }  # alice executes the .send...
+
+echo
+echo "beliefs of Bob:"
+agent mind bob         # show beliefs of bob
+
+
+
+

then run the script with

+
+
+
+
$ jason < hello.jcli
+
+
+
+

the output in the MAS Console will be:

+
+
+
+
[alice] done
+[bob] hello from alice
+
+
+
+

and the output in the terminal is:

+
+
+
+
starting MAS mas_1 ...
+MAS mas_1 is running (127.0.0.1:59052).
+agent bob started.
+agent alice started.
+beliefs of Bob:
+    hello[source(alice)]
+<end of script>
+
+
+
+

(the list of all commands is here.)

+
+
+
+
+ + + \ No newline at end of file diff --git a/publish.sh b/publish.sh new file mode 100755 index 00000000..bebcf62e --- /dev/null +++ b/publish.sh @@ -0,0 +1,10 @@ +# +# by Jomi +# + +cd .. +./gradlew renderAsciidoc +./gradlew javadoc +cd doc +cp readme.html index.html +scp -r * $USERSF,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/doc diff --git a/publishDocInGHPages.sh b/publishDocInGHPages.sh new file mode 100755 index 00000000..234d66fc --- /dev/null +++ b/publishDocInGHPages.sh @@ -0,0 +1,24 @@ +cd .. + +./gradlew doc + +SITE_PATH=../jason-lang.github.io + +rm -rf $SITE_PATH/api +rm -rf $SITE_PATH/doc + +IMAGE=jomifred/adoc +docker run --rm -i --user="$(id -u):$(id -g)" --net=none -v "$PWD":/app "$IMAGE" asciidoctor -r /pygments_init.rb -a stylesheet=adoc-empty.css doc/readme.adoc -o doc/doc.html + +cp -R jason-interpreter/build/docs/javadoc $SITE_PATH/api +cp -R doc $SITE_PATH + +cd $SITE_PATH +git add api +git commit -a -m "add javadoc api" + +#find doc -name readme.html -execdir cp readme.html index.html \; +git add doc +git commit -a -m "add jason github doc folder" + +git push diff --git a/publishFAQ.sh b/publishFAQ.sh new file mode 100755 index 00000000..3cc7c9df --- /dev/null +++ b/publishFAQ.sh @@ -0,0 +1,2 @@ +../scripts/asciidoc-docker faq.adoc +scp faq.html $USERSF,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/doc diff --git a/readme.html b/readme.html new file mode 100644 index 00000000..b1e5f9e9 --- /dev/null +++ b/readme.html @@ -0,0 +1,555 @@ + + + + + + + +Jason Documentation + + + + + +
+
+
+
+

Jason is an interpreter for an extended version of AgentSpeak. It implements the operational semantics of that language, and provides a platform for the development of multi-agent systems, with many user-customisable features. Jason is available as Open Source, and is distributed under GNU LGPL.

+
+
+

Jason is developed by Jomi F. Hübner and Rafael H. Bordini, based on previous work done with many colleagues, in particular Michael Fisher, Joyce Martins, Álvaro Moreira, Renata Vieira, Willem Visser, Mike Wooldridge, but also many others, as acknowledged in the manual (see the Jason web site).

+
+
+
+
+

Installation

+ +
+
+

Tutorials

+ +
+
+

Other

+
+
+ +
+
+
+
+

Technical documents

+ +
+
+ + + \ No newline at end of file diff --git a/release-notes.html b/release-notes.html new file mode 100644 index 00000000..6daf4b5b --- /dev/null +++ b/release-notes.html @@ -0,0 +1,3652 @@ + + + + + + + +Jason release notes + + + + + +
+
+

version 3.3

+
+
+
    +
  • +

    Java 21 is used

    +
  • +
  • +

    Agent’s thread is Virtual and not Platform. It allow us to run thousands of agents.

    +
  • +
  • +

    namespaces may have assigned properties/values. See internal actions .namespace_set_property and .namespace_get_property.

    +
  • +
  • +

    internal actions .min and .max may have a query as second argument.

    +
  • +
  • +

    several (minor) improvements in Jason-CLI. About running a project:

    +
    +
      +
    • +

      jason x.mas2h uses gradle to run the application

      +
    • +
    • +

      jason mas start --mas2j=x.mas2h runs without gradle. The classpath might be informed using --cp if necessary.

      +
    • +
    • +

      jason app compile uses shadowJar to create a jar file with all files and dependencies to run the application.

      +
    • +
    +
    +
  • +
  • +

    update doc for new Jason web site: https://jason-lang.github.io

    +
  • +
+
+
+
+
+

version 3.2 (2023-04-15)

+
+
+

The main new feature of Jason 3.2 is the Jason Command Line Interface (JasonCLI). This tool is created to support the creation and monitoring of Jason application independently of IDEs. More information here.

+
+
+
    +
  • +

    Java17 is used

    +
  • +
  • +

    some bugs were fixed

    +
  • +
  • +

    preliminary support for packages (used by JaCaMo)

    +
  • +
  • +

    Jason is available in Maven Central

    +
  • +
  • +

    mas2j files do not handle java class path anymore. Gradle should be used for that. The command jason app add-gradle turn a Jason project into a Gradle project. It also helps your IDE to find Jason dependencies when programming Java classes for the environment, internal actions, …​

    +
  • +
  • +

    to use JADE, the Jason project should have a Gradle script. Then ./gradlew runJade can be used to start the MAS on top of JADE.

    +
  • +
+
+
+

The project is cleaned:

+
+
+
    +
  • +

    jEdit is removed (JasonCLI and third party IDEs are proposed)

    +
  • +
  • +

    Ant is replaced by Gradle

    +
  • +
  • +

    Java Web Start is not used anymore

    +
  • +
+
+
+
+
+

version 3.1 (2022-03-23)

+
+
+
    +
  • +

    This release only contains bug fixes

    +
  • +
+
+
+
+
+

version 3.0 (2021-09-07)

+
+
+
    +
  • +

    The major contribution of this version is the inclusion of Jason(ER), see papers AgentSpeak(ER): Enhanced Encapsulation in Agent Plans and Encapsulating Reactive Behaviour in Goal-based Plans for Programming BDI Agents.

    +
    +
      +
    • +

      improved encapsulation (sub-plans)

      +
    • +
    • +

      goal condition (to be dropped)

      +
    • +
    • +

      see examples/contract-net-protocol-er for an example

      +
    • +
    +
    +
  • +
  • +

    Cartago is not included in the distribution anymore. Use JaCaMo for a proper integration of Jason and Cartago.

    +
  • +
  • +

    Centralised infrastructure was renamed to Local. Classes as RunCentralisedMAS was renamed to RunLocalMAS.

    +
  • +
  • +

    The Jason Grammar was refactored and improved by Jan Pierry Coelho dos Santos

    +
  • +
  • +

    Java 15 is used

    +
  • +
+
+
+
+
+

version 2.6 (2020-09-28)

+
+
+
    +
  • +

    the functor of plan labels can be omitted, as in @[atomic] +!g ← a. In this case, as usual, a new unique label functor is defined by the interpreter.

    +
  • +
  • +

    new syntax for list tail: [|T] (note that we have no term before |). It unifies with any list (even empty) and thus it is conceptually equivalent to T. It is useful to get the list of all annotations of some belief: ?b(X)[|AllAnnots].

    +
  • +
  • +

    new tests framework implemented in Jason (see src/test/jason/asl and doc/tech/unit-tests), contribution of Cleber Amaral.

    +
  • +
  • +

    new internal action .intention used to inspect the state of intentions. .current_intention is still available for backwards compatibility but will not be improved.

    +
  • +
  • +

    new internal action .set_random_seed, contribution of Timotheus Kampik.

    +
  • +
  • +

    internal action .stopMAS has a new (optional) argument for exit value.

    +
  • +
  • +

    revision of goal states reported in meta events and used in .desire and .intend. See doc/tech/goal-states.pdf for more details.

    +
  • +
  • +

    new internal actions to manipulate a Java Queues. In Jason, it is represented by a variable. Example:

    +
    +
    +
    .queue.create(Q);                // Q = []
    +.queue.add(Q,a);                 // Q = [a]
    +.queue.add(Q,b);                 // Q = [a, b]
    +.queue.add_all(Q,[c,d,e]);       // Q = [a, b, c, d, e]
    +.queue.copy(Q,Bak);              // Bak = [a, b, c, d, e]
    +.queue.head(Q,H);                // H = a
    +.queue.remove(Q,H);              // H = a, Q = [b, c, d, e]; Bak = [a, b, c, d, e]
    +.length(Q,X);                    // X = 4
    +// iteration
    +for ( .member(V,Q) ) {
    +   .print(V);
    +}.
    +.queue.clear(Q);                 // Q = []
    +
    +
    +
    +

    The queue can be ordered as follows (and a Java Priority Queue is used):

    +
    +
    +
    +
    .queue.create(Q,priority);       // Q = [] with priority
    +.queue.add(Q,d);                 // Q = [d]
    +.queue.add(Q,c);                 // Q = [c, d]
    +.queue.add_all(Q,[b,d,a]);       // Q = [a, b, c, d, e]
    +.queue.head(Q,H);                // H = a
    +
    +
    +
  • +
  • +

    url syntax can be used for project file, as in:

    +
    +
    +
    java -cp "$JASON_HOME/libs/*" jason.infra.centralised.RunCentralisedMAS jar:file:/home/bob/myfile.jar!/x.masj2
    +
    +
    +
  • +
  • +

    url syntax can be used in aslSourcePath, for example:

    +
    +
    +
    MAS ex1 {
    +    agents: bob;
    +
    +    aslSourcePath:
    +       "src";
    +       "http://acme.com/src";
    +       "jar:file:/home/bob/my.jar/src";
    +       "$jasonJar/test/jason/inc";
    +}
    +
    +
    +
  • +
  • +

    add option --log-conf to setup the logging configuration file when launching the application. Examples:

    +
    +
    +
    java -cp "$JASON_HOME/libs/*" jason.infra.centralised.RunCentralisedMAS \
    +    x.mas2j \
    +    --log-conf mylog.properties
    +
    +
    +
    +
    +
    java -cp "$JASON_HOME/libs/*" jason.infra.centralised.RunCentralisedMAS \
    +    x.mas2j \
    +    --log-conf jar:file:$JASON_HOME/libs/jason-2.6-SNAPSHOT.jar!/templates/console-logging.properties
    +
    +
    +
    +
    +
    java -cp "$JASON_HOME/libs/*" jason.infra.centralised.RunCentralisedMAS \
    +    x.mas2j \
    +    --log-conf \$jasonJar/templates/console-logging.properties
    +
    +
    +
  • +
+
+
+
+
+

version 2.5 (2020-06-25)

+
+
+
    +
  • +

    cascading failures of failures (see FAQ)

    +
  • +
  • +

    new internal actions to manipulate a Java Set. In Jason, it is represented by a variable. Example:

    +
    +
    +
    .set.create(S);                // S = {}
    +.set.add(S,a);                 // S = {a}
    +.set.add_all(S,[5,b,p(2),a]);  // S = {5,a,b,p(2)}
    +.set.remove(S,b);              // S = {5,a,p(2)}
    +.set.union(S,[a,1]);           // S = {1,5,a,p(2)}
    +.length(S,X);                  // X = 4
    +.set.difference(S,[1,a]);      // S = {5,p(2)}
    +.findall(K, .member(K,S), LL)  // LL = [5,p(2)]
    +.set.add(S,5);
    +.set.intersection(S,V);        // S = {5}
    +.set.copy(S,Bak);              // Bak = {5}
    +.set.clear(S);                 // S = {}; Bak = {5}
    +// iteration
    +for ( .member(V,S) ) {
    +   .print(K,V);
    +}.
    +
    +
    +
  • +
  • +

    new internal actions to manipulate a Java Map. In Jason, it is represented by a variable. Example:

    +
    +
    +
    .map.create(M);                  // M = {}
    +.map.put(M,a,10);                // M = {a->10}
    +.map.put(M,b,ok);                // M = {a->10, b->ok}
    +.map.put(M,a,20);                // M = {a->20, b->ok}
    +.length(M,X);                    // X = 2
    +.map.key(M,a)                    // true
    +.map.key(M,V)                    // unifies V with all keys of M
    +.map.value(M,10)                 // true
    +.map.value(M,V)                  // unifies V with all values of M
    +.findall(K, .map.key(M,K), LL)   // LL = [a,b]
    +.findall(V, .map.value(M,V), LL) // LL = [20,ok]
    +.findall([K,V], .map.key(M,K) & .map.get(M,K,V), LL)
    +                                 // LL = [[a,30],[d,ok(3)]]
    +.map.get(M,a,V);                 // V = 20
    +.map.get(M,c,V);                 // fail
    +.map.get(M,c,V,0);               // V = 0
    +.map.remove(M,a,V);              // M = {b->ok} V = 20
    +.map.copy(M,Bak);                // Bak = {b->ok}
    +.map.clear(M);                   // M = {}; Bak = {b->ok}
    +// iteration
    +for ( .map.key(M,K) & .map.get(M,K,V) ) {
    +   .print(K,V);
    +}.
    +
    +
    +
  • +
  • +

    new internal action to replace strings (see internal action .replace).

    +
  • +
+
+
+
+
+

version 2.4 (2019-05-24)

+
+
+

(a built package is available at here)

+
+
+
    +
  • +

    .stopMAS accepts an optional parameter with an amount of time before shutdown. Agents thus can prepare themselves reacting to the signal +jag_shutting_down(T). E.g.

    +
    +
    +
    ...  .stopMAS(2000); // shutdown the system in 2 seconds
    +...
    ++jag_shutting_down(T) <- .print("I have ",T/1000," seconds to pack my stuff").
    +
    +
    +
  • +
  • +

    similarly, .kill_agent has an optional parameter to inform the amount of time before the agent will be killed.

    +
  • +
  • +

    New performative signal. The semantics is that the receiver will have the event added in its event queue. For example, if Alice executes

    +
    +
    +
    .send(bob,signal,hello);
    +.send(bob,signal,hello);
    +
    +
    +
    +

    it produces in Bob two events +hello[source(alice)]. Different than tell, no belief is added.

    +
    +
  • +
  • +

    New internal action to change verbosity:

    +
    +
      +
    • +

      .verbose(2): start showing debug messages

      +
    • +
    • +

      .verbose(1): goes back to normal message / logging level

      +
    • +
    +
    +
  • +
  • +

    Improved support for meta-programming. See demos/meta-programming.

    +
  • +
  • +

    event +!jag_sleeping was replaced by (a signal) +jag_sleeping

    +
  • +
  • +

    event +!jag_awaking was replaced by (a signal) +jag_awaking

    +
  • +
+
+
+
+
+

version 2.3 (2018-10-01)

+
+
+

(a built package is available at here)

+
+
+
    +
  • +

    New internal actions to support Directory Facilitator services:

    +
    +
      +
    • +

      .df_register(S): register the agent in the DF as a provider of service S

      +
    • +
    • +

      .df_deregister(S): removes the agent in the DF as a provider of service S

      +
    • +
    • +

      .df_search(S, L): unifies in L a list of all agents providing the service S

      +
    • +
    • +

      .df_subscribe(S): subscribes the agent as interested in providers of service S

      +
      +

      When JADE is used, this services are mapped to the JADE DF service.

      +
      +
    • +
    +
    +
  • +
  • +

    Java 1.8 a is now used

    +
  • +
  • +

    new syntax: operator -- to delete some belief with new focus for the event.

    +
  • +
  • +

    new internal action: .drop_future_intention (see javadoc api for more information)

    +
  • +
  • +

    new internal action: .printf, inspired in Java Format +(https://docs.oracle.com/javase/tutorial/java/data/numberformat.html)

    +
    +
    +
    I=4;
    +D=34.123;
    +.printf("i=%08.0f and d=%10.2f", I, D);
    +
    +
    +
    +

    produces:

    +
    +
  • +
+
+
+
+
i=00000004 and d=     34.12
+
+
+
+
+
+

version 2.2 (2017-09-21)

+
+
+

(a built package is available at here)

+
+
+
    +
  • +

    new syntax for atoms: as in Prolog, any sequence of characters enclosed by ' can be used. Examples:

    +
    +
      +
    • +

      '$%12' (atom)

      +
    • +
    • +

      b('@1') (term using new syntax, in this case, the term is an atom and not a string)

      +
    • +
    • +

      '$%12'(10) (literal with functor using new syntax)

      +
    • +
    +
    +
  • +
  • +

    new syntax: optional elif in conditional statement. Example:

    +
    +
    +
    if   (e(1)) { .print(a); }
    +elif (e(2)) { .print(b); }
    +elif (e(3)) { .print(c); }
    +else        { .print(d); }
    +
    +
    +
  • +
  • +

    this release fixes some bugs and improves documentation

    +
  • +
+
+
+
+
+

version 2.1 (2016-12-15)

+
+
+

(a built package is available at here)

+
+
+
    +
  • +

    this release just fixes some bugs

    +
  • +
+
+
+
+
+

version 2.0 (2016-09-15)

+
+
+

(a built package is available at here)

+
+
+

New features

+
+
+
    +
  • +

    modules and namespaces, see doc/tech/modules-namespaces.pdf

    +
  • +
  • +

    concurrent courses of actions within a single plan and advanced concurrent agent architectures, see doc/tech/concurrency.html

    +
  • +
  • +

    operator + works with plans and rules enclosed by { and }. For instance:

    +
    +
    +
    ...
    ++ { p :- q & r };
    ++ { +b : p <- .print(ok) };
    +...
    +
    +
    +
  • +
  • +

    two new parameters in the .jason/user.properties file: kqmlPlansFile (the file +with the plans that implement the KQML semantics) and kqmlReceivedFunctor +(the functor used to produce new message events).

    +
  • +
  • +

    improved BUF with linear time (previous belief update function was quadratic)

    +
  • +
  • +

    source code has been moved to GitHub

    +
  • +
  • +

    started using gradle

    +
  • +
+
+
+

New internal actions

+
+
+
    +
  • +

    .asserta: inserts a belief (or rule) in the begin of the belief base (can be used in prolog like rules)

    +
  • +
  • +

    .assertz: inserts a belief (or rule) in the end of the belief base (can be used in prolog like rules)

    +
  • +
  • +

    .relevant_rules: gets rules with a given head predicate

    +
  • +
  • +

    .lower_case and .upper_case for strings

    +
  • +
  • +

    .include: to load an asl source code at run time

    +
  • +
+
+
+

Changes

+
+
+
    +
  • +

    AgArch act method has just one parameter (the action to be executed)

    +
  • +
  • +

    Java 1.7 is now used

    +
  • +
  • +

    JaCaMo is not an available infrastructure anymore, it has its own support to run MAS (the .jcm files)

    +
  • +
+
+
+ + + + + +
+
Note
+
+In Jason 2.0 the way to run the Jason IDE (based on jEdit) has changed. Rather than running an application (Jason.exe or Jason.app), the IDE is now run by double clicking the jedit/jedit.jar file or using the script files in the scripts folder. +
+
+
+

New Tutorial on BDI (see doc/tutorials/hello-bdi/readme.html).

+
+
+
+
+

version 1.4.2 (2015-03-03)

+
+
+

revision 1821 on SVN of SF

+
+
+

New features

+
+
+
    +
  • +

    REPL button on MASConsole and jason-repl.jar +this feature allows the user to easily create +and run agents while the MAS is running

    +
  • +
+
+
+
+
+

version 1.4.1 (2014-08-06)

+
+
+

revision 1792 on SVN

+
+
+

New features

+
+
+ +
+
+
+
+

version 1.4.0 (2014-03-06)

+
+
+

revision 1759 on SVN

+
+
+

New features

+
+
+
    +
  • +

    implementation of tail recursion optimisation (TRO) for sub-goals. +It can be turned off in the agent options, e.g.:

    +
    +
    +
    agents: bob [tro=false];
    +
    +
    +
  • +
+
+
+

Changes in the API

+
+
+
    +
  • +

    the method apply was removed and replaced by capply that +clones and applies an unifier. Usually a code like

    +
    +
    +
    Term t = ....
    +t = t.clone();
    +t.apply(u);
    +
    +
    +
    +
    +
    should be replaced by
    +
    +
    +
    +
    +
    Term t = .....
    +t = t.capply(u);
    +
    +
    +
  • +
+
+
+

NB. TRO and capply have improved the performance of some applications by up to 30%.

+
+
+
+
+

version 1.3.10b (2013-10-04)

+
+
+

revision 1750 on SVN

+
+
+

New features

+
+
+
    +
  • +

    (sub)goals can have a deadline, e.g.

    +
    +
    +
    ...; !g(4)[hard_deadline(3000)]; ...
    +
    +
    +
    +

    if g(4) is not finished in 3 seconds, a failure event is produced.

    +
    +
  • +
  • +

    the internal action .wait accepts a logical expression as argument, as in

    +
    +
    +
    ...; .wait(b(X) & X > 10); ....
    +
    +
    +
    +

    The intention will be suspended until the agent believes b(X) with X > 10. + Timeout and elapse time arguments can be used as previously.

    +
    +
  • +
+
+
+

New example:

+
+
+ +
+
+
+
+

version 1.3.9 (2013-03-14)

+
+
+

revision 1721 on SVN

+
+
+

New features

+
+
+
    +
  • +

    new operators do add beliefs

    +
    +
      +
    • +

      "++" adds a belief with new focus (a new intention is created for the +event produced by the addition)

      +
    • +
    • +

      "<" adds a belief at the beginning of the belief base (it is the same as +the usual "" operator)

      +
    • +
    • +

      '+>" adds a belief at the end of the belief base

      +
    • +
    +
    +
  • +
  • +

    new special achievement goal events

    +
    +
    +
    	+!jag_sleeping
    +	+!jag_awaking
    +
    +
    +
    +

    that are created when the agent is going to sleep (has just become idle) and is becoming busy after sleeping, respectively. +See demos/idle for an example of how to use this feature.

    +
    +
  • +
+
+
+ + + + + +
+
Note
+
+The +!idle event is deprecated, you must use +!jag_sleeping instead! + Note however that the +!jag_sleeping event is only generated when the agent + starts an idle period, rather than being generated again at every reasoning + cycle as with +!idle in previous releases. +
+
+
+
    +
  • +

    new agent options:

    +
    +
      +
    • +

      [qcache=cycle]: it enables cache for queries on the same cycle, this could +improve the agent performance in some applications.

      +
    • +
    • +

      [qprofiling=yes]: it generates some statistical data related to queries and is used +to measure the performance of the qcache option

      +
    • +
    +
    +
  • +
  • +

    new general configuration parameter the define whether short names will be used +for unnamed variables (those starting with _). +Usually these vars may have quite long names. With this option enabled, the names +will be kept short.

    +
    +

    This parameter is stored in the ~/.jason/user.properties file and can be changed either by editing the file or by running

    +
    +
    +
    +
    java -jar lib/jason.jar
    +
    +
    +
  • +
+
+
+ + + + + +
+
Note
+
+If in the user.properties file doesn’t exist the first time someone runs Jason, the file <jason install directory>/jason.properties will be used for initial user’s parameters. +
+
+
+
    +
  • +

    new internal action .shuffle to shuffle the elements of lists

    +
  • +
+
+
+
+
+

version 1.3.8 (2012-08-10)

+
+
+

revision 1709 on SVN

+
+
+

New features

+
+
+
    +
  • +

    new internal action .empty to check lists

    +
  • +
  • +

    new method in Agent class (killAcc) to customise +whether an agent accepts to be killed by another. +(implemented only in Centralised infrastructure)

    +
  • +
  • +

    performance improvement for pool of threads

    +
  • +
  • +

    some kqmlPlans (tell/achieve) are bypassed if not +customized by the user and not running in debug mode +to improve performance

    +
  • +
+
+
+

Bugs fixed +- unique id of Intention wasn’t thread safe +- indexedBB didn’t work on pool of threads

+
+
+
+
+

version 1.3.7 (2012-04-19)

+
+
+

revision 1687 on SVN

+
+
+

New features

+
+
+
    +
  • +

    Initial implementation of Cyclic Terms

    +
  • +
  • +

    JaCaMo infrastructure (in beta)

    +
  • +
+
+
+

Bugs fixed +- the expression "1 - 1 - 1" is evaluated as 1 instead of -1

+
+
+

Other changes +- support for SACI is removed, users that still use this platform + should not upgrade to this version

+
+
+
+
+

version 1.3.6a (2011-11-10)

+
+
+

revision 1668 on SVN

+
+
+

New features

+
+
+

Bugs fixed +- real numbers cannot be used in mas2j. +- jade architecture not visible for other classes

+
+
+
+
+

version 1.3.6 (2011-09-12)

+
+
+

revision 1659 on SVN

+
+
+

New features

+
+
+
    +
  • +

    several architectures can be defined for an agent +(e.g. Cartago and FailurePerception)

    +
  • +
+
+
+

Bugs fixed

+
+
+
    +
  • +

    .send ask with multiple receivers (in a variable ground to a list) doesn’t work

    +
  • +
  • +

    JADE infrastructure does not start the agents when used with jEdit plugin

    +
  • +
+
+
+
+
+

version 1.3.5 (2011-08-23)

+
+
+

revision 1656 on SVN

+
+
+

New features

+
+
+
    +
  • +

    new option to start up mind inspector for agents in non-debug mode.

    +
  • +
  • +

    new option to store mind samples in files +(see debug section in FAQ for more information)

    +
  • +
  • +

    synchronous ask can have several receivers, the answers in +this case is a list of all replies.

    +
  • +
  • +

    backtracking for .intend and .desire

    +
  • +
+
+
+

Bugs fixed

+
+
+
    +
  • +

    cartago + jade does not work together

    +
  • +
  • +

    execution control deadlock

    +
  • +
+
+
+
+
+

version 1.3.4 (2010-11-19)

+
+
+

revision 1628 on SVN

+
+
+

New example

+
+
+
    +
  • +

    wumpus (inspired by Russel & Norvig book)

    +
  • +
+
+
+

New features

+
+
+
    +
  • +

    creation of Ant scripts to help the running of JADE agents +in a distributed configuration. See demos/distributed-jade +for examples and the FAQ for more details.

    +
  • +
  • +

    possibility to customize the sniffer.properties of JADE

    +
  • +
  • +

    new function to compute standard deviation

    +
  • +
  • +

    new internal action setof

    +
  • +
  • +

    two new arguments in options to create agents in the .masj2 +project: initial beliefs and goals. For example, in the project

    +
  • +
+
+
+
+
    agents:
+        bob   ag.asl [beliefs="b(20),rec(alice)",goals="g(1),g(2)"];
+        alice ag.asl [beliefs="b(20),rec(bob)"];
+
+
+
+

both agents has the same source code. They differ in the initial + beliefs and goals, which are defined in the projects instead of the + agent’s code (ag.asl).

+
+
+

Bugs fixed

+
+
+
    +
  • +

    atomic plans that fail aren’t removed from the intention set.

    +
  • +
  • +

    succeed_goal doesn’t consider the case where several goals exist

    +
  • +
  • +

    backtrack on annotations doesn’t work with tail as in p[A|R]

    +
  • +
+
+
+

Other changes

+
+
+
    +
  • +

    JADE is updated to 4.0.1

    +
  • +
+
+
+
+
+

version 1.3.3 (2010-07-09)

+
+
+

revision 1603 on SVN

+
+
+

New features

+
+
+

Creation of meta events for goal state change. Goal states are:

+
+
+
    +
  • +

    started: the goal has been started, e.g. !g in a plan

    +
  • +
  • +

    finished: the goal has been achieved, e.g. a plan for !g has finished

    +
  • +
  • +

    failed: the goal has failed

    +
  • +
  • +

    suspended: the goal has been suspended by .suspend, .wait, and action, …​

    +
  • +
  • +

    resumed: the goal has been resumed by .resume

    +
  • +
+
+
+

The syntax for meta-events is

+
+
+
+
^<goal type><goal literal>[state(<s>)]
+
+
+
+

where <goal type> is ! or ? and <s> is one of the above states

+
+
+

These events can than be handled by plans such as

+
+
+
+
^!goto(X,Y)[state(S)] <- .print("goto state is ",S).
+
+
+
+

for the state suspended, another annotation contains the suspension reason (.wait, .suspend, …​)

+
+
+
+
^!goto(X,Y)[state(S)[reason(R)]]
+   <- .print("goto state is ",S," due to ",R).
+
+
+
+

see demos/meta-events for an example

+
+
+
+
+

version 1.3.2 (2010-03-06)

+
+
+

revision 1586 on SVN

+
+
+

New features

+
+
+
    +
  • +

    backtracking on annotations +(and literal’s annotations are sorted)

    +
  • +
+
+
+

API changes

+
+
+
    +
  • +

    a new listener can be added in TS to be notified about +changes in goals state (there are methods for created, +suspended, resumed, finished, and failed goals) +(see new class GoalListener)

    +
  • +
+
+
+

Changes in the syntax

+
+
+
    +
  • +

    syntax of if/while/for statements are now like C/Java:

    +
  • +
+
+
+
+
      if ( X > 3) {
+           bla;
+      } else {
+           bla;
+      }
+
+
+
+

";" is not required after "}" and the + last formula in <then> can be followed by ";".

+
+
+

Bugs fixed

+
+
+
    +
  • +

    equals in ObjectTermImpl, as reported by Tim Cleaver in jason-bugs list

    +
  • +
  • +

    unnamed variables in some rules are not correctly replaced, +as reported by Tim Cleaver in jason-bugs list

    +
  • +
  • +

    "E+1" is parsed as <exponent> instead of arithmetic expression

    +
  • +
  • +

    .relevant_plan with meta-variable plans as reported by Iain Wallance

    +
  • +
+
+
+
+
+

version 1.3.1 (2009-09-10)

+
+
+

revision 1553 on SVN

+
+
+

New demo

+
+
+
    +
  • +

    use of controllers to write a customised mind inspector

    +
  • +
+
+
+

Internal actions

+
+
+
    +
  • +

    .random has an optional second parameter to setup backtrack

    +
  • +
+
+
+

Bugs fixed

+
+
+
    +
  • +

    foreach when no solution exists causes failure

    +
  • +
  • +

    perception of atoms cause failure with SACI

    +
  • +
  • +

    initialisation of TimeSteppedEnvironment (bug: waits for a first action to start)

    +
  • +
  • +

    .succeed_goal does not work when applied to 'itself' (the intention succeed itself)

    +
  • +
  • +

    !Var does no work correctly

    +
  • +
+
+
+
+
+

version 1.3 (2009-04-20)

+
+
+

revision 1489 on SVN

+
+
+

New features

+
+
+
    +
  • +

    Plans and Triggers can be used as terms when enclosed by { and }. This feature is used in the following internal actions

    +
    +
      +
    • +

      .relevant_plans, e.g. .relevant_plans({ !g(_) }, ListOfPlans)` instead of `.relevant_plans( "!g(_)" , ListOfPlans)

      +
    • +
    • +

      .add_plan

      +
    • +
    • +

      .at

      +
    • +
    • +

      .wait

      +
      +

      It may be used in send tellHow .send(bob, tellHow, { +te : c ← a1 }). It is also used by internal actions that 'return' plans, like .plan_label, .relevant_plans, and .current_intention

      +
      +
      +

      The advantages are that unification works

      +
      +
      +
      +
      .at("now +1 m", {+stop(ID)})
      +
      +
      +
      +

      and syntax errors are detected at compilation time

      +
      +
      +

      The old style (with strings) continues to work.

      +
      +
      +

      More complex meta-programming is also possible:

      +
      +
      +
      +
      !myadd( { .print(a); .print(b) } ) ....
      +// pass the body of the plan as parameter to !myadd
      ++!myadd(Action)
      +   <- .add_plan( {+!g : c & b <- Action} ).
      +   // add a plan with a fixed event/context and body
      +   // given as a parameter
      +
      +
      +
    • +
    +
    +
  • +
  • +

    The performance is improved (+- 15%) by not cloning all the plan in the creation of intended means

    +
  • +
+
+
+

Changes in the GUI

+
+
+
    +
  • +

    When closing the window of MAS Console, the application is also stopped.

    +
  • +
+
+
+

Changes in communication

+
+
+
    +
  • +

    for messages sent to itself, the sender is 'self' now, +and not the agent’s name as in previous releases

    +
  • +
+
+
+

New internal actions

+
+
+
    +
  • +

    .puts: used for printing messages to the console (based on Ruby similar method). Developed by Felipe Meneguzzi.

    +
  • +
  • +

    .all_names: get the name of all agentes in the system.

    +
  • +
  • +

    .list_plans: print out the plans of agent’s plan library

    +
  • +
  • +

    .prefix, .suffix and .sublist: see comments in the API doc, as their implementation is currently generates slightly different results from their usual implementation in logic programming.

    +
  • +
+
+
+

Changes in internal actions

+
+
+
    +
  • +

    .relevant_plans has a third argument that gets the labels +of the plans

    +
  • +
  • +

    .create_agent and .kill_agent accept strings for the agents' name

    +
  • +
+
+
+

New example

+
+
+
    +
  • +

    Blocks World

    +
  • +
+
+
+

Bugs fixed

+
+
+
    +
  • +

    arithmetic expressions are considered as Literal, causing +failures in unification

    +
  • +
  • +

    variable unified with atom cannot be added in BB, as in +X = p; +X;

    +
  • +
  • +

    The third argument of .create_agent (list of options) can +not be used.

    +
  • +
  • +

    Some concurrent execution of .wait and .drop_desire/intention +does not work (the intention isn’t dropped)

    +
  • +
  • +

    send askHow with 4th argument blocks the intention

    +
  • +
  • +

    TimeSteepedEnvironment wait timeout when it is not required to wait

    +
  • +
+
+
+
+
+

version 1.2 (2009-01-06)

+
+
+

the 5th Anniversary Release

+
+
+

revision 1428 on SVN

+
+
+

New features

+
+
+
    +
  • +

    customised belief bases can be organised in a chain so +that several functionalities can be composed. For more +information see the demo/chain-bb and API doc of ChainBB and ChainBBAdapter.

    +
  • +
  • +

    annotations in failure events. All failure events are now annotated with:

    +
    +
    +
    error(<atom: error id>)
    +
    +
    +
    +

    the identification of the type of error, values used by Jason are:

    +
    +
    +
      +
    • +

      no_applicable: no applicable plan

      +
    • +
    • +

      no_relevant: no relevant plan

      +
    • +
    • +

      no_option: no option selected

      +
    • +
    • +

      constraint_failed: constraint (i.e., a logic expression in the plan body) failed

      +
    • +
    • +

      ia_failed: internal action returned false

      +
    • +
    • +

      action_failed: environment action failed

      +
    • +
    • +

      ask_failed: answer to an ask message failed (due to timeout)

      +
    • +
    • +

      wrong_arguments: wrong arguments (type and/or number) passed to an internal action

      +
      +

      Other annotations:

      +
      +
    • +
    • +

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

      +
    • +
    • +

      code(<literal>): the part of the plan body where the failure occurred

      +
    • +
    • +

      code_src(<string>): the file where the failure was

      +
    • +
    • +

      code_line(<int>): the line in that file

      +
      +

      see demo/failure for an example, FAQ for more details, and code of JasonException and TS for more information

      +
      +
    • +
    +
    +
  • +
  • +

    the version of JADE is upgraded to 3.6

    +
  • +
  • +

    new base class for internal actions: ConcurrentInternalAction. This +class can be used in place of DefaultInternalAction to create an IA +that suspends the intention while it is being executed. For example, +if DefaultInternalAction is used for an action that requires user +input, the agent’s thread is blocked until an answer is given by the +user. With ConcurrentInternalAction, only the intention using the IA +is suspended. See demos/gui/gui1 and the API doc of this new class.

    +
  • +
  • +

    API doc uses UMLGraph to show relations between classes

    +
  • +
+
+
+

New demo

+
+
+
    +
  • +

    java-object-terms: shows how variables may be unified to Java objects

    +
  • +
+
+
+

New internal actions

+
+
+
    +
  • +

    .term2string: transforms a term into a string and vice-versa

    +
  • +
+
+
+

New functions

+
+
+
    +
  • +

    .math.sum: sums a list of numbers

    +
  • +
  • +

    .math.average: returns the average of a list of numbers (renamed to math.mean in jason 3.3)

    +
  • +
+
+
+

API changes

+
+
+
    +
  • +

    the most significant change is in the Literal class, which is now abstract. To create a new literal, the previous method

    +
    +
    +
    Literal.parseLiteral(....)
    +
    +
    +
    +

    still works, but

    +
    +
    +
    +
    new Literal(...)
    +
    +
    +
    +

    has to be written as

    +
    +
    +
    +
    ASSyntax.createLiteral(....)
    +
    +
    +
    +

    the ASSyntax factory is the preferred approach for the creation of all types of terms.

    +
    +
  • +
+
+
+
+
+

version 1.1.2 (2008-07-06)

+
+
+

New features

+
+
+
    +
  1. +

    (experimental) control of the execution in plan bodies with if, while, and for.

    +
    +
    +
    --- if ----
    +syntax:
    +
    +
    +
    +
    +
    if ( <logical formula> ) {
    +   <plan_body1>
    +[ } else { <plan_body2> ]
    +};
    +
    +
    +
  2. +
+
+
+

if <logical formula> holds, <plan_body1> is executed; otherwise, + <plan_body2> is executed.

+
+
+
+
if (vl(X) & X > 10 & X < 20) { // where vl(X) is a belief
+         .print("value > 10 and ");
+         .print("value < 20")
+}
+
+
+
+
+
--- while ---
+syntax:
+
+
+
+
+
while ( <logical formula> ) {
+  <plan_body>
+};
+
+
+
+

while <logical formula> holds, the <plan_body> is executed.

+
+
+
+
while (vl(X) & X > 10) {
+         -+vl(X+1)
+}
+
+
+
+
+
--- for ---
+syntax:
+
+
+
+
+
for ( <logical formula> ) {
+  <plan_body>
+};
+
+
+
+

the <plan_body> is executed for all unifications of <logical formula>.

+
+
+
+
for ( vl(X) ) {
+        .print(X)
+};
+for ( .member(X,[a,b,c]) ) {
+        .print(X)
+};
+for ( .range(I,1,10) ) {
+         .print(I)    // print all values from 1 to 10
+};
+
+
+
+

New examples and demos:

+
+
+
    +
  1. +

    demos/gui: two simple examples of how to make a GUI for individual agents

    +
  2. +
  3. +

    example/food-simulation: implementation of the scenario of simulation presented in http://jasss.soc.surrey.ac.uk/1/3/3.html

    +
  4. +
+
+
+

Bugs fixed:

+
+
+
    +
  1. +

    BUF didn’t add annotation "source(percept)" in the perception deletion event

    +
  2. +
  3. +

    drop_desire did not remove desires in Circumstance.Event correctly +when annotations are used

    +
  4. +
  5. +

    print worked like println

    +
  6. +
  7. +

    problem in =.. with atoms

    +
  8. +
  9. +

    problem in unification when unbound vars were used as arguments +for rules (as identified by Stephen Cranefield)

    +
  10. +
+
+
+
+
+

version 1.1.1 (2008-04-21)

+
+
+

New features

+
+
+
    +
  1. +

    Terms can be body plans enclosed by "{ …​ }", as in the following +example: + test({ a1; !g; ?b(X); .print(X) }, 10)

    +
  2. +
+
+
+

Bugs fixed:

+
+
+
    +
  1. +

    unification in return of ! and ?

    +
  2. +
  3. +

    use nested source annotations in communication

    +
  4. +
  5. +

    add "source(self)" in goals without source

    +
  6. +
  7. +

    correctly handle failure event caused by no relevant plans

    +
  8. +
  9. +

    timeout in .wait does not cause a runtime exception

    +
  10. +
+
+
+
+
+

version 1.1.0 (2008-04-08)

+
+
+

New features

+
+
+
    +
  1. +

    Performance improvements: in general, applications run 30% faster.

    +
  2. +
  3. +

    Arithmetic functions: math.abs, math.max, …​ +see doc/index.html and demo/function for more information

    +
  4. +
  5. +

    Compiler warns about "singleton variables" in plans and rules +(see plugin options to disable this feature). If you don’t use +anonymous variables for logical variables whose contents will +not be used, you may want to disable this feature.

    +
  6. +
  7. +

    Terms can be logical expressions, as in the following +example of .findall usage: + .findall(X, (a(X) & X > 10), L)

    +
  8. +
  9. +

    A list of goals can be sent with the "achieve" performative: + .send(bob,achieve,[g1,g2,g3]) +Note that each goal will become a separate intention of bob +(if the message is accepted).

    +
  10. +
+
+
+

New example:

+
+
+
    +
  1. +

    the Jason team used in the Agent Contest 2007 was added to the +examples (folder gold-miners-II)

    +
  2. +
  3. +

    a GUI was added to the IPD example

    +
  4. +
+
+
+

New demo:

+
+
+
    +
  1. +

    function: shows how to create new arithmetic functions.

    +
  2. +
+
+
+

New internal actions:

+
+
+
    +
  1. +

    .reverse: reverse the order of lists and strings.

    +
  2. +
  3. +

    .union, .intersection and .difference of sets.

    +
  4. +
+
+
+

Bugs fixed:

+
+
+
    +
  1. +

    the internal action .concat did not clone the lists properly

    +
  2. +
  3. +

    +?b(X) plans did not "return" the X value (bug in 1.0.1 only)

    +
  4. +
  5. +

    +!A used to catch events of the form +p

    +
  6. +
  7. +

    JDBC belief base did not work with null values

    +
  8. +
  9. +

    The MAS did not stop running when the "stop" button is pressed

    +
  10. +
  11. +

    The parser allowed mixing initial beliefs and goals with plans.

    +
  12. +
+
+
+
+
+

version 1.0.1 (2007-12-09)

+
+
+

New features

+
+
+
    +
  1. +

    a new entry is added in the mas2j project: aslSourcePath. This entry +allows the developer to set where the runtime will search for AgentSpeak +sources. E.g:

    +
    +
    +
    MAS ts {
    +  agents: a; b; c;
    +  aslSourcePath: "."; "src/asl"; "kk";
    +}
    +
    +
    +
    +

    search the sources of agents a, b, and c in the paths "." (current path), + "src/asl", and "kk". + The default value is the project’s directory.

    +
    +
  2. +
  3. +

    a preliminary version of an eclipse plugin (http://jasonplugin.wikidot.com)

    +
  4. +
+
+
+

New documentation

+
+
+
    +
  1. +

    A getting started with Jason (see doc/index.html)

    +
  2. +
  3. +

    A mini-tutorial of interoperability between Jason and JADE (see doc/index.html)

    +
  4. +
+
+
+

New Demo

+
+
+
    +
  1. +

    demo/sync-environment shows how to use the SteppedEnvironment. +This environment has steps where each agent can perform only one action. +When all agents have asked for the execution of an action, the actions +are really executed, the perception is updated and the next step starts. +The game-of-live example is also updated to use this kind of +environment.

    +
  2. +
+
+
+

New internal actions

+
+
+
    +
  1. +

    .suspend and .resume were moved from the example to the standard library. +They can thus be used in any Jason application.

    +
  2. +
  3. +

    .delete to remove elements from lists or strings

    +
  4. +
+
+
+

Bugs fixed

+
+
+
    +
  1. +

    clone example

    +
  2. +
  3. +

    use-only-jason-bdi example

    +
  4. +
  5. +

    the save files when opening a new project locks the jEdit

    +
  6. +
  7. +

    parser accepts initial goals and beliefs mixed with plans

    +
  8. +
+
+
+
+
+

version 1.0 (2007-08-22)

+
+
+

Jason v 1.0 is used in the book +'Programming Multi-Agent Systems in AgentSpeak using Jason'

+
+
+

New feature +. the centralised infrastructure can use a thread pool instead of + one thread by agent. It is useful to run thousand of agents. + See demo/big and examples/game-of-life for more details.

+
+
+

New Demo: +. demo/clone shows how an agent can create a clone of itself.

+
+
+
+
+

version 0.9.7 (2007-08-22)

+
+
+

New features:

+
+
+
    +
  1. +

    First (experimental) version of JADE infrastructure +(see FAQ for details)

    +
  2. +
  3. +

    Mind inspector has "bi-directional" debug and other improvements.

    +
  4. +
+
+
+

New example:

+
+
+
    +
  1. +

    iterated-prisoners-dilemma

    +
  2. +
+
+
+

New Demos:

+
+
+
    +
  1. +

    tell-rule: implements a new performative to tell rules like a :- b & c. to other agents.

    +
  2. +
  3. +

    suspend-resume: implements two useful internal actions: one to +suspend intentions and other to resume them.

    +
  4. +
+
+
+

Bugs fixed:

+
+
+
    +
  1. +

    JavaWebStart of Jason applications in windows.

    +
  2. +
+
+
+

Changes:

+
+
+
    +
  1. +

    new beliefs are added before the others in the belief base.

    +
  2. +
  3. +

    asynchronous acting in centralised infrastructure.

    +
  4. +
+
+
+
+
+

version 0.9.6 (2007-05-10)

+
+
+

New features

+
+
+
    +
  1. +

    test goal now can also have expressions, as in: ++e : true ← …​ ?(a & b | d); …​ + unlike simple test goals, the event +? will not be generated + in case the test fails. As before, simple expressions that make + no reference to the belief base don’t need to be in a test goal.

    +
  2. +
  3. +

    when an error occurs during the execution of a plan, +the corresponding line in the source code is shown +in the console.

    +
  4. +
  5. +

    the build.xml file created for each Jason application has two +new tasks: +"jar": creates an executable jar for the application +"jnlp": creates a JavaWebStart application

    +
  6. +
+
+
+

New internal actions

+
+
+
    +
  1. +

    min(<list>,<term>) gets the minimum value from the list.

    +
  2. +
  3. +

    max(<list>,<term>) gets the maximum value from the list.

    +
  4. +
  5. +

    .drop_event(D) removes the event +!D from the set of events

    +
  6. +
+
+
+

Changes in internal actions

+
+
+
    +
  1. +

    .drop_desire(D) also removes the intentions related to +!D.

    +
  2. +
  3. +

    .drop_all_desires also removes all intentions.

    +
  4. +
+
+
+

Bugs fixed

+
+
+
    +
  1. +

    broadcast did not work with SACI.

    +
  2. +
  3. +

    persistent BB in text files did not work

    +
  4. +
  5. +

    strong negation was not shown in the mind inspector

    +
  6. +
  7. +

    initial beliefs with negative arguments were not shown in the mind inspector

    +
  8. +
+
+
+
+
+

version 0.9.5 (2007-03-07)

+
+
+

New features

+
+
+
    +
  1. +

    Users can define their own compiler directives. A directive can, for +instance, change a set of plans to add a command in the end of all +plans. See the new example "directives" for more information.

    +
  2. +
  3. +

    Asynchronous ask in communication. When the internal action .send with +an ask performative does not have the fourth argument, it does not suspend +the intention. The answer is added to the sender’s belief base.

    +
  4. +
+
+
+

Changes in AgentSpeak semantics

+
+
+
    +
  1. +

    "-b" in a plan removes "b[source(self)]" from the Belief Base and +not b with its all annotations. However, the source(self) annotation +is added only in case b has no annots. For -b[a], the "self" source is +not added and only annotation "a" is removed.

    +
  2. +
+
+
+

Changes in internal actions

+
+
+
    +
  1. +

    Many internal actions were renamed to follow a Prolog pattern. E.g., +addPlan → add_plan, createAgent → create_agent.

    +
  2. +
  3. +

    .drop_desire does not produce events anymore, it just removes the +event from the circumstance.

    +
  4. +
  5. +

    uses of .dropGoal(g,true) should be replaced by .succeed_goal(g).

    +
  6. +
  7. +

    uses of .dropGoal(g,false) should be replaced by .fail_goal(g).

    +
  8. +
  9. +

    new internal action .nth to select some term of a list.

    +
  10. +
+
+
+

Documentation

+
+
+
    +
  1. +

    all internal actions were documented using javadoc (see doc/api).

    +
  2. +
+
+
+

Bugs fixed in 0.9.5b

+
+
+
    +
  1. +

    The date in the application build.xml use latin characters.

    +
  2. +
  3. +

    The variable name in the KQML plans may conflict with users' +variables.

    +
  4. +
  5. +

    .sort changes the first parameter.

    +
  6. +
  7. +

    the include directive can not be used before initial beliefs.

    +
  8. +
+
+
+
+
+

version 0.9.4 (2006-12-01)

+
+
+

New features

+
+
+
    +
  1. +

    The user can define class paths for Jason projects, see the Sniffer +project file (Sniffer.mas2j) for an example.

    +
  2. +
+
+
+

Examples:

+
+
+
    +
  1. +

    Add support form message sniffing in centralised infrastructure +and improve the Sniffer example to use it (and also store all +messages in a data base)

    +
  2. +
  3. +

    Improve the wandering capabilities in the Gold-Miners example.

    +
  4. +
+
+
+

Changes in the API

+
+
+
    +
  1. +

    The TermImpl was renamed to Structure

    +
  2. +
  3. +

    The method that executes actions in the environment is not +executeAction(String agName, Term act) + anymore, but was changed to + executeAction(String agName, Structure act) + So you should change your environment method parameters to + work with this version.

    +
  4. +
+
+
+

Bugs fixed:

+
+
+
    +
  1. +

    unification of variable in annotations

    +
  2. +
+
+
+
+
+

version 0.9.3 (2006-10-09)

+
+
+

New features

+
+
+
    +
  1. +

    an event +!idle is generated when the agent has nothing to do +(no other event, no intention, no message, …​.)

    +
  2. +
  3. +

    Mind inspector can show the agent state in LaTeX

    +
  4. +
  5. +

    New commands: asl2html and asl2tex

    +
  6. +
  7. +

    We add some useful classes to develop grid based environments. +There is a class to model (maintain the data) the scenario and +another class to draw it in the screen. The examples CleaningRobots, +DomesticRobot, and Gold-Miners use these classes. More information +is available in these examples and in the API of package +import jason.environment.grid

    +
  8. +
  9. +

    goal patterns as proposed in DALT 2006 paper:

    +
  10. +
  11. +

    Backtracking Declarative Goal

    +
  12. +
  13. +

    Blind Commitment Goal

    +
  14. +
  15. +

    Open-Minded Commitment

    +
  16. +
  17. +

    Maintenance Goal

    +
  18. +
  19. +

    Relativised Commitment Goal

    +
  20. +
  21. +

    and others

    +
  22. +
+
+
+

New examples

+
+
+
    +
  1. +

    Sniffer: shows how to get all messages sent by the agents.

    +
  2. +
  3. +

    ContractNetProtocol: shows how the CNP may be implemented with Jason

    +
  4. +
+
+
+

New internal action:

+
+
+
    +
  1. +

    dropGoal(<goal>,[true|false]): the implementation of the +.dropGoal as specified in DALT 2006 paper. All intentions +with goal <goal> will be popped until the <goal> intended means (im). +If the second parameter is true, the IM is considered successfully +finished. Otherwise, the IM fails.

    +
  2. +
  3. +

    member(<element>, <list>), verify whether <element> belong to the +<list>. this internal action backtracks when there are more than +one answer, as in + .member(X, [4,1,6]) +which has 3 results.

    +
  4. +
  5. +

    planLabel(<plan>, <label>), gets the string of a plan based on its +label (useful for tellHow). E.g.: + @test +!g : true ← act. + …​. + ← .planLabel(P, test); + .send(ag,tellHow,P).

    +
  6. +
  7. +

    structure(X): verify whether X is a structure (see API doc)

    +
  8. +
  9. +

    atom(X): verify whether X is an atom (see API doc)

    +
  10. +
+
+
+

Changes in the communication

+
+
+
    +
  1. +

    performative ask is changed to askOne

    +
  2. +
  3. +

    the event for messages is now +!kqmlReceived (and not +!received)

    +
  4. +
  5. +

    send ask can have an 5th parameter: timeout. +E.g. .send(ag,askOne,vl(X),Answer,3000) +will wait the answer for 3 seconds. If ag will not respond, +Answer will unify with "timeout".

    +
  6. +
+
+
+

Changes in the API

+
+
+
    +
  1. +

    The interface of internal actions changed. The execute method returns +an Object, and not a boolean anymore, and the class may extends +DefaultInternalAction (see the API for more information). +For example:

    +
    +
    +
    public class myIA extends DefaultInternalAction {
    +   public Object execute(TransitionSystem ts, Unifier un, Term[] args) throws Exception {
    +  ....
    +     return true;
    +}  }
    +
    +
    +
  2. +
+
+
+
+
+

version 0.9.2 (2006-08-21)

+
+
+

New internal action:

+
+
+
    +
  1. +

    count(<bel>,<var>): count the number of beliefs that match +<bel>.

    +
  2. +
+
+
+

New examples:

+
+
+
    +
  1. +

    SimpleCommunication: briefly shows how to send and receive +messages.

    +
  2. +
  3. +

    DomesticRobot: it is an improved version of the previous House robot.

    +
  4. +
+
+
+

Bugs fixes:

+
+
+
    +
  1. +

    performative ask does not work properly.

    +
  2. +
+
+
+
+
+

version 0.9.1 (2006-08-11)

+
+
+

New internal actions:

+
+
+
    +
  1. +

    random(X): unifies X with a random value from 0 to 1.

    +
  2. +
  3. +

    date(YY,MM,DD): gets the current date

    +
  4. +
  5. +

    time(HH,MM,SS): gets the current time

    +
  6. +
  7. +

    var(X), string(X), number(X), ground(X), list(X): +verify whether X is a var, string, number, ground, or list.

    +
  8. +
+
+
+

Bugs fixed:

+
+
+
    +
  1. +

    Jason 0.9.1 correctly stops the running project (in windows). +In Jason 0.9 some java.exe processes do not finish properly.

    +
  2. +
+
+
+
+
+

version 0.9 (2006-07-14)

+
+
+

This version requires java 1.5.

+
+
+

New features:

+
+
+
    +
  1. +

    Belief Base (BB) can be customised. There are two available +customisations: one that stores the beliefs in a text file and +another that stores them in a relational DB. This latter +customisation can also be used the access any other +relational DB (via JDBC). The AgentSpeak code remains the +same regardless of the BB customisation. +See the "persistentBelBase" example for more information.

    +
  2. +
+
+
+

Changes in the AgentSpeak syntax

+
+
+
    +
  1. +

    there can be initial goals in the source code, e.g.: +bel(a). +!initgoal. ++!initgoal : …​. ← …​.

    +
  2. +
  3. +

    belief base can have simple (prolog-like) inferences rules, e.g.: +a(10). +a(20). +b(20). +c(X) :- a(X) & b(X).

    +
  4. +
  5. +

    or (represented by "|") is allowed in plans' context, e.g.: + +e : a | b ← …​. + +e : a & not(b | c) ← …​. +Disjunction is also possible in the inference rules in the belief base.

    +
  6. +
  7. +

    'true' context or plans can be omitted. e.g.: + +e : c ← true. + +e : true ← !g. + +!e : true ← true. + can be written as + +e : c. ++e ← !g. ++!e.

    +
  8. +
  9. +

    new operator "-+", which can appear in a plan body, adds a belief +after removing (the first) existing occurrence of that belief in the +belief base, e.g.: + -+a(X+1) +removes a(_) from and adds a(X+1) to the belief base.

    +
  10. +
  11. +

    new plan annotation: "all_unifs". When a plan’s label has this +annotation the list of applicable plans will include all possible +unifications (the same plan can lead to more than one Option), e.g.: + a(10). + a(20). + @l[all_unifs] !g : a(X) <- print(X). +"!g" has two options, one where X=10 and another where X=20.

    +
  12. +
  13. +

    the arithmetic operator % was renamed to "mod"

    +
  14. +
+
+
+

Changes in .mas2j file

+
+
+
    +
  1. +

    the environment class can receive parameters from the .mas2j file. +e.g. in a mas2j file: + …​ + environment: myenv(1,"a b c",vl) + …​ +the environment implementation will receive these parameters +in the init method: + public void init(String[] args) { …​ }

    +
  2. +
+
+
+

Changes in the API

+
+
+
    +
  1. +

    the BRF method, in the "Agent" class, was renamed to BUF (Belief Update +Function). A new BRF method was added for belief revision rather +than update. +While BUF is called to update the BB when percepts are obtained, BRF +is called for `', `-', and `-' operators (those used in AS plans). +Note that certain custmosations of BRF may require that BUF is +customised to use BRF for the actual changes in the BB.

    +
  2. +
+
+
+

Other changes

+
+
+
    +
  1. +

    the "src/templates" folders contains all sources used by the JasonIDE +to create new files (e.g., when users request a new agent or a new +project to be created).

    +
  2. +
  3. +

    new internal action ".length(<string>|<list>, <size>)": gets the size +of a list or string

    +
  4. +
  5. +

    new internal action ".abolish(<literal>)": remove all ocurrences of a +literal from BB

    +
  6. +
  7. +

    Performatives "askOne" and "askIf" are new "ask".

    +
  8. +
  9. +

    Events generated from received KQML messages are not "received(....)", but +"!received(…​)".

    +
  10. +
+
+
+
+
+

version 0.8 (2006-05-02)

+
+
+

New features

+
+
+
    +
  1. +

    Jason is now a jEdit (www.jedit.org) plugin.

    +
  2. +
  3. +

    Jason was prepared for new infrastructures (Jade, MadKit, …​) +To create a new infrastructure, you shoud add an infrastrucure Factory +in .jason/user.properties file and implement some classes. +See jason.infra.centralised and jason.infra.saci packages as examples.

    +
  4. +
  5. +

    AS syntax was changed to support include directive, +e.g. in an AS file:

    +
    +
      +
    1. +

      plans …​. +{ include("anotherfile.asl") }

      +
    2. +
    3. +

      more plans …​.

      +
    4. +
    +
    +
  6. +
  7. +

    new internal action wait, e.g. in an AS file: +a : true <- .wait(1000). // waits 1 second ++a : true <- .wait("!x"). // waits an event

    +
  8. +
  9. +

    new internal action sort, e.g. in an AS file:

    +
    +
      +
    1. +

      .sort([b,c,g,casa,f(10),[3,4],[3,1],f(4)],L); …​ +L is [b,c,casa,f(4),f(10),g,[3,1],[3,4]]

      +
    2. +
    +
    +
  10. +
+
+
+

Changes in .mas2j file

+
+
+
    +
  1. +

    The user can inform its own parameters in the agent declaration, e.g.:

    +
    +
      +
    1. +

      agents: ag1 [verbose=2,file="a.xml",value=45]; +These extra parameters are stored in the Settings class and can be +consulted in the programmer classes by getUserParameter method, +for example, + ts.getSettings().getUserParameter("file");

      +
    2. +
    +
    +
  2. +
+
+
+

Changes in ASL syntax

+
+
+
    +
  1. +

    the unnamed variable ("_") is added

    +
  2. +
  3. +

    annotations are an AS list, so it is possible constructions like +p(t)[a,b,c] = p(t)[b|R] (R is [a,c])

    +
  4. +
  5. +

    variables can have annotations, e.g. + X[a,b,c] = p[a,b,c,d] (unifies and X is p) + p[a,b] = X[a,b,c] (unifies and X is p) + X[a,b] = p[a] (do not unify) + p[a,b] = X[a] (do not unify) +e.g in a plan + +te : X[source(ag1)] ← do(X).

    +
  6. +
  7. +

    plans' trigger event can be a variable, e.g. ++!X[source(S)] : not friend(S) ← .send(S, tell, no).

    +
  8. +
  9. +

    new operator =.. used to (de)construct literals, syntax: + <literal> =.. <list> +where <list> is [<functor>, <list of terms>, <list of annots>] +e.g. + p(t1,t2)[a1,a2] =.. L (L is [p,[t1,t2],[a1,a2]]) + X =.. [p,[t1,t2],[a1,a2]] (X is p(t1,t2)[a1,a2])

    +
  10. +
  11. +

    new operator "!!": sub-goal with new focus

    +
  12. +
  13. +

    new operator "div": integer division

    +
  14. +
+
+
+

Changes in the agent architecture customisation

+
+
+
    +
  1. +

    In this version, the user extends AgArch class instead of Centralised +or Saci architectures. Thus, the same architecture +customisation can be used in both infrastructures.

    +
  2. +
+
+
+

Other changes

+
+
+
    +
  1. +

    The Java logging API is used to output the execution. +The default log configuration is in the +src/logging.properties file. The user can copy this file to its +project directory to customise the output format.

    +
  2. +
  3. +

    The internalAction removePlan use plan’s label as argument instead of +plan’s strings.

    +
  4. +
  5. +

    Ant is used to run the MAS, for each project a build.xml file is +created. The build template file is located in src/xml directory. +If the project has a file called c-build.xml, the build.xml file +is not created and this script is used instead.

    +
  6. +
+
+
+
+
+

version 0.7 (2005-08-18)

+
+
+

New features

+
+
+
    +
  1. +

    atomic execution of intention. When an intention is created from +a plan with a label that has an 'atomic' annotation + @label[atomic] +…​. : …​. ← …​. +this intention has highest priority, no other intention will be selected +until this one was finished.

    +
  2. +
  3. +

    breakpoint annotation in plans' label

    +
  4. +
  5. +

    editor syntax highlight for AS/MAS2J

    +
  6. +
  7. +

    online parsing on editing

    +
  8. +
  9. +

    number of cycles until perception (see manual)

    +
  10. +
  11. +

    new AS grammar that supports expressions, e.g. ++b : true : X = 4; Y = X + 3 * X / 2; …​

    +
  12. +
  13. +

    jar files in the application lib directory are automatically added in the +classpath

    +
  14. +
+
+
+

Changes in the Environment programming

+
+
+
    +
  1. +

    Each agent has its own perception list in version 0.7. +In the application Environment class, the user can change these lists by +calling

    +
  2. +
  3. +

    addPercept(P): add perception P in the perception of all agents;

    +
  4. +
  5. +

    addPercept(A,P): add perception P only in the agent A’s perception.

    +
  6. +
  7. +

    removePercept(P): …​

    +
  8. +
  9. +

    removePercept(A,P): …​ +The method getPercepts(A) returns the perceptions for agent A. +See Environment javadoc API for more information.

    +
  10. +
  11. +

    Perception is now a list of Literals, thus there is not anymore a +positive and a negative list of Predicates.

    +
    +
    +
    a code like
    +  getPercepts().add(Term.parse("p(a)"));
    +should now be written as
    +  addPercept(Literal.parseLiteral("p(a)"));
    +
    +
    +
    +
    +
    and a code like
    +  getNegativePercepts().add(Term.parse("p(a)"));
    +should now be written as
    +  addPercept(Literal.parseLiteral("~p(a)"));
    +
    +
    +
  12. +
+
+
+

Changes in Internal Actions

+
+
+
    +
  1. +

    Internal actions args are now terms and not Strings

    +
  2. +
  3. +

    Internal actions implements InternalAction interface

    +
  4. +
  5. +

    Each agent has its own IA objects — IA has a state for its agent

    +
  6. +
+
+
+

Other changes

+
+
+
    +
  1. +

    auto-save before running

    +
  2. +
  3. +

    brf() was moved to Agent class (and architecture perceive returns a List of perceptions)

    +
  4. +
  5. +

    The log4j is used to output the execution. The default log configuration is in the +src/log4j.configuration file. The user can copy this file to its project directory +to customise the output format. +See http://logging.apache.org/log4j/docs/ for more information.

    +
  6. +
  7. +

    environment is optional in mas2j

    +
  8. +
  9. +

    initial beliefs generate events like + operator.

    +
  10. +
+
+
+
+
+

version 0.6 (2005-02-28)

+
+
+

New features

+
+
+
    +
  1. +

    Two execution modes: async and sync (see doc/faq.html)

    +
  2. +
  3. +

    Debugging execution mode with "mind inspector" tool +(works both for centralised and distributed agents)

    +
  4. +
+
+
+

Agent Communication

+
+
+
    +
  1. +

    new implementation: all received messages create an event that +is handled by standard AS plans (see bin/resources/kqmlPlans.asl file)

    +
  2. +
  3. +

    acceptTell/Trust functions are replaced by socAcc (see manual)

    +
  4. +
+
+
+

Changes to AS syntax

+
+
+
    +
  1. +

    variables can be used where literals are expected, and a few +other changes (see manual)

    +
  2. +
+
+
+

Changes to .mas2j file syntax

+
+
+
    +
  1. +

    user can set a controller class (see grammar) and doc/faq

    +
  2. +
  3. +

    Environment.notifyEvents() was renamed to informAgsEnvironmentChanged()

    +
  4. +
  5. +

    default architecture is centralised, not Saci.

    +
  6. +
+
+
+

Changes in the API

+
+
+
    +
  1. +

    the classes was reorganised into new packages. + An User’s environment class + needs the following imports: +import jason.; +import jason.asSyntax.; +import jason.environment.*;

    +
  2. +
+
+
+

Other changes

+
+
+
    +
  1. +

    the ulibs dir. is not used anymore. The user classes should be +placed in his/her project directory (or in any directory in your CLASSPATH)

    +
  2. +
  3. +

    source annotation in predicates now have the form "[source(self)]" instead of +"[self]" (similarly for perception and other agents as sources).

    +
  4. +
  5. +

    Saci is included in the distribuion

    +
  6. +
+
+
+
+
+

version 0.5 (2004-11-22)

+
+
+

Changes at .mas2j file syntax +. the user can use java packages for his/her classes + (see examples/Simple)

+
+
+

Changes in agentSpeak syntax +. the plan context can use infix relational operators (<, ⇐, >, >=, ==, \==, = (unify)) + for example: + +p(X,Y) : X >= Y + ← !doSomeThing().

+
+
+
    +
  1. +

    the plan label must be prefixed by "@", e.g.: +@label +trigger : true ← action1; action2.

    +
  2. +
+
+
+

Changes in the API +. The jason packages was refactored. The user environment class imports + likely will need to be rewritten to: + import jason.asSyntax.; + import jason.environment.;

+
+
+
    +
  1. +

    Some methods' name has changed:

    +
  2. +
  3. +

    Term.parameter → Term.getTerm(i)

    +
  4. +
  5. +

    Term.funcSymb → Term.getFunctor()

    +
  6. +
+
+
+

A new internal action, .broadcast(<ilforce>,<content>), was added.

+
+
+
+
+

version 0.4 (2004-07-21)

+
+
+

The implementation of the user-defined environment class has been +changed so as to allow users to specify customised perception for +each individual agent.

+
+
+

Users who used old-style environment code such as:

+
+
+

public class marsEnv implements Environment { + <code1> + EnvironmentPerception envP = null; + public void setEnvironmentPerception(EnvironmentPerception ep) { + envP = ep; + <code2> + } + <code3> +}

+
+
+

should be changed to:

+
+
+

public class marsEnv extends Environment { + <code1> + public marsEnv() { + <code2> + } + <code3> +}

+
+
+

Briefly, the changes are as follows:

+
+
+
    +
  1. +

    The user’s environment class does not "implements Environment" +anymore, but "extends Environment". (See API documentation +for more information on this new class.)

    +
  2. +
  3. +

    The method setEnvironmentPerception, where the environment +initialisation was done, is replaced by the user environment +constructor.

    +
  4. +
  5. +

    To change the environment perception list use: +getPercepts().remove(g1); instead of +envP.getPercepts().remove(g1);

    +
  6. +
  7. +

    To send specific perceptions for an individual agent, override +the method getPercepts(agName); for example:

    +
    +
    +
    public class marsEnv extends Environment {
    +  ...
    +  public List getPercepts(String agName) {
    +    if (agName.equals(...)) {
    +      List customPercepts = new LinkedList(super.getPercepts(agName));
    +      customPercepts.add(...);
    +      customPercepts.remove(...);
    +      return customPercepts;
    +    } else {
    +      return super.getPerceps(agName);
    +    }
    +  }
    +  ...
    +}
    +
    +
    +
  8. +
+
+
+

The option "event=retrieve" was added. It makes the selectOption function be called even if there is not relevant plans.

+
+
+
+
+

version 0.3 (2004-04-12)

+
+
+

Jason now has an IDE! This version of Jason also runs on MS +Windows, if you must.

+
+
+
+
+

version 0.2 (2004-02-08)

+
+
+

First public release.

+
+
+

Agent and AgentArchitecture classes are only required if the user +needs to provide any customisation. The same environment code now +works for Saci and Centralised.

+
+
+
+
+

version 0.1 (2004-01-06)

+
+
+

The very first release of Jason!

+
+
+
+
+ + + \ No newline at end of file diff --git a/tech/Jason Operators and Events.pdf b/tech/Jason Operators and Events.pdf new file mode 100644 index 00000000..6ef6fd6f Binary files /dev/null and b/tech/Jason Operators and Events.pdf differ diff --git a/tech/annotations.html b/tech/annotations.html new file mode 100644 index 00000000..c7170046 --- /dev/null +++ b/tech/annotations.html @@ -0,0 +1,709 @@ + + + + + + + +Annotations in Jason + + + + + + +
+
+

Introduction

+
+
+

Each belief in an agent’s belief base has at least one annotation; goals and plans can also have annotations. The whole idea of annotations emerged when we added speech-act based communication, so we needed to annotate the source of each belief. In a multi-agent systems, agents' beliefs can come from inter-agent communication, by sensing the environment (such beliefs are called percepts), or because the agent added "mental notes" (i.e., beliefs the agent created itself whilst executing plans in order to remind itself of something). In Jason, all beliefs have a pre-defined source annotation, which is automatically handled by the interpreter; all other annotations are user-defined an need to be used/controlled by the programmer.

+
+
+

Annotations do not change the expressive power of the programming language, but they greatly improve legibility. In fact, they are one of the most interesting additions to the original AgentSpeak language that were introduced in Jason. As agent-oriented programming is heavily influenced by Artificial Intelligence, it often makes sense to represent meta-level information about each individual belief, goal, or plan that an agent has. Even though originally we only needed annotations to denote the sources of information an agent had, they turned out to be an extremely flexible mechanism with many uses and purposes. Much research work extending AgentSpeak has taken advantage of annotations for specific purposes.

+
+
+

However, in order to deal with annotations, we have had to create a more sophisticated unification algorithm. This document presents how it works by means of examples.

+
+
+
+
+

Syntax

+
+
+

Annotations are represented with the same syntax of a list in Prolog; however, this needs to be a list of terms rather than literals, and it must immediately follow the literal or term they are annotating (plans are annotated in the optional label they have, which is itself a predicate). For example:

+
+
+
+
p(t)[source(ag)]
+
+
+
+

represents a belief literal p(t) with a single annotation source(ag) which is an annotation handled by Jason to say that this belief originating from agent ag telling this agent that ag believed p(t) to be true. Other possible sources are source(percept) and source(self); the former means that belief p(t) originated from perceiving the environment and the latter from a mental note. In the following example:

+
+
+
+
p(t)[a1,a2(0)].
+
+
+
+

the literal p(t) has two annotations: terms a1 and a2(0).

+
+
+

One important thing to note is that even though the notation for lists in Prolog is used for Jason annotations, they are considered as a set and their order is not preserved. E.g. p[b,c,10,b] are replaced by p[10,b,c].

+
+
+
+
+

Unification Between Literals

+
+
+

In the case of a unification like A = B, the set of annotations of the first argument A has to be a subset of the annotations of the second argument B. Example:

+
+
+
+
p(t) = p(t)[a1];           // unifies
+p(t)[a1] = p(t);           // does not unify
+p(t)[a2] = p(t)[a1,a2,a3]; // unifies
+
+
+
+

The "tail" of the list of annotations (in this case working like set difference) can be used:

+
+
+
+
p[a2|T] = p[a1,a2,a3];     // T unifies with [a1,a3]
+p[a1,a2,a3] = p[a1,a4|T];  // T unifies with [a2,a3]
+
+
+
+
+
+

Annotations in plan trigger

+
+
+

When the unification is between a triggering event and a plan’s trigger, the plan’s trigger is the first argument of the unification. So for an event +!g[a], the relevance of the following plans is as follows:

+
+
+
+
+!g : true <- ...       // relevant for event +!g[a], since g = g[a]
++!g[a] : true <- ...    // relevant for event +!g[a]
++!g[a,b] : true <- ...  // not relevant for event +!g[a]
++!g[b] : true <- ...    // not relevant for event +!g[a]
+
+
+
+

However, for an event !g` a plan with trigger `!g[a] is not relevant. In other words, to put an annotation is a plan’s trigger means "this plan is relevant only for events with (at least) these annotations, or annotations that unify with these".

+
+
+

A plan like

+
+
+
+
+!g : ... <- ....
+
+
+
+

can handle goals !g, !g[a], !g[a,b], …​

+
+
+

A plan like

+
+
+
+
+!g[a] : ... <- ....
+
+
+
+

can handle goals !g[a], !g[a,b], …​ It can thus be relevant for any goal g with at least the annotation a.

+
+
+
+
+

Annotations in rules

+
+
+

When the unification is between a query event and a rule, the query is the first argument of the unification.

+
+
+

The rule

+
+
+
+
r[a] :- true.
+
+
+
+

is relevant for the query ?r, since the agent believes in r (r = r[a]). The query ?r[a], of course, also succeeds. However, the query ?r[a,b] fails, the agent does not believe in r with both annotations (r[a,b] \= r[a]).

+
+
+ + + + + +
+ + +The handling of annotations in rules and plans is not symmetrical. The plan +!g[a] ← …​ is applicable for !g[a,b], however, the rule +r[a] :- …​ is not applicable for ?r[a,b]! One reason is that rules and plans are of different natures when used by the interpreter. When we query ?r[a] we are interested in the final result of a process (i.e., whether the theoretical reasoning can produce r[a] or not). When we add a goal !g[a] we are providing a motivation to start a process (i.e. the practical reasoning). +
+
+
+
+
+

Unification Between Variables

+
+
+

Consider the various cases of the a unification X[As] = Y[Bs] below; the notation used is X and Y for variables, and As, Bs, Cs, and Ds are sets of annotations.

+
+
+

X and Y are ground

+
+
+
+
X     = p[Cs]  // unify X with p[Cs], where Cs is a set of annotations
+Y     = p[Ds]  // unify Y with p[Ds], where Ds is a set of annotations
+X[As] = Y[Bs]  // unifies if (Cs union As) is a subset of (Ds union Bs) ...
+               // ... after attempting to unify the annotations individually
+
+
+
+

Example:

+
+
+
+
X = p[a1,a2];
+Y = p[a1,a3];
+X[a4] = Y[a2,a4,a5]; // unifies
+
+
+
+

Since X is unified with p[a1,a2], the result from the substitutions of X[a4] is p[a1,a2][a4], that is equals to p[a1,a2,a4].

+
+
+

Only X is ground

+
+
+
+
X     = p[Cs]
+X[As] = Y[Bs]  // unifies if (Cs union As) subset Bs
+               // and Y unifies with p
+
+
+
+

Example:

+
+
+
+
X = p[a1,a2];
+X[a3] = Y[a1,a2,a3,a4,a5]; // unifies Y with p
+X[a3] = Y[a2,a3,a4,a5];    // does not unify
+X[a3] = Y[a1,a2,a4,a5];    // does not unify
+
+
+
+

Only Y is ground

+
+
+
+
Y     = p[Ds]
+X[As] = Y[Bs]  // unifies if As subset (Ds union Bs)
+               // and unifies X with p
+
+
+
+ + + + + +
+ + +the annotations of X is an issue to discuss (what X should unify with?). It could be [], since [] is a subset of anything. It could be: X = p[(Ds + Bs) - As]. A minimal subset approach or a maximal subset approach. The current implementation is like above (minimal subset approach). The problem is that X = p[a,b,c] unifies X with p[a,b,c], i.e., the maximal approach. So the current implementation is somewhat inconsistent. Proposal: use always the maximal approach when Y is ground and the minimal when X is ground. Another option is to consider that X = p[a,b,c] is not equal to X[] = p[a,b,c]; the first unifies X to p[a,b,c]; the second X unifies with p. Thus X is not the same thing as X[] (!!); what seems worst, since it implies that p[] is not equal to p. +
+
+
+

Example:

+
+
+
+
Y     = p[a1,a3];
+X[a1] = Y[a4,a5]; // unifies X with p; in maximal approach X value would be X[a3,a4,a5]
+X[a6] = Y[a4,a5]; // does not unify
+
+
+
+

Neither X nor Y are ground

+
+
+
+
X[As] = Y[Bs]  // unifies if As is a subset of Bs
+               // and X unifies with Y
+
+
+
+
+
+

Annotated Variables in a Plan Body

+
+
+

The annotations of the variable and the annotations of its value are combined (using set union) to produce the corresponding event:

+
+
+
+
X=g[a];
+...
+!X[b]; // produce event +!g[a,b]
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/tech/concurrency.html b/tech/concurrency.html new file mode 100644 index 00000000..3b654a1a --- /dev/null +++ b/tech/concurrency.html @@ -0,0 +1,1063 @@ + + + + + + + + +Concurrency in Jason + + + + + + +
+
+
+
+

This document presents some Jason features for concurrent programming.

+
+
+
+
+

Intentions

+
+
+

Intentions in Jason are somewhat similar to threads in other languages in so far as they also execute concurrently, unless you have customised the intention selection function to alter the default intention scheduling. By default, different intentions are executed in a round-robin fashion, executing only one element of the (topmost) plan body each time the intention is selected.

+
+
+

New intentions are created by:

+
+
+
    +
  1. +

    external events

    +
    +
      +
    • +

      each perceived change in the environment that the agent reacts to starts a new intention

      +
    • +
    • +

      another agent delegates a goal (through an achieve message)

      +
    • +
    +
    +
  2. +
  3. +

    initial goals

    +
  4. +
  5. +

    the !!, |&| and ||| operators (see next section)

    +
  6. +
+
+
+

For instance, for an agent with the following program

+
+
+
+
+b(X)    <- !say(hello(X)).
++!say(M) <- .print(M); !say(M).
+
+
+
+

when it starts to believe in b(a), b(b), and b(c) (by perceiving these beliefs, for example), three events +b(…​) are produced and then three intentions are created and will concurrently print the messages as follows:

+
+
+
+
hello(a)
+hello(b)
+hello(c)
+hello(a)
+hello(b)
+hello(c)
+....
+
+
+
+
+
+

Agent Language

+
+
+

New intentions

+
+

The plan

+
+
+
+
+!ga <- ...; !!gb; a1; ...
+
+
+
+

creates a new intention for gb and then executes the action a1. a1 is executed after the creation of the intention for gb and not after the achievement of gb (as it would be the case if ! was used instead of !!). The intention for gb is a new intention and not the same as the intention for ga.

+
+
+
+

Concurrent Operators

+
+

Besides the usual sequence operator ;, plan bodies can also use fork and join operators for concurrent execution of plan bodies: |&| and |||. The first is called fork-join-and and the second fork-join-xor.

+
+
+

For instance, in

+
+
+
+
+!ga <- ...; !gb; ...
++!gb <- ...; !g1 |&| !g2; a1; …
+
+
+
+

the two subgoals g1 and g2 will be achieved concurrently by two sub-intentions; when both are finished, the action a1 will be executed.

+
+
+

In the following case,

+
+
+
+
+!ga <- ...; !gb; ...
++!gb <- ...; !g1 ||| !g2; a1; ...
+
+
+
+

the two subgoals g1 and g2 will be also achieved concurrently; however, when one sub-intention is finished, the other is dropped and the action a1 will be executed.

+
+
+

Regarding precedence, the operator |&| has precedence over ||| which has preference over ;. For instance, a plan like:

+
+
+
+
x; (a;b) |&| (c;d) ||| (e;f); y
+
+
+
+

would have the following behaviour: +. execute x +. concurrently execute +* a;b +* c;d +* e;f +. execute y when either a,b,c, and d have finished executing concurrently, or when both e and f have finished.

+
+
+

The following cases can be considered when a failure occurs while achieving either g1 or g2:

+
+
+
    +
  1. +

    there is plan failure for the failed subgoal: the failure is handled by that concurrent sub-intention without interference to the other subgoal.

    +
  2. +
  3. +

    there is no plan failure:

    +
    +
      +
    • +

      in case of fork-join-and: drops also the other subgoal and handles the failure in the achievement of goal gb above as usual.

      +
    • +
    • +

      in case of fork-join-xor: ignore the failure (discarding that concurrent sub-intention) and continue to try the other subgoal.

      +
    • +
    +
    +
  4. +
+
+
+

When a .fail_goal(ga) is executed:

+
+
+
    +
  • +

    The sub-intentions for g1 and g2 are dropped,

    +
  • +
  • +

    The goal gb is dropped, and

    +
  • +
  • +

    the failure of ga is handled as usual.

    +
  • +
+
+
+

When a .succeed_goal(gb) is executed:

+
+
+
    +
  • +

    The sub-intentions for g1 and g2 are dropped,

    +
  • +
  • +

    The goal gb is dropped, and

    +
  • +
  • +

    The plan for ga continues.

    +
  • +
+
+
+
+
+
+

Conflicting plans

+
+
+

If some intention cannot interleave its execution with another, the atomic annotation can be used in the label of plans:

+
+
+
+
@alabel[atomic] // no other intention will run if an intention selects this plan
++!update(X)
+   <- -vl(T);   // gets the current value of belief vl
+      +vl(T+X). // updates its value
+
+
+
+

If an atomic plan runs, all its subgoals will be also atomic. More documentation regarding this matter can be found here.

+
+
+
+
+

Internal actions

+
+
+

Some internal actions are useful for concurrent programming in Jason:

+
+
+ +
+
+
+
+

Configuration

+
+
+

Different concurrency configurations can be set for the Local infrastructure in Jason.

+
+
+

The Jason agent reasoning cycle is executed considering three main stages: sense, deliberate, and act. Such stages can be executed in two different configurations:

+
+
+
    +
  1. +

    Synchronously (or sequentially): +In this configuration, the stages of the reasoning cycle are executed sequentially. One stage just starts its execution when the previous stage has finished its execution. For example, the deliberate stage only starts after sense.

    +
  2. +
  3. +

    Asynchronously (or concurrently): +In this configuration, the stages of the reasoning cycle are executed concurrently. One stage can start its execution before the (usual) previous stage has finished. For example, an agent can execute its intentions at the same time as new intentions are being produced by the deliberate stage.

    +
  4. +
+
+
+

Synchronous Reasoning Cycle

+
+

One thread per agent

+
+

Each agent has its own thread, which means that if the MAS is composed of 100 agents, 100 threads will be created to execute the agents.

+
+
+

In the default configuration of the .mas2j project file

+
+
+
+
infrastructure: Local
+
+
+
+

the agent’s thread runs each stage every reasoning cycle:

+
+
+
+
loop
+  sense();
+  deliberate();
+  act();
+
+
+
+

When some stages must be executed more than once, the number of cycles for each stage must be informed. The parameters in the .mas2j for this configuration are presented below.

+
+
+
+
infrastructure: Local(threaded,
+    <NUMBER-CYCLES-SENSE>, <NUMBER-CYCLES-DELIBERATE>, <NUMBER-CYCLES-ACT>)
+
+
+
+

and the reasoning cycle is:

+
+
+
+
loop
+  do <NUMBER-CYCLES-SENSE> times:
+    sense();
+  do <NUMBER-CYCLES-DELIBERATE> times:
+    deliberate();
+  do min( <NUMBER-CYCLES-ACT>, numberOfIntentions()) times:
+    act();
+
+
+
+

<NUMBER-CYCLES-SENSE> is the maximum number of times that the sense stage is executed before the deliberate stage starts its execution. <NUMBER-CYCLES-DELIBERATE> is the maximum number of times that the deliberate stage is executed before the act stage starts its execution. <NUMBER-CYCLES-ACT> is the maximum number of times that the act stage is executed before the sense stage starts its execution. The <NUMBER-CYCLES-ACT> is limited to the number of intentions so that no more and one deed of each intentions are executed each reasoning cycle.

+
+
+

In the example below, the sense and deliberate stages will be executed only once, while the act stage will be executed at most 5 times.

+
+
+
+
infrastructure: Local(threaded, 1, 1, 5)
+
+
+
+
+

Thread pool

+
+

When the number of agents in the MAS is significantly higher than the number of computer cores, it makes more sense to use thread pools in order to minimize the overhead caused by managing many threads. In this configuration, a limited number of threads is used to execute all agents in the MAS. The parameters for this configuration are detailed below.

+
+
+
+
infrastructure: Local(pool, <NUMBER-THREADS>, [NUMBER-REASONING-CYCLES])
+
+
+
+

or

+
+
+
+
infrastructure: Local(pool, <NUMBER-THREADS>,
+    <NUMBER-CYCLES-SENSE>, <NUMBER-CYCLES-DELIBERATE>, <NUMBER-CYCLES-ACT>,
+    [NUMBER-REASONING-CYCLES])
+
+
+
+

The keyword pool makes the execution platform to create one thread pool with <NUMBER-THREADS> threads. [NUMBER-REASONING-CYCLES] is the maximum number of times that the sequence sense-deliberate-act is executed (default value is 5).

+
+
+

Each time a thread of the pool runs an agent, the following algorithm is executed:

+
+
+
+
do <NUMBER-REASONING-CYCLES> times:
+  do <NUMBER-CYCLES-SENSE> times:
+    sense();
+  do <NUMBER-CYCLES-DELIBERATE> times:
+    deliberate();
+  do min( <NUMBER-CYCLES-ACT>, numberOfIntentions()) times:
+    act();
+
+
+
+

In the example below, a thread pool with 4 threads is created and each stage will be executed just once.

+
+
+
+
infrastructure: Local(pool,4)
+
+
+
+

In the example below, a thread pool with 4 threads is created and the sequence sense-deliberate-act is executed at most 5 times.

+
+
+
+
infrastructure: Local(pool,4,5)
+
+
+
+

In the example below, a thread pool with 4 threads is created, and the sense and deliberate stages are configured to execute just once, while the act stage will be executed at most 5 times.

+
+
+
+
infrastructure: Local(pool,4,1,1,5)
+
+
+
+

Finally, in the example below, the parameter [NUMBER-REASONING-CYCLES] is used. A thread pool with 4 threads is created, the sense and deliberate stages are configured to execute just once, while in the first case, the act stage executes at most 5 times, and in the second case, at least one action of each intention will be executed. In both cases, the sense-deliberate-act sequence will be repeated 10 times.

+
+
+
+
infrastructure: Local(pool,4,1,1,5,10)
+infrastructure: Local(pool,4,1,1,9999,10)
+
+
+
+

A further configuration for pools is to execute only one stage every time that a thread selects an agent. Thus, the thread, for example, will execute the sense stage and put the agent back to the queue, then, the next time that this agent is selected, the thread will execute the deliberate stage, and finally the act stage.

+
+
+

In this case, the algorithm presented previously is executed like this:

+
+
+
+
switch (stage)
+  case SENSE:
+    loop do <NUMBER-CYCLES-SENSE> times:
+      sense();
+    stage = DELIBERATE;
+  case DELIBERATE:
+    loop do <NUMBER-CYCLES-DELIBERATE> times:
+      deliberate();
+    stage = ACT;
+  case ACT:
+    loop do min( <NUMBER-CYCLES-ACT>, numberOfIntentions()) times:
+      act();
+    stage = SENSE;
+
+
+
+

The parameters are almost the same as before, however, the first parameter must be defined as synch_scheduled and [NUMBER-REASONING-CYCLES] is not a parameter for this configuration. Thus, the examples aforementioned could be written exemplified below.

+
+
+

Using 4 threads, each stage will be executed once:

+
+
+
+
infrastructure: Local(synch_scheduled,4)
+
+
+
+

Each stage is executed at most 5 times:

+
+
+
+
infrastructure: Local(synch_scheduled,4,5)
+
+
+
+

The sense and deliberate stages are executed once, while the act stage is executed at most 5 times:

+
+
+
+
infrastructure: Local(synch_scheduled,4,1,1,5)
+
+
+
+

The sense and deliberate stages are executed once, and at least one action of each intention will be executed in the act stage:

+
+
+
+
infrastructure: Local(synch_scheduled,4,1,1,9999)
+
+
+
+
+
+

Asynchronous Reasoning Cycle

+
+

The asynchronous configuration can be configured to use a single thread pool to execute all the stages or to use one dedicated thread pool to execute each stage.

+
+
+

In the case of asynchronous execution, the tasks in the pool are the execution of a stage. The algorithm is the same independent of the number of threads or thread pools. Thus, each thread executes the stage according to its tasks, like the algorithm below.

+
+
+
+
switch (task.stage)
+  case SENSE:
+    loop do <NUMBER-CYCLES-SENSE> times:
+      sense();
+  case DELIBERATE:
+    loop do <NUMBER-CYCLES-DELIBERATE> times:
+      deliberate();
+  case ACT:
+    loop do min( <NUMBER-CYCLES-ACT>, numberOfIntentions()) times:
+      act();
+
+
+
+

The parameters to use a single thread pool are presented below:

+
+
+
+
infrastructure: Local(asynch_shared, <NUMBER-THREADS>,
+    <NUMBER-CYCLES-SENSE>, <NUMBER-CYCLES-DELIBERATE>, <NUMBER-CYCLES-ACT>)
+
+
+
+

As in the pool case, the keyword asynch_shared makes the execution platform to create a thread pool with <NUMBER-THREADS> threads.

+
+
+

In the example below, a thread pool with 4 threads is created and each stage will be executed just once.

+
+
+
+
infrastructure: Local(asynch_shared,4)
+
+
+
+

In the example below, a thread pool with 4 threads is created, the sense and deliberate stages are configured to execute at most 15 times, and the act stage will be executed at most 20 times.

+
+
+
+
infrastructure: Local(asynch_shared,4,15,15,20)
+
+
+
+

In another configuration, each stage can be executed by a different thread pool. The parameters for this configuration are presented below.

+
+
+
+
infrastructure: Local(asynch,
+    <NUMBER-THREADS-SENSE>, <NUMBER-THREADS-DELIBERATE>, <NUMBER-THREADS-ACT>)
+
+
+
+

or

+
+
+
+
infrastructure: Local(asynch,
+    <NUMBER-THREADS-SENSE>, <NUMBER-THREADS-DELIBERATE>, <NUMBER-THREADS-ACT>,
+    <NUMBER-CYCLES-SENSE>, <NUMBER-CYCLES-DELIBERATE>, <NUMBER-CYCLES-ACT>)
+
+
+
+

The keyword asynch makes the execution platform to create three thread pools, one for each stage. <NUMBER-THREADS-SENSE> is the number of threads for the thread pool to execute the sense stage. <NUMBER-THREADS-DELIBERATE> is the number of threads for the thread pool to execute the deliberate stage. <NUMBER-THREADS-ACT> is the number of threads for the thread pool to execute the act stage.

+
+
+

In the example below, three thread pools with 4 threads each are created:

+
+
+
+
infrastructure: Local(asynch,4,4,4)
+
+
+
+

In the example below, three thread pools with 4 threads each are created, the sense and deliberate stages are configured to execute at most 15 times, and the act stage will be executed at most 20 times.

+
+
+
+
infrastructure: Local(asynch,4,4,4,15,15,20)
+
+
+
+
+

Individual Agents

+
+

Besides the global configuration for the MAS. Jason allows to configure the number of cycles for each agent individually, allowing to define a kind of priority by giving more CPU for certain agents than others. The parameters for the agents are presented by means of the two examples below.

+
+
+

The agent ana has the number of cycles for the sense and deliberate stages as 2, while the number of cycles for the act stage is 10:

+
+
+
+
ana [cycles_sense = 2, cycles_deliberate = 2, cycles_act = 10];
+
+
+
+

The agent bob has the number of cycles for the sequence sense-deliberate-act as 10:

+
+
+
+
bob [cycles = 10];
+
+
+
+
+
+
+ +
+
+
    +
  1. +

    Alex Muscar, Costin Badica. Monadic Foundations for Promises in Jason. ITC, v. 43, n. 1, p. 65–72, 2014. DOI: 10.5755/j01.itc.43.1.4586

    +
  2. +
  3. +

    Alex Muscar. Agents for the 21st century: the blueprint agent programming language. In: Proc. of the 1st AAMAS Workshop on Engineering MultiAgent Systems, 2013. p. 49–64.

    +
  4. +
  5. +

    Maicon R. Zatelli, Alessandro Ricci, Jomi F. Hübner. A Concurrent Architecture for Agent Reasoning Cycle Execution in Jason. In: 13th European Conference on Multi-Agent Systems (EUMAS), 2016, Athens. Multi-Agent Systems and Agreement Technologies, 2016. v. 9571. p. 425-440. DOI: 10.1007/978-3-319-33509-4_33

    +
  6. +
  7. +

    Maicon R. Zatelli, Alessandro Ricci, Jomi F. Hübner. Evaluating Different Concurrency Configurations for Executing Multi-Agent Systems. In: 3rd International Workshop on Engineering Multi-agent Systems (EMAS@AAMAS), 2015, Istanbul. Engineering Multi-agent Systems, 2015. v. 9318. p. 212-230. DOI: 10.1007/978-3-319-26184-3_12

    +
  8. +
  9. +

    Pascual Pérez-Carro, Francisco Grimaldo, Miguel Lozano, Juan M. Orduña. Characterization of the Jason Multiagent Platform on Multicore Processors. Scientific Programming 22(1). p 21-35, 2014. DOI: 10.3233/SPR-130375

    +
  10. +
  11. +

    Victor Fernández-Bauset, Francisco Grimaldo, Miguel Lozano, Juan M. Orduña. Tuning Java to Run Interactive Multiagent Simulations over Jason. In: LI, J. (Ed.). Australasian Conference on Artificial Intelligence, 2010. (Lecture Notes in Computer Science, v. 6464), p. 354–363. DOI: 10.1007/978-3-642-17432-2_36

    +
  12. +
  13. +

    Victor Fernández, Francisco Grimaldo, Miguel Lozano, Juan M. Orduña. Evaluating Jason for Distributed Crowd Simulations. In: FILIPE, J.; FRED, A. L. N.; SHARP, B. (Ed.). ICAART (2). [S.l.]: INSTICC Press, 2010. p. 206–211. ISBN 978-989-674-022-1.

    +
  14. +
+
+
+
+
+ + + \ No newline at end of file diff --git a/tech/goal-states.gv b/tech/goal-states.gv new file mode 100644 index 00000000..a02e8132 --- /dev/null +++ b/tech/goal-states.gv @@ -0,0 +1,73 @@ +// dot goal-states.gv -Tpdf -o goal-states.pdf + +digraph goal_states { + node [color=gray]; + + compound=true; + + ENTRY[shape=point,color=black,label=""]; + //EXIT[shape=point,color=black,label=""]; + + + subgraph cluster1 { + shape = rectangle; style=invis; + + node [shape=oval,style=filled,color=gray, fillcolor="lightgoldenrod", fixedsize=shape,width=1.5]; + S [label="suspended"]; + R [label="resumed",shape=rectangle]; + + S->R[label=< .resume> ,fontsize="8",arrowsize=0.5]; + + } + + subgraph cluster2 { + shape = rectangle; style=dashed; color=grey; + node [shape=oval,style=filled,color=gray, fillcolor="lightgoldenrod", fixedsize=shape,width=2]; + C [label="pending"]; + + node [shape=rectangle,style="filled",fillcolor="lightgoldenrod",fixedsize=shape,width=2]; + E [label="executing"]; + P [label="waiting"]; + + C->E[label=< has applicable
plan
>,fontsize="8",arrowsize=0.5]; + + E->P[label= .wait
>,fontsize="8",arrowsize=0.5]; + P->E[label=<>,fontsize="8",arrowsize=0.5]; + } + + subgraph cluster3 { + //rankdir=LR; + shape = rectangle; style=invis; + node [shape=oval,fillcolor=white,color=gray,style=filled,fixedsize=shape,width=1,fontsize="10"]; + A [label="achieved"]; + F [label="failed"]; + D [label="dropped"]; + T [label="finished",peripheries=2]; + + {A,F,D} -> T [arrowsize=0.5]; + } + + ENTRY->C[label=< event +!>,fontsize="8",arrowsize=0.5]; + + C->F[label=< no plan
>,fontsize="8",arrowsize=0.5]; + + E->A[label=,fontsize="8",arrowsize=0.5]; + P->D[label=<.drop_intention
.drop_desire>,fontsize="8",arrowsize=0.5,ltail=cluster2]; + + C -> F [label=<.fail_goal
failure>,fontsize="8",arrowsize=0.5,ltail=cluster2]; + E -> A [label=<.succeed_goal>,fontsize="8",arrowsize=0.5,ltail=cluster2]; + + F -> E [label=plan>,fontsize="8",arrowsize=0.5]; + + P->S[label=<.suspend>,fontsize="8",arrowsize=0.5,ltail=cluster2]; + R->P[label=<> ,fontsize="8",arrowsize=0.5,lhead=cluster2]; + + subgraph cluster0 { + label = "key"; fontsize="10"; + rankdir=LR; shape = rectangle; style=dotted; color=grey; + //key4 [label=<^meta event >, shape=plaintext,fontsize="10",]; + key2 [label=".desire\n.intend",shape=rectangle,style=filled,fontsize="8", fillcolor=lightgoldenrod,width=0.5]; + key1 [label=".desire", shape=oval, style=filled,fontsize="8", fillcolor=lightgoldenrod,width=0.5]; + //key3 [label="finished", shape=oval, style=filled,fontsize="10", fillcolor=lightgrey,fixedsize=shape,width=1]; + } +} diff --git a/tech/goal-states.pdf b/tech/goal-states.pdf new file mode 100644 index 00000000..5b1afc8a Binary files /dev/null and b/tech/goal-states.pdf differ diff --git a/tech/intention-states.gv b/tech/intention-states.gv new file mode 100644 index 00000000..4307c36f --- /dev/null +++ b/tech/intention-states.gv @@ -0,0 +1,24 @@ +// dot intention-states.gv -Tpdf -o intention-states.pdf + +digraph intention_states { + compound=true; + + ENTRY[shape=point,color=black,label=""]; + EXIT[shape=point,color=black,label=""]; + + node [shape=oval,style=filled,color=gray, fillcolor="lightgoldenrod", fixedsize=shape,width=2]; + R [label=<running
(I,E,SE,SI)>]; + S [label=<suspended
(PI,PE)>]; + P [label=<waiting
(PI,PA)>]; + + R->S[arrowsize=0.5]; + S->R[arrowsize=0.5]; + + R->P[arrowsize=0.5]; //[label=<^resumed>,fontsize="8",arrowsize=0.5]; + P->R[arrowsize=0.5]; + + + ENTRY->R[arrowsize=0.5]; + {R,S,P} -> EXIT [arrowsize=0.5]; + +} diff --git a/tech/intention-states.pdf b/tech/intention-states.pdf new file mode 100644 index 00000000..0235166a Binary files /dev/null and b/tech/intention-states.pdf differ diff --git a/tech/modules-namespaces.pdf b/tech/modules-namespaces.pdf new file mode 100644 index 00000000..736ddec1 Binary files /dev/null and b/tech/modules-namespaces.pdf differ diff --git a/tech/patterns.html b/tech/patterns.html new file mode 100644 index 00000000..ef6b314c --- /dev/null +++ b/tech/patterns.html @@ -0,0 +1,988 @@ + + + + + + + +Some Programming Patterns in Jason + + + + + + +
+
+

Loops

+
+
+

List Iteration

+
+

To do something for all members of a list, we have two main approaches: the classic recursion and the for-each.

+
+
+

Recursive approach

+
+
+
+!iterate([]).            // list is empty -> nothing to do
++!iterate([Head|Tail])    // does something with the head of the list
+   <- dosomethingwith(Head);
+      !iterate(Tail).     // and continues with the tail
+
+
+
+

Example:

+
+
+
+
!print([b,a,n,a,n,a]).
+
++!print([]).
++!print([Head|Tail])
+   <- .print(Head);
+      !print(Tail).
+
+
+
+

Prints:

+
+
+
+
b
+a
+n
+a
+n
+a
+
+
+
+
+

For-each approach

+
+
+
+!iterate(List)
+   <- for (.member(M,List)) {   // use .member as the query
+         dosomethingwith(Head);
+      }.
+
+
+
+ + + + + +
+ + +The Jason for is not like a typical for-each (witch iterates over a collection of values). Jason for iterates over a query, it can be read as "for each solution of a query". +
+
+
+

Example:

+
+
+
+
!print([b,a,n,a,n,a]).
+
++!print(List)
+   <- for (.member(M,List) & M \== a) { // note the use of a query as the argumet
+         .print(M);
+      }.
+
+
+
+

Prints:

+
+
+
+
b
+n
+n
+
+
+
+
+
+

For i in a .. b

+
+

The classical C like iteration with a counter variable can be implemented using recursion or for. Below the internal action .range is used as the for query to mimmic the typical C loop.

+
+
+
+
+!loop
+   <- for (.range(I,A,B)) { // for i from a to b (included)
+         dosomething(I);
+      }.
+
+
+
+

Example:

+
+
+
+
!loop.
+
++!loop
+   <- for (.range(I,1,5) & .range(J,1,5) & I > J) {
+         .print(I," ",J);
+      }.
+
+
+
+

Prints:

+
+
+
+
2 1
+3 1
+3 2
+4 1
+4 2
+4 3
+5 1
+5 2
+5 3
+5 4
+
+
+
+
+

Query iteration

+
+

To do something for all solutions of a query we can (1) use .findall to place them all in a list and then iterate over the list or (2) use for loops. The pattern based on for follows.

+
+
+
+
+!loop
+   <- for ( query ) { // for all solutions of `query`
+         dosomething;
+      }.
+
+
+
+

The example that follows prints all values of b that are greater than some p.

+
+
+
+
!loop.
+
+b(10).
+b(20).
+p(05).
+p(15).
+p(25).
+
++!loop
+   <- for (b(X) & p(Y) & X > Y) {
+         .print(X);
+      }.
+
+
+
+

Prints:

+
+
+
+
10
+20
+20
+
+
+
+ + + + + +
+ + +There are two 20 printed out since the query has 3 answers: { X=10, Y=5 }; { X=20, Y=5 }; and { X=20,Y=15}. +
+
+
+
+
+
+

Plans execution interleaving

+
+
+

Regarding concurrent execution in Jason, we recommend the reading of this doc.

+
+
+

Singleton Plan

+
+

Some times we want that a plan has only one intention running it. For instance, when the agent wants to control the movement of a robot, it will be chaotic if two intentions with different targets are controlling the robot.

+
+
+

The following code avoids two or more concurrent executions of plan g:

+
+
+
+
+!g : not .intend(g) <- dosomething.
++!g. // do nothing for g
+
+
+
+

If the agent has two events +!g, when the first is handled, the agent does not intend g and the first plan is selected and thus the agent now intends g avoiding this plan to be selected again.

+
+
+ + + + + +
+ + +This pattern considers g as achieved if some other intention is trying it (cf. the second plan for g). +
+
+
+

Example:

+
+
+
+
e.
++!e
+   <- for ( .range(I,0,5) ) { // creates 6 concurrent intentions for g
+         !!g(I);
+      }.
+
++!g(I) : not .intend(g(_))
+   <- .wait(200);
+      .print(I).
++!g(I).
+
+
+
+

Prints:

+
+
+
+
0
+
+
+
+
+

"Queued" Singleton Plan

+
+

As for the singleton plan, we want that only one intention is executing the plan. However, when an intention has no access to the plan, it waits for the running intention to complete and then tries again to execute.

+
+
+
+
+!g : not .intend(g)   // I do not intend g yet, so starts doing something to achieve g
+   <- dosomething;
+      !!resume(g).     // resume other intentions waiting to execute
+                       // must be done by a new intention (!!) and be the last command in the plan,
+                       // otherwise this plan will not be selected again
+
++!g                    // a plan for g is running, suspends this tentative
+   <- .suspend;        // (when the running intention finishes, it will resume this one)
+      !!g.             // tries again (note that we have to use !!, otherwise this intention prevents the above plan to be selected)
+
++!resume(G)
+   <- .resume(G).      // resume all suspended Gs.
+
+
+
+ + + + + +
+ + +The annotation atomic could be considered for the first plan to achieve g (the plan being @[atomic] !g <- dosomething.`). However it may constraint too much the agent execution: no other intention (even not related to `g`) will run until `!g is finished. The reactivity of the agent can be compromised, specially in cases where dosomething takes a lot of time to execute. If dosomething is fast, atomic can be considered since it is far simple to use than this patter (this pattern adds two extra plans). +
+
+
+

Example:

+
+
+
+
!e.
++!e
+   <- for ( .range(I,0,5)) { // creates 6 concurrent intentions for g
+         !!g(I);
+      }.
+
++!g(I) : not .intend(g(_))
+   <- .print(I);
+      .wait(50);
+      .print(I);
+      !!resume(g(_)).
++!g(I)
+   <- .suspend;
+      !!g(I).
++!resume(G)
+   <- .resume(G).
+
+
+
+

Prints:

+
+
+
+
0
+0
+4
+4
+5
+5
+2
+2
+3
+3
+1
+1
+
+
+
+ + + + + +
+ + +There is no interleaving among the execution of the intentions. +
+
+
+

This pattern is used in the Santa Claus example that comes with Jason.

+
+
+
+

Plan dependency (synchronisation)

+
+

Suppose you have two plans:

+
+
+
+
+!a <- action1.
++!b <- action2.
+
+
+
+

and you need that the second plan is executed only when the first is already finished. However, you are not able to define the order of events !a` and `!b (their are externally determined).

+
+
+

Procedural goals

+
+

An initial tentative is:

+
+
+
+
+!a <- action1; .resume(b).
++!b <- .suspend; action2.
+
+
+
+

the second plan suspends itself and the first resumes the second when finished. It works often, but some very particular interleaving executions can break it: when the .resume(b) is executed and the second plan hasn’t executed .suspend yet. The following example creates this situation (.wait is used to force the delay in the execution of .suspend):

+
+
+
+
!a.
+!b.
+
++!a <- .print(a); .resume(b).
++!b <- .wait(1000); .suspend; .print(b).
+
+
+
+

The first plan should wait for the second to be suspended by the internal action .suspend before resuming it:

+
+
+
+
+!a <- action1; .wait( .suspended(b,suspend_ia) ); .resume(b).
++!b <- .suspend; action2.
+
+
+
+

If by some reason you do not want to change the two intitial plans, meta-events can be used:

+
+
+
+
+!a <- action1.
++!b <- action2.
+
+^!b[state(pending)]  <- .suspend(b). // suspend b when starting
+^!a[state(finished)] <- .resume(b).  // resume b when a finishes
+
+
+
+
+

Declarative goals

+
+

If the first plan is for a declarative goal (i.e., the goal !a refers to a fact that the agent initially believes a is not true, and if the goal is achieved, the agent will believe that a has become true), another solution is possible: the second plan can simply wait for the agent to believe in a.

+
+
+
+
+!a <- action1.
++!b <- .wait(a); action2.
+
+
+
+

In this case, of course, we should ensure that action1 will change the environment so that the agent will perceive a later.

+
+
+

Indeed we can relax a bit this pattern, and replace the a in .wait(a) by any belief we know that will hold after the first plan execution.

+
+
+
+
+
+
+

Commitment

+
+
+

The section 8.3 of the Jason Book presents some useful patterns to configure the agent commitment towards some goal. Two of these patterns are included here.

+
+
+

Single-Minded Commitment

+
+

In this pattern we want an agent that keeps trying to achieve goal g until it believes g is achieved (as a declarative goal) or that g is impossible. See paper "Cohen & Levesque. Intention is choice with commitment. Artificial Intelligence 42(3), 213–261, 1990."

+
+
+

Supposing that to believe in f implies that g is impossible, the pattern can be written as:

+
+
+
+
+!g : g.                // if I already believe g, there is nothing to do
++!g : .intend(g).       // if there is an intention to g already, do nothing
+
++!g : somecontext1      // a possible plan to achieve g
+   <- dosomething1;
+   ?g.
++!g : somecontext2      // another possibility
+   <- dosomething2;
+   ?g.
+
++!g : !g.               // no applicable plan, keeps trying
+-!g <- !g.              // if the above plans have failed, keeps trying hopping for better conditions
++g <- .succeed_goal(g). // stops trying g if g
++f <- .fail_goal(g).    // stops trying g if f
+
+
+
+ + + + + +
+ + +The plans to achieve g end with ?g, so they only succeed if after doing something to acheive g the agent believes g (for instance, it perceives g). +
+
+
+

In Jason, a directive is available to simplify the use of this pattern:

+
+
+
+
{ begin smc(g,f) }
++!g : somecontext1 <- dosomething1.
++!g : somecontext2 <- dosomething2.
+{ end }
+
+
+
+
+

Maintenance Goal

+
+

In the case of a maintenance goal, the agent should keep g always true. Whenever it realises that g is no longer in its belief base, it attempts to bring about g again by having the respective (declarative) achievement goal.

+
+
+
+
-g <- !g.
+
+// the code to achieve g follows
+
+{ begin bc(g) }
++!g : somecontext1 <- dosomething1.
++!g : somecontext2 <- dosomething2.
+{ end }
+
+
+
+ + + + + +
+ + +BC (Blindly Commitment) is a pattern similar to SMC, without the failure condition f. +
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/tech/run-jason-without-gradle.txt b/tech/run-jason-without-gradle.txt new file mode 100644 index 00000000..eb7c7cbc --- /dev/null +++ b/tech/run-jason-without-gradle.txt @@ -0,0 +1,22 @@ + +if you want to run/test changes in Jason sources without publishing jars on maven/gradle repositories: + +1. compile the changes + ./gradlew :jason-cli:uberJar + +2. set a var with UBERJAR + export JASON_UJ=/jason-cli/build/ + +3. go to an application directory + +4. compile java sources of the application + jason app compile + or + ./gradlew build + +4. run with local infra: + java -cp ".:build/classes/java/main:JASON_UJ/*" jason.infra.local.RunLocalMAS xx.mas2j + +5. run with jade infra: + java -cp ".:build/classes/java/main:JASON_UJ/*" jason.infra.jade.RunJadeMAS xx.mas2j + diff --git a/tech/unit-tests.html b/tech/unit-tests.html new file mode 100644 index 00000000..7599a727 --- /dev/null +++ b/tech/unit-tests.html @@ -0,0 +1,700 @@ + + + + + + + +Unit Tests in Jason + + + + + + +
+
+

Introduction

+
+
+

Jason has a set of tools for testing Jason agents which includes a test management engine, a tester agent skeleton and plans for assertion and performance checks.

+
+
+

The test library is written and interpreted by Jason.

+
+
+

This test facilities can be used both using the management engine or as a simple library.

+
+
+
+
+

The test management engine

+
+
+

Jason provides an infrastructure to add testing agents to be launched in tests, which allows, for instance, continuous integration tests for Jason agents.

+
+
+

The test management engine is launched by $ ./gradlew test command (use just gradlew on MS Windows). It will launch all tester agents present in the default test folder for asl files.

+
+
+

In case of any assertion fails the exit status will inform failure to the operation system. If all tests pass, the exit status is normal, meaning success. These status inform integration tools (e.g. circle CI, github actions) about the results of tests.

+
+
+

The default command $ ./gradlew test prints out only warning and severe log messages. It also supports $ ./gradlew test --info which besides higher levels also prints info messages (which include the .print internal action). For even more deailed output $ ./gradlew test --debug can be used.

+
+
+

Jason tests is a NOT cacheable gradle task which means it runs completely every time and no clean command is needed.

+
+
+

The tester agents that imports the skeleton tester_agent.asl are equipped with the test library such as assertion plans.

+
+
+

All plans in which the label has the annotation test will be automatically launched by the test task.

+
+
+
+
+

Using the test engine

+
+
+
    +
  1. +

    Create an agent for testing your agent(s) in the folder src/test/jason/asl (all agents in this folder are automatically launched in the test task).

    +
  2. +
  3. +

    Make your agent a tester agent (e.g.: test_bob.asl) including the tester_agent.asl skeleton +` +{ include("$jasonJar/test/jason/inc/tester_agent.asl") } +`

    +
  4. +
  5. +

    Add to your test agent support to the agent it is going to test, eg: + ` +{ include("bob.asl") } + `

    +
  6. +
  7. +

    Run $ ./gradlew test to check the results.

    +
  8. +
+
+
+

Example 1

+
+

Let us say we have an agent bob which has a rule to sum two numbers. We want to check if bob can sum correctly. The content of bob.asl is:

+
+
+
+
sum(X,Y,R):-R = X + Y.
+
+
+
+

To test it, we can create a tester agent following the steps above. The content of src/test/jason/asl/test_bob.asl can be:

+
+
+
+
{ include("$jasonJar/test/jason/inc/tester_agent.asl") }
+{ include("bob.asl") }
+
+@[test] /* Notice the label with the annotation `test` will be automatically launched */
++!test_sum :
+    true
+    <-
+    ?sum(1.3,2.6,R);
+    !assert_equals(3.9,R,0.1);
+.
+
+
+
+

Running ./gradlew test the result for this test should be:

+
+
+
+
> Task :testJason
+BUILD SUCCESSFUL in 3s
+
+
+
+

Running ./gradlew test --info the result for this test should be:

+
+
+
+
[test_bob] assert_equals on goal 'test_sum' PASSED
+[test_manager] #1 plans executed, #1 PASSED and #0 failed.
+[test_manager] End of Jason unit tests: PASSED
+BUILD SUCCESSFUL in 3s
+
+
+
+

Let us say, bob is not doing sums correctly, let us say the content of bob.asl is:

+
+
+
+
sum(X,Y,R):-R = X + Y - 1. /* Notice, this -1 will make all sums wrong!!! */
+
+
+
+

For this failure condition, running ./gradlew test the result for this test should be:

+
+
+
+
[test_bob] assert_equals on event 'test_sum' starting at line 1 FAILED! Expected 3.9+/-0.1, but had 2.9000000000000004
+[test_manager] #1 plans executed, #0 passed and #1 FAILED.
+[test_manager] End of Jason unit tests: FAILED!
+> Task :testJason FAILED
+BUILD FAILED in 3s
+
+
+
+

Notice that failures are severe messages that will be shown regardless '--info' is set or not on gradle test command.

+
+
+
+

Example 2

+
+

Let us say we have an agent alice as below in which the testing functionality is provided by the plan do_something_with_a_counter. However, the agent is using an artifact counter that is not focus of our tests.

+
+
+

In this sense, one may find a good approach bypassing inc external action using a mock plan which is useful to abstract complexity that is not necessary in the current context.

+
+
+
+
+!do_something_with_a_counter
+    <-
+    !do_inc;
+    ?count(N);
+    .log(warning,"Counter state ",N);
+.
+
++!do_inc
+    <-
+    inc;
+.
+
+{ include("$jacamoJar/templates/common-cartago.asl") }
+{ include("$jacamoJar/templates/common-moise.asl") }
+
+
+
+

To test it, we can create a tester agent src/test/jason/asl/test_alice.asl which the code is as below.

+
+
+

In this implementation, the plan !do_inc which is triggering the external action inc is being mocked.

+
+
+

We can bypass a plan adding a mock plan on the beginning of agent’s plans library. Since it has same functor and it is on the top, the agent by default will use the mock plan.

+
+
+
+
{ include("$jasonJar/test/jason/inc/tester_agent.asl") }
+{ include("alice.asl") }
+
+count(5).
+
+@[test]
++!test_do_something_with_a_counter
+    <-
+    ?count(N0);
+
+    !assert_equals(5,N0);
+    .add_plan({ +!do_inc :
+        count(N)
+        <-
+        -+count(N+1);
+    }, self, begin);
+
+    !do_something_with_a_counter;
+
+    ?count(N1);
+    !assert_equals(6,N1);
+.
+
+
+
+
+

Additional info

+
+
    +
  • +

    The default test folder src/test/jason/asl should only have tester agents, otherwise statistics will fail.

    +
  • +
  • +

    Files you want to include into your tester agents can be placed into src/test/jason/inc, the content of this folder is not counted into statistics.

    +
  • +
  • +

    Two similar assertions done in the same plan will not be counted since they would have same signatures.

    +
  • +
+
+
+
+
+
+

The library

+
+
+

The library provides assertion plans, which can be found in test_assert.asl file.

+
+
+

An alternative use of the test tools is to do not use the management engine, instead, just include test_assert.asl to any agent.

+
+
+
+
{ include("$jasonJar/test/jason/inc/test_assert.asl") }
+
+
+
+

The results for assertions will be displayed as ordinary printed messages generated by the agent.

+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/getting-started/VacuumCleaning-1.zip b/tutorials/getting-started/VacuumCleaning-1.zip new file mode 100644 index 00000000..58a87060 Binary files /dev/null and b/tutorials/getting-started/VacuumCleaning-1.zip differ diff --git a/tutorials/getting-started/VacuumCleaning-1/VCWorld.java b/tutorials/getting-started/VacuumCleaning-1/VCWorld.java new file mode 100644 index 00000000..ca6f917d --- /dev/null +++ b/tutorials/getting-started/VacuumCleaning-1/VCWorld.java @@ -0,0 +1,176 @@ +import jason.asSyntax.*; +import jason.environment.*; +import java.util.logging.*; +import java.util.*; +import javax.swing.*; +import java.awt.*; +import javax.swing.border.*; + +/** + * Simple Vacuum cleaning environment + * + * @author Jomi + * + */ +public class VCWorld extends Environment { + + /** world model */ + private boolean[][] dirty = + { { true, true }, // all dirty + { true, true } + }; + + private int vcx = 0; // the vacuum cleaner location + private int vcy = 0; + + private Object modelLock = new Object(); + + /** general delegations */ + private HouseGUI gui = new HouseGUI(); + private Logger logger = Logger.getLogger("env."+VCWorld.class.getName()); + private Random r = new Random(); + + /** constant terms used for perception */ + private static final Literal lPos1 = ASSyntax.createLiteral("pos", ASSyntax.createNumber(1)); + private static final Literal lPos2 = ASSyntax.createLiteral("pos", ASSyntax.createNumber(2)); + private static final Literal lPos3 = ASSyntax.createLiteral("pos", ASSyntax.createNumber(3)); + private static final Literal lPos4 = ASSyntax.createLiteral("pos", ASSyntax.createNumber(4)); + private static final Literal lDirty = ASSyntax.createLiteral("dirty"); + private static final Literal lClean = ASSyntax.createLiteral("clean"); + + public VCWorld() { + createPercept(); + + // create a thread to add dirty + new Thread() { + public void run() { + try { + while (isRunning()) { + // add random dirty + if (r.nextInt(100) < 20) { + dirty[r.nextInt(2)][r.nextInt(2)] = true; + gui.paint(); + createPercept(); + } + Thread.sleep(1000); + } + } catch (Exception e) {} + } + } .start(); + } + + /** create the agents perceptions based on the world model */ + private void createPercept() { + // remove previous perception + clearPercepts(); + + if (vcx == 0 && vcy == 0) { + addPercept(lPos1); + } else if (vcx == 1 && vcy == 0) { + addPercept(lPos2); + } else if (vcx == 0 && vcy == 1) { + addPercept(lPos3); + } else if (vcx == 1 && vcy == 1) { + addPercept(lPos4); + } + + if (dirty[vcx][vcy]) { + addPercept(lDirty); + } else { + addPercept(lClean); + } + } + + @Override + public boolean executeAction(String ag, Structure action) { + logger.info("doing "+action); + + try { + Thread.sleep(500); // slow down the execution + } catch (Exception e) {} + + synchronized (modelLock) { + // Change the world model based on action + if (action.getFunctor().equals("suck")) { + if (dirty[vcx][vcy]) { + dirty[vcx][vcy] = false; + } else { + logger.info("suck in a clean location!"); + Toolkit.getDefaultToolkit().beep(); + } + } else if (action.getFunctor().equals("left")) { + if (vcx > 0) { + vcx--; + } + } else if (action.getFunctor().equals("right")) { + if (vcx < 1) { + vcx++; + } + } else if (action.getFunctor().equals("up")) { + if (vcy > 0) { + vcy--; + } + } else if (action.getFunctor().equals("down")) { + if (vcy < 1) { + vcy++; + } + } else { + logger.info("The action "+action+" is not implemented!"); + return false; + } + } + + createPercept(); // update agents perception for the new world state + gui.paint(); + return true; + } + + @Override + public void stop() { + super.stop(); + gui.setVisible(false); + } + + + /* a simple GUI */ + class HouseGUI extends JFrame { + JLabel[][] labels; + + HouseGUI() { + super("Domestic Robot"); + labels = new JLabel[dirty.length][dirty.length]; + getContentPane().setLayout(new GridLayout(labels.length, labels.length)); + for (int j = 0; j < labels.length; j++) { + for (int i = 0; i < labels.length; i++) { + labels[i][j] = new JLabel(); + labels[i][j].setPreferredSize(new Dimension(180,180)); + labels[i][j].setHorizontalAlignment(JLabel.CENTER); + labels[i][j].setBorder(new EtchedBorder()); + getContentPane().add(labels[i][j]); + } + } + pack(); + setVisible(true); + paint(); + } + + void paint() { + synchronized (modelLock) { // do not allow changes in the robot location while painting + for (int i = 0; i < labels.length; i++) { + for (int j = 0; j < labels.length; j++) { + String l = "
"; + if (vcx == i && vcy == j) { + l += "Robot
"; + } + if (dirty[i][j]) { + l += "*kaka*"; + } + l += "
"; + labels[i][j].setText(l); + } + } + } + } + } +} + diff --git a/tutorials/getting-started/VacuumCleaning-1/vacuum-cleaning-1.mas2j b/tutorials/getting-started/VacuumCleaning-1/vacuum-cleaning-1.mas2j new file mode 100644 index 00000000..8adfec4d --- /dev/null +++ b/tutorials/getting-started/VacuumCleaning-1/vacuum-cleaning-1.mas2j @@ -0,0 +1,9 @@ +/* + Jason Exercise: Vacuum Cleaning 1 +*/ + +MAS vacuum_cleaning { + environment: VCWorld + agents: vc; +} + diff --git a/tutorials/getting-started/VacuumCleaning-1/vc.asl b/tutorials/getting-started/VacuumCleaning-1/vc.asl new file mode 100644 index 00000000..1861684a --- /dev/null +++ b/tutorials/getting-started/VacuumCleaning-1/vc.asl @@ -0,0 +1,17 @@ + +/* + +Very simple vacuum cleaner agent in a world that has only four locations. + +Perceptions: +. dirty: the current location has dirty +. clean: the current location is clean +. pos(X): the agent position is X (0 < X < 5). + +Actions: +. suck: clean the current location +. left, right, up, down: move the agent + +*/ + +// TODO: the code of the agent diff --git a/tutorials/getting-started/exercise-answers.txt b/tutorials/getting-started/exercise-answers.txt new file mode 100644 index 00000000..350edee7 --- /dev/null +++ b/tutorials/getting-started/exercise-answers.txt @@ -0,0 +1,171 @@ +There are several solutions for the code of the vacuum cleaner +agent. Here we present and comment on some of them. We start from a very +reactive solution and finish with a more goal-oriented version. + + + +1. First solution + +---------------------------------------- ++dirty <- suck. + ++pos(1) <- right. ++pos(2) <- down. ++pos(3) <- up. ++pos(4) <- left. +---------------------------------------- + +* comments +- this is a reactive agent, which is easy to implement with Jason, + but note that the language is meant for cognitive agents +- as a consequence, all plans have an empty context (normally used + to check the situation currently believed by the agent) + +* problems +- the robot may leave dirt behind, and you will get messages like + [VCWorld] suck in a clean location! +- reason: the events related to location ("+pos(...)") are + selected before the "dirty" event, so the suck action is performed + after the move action in a possibly clean location + + +2. Second solution + +---------------------------------------- +// plans for dirty location ++pos(1) : dirty <- suck; right. ++pos(2) : dirty <- suck; down. ++pos(3) : dirty <- suck; up. ++pos(4) : dirty <- suck; left. + +// plans for clean location ++pos(1) : clean <- right. ++pos(2) : clean <- down. ++pos(3) : clean <- up. ++pos(4) : clean <- left. +---------------------------------------- + +* comments +- again a rather reactive agent +- the selection of plans is based on context (perceptual beliefs + in this case) +- it solves the problems of the previous solution + +* problems +- the moving strategy is coded in two sets of plans, so to change + the strategy we need change all plans +- if you leave the agent running for a long time, it eventually stops. + the reason is that sometimes the robot does not perceive neither + dirty nor clean and thus no plan are selected. The following + code solves that: + +---------------------------------------- +// plans for a dirty location ++pos(1) : dirty <- suck; right. ++pos(2) : dirty <- suck; down. ++pos(3) : dirty <- suck; up. ++pos(4) : dirty <- suck; left. + +// plans for other circumstances ++pos(1) : true <- right. ++pos(2) : true <- down. ++pos(3) : true <- up. ++pos(4) : true <- left. +---------------------------------------- + + +3. Third solution + +---------------------------------------- ++pos(_) : dirty <- suck; !move. ++pos(_) : true <- !move. + +// plans to move ++!move : pos(1) <- right. ++!move : pos(2) <- down. ++!move : pos(3) <- up. ++!move : pos(4) <- left. +---------------------------------------- + +* comments +- the moving strategy is re-factored to use a (perform) goal + (the goal '!move') +- this agent reacts to the perception of its location, but the + reaction creates a new goal (to move) +- to change the moving strategy we only need to change the + way the goal "move" is achieved (the plans for triggering + event '+!move') + +* problem +- suppose that actions may fail, in this case, after performing 'up', + for example, the agent may remain in the same place and then no new + location is perceived: the agent will stop moving + (this is only conceptually a problem since the environment was not + coded to simulate action failures, i.e., the environment model is + deterministic). + + +4. Fourth solution + +---------------------------------------- +!clean. // initial goal + ++!clean : clean <- !move; !clean. ++!clean : dirty <- suck; !move; !clean. +-!clean <- !clean. + ++!move : pos(1) <- right. ++!move : pos(2) <- down. ++!move : pos(3) <- up. ++!move : pos(4) <- left. +---------------------------------------- + +* comments +- this agent is not reactive at all; it has no behaviour which is + triggered by an external event, that is, a perception of change + in the environment (note however that BDI agents typically have + both goal-directed and reactive behaviour) +- instead, the agent has a *maintenance goal* (the '!clean' goal) and + is blindly committed towards it (if it ever fails, the goal is just + adopted again -- see below) +- this goal is implemented by a form of infinite loop using recursive + plans: all plans to achieve 'clean' finish by adding 'clean' itself + as a new goal +- if anything fails in an attempt to achieve the goal 'clean', the + contingency plan (-!clean) reintroduces the goal again at all + circumstances (note the empty plan context); this is what causes the + "blind commitment" behaviour mentioned above +- this agent is thus more 'robust' against action failures + +- the use of goals also allows us to easily code plans that handle + other goals. For instance, suppose we want to code the robot in a way + that after 2 seconds of cleaning, it makes a break of 1 second. This + behaviour can be easily code as follows: + + +---------------------------------------- +!clean. // initial goal to clean +!pause. // initial goal to break + ++!clean : clean <- !move; !clean. ++!clean : dirty <- suck; !clean. +-!clean <- !clean. + ++!move : pos(1) <- right. ++!move : pos(2) <- down. ++!move : pos(3) <- up. ++!move : pos(4) <- left. + ++!pause + <- .wait(2000); // suspend this intention (the pause) for 2 seconds + .suspend(clean); // suspend the clean intention + .print("I'm having a break, alright."); + .wait(1000); // suspend this intention again for 1 second + .print(cleaning); + .resume(clean); // resume the clean intention + !pause. +---------------------------------------- + +Just to see how flexible it is to program with goals, you might want +to try and implement the break strategy for the first (purely reactive) +solution. diff --git a/tutorials/getting-started/figures/JasonEx-CR-ss1.png b/tutorials/getting-started/figures/JasonEx-CR-ss1.png new file mode 100755 index 00000000..02b45aea Binary files /dev/null and b/tutorials/getting-started/figures/JasonEx-CR-ss1.png differ diff --git a/tutorials/getting-started/figures/ambiente.png b/tutorials/getting-started/figures/ambiente.png new file mode 100755 index 00000000..3fa1be43 Binary files /dev/null and b/tutorials/getting-started/figures/ambiente.png differ diff --git a/tutorials/getting-started/figures/bob-ini-code.png b/tutorials/getting-started/figures/bob-ini-code.png new file mode 100644 index 00000000..307bb702 Binary files /dev/null and b/tutorials/getting-started/figures/bob-ini-code.png differ diff --git a/tutorials/getting-started/figures/debug.gif b/tutorials/getting-started/figures/debug.gif new file mode 100755 index 00000000..7478dcf9 Binary files /dev/null and b/tutorials/getting-started/figures/debug.gif differ diff --git a/tutorials/getting-started/figures/greeting.png b/tutorials/getting-started/figures/greeting.png new file mode 100644 index 00000000..de434a6a Binary files /dev/null and b/tutorials/getting-started/figures/greeting.png differ diff --git a/tutorials/getting-started/figures/overview.png b/tutorials/getting-started/figures/overview.png new file mode 100755 index 00000000..113426c1 Binary files /dev/null and b/tutorials/getting-started/figures/overview.png differ diff --git a/tutorials/getting-started/figures/screen-mars.png b/tutorials/getting-started/figures/screen-mars.png new file mode 100644 index 00000000..e18e4307 Binary files /dev/null and b/tutorials/getting-started/figures/screen-mars.png differ diff --git a/tutorials/getting-started/figures/screen-masconsole.png b/tutorials/getting-started/figures/screen-masconsole.png new file mode 100644 index 00000000..b81804a7 Binary files /dev/null and b/tutorials/getting-started/figures/screen-masconsole.png differ diff --git a/tutorials/getting-started/figures/screen-mindinsp.png b/tutorials/getting-started/figures/screen-mindinsp.png new file mode 100644 index 00000000..1854cd6d Binary files /dev/null and b/tutorials/getting-started/figures/screen-mindinsp.png differ diff --git a/tutorials/getting-started/figures/suspend.png b/tutorials/getting-started/figures/suspend.png new file mode 100755 index 00000000..b34857ba Binary files /dev/null and b/tutorials/getting-started/figures/suspend.png differ diff --git a/tutorials/getting-started/index.html b/tutorials/getting-started/index.html new file mode 100644 index 00000000..708c27a9 --- /dev/null +++ b/tutorials/getting-started/index.html @@ -0,0 +1,993 @@ + + + + + + + +Getting started with Jason + + + + + + + +
+
+
+
+

This document aims to help you install and run Jason, as well as +developing a simple multi-agent system using Jason.

+
+
+
+
+

Installation and Configuration

+
+
+

This tutorial uses VSCode + Jason. See here how to configure them.

+
+
+
+
+

Execution of an example

+
+
+

Jason comes with many examples and demos. The examples are +multi-agent system applications for simple scenarios. The demos are +meant simply to show how to use some useful features of Jason.

+
+
+

We will now run the classic Cleaning Robots example:

+
+
+
+This is a very simple example, showing a robot that searches the + whole environment (represented as a grid) for pieces of garbage, and + when one is found, it takes it to another robot, located in the + centre of the grid, where there is an incinerator; the moving robot + then goes back to the place where the last piece of garbage was + found and continues the search from there. It is based on the + original scenario that Anand Rao used when he introduced the + AgentSpeak language. +
+
+
+

+ +align:center

+
+
+

All Jason projects have a configuration file that ends with + .mas2j, so to open the cleaning robots example, open the + folder examples/cleaning-robots in VSCode. You’ll find + in the folder where you installed Jason.

+
+
+

screen mars

+
+
+

The project file defines the Java + class that implements the environment (MarsEnv), and the agents that + belong to this application (agent r1 searches for pieces of garbage and + r2 incinerates them).

+
+
+

To execute this application, in the VSCode terminal, type

+
+
+
+
jason mars.mas2j
+
+
+
+

Two windows are opened, the + first is the application GUI and the second is the Jason MAS + Console where all print messages are shown (MAS is a common + abbreviation of Multi-Agent Systems).

+
+
+

screen masconsole

+
+
+

To stop the MAS execution, click + on suspend in the MAS Console.

+
+
+
+
+

Creation of a simple example

+
+
+

In this section we will create a new and simple example where two +agents, bob and alice, exchange greeting messages.

+
+
+
    +
  • +

    Create a new application called greeting with the command:

    +
    +
    +
    jason app create greeting
    +
    +
    +
  • +
  • +

    Open the folder greeting in VSCode and you you notice the initial project is created with two agents already.

    +
    +

    greeting

    +
    +
  • +
  • +

    As you can see, there is a skeleton for the agent’s code: the +agent has no beliefs, but an initial goal start and one +plan to achieve this goal. The plan simply prints something when +triggered.

    +
    +

    bob ini code

    +
    +
  • +
  • +

    We will now change agent alice 's code so that it sends a “hello” +message to bob. To send messages, an internal action +called .send is used:

    +
    +
    src/agt/alice.asl
    +
    +
    !start.
    +
    ++!start : true <- .send(bob,tell,hello).
    +
    +
    +
    +

    In bob code, we remove the start goal (and its + related plan), leaving its program empty:

    +
    +
    +
    src/agt/bob.asl
    +
    +
    // Agent bob in project greeting.mas2j
    +
    +
    +
  • +
  • +

    You can now run the application. There is no output! However, in +the MAS Console, click on the debug +button debug and then select, in a new +windows named Jason Mind Inspector (also available at http://localhost:3272) the agent bob (if the +agent’s list is empty, click once in the run button). The mind +inspector for bob will look as follows:

    +
    +

    screen mindinsp

    +
    +
    +

    Note the bob has a belief hello[source(alice)], + which means that it received alice’s message.

    +
    +
  • +
  • +

    Suppose now that we want bob to react to this +message. Since the received message implies a belief addition, an +event like +hello[source(alice)] is produced and may trigger +the execution of the following plan:

    +
    +
    src/agt/bob.asl
    +
    +
    // Agent bob in project greeting.mas2j
    +
    ++hello[source(A)] <- .print("I received a 'hello' from ",A).
    +
    +
    +
    +

    In the plan, A is a variable that contains the name of the + sender. In AgentSpeak, as in Prolog, identifiers that start with + uppercase letters are variables.

    +
    +
    +

    When you run the new version, the output will be:

    +
    +
    +
    +
    [bob] I received a 'hello' from alice
    +
    +
    +
  • +
  • +

    Since bob is a polite agent, we will now make it send a +hello back to alice:

    +
    +
    src/agt/bob.asl
    +
    +
    +hello[source(A)]
    +  <- .print("I received a 'hello' from ",A);
    +     .send(A,tell,hello).
    +
    +
    +
    +

    and alice does the same:

    +
    +
    +
    src/agt/alice.asl
    +
    +
    !start.
    +
    ++!start : true <- .send(bob,tell,hello).
    +
    ++hello[source(A)]
    +  <- .print("I receive an hello from ",A);
    +     .send(A,tell,hello).
    +
    +
    +
    +

    Before running the system, think what you would expect to happen. + Perhaps the agents will enter a kind of greeting loop?

    +
    +
  • +
  • +

    Run the system and you will realise that there is no loop! The +reason is because when bob receives the second hello, it already has +this belief in its belief base (BB). Since nothing changed in the +BB, no event was produced, and thus no plan triggered.

    +
  • +
  • +

    If you want to use JADE as the infrastructure, execute the following commands:

    +
    +
    +
    jason app add-gradle
    +./gradlew runJade
    +
    +
    +
  • +
+
+
+
+
+

An example with environment

+
+
+

In this section we will create a system where one agent will perform +one action in a simulated environment.

+
+
+
    +
  • +

    In the previous application, add one agent called liz with the following code:

    +
    +
    +
    jason app add-agent liz
    +
    +
    +
    +

    then edit the code of the agent to:

    +
    +
    +
    src/agt/liz.asl
    +
    +
    // Agent liz in project testeenv.mas2j
    +
    +!start.
    +
    ++!start : true <- burn.
    +
    +
    +
    +

    The plan’s body has only the action, burn. Action here is + meant to an environment action (i.e., something that changes + the state of the environment), and not internal actions (the ones + which starts with a dot, or have a dot anywhere in their name).

    +
    +
  • +
  • +

    The implementation of the burn action is done in an environment +class. The project has an initial implementation of the environment in src/env/example/Env.java.

    +
    +

    A skeleton for this class is added by Jason. Change it to be + exactly as follows:

    +
    +
    +
    src/env/example/Env.java
    +
    +
    package example;
    +
    +import jason.asSyntax.*;
    +import jason.environment.*;
    +import java.util.logging.*;
    +
    +public class Env extends Environment {
    +
    +  private Logger logger = Logger.getLogger("testenv.mas2j."+Env.class.getName());
    +
    +  /** Called before the MAS execution with the args informed in .mas2j */
    +  @Override
    +  public void init(String[] args) {    }
    +
    +  @Override
    +  public boolean executeAction(String agName, Structure action) {
    +    if (action.getFunctor().equals("burn")) {
    +      addPercept(Literal.parseLiteral("fire"));
    +      return true;
    +    } else {
    +      logger.info("executing: "+action+", but not implemented!");
    +      return false;
    +    }
    +  }
    +
    +  /** Called before the end of MAS execution */
    +  @Override
    +  public void stop() {
    +    super.stop();
    +  }
    +}
    +
    +
    +
    +

    When an agent attempts to execute an environment action, the method + executeAction of this class is executed. In this + implementation, if the action burn is executed, a new + percept fire becomes available to all agents.

    +
    +
  • +
  • +

    Agent liz can now react to the perception of fire:

    +
    +
    +
    !start.
    +
    ++!start : true <- burn.
    +
    ++fire <- run.
    +
    +
    +
    +

    (The implementation of the run action is left as an exercise.)

    +
    +
  • +
+
+
+
+
+

Exercise

+
+
+

Imagine a very simple environment formed by 4 locations (identified by 1, 2, 3, +and 4) as in the figure below:

+
+
+

ambiente

+
+
+

A vacuum-cleaner robot should be programmed in AgentSpeak to maintain +the environment clean. The available actions for the robot are:

+
+
+
    +
  • +

    suck: remove dirt at the robot’s position;

    +
  • +
  • +

    left: move the left;

    +
  • +
  • +

    right: move to right;

    +
  • +
  • +

    up: move up;

    +
  • +
  • +

    down: move down.

    +
  • +
+
+
+

To help the robot decide what action to take, the following percepts +are given:

+
+
+
    +
  • +

    dirty: the robot is in a dirty location;

    +
  • +
  • +

    clean: the robot is in a clean location;

    +
  • +
  • +

    pos(X): the location of the robot is X (0 < X < 5).

    +
  • +
+
+
+

The following diagram, using the Prometheus notation, illustrates the +interactions between the robot and the environment.

+
+
+

overview

+
+
+

An implementation of the environment class is available +here.

+
+
+

Some tips

+
+
+

You can start programming your agent by thinking about how it should +react to the available perception. For instance, what it should do +when it perceives "dirty"? The action "suck", of course! In AgentSpeak, +we program this reaction by means of a plan as follows:

+
+
+
+
+dirty <- suck. // when dirty is perceived, do the action suck
+
+
+
+

So, an initial and very reactive agent can simply react to every +perception and be programmed as shown below (replace "someaction" for +the action you think is the most suitable, you might also want to +remove some of the plans):

+
+
+
+
+dirty  <- someaction.
++clean  <- someaction.
++pos(1) <- someaction.
++pos(2) <- someaction.
++pos(3) <- someaction.
++pos(4) <- someaction.
+
+
+
+

Since all perception is also included in the belief base, they can +also be used to select the right plan, as in the following example:

+
+
+
+
+pos(1) : clean <- someaction.   // whenever I perceive I'm in pos(1) and
+                                 // I believe that my position is clean,
+                                 // do some action.
+
+
+
+

You will soon realise that this reactive approach has some limitation +in defining a good behaviour for our vacuum cleaner. In fact, this agent +should be defined has having goals, in particular, a persistent +goal of maintaining the house clean. The easiest way to define a +persistent goal is by a recursive plan; for example, the code below +implements the persistent goal (represented by p) of printing out "a":

+
+
+
+
!p.                   // initial goal
++!p <- .print(a); !p. // to achieve the goal p, print "a"
+                      // and after has p as a new goal.
+
+
+
+

Some comments on possible solutions for this exercise are available +here.

+
+
+

This document has shown a very limited range of Jason’s features; the +next section contains references where you can find further +information.

+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/getting-started/publish.sh b/tutorials/getting-started/publish.sh new file mode 100755 index 00000000..581128f4 --- /dev/null +++ b/tutorials/getting-started/publish.sh @@ -0,0 +1,11 @@ +IMAGE=jomifred/adoc +docker run --rm -i --user="$(id -u):$(id -g)" --net=none -v "$PWD":/app "$IMAGE" asciidoctor -r /pygments_init.rb readme.adoc +docker run --rm -i --user="$(id -u):$(id -g)" --net=none -v "$PWD":/app "$IMAGE" asciidoctor -r /pygments_init.rb shell-based.adoc + +cp readme.html index.html + +scp -r *.html $USERSF,jason@web.sf.net:/home/project-web/jason/htdocs/doc/tutorials/getting-started + +#zip -r ../../getting-started/VacuumCleaning-1.zip VacuumCleaning-1/*.asl VacuumCleaning-1/*.mas2j VacuumCleaning-1/*.java +#scp -r figures jomifred,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/mini-tutorial/getting-started +#scp exercise-answers.txt jomifred,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/mini-tutorial/getting-started diff --git a/tutorials/getting-started/readme.html b/tutorials/getting-started/readme.html new file mode 100644 index 00000000..708c27a9 --- /dev/null +++ b/tutorials/getting-started/readme.html @@ -0,0 +1,993 @@ + + + + + + + +Getting started with Jason + + + + + + + +
+
+
+
+

This document aims to help you install and run Jason, as well as +developing a simple multi-agent system using Jason.

+
+
+
+
+

Installation and Configuration

+
+
+

This tutorial uses VSCode + Jason. See here how to configure them.

+
+
+
+
+

Execution of an example

+
+
+

Jason comes with many examples and demos. The examples are +multi-agent system applications for simple scenarios. The demos are +meant simply to show how to use some useful features of Jason.

+
+
+

We will now run the classic Cleaning Robots example:

+
+
+
+This is a very simple example, showing a robot that searches the + whole environment (represented as a grid) for pieces of garbage, and + when one is found, it takes it to another robot, located in the + centre of the grid, where there is an incinerator; the moving robot + then goes back to the place where the last piece of garbage was + found and continues the search from there. It is based on the + original scenario that Anand Rao used when he introduced the + AgentSpeak language. +
+
+
+

+ +align:center

+
+
+

All Jason projects have a configuration file that ends with + .mas2j, so to open the cleaning robots example, open the + folder examples/cleaning-robots in VSCode. You’ll find + in the folder where you installed Jason.

+
+
+

screen mars

+
+
+

The project file defines the Java + class that implements the environment (MarsEnv), and the agents that + belong to this application (agent r1 searches for pieces of garbage and + r2 incinerates them).

+
+
+

To execute this application, in the VSCode terminal, type

+
+
+
+
jason mars.mas2j
+
+
+
+

Two windows are opened, the + first is the application GUI and the second is the Jason MAS + Console where all print messages are shown (MAS is a common + abbreviation of Multi-Agent Systems).

+
+
+

screen masconsole

+
+
+

To stop the MAS execution, click + on suspend in the MAS Console.

+
+
+
+
+

Creation of a simple example

+
+
+

In this section we will create a new and simple example where two +agents, bob and alice, exchange greeting messages.

+
+
+
    +
  • +

    Create a new application called greeting with the command:

    +
    +
    +
    jason app create greeting
    +
    +
    +
  • +
  • +

    Open the folder greeting in VSCode and you you notice the initial project is created with two agents already.

    +
    +

    greeting

    +
    +
  • +
  • +

    As you can see, there is a skeleton for the agent’s code: the +agent has no beliefs, but an initial goal start and one +plan to achieve this goal. The plan simply prints something when +triggered.

    +
    +

    bob ini code

    +
    +
  • +
  • +

    We will now change agent alice 's code so that it sends a “hello” +message to bob. To send messages, an internal action +called .send is used:

    +
    +
    src/agt/alice.asl
    +
    +
    !start.
    +
    ++!start : true <- .send(bob,tell,hello).
    +
    +
    +
    +

    In bob code, we remove the start goal (and its + related plan), leaving its program empty:

    +
    +
    +
    src/agt/bob.asl
    +
    +
    // Agent bob in project greeting.mas2j
    +
    +
    +
  • +
  • +

    You can now run the application. There is no output! However, in +the MAS Console, click on the debug +button debug and then select, in a new +windows named Jason Mind Inspector (also available at http://localhost:3272) the agent bob (if the +agent’s list is empty, click once in the run button). The mind +inspector for bob will look as follows:

    +
    +

    screen mindinsp

    +
    +
    +

    Note the bob has a belief hello[source(alice)], + which means that it received alice’s message.

    +
    +
  • +
  • +

    Suppose now that we want bob to react to this +message. Since the received message implies a belief addition, an +event like +hello[source(alice)] is produced and may trigger +the execution of the following plan:

    +
    +
    src/agt/bob.asl
    +
    +
    // Agent bob in project greeting.mas2j
    +
    ++hello[source(A)] <- .print("I received a 'hello' from ",A).
    +
    +
    +
    +

    In the plan, A is a variable that contains the name of the + sender. In AgentSpeak, as in Prolog, identifiers that start with + uppercase letters are variables.

    +
    +
    +

    When you run the new version, the output will be:

    +
    +
    +
    +
    [bob] I received a 'hello' from alice
    +
    +
    +
  • +
  • +

    Since bob is a polite agent, we will now make it send a +hello back to alice:

    +
    +
    src/agt/bob.asl
    +
    +
    +hello[source(A)]
    +  <- .print("I received a 'hello' from ",A);
    +     .send(A,tell,hello).
    +
    +
    +
    +

    and alice does the same:

    +
    +
    +
    src/agt/alice.asl
    +
    +
    !start.
    +
    ++!start : true <- .send(bob,tell,hello).
    +
    ++hello[source(A)]
    +  <- .print("I receive an hello from ",A);
    +     .send(A,tell,hello).
    +
    +
    +
    +

    Before running the system, think what you would expect to happen. + Perhaps the agents will enter a kind of greeting loop?

    +
    +
  • +
  • +

    Run the system and you will realise that there is no loop! The +reason is because when bob receives the second hello, it already has +this belief in its belief base (BB). Since nothing changed in the +BB, no event was produced, and thus no plan triggered.

    +
  • +
  • +

    If you want to use JADE as the infrastructure, execute the following commands:

    +
    +
    +
    jason app add-gradle
    +./gradlew runJade
    +
    +
    +
  • +
+
+
+
+
+

An example with environment

+
+
+

In this section we will create a system where one agent will perform +one action in a simulated environment.

+
+
+
    +
  • +

    In the previous application, add one agent called liz with the following code:

    +
    +
    +
    jason app add-agent liz
    +
    +
    +
    +

    then edit the code of the agent to:

    +
    +
    +
    src/agt/liz.asl
    +
    +
    // Agent liz in project testeenv.mas2j
    +
    +!start.
    +
    ++!start : true <- burn.
    +
    +
    +
    +

    The plan’s body has only the action, burn. Action here is + meant to an environment action (i.e., something that changes + the state of the environment), and not internal actions (the ones + which starts with a dot, or have a dot anywhere in their name).

    +
    +
  • +
  • +

    The implementation of the burn action is done in an environment +class. The project has an initial implementation of the environment in src/env/example/Env.java.

    +
    +

    A skeleton for this class is added by Jason. Change it to be + exactly as follows:

    +
    +
    +
    src/env/example/Env.java
    +
    +
    package example;
    +
    +import jason.asSyntax.*;
    +import jason.environment.*;
    +import java.util.logging.*;
    +
    +public class Env extends Environment {
    +
    +  private Logger logger = Logger.getLogger("testenv.mas2j."+Env.class.getName());
    +
    +  /** Called before the MAS execution with the args informed in .mas2j */
    +  @Override
    +  public void init(String[] args) {    }
    +
    +  @Override
    +  public boolean executeAction(String agName, Structure action) {
    +    if (action.getFunctor().equals("burn")) {
    +      addPercept(Literal.parseLiteral("fire"));
    +      return true;
    +    } else {
    +      logger.info("executing: "+action+", but not implemented!");
    +      return false;
    +    }
    +  }
    +
    +  /** Called before the end of MAS execution */
    +  @Override
    +  public void stop() {
    +    super.stop();
    +  }
    +}
    +
    +
    +
    +

    When an agent attempts to execute an environment action, the method + executeAction of this class is executed. In this + implementation, if the action burn is executed, a new + percept fire becomes available to all agents.

    +
    +
  • +
  • +

    Agent liz can now react to the perception of fire:

    +
    +
    +
    !start.
    +
    ++!start : true <- burn.
    +
    ++fire <- run.
    +
    +
    +
    +

    (The implementation of the run action is left as an exercise.)

    +
    +
  • +
+
+
+
+
+

Exercise

+
+
+

Imagine a very simple environment formed by 4 locations (identified by 1, 2, 3, +and 4) as in the figure below:

+
+
+

ambiente

+
+
+

A vacuum-cleaner robot should be programmed in AgentSpeak to maintain +the environment clean. The available actions for the robot are:

+
+
+
    +
  • +

    suck: remove dirt at the robot’s position;

    +
  • +
  • +

    left: move the left;

    +
  • +
  • +

    right: move to right;

    +
  • +
  • +

    up: move up;

    +
  • +
  • +

    down: move down.

    +
  • +
+
+
+

To help the robot decide what action to take, the following percepts +are given:

+
+
+
    +
  • +

    dirty: the robot is in a dirty location;

    +
  • +
  • +

    clean: the robot is in a clean location;

    +
  • +
  • +

    pos(X): the location of the robot is X (0 < X < 5).

    +
  • +
+
+
+

The following diagram, using the Prometheus notation, illustrates the +interactions between the robot and the environment.

+
+
+

overview

+
+
+

An implementation of the environment class is available +here.

+
+
+

Some tips

+
+
+

You can start programming your agent by thinking about how it should +react to the available perception. For instance, what it should do +when it perceives "dirty"? The action "suck", of course! In AgentSpeak, +we program this reaction by means of a plan as follows:

+
+
+
+
+dirty <- suck. // when dirty is perceived, do the action suck
+
+
+
+

So, an initial and very reactive agent can simply react to every +perception and be programmed as shown below (replace "someaction" for +the action you think is the most suitable, you might also want to +remove some of the plans):

+
+
+
+
+dirty  <- someaction.
++clean  <- someaction.
++pos(1) <- someaction.
++pos(2) <- someaction.
++pos(3) <- someaction.
++pos(4) <- someaction.
+
+
+
+

Since all perception is also included in the belief base, they can +also be used to select the right plan, as in the following example:

+
+
+
+
+pos(1) : clean <- someaction.   // whenever I perceive I'm in pos(1) and
+                                 // I believe that my position is clean,
+                                 // do some action.
+
+
+
+

You will soon realise that this reactive approach has some limitation +in defining a good behaviour for our vacuum cleaner. In fact, this agent +should be defined has having goals, in particular, a persistent +goal of maintaining the house clean. The easiest way to define a +persistent goal is by a recursive plan; for example, the code below +implements the persistent goal (represented by p) of printing out "a":

+
+
+
+
!p.                   // initial goal
++!p <- .print(a); !p. // to achieve the goal p, print "a"
+                      // and after has p as a new goal.
+
+
+
+

Some comments on possible solutions for this exercise are available +here.

+
+
+

This document has shown a very limited range of Jason’s features; the +next section contains references where you can find further +information.

+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/hello-bdi/code/Calendar.java b/tutorials/hello-bdi/code/Calendar.java new file mode 100644 index 00000000..fe3d867d --- /dev/null +++ b/tutorials/hello-bdi/code/Calendar.java @@ -0,0 +1,70 @@ +import jason.asSyntax.ASSyntax; +import jason.asSyntax.Term; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; + +import cartago.INTERNAL_OPERATION; +import cartago.ObsProperty; +import cartago.tools.GUIArtifact; + +public class Calendar extends GUIArtifact { + Term[] days = { + ASSyntax.createAtom("sunday"), + ASSyntax.createAtom("monday"), + ASSyntax.createAtom("tuesday"), + ASSyntax.createAtom("wednesday"), + ASSyntax.createAtom("thursday"), + ASSyntax.createAtom("friday"), + ASSyntax.createAtom("saturday") + }; + + public void setup() { + defineObsProperty("today", days[0]); + initGUI(); + } + + JSlider s = new JSlider(); + + void initGUI() { + JFrame f = new JFrame("Calendar"); + + s.setMinimum(0); + s.setMaximum(6); + s.setPaintTicks(true); + s.setPaintLabels(true); + s.setValue(0); + Dictionary lbs = new Hashtable(); + lbs.put(0, new JLabel("S")); + lbs.put(1, new JLabel("M")); + lbs.put(2, new JLabel("T")); + lbs.put(3, new JLabel("W")); + lbs.put(4, new JLabel("T")); + lbs.put(5, new JLabel("F")); + lbs.put(6, new JLabel("S")); + s.setLabelTable(lbs); + linkChangeEventToOp(s, "updateDay"); + + f.add(s); + f.pack(); + f.setVisible(true); + } + + @INTERNAL_OPERATION + void updateDay(ChangeEvent ev) { + JSlider source = (JSlider) ev.getSource(); + if (!source.getValueIsAdjusting()) { + try { + ObsProperty prop = getObsProperty("today"); + prop.updateValue(days[(int) s.getValue()]); + } catch (Exception e2) { + e2.printStackTrace(); + } + } + } +} diff --git a/tutorials/hello-bdi/code/alice.asl b/tutorials/hello-bdi/code/alice.asl new file mode 100644 index 00000000..d5fb2b71 --- /dev/null +++ b/tutorials/hello-bdi/code/alice.asl @@ -0,0 +1,20 @@ +!start. + ++!start + <- .send(bob,tell,happy(bob)); + .send(bob,tell,happy(alice1)); + .send(bob,tell,happy(alice2)); + .send(bob,tell,happy(alice3)); + .send(bob,tell,happy(alice4)); + .wait(1000); + .send(bob,tell,happy(morgana)); + .wait(1000); + /*.send(bob,tell,today(wednesday)); + .wait(3000); + .send(bob,tell,today(friday)); + .wait(3000); + .send(bob,tell,today(saturday)); + */ + //.send(bob,untell,happy(bob)); + .wait(1000); + .send(bob,untell,happy(alice)). diff --git a/tutorials/hello-bdi/code/bdi_hw.mas2j b/tutorials/hello-bdi/code/bdi_hw.mas2j new file mode 100644 index 00000000..e26abefb --- /dev/null +++ b/tutorials/hello-bdi/code/bdi_hw.mas2j @@ -0,0 +1,10 @@ +/* Jason Project */ + +MAS bdi_hw { + environment: jaca.CartagoEnvironment + + agents: + bob agentArchClass jaca.CAgentArch; + alice agentArchClass jaca.CAgentArch; + +} diff --git a/tutorials/hello-bdi/code/bob.asl b/tutorials/hello-bdi/code/bob.asl new file mode 100644 index 00000000..b9bc372f --- /dev/null +++ b/tutorials/hello-bdi/code/bob.asl @@ -0,0 +1,33 @@ +sincere(alice). + +!create_calendar. ++!create_calendar <- makeArtifact("c","Calendar",[],AId); focus(AId). + ++happy(H)[source(A)] : sincere(A)[source(self)] & .my_name(H) <- !say(hello(A)). ++happy(H) : not .my_name(H) <- !say(i_envy(H)). + +-happy(H)[source(A)] + <- .drop_intention(say(hello(A))); + .drop_intention(say(i_envy(H))). + ++!say(X) : today(friday) <- .print(X,"!!!!!"); .wait(500); !say(X). ++!say(X) : not today(monday) <- .print(X); .wait(math.random(400)+100); !say(X). ++!say(X) <- !say(X). + ++today(wednesday) <- .print("**** Let's slow down.... **** (only 2 intentions)"); !enter_lazy_mode. ++today(friday) <- .print("**** Let's finish the work!"); !resume_all. ++today(saturday) <- .print("**** weekend!"); .drop_all_intentions. + ++!enter_lazy_mode + : .findall(A, .intend(say(A)), [_,_|L]) // the agent has two say intentions + <- for ( .member(I,L) ) { + .suspend(say(I)); + }. ++!enter_lazy_mode. + + ++!resume_all + : .count( .intend(A) & .suspended(A,R) & .substring("suspended",R), I) & I > 0 + <- .resume(say(_)); + !resume_all. ++!resume_all. diff --git a/tutorials/hello-bdi/hello-bdi-code.zip b/tutorials/hello-bdi/hello-bdi-code.zip new file mode 100644 index 00000000..674cc480 Binary files /dev/null and b/tutorials/hello-bdi/hello-bdi-code.zip differ diff --git a/tutorials/hello-bdi/hello-bdi-code/Calendar.java b/tutorials/hello-bdi/hello-bdi-code/Calendar.java new file mode 100644 index 00000000..fe3d867d --- /dev/null +++ b/tutorials/hello-bdi/hello-bdi-code/Calendar.java @@ -0,0 +1,70 @@ +import jason.asSyntax.ASSyntax; +import jason.asSyntax.Term; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; + +import cartago.INTERNAL_OPERATION; +import cartago.ObsProperty; +import cartago.tools.GUIArtifact; + +public class Calendar extends GUIArtifact { + Term[] days = { + ASSyntax.createAtom("sunday"), + ASSyntax.createAtom("monday"), + ASSyntax.createAtom("tuesday"), + ASSyntax.createAtom("wednesday"), + ASSyntax.createAtom("thursday"), + ASSyntax.createAtom("friday"), + ASSyntax.createAtom("saturday") + }; + + public void setup() { + defineObsProperty("today", days[0]); + initGUI(); + } + + JSlider s = new JSlider(); + + void initGUI() { + JFrame f = new JFrame("Calendar"); + + s.setMinimum(0); + s.setMaximum(6); + s.setPaintTicks(true); + s.setPaintLabels(true); + s.setValue(0); + Dictionary lbs = new Hashtable(); + lbs.put(0, new JLabel("S")); + lbs.put(1, new JLabel("M")); + lbs.put(2, new JLabel("T")); + lbs.put(3, new JLabel("W")); + lbs.put(4, new JLabel("T")); + lbs.put(5, new JLabel("F")); + lbs.put(6, new JLabel("S")); + s.setLabelTable(lbs); + linkChangeEventToOp(s, "updateDay"); + + f.add(s); + f.pack(); + f.setVisible(true); + } + + @INTERNAL_OPERATION + void updateDay(ChangeEvent ev) { + JSlider source = (JSlider) ev.getSource(); + if (!source.getValueIsAdjusting()) { + try { + ObsProperty prop = getObsProperty("today"); + prop.updateValue(days[(int) s.getValue()]); + } catch (Exception e2) { + e2.printStackTrace(); + } + } + } +} diff --git a/tutorials/hello-bdi/hello-bdi-code/bdih.jcm b/tutorials/hello-bdi/hello-bdi-code/bdih.jcm new file mode 100644 index 00000000..fbccefd0 --- /dev/null +++ b/tutorials/hello-bdi/hello-bdi-code/bdih.jcm @@ -0,0 +1,11 @@ +/* + JaCaMo Application File + + JaCaMo 1.0 + July 26, 2021 - 16:00:06 +*/ +mas bdi_hw { + + agent bob + +} diff --git a/tutorials/hello-bdi/hello-bdi-code/bob.asl b/tutorials/hello-bdi/hello-bdi-code/bob.asl new file mode 100644 index 00000000..bc239202 --- /dev/null +++ b/tutorials/hello-bdi/hello-bdi-code/bob.asl @@ -0,0 +1,5 @@ +happy(bob). + +!say(hello). + ++!say(X) : happy(bob) <- .print(X). diff --git a/tutorials/hello-bdi/hello-bdi-code/build.gradle b/tutorials/hello-bdi/hello-bdi-code/build.gradle new file mode 100644 index 00000000..033bf448 --- /dev/null +++ b/tutorials/hello-bdi/hello-bdi-code/build.gradle @@ -0,0 +1,92 @@ +defaultTasks 'run' + +apply plugin: 'java' + +version '1.0' +group 'org.jacamo' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + + +repositories { + maven { url "https://raw.githubusercontent.com/jacamo-lang/mvn-repo/master" } + + maven { url "https://repo.gradle.org/gradle/libs-releases" } + //maven { url "https://jade.tilab.com/maven/" } + + flatDir { dirs 'lib' } + + mavenCentral() +} + +dependencies { + compile group: 'org.jacamo', name: 'jacamo', version: '1.0' +} + +sourceSets { + main { + java { + srcDir 'src/env' + srcDir 'src/agt' + srcDir 'src/org' + srcDir 'src/int' + srcDir 'src/java' + } + resources { + srcDir 'src/resources' + } + } +} + +task run (type: JavaExec, dependsOn: 'classes') { + group ' JaCaMo' + description 'runs the JaCaMo application' + doFirst { + mkdir 'log' + } + mainClass = 'jacamo.infra.JaCaMoLauncher' + args 'bdih.jcm' + // jvmArgs '-Xss15m' + classpath sourceSets.main.runtimeClasspath +} + + +task uberJar(type: Jar, dependsOn: 'classes') { + group ' JaCaMo' + description 'creates a single runnable jar file with all dependencies' + + manifest { + attributes 'Main-Class': 'jacamo.infra.JaCaMoLauncher' + } + baseName = 'jacamo-bdih' // the name must start with jacamo so that jacamo...jar is found in the classpath + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + from (project.projectDir.absolutePath) { + include '**/*.asl' + include '**/*.xml' + include '**/*.ptl' + include '**/*.jcm' + include '*.properties' + } + from (project.buildDir.absolutePath + '/jcm') { + include '**/*' + } + with jar + + doFirst { + copy { + from 'bdih.jcm' + rename 'bdih.jcm','default.jcm' + into project.buildDir.absolutePath + '/jcm' + } + } +} + +clean { + delete 'bin' + delete 'build' + delete 'log' +} diff --git a/tutorials/hello-bdi/hello-bdi-code/gradle/wrapper/gradle-wrapper.jar b/tutorials/hello-bdi/hello-bdi-code/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and b/tutorials/hello-bdi/hello-bdi-code/gradle/wrapper/gradle-wrapper.jar differ diff --git a/tutorials/hello-bdi/hello-bdi-code/gradle/wrapper/gradle-wrapper.properties b/tutorials/hello-bdi/hello-bdi-code/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..da9702f9 --- /dev/null +++ b/tutorials/hello-bdi/hello-bdi-code/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/tutorials/hello-bdi/hello-bdi-code/gradlew b/tutorials/hello-bdi/hello-bdi-code/gradlew new file mode 100755 index 00000000..4f906e0c --- /dev/null +++ b/tutorials/hello-bdi/hello-bdi-code/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/tutorials/hello-bdi/hello-bdi-code/gradlew.bat b/tutorials/hello-bdi/hello-bdi-code/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/tutorials/hello-bdi/hello-bdi-code/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/tutorials/hello-bdi/hello-bdi-code/logging.properties b/tutorials/hello-bdi/hello-bdi-code/logging.properties new file mode 100644 index 00000000..ba017d29 --- /dev/null +++ b/tutorials/hello-bdi/hello-bdi-code/logging.properties @@ -0,0 +1,48 @@ +# JaCaMo Default log configuration +# +# Comment/uncomment the following lines to setup your log +# + +# default Jason MAS Console +handlers = jason.runtime.MASConsoleLogHandler + +# To use the ConsoleHandler, use the following line instead. +#handlers= java.util.logging.ConsoleHandler + +# To also add the FileHandler, use the following line instead. +#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +# Default logging level. Other values are: +# SEVERE (only severe messages) +# WARNING (only warnings and severe messages) +# INFO (normal output) +# FINE (debug level of messages) +.level = INFO + +############################################################ +# Handler specific properties. +# Describes specific configuration info for Handlers. +############################################################ + +# Jason Handler parameters +jason.runtime.MASConsoleLogHandler.level = ALL +jason.runtime.MASConsoleLogHandler.formatter = jason.runtime.MASConsoleLogFormatter +# set one text area for each agent +jason.runtime.MASConsoleLogHandler.tabbed = true +jason.runtime.MASConsoleLogHandler.colors = false + +# default file output is in project's directory. +java.util.logging.FileHandler.pattern = log/mas-%g.log +java.util.logging.FileHandler.limit = 500000 +java.util.logging.FileHandler.count = 10 +java.util.logging.FileHandler.formatter = jason.runtime.MASConsoleLogFormatter +#java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter + +# Limit the message that are printed on the console to FINE and above. +java.util.logging.ConsoleHandler.level = FINE +java.util.logging.ConsoleHandler.formatter = jason.runtime.MASConsoleLogFormatter + +java.level=OFF +javax.level=OFF +sun.level=OFF +jade.level=OFF diff --git a/tutorials/hello-bdi/index.html b/tutorials/hello-bdi/index.html new file mode 100644 index 00000000..544000df --- /dev/null +++ b/tutorials/hello-bdi/index.html @@ -0,0 +1,1290 @@ + + + + + + + + +(BDI) Hello World + + + + + + + +
+
+

Introduction

+
+
+

This programming (mini) tutorial illustrates how the BDI model is +used in the Jason agent-oriented programming +language. We start by a very simple agent code and progress exploring +the BDI features of Jason.

+
+
+

We assume that the reader knows the basic concepts of the BDI model (an +introduction and further references are found at the +Wikipedia). +It is important to know these concepts to be a good Jason programmer, in +the same way that knowing the concepts of and objects and classes is +important for a Java programmer. Very briefly, in the BDI model the +agent has beliefs (based on what it perceives and communicates with +other agents) that can produce desires (states of the world that the +agent wants to achieve). The agent deliberates on its desires and +decides to commit to some (desires to which the agent is committed +become intentions). To satisfy its intentions, the agent executes +plans that lead to action. The behaviour of the agent (i.e., its +actions) is thus explained/caused by what it intends (i.e., the desires +it decided to pursue). An important feature of architectures that +implement the BDI model is that the agent should react to changes in +its environment as soon as possible while keeping its pro-active +(i.e., desires-oriented) behaviour. (Do not worry about all these +high-level anthropomorphic concepts (in italics), we will try to keep +the simplicity of usual hello world programs.)

+
+
+
+
+

Bob (the mentalist)

+
+
+

Agent program

+
+

The Jason program for our agent is the following (since BDI is inspired +in folk psychology, we can name this agent Bob):

+
+
+
+
happy(bob).
+
+!say(hello).
+
++!say(X) : happy(bob) <- .print(X).
+
+
+
+

As we can see, the syntax is far from the usual C, Java, or Python +programs we are used to. For those (rare) guys who have had some contact +with Prolog, maybe it looks a bit familiar. The syntax is indeed +inspired by Prolog, but the objective is different (the output is not +knowledge and the underlying engine is not based on resolution). Let’s +read this program:

+
+
+
    +
  1. +

    The agent has one (initial) belief: happy(bob), included by the +programmer (rather than by perceiving the state of the environment). +This belief can be read as “bob has the property (or predicate) happy”.

    +
  2. +
  3. +

    The agent has one (initial) desire: !say(hello), also included by +the programmer. What follows the symbol ! describes the desire and is +also represented as a Prolog literal.

    +
  4. +
  5. +

    The agent has one plan to achieve the desire say(hello). We can +read this plan as “whenever the agent has the desire to say(X) and +believes that happy(bob), by executing the action .print(X) the +desire is achieved, for any X (which is a variable since it starts +with an uppercase letter, as in Prolog)”.

    +
  6. +
+
+
+

The deliberation process of the BDI model is highly related to plans. +The plan states whether a desire can become an intention by means of +its event and context. In the Bob’s plan, the event is +!say(X) +(what is written before :) and it means the event of having a new +desire to say something. The context is happy(bob) (the part of the +code that goes between : and ) which is a logical formula +evaluated in regards to the current believes of the agent.

+
+
+

The plan also states how to achieve the desire (i.e. the means-end +reasoning part of the BDI model). If the sequence of actions (after +) is successfully executed, the desire is (hopefully) achieved. An +intention in Jason is an instantiated plan that the agent is executing +in order to achieve a desire (also called goal).

+
+
+

This program is interpreted by Jason as follows:

+
+
+
    +
  1. +

    The initial belief is added in the agent belief base (BB).

    +
  2. +
  3. +

    From the initial desire, the event +!say(hello) is added in the +queue of events to be handled by the agent.

    +
  4. +
  5. +

    The plan is included in the plan library (PL) of the agent.

    +
  6. +
  7. +

    A reasoning cycle loop is executed:

    +
    +
      +
    • +

      The event +!say(hello) is selected from the queue.

      +
    • +
    • +

      The above plan is selected (it matches the selected event when the +variable X is bound to hello).

      +
    • +
    • +

      The context of the plan is evaluated as true since it follows from be +BB (i.e. the agent believes happy(bob)).

      +
    • +
    • +

      A new intention is created based on this plan and the X value. The +agent has thus committed itself to the desire to say(hello).

      +
    • +
    • +

      One action of the intention is executed (the .print(hello) command +in this case).

      +
    • +
    • +

      Since the intention has executed all actions, it finishes.

      +
    • +
    +
    +
  8. +
  9. +

    The agent keeps waiting for new events to react to.

    +
  10. +
+
+
+
+

Execution

+
+
    +
  • +

    Create a new project: you can download and initial JaCaMo project; +or create a new one Jason application with JasonCLI: jason app create bdi_hw.

    +
  • +
  • +

    Create agent Bob with the source code above (file bob.asl). The project should +look like:

    + ++++ + + + + + + + + + + + + +
    Jason .mas2j projectJaCaMo .jcm project
    +
    +
    MAS bdi_hw {
    +
    +    agents: bob;
    +
    +}
    +
    +
    +
    +
    mas bdi_hw {
    +
    +    agent bob
    +    // file bob.asl at src/agt under the project directory
    +
    +}
    +
    +
    +
  • +
  • +

    Run the project. In the case of JaCaMo, run the script ./gradlew; in case of Jason jason bdi_hw.mas2j.

    +
  • +
+
+
+
+

Exercises A

+
+
    +
  1. +

    Add a new goal for Bob: say(bonjour).

    +
  2. +
  3. +

    Add the following beliefs for Bob:

    +
    +
    +
    msg(en,"Hello").
    +msg(fr,"Bonjour").
    +msg(pt,"Ola").
    +
    +
    +
    +

    and change the plan for the goal say so that the argument is the language and the message is based on the above beliefs. For instance the goal !say(fr) prints out Bonjour.

    +
    +
  4. +
+
+
+
+
+
+

Bob (the believer)

+
+
+

The second version of agent Bob has neither initial beliefs nor desires:

+
+
+
+
+happy(bob) <- !say(hello).
++!say(X) : not today(monday) <- .print(X); .wait(500); !say(X).
+
+
+
+

The first plan has a different kind of event: the agent has started to +believe something (the belief that follows +). So when the agent +starts believing that Bob is happy, the desire to say hello +(!say(hello)) is created. In this case, the desire is the result of +changes in the agent’s beliefs. The agent starts believing something +when, for instance, it perceives the state of the environment or +receives a message from another agent.

+
+
+

The second plan has also changed: (i) the agent will decide to pursue +the desire to say something on days other than Monday; (ii) after +printing the message, the desire is kept, producing a loop that will end +on the next Monday. In other words, the intention to achieve !say does +not finish because that intention itself creates a new desire !say +(here also conveniently called sub-goal). Only when this sub-goal is +achieved, the intention finishes (which never happens in the above +plan).

+
+
+

If you run this program, nothing happens! Different from other languages +where the programmer defines a sequence of operations, in Jason the +programmer declares plans and the order of execution depends on the +order of the events that take place on a particular environment.

+
+
+

To interact with Bob, we will create another agent at runtime that informs him +about new facts.

+
+
+
    +
  1. +

    Run the project.

    +
  2. +
  3. +

    In the MAS Console, click on the button "New REPL agent" and fill +"alice" as the name of the new agent.

    +
  4. +
  5. +

    In the Alice interface, enter .send(bob,tell,happy(bob)).

    +
  6. +
  7. +

    You will notice that Bob starts saying hello.

    +
  8. +
+
+
+

The tell message that Alice sent to Bob is automatically interpreted +by Jason. The default interpretation, since it is a "tell" message, is +to include the content of the message (happy(bob)) in the Bob’s belief +base. When that belief is added in the belief base, the event ++happy(bob) is included in the queue of events. Bob then reacts to +this event creating an intention. You can access the +Jason Mind Inspector to see the Bob’s mental +state (or use the Debug button in the MAS Console):

+
+
+

image

+
+
+

As we can see, the belief is not exactly happy(bob) but +happy(bob)[source(alice)]. The part enclosed by [ and ] are +annotations. All beliefs in Jason have annotations for their sources. +This information can be used, for instance, if an agent needs to +consider only those beliefs that come from trustable sources:

+
+
+
+
sincere(alice).
+
++happy(bob)[source(A)] : sincere(A) <- !say(hello(A)).
+
++!say(X) : not today(monday) <- .print(X); .wait(500); !say(X).
+
+
+
+

This program has a problem, however. Another malicious agent can tell +Bob that it is sincere just before telling him happy(bob)! The source +of the sincere belief should be Bob itself (and not another agent):

+
+
+
+
sincere(alice).
+
++happy(bob)[source(A)] : sincere(A)[source(self)] <- !say(hello(A)).
+
++!say(X) : not today(monday) <- .print(X); .wait(500); !say(X).
+
+
+
+

Exercises B

+
+

Using the REPL interface, create a third agent called marcos that runs .send(bob,tell,happy(bob)).

+
+
+
    +
  1. +

    How is the belief base of Bob?

    +
  2. +
  3. +

    How many intentions Bob has? Why?

    +
  4. +
  5. +

    Add the belief sincere(marcos) for Bob and run the exercises 1 and 2 again.

    +
  6. +
  7. +

    Create a fourth agent, called john that runs .send(bob,achieve,say(kkk)). What can you infer from the achieve performative used in this message?

    +
  8. +
+
+
+
+

Perception

+
+

Besides messages from other agents, another source for beliefs is +perception. We will place a calendar in the environment so that Bob can +be aware of the current day. It is not the focus of this tutorial to +develop the environment, so we will simply copy & paste some code:

+
+
+
    +
  • +

    change the project to:

    + ++++ + + + + + + + + + + + + +
    Jason .mas2j projectJaCaMo .jcm project
    +
    +
    MAS bdi_hw {
    +
    +  // CArtAgO environment
    +  environment: jaca.CartagoEnvironment
    +
    +  // Agent architecture for CArtAgO
    +  agents:
    +     bob agentArchClass jaca.CAgentArch;
    +}
    +
    +
    +
    +
    mas bdi_hw {
    +
    +   agent bob
    +
    +   workspace world {
    +      artifact cal: Calendar {
    +         focused-by: bob
    +      }
    +   }
    +}
    +
    +
    +
  • +
  • +

    Download this file and place it in the +directory of the project where artifacts go (when using JaCaMo, this directory usually is src/env)

    +
  • +
  • +

    In the beginning of Bob’s program (bob.asl), add the following lines to give him access to the calendar:

    + ++++ + + + + + + + + + + + + +
    If using .mas2j projectIf using .jcm project
    +
    +
    !create_calendar.
    ++!create_calendar
    +   <- makeArtifact("c","Calendar",[],AId);
    +      focus(AId).
    +
    +
    +
    +
    { include("$jacamoJar/templates/common-cartago.asl") }
    +
    +
    +
  • +
  • +

    Run the project and interactively change the current day observing +Bob’s belief base and intentions. For example, if you change the day to +Monday, the intention will finish. In this case, the intention finishes +with failure, since the agent has a desire without a suitable plan.

    +
  • +
+
+
+
+

Exercises C

+
+
    +
  1. +

    Change the Bob’s program so that no failure is produced on Mondays, but a proper message is printed.

    +
  2. +
+
+
+
+
+
+

Bob (the vigilant)

+
+
+

The following program for Bob includes alternative plans for the events +happy(H)` and `!say(X).

+
+
+
+
sincere(alice).
+
++happy(H)[source(A)] : sincere(A)[source(self)] & .my_name(H) <- !say(hello(A)).
++happy(H)            : not .my_name(H)                        <- !say(i_envy(H)).
+
++!say(X) : today(friday)     <- .print(X,"!!!!!"); .wait(math.random(400)+100); !say(X).
++!say(X) : not today(monday) <- .print(X);         .wait(math.random(400)+100); !say(X).
++!say(X)					 <- !say(X).
+
+
+
+

For each event, one plan is selected according to the context: the +first plan with a context that holds is selected to create the intention +to react to the event.

+
+
+

The first plan for happy(H)` is used when `H` is `bob` and the source +of `happy(H)` is sincere +(http://jason-lang.github.io/api/jason/stdlib/my_name.html[`.my_name`] +is true if the value of `H` is the name of the agent executing that +internal action). The second plan is used otherwise. The first plan for +`!say(X) is used on Fridays and the second on days other than Monday. +(Notice that there is a plan for Mondays that does not actually say anything +but just keeps the intention alive. Without it Bob would find no plan for +say(X) on Monday and the goal for say(X) would not be re-added. Thus, Bob +would remain mute thereafter.)

+
+
+

Instead of using REPL, we will add a new agent, called Alice, to run +this system. The program for Alice is bellow (in a file named alice.asl).

+
+
+
+
!start.
+
++!start
+   <- .send(bob,tell,happy(bob));
+      .send(bob,tell,happy(alice));
+      .wait(2000);
+      .send(bob,tell,happy(morgana)).
+
+
+
+

The project file has to be updated:

+
+ ++++ + + + + + + + + + + + + +
Jason .mas2j projectJaCaMo .jcm project
+
+
MAS bdi_hw {
+
+  environment: jaca.CartagoEnvironment
+
+  agents:
+     bob agentArchClass jaca.CAgentArch;
+
+     alice; // new agent
+}
+
+
+
+
mas bdi_hw {
+
+   agent bob
+
+   agent alice // new agent
+
+   workspace world {
+      artifact cal: Calendar {
+         focused-by: bob
+      }
+   }
+}
+
+
+
+

When running this new application, we can notice how many intentions Bob has now:

+
+
+

image

+
+
+

Bob is concurrently executing three intentions: one for each event. More +importantly, even with 3 intentions (or 100 intentions) Bob promptly +reacts to new events. This reactivity is indeed one of the nicer +features of the BDI model. You can test it by creating a new REPL agent +that sends tell messages to Bob and see how fast it reacts.

+
+
+

To really stress Bob, we can change Alice’s program as follows:

+
+
+
+
!start.
+
++!start
+   <- .send(bob,tell,happy(bob));
+      .send(bob,tell,happy(alice));
+      .wait(2000);
+      .send(bob,tell,happy(morgana));
+      for (.range(I,1,100)) {
+         .send(bob,tell,happy(I));
+      }.
+
+
+
+

At this point of the tutorial, you could try to imagine how to program +this application using conventional languages like Java and C. Even +actor-based languages, which are also oriented to events and great tools +for concurrency, may not be as simple as Jason.

+
+
+

Exercises D

+
+
    +
  1. +

    Add the agent Carlos from previous exercise in the project.

    +
  2. +
  3. +

    Write a plan for Bob so that as soon as it realises that someone is happy, he shares this information with Carlos.

    +
  4. +
  5. +

    What happens in the application when Carlos executes .send(bob,tell,happy(thales))?

    +
  6. +
+
+
+
+
+
+

Bob (the revisionist)

+
+
+

Another important feature of the BDI model is that agents are able to +revise their own intentions. The following plan reacts to the event of +stop believing that someone is happy. The reaction is to drop the +corresponding intention.

+
+
+
+
// new plan in Bob's program:
+
+-happy(H)[source(A)]
+   <- .drop_intention(say(hello(A)));
+      .drop_intention(say(i_envy(H))).
+
+
+
+

We can test this with the following program for Alice:

+
+
+
+
!start.
+
++!start
+   <- .send(bob,tell,happy(bob));
+      .send(bob,tell,happy(alice));    .wait(2000);
+      .send(bob,tell,happy(morgana));  .wait(2000);
+      .send(bob,untell,happy(bob));    .wait(1000);
+      .send(bob,untell,happy(alice)).
+
+
+
+

The untell message removes the corresponding belief in the receiver +(only for the belief with that same source, of course).

+
+
+

Exercises E

+
+
    +
  1. +

    Write a new plan for Bob so that on Saturdays he drops all his intentions. The internal action .drop_all_intentions may help for that.

    +
  2. +
  3. +

    Write a plan for Bob so that as soon as it realises that someone is happy, he shares this information with Carlos only if Bob intends to say(hello(carlos)). The internal action .intend may help for that.

    +
  4. +
+
+
+
+
+
+

Bob (the lazy — finally)

+
+
+

This last code for Bob implements the following:

+
+
+
    +
  1. +

    On Wednesdays, Bob keeps only two say intentions, the others will +be suspended.

    +
  2. +
  3. +

    On Fridays, suspended intentions are resumed.

    +
  4. +
  5. +

    On Saturdays, all intentions are dropped.

    +
  6. +
+
+
+
+
sincere(alice).
+
++happy(H)[source(A)] : sincere(A)[source(self)] & .my_name(H) <- !say(hello(A)).
++happy(H)            : not .my_name(H)                        <- !say(i_envy(H)).
+
+-happy(H)[source(A)]
+   <- .drop_intention(say(hello(A)));
+      .drop_intention(say(i_envy(H))).
+
++!say(X) : today(friday)     <- .print(X,"!!!!!"); .wait(500); !say(X).
++!say(X) : not today(monday) <- .print(X);         .wait(math.random(400)+100); !say(X).
++!say(X)					 <- !say(X).
+
+/**** the following is NEW ****/
+
++today(wednesday) <- .print("**** Let's slow down.... ****"); !enter_lazy_mode.
++today(friday)    <- .print("**** Let's finish the work!");   !resume_all.
++today(saturday)  <- .print("**** weekend!");                 .drop_all_intentions.
+
++!enter_lazy_mode
+    : .findall(A, .intend(say(A)), [_,_|L]) // the agent has at most two active "say" intentions
+   <- for ( .member(I,L) ) {
+         .suspend(say(I));
+      }.
++!enter_lazy_mode.
+
++!resume_all
+    : .count( .intend(A) & .suspended(A,R) & .substring("suspended",R), I) & I > 0
+   <- .resume(say(_));
+      !resume_all.
++!resume_all.
+
+
+
+

(You can refer to the +Jason +API for explanations about all the commands used in this example.)

+
+
+

This tutorial showed how some of the (great) BDI concepts become +concrete and practical in Jason, particularly long-term intentions and +reactivity.

+
+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/hello-bdi/publish.sh b/tutorials/hello-bdi/publish.sh new file mode 100755 index 00000000..b77ad78f --- /dev/null +++ b/tutorials/hello-bdi/publish.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +docker run --rm -i --user="$(id -u):$(id -g)" --net=none -v "$PWD":/app jomifred/adoc asciidoctor -r /pygments_init.rb readme.adoc +mv readme.html index.html +scp index.html jomifred,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/mini-tutorial/hello-bdi + +#scp hello-bdi-code.zip jomifred,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/mini-tutorial/hello-bdi diff --git a/tutorials/hello-bdi/readme.html b/tutorials/hello-bdi/readme.html new file mode 100644 index 00000000..544000df --- /dev/null +++ b/tutorials/hello-bdi/readme.html @@ -0,0 +1,1290 @@ + + + + + + + + +(BDI) Hello World + + + + + + + +
+
+

Introduction

+
+
+

This programming (mini) tutorial illustrates how the BDI model is +used in the Jason agent-oriented programming +language. We start by a very simple agent code and progress exploring +the BDI features of Jason.

+
+
+

We assume that the reader knows the basic concepts of the BDI model (an +introduction and further references are found at the +Wikipedia). +It is important to know these concepts to be a good Jason programmer, in +the same way that knowing the concepts of and objects and classes is +important for a Java programmer. Very briefly, in the BDI model the +agent has beliefs (based on what it perceives and communicates with +other agents) that can produce desires (states of the world that the +agent wants to achieve). The agent deliberates on its desires and +decides to commit to some (desires to which the agent is committed +become intentions). To satisfy its intentions, the agent executes +plans that lead to action. The behaviour of the agent (i.e., its +actions) is thus explained/caused by what it intends (i.e., the desires +it decided to pursue). An important feature of architectures that +implement the BDI model is that the agent should react to changes in +its environment as soon as possible while keeping its pro-active +(i.e., desires-oriented) behaviour. (Do not worry about all these +high-level anthropomorphic concepts (in italics), we will try to keep +the simplicity of usual hello world programs.)

+
+
+
+
+

Bob (the mentalist)

+
+
+

Agent program

+
+

The Jason program for our agent is the following (since BDI is inspired +in folk psychology, we can name this agent Bob):

+
+
+
+
happy(bob).
+
+!say(hello).
+
++!say(X) : happy(bob) <- .print(X).
+
+
+
+

As we can see, the syntax is far from the usual C, Java, or Python +programs we are used to. For those (rare) guys who have had some contact +with Prolog, maybe it looks a bit familiar. The syntax is indeed +inspired by Prolog, but the objective is different (the output is not +knowledge and the underlying engine is not based on resolution). Let’s +read this program:

+
+
+
    +
  1. +

    The agent has one (initial) belief: happy(bob), included by the +programmer (rather than by perceiving the state of the environment). +This belief can be read as “bob has the property (or predicate) happy”.

    +
  2. +
  3. +

    The agent has one (initial) desire: !say(hello), also included by +the programmer. What follows the symbol ! describes the desire and is +also represented as a Prolog literal.

    +
  4. +
  5. +

    The agent has one plan to achieve the desire say(hello). We can +read this plan as “whenever the agent has the desire to say(X) and +believes that happy(bob), by executing the action .print(X) the +desire is achieved, for any X (which is a variable since it starts +with an uppercase letter, as in Prolog)”.

    +
  6. +
+
+
+

The deliberation process of the BDI model is highly related to plans. +The plan states whether a desire can become an intention by means of +its event and context. In the Bob’s plan, the event is +!say(X) +(what is written before :) and it means the event of having a new +desire to say something. The context is happy(bob) (the part of the +code that goes between : and ) which is a logical formula +evaluated in regards to the current believes of the agent.

+
+
+

The plan also states how to achieve the desire (i.e. the means-end +reasoning part of the BDI model). If the sequence of actions (after +) is successfully executed, the desire is (hopefully) achieved. An +intention in Jason is an instantiated plan that the agent is executing +in order to achieve a desire (also called goal).

+
+
+

This program is interpreted by Jason as follows:

+
+
+
    +
  1. +

    The initial belief is added in the agent belief base (BB).

    +
  2. +
  3. +

    From the initial desire, the event +!say(hello) is added in the +queue of events to be handled by the agent.

    +
  4. +
  5. +

    The plan is included in the plan library (PL) of the agent.

    +
  6. +
  7. +

    A reasoning cycle loop is executed:

    +
    +
      +
    • +

      The event +!say(hello) is selected from the queue.

      +
    • +
    • +

      The above plan is selected (it matches the selected event when the +variable X is bound to hello).

      +
    • +
    • +

      The context of the plan is evaluated as true since it follows from be +BB (i.e. the agent believes happy(bob)).

      +
    • +
    • +

      A new intention is created based on this plan and the X value. The +agent has thus committed itself to the desire to say(hello).

      +
    • +
    • +

      One action of the intention is executed (the .print(hello) command +in this case).

      +
    • +
    • +

      Since the intention has executed all actions, it finishes.

      +
    • +
    +
    +
  8. +
  9. +

    The agent keeps waiting for new events to react to.

    +
  10. +
+
+
+
+

Execution

+
+
    +
  • +

    Create a new project: you can download and initial JaCaMo project; +or create a new one Jason application with JasonCLI: jason app create bdi_hw.

    +
  • +
  • +

    Create agent Bob with the source code above (file bob.asl). The project should +look like:

    + ++++ + + + + + + + + + + + + +
    Jason .mas2j projectJaCaMo .jcm project
    +
    +
    MAS bdi_hw {
    +
    +    agents: bob;
    +
    +}
    +
    +
    +
    +
    mas bdi_hw {
    +
    +    agent bob
    +    // file bob.asl at src/agt under the project directory
    +
    +}
    +
    +
    +
  • +
  • +

    Run the project. In the case of JaCaMo, run the script ./gradlew; in case of Jason jason bdi_hw.mas2j.

    +
  • +
+
+
+
+

Exercises A

+
+
    +
  1. +

    Add a new goal for Bob: say(bonjour).

    +
  2. +
  3. +

    Add the following beliefs for Bob:

    +
    +
    +
    msg(en,"Hello").
    +msg(fr,"Bonjour").
    +msg(pt,"Ola").
    +
    +
    +
    +

    and change the plan for the goal say so that the argument is the language and the message is based on the above beliefs. For instance the goal !say(fr) prints out Bonjour.

    +
    +
  4. +
+
+
+
+
+
+

Bob (the believer)

+
+
+

The second version of agent Bob has neither initial beliefs nor desires:

+
+
+
+
+happy(bob) <- !say(hello).
++!say(X) : not today(monday) <- .print(X); .wait(500); !say(X).
+
+
+
+

The first plan has a different kind of event: the agent has started to +believe something (the belief that follows +). So when the agent +starts believing that Bob is happy, the desire to say hello +(!say(hello)) is created. In this case, the desire is the result of +changes in the agent’s beliefs. The agent starts believing something +when, for instance, it perceives the state of the environment or +receives a message from another agent.

+
+
+

The second plan has also changed: (i) the agent will decide to pursue +the desire to say something on days other than Monday; (ii) after +printing the message, the desire is kept, producing a loop that will end +on the next Monday. In other words, the intention to achieve !say does +not finish because that intention itself creates a new desire !say +(here also conveniently called sub-goal). Only when this sub-goal is +achieved, the intention finishes (which never happens in the above +plan).

+
+
+

If you run this program, nothing happens! Different from other languages +where the programmer defines a sequence of operations, in Jason the +programmer declares plans and the order of execution depends on the +order of the events that take place on a particular environment.

+
+
+

To interact with Bob, we will create another agent at runtime that informs him +about new facts.

+
+
+
    +
  1. +

    Run the project.

    +
  2. +
  3. +

    In the MAS Console, click on the button "New REPL agent" and fill +"alice" as the name of the new agent.

    +
  4. +
  5. +

    In the Alice interface, enter .send(bob,tell,happy(bob)).

    +
  6. +
  7. +

    You will notice that Bob starts saying hello.

    +
  8. +
+
+
+

The tell message that Alice sent to Bob is automatically interpreted +by Jason. The default interpretation, since it is a "tell" message, is +to include the content of the message (happy(bob)) in the Bob’s belief +base. When that belief is added in the belief base, the event ++happy(bob) is included in the queue of events. Bob then reacts to +this event creating an intention. You can access the +Jason Mind Inspector to see the Bob’s mental +state (or use the Debug button in the MAS Console):

+
+
+

image

+
+
+

As we can see, the belief is not exactly happy(bob) but +happy(bob)[source(alice)]. The part enclosed by [ and ] are +annotations. All beliefs in Jason have annotations for their sources. +This information can be used, for instance, if an agent needs to +consider only those beliefs that come from trustable sources:

+
+
+
+
sincere(alice).
+
++happy(bob)[source(A)] : sincere(A) <- !say(hello(A)).
+
++!say(X) : not today(monday) <- .print(X); .wait(500); !say(X).
+
+
+
+

This program has a problem, however. Another malicious agent can tell +Bob that it is sincere just before telling him happy(bob)! The source +of the sincere belief should be Bob itself (and not another agent):

+
+
+
+
sincere(alice).
+
++happy(bob)[source(A)] : sincere(A)[source(self)] <- !say(hello(A)).
+
++!say(X) : not today(monday) <- .print(X); .wait(500); !say(X).
+
+
+
+

Exercises B

+
+

Using the REPL interface, create a third agent called marcos that runs .send(bob,tell,happy(bob)).

+
+
+
    +
  1. +

    How is the belief base of Bob?

    +
  2. +
  3. +

    How many intentions Bob has? Why?

    +
  4. +
  5. +

    Add the belief sincere(marcos) for Bob and run the exercises 1 and 2 again.

    +
  6. +
  7. +

    Create a fourth agent, called john that runs .send(bob,achieve,say(kkk)). What can you infer from the achieve performative used in this message?

    +
  8. +
+
+
+
+

Perception

+
+

Besides messages from other agents, another source for beliefs is +perception. We will place a calendar in the environment so that Bob can +be aware of the current day. It is not the focus of this tutorial to +develop the environment, so we will simply copy & paste some code:

+
+
+
    +
  • +

    change the project to:

    + ++++ + + + + + + + + + + + + +
    Jason .mas2j projectJaCaMo .jcm project
    +
    +
    MAS bdi_hw {
    +
    +  // CArtAgO environment
    +  environment: jaca.CartagoEnvironment
    +
    +  // Agent architecture for CArtAgO
    +  agents:
    +     bob agentArchClass jaca.CAgentArch;
    +}
    +
    +
    +
    +
    mas bdi_hw {
    +
    +   agent bob
    +
    +   workspace world {
    +      artifact cal: Calendar {
    +         focused-by: bob
    +      }
    +   }
    +}
    +
    +
    +
  • +
  • +

    Download this file and place it in the +directory of the project where artifacts go (when using JaCaMo, this directory usually is src/env)

    +
  • +
  • +

    In the beginning of Bob’s program (bob.asl), add the following lines to give him access to the calendar:

    + ++++ + + + + + + + + + + + + +
    If using .mas2j projectIf using .jcm project
    +
    +
    !create_calendar.
    ++!create_calendar
    +   <- makeArtifact("c","Calendar",[],AId);
    +      focus(AId).
    +
    +
    +
    +
    { include("$jacamoJar/templates/common-cartago.asl") }
    +
    +
    +
  • +
  • +

    Run the project and interactively change the current day observing +Bob’s belief base and intentions. For example, if you change the day to +Monday, the intention will finish. In this case, the intention finishes +with failure, since the agent has a desire without a suitable plan.

    +
  • +
+
+
+
+

Exercises C

+
+
    +
  1. +

    Change the Bob’s program so that no failure is produced on Mondays, but a proper message is printed.

    +
  2. +
+
+
+
+
+
+

Bob (the vigilant)

+
+
+

The following program for Bob includes alternative plans for the events +happy(H)` and `!say(X).

+
+
+
+
sincere(alice).
+
++happy(H)[source(A)] : sincere(A)[source(self)] & .my_name(H) <- !say(hello(A)).
++happy(H)            : not .my_name(H)                        <- !say(i_envy(H)).
+
++!say(X) : today(friday)     <- .print(X,"!!!!!"); .wait(math.random(400)+100); !say(X).
++!say(X) : not today(monday) <- .print(X);         .wait(math.random(400)+100); !say(X).
++!say(X)					 <- !say(X).
+
+
+
+

For each event, one plan is selected according to the context: the +first plan with a context that holds is selected to create the intention +to react to the event.

+
+
+

The first plan for happy(H)` is used when `H` is `bob` and the source +of `happy(H)` is sincere +(http://jason-lang.github.io/api/jason/stdlib/my_name.html[`.my_name`] +is true if the value of `H` is the name of the agent executing that +internal action). The second plan is used otherwise. The first plan for +`!say(X) is used on Fridays and the second on days other than Monday. +(Notice that there is a plan for Mondays that does not actually say anything +but just keeps the intention alive. Without it Bob would find no plan for +say(X) on Monday and the goal for say(X) would not be re-added. Thus, Bob +would remain mute thereafter.)

+
+
+

Instead of using REPL, we will add a new agent, called Alice, to run +this system. The program for Alice is bellow (in a file named alice.asl).

+
+
+
+
!start.
+
++!start
+   <- .send(bob,tell,happy(bob));
+      .send(bob,tell,happy(alice));
+      .wait(2000);
+      .send(bob,tell,happy(morgana)).
+
+
+
+

The project file has to be updated:

+
+ ++++ + + + + + + + + + + + + +
Jason .mas2j projectJaCaMo .jcm project
+
+
MAS bdi_hw {
+
+  environment: jaca.CartagoEnvironment
+
+  agents:
+     bob agentArchClass jaca.CAgentArch;
+
+     alice; // new agent
+}
+
+
+
+
mas bdi_hw {
+
+   agent bob
+
+   agent alice // new agent
+
+   workspace world {
+      artifact cal: Calendar {
+         focused-by: bob
+      }
+   }
+}
+
+
+
+

When running this new application, we can notice how many intentions Bob has now:

+
+
+

image

+
+
+

Bob is concurrently executing three intentions: one for each event. More +importantly, even with 3 intentions (or 100 intentions) Bob promptly +reacts to new events. This reactivity is indeed one of the nicer +features of the BDI model. You can test it by creating a new REPL agent +that sends tell messages to Bob and see how fast it reacts.

+
+
+

To really stress Bob, we can change Alice’s program as follows:

+
+
+
+
!start.
+
++!start
+   <- .send(bob,tell,happy(bob));
+      .send(bob,tell,happy(alice));
+      .wait(2000);
+      .send(bob,tell,happy(morgana));
+      for (.range(I,1,100)) {
+         .send(bob,tell,happy(I));
+      }.
+
+
+
+

At this point of the tutorial, you could try to imagine how to program +this application using conventional languages like Java and C. Even +actor-based languages, which are also oriented to events and great tools +for concurrency, may not be as simple as Jason.

+
+
+

Exercises D

+
+
    +
  1. +

    Add the agent Carlos from previous exercise in the project.

    +
  2. +
  3. +

    Write a plan for Bob so that as soon as it realises that someone is happy, he shares this information with Carlos.

    +
  4. +
  5. +

    What happens in the application when Carlos executes .send(bob,tell,happy(thales))?

    +
  6. +
+
+
+
+
+
+

Bob (the revisionist)

+
+
+

Another important feature of the BDI model is that agents are able to +revise their own intentions. The following plan reacts to the event of +stop believing that someone is happy. The reaction is to drop the +corresponding intention.

+
+
+
+
// new plan in Bob's program:
+
+-happy(H)[source(A)]
+   <- .drop_intention(say(hello(A)));
+      .drop_intention(say(i_envy(H))).
+
+
+
+

We can test this with the following program for Alice:

+
+
+
+
!start.
+
++!start
+   <- .send(bob,tell,happy(bob));
+      .send(bob,tell,happy(alice));    .wait(2000);
+      .send(bob,tell,happy(morgana));  .wait(2000);
+      .send(bob,untell,happy(bob));    .wait(1000);
+      .send(bob,untell,happy(alice)).
+
+
+
+

The untell message removes the corresponding belief in the receiver +(only for the belief with that same source, of course).

+
+
+

Exercises E

+
+
    +
  1. +

    Write a new plan for Bob so that on Saturdays he drops all his intentions. The internal action .drop_all_intentions may help for that.

    +
  2. +
  3. +

    Write a plan for Bob so that as soon as it realises that someone is happy, he shares this information with Carlos only if Bob intends to say(hello(carlos)). The internal action .intend may help for that.

    +
  4. +
+
+
+
+
+
+

Bob (the lazy — finally)

+
+
+

This last code for Bob implements the following:

+
+
+
    +
  1. +

    On Wednesdays, Bob keeps only two say intentions, the others will +be suspended.

    +
  2. +
  3. +

    On Fridays, suspended intentions are resumed.

    +
  4. +
  5. +

    On Saturdays, all intentions are dropped.

    +
  6. +
+
+
+
+
sincere(alice).
+
++happy(H)[source(A)] : sincere(A)[source(self)] & .my_name(H) <- !say(hello(A)).
++happy(H)            : not .my_name(H)                        <- !say(i_envy(H)).
+
+-happy(H)[source(A)]
+   <- .drop_intention(say(hello(A)));
+      .drop_intention(say(i_envy(H))).
+
++!say(X) : today(friday)     <- .print(X,"!!!!!"); .wait(500); !say(X).
++!say(X) : not today(monday) <- .print(X);         .wait(math.random(400)+100); !say(X).
++!say(X)					 <- !say(X).
+
+/**** the following is NEW ****/
+
++today(wednesday) <- .print("**** Let's slow down.... ****"); !enter_lazy_mode.
++today(friday)    <- .print("**** Let's finish the work!");   !resume_all.
++today(saturday)  <- .print("**** weekend!");                 .drop_all_intentions.
+
++!enter_lazy_mode
+    : .findall(A, .intend(say(A)), [_,_|L]) // the agent has at most two active "say" intentions
+   <- for ( .member(I,L) ) {
+         .suspend(say(I));
+      }.
++!enter_lazy_mode.
+
++!resume_all
+    : .count( .intend(A) & .suspended(A,R) & .substring("suspended",R), I) & I > 0
+   <- .resume(say(_));
+      !resume_all.
++!resume_all.
+
+
+
+

(You can refer to the +Jason +API for explanations about all the commands used in this example.)

+
+
+

This tutorial showed how some of the (great) BDI concepts become +concrete and practical in Jason, particularly long-term intentions and +reactivity.

+
+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/hello-bdi/screens/mind-1.png b/tutorials/hello-bdi/screens/mind-1.png new file mode 100755 index 00000000..0cc265bc Binary files /dev/null and b/tutorials/hello-bdi/screens/mind-1.png differ diff --git a/tutorials/hello-bdi/screens/mind-2.png b/tutorials/hello-bdi/screens/mind-2.png new file mode 100755 index 00000000..39ec0299 Binary files /dev/null and b/tutorials/hello-bdi/screens/mind-2.png differ diff --git a/tutorials/jason-jade/Makefile b/tutorials/jason-jade/Makefile new file mode 100755 index 00000000..b58fde0a --- /dev/null +++ b/tutorials/jason-jade/Makefile @@ -0,0 +1,13 @@ +# +# by Jomi +# + +adoc: + asciidoctor -r ../../../src/main/resources/pygments_init.rb readme.adoc + +publish: + cp readme.html index.html +# zip -r ../../jason-jade/jade-example.zip jade-example/examples/bookTrading/*.java + scp index.html jomifred,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/doc/tutorials/jason-jade + scp readme.html jomifred,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/doc/tutorials/jason-jade + scp -r figures jomifred,jason@web.sf.net:/home/groups/j/ja/jason/htdocs/doc/tutorials/jason-jade diff --git a/tutorials/jason-jade/book_trading.zip b/tutorials/jason-jade/book_trading.zip new file mode 100644 index 00000000..5f1fc70b Binary files /dev/null and b/tutorials/jason-jade/book_trading.zip differ diff --git a/tutorials/jason-jade/book_trading/book_trading.mas2j b/tutorials/jason-jade/book_trading/book_trading.mas2j new file mode 100644 index 00000000..d1ab5f33 --- /dev/null +++ b/tutorials/jason-jade/book_trading/book_trading.mas2j @@ -0,0 +1,10 @@ +/* Jason Project */ + +MAS book_trading { + + agents: + john; + + aslSourcePath: "src/agt"; +} + diff --git a/tutorials/jason-jade/book_trading/build.gradle b/tutorials/jason-jade/book_trading/build.gradle new file mode 100644 index 00000000..851c2355 --- /dev/null +++ b/tutorials/jason-jade/book_trading/build.gradle @@ -0,0 +1,61 @@ +/* + Project book_trading + + Gradle build file for Jason Application + May 07, 2023 - 19:29:43 +*/ + +defaultTasks 'run' + +apply plugin: 'java' + +// set version of group for your project +//version '1.0' +//group 'io.github.jason-lang' + +repositories { + mavenCentral() + maven { url "https://raw.githubusercontent.com/jacamo-lang/mvn-repo/master" } + maven { url "https://jade.tilab.com/maven/" } +} + +dependencies { + implementation('io.github.jason-lang:jason-interpreter:3.2.1-SNAPSHOT') + // to use locally installed jars: + //implementation fileTree(dir: 'lib', include: '*.jar') +} + +sourceSets { + main { + java { + srcDir 'src/java' + srcDir 'src/env' + } + } +} + +task run (type: JavaExec, dependsOn: 'classes') { + description 'runs the application' + mainClass = 'jason.infra.local.RunLocalMAS' + args = ['book_trading.mas2j'] + // options: + // args = ['book_trading.mas2j', '--debug', '--no-net', '--empty-mas'] + // args = ['book_trading.mas2j', '--log-conf', 'l.p'] // to use file l.p to configure logging + classpath sourceSets.main.runtimeClasspath +} + +task runJohn (type: JavaExec, dependsOn: 'classes') { + description 'runs agent jhon using JADE platform' + mainClass = 'jade.Boot' + args = [ '-container', 'john:jason.infra.jade.JadeAgArch(src/agt/john.asl)' ] + classpath sourceSets.main.runtimeClasspath +} + +task runJadeAgs (type: JavaExec, dependsOn: 'classes') { + description 'runs normal JADE agents' + mainClass = 'jade.Boot' + args = [ '-gui', 'bob:examples.bookTrading.BookBuyerAgent(Harry)' ] + //args = [ '-container', '-gui', '-local-host', '127.0.0.1', 'bob:examples.bookTrading.BookBuyerAgent(Harry)' ] + classpath sourceSets.main.runtimeClasspath +} + diff --git a/tutorials/jason-jade/book_trading/gradle/wrapper/gradle-wrapper.jar b/tutorials/jason-jade/book_trading/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..ccebba77 Binary files /dev/null and b/tutorials/jason-jade/book_trading/gradle/wrapper/gradle-wrapper.jar differ diff --git a/tutorials/jason-jade/book_trading/gradle/wrapper/gradle-wrapper.properties b/tutorials/jason-jade/book_trading/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..bdc9a83b --- /dev/null +++ b/tutorials/jason-jade/book_trading/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/tutorials/jason-jade/book_trading/gradlew b/tutorials/jason-jade/book_trading/gradlew new file mode 100755 index 00000000..79a61d42 --- /dev/null +++ b/tutorials/jason-jade/book_trading/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/tutorials/jason-jade/book_trading/gradlew.bat b/tutorials/jason-jade/book_trading/gradlew.bat new file mode 100644 index 00000000..6689b85b --- /dev/null +++ b/tutorials/jason-jade/book_trading/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/tutorials/jason-jade/book_trading/settings.gradle b/tutorials/jason-jade/book_trading/settings.gradle new file mode 100644 index 00000000..e69de29b diff --git a/tutorials/jason-jade/book_trading/src/agt/john.asl b/tutorials/jason-jade/book_trading/src/agt/john.asl new file mode 100644 index 00000000..2e0a4751 --- /dev/null +++ b/tutorials/jason-jade/book_trading/src/agt/john.asl @@ -0,0 +1,41 @@ +// Agent john + +/* Initial beliefs */ + +// The book beliefs has three arguments: +// . the book name +// . the price +// . the quantity in stock + +book("Harry", 32, 20). +book("Jason", 75, 10). + + +/* Initial goals */ + +!registerDF. + +/* Plans */ + ++!registerDF <- .df_register("JADE-book-trading", "book-selling"). // name, type + +/* handle CFP performatives */ + +// CFP ++!kqml_received(Sender, cfp, Content, MsgId) + : book(Content, Price, Qtd) & Qtd > 0 // if I have the book + <- .send(Sender, propose, Price, MsgId). // propose + ++!kqml_received(Sender, cfp, Content, MsgId) + <- .send(Sender, refuse, "not-available", MsgId). // refuse otherwise + + +// ACCEPT-PROPOSAL ++!kqml_received(Sender, accept_proposal, Content, MsgId) + : book(Content, Price, Qtd) & Qtd > 0 // If I still have the book + <- -+book(Content, Price, Qtd-1); // change stock + .print("New stock for ",Content," is ", Qtd-1); + .send(Sender, tell, Content, MsgId). // confirm + ++!kqml_received(Sender, accept_proposal, Content, MsgId) + <- .send(Sender, failure, "not-available", MsgId). diff --git a/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookBuyerAgent.java b/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookBuyerAgent.java new file mode 100644 index 00000000..128a4100 --- /dev/null +++ b/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookBuyerAgent.java @@ -0,0 +1,185 @@ +/***************************************************************** +JADE - Java Agent DEvelopment Framework is a framework to develop +multi-agent systems in compliance with the FIPA specifications. +Copyright (C) 2000 CSELT S.p.A. + +GNU Lesser General Public License + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation, +version 2.1 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*****************************************************************/ + +package examples.bookTrading; + +import jade.core.Agent; +import jade.core.AID; +import jade.core.behaviours.*; +import jade.lang.acl.ACLMessage; +import jade.lang.acl.MessageTemplate; +import jade.domain.DFService; +import jade.domain.FIPAException; +import jade.domain.FIPAAgentManagement.DFAgentDescription; +import jade.domain.FIPAAgentManagement.ServiceDescription; + +public class BookBuyerAgent extends Agent { + // The title of the book to buy + private String targetBookTitle; + // The list of known seller agents + private AID[] sellerAgents; + + // Put agent initializations here + protected void setup() { + // Printout a welcome message + System.out.println("Hallo! Buyer-agent "+getAID().getName()+" is ready."); + + // Get the title of the book to buy as a start-up argument + Object[] args = getArguments(); + if (args != null && args.length > 0) { + targetBookTitle = (String) args[0]; + System.out.println("Target book is "+targetBookTitle); + + // Add a TickerBehaviour that schedules a request to seller agents every minute + addBehaviour(new TickerBehaviour(this, 10000) { + protected void onTick() { + System.out.println("Trying to buy "+targetBookTitle); + // Update the list of seller agents + DFAgentDescription template = new DFAgentDescription(); + ServiceDescription sd = new ServiceDescription(); + sd.setType("book-selling"); + template.addServices(sd); + try { + DFAgentDescription[] result = DFService.search(myAgent, template); + System.out.println("Found the following seller agents:"); + sellerAgents = new AID[result.length]; + for (int i = 0; i < result.length; ++i) { + sellerAgents[i] = result[i].getName(); + System.out.println(sellerAgents[i].getName()); + } + } catch (FIPAException fe) { + fe.printStackTrace(); + } + + // Perform the request + myAgent.addBehaviour(new RequestPerformer()); + } + } ); + } else { + // Make the agent terminate + System.out.println("No target book title specified"); + doDelete(); + } + } + + // Put agent clean-up operations here + protected void takeDown() { + // Printout a dismissal message + System.out.println("Buyer-agent "+getAID().getName()+" terminating."); + } + + /** + Inner class RequestPerformer. + This is the behaviour used by Book-buyer agents to request seller + agents the target book. + */ + private class RequestPerformer extends Behaviour { + private AID bestSeller; // The agent who provides the best offer + private int bestPrice; // The best offered price + private int repliesCnt = 0; // The counter of replies from seller agents + private MessageTemplate mt; // The template to receive replies + private int step = 0; + + public void action() { + switch (step) { + case 0: + // Send the cfp to all sellers + ACLMessage cfp = new ACLMessage(ACLMessage.CFP); + for (int i = 0; i < sellerAgents.length; ++i) { + cfp.addReceiver(sellerAgents[i]); + } + cfp.setContent(targetBookTitle); + cfp.setConversationId("book-trade"); + cfp.setReplyWith("cfp"+System.currentTimeMillis()); // Unique value + myAgent.send(cfp); + // Prepare the template to get proposals + mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"), + MessageTemplate.MatchInReplyTo(cfp.getReplyWith())); + step = 1; + break; + case 1: + // Receive all proposals/refusals from seller agents + ACLMessage reply = myAgent.receive(mt); + if (reply != null) { + // Reply received + if (reply.getPerformative() == ACLMessage.PROPOSE) { + // This is an offer + int price = Integer.parseInt(reply.getContent()); + if (bestSeller == null || price < bestPrice) { + // This is the best offer at present + bestPrice = price; + bestSeller = reply.getSender(); + } + } + repliesCnt++; + if (repliesCnt >= sellerAgents.length) { + // We received all replies + step = 2; + } + } else { + block(); + } + break; + case 2: + // Send the purchase order to the seller that provided the best offer + ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL); + order.addReceiver(bestSeller); + order.setContent(targetBookTitle); + order.setConversationId("book-trade"); + order.setReplyWith("order"+System.currentTimeMillis()); + myAgent.send(order); + // Prepare the template to get the purchase order reply + mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"), + MessageTemplate.MatchInReplyTo(order.getReplyWith())); + step = 3; + break; + case 3: + // Receive the purchase order reply + reply = myAgent.receive(mt); + if (reply != null) { + // Purchase order reply received + if (reply.getPerformative() == ACLMessage.INFORM) { + // Purchase successful. We can terminate + System.out.println(targetBookTitle+" successfully purchased from agent "+reply.getSender().getName()); + System.out.println("Price = "+bestPrice); + myAgent.doDelete(); + } else { + System.out.println("Attempt failed: requested book already sold."); + } + + step = 4; + } else { + block(); + } + break; + } + } + + public boolean done() { + if (step == 2 && bestSeller == null) { + System.out.println("Attempt failed: "+targetBookTitle+" not available for sale"); + } + return ((step == 2 && bestSeller == null) || step == 4); + } + } // End of inner class RequestPerformer +} diff --git a/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookSellerAgent.java b/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookSellerAgent.java new file mode 100644 index 00000000..8b61b6b3 --- /dev/null +++ b/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookSellerAgent.java @@ -0,0 +1,165 @@ +/***************************************************************** +JADE - Java Agent DEvelopment Framework is a framework to develop +multi-agent systems in compliance with the FIPA specifications. +Copyright (C) 2000 CSELT S.p.A. + +GNU Lesser General Public License + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation, +version 2.1 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*****************************************************************/ + +package examples.bookTrading; + +import jade.core.Agent; +import jade.core.behaviours.*; +import jade.lang.acl.ACLMessage; +import jade.lang.acl.MessageTemplate; +import jade.domain.DFService; +import jade.domain.FIPAException; +import jade.domain.FIPAAgentManagement.DFAgentDescription; +import jade.domain.FIPAAgentManagement.ServiceDescription; + +import java.util.*; + +public class BookSellerAgent extends Agent { + // The catalogue of books for sale (maps the title of a book to its price) + private Hashtable catalogue; + // The GUI by means of which the user can add books in the catalogue + private BookSellerGui myGui; + + // Put agent initializations here + protected void setup() { + // Create the catalogue + catalogue = new Hashtable(); + + // Create and show the GUI + myGui = new BookSellerGui(this); + myGui.show(); + + // Register the book-selling service in the yellow pages + DFAgentDescription dfd = new DFAgentDescription(); + dfd.setName(getAID()); + ServiceDescription sd = new ServiceDescription(); + sd.setType("book-selling"); + sd.setName("JADE-book-trading"); + dfd.addServices(sd); + try { + DFService.register(this, dfd); + } catch (FIPAException fe) { + fe.printStackTrace(); + } + + // Add the behaviour serving queries from buyer agents + addBehaviour(new OfferRequestsServer()); + + // Add the behaviour serving purchase orders from buyer agents + addBehaviour(new PurchaseOrdersServer()); + } + + // Put agent clean-up operations here + protected void takeDown() { + // Deregister from the yellow pages + try { + DFService.deregister(this); + } catch (FIPAException fe) { + fe.printStackTrace(); + } + // Close the GUI + myGui.dispose(); + // Printout a dismissal message + System.out.println("Seller-agent "+getAID().getName()+" terminating."); + } + + /** + This is invoked by the GUI when the user adds a new book for sale + */ + public void updateCatalogue(final String title, final int price) { + addBehaviour(new OneShotBehaviour() { + public void action() { + catalogue.put(title, new Integer(price)); + System.out.println(title+" inserted into catalogue. Price = "+price); + } + }); + } + + /** + Inner class OfferRequestsServer. + This is the behaviour used by Book-seller agents to serve incoming requests + for offer from buyer agents. + If the requested book is in the local catalogue the seller agent replies + with a PROPOSE message specifying the price. Otherwise a REFUSE message is + sent back. + */ + private class OfferRequestsServer extends CyclicBehaviour { + public void action() { + MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.CFP); + ACLMessage msg = myAgent.receive(mt); + if (msg != null) { + // CFP Message received. Process it + String title = msg.getContent(); + ACLMessage reply = msg.createReply(); + + Integer price = (Integer) catalogue.get(title); + if (price != null) { + // The requested book is available for sale. Reply with the price + reply.setPerformative(ACLMessage.PROPOSE); + reply.setContent(String.valueOf(price.intValue())); + } else { + // The requested book is NOT available for sale. + reply.setPerformative(ACLMessage.REFUSE); + reply.setContent("not-available"); + } + myAgent.send(reply); + } else { + block(); + } + } + } // End of inner class OfferRequestsServer + + /** + Inner class PurchaseOrdersServer. + This is the behaviour used by Book-seller agents to serve incoming + offer acceptances (i.e. purchase orders) from buyer agents. + The seller agent removes the purchased book from its catalogue + and replies with an INFORM message to notify the buyer that the + purchase has been successfully completed. + */ + private class PurchaseOrdersServer extends CyclicBehaviour { + public void action() { + MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL); + ACLMessage msg = myAgent.receive(mt); + if (msg != null) { + // ACCEPT_PROPOSAL Message received. Process it + String title = msg.getContent(); + ACLMessage reply = msg.createReply(); + + Integer price = (Integer) catalogue.remove(title); + if (price != null) { + reply.setPerformative(ACLMessage.INFORM); + System.out.println(title+" sold to agent "+msg.getSender().getName()); + } else { + // The requested book has been sold to another buyer in the meanwhile . + reply.setPerformative(ACLMessage.FAILURE); + reply.setContent("not-available"); + } + myAgent.send(reply); + } else { + block(); + } + } + } // End of inner class OfferRequestsServer + +} // end of the agent class diff --git a/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookSellerGui.java b/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookSellerGui.java new file mode 100644 index 00000000..903d3964 --- /dev/null +++ b/tutorials/jason-jade/book_trading/src/main/java/examples/bookTrading/BookSellerGui.java @@ -0,0 +1,92 @@ +/***************************************************************** +JADE - Java Agent DEvelopment Framework is a framework to develop +multi-agent systems in compliance with the FIPA specifications. +Copyright (C) 2000 CSELT S.p.A. + +GNU Lesser General Public License + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation, +version 2.1 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*****************************************************************/ + +package examples.bookTrading; + +import jade.core.AID; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +/** + @author Giovanni Caire - TILAB + */ +class BookSellerGui extends JFrame { + private BookSellerAgent myAgent; + + private JTextField titleField, priceField; + + BookSellerGui(BookSellerAgent a) { + super(a.getLocalName()); + + myAgent = a; + + JPanel p = new JPanel(); + p.setLayout(new GridLayout(2, 2)); + p.add(new JLabel("Book title:")); + titleField = new JTextField(15); + p.add(titleField); + p.add(new JLabel("Price:")); + priceField = new JTextField(15); + p.add(priceField); + getContentPane().add(p, BorderLayout.CENTER); + + JButton addButton = new JButton("Add"); + addButton.addActionListener( new ActionListener() { + public void actionPerformed(ActionEvent ev) { + try { + String title = titleField.getText().trim(); + String price = priceField.getText().trim(); + myAgent.updateCatalogue(title, Integer.parseInt(price)); + titleField.setText(""); + priceField.setText(""); + } catch (Exception e) { + JOptionPane.showMessageDialog(BookSellerGui.this, "Invalid values. "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + } + } ); + p = new JPanel(); + p.add(addButton); + getContentPane().add(p, BorderLayout.SOUTH); + + // Make the agent terminate when the user closes + // the GUI using the button on the upper right corner + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + myAgent.doDelete(); + } + } ); + + setResizable(false); + } + + public void show() { + pack(); + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + int centerX = (int)screenSize.getWidth() / 2; + int centerY = (int)screenSize.getHeight() / 2; + setLocation(centerX - getWidth() / 2, centerY - getHeight() / 2); + super.show(); + } +} diff --git a/tutorials/jason-jade/figures/ams1.png b/tutorials/jason-jade/figures/ams1.png new file mode 100644 index 00000000..e5cac568 Binary files /dev/null and b/tutorials/jason-jade/figures/ams1.png differ diff --git a/tutorials/jason-jade/figures/ams2.png b/tutorials/jason-jade/figures/ams2.png new file mode 100644 index 00000000..d34e6ac7 Binary files /dev/null and b/tutorials/jason-jade/figures/ams2.png differ diff --git a/tutorials/jason-jade/figures/screen-df.png b/tutorials/jason-jade/figures/screen-df.png new file mode 100755 index 00000000..8ece4efc Binary files /dev/null and b/tutorials/jason-jade/figures/screen-df.png differ diff --git a/tutorials/jason-jade/index.html b/tutorials/jason-jade/index.html new file mode 100644 index 00000000..e78de725 --- /dev/null +++ b/tutorials/jason-jade/index.html @@ -0,0 +1,697 @@ + + + + + + + +Interoperation between Jason and JADE + + + + + + + +
+
+
+
+

This document aims to show how to create Jason agents that +participate in a multi-agent system (MAS) composed by “normal” JADE +agents (by normal we mean being not developed considering +interoperability with Jason). We will +develop a Jason book-seller agent that joins the system of the +traditional example of book trading that comes with JADE. The JADE +code will remain as in the example, it will not be changed to +interoperate with Jason.

+
+
+
+
+

A seller agent in Jason

+
+
+

The buyer agent, written in JADE, retrieves information about all +sellers from the DF, and then sends a CFP (call for proposal) message +to all those agents. The Jason agent has two tasks:

+
+
+
    +
  • +

    register itself in the DF as book seller, and

    +
  • +
  • +

    handle messages sent from buyers.

    +
  • +
+
+
+

The first task is performed with the Jason internal action .df_register (see the agent code below).

+
+
+

For the second task, since Jason agents use KQML-like performatives, +the performatives used by JADE agents are not available in Jason, +i.e., the semantics of those performatives are not implemented in +Jason (which implements the semantics of performatives such as tell, +askOne, achieve, etc.). We need therefore to write “low level” plans +to handle in AgentSpeak the CFP messages from JADE agents.

+
+
+

Every message that arrives in to Jason agent (and is accepted for +processing) produces an event like +!kqml_received(Sender, Performative, Content, MsgId) (the MsgId should be used to reply to +the message). We can then create plans to handle this event in the +particular case where the performative is CFP or ACCEPT_PROPOSAL:

+
+
+
john.asl
+
+
// Agent john
+
+/* Initial beliefs */
+
+// The book beliefs has three arguments:
+//   . the book name
+//   . the price
+//   . the quantity in stock
+
+book("Harry", 32, 20).
+book("Jason", 75, 10).
+
+
+/* Initial goals */
+
+!registerDF.
+
+/* Plans */
+
++!registerDF <- .df_register("JADE-book-trading", "book-selling"). // name, type 
+
+/* handle CFP performatives */
+
+// CFP
++!kqml_received(Sender, cfp, Content, MsgId)
+  :  book(Content, Price, Qtd) & Qtd > 0            // if I have the book
+  <- .send(Sender, propose, Price, MsgId).          // propose
+
++!kqml_received(Sender, cfp, Content, MsgId)
+  <- .send(Sender, refuse, "not-available", MsgId). // refuse otherwise
+
+
+// ACCEPT-PROPOSAL
++!kqml_received(Sender, accept_proposal, Content, MsgId)
+  :  book(Content, Price, Qtd) & Qtd > 0  // If I still have the book
+  <- -+book(Content, Price, Qtd-1);       // change stock
+     .print("New stock for ",Content," is ", Qtd-1);
+     .send(Sender, tell, Content, MsgId). // confirm
+
++!kqml_received(Sender, accept_proposal, Content, MsgId)
+  <- .send(Sender, failure, "not-available", MsgId).
+
+
+
+
+
+

Running the system

+
+
+

You can download all the application from here.

+
+
+

The JADE 'normal' agent can be started with ./gradlew runJadeAgs. This Gradle task essentially runs java jade.Boot -gui bob:examples.bookTrading.BookBuyerAgent(Harry), where the agent implementation is provided by JADE. The output will be:

+
+
+
+
...
+Hallo! Buyer-agent bob@10.200.0.100:1099/JADE is ready.
+Target book is Harry
+Trying to buy Harry
+Found the following seller agents:
+Trying to buy Harry
+Found the following seller agents:
+
+
+
+

ams1

+
+
+

Now you can run the Jason agent with ./gradlew runJohn. This Gradle task essentially runs java jade.Boot -container john:jason.infra.jade.JadeAgArch(src/agt/john.asl). The output will be:

+
+
+
+
....
+Agent container Container-1@10.200.0.100 is ready.
+starting john
+Agent mind inspector is running at http://127.0.0.1:3272
+New stock for Harry is 19
+
+
+
+

ams2

+
+
+

and in the output where Bob is running will change as follows, indicating it found agent john:

+
+
+
+
Trying to buy Harry
+Found the following seller agents:
+john@10.200.0.100:1099/JADE
+Harry successfully purchased from agent john@10.200.0.100:1099/JADE
+Price = 32
+Buyer-agent bob@10.200.0.100:1099/JADE terminating.
+
+
+
+
+
+

Exercises

+
+
+
    +
  • +

    Run the agents in different machines.

    +
  • +
  • +

    Write the code for a buyer agent in Jason that uses the DF to +find sellers, sends a CFP, select the cheapest, and only then buys +the book.

    +
  • +
+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/jason-jade/readme.html b/tutorials/jason-jade/readme.html new file mode 100644 index 00000000..e78de725 --- /dev/null +++ b/tutorials/jason-jade/readme.html @@ -0,0 +1,697 @@ + + + + + + + +Interoperation between Jason and JADE + + + + + + + +
+
+
+
+

This document aims to show how to create Jason agents that +participate in a multi-agent system (MAS) composed by “normal” JADE +agents (by normal we mean being not developed considering +interoperability with Jason). We will +develop a Jason book-seller agent that joins the system of the +traditional example of book trading that comes with JADE. The JADE +code will remain as in the example, it will not be changed to +interoperate with Jason.

+
+
+
+
+

A seller agent in Jason

+
+
+

The buyer agent, written in JADE, retrieves information about all +sellers from the DF, and then sends a CFP (call for proposal) message +to all those agents. The Jason agent has two tasks:

+
+
+
    +
  • +

    register itself in the DF as book seller, and

    +
  • +
  • +

    handle messages sent from buyers.

    +
  • +
+
+
+

The first task is performed with the Jason internal action .df_register (see the agent code below).

+
+
+

For the second task, since Jason agents use KQML-like performatives, +the performatives used by JADE agents are not available in Jason, +i.e., the semantics of those performatives are not implemented in +Jason (which implements the semantics of performatives such as tell, +askOne, achieve, etc.). We need therefore to write “low level” plans +to handle in AgentSpeak the CFP messages from JADE agents.

+
+
+

Every message that arrives in to Jason agent (and is accepted for +processing) produces an event like +!kqml_received(Sender, Performative, Content, MsgId) (the MsgId should be used to reply to +the message). We can then create plans to handle this event in the +particular case where the performative is CFP or ACCEPT_PROPOSAL:

+
+
+
john.asl
+
+
// Agent john
+
+/* Initial beliefs */
+
+// The book beliefs has three arguments:
+//   . the book name
+//   . the price
+//   . the quantity in stock
+
+book("Harry", 32, 20).
+book("Jason", 75, 10).
+
+
+/* Initial goals */
+
+!registerDF.
+
+/* Plans */
+
++!registerDF <- .df_register("JADE-book-trading", "book-selling"). // name, type 
+
+/* handle CFP performatives */
+
+// CFP
++!kqml_received(Sender, cfp, Content, MsgId)
+  :  book(Content, Price, Qtd) & Qtd > 0            // if I have the book
+  <- .send(Sender, propose, Price, MsgId).          // propose
+
++!kqml_received(Sender, cfp, Content, MsgId)
+  <- .send(Sender, refuse, "not-available", MsgId). // refuse otherwise
+
+
+// ACCEPT-PROPOSAL
++!kqml_received(Sender, accept_proposal, Content, MsgId)
+  :  book(Content, Price, Qtd) & Qtd > 0  // If I still have the book
+  <- -+book(Content, Price, Qtd-1);       // change stock
+     .print("New stock for ",Content," is ", Qtd-1);
+     .send(Sender, tell, Content, MsgId). // confirm
+
++!kqml_received(Sender, accept_proposal, Content, MsgId)
+  <- .send(Sender, failure, "not-available", MsgId).
+
+
+
+
+
+

Running the system

+
+
+

You can download all the application from here.

+
+
+

The JADE 'normal' agent can be started with ./gradlew runJadeAgs. This Gradle task essentially runs java jade.Boot -gui bob:examples.bookTrading.BookBuyerAgent(Harry), where the agent implementation is provided by JADE. The output will be:

+
+
+
+
...
+Hallo! Buyer-agent bob@10.200.0.100:1099/JADE is ready.
+Target book is Harry
+Trying to buy Harry
+Found the following seller agents:
+Trying to buy Harry
+Found the following seller agents:
+
+
+
+

ams1

+
+
+

Now you can run the Jason agent with ./gradlew runJohn. This Gradle task essentially runs java jade.Boot -container john:jason.infra.jade.JadeAgArch(src/agt/john.asl). The output will be:

+
+
+
+
....
+Agent container Container-1@10.200.0.100 is ready.
+starting john
+Agent mind inspector is running at http://127.0.0.1:3272
+New stock for Harry is 19
+
+
+
+

ams2

+
+
+

and in the output where Bob is running will change as follows, indicating it found agent john:

+
+
+
+
Trying to buy Harry
+Found the following seller agents:
+john@10.200.0.100:1099/JADE
+Harry successfully purchased from agent john@10.200.0.100:1099/JADE
+Price = 32
+Buyer-agent bob@10.200.0.100:1099/JADE terminating.
+
+
+
+
+
+

Exercises

+
+
+
    +
  • +

    Run the agents in different machines.

    +
  • +
  • +

    Write the code for a buyer agent in Jason that uses the DF to +find sellers, sends a CFP, select the cheapest, and only then buys +the book.

    +
  • +
+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/vscode-browser/figs/codespace1.png b/tutorials/vscode-browser/figs/codespace1.png new file mode 100644 index 00000000..c16ac448 Binary files /dev/null and b/tutorials/vscode-browser/figs/codespace1.png differ diff --git a/tutorials/vscode-browser/figs/codespace2.png b/tutorials/vscode-browser/figs/codespace2.png new file mode 100644 index 00000000..5842da17 Binary files /dev/null and b/tutorials/vscode-browser/figs/codespace2.png differ diff --git a/tutorials/vscode-browser/figs/vscweb1.png b/tutorials/vscode-browser/figs/vscweb1.png new file mode 100644 index 00000000..edf54fd2 Binary files /dev/null and b/tutorials/vscode-browser/figs/vscweb1.png differ diff --git a/tutorials/vscode-browser/figs/vscweb2.png b/tutorials/vscode-browser/figs/vscweb2.png new file mode 100644 index 00000000..5d906277 Binary files /dev/null and b/tutorials/vscode-browser/figs/vscweb2.png differ diff --git a/tutorials/vscode-browser/index.html b/tutorials/vscode-browser/index.html new file mode 100644 index 00000000..a8ff4482 --- /dev/null +++ b/tutorials/vscode-browser/index.html @@ -0,0 +1,539 @@ + + + + + + + +VSCode Browser (Web) as an IDE for Jason + + + + + + +
+
+

What You Will Build

+
+
+

In this document, you will build a web environment to develop agent-based system with Jason language.

+
+
+
+
+

Requirements

+
+
+
    +
  • +

    A GitHub account

    +
  • +
  • +

    A browser (Chrome and Safari works fine)

    +
  • +
+
+
+
+
+

Steps for GitPod

+
+
+

This IDE uses GitPod, so you will be asked to allow it to access your GitHub account.

+
+
+
    +
  1. +

    Open GitPod with the following link.

    +
  2. +
  3. +

    Register (or login) and then create a new workspace with the recommended settings.

    +
  4. +
  5. +

    Wait the initialization.

    +
  6. +
  7. +

    Open the main.mas2j file and you will get the same result as in the picture below

    +
  8. +
+
+
+

vscweb1

+
+
+

Run the MAS with the command ./gradlew run in the terminal.

+
+
+

vscweb2

+
+
+
+
+

Steps for GitHub CodeSpace

+
+
+
    +
  1. +

    Go the Jason Template project

    +
  2. +
  3. +

    Click on "use this template" and then "open in a codespace":

    +
  4. +
+
+
+

codespace1

+
+
+

Run the MAS with the command ./gradlew run in the terminal.

+
+
+

codespace2

+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/vscode-browser/readme.html b/tutorials/vscode-browser/readme.html new file mode 100644 index 00000000..a8ff4482 --- /dev/null +++ b/tutorials/vscode-browser/readme.html @@ -0,0 +1,539 @@ + + + + + + + +VSCode Browser (Web) as an IDE for Jason + + + + + + +
+
+

What You Will Build

+
+
+

In this document, you will build a web environment to develop agent-based system with Jason language.

+
+
+
+
+

Requirements

+
+
+
    +
  • +

    A GitHub account

    +
  • +
  • +

    A browser (Chrome and Safari works fine)

    +
  • +
+
+
+
+
+

Steps for GitPod

+
+
+

This IDE uses GitPod, so you will be asked to allow it to access your GitHub account.

+
+
+
    +
  1. +

    Open GitPod with the following link.

    +
  2. +
  3. +

    Register (or login) and then create a new workspace with the recommended settings.

    +
  4. +
  5. +

    Wait the initialization.

    +
  6. +
  7. +

    Open the main.mas2j file and you will get the same result as in the picture below

    +
  8. +
+
+
+

vscweb1

+
+
+

Run the MAS with the command ./gradlew run in the terminal.

+
+
+

vscweb2

+
+
+
+
+

Steps for GitHub CodeSpace

+
+
+
    +
  1. +

    Go the Jason Template project

    +
  2. +
  3. +

    Click on "use this template" and then "open in a codespace":

    +
  4. +
+
+
+

codespace1

+
+
+

Run the MAS with the command ./gradlew run in the terminal.

+
+
+

codespace2

+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/vscode/figs/app-files.png b/tutorials/vscode/figs/app-files.png new file mode 100644 index 00000000..963fceb1 Binary files /dev/null and b/tutorials/vscode/figs/app-files.png differ diff --git a/tutorials/vscode/figs/inst.png b/tutorials/vscode/figs/inst.png new file mode 100644 index 00000000..b5479a0d Binary files /dev/null and b/tutorials/vscode/figs/inst.png differ diff --git a/tutorials/vscode/index.html b/tutorials/vscode/index.html new file mode 100644 index 00000000..66b605fb --- /dev/null +++ b/tutorials/vscode/index.html @@ -0,0 +1,616 @@ + + + + + + + +VSCode as an IDE for Jason + + + + + + +
+
+

What You Will Build

+
+
+

In this document, you will build an environment to develop agent-based systems with Jason language.

+
+
+
+

Jason Installation

+
+
    +
  1. +

    Install Java 21

    +
  2. +
  3. +

    Install Visual Sudio Code

    +
  4. +
  5. +

    [windows] Install a terminal & shell tool like GitBash

    +
  6. +
  7. +

    Install Jason:

    +
    +
    +
    Unix and Windows
    +
    +
    +

    Download a Jason release from here (download the file named jason-bin-…​..zip) and decompress it. The zip file contains documentation, examples, and a sub-directory bin with the file jason. It is a unix executable file, if not, change its properties with chmod +x jason. Finally, adds the directory bin in your machine PATH so that the command jason can be executed in a terminal.

    +
    +
    +
    Linux
    +
    +

    You can use apt-get to install Jason (details here):

    +
    +
    +
    echo "deb [trusted=yes] http://packages.chon.group/ chonos main" | sudo tee /etc/apt/sources.list.d/chonos.list
    +sudo apt update
    +sudo apt install jason-cli
    +
    +
    +
    +
    +
    +
  8. +
+
+
+

To test the installation, run the command jason --version in a terminal. The output should be as follows:

+
+
+
+
Jason CLI 3.3.0
+
+
+
+

(You may need to close and open VSCode again to have Jason in its PATH terminal)

+
+
+

Create and run a new application

+
+
+

In a terminal, you can create a new Jason application, named app1, with the following command:

+
+
+
+
jason app create app1
+
+
+
+

A folder app1 is created for the application. Now you can open it with VSCode:

+
+
+

application

+
+
+

It has two agents (bob and alice) sharing a common environment. The code of the agents are in src/agt. The code of the environment is in src/env.

+
+
+

It would be useful to install a VSCode plugin that provides syntax highlight for Jason.

+
+
+

You can execute the application with

+
+
+
+
cd app1
+jason app1.mas2j -v
+
+
+
+

The two agents print a hello world message.

+
+
+ + + + + +
+ + +The first time you run a Jason application, it may take a while to start, since Gradle is being used and it downloads all dependencies. +
+
+
+

You can now change the code of your application and evolve the code of your agents.

+
+
+

Just as an example, change the code of alice.asl to

+
+
+
+
!start.
+
++!start <- .send(bob,tell,hello).
+
+
+
+

executes the system again, open the mind inspector, and see bob’s beliefs.

+
+
+
+
+

More on Jason CLI

+
+
+

To add more agents in your project:

+
+
+
+
jason app add-agent karlos
+
+
+
+

More commands for the application are shown with

+
+
+
+
jason app
+
+
+
+

and commands to monitor/control running applications with

+
+
+
+
jason mas
+
+
+
+

More about JasonCLI here.

+
+
+
+
+ + + \ No newline at end of file diff --git a/tutorials/vscode/readme.html b/tutorials/vscode/readme.html new file mode 100644 index 00000000..66b605fb --- /dev/null +++ b/tutorials/vscode/readme.html @@ -0,0 +1,616 @@ + + + + + + + +VSCode as an IDE for Jason + + + + + + +
+
+

What You Will Build

+
+
+

In this document, you will build an environment to develop agent-based systems with Jason language.

+
+
+
+

Jason Installation

+
+
    +
  1. +

    Install Java 21

    +
  2. +
  3. +

    Install Visual Sudio Code

    +
  4. +
  5. +

    [windows] Install a terminal & shell tool like GitBash

    +
  6. +
  7. +

    Install Jason:

    +
    +
    +
    Unix and Windows
    +
    +
    +

    Download a Jason release from here (download the file named jason-bin-…​..zip) and decompress it. The zip file contains documentation, examples, and a sub-directory bin with the file jason. It is a unix executable file, if not, change its properties with chmod +x jason. Finally, adds the directory bin in your machine PATH so that the command jason can be executed in a terminal.

    +
    +
    +
    Linux
    +
    +

    You can use apt-get to install Jason (details here):

    +
    +
    +
    echo "deb [trusted=yes] http://packages.chon.group/ chonos main" | sudo tee /etc/apt/sources.list.d/chonos.list
    +sudo apt update
    +sudo apt install jason-cli
    +
    +
    +
    +
    +
    +
  8. +
+
+
+

To test the installation, run the command jason --version in a terminal. The output should be as follows:

+
+
+
+
Jason CLI 3.3.0
+
+
+
+

(You may need to close and open VSCode again to have Jason in its PATH terminal)

+
+
+

Create and run a new application

+
+
+

In a terminal, you can create a new Jason application, named app1, with the following command:

+
+
+
+
jason app create app1
+
+
+
+

A folder app1 is created for the application. Now you can open it with VSCode:

+
+
+

application

+
+
+

It has two agents (bob and alice) sharing a common environment. The code of the agents are in src/agt. The code of the environment is in src/env.

+
+
+

It would be useful to install a VSCode plugin that provides syntax highlight for Jason.

+
+
+

You can execute the application with

+
+
+
+
cd app1
+jason app1.mas2j -v
+
+
+
+

The two agents print a hello world message.

+
+
+ + + + + +
+ + +The first time you run a Jason application, it may take a while to start, since Gradle is being used and it downloads all dependencies. +
+
+
+

You can now change the code of your application and evolve the code of your agents.

+
+
+

Just as an example, change the code of alice.asl to

+
+
+
+
!start.
+
++!start <- .send(bob,tell,hello).
+
+
+
+

executes the system again, open the mind inspector, and see bob’s beliefs.

+
+
+
+
+

More on Jason CLI

+
+
+

To add more agents in your project:

+
+
+
+
jason app add-agent karlos
+
+
+
+

More commands for the application are shown with

+
+
+
+
jason app
+
+
+
+

and commands to monitor/control running applications with

+
+
+
+
jason mas
+
+
+
+

More about JasonCLI here.

+
+
+
+
+ + + \ No newline at end of file