Environment Oriented Programming

Practical work using CArtAgO within JaCaMo

Introduction

In the following, you will use a MAS with an environment deployed on multiple machines. You will develop some agents joining a remote workspace of this environment. The code is thus organized into two JaCaMo configuration files (.jcm): one for the MAS "kind-of" server, one for the MAS "kind-of" client.

  • The MAS server part ("step_main.jcm") provides you with the configuration file where some artifacts are deployed in the "server" workspace.
  • The MAS client part ("step.jcm") is refering to the agents that you will have to customize or develop. These agents will connect on the remote workspace to use artifacts that are deployed on this remote workspace.
  • For an agent deployed in the client part, use the action in the agent code: "joinRemoteWorkspace("default","localhost",WspID2)" where you replace "localhost" by the machine IP number.

Configuration

  • The standalone CArtAgO (Common ARTifact infrastructure for AGents Open environments) distribution can be downloaded from http://cartago.sourceforge.net/.
  • However, being already part of the JaCaMo Platform that you installed in the previous step (cf. Introduction), you don't have anything more to do to configure your working environment.
  • In this part of the practical work, we will use the Eclipse IDE with the JaCaMo plugin.

Preamble

Default artifacts at the disposal of agents:

By default, each workspace contains a basic set of predefined artifacts that provide core functionalities to the agents.

  • workspace artifact (see the [[./DOC/cartago/main-api/cartago/WorkspaceArtifact.html][Workspace API]): the workspace artifact (cartago.WorkspaceArtifact) provides functionalities to create, dispose, lookup, link, focus artifacts of the workspace. It provides also operations to set roles and policies related to the RBAC security model.
  • node artifact (see the Node API): the node artifact (cartago.NodeArtifact) provides functionalities to create new workspaces, to join local and remote workspaces
  • blackboard artifact: the blackboard artifact (cartago.tools.TupleSpace) provides a tuple space that agents can exploit to communicate and coordinate
  • console artifact: the console artifact (cartago.tools.Console) provides functionalities to print messages on standard output.

How to make agents invoque operations of the artifact

  • In case of operation invocation with no specification of target artifact: the artifact is automatically selected from the workspace. If there are no artifacts providing such action, the action fails. if more than one artifact is found, artifacts created by the agent itself are considered first. If more than one artifact is found, one is selected non deterministically. Then, the rest of the artifacts are considered, and one is selected non deterministically.
  • In case of operation invocation with specification of a target artifact: This is done by adding the annotation [artifact_id(Id)], where Id must be bound to the artifact identifier. Alternatively, the annotation [artifact_name(Name)] can be used, where Name must be bound to the logic name of the artifact.
  • In case of operation invocation with specification of the target workspace: done by adding the annotation [wsp_id(WspID)], where WspID must be bound to the wsp identifier.

How to make agents work in workspaces

  • By default an agent, when launched, joins the default workspace on current node.
  • Agents can create, join and work in multiple workspace at a time. However there is always a current workspace, to which are routed actions with no artifact id or workspace id specified. Current workspace info are automatically tracked by the current wsp(WspId,Name,NodeId) belief.
  • Agents can join workspaces that are hosted on remote nodes, by means of a joinRemoteWorkspace action. As soon as the join succeed, the interaction within remote workspaces is the same as local workspace.
  • Infrastructure options:
    • by default, Jason programs using CArtAgO environment create a standalone CArtAgO node, i.e. not accessible through the network
    • To install a CArtAgO node accessible also to remote agents further parameters can be specified to the c4jason.CartagoEnvironment:
      • c4jason.CartagoEnvironment("infrastructure"{,WspName, protocol(ProtName, Address), …}): installs an infrastructure layer specifying the protocols to support and the local address where to start the service;
      • c4jason.CartagoEnvironment("remote"{,WspName, protocol(ProtName, Address), …}): does not install any node – agents directly join the specified remote workspace;
      • c4jason.CartagoEnvironment("local"{,WspName}): does not install any node – agents directly join the specified locak workspace.

Step 1: Joining workspaces and using Artifacts (part a, b)

In this step, the configuration is as follows:

  • In the workspace running on the server, a very simple artifact of type "EnvBasic", called "env" has been deployed. This artifact will be enriched step by step with actions and observable properties.
  • The first version of this artifact has one action "printMsg(String msg)". This action prints the parameter "msg" on the standard output adding the name of the emitter of this message
  • On the server, the "majordomo" agent creates the workspace and the artifact, and leaves a message
"majordomo" agent code:

!setup_and_monitor.

+!setup_and_monitor
        <-      createWorkspace("server");
                joinWorkspace("server",Id);
                !setupArtifacts.
                
+!setupArtifacts
        <- makeArtifact("env","easss.step.EnvBasic",[]);
           printMsg("ready. Your turn!").

a. Create a MAS acting on a simple artifact for leaving a message in different workspaces

  • Download the code for this step and install it in your maop eclipse workspace as a jacamo project.
  • Look at the code of the "guest_agent":
    • it joins the remote workspace and leaves one message.
  • Add an action in its plan so that the "guest_agent" leaves a message consisting of your name. You can use the internal action ".my_name(Name)" to get the name of the agent, the internal action ".concat(str1,str2,Result)" to concat str1 to str2 in Result.
  • Using the two configuration files, execute first the main configuration file (i.e. execution of the MAS server part) and then the other configuration file (i.e. execution of the MAS client part) as soon as you see the message from the "majordomo" agent).

