|
1 | | -<a href="https://agentclientprotocol.com/" > |
| 1 | +<a href="https://agentclientprotocol.com/"> |
2 | 2 | <img alt="Agent Client Protocol" src="https://zed.dev/img/acp/banner-dark.webp"> |
3 | 3 | </a> |
4 | 4 |
|
5 | 5 | # Agent Client Protocol (Python) |
6 | 6 |
|
7 | | -Python SDK for the Agent Client Protocol (ACP). Build agents that speak ACP over stdio so tools like Zed can orchestrate them. |
| 7 | +Build ACP-compliant agents and clients in Python with generated schema models, asyncio transports, helper builders, and runnable demos. |
8 | 8 |
|
9 | | -> Each release tracks the matching ACP schema version. Contributions that improve coverage or tooling are very welcome. |
10 | | -
|
11 | | -**Highlights** |
12 | | - |
13 | | -- Generated `pydantic` models that track the upstream ACP schema (`acp.schema`) |
14 | | -- Async base classes and JSON-RPC plumbing that keep stdio agents tiny |
15 | | -- Process helpers such as `spawn_agent_process` for embedding agents and clients directly in Python |
16 | | -- Batteries-included examples that exercise streaming updates, file I/O, and permission flows |
17 | | -- Optional Gemini CLI bridge (`examples/gemini.py`) for the `gemini --experimental-acp` integration |
18 | | -- Experimental contrib modules (`acp.contrib`) that streamline session state, tool call tracking, and permission prompts |
| 9 | +> Releases track the upstream ACP schema; contributions that tighten coverage or tooling are always welcome. |
19 | 10 |
|
20 | 11 | ## Install |
21 | 12 |
|
22 | 13 | ```bash |
23 | 14 | pip install agent-client-protocol |
24 | | -# or with uv |
| 15 | +# or |
25 | 16 | uv add agent-client-protocol |
26 | 17 | ``` |
27 | 18 |
|
28 | | -## Quickstart |
29 | | - |
30 | | -1. Install the package and point your ACP-capable client at the provided echo agent: |
31 | | - ```bash |
32 | | - pip install agent-client-protocol |
33 | | - python examples/echo_agent.py |
34 | | - ``` |
35 | | -2. Wire it into your client (e.g. Zed → Agents panel) so stdio is connected; the SDK handles JSON-RPC framing and lifecycle messages. |
36 | | - |
37 | | -Prefer a step-by-step walkthrough? Read the [Quickstart guide](docs/quickstart.md) or the hosted docs: https://agentclientprotocol.github.io/python-sdk/. |
38 | | - |
39 | | -### Launching from Python |
40 | | - |
41 | | -Embed the agent inside another Python process without spawning your own pipes: |
42 | | - |
43 | | -```python |
44 | | -import asyncio |
45 | | -import sys |
46 | | -from pathlib import Path |
47 | | - |
48 | | -from acp import spawn_agent_process, text_block |
49 | | -from acp.schema import InitializeRequest, NewSessionRequest, PromptRequest |
50 | | - |
51 | | - |
52 | | -async def main() -> None: |
53 | | - agent_script = Path("examples/echo_agent.py") |
54 | | - async with spawn_agent_process(lambda _agent: YourClient(), sys.executable, str(agent_script)) as (conn, _proc): |
55 | | - await conn.initialize(InitializeRequest(protocolVersion=1)) |
56 | | - session = await conn.newSession(NewSessionRequest(cwd=str(agent_script.parent), mcpServers=[])) |
57 | | - await conn.prompt( |
58 | | - PromptRequest( |
59 | | - sessionId=session.sessionId, |
60 | | - prompt=[text_block("Hello!")], |
61 | | - ) |
62 | | - ) |
63 | | - |
64 | | - |
65 | | -asyncio.run(main()) |
66 | | -``` |
67 | | - |
68 | | -`spawn_client_process` mirrors this pattern for the inverse direction. |
69 | | - |
70 | | -### Minimal agent sketch |
71 | | - |
72 | | -```python |
73 | | -import asyncio |
74 | | - |
75 | | -from acp import ( |
76 | | - Agent, |
77 | | - AgentSideConnection, |
78 | | - InitializeRequest, |
79 | | - InitializeResponse, |
80 | | - NewSessionRequest, |
81 | | - NewSessionResponse, |
82 | | - PromptRequest, |
83 | | - PromptResponse, |
84 | | - session_notification, |
85 | | - stdio_streams, |
86 | | - text_block, |
87 | | - update_agent_message, |
88 | | -) |
89 | | - |
90 | | - |
91 | | -class EchoAgent(Agent): |
92 | | - def __init__(self, conn): |
93 | | - self._conn = conn |
94 | | - |
95 | | - async def initialize(self, params: InitializeRequest) -> InitializeResponse: |
96 | | - return InitializeResponse(protocolVersion=params.protocolVersion) |
97 | | - |
98 | | - async def newSession(self, params: NewSessionRequest) -> NewSessionResponse: |
99 | | - return NewSessionResponse(sessionId="sess-1") |
100 | | - |
101 | | - async def prompt(self, params: PromptRequest) -> PromptResponse: |
102 | | - for block in params.prompt: |
103 | | - text = block.get("text", "") if isinstance(block, dict) else getattr(block, "text", "") |
104 | | - await self._conn.sessionUpdate( |
105 | | - session_notification( |
106 | | - params.sessionId, |
107 | | - update_agent_message(text_block(text)), |
108 | | - ) |
109 | | - ) |
110 | | - return PromptResponse(stopReason="end_turn") |
111 | | - |
112 | | - |
113 | | -async def main() -> None: |
114 | | - reader, writer = await stdio_streams() |
115 | | - AgentSideConnection(lambda conn: EchoAgent(conn), writer, reader) |
116 | | - await asyncio.Event().wait() |
117 | | - |
118 | | - |
119 | | -if __name__ == "__main__": |
120 | | - asyncio.run(main()) |
121 | | -``` |
122 | | - |
123 | | -Full example with streaming and lifecycle hooks lives in [examples/echo_agent.py](examples/echo_agent.py). |
124 | | - |
125 | | -## Examples |
126 | | - |
127 | | -- `examples/echo_agent.py`: the canonical streaming agent with lifecycle hooks |
128 | | -- `examples/client.py`: interactive console client that can launch any ACP agent via stdio |
129 | | -- `examples/agent.py`: richer agent showcasing initialization, authentication, and chunked updates |
130 | | -- `examples/duet.py`: launches both example agent and client using `spawn_agent_process` |
131 | | -- `examples/gemini.py`: connects to the Gemini CLI in `--experimental-acp` mode, with optional auto-approval and sandbox flags |
132 | | - |
133 | | -## Helper APIs |
134 | | - |
135 | | -Use `acp.helpers` to build protocol payloads without manually shaping dictionaries: |
136 | | - |
137 | | -```python |
138 | | -from acp import ( |
139 | | - start_read_tool_call, |
140 | | - text_block, |
141 | | - tool_content, |
142 | | - update_available_commands, |
143 | | - update_tool_call, |
144 | | -) |
145 | | - |
146 | | -start = start_read_tool_call("call-1", "Inspect config", path="config.toml") |
147 | | -commands = update_available_commands([]) |
148 | | -update = update_tool_call("call-1", status="completed", content=[tool_content(text_block("Done."))]) |
149 | | -``` |
| 19 | +## Why teams adopt this SDK |
150 | 20 |
|
151 | | -Helpers cover content blocks (`text_block`, `resource_link_block`), embedded resources, tool calls (`start_edit_tool_call`, `update_tool_call`), and session updates (`update_agent_message_text`, `update_available_commands`, `update_current_mode`, `session_notification`). |
| 21 | +- **Schema parity:** Generated Pydantic models in `acp.schema` stay pinned to the official ACP specification so payloads stay valid as the protocol evolves. |
| 22 | +- **Runtime ergonomics:** Async base classes, stdio JSON-RPC plumbing, and lifecycle helpers keep custom agents focused on behaviour, not wiring. |
| 23 | +- **Batteries included:** `examples/` cover streaming, permission flows, file access, Gemini CLI bridging, and embedded agent/client launches. |
| 24 | +- **Helper builders:** `acp.helpers` mirrors the Go/TS SDK convenience APIs for content blocks, tool calls, and session updates. |
| 25 | +- **Contrib patterns:** `acp.contrib` packages in-progress utilities (session accumulators, permission brokers, tool call trackers) harvested from reference integrations. |
152 | 26 |
|
153 | | -## Contrib helpers |
| 27 | +## Who benefits |
154 | 28 |
|
155 | | -The experimental `acp.contrib` package captures patterns from reference integrations: |
| 29 | +- Agent authors who need typed models, helper builders, and event-stream ergonomics for ACP-compatible assistants. |
| 30 | +- Client integrators embedding ACP parties inside Python applications or wrapping existing CLIs via stdio. |
| 31 | +- Tooling teams experimenting with permission flows, streaming UX, or Gemini bridges without re-implementing transports. |
| 32 | +See real adopters like kimi-cli in the [Use Cases list](https://agentclientprotocol.github.io/python-sdk/use-cases/). |
156 | 33 |
|
157 | | -- `SessionAccumulator` (`acp.contrib.session_state`) merges `SessionNotification` streams into immutable snapshots for UI rendering. |
158 | | -- `ToolCallTracker` (`acp.contrib.tool_calls`) generates consistent tool call starts/updates and buffers streamed content. |
159 | | -- `PermissionBroker` (`acp.contrib.permissions`) wraps permission requests with sensible default option sets. |
| 34 | +## How to get started |
160 | 35 |
|
161 | | -Read more in [docs/contrib.md](docs/contrib.md). |
| 36 | +- Follow the [Quickstart guide](https://agentclientprotocol.github.io/python-sdk/quickstart/) for installation, echo-agent validation, editor wiring (e.g. Zed), and programmatic launch recipes. |
| 37 | +- Browse the [example gallery](https://github.com/agentclientprotocol/python-sdk/tree/main/examples) to see progressively richer integrations you can copy or extend. |
| 38 | +- Skim the [docs hub](https://agentclientprotocol.github.io/python-sdk/) for focused references on contrib helpers, releasing, and transport details. |
162 | 39 |
|
163 | | -## Documentation |
| 40 | +## Resource map |
164 | 41 |
|
165 | | -- Project docs (MkDocs): https://agentclientprotocol.github.io/python-sdk/ |
166 | | -- Local sources: `docs/` |
167 | | - - [Quickstart](docs/quickstart.md) |
168 | | - - [Contrib helpers](docs/contrib.md) |
169 | | - - [Releasing](docs/releasing.md) |
| 42 | +- Docs hub: https://agentclientprotocol.github.io/python-sdk/ |
| 43 | +- PyPI package: https://pypi.org/project/agent-client-protocol/ |
| 44 | +- Quickstart: https://agentclientprotocol.github.io/python-sdk/quickstart/ |
| 45 | +- Use Cases: https://agentclientprotocol.github.io/python-sdk/use-cases/ |
| 46 | +- Contrib overview: https://agentclientprotocol.github.io/python-sdk/experimental-contrib/ |
| 47 | +- Releasing workflow: https://agentclientprotocol.github.io/python-sdk/releasing/ |
| 48 | +- Examples: https://github.com/agentclientprotocol/python-sdk/tree/main/examples (echo agent, richer agent, duet, client, Gemini bridge) |
| 49 | +- Tests: https://github.com/agentclientprotocol/python-sdk/tree/main/tests with pytest coverage and opt-in Gemini smoke checks (`ACP_ENABLE_GEMINI_TESTS=1`) |
170 | 50 |
|
171 | | -## Gemini CLI bridge |
| 51 | +## Repository tour |
172 | 52 |
|
173 | | -Want to exercise the `gemini` CLI over ACP? The repository includes a Python replica of the Go SDK's REPL: |
| 53 | +- `src/acp/`: runtime package (agents, clients, transports, helpers, schema bindings, contrib utilities) |
| 54 | +- `schema/`: upstream JSON schema sources (regenerate via `make gen-all`) |
| 55 | +- `docs/`: MkDocs content backing the published documentation |
| 56 | +- `examples/`: runnable scripts covering stdio orchestration patterns |
| 57 | +- `tests/`: pytest suite with golden fixtures and optional Gemini coverage |
174 | 58 |
|
175 | | -```bash |
176 | | -python examples/gemini.py --yolo # auto-approve permissions |
177 | | -python examples/gemini.py --sandbox --model gemini-2.5-pro |
178 | | -``` |
179 | | - |
180 | | -Defaults assume the CLI is discoverable via `PATH`; override with `--gemini` or `ACP_GEMINI_BIN=/path/to/gemini`. |
181 | | - |
182 | | -The smoke test (`tests/test_gemini_example.py`) is opt-in to avoid false negatives when the CLI is unavailable or lacks credentials. Enable it locally with: |
183 | | - |
184 | | -```bash |
185 | | -ACP_ENABLE_GEMINI_TESTS=1 ACP_GEMINI_BIN=/path/to/gemini uv run python -m pytest tests/test_gemini_example.py |
186 | | -``` |
| 59 | +## Development workflow |
187 | 60 |
|
188 | | -The test gracefully skips when authentication prompts (e.g. missing `GOOGLE_CLOUD_PROJECT`) block the interaction. |
| 61 | +- `make install` provisions the `uv` virtualenv and installs pre-commit hooks. |
| 62 | +- `make check` runs Ruff formatting/linting, type analysis, dependency hygiene, and lock verification. |
| 63 | +- `make test` executes `pytest` (with doctests) inside the managed environment. |
| 64 | +- `ACP_SCHEMA_VERSION=<ref> make gen-all` refreshes protocol artifacts when the schema advances. |
189 | 65 |
|
190 | | -## Development workflow |
| 66 | +Keep docs and examples current whenever you ship public API or transport changes, and prefer Conventional Commits (`feat:`, `fix:`, etc.) when submitting patches. |
191 | 67 |
|
192 | | -```bash |
193 | | -make install # create uv virtualenv and install hooks |
194 | | -ACP_SCHEMA_VERSION=<ref> make gen-all # refresh generated schema bindings |
195 | | -make check # lint, types, dependency analysis |
196 | | -make test # run pytest + doctests |
197 | | -``` |
| 68 | +## Community & support |
198 | 69 |
|
199 | | -After local changes, consider updating docs/examples if the public API surface shifts. |
| 70 | +- File issues or feature requests at https://github.com/agentclientprotocol/python-sdk. |
| 71 | +- Discuss ideas or get help via GitHub Discussions: https://github.com/agentclientprotocol/python-sdk/discussions. |
| 72 | +- Join the broader ACP conversations at https://agentclientprotocol.com/, the Zed community channels, or the community Zulip: https://agentclientprotocol.zulipchat.com/. |
| 73 | +- Shared learnings, integrations, or third-party transports are welcome additions to the documentation—open a PR! |
0 commit comments