Skip to Content

Communicating with other agents

Introduction

Communication is an essential feature within any agents network. Communication allows agents to work together, exchange information, and forms an organic marketplace. In this guide, we will explore two methods of communication between agents:

Let’s start with local communication. This is the first step you would need to undertake to familiarize yourself with the code syntax we will be using in the remote communication section.

Imports needed

Agents: Local Communication

Walk-through

The first step to better understand how agents communicate is to introduce how 2 agents perform a local communication. Let’s consider a basic example in which two agents say hello to each other.

First of all, let’s create a Python script for the agent1 for this task:

windows
echo. > agent_sigmar.py

Let’s create a Python script for the agent2 for this task:

windows
echo. > agent_slaanesh.py

Agent 1: Sigmar

1. Define the Message Model

This defines a simple message structure using the Model class from uAgents. The message field is a string that will be exchanged between agents. This ensures that both agents can communicate using a predefined format.

agent_sigmar.py
from uagents import Agent, Context, Model class Message(Model): message: str

2. Create Sigmar Agent

Here, the Sigmar agent is initialized with a unique name and seed (recovery phrase) to establish its identity. It runs on port 8000 and listens for messages at the specified endpoint. This setup enables the agent to send and receive messages in a local environment.

agent_sigmar.py
sigmar = Agent(name="sigmar", seed="sigmar recovery phrase", port=8000, endpoint=["http://localhost:8000/submit"])

3. Sigmar Sends a Message Every 3 Seconds

A periodic function is defined, which executes every 3 seconds. It sends a message, “hello there sigmar”, to the Slaanesh agent using its unique address. This ensures that communication is continuously initiated from Sigmar without requiring any manual input.

agent_sigmar.py
SLAANESH_ADDRESS = < SLAANESH ADDRESS > @sigmar.on_interval(period=3.0) async def send_message(ctx: Context): await ctx.send(SLAANESH_ADDRESS, Message(message="hello there sigmar"))

4. Handle Incoming Messages

This function triggers whenever Slaanesh receives a message matching the Message model. It logs the sender’s address and message content, then replies with “hello there slaanesh” to the sender. This ensures a two-way communication flow between the agents.

agent_sigmar.py
@sigmar.on_message(model=Message) async def sigmar_message_handler(ctx: Context, sender: str, msg: Message): ctx.logger.info(f"Received message from {sender}: {msg.message}")

5. Start the Agent

The agent is started using sigmar.run(), making it continuously run and process messages. This ensures that the agent remains active and responsive to incoming communications.

agent_sigmar.py
if __name__ == "__main__": sigmar.run()

Agent 2: Slaanesh

1. Define the Message Model

The same message structure is defined for Slaanesh, ensuring compatibility with Sigmar. This consistency allows both agents to understand the messages they exchange.

agent_slaanesh.py
from uagents import Agent, Context, Model class Message(Model): message: str

2. Create Slaanesh Agent

The Slaanesh agent is initialized with its own name and seed for identity. It runs on port 8001 and listens for messages at its specified endpoint. This setup enables Slaanesh to receive messages from Sigmar and respond appropriately.

agent_slaanesh.py
slaanesh = Agent(name="slaanesh", seed="slaanesh recovery phrase", port=8001, endpoint=["http://localhost:8001/submit"])

3. Handle Incoming Messages & Reply

This function triggers whenever Slaanesh receives a message matching the Message model. It logs the sender’s address and message content, then replies with “hello there slaanesh” to the sender. This ensures a two-way communication flow between the agents.

agent_slaanesh.py
@slaanesh.on_message(model=Message) async def slaanesh_message_handler(ctx: Context, sender: str, msg: Message): ctx.logger.info(f"Received message from {sender}: {msg.message}") await ctx.send(sender, Message(message="hello there slaanesh"))

4. Start the Agent

The agent is started using slaanesh.run(), making it continuously run and process messages. This keeps the agent active and ready to communicate with Sigmar whenever it receives a message.

agent_slaanesh.py
if __name__ == "__main__": slaanesh.run()

Complete Script for Both Agents

These two scripts together create an autonomous request-response loop between two local agents, continuously exchanging messages. To ensure smooth communication between Sigmar and Slaanesh, you must start the Slaanesh agent first before running Sigmar.

