agentex-sdk 0.8.2__py3-none-any.whl → 0.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentex/_base_client.py +134 -11
- agentex/_models.py +16 -1
- agentex/_types.py +9 -0
- agentex/_version.py +1 -1
- agentex/lib/cli/commands/agents.py +97 -0
- agentex/lib/cli/commands/init.py +13 -2
- agentex/lib/cli/handlers/agent_handlers.py +130 -12
- agentex/lib/cli/templates/sync-openai-agents/.dockerignore.j2 +43 -0
- agentex/lib/cli/templates/sync-openai-agents/Dockerfile-uv.j2 +42 -0
- agentex/lib/cli/templates/sync-openai-agents/Dockerfile.j2 +43 -0
- agentex/lib/cli/templates/sync-openai-agents/README.md.j2 +313 -0
- agentex/lib/cli/templates/sync-openai-agents/dev.ipynb.j2 +167 -0
- agentex/lib/cli/templates/sync-openai-agents/environments.yaml.j2 +53 -0
- agentex/lib/cli/templates/sync-openai-agents/manifest.yaml.j2 +115 -0
- agentex/lib/cli/templates/sync-openai-agents/project/acp.py.j2 +137 -0
- agentex/lib/cli/templates/sync-openai-agents/pyproject.toml.j2 +32 -0
- agentex/lib/cli/templates/sync-openai-agents/requirements.txt.j2 +5 -0
- agentex/lib/cli/templates/sync-openai-agents/test_agent.py.j2 +70 -0
- {agentex_sdk-0.8.2.dist-info → agentex_sdk-0.9.0.dist-info}/METADATA +1 -1
- {agentex_sdk-0.8.2.dist-info → agentex_sdk-0.9.0.dist-info}/RECORD +23 -12
- {agentex_sdk-0.8.2.dist-info → agentex_sdk-0.9.0.dist-info}/WHEEL +0 -0
- {agentex_sdk-0.8.2.dist-info → agentex_sdk-0.9.0.dist-info}/entry_points.txt +0 -0
- {agentex_sdk-0.8.2.dist-info → agentex_sdk-0.9.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import NamedTuple
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
from rich.console import Console
|
|
@@ -8,7 +9,7 @@ from python_on_whales import DockerException, docker
|
|
|
8
9
|
from agentex.lib.cli.debug import DebugConfig
|
|
9
10
|
from agentex.lib.utils.logging import make_logger
|
|
10
11
|
from agentex.lib.cli.handlers.run_handlers import RunError, run_agent as _run_agent
|
|
11
|
-
from agentex.lib.sdk.config.agent_manifest import AgentManifest
|
|
12
|
+
from agentex.lib.sdk.config.agent_manifest import AgentManifest, BuildContextManager
|
|
12
13
|
|
|
13
14
|
logger = make_logger(__name__)
|
|
14
15
|
console = Console()
|
|
@@ -18,6 +19,17 @@ class DockerBuildError(Exception):
|
|
|
18
19
|
"""An error occurred during docker build"""
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
class CloudBuildContext(NamedTuple):
|
|
23
|
+
"""Contains the prepared build context for cloud builds."""
|
|
24
|
+
|
|
25
|
+
archive_bytes: bytes
|
|
26
|
+
dockerfile_path: str
|
|
27
|
+
agent_name: str
|
|
28
|
+
tag: str
|
|
29
|
+
image_name: str
|
|
30
|
+
build_context_size_kb: float
|
|
31
|
+
|
|
32
|
+
|
|
21
33
|
def build_agent(
|
|
22
34
|
manifest_path: str,
|
|
23
35
|
registry_url: str,
|
|
@@ -42,9 +54,7 @@ def build_agent(
|
|
|
42
54
|
The image URL
|
|
43
55
|
"""
|
|
44
56
|
agent_manifest = AgentManifest.from_yaml(file_path=manifest_path)
|
|
45
|
-
build_context_root = (
|
|
46
|
-
Path(manifest_path).parent / agent_manifest.build.context.root
|
|
47
|
-
).resolve()
|
|
57
|
+
build_context_root = (Path(manifest_path).parent / agent_manifest.build.context.root).resolve()
|
|
48
58
|
|
|
49
59
|
repository_name = repository_name or agent_manifest.agent.name
|
|
50
60
|
|
|
@@ -85,9 +95,7 @@ def build_agent(
|
|
|
85
95
|
key, value = arg.split("=", 1)
|
|
86
96
|
docker_build_args[key] = value
|
|
87
97
|
else:
|
|
88
|
-
logger.warning(
|
|
89
|
-
f"Invalid build arg format: {arg}. Expected KEY=VALUE"
|
|
90
|
-
)
|
|
98
|
+
logger.warning(f"Invalid build arg format: {arg}. Expected KEY=VALUE")
|
|
91
99
|
|
|
92
100
|
if docker_build_args:
|
|
93
101
|
docker_build_kwargs["build_args"] = docker_build_args
|
|
@@ -100,9 +108,7 @@ def build_agent(
|
|
|
100
108
|
if push:
|
|
101
109
|
# Build and push in one step for multi-platform builds
|
|
102
110
|
logger.info("Building and pushing image...")
|
|
103
|
-
docker_build_kwargs["push"] =
|
|
104
|
-
True # Push directly after build for multi-platform
|
|
105
|
-
)
|
|
111
|
+
docker_build_kwargs["push"] = True # Push directly after build for multi-platform
|
|
106
112
|
docker.buildx.build(**docker_build_kwargs)
|
|
107
113
|
|
|
108
114
|
logger.info(f"Successfully built and pushed {image_name}")
|
|
@@ -146,11 +152,11 @@ def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = None):
|
|
|
146
152
|
shutting_down = True
|
|
147
153
|
logger.info(f"Received signal {signum}, shutting down...")
|
|
148
154
|
raise KeyboardInterrupt()
|
|
149
|
-
|
|
155
|
+
|
|
150
156
|
# Set up signal handling for the main thread
|
|
151
157
|
signal.signal(signal.SIGINT, signal_handler)
|
|
152
158
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
153
|
-
|
|
159
|
+
|
|
154
160
|
try:
|
|
155
161
|
asyncio.run(_run_agent(manifest_path, debug_config))
|
|
156
162
|
except KeyboardInterrupt:
|
|
@@ -158,3 +164,115 @@ def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = None):
|
|
|
158
164
|
sys.exit(0)
|
|
159
165
|
except RunError as e:
|
|
160
166
|
raise RuntimeError(str(e)) from e
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def parse_build_args(build_args: list[str] | None) -> dict[str, str]:
|
|
170
|
+
"""Parse build arguments from KEY=VALUE format to a dictionary.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
build_args: List of build arguments in KEY=VALUE format
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Dictionary mapping keys to values
|
|
177
|
+
"""
|
|
178
|
+
result: dict[str, str] = {}
|
|
179
|
+
if not build_args:
|
|
180
|
+
return result
|
|
181
|
+
|
|
182
|
+
for arg in build_args:
|
|
183
|
+
if "=" in arg:
|
|
184
|
+
key, value = arg.split("=", 1)
|
|
185
|
+
result[key] = value
|
|
186
|
+
else:
|
|
187
|
+
logger.warning(f"Invalid build arg format: {arg}. Expected KEY=VALUE")
|
|
188
|
+
|
|
189
|
+
return result
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def prepare_cloud_build_context(
|
|
193
|
+
manifest_path: str,
|
|
194
|
+
tag: str | None = None,
|
|
195
|
+
build_args: list[str] | None = None,
|
|
196
|
+
) -> CloudBuildContext:
|
|
197
|
+
"""Prepare the build context for cloud-based container builds.
|
|
198
|
+
|
|
199
|
+
Reads the manifest, prepares the build context by copying files according to
|
|
200
|
+
the include_paths and dockerignore, then creates a compressed tar.gz archive
|
|
201
|
+
ready for upload to a cloud build service.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
manifest_path: Path to the agent manifest file
|
|
205
|
+
tag: Image tag override (if None, reads from manifest's deployment.image.tag)
|
|
206
|
+
build_args: List of build arguments in KEY=VALUE format
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
CloudBuildContext containing the archive bytes, dockerfile path, and metadata
|
|
210
|
+
"""
|
|
211
|
+
agent_manifest = AgentManifest.from_yaml(file_path=manifest_path)
|
|
212
|
+
build_context_root = (Path(manifest_path).parent / agent_manifest.build.context.root).resolve()
|
|
213
|
+
|
|
214
|
+
agent_name = agent_manifest.agent.name
|
|
215
|
+
dockerfile_path = agent_manifest.build.context.dockerfile
|
|
216
|
+
|
|
217
|
+
# Validate that the Dockerfile exists
|
|
218
|
+
full_dockerfile_path = build_context_root / dockerfile_path
|
|
219
|
+
if not full_dockerfile_path.exists():
|
|
220
|
+
raise FileNotFoundError(
|
|
221
|
+
f"Dockerfile not found at: {full_dockerfile_path}\n"
|
|
222
|
+
f"Check that 'build.context.dockerfile' in your manifest points to an existing file."
|
|
223
|
+
)
|
|
224
|
+
if not full_dockerfile_path.is_file():
|
|
225
|
+
raise ValueError(
|
|
226
|
+
f"Dockerfile path is not a file: {full_dockerfile_path}\n"
|
|
227
|
+
f"'build.context.dockerfile' must point to a file, not a directory."
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Get tag and repository from manifest if not provided
|
|
231
|
+
if tag is None:
|
|
232
|
+
if agent_manifest.deployment and agent_manifest.deployment.image:
|
|
233
|
+
tag = agent_manifest.deployment.image.tag
|
|
234
|
+
else:
|
|
235
|
+
tag = "latest"
|
|
236
|
+
|
|
237
|
+
# Get repository name from manifest (just the repo name, not the full registry URL)
|
|
238
|
+
if agent_manifest.deployment and agent_manifest.deployment.image:
|
|
239
|
+
repository = agent_manifest.deployment.image.repository
|
|
240
|
+
if repository:
|
|
241
|
+
# Extract just the repo name (last part after any slashes)
|
|
242
|
+
image_name = repository.split("/")[-1]
|
|
243
|
+
else:
|
|
244
|
+
image_name = "<repository>"
|
|
245
|
+
else:
|
|
246
|
+
image_name = "<repository>"
|
|
247
|
+
|
|
248
|
+
logger.info(f"Agent: {agent_name}")
|
|
249
|
+
logger.info(f"Image name: {image_name}")
|
|
250
|
+
logger.info(f"Build context root: {build_context_root}")
|
|
251
|
+
logger.info(f"Dockerfile: {dockerfile_path}")
|
|
252
|
+
logger.info(f"Tag: {tag}")
|
|
253
|
+
|
|
254
|
+
if agent_manifest.build.context.include_paths:
|
|
255
|
+
logger.info(f"Include paths: {agent_manifest.build.context.include_paths}")
|
|
256
|
+
|
|
257
|
+
parsed_build_args = parse_build_args(build_args)
|
|
258
|
+
if parsed_build_args:
|
|
259
|
+
logger.info(f"Build args: {list(parsed_build_args.keys())}")
|
|
260
|
+
|
|
261
|
+
logger.info("Preparing build context...")
|
|
262
|
+
|
|
263
|
+
with agent_manifest.context_manager(build_context_root) as build_context:
|
|
264
|
+
# Compress the prepared context using the static zipped method
|
|
265
|
+
with BuildContextManager.zipped(root_path=build_context.path) as archive_buffer:
|
|
266
|
+
archive_bytes = archive_buffer.read()
|
|
267
|
+
|
|
268
|
+
build_context_size_kb = len(archive_bytes) / 1024
|
|
269
|
+
logger.info(f"Build context size: {build_context_size_kb:.1f} KB")
|
|
270
|
+
|
|
271
|
+
return CloudBuildContext(
|
|
272
|
+
archive_bytes=archive_bytes,
|
|
273
|
+
dockerfile_path=build_context.dockerfile_path,
|
|
274
|
+
agent_name=agent_name,
|
|
275
|
+
tag=tag,
|
|
276
|
+
image_name=image_name,
|
|
277
|
+
build_context_size_kb=build_context_size_kb,
|
|
278
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Environments
|
|
24
|
+
.env**
|
|
25
|
+
.venv
|
|
26
|
+
env/
|
|
27
|
+
venv/
|
|
28
|
+
ENV/
|
|
29
|
+
env.bak/
|
|
30
|
+
venv.bak/
|
|
31
|
+
|
|
32
|
+
# IDE
|
|
33
|
+
.idea/
|
|
34
|
+
.vscode/
|
|
35
|
+
*.swp
|
|
36
|
+
*.swo
|
|
37
|
+
|
|
38
|
+
# Git
|
|
39
|
+
.git
|
|
40
|
+
.gitignore
|
|
41
|
+
|
|
42
|
+
# Misc
|
|
43
|
+
.DS_Store
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.3
|
|
2
|
+
FROM python:3.12-slim
|
|
3
|
+
COPY --from=ghcr.io/astral-sh/uv:0.6.4 /uv /uvx /bin/
|
|
4
|
+
|
|
5
|
+
# Install system dependencies
|
|
6
|
+
RUN apt-get update && apt-get install -y \
|
|
7
|
+
htop \
|
|
8
|
+
vim \
|
|
9
|
+
curl \
|
|
10
|
+
tar \
|
|
11
|
+
python3-dev \
|
|
12
|
+
postgresql-client \
|
|
13
|
+
build-essential \
|
|
14
|
+
libpq-dev \
|
|
15
|
+
gcc \
|
|
16
|
+
cmake \
|
|
17
|
+
netcat-openbsd \
|
|
18
|
+
nodejs \
|
|
19
|
+
npm \
|
|
20
|
+
&& apt-get clean \
|
|
21
|
+
&& rm -rf /var/lib/apt/lists/**
|
|
22
|
+
|
|
23
|
+
RUN uv pip install --system --upgrade pip setuptools wheel
|
|
24
|
+
|
|
25
|
+
ENV UV_HTTP_TIMEOUT=1000
|
|
26
|
+
|
|
27
|
+
# Copy just the pyproject.toml file to optimize caching
|
|
28
|
+
COPY {{ project_path_from_build_root }}/pyproject.toml /app/{{ project_path_from_build_root }}/pyproject.toml
|
|
29
|
+
|
|
30
|
+
WORKDIR /app/{{ project_path_from_build_root }}
|
|
31
|
+
|
|
32
|
+
# Install the required Python packages using uv
|
|
33
|
+
RUN uv pip install --system .
|
|
34
|
+
|
|
35
|
+
# Copy the project code
|
|
36
|
+
COPY {{ project_path_from_build_root }}/project /app/{{ project_path_from_build_root }}/project
|
|
37
|
+
|
|
38
|
+
# Set environment variables
|
|
39
|
+
ENV PYTHONPATH=/app
|
|
40
|
+
|
|
41
|
+
# Run the agent using uvicorn
|
|
42
|
+
CMD ["uvicorn", "project.acp:acp", "--host", "0.0.0.0", "--port", "8000"]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.3
|
|
2
|
+
FROM python:3.12-slim
|
|
3
|
+
COPY --from=ghcr.io/astral-sh/uv:0.6.4 /uv /uvx /bin/
|
|
4
|
+
|
|
5
|
+
# Install system dependencies
|
|
6
|
+
RUN apt-get update && apt-get install -y \
|
|
7
|
+
htop \
|
|
8
|
+
vim \
|
|
9
|
+
curl \
|
|
10
|
+
tar \
|
|
11
|
+
python3-dev \
|
|
12
|
+
postgresql-client \
|
|
13
|
+
build-essential \
|
|
14
|
+
libpq-dev \
|
|
15
|
+
gcc \
|
|
16
|
+
cmake \
|
|
17
|
+
netcat-openbsd \
|
|
18
|
+
node \
|
|
19
|
+
npm \
|
|
20
|
+
&& apt-get clean \
|
|
21
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
22
|
+
|
|
23
|
+
RUN uv pip install --system --upgrade pip setuptools wheel
|
|
24
|
+
|
|
25
|
+
ENV UV_HTTP_TIMEOUT=1000
|
|
26
|
+
|
|
27
|
+
# Copy just the requirements file to optimize caching
|
|
28
|
+
COPY {{ project_path_from_build_root }}/requirements.txt /app/{{ project_path_from_build_root }}/requirements.txt
|
|
29
|
+
|
|
30
|
+
WORKDIR /app/{{ project_path_from_build_root }}
|
|
31
|
+
|
|
32
|
+
# Install the required Python packages
|
|
33
|
+
RUN uv pip install --system -r requirements.txt
|
|
34
|
+
|
|
35
|
+
# Copy the project code
|
|
36
|
+
COPY {{ project_path_from_build_root }}/project /app/{{ project_path_from_build_root }}/project
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Set environment variables
|
|
40
|
+
ENV PYTHONPATH=/app
|
|
41
|
+
|
|
42
|
+
# Run the agent using uvicorn
|
|
43
|
+
CMD ["uvicorn", "project.acp:acp", "--host", "0.0.0.0", "--port", "8000"]
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# {{ agent_name }} - AgentEx Sync ACP Template
|
|
2
|
+
|
|
3
|
+
This is a starter template for building synchronous agents with the AgentEx framework. It provides a basic implementation of the Agent 2 Client Protocol (ACP) with immediate response capabilities to help you get started quickly.
|
|
4
|
+
|
|
5
|
+
## What You'll Learn
|
|
6
|
+
|
|
7
|
+
- **Tasks**: A task is a grouping mechanism for related messages. Think of it as a conversation thread or a session.
|
|
8
|
+
- **Messages**: Messages are communication objects within a task. They can contain text, data, or instructions.
|
|
9
|
+
- **Sync ACP**: Synchronous Agent Communication Protocol that requires immediate responses
|
|
10
|
+
- **Message Handling**: How to process and respond to messages in real-time
|
|
11
|
+
|
|
12
|
+
## Running the Agent
|
|
13
|
+
|
|
14
|
+
1. Run the agent locally:
|
|
15
|
+
```bash
|
|
16
|
+
agentex agents run --manifest manifest.yaml
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The agent will start on port 8000 and respond immediately to any messages it receives.
|
|
20
|
+
|
|
21
|
+
## What's Inside
|
|
22
|
+
|
|
23
|
+
This template:
|
|
24
|
+
- Sets up a basic sync ACP server
|
|
25
|
+
- Handles incoming messages with immediate responses
|
|
26
|
+
- Provides a foundation for building real-time agents
|
|
27
|
+
- Can include streaming support for long responses
|
|
28
|
+
|
|
29
|
+
## Next Steps
|
|
30
|
+
|
|
31
|
+
For more advanced agent development, check out the AgentEx tutorials:
|
|
32
|
+
|
|
33
|
+
- **Tutorials 00-08**: Learn about building synchronous agents with ACP
|
|
34
|
+
- **Tutorials 09-10**: Learn how to use Temporal to power asynchronous agents
|
|
35
|
+
- Tutorial 09: Basic Temporal workflow setup
|
|
36
|
+
- Tutorial 10: Advanced Temporal patterns and best practices
|
|
37
|
+
|
|
38
|
+
These tutorials will help you understand:
|
|
39
|
+
- How to handle long-running tasks
|
|
40
|
+
- Implementing state machines
|
|
41
|
+
- Managing complex workflows
|
|
42
|
+
- Best practices for async agent development
|
|
43
|
+
|
|
44
|
+
## The Manifest File
|
|
45
|
+
|
|
46
|
+
The `manifest.yaml` file is your agent's configuration file. It defines:
|
|
47
|
+
- How your agent should be built and packaged
|
|
48
|
+
- What files are included in your agent's Docker image
|
|
49
|
+
- Your agent's name and description
|
|
50
|
+
- Local development settings (like the port your agent runs on)
|
|
51
|
+
|
|
52
|
+
This file is essential for both local development and deployment of your agent.
|
|
53
|
+
|
|
54
|
+
## Project Structure
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
{{ project_name }}/
|
|
58
|
+
├── project/ # Your agent's code
|
|
59
|
+
│ ├── __init__.py
|
|
60
|
+
│ └── acp.py # ACP server and event handlers
|
|
61
|
+
├── Dockerfile # Container definition
|
|
62
|
+
├── manifest.yaml # Deployment config
|
|
63
|
+
├── dev.ipynb # Development notebook for testing
|
|
64
|
+
{% if use_uv %}
|
|
65
|
+
└── pyproject.toml # Dependencies (uv)
|
|
66
|
+
{% else %}
|
|
67
|
+
└── requirements.txt # Dependencies (pip)
|
|
68
|
+
{% endif %}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
### 1. Customize Message Handlers
|
|
74
|
+
- Modify the handlers in `acp.py` to implement your agent's logic
|
|
75
|
+
- Add your own tools and capabilities
|
|
76
|
+
- Implement custom response generation
|
|
77
|
+
|
|
78
|
+
### 2. Test Your Agent with the Development Notebook
|
|
79
|
+
Use the included `dev.ipynb` Jupyter notebook to test your agent interactively:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Start Jupyter notebook (make sure you have jupyter installed)
|
|
83
|
+
jupyter notebook dev.ipynb
|
|
84
|
+
|
|
85
|
+
# Or use VS Code to open the notebook directly
|
|
86
|
+
code dev.ipynb
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The notebook includes:
|
|
90
|
+
- **Setup**: Connect to your local AgentEx backend
|
|
91
|
+
- **Non-streaming tests**: Send messages and get complete responses
|
|
92
|
+
- **Streaming tests**: Test real-time streaming responses
|
|
93
|
+
- **Task management**: Optional task creation and management
|
|
94
|
+
|
|
95
|
+
The notebook automatically uses your agent name (`{{ agent_name }}`) and provides examples for both streaming and non-streaming message handling.
|
|
96
|
+
|
|
97
|
+
### 3. Manage Dependencies
|
|
98
|
+
|
|
99
|
+
{% if use_uv %}
|
|
100
|
+
You chose **uv** for package management. Here's how to work with dependencies:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Add new dependencies
|
|
104
|
+
agentex uv add requests openai anthropic
|
|
105
|
+
|
|
106
|
+
# Install/sync dependencies
|
|
107
|
+
agentex uv sync
|
|
108
|
+
|
|
109
|
+
# Run commands with uv
|
|
110
|
+
uv run agentex agents run --manifest manifest.yaml
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Benefits of uv:**
|
|
114
|
+
- Faster dependency resolution and installation
|
|
115
|
+
- Better dependency isolation
|
|
116
|
+
- Modern Python packaging standards
|
|
117
|
+
|
|
118
|
+
{% else %}
|
|
119
|
+
You chose **pip** for package management. Here's how to work with dependencies:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Edit requirements.txt manually to add dependencies
|
|
123
|
+
echo "requests" >> requirements.txt
|
|
124
|
+
echo "openai" >> requirements.txt
|
|
125
|
+
|
|
126
|
+
# Install dependencies
|
|
127
|
+
pip install -r requirements.txt
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Benefits of pip:**
|
|
131
|
+
- Familiar workflow for most Python developers
|
|
132
|
+
- Simple requirements.txt management
|
|
133
|
+
- Wide compatibility
|
|
134
|
+
{% endif %}
|
|
135
|
+
|
|
136
|
+
### 4. Configure Credentials
|
|
137
|
+
Options:
|
|
138
|
+
1. Add any required credentials to your manifest.yaml via the `env` section
|
|
139
|
+
2. Export them in your shell: `export OPENAI_API_KEY=...`
|
|
140
|
+
3. For local development, create a `.env.local` file in the project directory
|
|
141
|
+
|
|
142
|
+
## Local Development
|
|
143
|
+
|
|
144
|
+
### 1. Start the Agentex Backend
|
|
145
|
+
```bash
|
|
146
|
+
# Navigate to the backend directory
|
|
147
|
+
cd agentex
|
|
148
|
+
|
|
149
|
+
# Start all services using Docker Compose
|
|
150
|
+
make dev
|
|
151
|
+
|
|
152
|
+
# Optional: In a separate terminal, use lazydocker for a better UI (everything should say "healthy")
|
|
153
|
+
lzd
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 3. Run Your Agent
|
|
157
|
+
```bash
|
|
158
|
+
# From this directory
|
|
159
|
+
export ENVIRONMENT=development && agentex agents run --manifest manifest.yaml
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 4. Interact with Your Agent
|
|
163
|
+
|
|
164
|
+
**Option 1: Web UI (Recommended)**
|
|
165
|
+
```bash
|
|
166
|
+
# Start the local web interface
|
|
167
|
+
cd agentex-web
|
|
168
|
+
make dev
|
|
169
|
+
|
|
170
|
+
# Then open http://localhost:3000 in your browser to chat with your agent
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Option 2: CLI (Deprecated)**
|
|
174
|
+
```bash
|
|
175
|
+
# Submit a task via CLI
|
|
176
|
+
agentex tasks submit --agent {{ agent_name }} --task "Your task here"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Development Tips
|
|
180
|
+
|
|
181
|
+
### Environment Variables
|
|
182
|
+
- Set environment variables in project/.env for any required credentials
|
|
183
|
+
- Or configure them in the manifest.yaml under the `env` section
|
|
184
|
+
- The `.env` file is automatically loaded in development mode
|
|
185
|
+
|
|
186
|
+
### Local Testing
|
|
187
|
+
- Use `export ENVIRONMENT=development` before running your agent
|
|
188
|
+
- This enables local service discovery and debugging features
|
|
189
|
+
- Your agent will automatically connect to locally running services
|
|
190
|
+
|
|
191
|
+
### Sync ACP Considerations
|
|
192
|
+
- Responses must be immediate (no long-running operations)
|
|
193
|
+
- Use streaming for longer responses
|
|
194
|
+
- Keep processing lightweight and fast
|
|
195
|
+
- Consider caching for frequently accessed data
|
|
196
|
+
|
|
197
|
+
### Debugging
|
|
198
|
+
- Check agent logs in the terminal where you ran the agent
|
|
199
|
+
- Use the web UI to inspect task history and responses
|
|
200
|
+
- Monitor backend services with `lzd` (LazyDocker)
|
|
201
|
+
- Test response times and optimize for speed
|
|
202
|
+
|
|
203
|
+
### To build the agent Docker image locally (normally not necessary):
|
|
204
|
+
|
|
205
|
+
1. Build the agent image:
|
|
206
|
+
```bash
|
|
207
|
+
agentex agents build --manifest manifest.yaml
|
|
208
|
+
```
|
|
209
|
+
{% if use_uv %}
|
|
210
|
+
```bash
|
|
211
|
+
# Build with uv
|
|
212
|
+
agentex agents build --manifest manifest.yaml --push
|
|
213
|
+
```
|
|
214
|
+
{% else %}
|
|
215
|
+
```bash
|
|
216
|
+
# Build with pip
|
|
217
|
+
agentex agents build --manifest manifest.yaml --push
|
|
218
|
+
```
|
|
219
|
+
{% endif %}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
## Advanced Features
|
|
223
|
+
|
|
224
|
+
### Streaming Responses
|
|
225
|
+
Handle long responses with streaming:
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
# In project/acp.py
|
|
229
|
+
@acp.on_message_send
|
|
230
|
+
async def handle_message_send(params: SendMessageParams):
|
|
231
|
+
# For streaming responses
|
|
232
|
+
async def stream_response():
|
|
233
|
+
for chunk in generate_response_chunks():
|
|
234
|
+
yield TaskMessageUpdate(
|
|
235
|
+
content=chunk,
|
|
236
|
+
is_complete=False
|
|
237
|
+
)
|
|
238
|
+
yield TaskMessageUpdate(
|
|
239
|
+
content="",
|
|
240
|
+
is_complete=True
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
return stream_response()
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Custom Response Logic
|
|
247
|
+
Add sophisticated response generation:
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
# In project/acp.py
|
|
251
|
+
@acp.on_message_send
|
|
252
|
+
async def handle_message_send(params: SendMessageParams):
|
|
253
|
+
# Analyze input
|
|
254
|
+
user_message = params.content.content
|
|
255
|
+
|
|
256
|
+
# Generate response
|
|
257
|
+
response = await generate_intelligent_response(user_message)
|
|
258
|
+
|
|
259
|
+
return TextContent(
|
|
260
|
+
author=MessageAuthor.AGENT,
|
|
261
|
+
content=response
|
|
262
|
+
)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Integration with External Services
|
|
266
|
+
{% if use_uv %}
|
|
267
|
+
```bash
|
|
268
|
+
# Add service clients
|
|
269
|
+
agentex uv add httpx requests-oauthlib
|
|
270
|
+
|
|
271
|
+
# Add AI/ML libraries
|
|
272
|
+
agentex uv add openai anthropic transformers
|
|
273
|
+
|
|
274
|
+
# Add fast processing libraries
|
|
275
|
+
agentex uv add numpy pandas
|
|
276
|
+
```
|
|
277
|
+
{% else %}
|
|
278
|
+
```bash
|
|
279
|
+
# Add to requirements.txt
|
|
280
|
+
echo "httpx" >> requirements.txt
|
|
281
|
+
echo "openai" >> requirements.txt
|
|
282
|
+
echo "numpy" >> requirements.txt
|
|
283
|
+
pip install -r requirements.txt
|
|
284
|
+
```
|
|
285
|
+
{% endif %}
|
|
286
|
+
|
|
287
|
+
## Troubleshooting
|
|
288
|
+
|
|
289
|
+
### Common Issues
|
|
290
|
+
|
|
291
|
+
1. **Agent not appearing in web UI**
|
|
292
|
+
- Check if agent is running on port 8000
|
|
293
|
+
- Verify `ENVIRONMENT=development` is set
|
|
294
|
+
- Check agent logs for errors
|
|
295
|
+
|
|
296
|
+
2. **Slow response times**
|
|
297
|
+
- Profile your message handling code
|
|
298
|
+
- Consider caching expensive operations
|
|
299
|
+
- Optimize database queries and API calls
|
|
300
|
+
|
|
301
|
+
3. **Dependency issues**
|
|
302
|
+
{% if use_uv %}
|
|
303
|
+
- Run `agentex uv sync` to ensure all dependencies are installed
|
|
304
|
+
{% else %}
|
|
305
|
+
- Run `pip install -r requirements.txt`
|
|
306
|
+
- Check if all dependencies are correctly listed in requirements.txt
|
|
307
|
+
{% endif %}
|
|
308
|
+
|
|
309
|
+
4. **Port conflicts**
|
|
310
|
+
- Check if another service is using port 8000
|
|
311
|
+
- Use `lsof -i :8000` to find conflicting processes
|
|
312
|
+
|
|
313
|
+
Happy building with Sync ACP! 🚀⚡
|