b. Create a MAS acting on a more complex artifact for leaving a message in different workspaces

  • Modify the code of the majordomo agent so that it creates now an artifact of type Env ( / makeArtifact("env","easss.step.Env",[]);/)
  • The artifact "env" running on the server has been changed. Its action "printMsg(String msg)" has an effect on a GUI version now.
  • Reuse the "guest_agent" that you have developed in the previous exercise and execute the client part as soon as the "majordomo" agent invites you to do so.

Note

  • You can execute this exercise in group where one member of the group executes the "server" and the other members of the group execute the MAS containing the "guest_agent" that joins this remote workspace.
  • You can specify the number of agents of a certain agent types to execute by using the keyword instances: followed by the number of instances in the configuration file in the definition of an agent
mas step {
    agent guest_agent {
        instances:   5   
    }
...    
}

Learned features

In this step, you have learned:

  • how to create (a workspace and) an artifact
  • how to do actions on artifact
  • how to join a (remote) workspace
  • definition of a basic artifact exposing some operations
  • see and experiment the concurrent use of an artifact by multiple agents (mutual exclusive access, no race conditions)

Step 2: Observing Artifacts

In this step:

  • The artifact "env" has been enriched with an observable property numMsg showing the number of messages left so far.
  • A couple of guest agents repeatedly place messages on env
  • An observer agent has been added, observing the env artifact and reacting to changes related to the numMsg observable property

c. Create a MAS for "observing" artifacts situated in the environment

  • Download the code for this step and install it in your maop eclipse workspace as a jacamo project.
  • Look at the code of the "guest_agent": it joins the workspace and leaves a message for ever.
  • Adapt this agent so that it leaves a message corresponding to the room ID in which you are situated.
  • Look at the code of the "observer" agent aiming at observing the "env" artifact. The "observer" agent joins the remote workspace, lookups for the artifact "env", focuses on this artifact and gets the value of the "numMsg" observable property of this artifact.
  • Adapt the "observer" agents so that it prints a message only when number of message is included in the range 10..40.
  • Adapt the configuration file of the client part so that many guest_agent are executed.
  • As in the previous steps, execute the client part as soon as the "majordomo" agent invites you to do so.

Learned features

In this step, you have learned:

  • how to lookup or discover an artifact
  • how to observe an artifact
  • definition of an artifact including observable properties
  • concurrent use and observation

Step 3: Computing with Artifacts

In this step:

  • The artifact "env" has been enriched with a "computePi" action (with output parameters "OpFeedbackParams")
  • We still have the observer and guest agents of the previous step. You can reuse the "observer" agent that you adapted in the previous exercise

