What you’ll build

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

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

What you’ll need

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

STEP 1. Creating a simple MAS

Learned features

In this step, you will learn:

  • how to make agents

    • create workspaces and deploy artifacts in it

    • do actions on artifact

    • join a (remote) workspace

    • act in different workspaces

You will see:

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

Understand

The multi-agent system is built from artifact types, agent programs and jacamo scripting programs to launch and deploy the multi-agent system.

A simple type of GUI artifact: Env.java
  • This artifact 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 leaves a message on the MAS console when deployed in the MAS

// majordomo agent program
!setup_and_monitor.

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

...
The guest_agent agent program: guest_agent.asl
  • The guest_agent agent program defines plans for observing and acting in the environment.

  • For now, the plan in this program makes the agent use the printMsg operation of the env artifact.

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

// guest_agent agent program
/* Initial goals */
!greet.

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

...
server.jcm and client.jcm
  • These two jacamo scripting programs are used to distribute agents and artifacts in the multi-agent system

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

    • The client.jcm creates a client workspace and deploys artifacts and agents both in this workspace and in the server workspace. The agents will join also the server workspace to use artifacts that are deployed in it.

Practice

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

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

    • You can use the internal actions .my_name(Name) to get the name of the agent and .concat(str1,str2,Result) to concat str1 to str2 into Result.

  • Refactor the code of the guest_agent agent program and of the client.jcm jacamo script so that initialisation of goals and beliefs of this agent, joining remote workspace appear in the guest_agent agent program.

The new guest_agent agent program: guest_agent.asl
/* Initial goals */
!greet.

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

...
  • Execute first the server.jcm and then the client.jcm scripts

  • Refactor the code of the majordomo agent program and of the server.jcm script so that initialisation of goals and beliefs of this agent, creation of workspaces and artifacts appears in the majordomo agent programs.

The new majordomo agent program: majordomo.asl
/* 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!").

...
  • Execute first the server.jcm and then the client.jcm

STEP 2. Acting and observing artifacts

Learned features

In this step, you will learn how to make agents:

  • lookup or discover an artifact

  • observe an artifact

You will see:

  • definition of an artifact including observable properties

  • concurrent use and observation

Understand

In this step:

  • The 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 env

You can execute this step in group where one member of the group executes the "server" and the other members of the group execute each 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 script file.
mas client {
    agent guest_agent {
    	instances:   5
    }
...
}
  • An observer_agent agent program is added to define agents able of observing the env artifact and reacting to changes related to its observable property numMsg.

The observer_agent agent program: observer_agent.asl

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

// oberver agent program
+numMsg(N)
	<- .println("new message: total number is ",N).
...

Practice

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

  • Refactor the client.jcm jacamo script and the observer_agent 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

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

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

  • Adapt the client.jcm file so that several guest\_agent are executed.

STEP 3. Computing with Artifacts

Learned features

In this step you will learn:

  • how to define actions with feedbacks (output parameters) 'OpFeedbackParams API'

  • how to use in a sequence, operations on the same artifact

Understand

In this step:

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

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

  • A new agent program computer_agent will be added with a plan for joining the remote workspace, then using the computePi action and finally printing the value and your name using the action printMsg

Practice

  • Program the computer_agent as specified above

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

  • Execute the client part as soon as the majordomo agent invites you to do so

  • Modify the client.jcm for executing now all the agents

  • Execute the client part as soon as the majordomo agent invites you to do so

STEP 4. Coordination with the help of the artifact

Learned features

In this step you will learn:

  • How to use an artifact as a coordination mean

  • How to use GUARDs in artifact

Understand

In this step,

  • The env artifact 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 env, focuses on it and gets the value of the numMsg observable property.

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.

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

STEP 5. Coordination again by the way of artifact

Learned features

In this step, you will learn:

  • how to initialise artifacts with parameters

  • use artifacts as synchronization means

Understand

In this step:

  • The env artifact 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. .The majordomo agent program: majordomo.asl

// 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!").
...

Practice

  • Write a yourname_bis_agent writing 5 messages in sequence

    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.

STEP 6. Modularity / Instances of Artifacts

Learned features

In this step, you will learn:

  • how to improve extensibility, reusability

  • how to create and use multiple artifacts

Understand

  • With the previous implementation, we had a monolithic env 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 the env in multiple artifacts (types and instances). Let’s do a little bit of refactoring in this step.

  • Thus, for this step, the artifact env will be refactored and decomposed into msg_console, calculator, lock, barrier

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

Practice

  • Refactor the Env artifact as specified above (you can do this refactoring in an incremental way)

  • Refactor the agents code for using these artifacts.

STEP 7. Creating a Counter Artifact

Learned features

In this step, you will learn:

  • how to create artifact

  • how to create operations, observable properties, signals

Understand

In this step, you are going to create your own artifacts building a simple counting world example. In this world, counter 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'" signal every time it is executed by an agent.

  • The "'observer'" agent:

    • sends a message to the "'ticker'" agent and starts focusing on this artifact, as soon as it receives a message telling it the name of the counter artifact that has been created "'artifact\_counter\_is(Name)'".

    • stops focusing on the artifact as soon as the observable property "'count'" is equal to 6.

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

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

// Agent observer code
/* Initial beliefs and rules */

/* Initial goals */
!observe.

/* Plans */

+!observe : true
<-      println("Observer starting to work");
        lookupArtifact("counter",Count);
        +myTool(Count);
        focus(Count).
...
  • 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 ("'tell'", "'artifact\_counter\_is(counter)'"),

    • starts to use this artifact to increment the value of the counter as soon as it receives an answer of an agent

    • 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 time, it increments the artifact and prints a message.

// 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","easss.step7.Counter",[],C);
	.broadcast(tell,artifact_counter_is(counter)).

Practice

  • Write the code of the "'Counter'" artifact type.

  • Write the code of the "'observer'" agent (see template above to fill)

STEP 8. Creating a Bounded Counter Artifact

Learned features

In this step, you will learn:

  • to create and manipulate artifacts

  • to handle failure of actions in artifacts

  • to handle failure of actions in agent plans

Understand

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

  • Keeping the same agents, the "'Counter'" artifact will be transformed into a "bounded" counter artifact, i.e. its 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.

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

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

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'" artifact type, 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'"