agent_sigmar.py
from uagents import Agent, Context, Model class Message(Model): message: str sigmar = Agent(name="sigmar", seed="sigmar recovery phrase", port=8000, endpoint=["http://localhost:8000/submit"]) SLAANESH_ADDRESS = < SLAANESH ADDRESS > @sigmar.on_interval(period=3.0) async def send_message(ctx: Context): await ctx.send(SLAANESH_ADDRESS, Message(message="hello there slaanesh")) @sigmar.on_message(model=Message) async def sigmar_message_handler(ctx: Context, sender: str, msg: Message): ctx.logger.info(f"Received message from {sender}: {msg.message}") if __name__ == "__main__": sigmar.run()
agent_slaanesh.py
from uagents import Agent, Context, Model class Message(Model): message: str slaanesh = Agent(name="slaanesh", seed="slaanesh recovery phrase", port=8001, endpoint=["http://localhost:8001/submit"]) @slaanesh.on_message(model=Message) async def slaanesh_message_handler(ctx: Context, sender: str, msg: Message): ctx.logger.info(f"Received message from {sender}: {msg.message}") await ctx.send(sender, Message(message="hello there sigmar")) if __name__ == "__main__": slaanesh.run()

Steps to Run the Agents in Order:

  1. Start Slaanesh first in one terminal window:
python agent_slaanesh.py
  1. Then start Sigmar in another terminal window:
python agent_sigmar.py

The output would be:

for agent agent_slaanesh.py

INFO: [slaanesh]: Starting agent with address: agent1qddw8cfn685e3p082lcn9dxe63yrqf03s77puv4d0as8a4j7c84s572juzj INFO: [slaanesh]: Agent inspector available at https://agentverse.ai/inspect/?uri=http%3A//127.0.0.1%3A8001&address=agent1qddw8cfn685e3p082lcn9dxe63yrqf03s77puv4d0as8a4j7c84s572juzj INFO: [slaanesh]: Starting server on http://0.0.0.0:8001 (Press CTRL+C to quit) INFO: [uagents.registration]: Registration on Almanac API successful INFO: [uagents.registration]: Almanac contract registration is up to date! INFO: [slaanesh]: Received message from agent1qdtmapxwfljj2xwz8yqpljd75tmnxjjdmrta86q68aqf5r9d7nw7kqyt40p: hello there sigmar INFO: [slaanesh]: Received message from agent1qdtmapxwfljj2xwz8yqpljd75tmnxjjdmrta86q68aqf5r9d7nw7kqyt40p: hello there sigmar

for agent agent_sigmar.py

INFO: [sigmar]: Starting agent with address: agent1qdtmapxwfljj2xwz8yqpljd75tmnxjjdmrta86q68aqf5r9d7nw7kqyt40p INFO: [sigmar]: Agent inspector available at https://agentverse.ai/inspect/?uri=http%3A//127.0.0.1%3A8000&address=agent1qdtmapxwfljj2xwz8yqpljd75tmnxjjdmrta86q68aqf5r9d7nw7kqyt40p INFO: [sigmar]: Starting server on http://0.0.0.0:8000 (Press CTRL+C to quit) INFO: [uagents.registration]: Registration on Almanac API successful INFO: [uagents.registration]: Almanac contract registration is up to date! INFO: [sigmar]: Received message from agent1qddw8cfn685e3p082lcn9dxe63yrqf03s77puv4d0as8a4j7c84s572juzj: hello there slaanesh INFO: [sigmar]: Received message from agent1qddw8cfn685e3p082lcn9dxe63yrqf03s77puv4d0as8a4j7c84s572juzj: hello there slaanesh

However, these agents can only communicate with each other on their local network.

Agents Remote Communication: the Almanac Contract

An agent must register to the Almanac contract to communicate, to search for other agents or be found. Agents can query this contract to retrieve an HTTP endpoint for a recipient agent. Registration in the Almanac requires paying a small fee, so make sure to have enough funds to allow for this. You can query the Almanac now, by using the search feature on Agentverse.

Whenever an agent registers in the Almanac, it must specify the service endpoints alongside a weight parameter for each endpoint provided. Agents trying to communicate with your agent will choose the service endpoints using a weighted random selection.

Here, we show you how to create two agents and make them remotely communicate by registering and using the Almanac Contract.

Walk-through

The first step would be to create two different Python scripts for this task, each one representing a remote agent:

Slaanesh:

windows
echo. > remote_agents_slaanesh.py

Sigmar:

windows
echo. > remote_agents_sigmar.py

Let’s start by defining the script for sigmar.

