Skip to main content

Opinionated agent kit for building sophisticated ACP agents

Project description

chuk-acp-agent

Build powerful ACP agents with minimal boilerplate

A clean, type-safe framework for building editor agents. Features one-line MCP setup, direct result access, and zero legacy code.

# That's it - a complete working agent!
from chuk_acp_agent import Agent, Context

class MyAgent(Agent):
    def __init__(self):
        super().__init__()
        self.add_mcp_server("echo", "uvx chuk-mcp-echo stdio")  # One line!

    async def on_prompt(self, ctx: Context, prompt: str):
        result = await ctx.tools.call("echo_text", message=prompt)
        yield f"Echo: {result.text}\n"  # Direct access!

Features

  • High-level abstractions: Rich Context API with memory, streaming, and tool integration
  • MCP integration: Built-in support for Model Context Protocol via chuk-tool-processor
    • Simple config: One-line MCP server setup with add_mcp_server()
    • Clean results: Direct .text access, no manual extraction
    • Tool discovery: List available tools with ctx.tools.list()
    • Batch execution: Parallel tool calls with call_batch()
    • Load from file: load_mcp_config("config.json") for file-based configuration
  • Session memory: Key-value storage scoped to session lifecycle
  • Streaming responses: Async generator pattern with yield for real-time output
  • Plan tracking: Create and update task plans with send_plan() and update_plan()
  • Type-safe: Pydantic models throughout (AgentInfo, ToolResult, etc.)

Installation

pip install chuk-acp-agent

Quick Start

Minimal Agent

from chuk_acp_agent import Agent, Context

class MyAgent(Agent):
    async def on_prompt(self, ctx: Context, prompt: str):
        """Handle user prompts - yield strings to stream back."""
        # Increment message counter
        count = ctx.memory.get("count", 0) + 1
        ctx.memory.set("count", count)

        yield f"Message #{count}\n"
        yield f"You said: {prompt}\n"
        yield f"Session: {ctx.session_id}\n"

if __name__ == "__main__":
    MyAgent().run()

Run it:

# If installed in current environment
python my_agent.py

# Or use uv (recommended for development)
uv run my_agent.py

Test it with the chuk-acp client:

# Using uv (recommended)
uvx chuk-acp client uv run my_agent.py --prompt "Hello!"

# Or if chuk-acp-agent is installed globally
uvx chuk-acp client python my_agent.py --prompt "Hello!"

Using MCP Tools

Simple configuration and clean result access:

from chuk_acp_agent import Agent, Context

class MCPAgent(Agent):
    def __init__(self):
        super().__init__()
        # Simple one-line configuration!
        self.add_mcp_server("echo", "uvx chuk-mcp-echo stdio")
        self.add_mcp_server("filesystem", "npx -y @modelcontextprotocol/server-filesystem /tmp")

    async def on_prompt(self, ctx: Context, prompt: str):
        # Call MCP tool - returns clean ToolResult
        result = await ctx.tools.call("echo_text", message=prompt)

        # Access text directly - no manual extraction!
        yield f"Echo: {result.text}\n"

        # List available tools
        tools = await ctx.tools.list()
        yield f"Available: {', '.join(t.name for t in tools)}\n"

        # Batch execution (runs in parallel)
        results = await ctx.tools.call_batch([
            ("echo_text", {"message": "First"}),
            ("echo_text", {"message": "Second"}),
        ])
        for r in results:
            yield f"- {r.text}\n"

Clean and simple - that's it!

Streaming & Progress

async def on_prompt(self, ctx: Context, prompt: str):
    # Send plan
    await ctx.send_plan([
        {"content": "Analyzing code", "status": "in_progress"},
        {"content": "Applying fixes", "status": "pending"},
    ])

    # Stream tokens
    yield "Analyzing...\n"

    # Update plan
    await ctx.update_plan(0, status="completed")
    await ctx.update_plan(1, status="in_progress")

    # Continue streaming
    yield "Fixed 3 issues\n"

Context API

The Context object provides access to all agent capabilities:

Session Memory

# Store data per session
ctx.memory.set("current_file", "/path/to/file.py")
ctx.memory.set("user_preferences", {"theme": "dark"})

# Retrieve
file = ctx.memory.get("current_file")
prefs = ctx.memory.get("user_preferences", default={})

Tools (MCP)

# Call MCP tools - returns clean ToolResult
result = await ctx.tools.call("tool_name", **kwargs)
text = result.text  # Direct text access
is_error = result.is_error  # Check for errors

