What you’ll build

The focus of this tutorial is on the programming of the environment of a multi-agent system.

You will program agents situated in a simple shared environment with a set of resources encapsulated in artifacts that agents can observe and/or act on.

In this tutorial, you will program a multi-agent system with an environment shared among agents and possibly deployed on multiple machines. The code is organized into two JaCaMo project files (.jcm): one for a so-called server workspace, one for a client one.

What you’ll need

Code

  • Access to the whole code of this tutorial (it contains all the necessary code for each of the following steps). If you prefer, you can also download each particular piece of code in each of the corresponding step.

1. Creating a simple MAS

Learned features in this step

  • how to make agents able to:

    • create workspaces and deploy artifacts in it

    • do actions on artifact

    • join a (remote) workspace

    • act in different workspaces

  • definition of a basic artifact exposing some operations

  • distributed execution of a MAS

  • the concurrent use of an artifact by multiple agents (mutual exclusive access, no race conditions)

1.1. Explanations

The multi-agent system is programmed by defining artifact templates (in java) and agent programs (in jason agent programming language). The jacamo project files launch and deploy the multi-agent system by creating and executing artifacts, workspaces and agents.

A simple template of GUI artifact: Env.java
  • This artifact (in src/env/tools/Env.java) has one operation printMsg(String msg). This operation prints on the standard output the msg followed by the name of the agent executing the action.

  • This artifact will be enriched step by step with operations and observable properties.

The majordomo agent program: majordomo.asl
  • The majordomo agent program (in src/agt/majordomo.asl) prints a message on the MAS console when deployed in the MAS

1
2
3
4
5
6
7
8
// majordomo agent program
!setup_and_monitor.

+!setup_and_monitor
        <-    print("ready. Your turn!").

{ include("$jacamoJar/templates/common-cartago.asl") }
{ include("$jacamoJar/templates/common-moise.asl") }
The guest_agent agent program: guest_agent.asl
  • The guest_agent agent program (programmed in src/agt/guest_agent.asl) has plans for observing and acting in the environment.

  • For now, there in one plan with the action printMsg, operation of the artifact template Env.

  • This agent program will be enriched step by step during this tutorial

1
2
3
4
5
6
7
8
9
10
// guest_agent agent program
/* Initial goals */
!greet.

/* Plans */
+!greet : true
          <-  printMsg("Hello from guest").

{ include("$jacamoJar/templates/common-cartago.asl") }
{ include("$jacamoJar/templates/common-moise.asl") }
server.jcm and client.jcm
  • These two jacamo .jcm files are used to create and deploy agents, workspaces and artifacts in the multi-agent system on a single or several nodes:

    • The server.jcm creates a server workspace and deploys artifacts and agents in it on one node

    • The client.jcm creates a client workspace on a different node and deploys artifacts and agents both in this workspace and in the server workspace. The agents created by this project file join also the server workspace to use artifacts that are deployed in it.

1.2. Practice

  • Execute first the server.jcm project file on one machine and the client.jcm project file on another machine (specify the IP in the node information of this file) or on the same machine (use of localhost).

  • Add an action in the agent’s plan so that the agent leaves a message consisting of its name.

  • Refactor the code of the guest_agent agent program and of the client.jcm jacamo project file so that guest_agent (i) has one initial goal greet and (ii) joins remote workspace through explicit use of joinRemoteWorkspace operation.

    joinRemoteWorkspace(String wspName, String address, OpFeedbackParam<WorkspaceId> res) where wspName is the workspace name, address is the address and res is the output parameter receiving the workspace id.

    This agent has now two plans for achieving greet goal and setup sub-goal (created within execution of plan to achieve greet). The plan for achieving setup consists in one action joining the remote workspace.

The new guest_agent agent program: guest_agent.asl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Initial goals */
!greet.

/* Plans */
+!greet : true
          <-  !setup;
                .my_name(Name);
                .concat("Hello from ",Name,Msg);
                printMsg(Msg).
