Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Environments
.env**
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# IDE
.idea/
.vscode/
*.swp
*.swo

# Git
.git
.gitignore

# Misc
.DS_Store
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# syntax=docker/dockerfile:1.3
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:0.6.4 /uv /uvx /bin/

# Install system dependencies
RUN apt-get update && apt-get install -y \
htop \
vim \
curl \
tar \
python3-dev \
postgresql-client \
build-essential \
libpq-dev \
gcc \
cmake \
netcat-openbsd \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Install tctl (Temporal CLI)
RUN curl -L https://github.com/temporalio/tctl/releases/download/v1.18.1/tctl_1.18.1_linux_arm64.tar.gz -o /tmp/tctl.tar.gz && \
tar -xzf /tmp/tctl.tar.gz -C /usr/local/bin && \
chmod +x /usr/local/bin/tctl && \
rm /tmp/tctl.tar.gz

RUN uv pip install --system --upgrade pip setuptools wheel

ENV UV_HTTP_TIMEOUT=1000

# Copy requirements
COPY pyproject.toml /app/pyproject.toml
COPY uv.lock /app/uv.lock
COPY README.md /app/README.md

WORKDIR /app/

# Install the required Python packages
RUN uv sync

# Copy the project code
COPY project /app/project

WORKDIR /app/project

# Run the ACP server using uvicorn
CMD ["uvicorn", "acp:acp", "--host", "0.0.0.0", "--port", "8000"]

# When we deploy the worker, we will replace the CMD with the following
# CMD ["python", "-m", "run_worker"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
install-dev:
uv sync --group dev

dev: install-dev
uv run --env-file=.env agentex agents run --manifest manifest.yaml

typecheck: install-dev
uv run mypy project --strict
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# [Agentic] Agentic Chat with a Custom Temporal Activity