# List available tools (returns List[Tool])
tools = await ctx.tools.list()
for tool in tools:
    print(f"{tool.name}: {tool.description}")

# Batch execution (parallel)
results = await ctx.tools.call_batch([
    ("echo_text", {"message": "one"}),
    ("echo_text", {"message": "two"}),
])

Streaming

# Stream text tokens
await ctx.emit("Processing...\n")

# Stream with flushing
async for token in llm_stream:
    await ctx.emit(token)

Plans & Progress

# Create plan
await ctx.send_plan([
    {"content": "Step 1", "status": "pending"},
    {"content": "Step 2", "status": "pending"},
])

# Update plan
await ctx.update_plan(0, status="in_progress")
await ctx.update_plan(0, status="completed")

Agent Lifecycle

from chuk_acp import AgentInfo
from chuk_acp_agent import Agent, Context

class MyAgent(Agent):
    def get_agent_info(self) -> AgentInfo:
        """Return agent metadata using Pydantic type."""
        return AgentInfo(
            name="my-agent",
            version="1.0.0",
            title="My Agent - Custom Agent",
        )

    async def on_new_session(self, ctx: Context) -> None:
        """Called when a new session starts."""
        ctx.memory.set("session_start", time.time())

    async def on_prompt(self, ctx: Context, prompt: str):
        """Handle user prompt. Yield strings to stream back."""
        yield "Response\n"

    async def on_cancel(self, ctx: Context) -> None:
        """Called when user cancels ongoing prompt."""
        # Cleanup resources
        pass

Middleware

Add cross-cutting behaviors:

from chuk_acp_agent import Agent, Context
from chuk_acp_agent.middlewares import TracingMiddleware, RateLimitMiddleware

class MyAgent(Agent):
    def __init__(self):
        super().__init__()
        self.add_middleware(TracingMiddleware())
        self.add_middleware(RateLimitMiddleware(max_tokens_per_minute=100000))

Editor Integration

Zed

Add to ~/.config/zed/settings.json:

{
  "agent_servers": {
    "My Agent": {
      "command": "uv",
      "args": ["run", "/absolute/path/to/my_agent.py"],
      "env": {}
    }
  }
}

Or if chuk-acp-agent is installed globally:

{
  "agent_servers": {
    "My Agent": {
      "command": "python",
      "args": ["/absolute/path/to/my_agent.py"],
      "env": {}
    }
  }
}

VS Code (future)

Coming soon.

Examples

See the examples/ directory for complete working examples:

Core Examples:

MCP Integration:

All examples showcase the clean DX improvements!

Architecture

chuk-acp-agent/
├─ agent/                 # Core abstractions
│   ├─ base.py            # Agent base class with add_mcp_server()
│   └─ context.py         # Context with tools, memory, plans
├─ integrations/
│   └─ mcp_tools.py       # MCP tool invoker (ToolResult, call_batch, list)
├─ models/
│   ├─ mcp.py             # MCPConfig, MCPServerConfig (Pydantic)
│   ├─ tool.py            # Tool, ToolParameter (Pydantic)
│   └─ tool_result.py     # ToolResult wrapper
├─ exceptions.py          # ToolNotFoundError, ToolExecutionError
└─ examples/              # Working example agents

Testing

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# With coverage
pytest --cov=chuk_acp_agent

Contributing

Contributions welcome! Please open an issue or PR.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chuk_acp_agent-0.1.4.tar.gz (5.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chuk_acp_agent-0.1.4-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

Details for the file chuk_acp_agent-0.1.4.tar.gz.

File metadata

  • Download URL: chuk_acp_agent-0.1.4.tar.gz
  • Upload date:
  • Size: 5.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.2

File hashes

Hashes for chuk_acp_agent-0.1.4.tar.gz
Algorithm Hash digest
SHA256 4e60346d32bdb164b497ebda0c52e2b012cb534c8f207096064a574072e0d4b7
MD5 65601a2ae45ef4f3de7a329ba3fdb831
BLAKE2b-256 09b69d406b822587de56aac0dcd181aa5170f6f362aae3e82a549044d9e24237

See more details on using hashes here.

File details

Details for the file chuk_acp_agent-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: chuk_acp_agent-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 5.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.2

File hashes

Hashes for chuk_acp_agent-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 d780e471df6b0e1513a86adeb1ea09b913ef174932b9837d1994bb043aea0bc9
MD5 b3b3bff689477d1dde6cc07b6534c453
BLAKE2b-256 40adf46e21714dcf06eb2894a1fac6a96dc8d16ed7c5cf69346d76ceb93892cf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page