+!setup
        <- joinRemoteWorkspace("server","localhost",_).

{ include("$jacamoJar/templates/common-cartago.asl") }
{ include("$jacamoJar/templates/common-moise.asl") }
  • Execute first the server.jcm and then the client.jcm project files.

  • Refactor the code of the majordomo agent program and of the server.jcm project file so that initialisation of goals and beliefs of this agent, creation of workspaces and artifacts are realized in the majordomo agent program.

To that aim, you will use the operations createWorkspace, joinWorkspace, makeArtifact and focus.

  • createWorkspace(String wspName) where wspName is the workspace name.

  • joinWorkspace(String wspName, OpFeedbackParam<WorkspaceId> res) where wspName is the workspace name and res is the output parameter receiving the workspace id.

  • makeArtifact(artifactName, String templateName, OpFeedbackParam<ArtifactId> aid) where name is the name of the artifact, templateName is the artifact template (type) and aid is the output parameter receiving the artifact id.

  • focus(aid) where aid is the artifact id on which to focus.

The new majordomo agent program: majordomo.asl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Initial goals */
!setup_and_monitor.

+!setup_and_monitor
        <-  createWorkspace("server");
            joinWorkspace("server",Id);
            !setupArtifacts.

+!setupArtifacts
        <- makeArtifact("env","tools.Env",[],Id);
           focus(Id);
           print("ready. Your turn!").

{ include("$jacamoJar/templates/common-cartago.asl") }
{ include("$jacamoJar/templates/common-moise.asl") }
  • Execute first the server.jcm and then when the server is running, the client.jcm project files.

2. Acting on artifacts and observing artifacts

  • Download the code used in this step (initial and solution in a single zipped file) contains a new version of the template artifact 'Env'. You can also reuse the code of the agents that you developed in the previous step.

Learned features in this step

  • how to make agents able to:

    • lookup or discover an artifact

    • observe an artifact

  • definition of an artifact including observable properties

  • concurrent use and observation of an artifact by an agent

2.1. Explanations

  • The template artifact Env is enriched with an observable property ‘numMsg’ showing the number of messages left so far on the artifact by the different agents

  • A couple of agents of type guest_agent repeatedly place messages on the artifact of type Env created in the workspace

You can execute this step in group where one member of the group executes the "server" and each member of the group execute the MAS containing the guest_agent that joins the remote workspace of the server.
You can specify the number of agents of a certain agent types to be executed by using the keyword instances: followed by the number of instances in the definition of an agent of the jacamo project file (more detailed information on jacamo project file)
1
2
3
4
5
6
mas client {
    agent guest_agent {
            instances:   5
    }
...
}
  • An observer_agent.asl agent program is added to define agents able of observing artifacts of type Env and reacting to changes related to its observable property numMsg.

The observer_agent agent program: observer_agent.asl

The observer_agent.asl agent program and the client.jcm make this agent joins the remote workspace server, lookups for the artifact env (of type Env), focuses on this artifact and gets the value of the numMsg observable property of this artifact.

1
2
3
4
5
6
// oberver agent plan reacting to change of belief
+numMsg(N)
        <- .println("new message: total number is ",N).

{ include("$jacamoJar/templates/common-cartago.asl") }
{ include("$jacamoJar/templates/common-moise.asl") }

2.2. Practice

  • Execute the server.jcm jacamo project file and the client.jcm as soon as the "'majordomo'" agent invites you to do so on the console.

  • Refactor the client.jcm jacamo project file and the observer_agent.asl program so that the agent joins the remote workspace server, looks up for artifact, focuses on it instead of having this done within the client.jcm project file.

  • Refactor the code of the guest_agent.asl program so that it leaves a message for ever.

  • Refactor the observing plan of the observer_agent.asl program, so that the agent prints a message only when the number of messages is in the range 10 to 40.

  • Adapt the client.jcm project file so that several guest_agent are executed.

