What you’ll build

This programming tutorial illustrates the programming of message oriented interaction between autonomous agents. You will develop a simple market place where an agent who wants to buy some product or service, announces its requirements, other agents bid, and the winner is then chosen.

In a market place, different interaction processes (interaction protocols) can be followed by the agents. Here we will consider a simple auction protocol and its implementation based on message exchanges:

  1. An auctioneer broadcasts a message with the requirements he/she would like to be satisfied

  2. Participants send him/her back messages with the prices

  3. The auctioneer broadcasts to the participants the winner of the auction process

What you’ll need

STEP 1. Simple Market Place

Learned features

In this step, you will learn:

  • How to send messages to agent

  • How to handle messages

  • How to use some internal functions

Understand

The very first implementation of the market has 5 agents:

  • bob (auctioneer): this agent is interested in buying a flight ticket from Paris to Athens.

  • francois, alice, maria, and giacomo (participants): each agent manages a travel agency, that is to say that they can sell flight tickets from somewhere to somewhere else at a certain price.

    Each time the participant gets an event corresponding to the reception of an auction for a service from an agent, it sends back a bid to this agent with a random price. This agent will only respond to auctions for services. Each service has a simple description.

Practice

Implement this system as follows:

1. Create a new JaCaMo project called auction_ag with the following project file content:

auction_ag.jcm
 1mas auction_ag {
 2
 3    agent bob: auctioneer.asl
 4
 5    agent alice   : participant.asl
 6    agent maria   : participant.asl
 7    agent francois: participant.asl
 8    agent giacomo : participant.asl
 9
10    asl-path: src/agt
11              src/agt/inc
12}

2. The agent code for the participant agents is composed of a simple plan. By this plan each time the participant gets an event corresponding to the creation of an auction belief for a service, it sends back a bid with a random price (you can improve as you want this strategy)

Notice that service (after +auction) is not a variable, so this agent will only respond to auctions for services. The variable D is bound to the description of the service. Variable A is bound to the source of the perception (bob in our case). The message has the format bib( <service description>, <price>).

participant.asl
1+auction(service, D)[source(A)] <-
2         .send(A,tell,bid(D, math.random * 100 + 10)).
3
4{ include("$jacamoJar/templates/common-cartago.asl") }
5{ include("$jacamoJar/templates/common-moise.asl") }

3. The agent code for the auctioneer bob is composed of two plans.

  • The first plan achieves the initial goal start by broadcasting an auction announcement. The message content has the form auction(<type>, <description>).

  • Bids are sent to bob by tell messages (see code of participants) and thus are represented as beliefs in his mind. Each belief addition produces an event like +bid(<service>,<price>) that is handled by the second plan. If the agent has already received 4 bids for this service, the winner is announced.

    To be able to handle all the bids that have been received you can use the internal actions .findall, as well as the function for getting the length of a list .length. To get the minimal value of a list you can use .min internal action. All these functions are described in Jason API.

auctioneer.asl
 1!start. // initial goal
 2
 3+!start <- .broadcast(tell, auction(service, flight_ticket(paris,athens,"15/12/2015"))).
 4
 5// Here comes the plan for handling received bids and checking for new winner
 6
 7
 8{ include("$jacamoJar/templates/common-cartago.asl") }
 9{ include("$jacamoJar/templates/common-moise.asl") }

Using the mind inspector after the execution shows the beliefs and sources of beliefs (notice the annotation source of the beliefs):

image

4. The execution of the application will look like the following screen:

image

STEP 2. Improving the auctioneer

Learned features

In this step, you will learn:

  • How to launch two goals in parallel and thus two auctions

  • How to launch a goal at a certain time

Understand

We modify the auctioneer agent so that it can launch two auctions concurrently. Notice that plans in bob and participants are triggered by events (+bid, +auction) and executed concurrently: participants can produce bids and auctioneer can receive bids concurrently.

In the current version, the auctioneer bob waits for exactly 4 bids! It is far from a good design choice: (i) the number of participants may be unknown and (ii) some of them may not respond. We will change the program auctioneer.asl so that a decision is taken after 10 seconds, regardless of the number of bids.

Practice

  • Create a new JaCaMo project in which you copy what you did in the previous step (you can also create it from the downloaded code of this step)

  • Modify the plan for the goal start so that its execution triggers two auctions in parallel

  • Refactor the program auctioneer.asl so that a decision is taken after 10 seconds, regardless of the number of bids, we can use the internal action .at. This internal action .at can be used to produce a goal after some time. For example, .at("now + 10 seconds", { +!decide } ) will create a new goal decide after 10 seconds.

STEP 3. Improving the participant

Learned features

In this step, you will learn:

