Skip to content

Commit

Permalink
feat(docs): added example of running agent with docker (#899)
Browse files Browse the repository at this point in the history
Co-authored-by: felix.bucsa <[email protected]>
Co-authored-by: Joshua Croft <[email protected]>
  • Loading branch information
3 people authored Aug 28, 2024
1 parent 65fbbfe commit e86b7a1
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pages/examples/intermediate/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@
"tags": ["Intermediate", "Python", "Functions", "OpenAI", "Use Cases"],
"timestamp": true
},
"agents-with-docker": {
"title": "Running an Agent with Docker",
"tags": ["Intermediate", "Python", "Docker", "Use Cases"],
"timestamp": true
},
"postgres-database-with-an-agent": {
"title": "Utilize the PostgreSQL database with the Agent.",
"tags": ["Intermediate", "Python", "Docker", "PostgreSQL", "Use Cases"],
Expand Down
181 changes: 181 additions & 0 deletions pages/examples/intermediate/agents-with-docker.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@

# 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 ↗️](../../references/contracts/uagents-almanac/almanac-overview).
- [How to create an agent ↗️](../../guides/agents/create-a-uagent).
- [Registering in the Almanac Contract ↗️](../../guides/agents/register-in-almanac).
- [Creating an interval task ↗️](/guides/agents/interval-task)
- [Communicating with other agents ↗️](/guides/agents/communicating-with-other-agents)


## Pre-requisites

- **Python:** Download and install from [Python official website ↗️](https://www.python.org/downloads/).
- **Poetry:** Install by following the instructions on [Poetry's official website ↗️](https://python-poetry.org/docs/#installation).
- **Docker:** Download and install from [Docker official website ↗️](https://docs.docker.com/get-docker/).
- **Docker Compose:** Download and install from [Docker Compose official documentation ↗️](https://docs.docker.com/compose/).

## 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.


```py copy filename="agent.py"

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.

```Dockerfile copy filename="Dockerfile"
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.

```yml copy filename="docker-compose.yml"
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
```

0 comments on commit e86b7a1

Please sign in to comment.