d. Create your first agent for computing

  • Download the code for this step and install it in your maop eclipse workspace as a jacamo project.
  • Write your first Jason Agent "YOURNAME_agent" with code for joining the remote workspace, using this "computePi" action. After computing PI, the agent prints the value and your name using the action "printMsg"
  • Modify the config file step.jcm for executing only this new agent in the client part
  • Execute the client part as soon as the "majordomo" agent invites you to do so
  • Modify the config file step.jcm for executing all the agents in the client part
  • Execute the client part as soon as the "majordomo" agent invites you to do so

Learned features

In this step you have learned:

  • how to define actions with feedbacks (output parameters) OpFeedbackParams API
  • how to use in a sequence, operations on the same artifact

Step 4: Coordination with the help of the artifact

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 the artifact "env" and gets the value of the "numMsg" observable property.

e. "let's coordinate - Don't interfere!"

  • Download the code for this step and install it in your maop eclipse workspace as a jacamo project.
  • Develop your own Jason Agent "YOURNAME_agent" 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 your Jason Agent using the "lock" and "unlock" operations to leave three messages in sequence in a synchronized way.
  • Execute the client part again.

Learned features

In this step, you have learned:

  • How to use an artifact as a coordination mean
  • How to use GUARDs in artifact

Step 5: Coordination again by the way of artifact

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 in the "env" artifact.
majordomo agent code:

!setup_and_monitor.

+!setup_and_monitor
        <-      createWorkspace("server");
                joinWorkspace("server",Id);
                !setupArtifacts;
//        setupBarrier(3).
                
+!setupArtifacts
        <- makeArtifact("env","easss.step5.Env",[3]);
           printMsg("ready. Your turn!"). 

f. Synchronization by the way of an artifact

  • Download the code for this step and install it in your maop eclipse workspace as jacamo project.
  • Write a "YOURNAME_agent" writing 5 messages in sequence and then use the synchronisation between all agents provided by the artifact operation "sync"

Note

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

Learned features

In this step, you have learned:

  • how to initialise artifacts with parameters
  • use artifacts as synchronization means

Step 6: Modularity / Instances of Artifacts

  • 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" has been refactored and decomposed into "msg_console", "calculator", "lock", "barrier"
  • The majordomo agent has been changed to create instances of these artifacts in the workspace.
  • The observer agent has been changed to focus on the proper artifact.

g. Using a world of artifacts

  • Download the code for this step and install it in your maop eclipse workspace as a jacamo project.
  • Adapt, if needed, the "YOURNAME_agent" code for using these artifacts.

Learned features

In this step, you have learned:

  • how to improve extensibility, reusability
  • how to create and use multiple artifacts

Step 7: Creating a Counter Artifact

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

h. Create a Counter Artifact

  • Download the code for this step and install it in your maop eclipse workspace as a jacamo project.
  • Write the code of the "Counter" artifact type.
  • Write the code of the "observer" agent (see template above to fill)

Learned features

In this step, you have learned:

  • how to create artifact
  • how to create operations, observable properties, signals

Step 8: Creating a Bounded Counter Artifact

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

i. Create Bounded Counter Artifact

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

Learned features

In this step, you have learned:

  • to create and manipulate artifacts
  • to handle failure of actions in artifacts
  • to handle failure of actions in agent plans

Step 9: Going deeper in the use of Cartago

  • We strongly invite you to have a look at the set of exercises that are provided in the cartago distribution: here

Step 10: Coming back to the Gold Miners Tutorial

Coming soon …

Step 11: Artifact-Based Auction House

  • This last exercise is dedicated to the development of a MAS where agents use an artifact to execute an auction protocol to allocate a set of tasks between them. You can get here the specification of the global application.
  • The contractor agent, "giacomo" creates an artifact of this type for each of the tasks it needs to allocate the tasks to "company" agents: e.g. one auction artifact for building the walls, another one for setting the floors, …
  • The "company" agents observe the artifacts that propose a task compatible with goals and skills. They use these artifacts for bidding according to their own strategies.

