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.1.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.1-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: chuk_acp_agent-0.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 b69198fd80b1c4e32472815b51c194cfed8efb5a6e9c6ccc043ccd9ebddee2d7
MD5 f158ac4f54e578ae8d4c6b43d382a366
BLAKE2b-256 6c06ff61a231b901d693c8f539292ef9463d62a0edcc442b8c674529a2749857

See more details on using hashes here.

File details

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

File metadata

  • Download URL: chuk_acp_agent-0.1.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bea2ce899cbde3e261aff861ef44e91a47a5ac4b1720484629fccf8d00aacc59
MD5 ebf9e9599741f4492440a49650aceec8
BLAKE2b-256 c508d349eb994f5a92470835a52caf2748fe162f81aa595ee5fec0c7461f5783

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