Protocoles d’interaction FIPA
Les protocoles d’interaction FIPA définissent des séquences standardisées
d’échanges ACL entre agents. Ils sont implémentés dans include/gagent/protocols/
sous forme de Behaviour réutilisables.
Contract Net (FIPA SC00029H)
Le Contract Net Protocol permet à un agent (initiateur) de déléguer une tâche à l’agent le plus qualifié parmi plusieurs candidats (participants), via un mécanisme d’enchère.
Initiateur Participants
│ │
│── CFP ────────────►│ "qui peut faire X ?"
│ │
│◄── PROPOSE ────────│ offre avec contenu libre (ex: coût, délai)
│◄── REFUSE ─────────│ refus (participant surchargé, hors périmètre…)
│
│ [selectProposals() — choisit le(s) gagnant(s)]
│
│── ACCEPT_PROPOSAL ►│ au(x) gagnant(s)
│── REJECT_PROPOSAL ►│ aux autres
│
│◄── INFORM ─────────│ résultat de l'exécution
│◄── FAILURE ─────────│ (si la tâche a échoué)
Inclusion
#include <gagent/protocols/ContractNet.hpp>
using namespace gagent::protocols;
ContractNetInitiator
Crée une sous-classe et surcharge les méthodes virtuelles :
class MonInitiateur : public ContractNetInitiator {
public:
MonInitiateur(Agent* ag,
const std::string& my_name,
const std::vector<AgentIdentifier>& participants)
: ContractNetInitiator(
ag,
my_name,
[](){
ACLMessage cfp(ACLMessage::Performative::CFP);
cfp.setContent("ma tâche");
cfp.setOntology("mon-ontologie");
return cfp;
}(),
participants,
5000, // délai offres (ms)
10000) // délai résultat (ms)
{}
// Sélectionne les agents à accepter parmi les propositions reçues
std::vector<std::string> selectProposals(
const std::vector<ACLMessage>& proposals) override
{
// Exemple : prendre la proposition avec le plus petit coût
std::string best;
int best_cost = INT_MAX;
for (auto& p : proposals) {
int cost = std::stoi(p.getContent());
if (cost < best_cost) { best_cost = cost; best = p.getSender().name; }
}
return { best };
}
void handleInform(const ACLMessage& result) override {
std::cout << "Résultat : " << result.getContent() << "\n";
this_agent->doDelete();
}
void handleRefuse(const ACLMessage& msg) override {
std::cout << msg.getSender().name << " a refusé\n";
}
};
Méthode à surcharger |
Description |
|---|---|
|
Obligatoire. Retourne les noms des agents à accepter. |
|
Résultat reçu du participant accepté. |
|
Échec signalé par le participant. |
|
Refus d’un participant. |
Paramètres du constructeur :
Paramètre |
Description |
|---|---|
|
Nom de l’initiateur — détermine la queue |
|
Message CFP à envoyer (contenu déjà défini) |
|
Liste des |
|
Délai pour recevoir toutes les offres (défaut : 5000 ms) |
|
Délai pour recevoir le résultat d’exécution (défaut : 10000 ms) |
ContractNetParticipant
class MonParticipant : public ContractNetParticipant {
public:
MonParticipant(Agent* ag, const std::string& my_name)
: ContractNetParticipant(ag, my_name) {}
// Évaluer le CFP et répondre PROPOSE ou REFUSE
ACLMessage prepareProposal(const ACLMessage& cfp) override {
if (surcharge_) {
ACLMessage r(ACLMessage::Performative::REFUSE);
r.setContent("surchargé");
return r;
}
ACLMessage prop(ACLMessage::Performative::PROPOSE);
prop.setContent(std::to_string(mon_tarif_));
return prop;
}
// Exécuter la tâche acceptée et rapporter INFORM ou FAILURE
ACLMessage executeTask(const ACLMessage& accept) override {
// ... exécution ...
ACLMessage result(ACLMessage::Performative::INFORM);
result.setContent("terminé");
this_agent->doDelete();
return result;
}
};
Méthode à surcharger |
Description |
|---|---|
|
Obligatoire. Retourne PROPOSE (offre) ou REFUSE (raison). |
|
Obligatoire. Exécute la tâche. Retourne INFORM ou FAILURE. |
Le comportement se termine automatiquement (done() = true) après :
avoir envoyé un REFUSE
avoir envoyé INFORM ou FAILURE suite à un ACCEPT
avoir reçu un REJECT_PROPOSAL
Subscribe-Notify (FIPA SC00035H)
Le Subscribe-Notify Protocol permet à un agent (subscriber) de s’abonner
aux notifications d’un agent publisher. Le publisher envoie des INFORM à
chaque changement d’état à tous ses subscribers actifs.
Subscriber Publisher
│ │
│── SUBSCRIBE ──────►│ "notifie-moi quand X change"
│ │
│◄── AGREE ──────────│ accepté
│ (ou REFUSE) │ refusé → done
│ │
│ [événement]
│◄── INFORM ─────────│ notification (répétée)
│◄── INFORM ─────────│
│ │
│── CANCEL ──────────►│ se désabonner (optionnel)
│◄── INFORM ─────────│ confirmation finale (optionnel)
Inclusion
#include <gagent/protocols/SubscribeNotify.hpp>
using namespace gagent::protocols;
SubscribeInitiator
class MonSubscriber : public SubscribeInitiator {
public:
MonSubscriber(Agent* ag, const std::string& my_name,
const std::string& publisher)
: SubscribeInitiator(
ag,
my_name,
publisher,
"temperature", // topic / contenu du SUBSCRIBE
"sensors", // ontologie (optionnel)
5000) // timeout AGREE ms (défaut : 5000)
{}
void handleNotify(const ACLMessage& msg) override {
std::cout << "Notification : " << msg.getContent() << "\n";
}
void handleRefuse(const ACLMessage& msg) override {
std::cout << "Refusé : " << msg.getContent() << "\n";
}
// Retourner true pour envoyer CANCEL et se désabonner
bool shouldCancel() override {
return notifications_reçues_ >= 10;
}
};
Méthode à surcharger |
Description |
|---|---|
|
Appelé à chaque |
|
Publisher a refusé l’abonnement. |
|
Appelé à chaque tick. Retourner |
done() retourne true après réception de REFUSE ou après
traitement du CANCEL.
SubscribeParticipant
class MonPublisher : public SubscribeParticipant {
int tick_ = 0;
public:
MonPublisher(Agent* ag, const std::string& my_name)
: SubscribeParticipant(ag, my_name, 200) {} // poll_ms
bool handleSubscribe(const ACLMessage& sub) override {
// Accepter ou refuser l'abonnement
return true;
}
std::string handleCancel(const std::string& subscriber) override {
// Retourner le contenu du dernier INFORM (vide = aucun)
return "fin-abonnement";
}
void action() override {
SubscribeParticipant::action(); // gère SUBSCRIBE / CANCEL entrants
// Publier périodiquement
if (++tick_ % 10 == 0) {
notify(std::to_string(temperature_));
}
}
};
Méthode à surcharger |
Description |
|---|---|
|
Retourner |
|
Appelé quand un subscriber se désabonne. Retourner le contenu du
dernier |
Méthode publique |
Description |
|---|---|
|
Envoie un |
|
Envoie un |
|
Retourne le nombre de subscribers actifs. |
done() retourne toujours false — le publisher tourne indéfiniment.
Exemple complet (Subscribe-Notify)
Voir tests/test_subscribe_notify.cpp — capteur de température : le
publisher émet toutes les 200 ms, le subscriber annule après 3 notifications.
cd build/tests
./test_subscribe_notify
Request (FIPA SC00026H)
Le Request Protocol est le protocole FIPA le plus simple : un initiateur envoie une demande à un participant qui l’exécute et retourne le résultat.
Initiateur Participant
│ │
│── REQUEST ────────►│
│ │
│◄── AGREE ──────────│ (optionnel — si traitement long)
│ │
│◄── INFORM ─────────│ succès
│◄── REFUSE ─────────│ refus immédiat
│◄── FAILURE ─────────│ échec après AGREE
│◄── NOT_UNDERSTOOD ──│
Inclusion
#include <gagent/protocols/Request.hpp>
using namespace gagent::protocols;
RequestInitiator
class MonRequester : public RequestInitiator {
public:
MonRequester(Agent* ag, const std::string& my_name,
const std::string& target)
: RequestInitiator(
ag,
my_name,
target,
"add(3,4)", // contenu de la requête
"math", // ontologie (optionnel)
10000) // timeout ms (défaut : 10000)
{}
void handleInform(const ACLMessage& msg) override {
std::cout << "Résultat : " << msg.getContent() << "\n";
}
void handleRefuse(const ACLMessage& msg) override {
std::cout << "Refusé : " << msg.getContent() << "\n";
}
void handleTimeout() override {
std::cerr << "Pas de réponse !\n";
}
};
Méthode à surcharger |
Description |
|---|---|
|
Requête traitée avec succès. |
|
Participant a refusé. |
|
Participant a échoué après avoir accepté. |
|
Participant a accepté (traitement long en cours). |
|
Requête non comprise. |
|
Pas de réponse dans le délai imparti. |
done() retourne true dès réception d’une réponse ou timeout.
RequestParticipant
class MonServeur : public RequestParticipant {
public:
MonServeur(Agent* ag, const std::string& my_name)
: RequestParticipant(ag, my_name, 500) {} // tick_ms
ACLMessage handleRequest(const ACLMessage& req) override {
// Traiter la requête et retourner INFORM, REFUSE ou FAILURE
ACLMessage reply = req.createReply(ACLMessage::Performative::INFORM);
reply.setSender(AgentIdentifier{my_name_});
reply.setContent("7");
return reply;
}
};
Méthode à surcharger |
Description |
|---|---|
|
Obligatoire. Traite la requête et retourne la réponse (INFORM, REFUSE ou FAILURE). Par défaut retourne INFORM vide. |
done() retourne toujours false — le participant tourne indéfiniment
et peut traiter plusieurs requêtes successives.
Exemple complet
Voir tests/test_request.cpp — un agent calcule 3+4 à distance.
cd build/tests
./test_request
Messagerie ACL — AclMQ
Les fonctions bas niveau sont disponibles séparément pour un usage direct :
#include <gagent/messaging/AclMQ.hpp>
using namespace gagent::messaging;
// Envoyer
acl_send("bob", msg);
// Recevoir avec timeout
auto opt = acl_receive("alice", 5000); // ms
if (opt) { /* traiter *opt */ }
// Libérer la queue en fin d'agent (dans takeDown())
acl_unlink("alice");
Exemple complet (Contract Net)
Voir tests/test_contract_net.cpp — enchère de livraison avec 3
transporteurs et sélection du moins cher.
cd build/tests
./test_contract_net