Auction Artifact

  • The "AuctionArt" artifact has the following observable properties:
    • "task": task description,
    • "maxValue": maximum payment value,
    • "currentBid": current best bid (lower service price),
    • "currentWinner": current winning agent ID
  • It has the following operations:
    • "bid(p)": places a new bid for doing the task for price "p". If the bid is better than the previous one, the "currentBid" and the "currentWinner" are updated.
    • "init(task,maxp)": initializes the artifact with the task description "task" that will be auctionned and the maximum value for the bid "maxp".

How to get the name of agent that executes an action:

  • In an artifact, the method "getOpUserName" returns the name of the agent that is executing an action.

Create the Auction House

  • Create a jacamo project called "auction".
  • Define the "AuctionArt" artifact as described above.

Owner Agent

  • The "giacomo" agent is in charge of creating the auction house, i.e. to create an artifact of the type "AuctionArt" for each of the tasks to allocate to other agents
  • The "giacomo" agent is also in charge of driving and managing the auctions (the creation of an auction artifact consists in declaring the task that is managed by the artifact and the maximum possible price for it).
  • The agent waits for a certain amount of time for the bids. At the fixed time, the agent gets the winner for each of the tasks.
// Agent giacomo

/* Initial beliefs and rules */
my_task("SitePreparation").
my_task("Floors").
my_task("Walls").

my_max_bid("SitePreparation",2000).
my_max_bid("Floors",1000).
my_max_bid("Walls",3000).

/* Initial goals */

!contract.

/* Plans */

+!contract : true <- 
        !create_auction_house;
        !wait_for_bids.

 +!create_auction_house <-
        for (my_task(Task) & my_max_bid(Task,MaxPrice)) {
                !create_auction_artifact(Task,MaxPrice);
                .println("creating an auction artifact for ",Task);     
        }.
        
+!create_auction_artifact(Task,MaxPrice) <-
        makeArtifact(Task,"easss.auction.AuctionArt",[Task,MaxPrice],ArtId);
        focus(ArtId).

-!create_auction_artifact(Task,MaxPrice)[error_code(Code)] <-
        .print("Error creating auction artifact ",Code).

+!wait_for_bids <-
        .print("Waiting for bids for 5 seconds ...");
        .wait(5000);
        !show_winners.
...

Create the Owner Agent

  • Complete the "giacomo" agent for managing the auctions as described above

Iteration implementation

  • The implementation of the iteration on the auction artifacts can be done using the for construct:
Implementation of for.

Syntax:
  for ( logical formula ) {
     plan_body
  }

for all unifications of logical formula, the plan_body is executed.

Example:

+event : context
  <- ....
     for ( vl(X) ) {
        .print(X);     // print all values of X
     }
     for ( .member(X,[a,b,c]) ) {
        .print(X);    // print all members of the list
     }
     for ( .range(I,1,10) ) {
        .print(I);    // print all values from 1 to 10
     }
     ....

The unification resulting from the evaluation of the logical formula is used only inside the loop, i.e., the unification after the for is the same as before. 

Company Agents

  • The company agents discover the auction artifacts corresponding to the tasks they are interested in. They build the bids according to their own strategies.

Create Company agents

  • Write a "company_blind" agent interested in the tasks "sitePreparation", "Floors", "Walls" having a "blind" strategy for bidding: it decreases the current bid by a constant value until his/her lowest limit is reached.
  • Write a "company_strategies" agent having multiple strategies for each task (choose which strategy to use)
  • Write a "company_coordinated" agent having a maximum value for all the tasks it bids for (i.e. coordination of the bids it realizes on each task)

How to make agents aware that it is winning an auction

  • You can use the following code for making an agent aware that it is winning or not an auction:
i_am_winning(Art)   // check if I placed the current best bid on auction artifact Art
   :- currentWinner(W)[artifact_id(Art)] & .my_name(Me) & .term2string(Me,MeS) & W == MeS.
  • You can use the following code for summing all the current bids placed by the agent
sum_of_my_offers(S) :- 
   .my_name(Me) & .term2string(Me,MeS) &
   .findall( V,      // artifacts/auctions I am currently winning
             currentWinner(MeS)[artifact_id(ArtId)] &
                      currentBid(V)[artifact_id(ArtId)], 
             L) & 
   S = math.sum(L).

Olivier Boissier, November 2014