3. Computing with Artifacts

  • Download the code used in this step (initial and solution in a single zipped file) contains a new version of the template artifact 'Env'. You can reuse the code of the agents that you developed in the previous step.

Learned features in this step

  • how to define operations with feedbacks (output parameters) 'OpFeedbackParams API' in an artifact

  • how to use operations on the same artifact in a sequence within a plan body

3.1. Explanations

In this step:

  • The template artifact Env has been enriched with a computePi action (with output parameters "'OpFeedbackParams'")

  • Agents defined from the observer_agent.asl and guest_agent.asl agent programs of the previous step are still present in the MAS

  • A new agent program computer_agent.asl is added with a plan for joining the remote workspace, using the computePi operation and finally printing the value concatanated to your name using the action printMsg

3.2. Practice

  • Program the computer_agent.asl as specified above

  • Modify the client.jcm by commenting the launch of the execution of the agents from the previous steps and by adding the launch of this new agent

  • Execute the client part as soon as the majordomo agent invites you to do so by printing a message in the console

  • Stop the MAS client side (let the MAS server side run) and Modify the client.jcm for executing now all the agents

  • Execute the client part

4. Coordination with the help of the artifact

  • Download the code used in this step contains a new version of the template artifact 'Env'. You can reuse the code of the agents that you developed in the previous step.

Learned features in this step

  • How to use an artifact as a coordination mean

  • How to use GUARDs in artifact

4.1. Explanations

In this step,

  • The template artifact Env has been enriched to install mutual exclusion in the actions for leaving messages.

    It has a private attribute locked and two operations lock and unlock insuring the mutual exclusion.

  • The agent that you will develop for this step in the client part, will use these actions to access in an exclusive way to the artifact and print the messages in sequence.

  • The observer agent as in the previous steps, joins the workspace, lookups for the artifact of type Env, focuses on it and gets the value of the numMsg observable property.

4.2. Practice

  • Develop your own agent yourname_agent (yourname has to be replaced by your name) based on the guest_agent code so that your agent leaves three messages in sequence.

  • Execute the client part as soon as the "'majordomo'" agent invites you to do so by printing a message in the console

  • Transform the behaviour of your agent using the lock and unlock operations to leave three messages in sequence in a synchronized way.

  • Execute the client part again.

5. Coordination again by the way of artifact

  • Download the code used in this step contains a new version of the template artifact 'Env'. You can reuse the code of the agents that you developed in the previous step.

Learned features in this step

  • how to initialise artifacts with parameters

  • use artifacts as synchronization means

5.1. Explanations

In this step:

  • The template artifact Env has been enriched with a synchronisation operation sync and with the possibility to setup a number of participants for the synchronization setupBarrier or via initialisation.

  • The majordomo agent has been enriched to setup the barrier using the env artifact of type Env.

The majordomo agent program: majordomo.asl
1
2
3
4
5
6
7
8
9
10
11
12
13
// majordomo agent program

!setup_and_monitor.

+!setup_and_monitor
        <-         createWorkspace("server");
                joinWorkspace("server",Id);
                !setupArtifacts.

+!setupArtifacts
        <- makeArtifact("env","tools.Env",[3]);
           printMsg("ready. Your turn!").
...

5.2. Practice

  • Write a yourname_bis_agent.asl program writing 5 messages in sequence

    To that aim, you have to use the synchronisation between all agents provided by the artifact operation sync

  • You can do this exercise using a common env server and connecting the agents developed by different students.

6. Modularity / Instances of Artifacts

Learned features in this step

  • how to improve extensibility, reusability

  • how to create and use multiple artifacts