This tutorial demonstrates how to implement a custom temporal activity with agentic ACP.
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "0",
"metadata": {},
"outputs": [],
"source": [
"from agentex import Agentex\n",
"\n",
"client = Agentex(base_url=\"http://localhost:5003\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"AGENT_NAME = \"at011-custom-agent-chat\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2",
"metadata": {},
"outputs": [],
"source": [
"# (REQUIRED) Create a new task. For Agentic agents, you must create a task for messages to be associated with.\n",
"import uuid\n",
"\n",
"rpc_response = client.agents.create_task(\n",
" agent_name=AGENT_NAME,\n",
" params={\n",
" \"name\": f\"{str(uuid.uuid4())[:8]}-task\",\n",
" \"params\": {}\n",
" }\n",
")\n",
"\n",
"task = rpc_response.result\n",
"task"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3",
"metadata": {},
"outputs": [],
"source": [
"# Send an event to the agent\n",
"\n",
"# The response is expected to be a list of TaskMessage objects, which is a union of the following types:\n",
"# - TextContent: A message with just text content \n",
"# - DataContent: A message with JSON-serializable data content\n",
"# - ToolRequestContent: A message with a tool request, which contains a JSON-serializable request to call a tool\n",
"# - ToolResponseContent: A message with a tool response, which contains response object from a tool call in its content\n",
"\n",
"# When processing the message/send response, if you are expecting more than TextContent, such as DataContent, ToolRequestContent, or ToolResponseContent, you can process them as well\n",
"\n",
"rpc_response = client.agents.send_event(\n",
" agent_name=AGENT_NAME,\n",
" params={\n",
" \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Hello what can you do?\"},\n",
" \"task_id\": task.id,\n",
" }\n",
")\n",
"\n",
"event = rpc_response.result\n",
"event"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {},
"outputs": [],
"source": [
"# Subscribe to the async task messages produced by the agent\n",
"from agentex.lib.utils.dev_tools import subscribe_to_async_task_messages\n",
"\n",
"task_messages = subscribe_to_async_task_messages(\n",
" client=client,\n",
" task=task, \n",
" only_after_timestamp=event.created_at, \n",
" print_messages=True,\n",
" rich_print=True,\n",
" timeout=5,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "at001-custom-temporal-activity",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
OPENAI_API_KEY=123
SCALE_GP_API_KEY=abc
SCALE_GP_ACCOUNT_ID=456
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Agent Manifest Configuration
# ---------------------------
# This file defines how your agent should be built and deployed.

# Build Configuration
# ------------------
# The build config defines what gets packaged into your agent's Docker image.
# This same configuration is used whether building locally or remotely.
#
# When building:
# 1. All files from include_paths are collected into a build context
# 2. The context is filtered by dockerignore rules
# 3. The Dockerfile uses this context to build your agent's image
# 4. The image is pushed to a registry and used to run your agent
build:
context:
# Root directory for the build context
root: ../ # Keep this as the default root

# Paths to include in the Docker build context
# Must include:
# - Your agent's directory (your custom agent code)
# These paths are collected and sent to the Docker daemon for building
include_paths:
- 011_custom_agent_chat

# Path to your agent's Dockerfile
# This defines how your agent's image is built from the context
# Relative to the root directory
dockerfile: 011_custom_agent_chat/Dockerfile

# Path to your agent's .dockerignore
# Filters unnecessary files from the build context
# Helps keep build context small and builds fast
dockerignore: 011_custom_agent_chat/.dockerignore

# Local Development Configuration
# -----------------------------
# Only used when running the agent locally
local_development:
agent:
port: 8000 # Port where your local ACP server is running
host_address: host.docker.internal # Host address for Docker networking (host.docker.internal for Docker, localhost for direct)

# File paths for local development (relative to this manifest.yaml)
paths:
# Path to ACP server file
# Examples:
# project/acp.py (standard)
# src/server.py (custom structure)
# ../shared/acp.py (shared across projects)
# /absolute/path/acp.py (absolute path)
acp: project/acp.py

# Path to temporal worker file
# Examples:
# project/run_worker.py (standard)
# workers/temporal.py (custom structure)
# ../shared/worker.py (shared across projects)
worker: project/run_worker.py

# Agent Configuration
# -----------------
agent:
# Type of agent - either sync or agentic
acp_type: agentic

# Unique name for your agent
# Used for task routing and monitoring
name: at011-custom-agent-chat

# Description of what your agent does
# Helps with documentation and discovery
description: An AgentEx agent that streams chat using a custom Temporal activity

# Temporal workflow configuration
# This enables your agent to run as a Temporal workflow for long-running tasks
temporal:
enabled: true
workflows:
# Name of the workflow class
# Must match the @workflow.defn name in your workflow.py
- name: at011-custom-agent-chat

# Queue name for task distribution
# Used by Temporal to route tasks to your agent
# Convention: <agent_name>_task_queue
queue_name: 011_custom_agent_chat_queue

# Optional: Credentials mapping
# Maps Kubernetes secrets to environment variables
# Common credentials include:
# credentials:
# - env_var_name: OPENAI_API_KEY
# secret_name: openai-api-key
# secret_key: api-key

# Optional: Set Environment variables for running your agent locally as well
# as for deployment later on
# env:
# - name: OPENAI_BASE_URL
# value: "https://api.openai.com/v1"
# - name: ACCOUNT_ID
# value: "your_account_id_here"

# Deployment Configuration
# -----------------------
# Configuration for deploying your agent to Kubernetes clusters
deployment:
# Container image configuration
image:
repository: "" # Update with your container registry
tag: "latest" # Default tag, should be versioned in production

imagePullSecrets:
- name: my-registry-secret # Update with your image pull secret name

# Global deployment settings that apply to all clusters
# These can be overridden using --override-file with custom configuration files
global:
agent:
name: "at011-custom-agent-chat"
description: "An AgentEx agent that streams chat using a custom Temporal activity"

# Default replica count
replicaCount: 1

# Default resource requirements
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "1000m"
memory: "2Gi"
Loading
Loading