Sigmar

  1. In remote_agents_sigmar.py script, we would need to import the necessary classes from the uagents (Agent, Context, and Model). We then need to define the message structure for messages to be exchanged between agents using the class Model, as well as the RECIPIENT_ADDRESS (slaanesh’s address). Note that if you don’t know slaanesh’s address yet, you can use print(slaanesh.address) after defining agent slaanesh to get this information. This is the address towards which sigmar will send messages:
remote_agents_sigmar.py
from uagents import Agent, Context, Model class Message(Model): message: str RECIPIENT_ADDRESS = "agent1qvm7v76zs6w2x90xvq99yc5xh7c2thjtm44zc09me556zxnra627gkf4zum"
  1. Let’s now create our agent, sigmar, by providing name, seed, port, and endpoint:
remote_agents_sigmar.py
sigmar = Agent( name="sigmar", port=8000, seed="sigmar secret phrase", endpoint=["http://127.0.0.1:8000/submit"], )
  1. We are ready to define sigmar’s behaviors. Let’s start with a function for sigmar to send messages:
remote_agents_sigmar.py
@sigmar.on_interval(period=2.0) async def send_message(ctx: Context): await ctx.send(RECIPIENT_ADDRESS, Message(message="hello there slaanesh"))

Here, the .on_interval() decorator schedules the send_message() function to be run every 2 seconds. Inside the function, there is an asynchronous call indicated by the ctx.send() method. This call sends a message with the content "hello there slaanesh" to the RECIPIENT_ADDRESS.

  1. We then need to define a function for sigmar to handle incoming messages from other agents:
remote_agents_sigmar.py
@sigmar.on_message(model=Message) async def message_handler(ctx: Context, sender: str, msg: Message): ctx.logger.info(f"Received message from {sender}: {msg.message}") if __name__ == "__main__": sigmar.run()

Here, we have used the .on_message() decorator to register the message_handler() coroutine function as a handler for incoming messages of type Message.

The message_handler() function takes three arguments: ctx, sender, and msg. Inside this function, we call the ctx.logger.info() method to log information about the received message, including the sender and message content.

  1. We can now save the script.

The overall script for sigmar agent should be looking as follows:

remote_agents_sigmar.py
from uagents import Agent, Context, Model class Message(Model): message: str RECIPIENT_ADDRESS = "agent1qvm7v76zs6w2x90xvq99yc5xh7c2thjtm44zc09me556zxnra627gkf4zum" sigmar = Agent( name="sigmar", port=8000, seed="sigmar secret phrase", endpoint=["http://127.0.0.1:8000/submit"], ) @sigmar.on_interval(period=2.0) async def send_message(ctx: Context): await ctx.send(RECIPIENT_ADDRESS, Message(message="hello there slaanesh")) @sigmar.on_message(model=Message) async def message_handler(ctx: Context, sender: str, msg: Message): ctx.logger.info(f"Received message from {sender}: {msg.message}") if __name__ == "__main__": sigmar.run()

Remember that you need to provide the name, seed, port, endpoint and RECIPIENT_ADDRESS parameters to correctly run this code.

We can now proceed by writing the script for agent slaanesh.

Slaanesh

  1. In remote_agents_slaanesh.py script, import the necessary classes from the uagents. Then, define the message structure for messages to be exchanged between the agents using the Model class, as well as our second uAgent, slaanesh, by providing name, seed, port, and endpoint:
remote_agents_slaanesh.py
from uagents import Agent, Context, Model class Message(Model): message: str slaanesh = Agent( name="slaanesh", port=8001, seed="slaanesh secret phrase", endpoint=["http://127.0.0.1:8001/submit"], )
  1. Let’s now define a function for slaanesh to handle incoming messages and answering back to the sender:
remote_agents_slaanesh.py
@slaanesh.on_message(model=Message) async def message_handler(ctx: Context, sender: str, msg: Message): ctx.logger.info(f"Received message from {sender}: {msg.message}") await ctx.send(sender, Message(message="hello there sigmar")) if __name__ == "__main__": slaanesh.run()

Here, we have defined an asynchronous message_handler() function for slaanesh to handle incoming messages from other uAgents. The function is decorated with .on_message(), and it is triggered whenever a message of type Message is received by slaanesh. When a message is received, the handler function logs the sender’s address and the content of the message. It then sends a response back to the sender using the ctx.send() with a new message. The response message contains the Message data model with a "hello there sigmar" message.

  1. Save the script.