Understand

  • In this step we change the code of participants so that they use broadcast to announce their bids (like an auction room where everyone can listen to the bids done by participants).

  • Participant agents can now listen the bids done by other participants.

  • We change the code of a participant agent (e.g. giacomo) so that as soon as it listens a bid from another agent for a service, it bids for the same service with a better price (i.e. lower price).

Practice

  • Create a new JaCaMo project in which you copy what you did in the previous step (you can also create it from the downloaded code of this step)

  • Refactor the participant.asl agent code so that instead of using a .send each agent broadcasts its bid (.broadcast)

  • Create a repeater.asl agent program having reactive plan that creates a new bid from each bid heared from the other agents.

  • Question: Based on the number of running auction a and participants p, how many messages are sent in the broadcast version developed in these exercises?

Solution: available here.

STEP 4. Introducing agents on the market place

Learned features

In this step, you will learn:

  • How to use the Jade platform

Understand

  • In the current system, bob starts the auction without checking that there are at least some agents in the market place.

  • We will solve this problem by adding some "introduction" step before starting the auctions:

    • the auctioneer agent introduces itself by announcing to the other agents that it plays initiator

    • the participant agents answer by announcing that they play participant in the market

  • As soon as the auctioneer agent knows that at least two agents are in the market place, it launches the auctions

  • In this step, we will use also the Jade Platform as the agent communication platform so that we can use it in a distributed setting. We will also test and use the Sniffer service of the Jade platform to see and inspect the messages that are exchanged in the system among the agents.

Practice

  • Create a new JaCaMo project in which you copy what you did in the previous step (you can also create it from the downloaded code of this step)

  • Refactor the code of auctioneer.asl, participant.asl and repeater.asl to integrate these changes

  • Change the code of auction_ag.jcm so that to introduce jade() in the platform section of this file

  • Simply adding platform: jade() at the end of the project file (auction_ag.jcm) will launch the use of the jade platform (See here for hints on the use of the `.jcm`file). Test and use the Sniffer agent of the Jade platform to see and inspect the messages that are exchanged in the system.

Hint: see the JADE Tutorial.

STEP 5. Auctioning through artifacts

Learned features

In this step, you will learn:

  • How to realize an auction artifact

Understand

  • Instead of using message exchanges among the agents, in this part of the tutorial we instrument the agents' environment with artifacts that will help the coordination required for the market place auction protocol.

  • The speech acts used in the direct messages exchanged between the agents are replaced by interaction through perception and action on artifacts

  • Instead of implementing the auction protocol within the agents' code as done in the previous part, we will externalise and encapsulate the coordination mechanism within an auction artifact shared between the agents.

  • Thanks to the abstractions provided in JaCaMo we can also situate this artifact in a workspace, duplicate it, and control its access.

  • Each auction is managed by one artifact instance where:

    • The auctioneer starts the auction setting the service description,

    • The participants perceive the service and likely do their bids,

    • After some time, the auctioneer stops the auction and the winner is defined.

  • Thus, the auction artifact has the following observable properties:

    • the service description,

    • the current best bid,

    • the current winner (shown only when the auction has finished),

    • whether the auction is running or not,

  • and the following operations:

    • start,

    • stop, and

    • bid.

Practice

  • Create a new JaCaMo project

  • Create a new artifact, called AuctionArtifact with the following initial code:

AuctionArtifact.java
package auction_env;

import jason.asSyntax.Atom;
import cartago.*;

public class AuctionArtifact extends Artifact {

    String currentWinner = "no_winner";

    @OPERATION public void init()  {
        // observable properties
        defineObsProperty("running",     false);
        defineObsProperty("task",        "no_task");
        defineObsProperty("best_bid",    Double.MAX_VALUE);
        defineObsProperty("winner",      new Atom(currentWinner)); // Atom is a Jason type
    }

    @OPERATION public void start(String task)  {
        if (getObsProperty("running").booleanValue())
            failed("The protocol is already running and so you cannot start it!");

        getObsProperty("task").updateValue(task);
        getObsProperty("running").updateValue(true);
    }

    @OPERATION public void stop()  {
        if (! getObsProperty("running").booleanValue())
            failed("The protocol is not running, why to stop it?!");

        getObsProperty("running").updateValue(false);
        getObsProperty("winner").updateValue(new Atom(currentWinner));
    }

    @OPERATION public void bid(double bidValue) {
       // this is where you have to act
        System.out.println("Operation not yet implemented / Come back later for "+getObsProperty("task").stringValue());
    }
}
  • In the project file, create a market workspace and the same agents as before, joining this workspace

  • Refactor the code of the auctioneer.asl so that the agent instead of sending messages for launching an auction, creates an auction artifact for each service to auction on and acts on the auction artifact with the proper operations

  • Refactor the code of the participant.asl so that the corresponding agents focus on the auction artifacts created by the auctioneer and bid the proper price on the corresponding artifact

  • What are the pros and cons of this solution wrt the direct exchange of messages?