Running an Agent with Docker
Introduction
This example shows how to run an agent using the uAgents library inside a Docker container with Docker Compose. It walks you through setting up everything you need so you can easily build and run the agent.
Supporting Documents
- Almanac contract overview .
- How to create an agent .
- Registering in the Almanac Contract .
- Creating an interval task
- Communicating with other agents
Pre-requisites
- Python: Download and install from Python official website (opens in a new tab).
- Poetry: Install by following the instructions on Poetry's official website (opens in a new tab).
- Docker: Download and install from Docker official website (opens in a new tab).
- Docker Compose: Download and install from Docker Compose official documentation (opens in a new tab).
Project Structure
.agent_with_docker
├── docker-compose.yml
├── Dockerfile
├── poetry.lock
├── pyproject.toml
├── README.md
└── src
└── agent.py
Agent with Docker
agent.py
This example demonstrates a simple agent-based communication system using the uAgents library. The data_sender
agent sends a DataPacket
message to the data_receiver
agent every 4 seconds. Upon receiving the message, data_receiver
logs it and sends an acknowledgment back to data_sender. Both agents log the messages they receive. The agents are running with Docker Compose using Docker.
from uagents import Agent, Bureau, Context, Model
class DataPacket(Model):
message: str
data_sender = Agent(name="data_sender", seed="data_sender recovery phrase")
data_receiver = Agent(name="data_receiver", seed="data_receiver recovery phrase")
@data_sender.on_interval(period=4.0)
async def send_data_packet(ctx: Context):
"""
Event handler that gets triggered at regular intervals (every 4 seconds).
Args:
ctx (Context): The context in which the event is triggered.
Returns:
None: This function does not return any value but sends a DataPacket message from data_sender to data_receiver at intervals of (every 4 seconds).
"""
await ctx.send(
data_receiver.address, DataPacket(message="Initiating data transfer")
)
@data_sender.on_message(model=DataPacket)
async def data_sender_message_handler(ctx: Context, sender: str, msg: DataPacket):
"""
Event handler that gets triggered when data_sender receives a DataPacket message.
Args:
ctx (Context): The context in which the event is triggered.
sender (str): The address of the sender.
msg (DataPacket): The message received.
Returns:
None: This function does not return any value but logs the received message.
"""
ctx.logger.info(f"Data Sender received a message from {sender}: {msg.message}")
@data_receiver.on_message(model=DataPacket)
async def data_receiver_message_handler(ctx: Context, sender: str, msg: DataPacket):
"""
Event handler that gets triggered when data_receiver receives a DataPacket message.
Args:
ctx (Context): The context in which the event is triggered.
sender (str): The address of the sender.
msg (DataPacket): The message received.
Returns:
None: This function does not return any value but logs the received message and sends an acknowledgment back to data_sender.
"""
ctx.logger.info(f"Data Receiver received a message from {sender}: {msg.message}")
await ctx.send(
data_sender.address, DataPacket(message="Acknowledging data transfer")
)
bureau = Bureau()
bureau.add(data_sender)
bureau.add(data_receiver)
if __name__ == "__main__":
bureau.run()
Dockerfile
This Dockerfile sets up a Python environment with Poetry for dependency management. It installs necessary system packages, sets up the working directory, installs dependencies specified in pyproject.toml
, and runs agent.py
using Poetry. The application listens on port 8000.
FROM python:3.12-slim
ENV PATH="$PATH:/root/.local/bin"
RUN apt-get update && \
apt-get install -y curl gcc && \
curl -sSL https://install.python-poetry.org/ | python3 -
WORKDIR /app
ADD pyproject.toml poetry.lock /app/
RUN poetry install
ADD . /app
EXPOSE 8000
ENTRYPOINT ["poetry", "run"]
CMD ["python", "agent.py"]
docker-compose.yml
This Docker Compose configuration builds and runs a Python app using Poetry. It maps the current directory to the container, exposes port 8000, and starts the agent.py
script.
version: '3.8'
services:
app:
build: .
container_name: poetry_app
volumes:
- .:/app
ports:
- "8000:8000"
command: poetry run python src/agent.py
Poetry Dependencies
[tool.poetry.dependencies]
python = "^3.10"
uagents = { version = "^0.13.0", python = ">=3.10,<3.13" }
How to Run This Example
- Navigate to the root Folder of the Example.
- Run
docker-compose build
- Run
docker-compose up
Expected Output
Creating network "agent_with_docker_default" with the default driver
Creating poetry_app ... done
Attaching to poetry_app
poetry_app | INFO: [data_receiver]: Data Receiver received a message from agent1qdccxu8z03y3m27p22emtuffjxng8ks3pm69yn703eec6pk5a8p5vzf97qz: Initiating data transfer
poetry_app | INFO: [bureau]: Starting server on http://0.0.0.0:8000 (Press CTRL+C to quit)
poetry_app | INFO: [data_sender]: Data Sender received a message from agent1qg0ejev64auhjg7c7xsd32v7npflvhvs5afe43r4gzm4eqmhqgxs7mlfss0: Acknowledging data transfer
poetry_app | INFO: [data_receiver]: Data Receiver received a message from agent1qdccxu8z03y3m27p22emtuffjxng8ks3pm69yn703eec6pk5a8p5vzf97qz: Initiating data transfer