6.1. Explanations

  • With the previous implementation, we had a monolithic Env template artifact. It could cause some problems, for instance, if adding a long-term action such as computePi. Why?

  • A better way could be to decompose this template artifact Env in multiple artifacts (templates and instances).

  • Let’s do a little bit of refactoring in this step to obtain such a modular set of artifacts.

  • Thus, for this step, you will refactor the template artifact Env and decompose it into a template GUIConsole artifact (with instance msg_console), a template Calculator artifact (with instance calculator), a template Lock artifact (with instance lock) and a template Barrier artifact (with instance barrier).

  • The agents and the .jcm project files will have to be changed to take into account this refactoring.

6.2. Practice

  • Refactor the Env template artifact as specified above (you can do this refactoring in an incremental way, i.e. creating and testing each new modular artifact)

  • Refactor the agents code for using these artifacts.

7. Creating a Counter Artifact

Learned features in this step

  • how to program artifact

  • how to program operations, observable properties, signals

7.1. Explanations

In this step, you are going to program your own artifacts building a simple counting world example. In this world, ticker agents and observer agents are situated in the default workspace and use counting artifacts.

  • The Counter artifact is a simple artifact composed of a count observable property initialized to 0 when the artifact is created.

    The artifact has a single operation inc without any parameters. This operation increments count and sends a tick(v) signal every time it is executed by an agent, where v is the current value of the count observable property.

  • The ticker agent:

    • creates the counter artifact of type Counter and tells to all the agents that are in the MAS the name of this artifact .broadcast(tell, artifact_counter_is(counter)),

    • starts to use this artifact as soon as it receives an answer of one of the agents that it reached

    • Being a lazy agent, it rests for a while (let’s say 100 ticks), after each increment. It does this job for 100 cycles. Every cycle, it increments the artifact and prints a message.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Agent ticker code
/* Initial beliefs and rules */

/* Initial goals */
!setup.

/* Plans */

+!setup : true <-
        !setupCounter(Id);
        +counter(Id);
        !increment.

+!increment : ready[source(Ag)] & counter(Id) <-
        for (.range(I,1,100)) {
                .wait(100);
                inc[artifact_id(Id)];
                .print("incrementing");
                }.

+!increment : not ready[source(Ag)] <-
        !increment.

+!setupCounter(C) : true <-
        makeArtifact("counter","tools.Counter",[10],C);
        .broadcast(tell,artifact_counter_is(counter)).
  • The observer agent:

    • answers to the message sent by the ticker agent, telling this agent that it is ready

    • lookup for this artifact with the name sent by ticker, and starts focusing on this artifact

    • stops focusing on the artifact as soon as the observable property count is equal to 60

    • prints a message observed new value with the value, each time the observable property is changed.

    • prints a message perceived a tick with the name of the artifact in which a tick has been done.

7.2. Practice

  • Write the code of the Counter artifact template

  • Write the code of the ticker agent

  • Write the code of the observer agent

8. Creating a Bounded Counter Artifact

  • If you didn’t realize previous step, you can get the code used in this step otherwise just use the result of previous step

Learned features in this step

  • to create and manipulate artifacts

  • to handle failure of actions in artifacts

  • to handle failure of actions in agent plans

8.1. Explanations

In this step, we are going to extend the previous simple counting world example.

  • Keeping the same agents, the Counter artifact is transformed into a "bounded" counter artifact, i.e. the observable property count cannot be higher than a maximum value fixed at the initialisation of the artifact.

  • The artifact generates a failure signal when its action inc is no more possible.

Hints: Handling failure
  • The failed primitive is used to program the failure of an operation:

1
2
failed(String failureMsg)
failed(String failureMsg, String descr, Object... args)
  • An action feedback is generated, reporting a failure msg and optionally also a tuple descr(Object…​) describing the failure.

  • The annotation that you can use in the agent code, is a follows:

[error_msg(Msg),env_failure_reason(inc_failed("max_value_reached",Value))]

8.2. Practice

  • Create a 'jacamo' project called step8.

  • Reuse the code of the previous step and install it in step8

  • Change the code of the Counter template artifact, so that it behaves as described above

  • Change the code of the ticker agent so that it executes a plan in case of failure of the action inc