The overall script for slaanesh should be looking as follows:

remote_agents_slaanesh.py
from uagents import Agent, Context, Model class Message(Model): message: str slaanesh = Agent( name="slaanesh", port=8001, seed="slaanesh secret phrase", endpoint=["http://127.0.0.1:8001/submit"], ) @slaanesh.on_message(model=Message) async def message_handler(ctx: Context, sender: str, msg: Message): ctx.logger.info(f"Received message from {sender}: {msg.message}") await ctx.send(sender, Message(message="hello there sigmar")) if __name__ == "__main__": slaanesh.run()

Remember that you need to provide the name, seed, port and endpoint parameters to correctly run this code.

Run the scripts

In different terminal windows, first run slaanesh and then sigmar. They will register automatically in the Almanac contract using their funds. The received messages will print out in each terminal:

Terminal 1: python remote_agents_slaanesh.py

Terminal 2: python remote_agents_sigmar.py

The output will depend on the terminal:

  • Sigmar:

    INFO: [sigmar]: Registration on Almanac API successful INFO: [sigmar]: Registering on almanac contract... INFO: [sigmar]: Registering on almanac contract...complete INFO: [sigmar]: Agent inspector available at https://agentverse.ai/inspect/?uri=http%3A//127.0.0.1%3A8000&address=agent1qvwqu6a0km09mq4f6j6kmke9smswmgcergmml9a54av9449rqtmmxy4qwe6 INFO: [sigmar]: Starting server on http://0.0.0.0:8000 (Press CTRL+C to quit) INFO: [sigmar]: Received message from agent1qvm7v76zs6w2x90xvq99yc5xh7c2thjtm44zc09me556zxnra627gkf4zum: hello there sigmar INFO: [sigmar]: Received message from agent1qvm7v76zs6w2x90xvq99yc5xh7c2thjtm44zc09me556zxnra627gkf4zum: hello there sigmar INFO: [sigmar]: Received message from agent1qvm7v76zs6w2x90xvq99yc5xh7c2thjtm44zc09me556zxnra627gkf4zum: hello there sigmar
  • Slaanesh:

    INFO: [slaanesh]: Registration on Almanac API successful INFO: [slaanesh]: Registering on almanac contract... INFO: [slaanesh]: Registering on almanac contract...complete INFO: [slaanesh]: Agent inspector available at https://agentverse.ai/inspect/?uri=http%3A//127.0.0.1%3A8001&address=agent1qvm7v76zs6w2x90xvq99yc5xh7c2thjtm44zc09me556zxnra627gkf4zum INFO: [slaanesh]: Starting server on http://0.0.0.0:8001 (Press CTRL+C to quit) INFO: [slaanesh]: Received message from agent1qvwqu6a0km09mq4f6j6kmke9smswmgcergmml9a54av9449rqtmmxy4qwe6: hello there slaanesh INFO: [slaanesh]: Received message from agent1qvwqu6a0km09mq4f6j6kmke9smswmgcergmml9a54av9449rqtmmxy4qwe6: hello there slaanesh INFO: [slaanesh]: Received message from agent1qvwqu6a0km09mq4f6j6kmke9smswmgcergmml9a54av9449rqtmmxy4qwe6: hello there slaanesh

Before we go on…

As we touched on before in Register in Almanac, when the agent uses .run() function this tells the uagents library to register the agent to the Almanac. It’s simple, agents initialize themselves, and register to a service which acts as a search engine for agents (the Almanac) then, when agents receive messages they can respond.

Conclusion

In this guide, we explored two different methods of communication for Agents using the uagents library:

  • Local communication.
  • Remote communication via the Almanac Contract.

For local communication, we learned how to use the uagents library to create two agents, sigmar and slaanesh, and enable them to exchange messages with one another. We defined the message structure using the Model class and implemented message handlers for both agents. By running the script we observed their real-time message exchange.

Next, we delved into remote communication, which facilitates interaction between agents through the Almanac Contract. This method requires registering the agents in the Almanac Contract and querying for HTTP endpoints for communication. By running the scripts separately, we could observe the real-time messages exchange, fostering a decentralized network of interacting agents.

With this, we suspect you’re ready to start building agents, as part of multi-agent system the Almanac allows; awesome. If you want to go further though, take a look at the message verification and sending tokens, after-all you do want to be sure you are speaking to whom you think you are, and agents getting paid is awesome.

Last updated on