Overview of SPADE (Smart Python Agent Development Environment)
masterasyncio and uses a behavior-based agent model.repository·master·Indexed 43 days ago
https://github.com/javipalanca/spadeA Python-based multi-agent systems platform leveraging XMPP for real-time communication between agents and humans. It features asynchronous message handling via the Message class, FIPA-ACL compliance through FIPAMessageBuilder and FIPAMessageParser, and support for XEP-0363 HTTP file exchange. The framework provides various behaviour types, including PeriodicBehaviour, TimeoutBehaviour, and FSMBehaviour for complex state-machine logic.
asyncio and uses a behavior-based agent model.The core logic of a SPADE agent is implemented via Behaviours. You add a behaviour to an agent using the add_behaviour() method inside the agent's setup() coroutine.
spade.behaviour.CyclicBehaviour: A loop-like behaviour that repeats without a specific period.on_start(): An async coroutine executed just before the first iteration. Use it for initialization.run(): An async coroutine that contains the core logic. It is called on every iteration of the behaviour loop. Because it is async, you can use await (e.g., await asyncio.sleep(1)) without blocking the event loop.on_end(): An async coroutine executed when a behaviour is finished or killed.import asyncio
import spade
from spade.agent import Agent
from spade.behaviour import CyclicBehaviour
class DummyAgent(Agent):
class MyBehav(CyclicBehaviour):
async def on_start(self):
print("Starting behaviour . . .")
self.counter = 0
async def run(self):
print("Counter: {}".format(self.counter))
self.counter += 1
await asyncio.sleep(1)
async def on_end(self):
print("Behaviour ended")
async def setup(self):
b = self.MyBehav()
self.add_behaviour(b)
async def main():
dummy = DummyAgent("dummy@localhost", "your_password")
await dummy.start()
# Use wait_until_finished to keep the agent running
from spade import wait_until_finished
await wait_until_finished(dummy)
if __name__ == "__main__":
spade.run(main())Behaviours are the tasks an agent executes using repeating patterns. SPADE provides several predefined behaviour types to implement different logic structures:
You can create complex message filtering logic by combining simple Template instances using bitwise operators:
&: Boolean AND (both templates must match).|: Boolean OR (either template must match).^: Boolean XOR (exactly one template must match).~: Boolean NOT (the complement of the template).t1 = Template()
t1.sender = "sender1@host"
t2 = Template()
t2.metadata = {"performative": "query"}
# Matches messages that satisfy BOTH t1 and t2
combined_template = t1 & t2
# Matches messages that do NOT satisfy t3
t3 = Template()
t3.sender = "invalid@host"
not_t3 = ~t3Message dispatching is automated by the SPADE agent library. When a message arrives, the Message Dispatcher determines which behaviour should receive it by matching the incoming message against a message template attached to each behaviour.
This allows a single agent to run multiple behaviours simultaneously, where each behaviour 'subscribes' to specific types of messages by defining its own template.
The SPADE Agent Model is built on three core components that work together to enable autonomous agent communication and execution:
To identify an agent on the platform, you must use a JID in the format username@serverdomain (e.g., myagent@localhost).
The FSMBehaviour allows you to build complex agent logic using a Finite State Machine. It manages transitions between different State objects.
State (which is itself a OneShotBehaviour). You must override the run() coroutine. A state becomes a 'final state' if it does not call set_next_state().add_state(name, state, initial=False) to register states. An FSM can have only one initial state; if multiple are registered with initial=True, the last one registered wins.add_transition(source, dest) to define valid paths between state names. If a state attempts to transition to a non-registered transition, a NotValidTransition exception is raised and the FSM stops.run() method, call self.set_next_state("STATE_NAME") using the exact string name used during registration. If the name is unknown, a NotValidState exception is raised.FSMBehaviour share the same unique template and message queue.from spade.behaviour import FSMBehaviour, State
STATE_A = "STATE_A"
STATE_B = "STATE_B"
class StateA(State):
async def run(self):
print("In State A")
self.set_next_state(STATE_B)
class StateB(State):
async def run(self):
print("In State B (Final)")
# Not calling set_next_state makes this the final state
class MyFSM(FSMBehaviour):
pass
# In Agent setup:
fsm = MyFSM()
fsm.add_state(name=STATE_A, state=StateA(), initial=True)
fsm.add_state(name=STATE_B, state=StateB())
fsm.add_transition(source=STATE_A, dest=STATE_B)
self.add_behaviour(fsm)Paths can include dynamic segments using aiohttp syntax. For example, a path /a/{agentjid}/c will match /a/user@server/c. You can retrieve these variables from the request.match_info dictionary inside your controller.
async def my_controller(request):
jid = request.match_info['agentjid']
return {"jid": jid}SPADE provides several core capabilities for multi-agent development:
asyncio for efficient asynchronous operations.Requirements:
In SPADE, a Template is used to dispatch received messages to specific behaviours. When you add a behaviour to an agent, you can provide a Template instance. The agent will only deliver messages to that behaviour if the message's attributes exactly match all the attributes defined in the template.
Supported template attributes:
to: The JID string of the receiver.sender: The JID string of the sender.body: The message body.thread: The thread ID of the conversation.metadata: A (key, value) dictionary of strings (e.g., for FIPA attributes like ontology, performative, or language).template = Template()
template.sender = "sender1@host"
template.metadata = {"performative": "query"}
# The behaviour will only receive messages matching these criteria
self.add_behaviour(my_behaviour, template)If you are contributing to SPADE or need development tools, you can install the package along with its dev extra dependencies.
Using uv:
$ uv sync --extra devUsing pip:
$ pip install -e .[dev]For traditional Python environments using pip, you can install the most recent stable release of SPADE directly.
$ pip install spade