channel-bot-cli-acp 0.1.0__tar.gz
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.
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/SKILL.md +217 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/contrib.md +41 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/experimental-v2.md +157 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/index.md +64 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/migration-guide-0.11.md +144 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/migration-guide-0.7.md +109 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/migration-guide-0.8.md +37 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/quickstart.md +305 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/releasing.md +46 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/use-cases.md +29 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/docs/web-transport.md +244 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/examples/agent.py +132 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/examples/client.py +228 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/examples/duet.py +43 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/examples/echo_agent.py +85 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/examples/gemini.py +456 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/examples/http_client.py +55 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/examples/http_server.py +79 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/acp-python-sdk-docs/examples/ws_client.py +56 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/SKILL.md +510 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/go/a2ui/main.go +50 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/go/a2ui-card.json +41 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/go/a2ui-update.json +10 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/go/agent/main.go +300 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/go/echo/main.go +51 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/go/fullflow/main.go +115 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/go/livecheck/main.go +125 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/java/A2UI.java +39 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/java/EchoBot.java +45 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/java/FullFlow.java +101 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/java/LiveCheck.java +100 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/java/a2ui-card.json +41 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/java/a2ui-update.json +10 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/nodejs/a2ui-card.json +41 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/nodejs/a2ui-update.json +10 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/nodejs/a2ui.mjs +14 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/nodejs/echo.mjs +37 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/nodejs/fullflow.mjs +76 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/nodejs/livecheck.mjs +85 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/python/a2ui-card.json +41 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/python/a2ui-update.json +10 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/python/a2ui.py +25 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/python/echo.py +50 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/python/fullflow.py +97 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/dingtalk-channel-sdk-docs/example/python/livecheck.py +94 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/SKILL.md +232 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/cardkit-streaming.md +146 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/dedup-architecture.md +205 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/markdown.md +118 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/meeting-channel.md +257 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/migration-from-lark-oapi.md +163 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/quickstart.md +203 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/reference.md +483 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/release-notes/v1.0.0.md +48 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/release-notes/v1.1.0.md +14 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/security.md +178 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/docs/webhook-server.md +189 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/samples/channel/echo_bot.py +35 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/samples/channel/meeting_follow_agenda.py +76 -0
- channel_bot_cli_acp-0.1.0/.agents/skills/lark-channel-sdk-python-docs/samples/channel/meeting_join_bot.py +82 -0
- channel_bot_cli_acp-0.1.0/.github/workflows/publish.yml +44 -0
- channel_bot_cli_acp-0.1.0/.gitignore +15 -0
- channel_bot_cli_acp-0.1.0/.python-version +1 -0
- channel_bot_cli_acp-0.1.0/AGENTS.md +158 -0
- channel_bot_cli_acp-0.1.0/LICENSE +21 -0
- channel_bot_cli_acp-0.1.0/PKG-INFO +230 -0
- channel_bot_cli_acp-0.1.0/README.md +213 -0
- channel_bot_cli_acp-0.1.0/docs/DingTalkIncomingMessageSamples.md +129 -0
- channel_bot_cli_acp-0.1.0/pyproject.toml +47 -0
- channel_bot_cli_acp-0.1.0/skills/channel-bot-cli-acp/SKILL.md +123 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/__init__.py +42 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/agent.py +916 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/channel.py +8 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/channels/__init__.py +82 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/channels/base.py +166 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/channels/dingtalk.py +470 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/channels/feishu.py +428 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/cli.py +456 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/config.py +231 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/py.typed +0 -0
- channel_bot_cli_acp-0.1.0/src/channel_bot_cli_acp/utils.py +267 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/__init__.py +88 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/a2ui.py +173 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/bot_identity.py +104 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/card.py +349 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/channel.py +424 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/compat.py +17 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/config.py +136 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/emotion.py +46 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/errors.py +106 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/frame.py +25 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/http_mode.py +51 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/httpx.py +54 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/identity.py +51 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/lifecycle.py +76 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/media.py +82 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/normalize/__init__.py +22 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/normalize/converters/__init__.py +24 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/normalize/converters/card.py +34 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/normalize/converters/media.py +50 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/normalize/converters/reply.py +41 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/normalize/converters/richtext.py +52 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/normalize/converters/text.py +15 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/normalize/message.py +148 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/outbound/__init__.py +12 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/outbound/markdown.py +94 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/outbound/retry.py +33 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/outbound/splitter.py +77 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/ratelimit.py +39 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/reply.py +211 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/__init__.py +31 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/batching.py +197 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/chat_queue.py +137 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/dedup.py +79 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/media_pipeline.py +241 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/pipeline.py +290 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/policy.py +209 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/policy_gate.py +5 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/processing_lock.py +77 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/seen_cache.py +208 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/ssrf_guard.py +115 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/safety/stale_detector.py +39 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/send.py +120 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/stream.py +208 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/token.py +31 -0
- channel_bot_cli_acp-0.1.0/src/dingtalk_channel_sdk/types.py +88 -0
- channel_bot_cli_acp-0.1.0/tests/test_agent.py +257 -0
- channel_bot_cli_acp-0.1.0/tests/test_channels_and_cli.py +231 -0
- channel_bot_cli_acp-0.1.0/tests/test_config.py +88 -0
- channel_bot_cli_acp-0.1.0/tests/test_utils.py +110 -0
- channel_bot_cli_acp-0.1.0/uv.lock +567 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: acp-python-sdk-docs
|
|
3
|
+
description: Local knowledge base mirroring the official Agent Client Protocol (ACP) Python SDK (agent-client-protocol) documentation and runnable examples. Use when building, integrating, debugging, or migrating ACP-compatible AI agents and clients in Python over stdio, Streamable HTTP (HTTP/2 + SSE), or WebSocket transports, working with acp.schema Pydantic models, acp.contrib helpers (SessionAccumulator, ToolCallTracker, PermissionBroker), or experimental Protocol v2 (acp.experimental.v2).
|
|
4
|
+
metadata:
|
|
5
|
+
author: Ecat
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
source: https://github.com/agentclientprotocol/python-sdk
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Agent Client Protocol (ACP) Python SDK Documentation
|
|
11
|
+
|
|
12
|
+
This skill provides the official documentation, migration guides, and runnable example scripts for the **Agent Client Protocol (ACP) Python SDK** (`agent-client-protocol`), enabling Python applications to implement ACP-compatible AI agents and clients without rebuilding JSON-RPC transports or schema models.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## ⚠️ Important Note on Reference Links & Path Mapping
|
|
17
|
+
|
|
18
|
+
This skill directory (`skills/acp-python-sdk-docs`) is a local mirror of the official [`agentclientprotocol/python-sdk`](https://github.com/agentclientprotocol/python-sdk) repository. When reading the Markdown files in `docs/`, resolve reference links using these rules:
|
|
19
|
+
|
|
20
|
+
1. **GitHub Repository Links (`blob/main/` & `tree/main/`)**:
|
|
21
|
+
Any link starting with `https://github.com/agentclientprotocol/python-sdk/blob/main/` or `https://github.com/agentclientprotocol/python-sdk/tree/main/` maps directly to the root of this skill directory (`skills/acp-python-sdk-docs/`).
|
|
22
|
+
- The local [`examples/`](examples/) directory is a direct mirror of the GitHub repository's `examples/` folder:
|
|
23
|
+
- `https://github.com/agentclientprotocol/python-sdk/blob/main/examples/echo_agent.py` ➔ [`examples/echo_agent.py`](examples/echo_agent.py)
|
|
24
|
+
- `https://github.com/agentclientprotocol/python-sdk/blob/main/examples/agent.py` ➔ [`examples/agent.py`](examples/agent.py)
|
|
25
|
+
- `https://github.com/agentclientprotocol/python-sdk/blob/main/examples/client.py` ➔ [`examples/client.py`](examples/client.py)
|
|
26
|
+
- `https://github.com/agentclientprotocol/python-sdk/blob/main/examples/duet.py` ➔ [`examples/duet.py`](examples/duet.py)
|
|
27
|
+
- `https://github.com/agentclientprotocol/python-sdk/blob/main/examples/gemini.py` ➔ [`examples/gemini.py`](examples/gemini.py)
|
|
28
|
+
- `https://github.com/agentclientprotocol/python-sdk/blob/main/examples/http_server.py` ➔ [`examples/http_server.py`](examples/http_server.py)
|
|
29
|
+
- `https://github.com/agentclientprotocol/python-sdk/blob/main/examples/http_client.py` ➔ [`examples/http_client.py`](examples/http_client.py)
|
|
30
|
+
- `https://github.com/agentclientprotocol/python-sdk/blob/main/examples/ws_client.py` ➔ [`examples/ws_client.py`](examples/ws_client.py)
|
|
31
|
+
- `https://github.com/agentclientprotocol/python-sdk/tree/main/examples` ➔ [`examples/`](examples/)
|
|
32
|
+
2. **Relative Documentation Links**:
|
|
33
|
+
Links within `docs/*.md` such as `[Quickstart](quickstart.md)`, `[Use Cases](use-cases.md)`, or `[contrib.md](contrib.md)` are relative to the `docs/` directory (e.g., `docs/quickstart.md`, `docs/use-cases.md`, `docs/contrib.md`).
|
|
34
|
+
3. **Unmirrored Internal SDK Source Files (`src/acp/`, `tests/`, `schema/`)**:
|
|
35
|
+
Mentions of internal repository paths like `src/acp/interfaces.py`, `src/acp/schema.py`, `src/acp/core.py`, or `tests/` refer to the upstream SDK source code and are not included in this documentation mirror. Use `docs/` and `examples/` for API signatures and usage patterns.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 📦 Package & Environment Overview
|
|
40
|
+
|
|
41
|
+
- **PyPI Package**: `agent-client-protocol`
|
|
42
|
+
- **Import Root**: `acp`
|
|
43
|
+
- **Python Requirement**: Python `>=3.10` (3.10–3.14+)
|
|
44
|
+
- **Bundled Protocol Schemas**:
|
|
45
|
+
- **Stable v1**: `schema-v1.23.0` (`acp`, `acp.schema`, `acp.interfaces`)
|
|
46
|
+
- **Experimental v2**: `schema-v2.0.0-alpha.5` (`acp.experimental.v2`)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Core SDK (stdio transport + Pydantic schema models)
|
|
50
|
+
pip install agent-client-protocol
|
|
51
|
+
# or
|
|
52
|
+
uv add agent-client-protocol
|
|
53
|
+
|
|
54
|
+
# Optional web transports (Streamable HTTP over HTTP/2 + SSE, WebSocket, Starlette ASGI server)
|
|
55
|
+
pip install "agent-client-protocol[http]"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 📚 Documentation Index (`docs/`)
|
|
61
|
+
|
|
62
|
+
| Document | Topic | Key Contents |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| [`docs/index.md`](docs/index.md) | **Overview & Architecture** | High-level overview of ACP, SDK building blocks (`acp.schema`, `acp.agent`/`acp.client`, `acp.contrib`), and navigation links. |
|
|
65
|
+
| [`docs/quickstart.md`](docs/quickstart.md) | **Quickstart & v1 Guide** | Installation, running the echo agent, Zed `settings.json` wiring, `spawn_agent_process`, subclassing `acp.Agent`, session notices (`SessionUpdateNotice`), additional v1 methods (`session/delete`, `providers/*`, `logout`, `mcp/*`, `nes/*`, `document/*`), request cancellation (`$/cancel_request`), `@param_model` routing, and Gemini CLI bridge. |
|
|
66
|
+
| [`docs/web-transport.md`](docs/web-transport.md) | **Web Transports (HTTP & WS)** | Experimental remote transports (`agent-client-protocol[http]`): Streamable HTTP (`create_http_stream`) and WebSocket (`create_websocket_stream`), Starlette server (`create_asgi_app`), sub-app mounting with lifespan, `load_session` / `resume_session` SSE routing, and HTTP/2 server setup with Hypercorn. |
|
|
67
|
+
| [`docs/contrib.md`](docs/contrib.md) | **Experimental Contrib Helpers** | Production utilities in `acp.contrib`: `SessionAccumulator` (`acp.contrib.session_state`), `ToolCallTracker` (`acp.contrib.tool_calls`), and `PermissionBroker` (`acp.contrib.permissions`). |
|
|
68
|
+
| [`docs/experimental-v2.md`](docs/experimental-v2.md) | **Experimental Protocol v2** | Draft v2 bindings (`acp.experimental.v2`, `schema-v2.0.0-alpha.5`), v2 `Agent`/`Client` handlers, non-blocking `prompt` with `message_id`, session notices, patch semantics (`None` vs omitted), and serving v1+v2 simultaneously via `AgentProtocolRouter`. |
|
|
69
|
+
| [`docs/use-cases.md`](docs/use-cases.md) | **Real-World Use Cases** | Production agents and clients built with the SDK (kimi-cli, Mini-Agent, OpenHands-CLI, fast-agent, agent-client-kernel, simple-acp-client). |
|
|
70
|
+
| [`docs/migration-guide-0.11.md`](docs/migration-guide-0.11.md) | **Migration Guide: 0.11** | Upgrading to 0.11 (`schema-v1.16.0`): `session_id`-first parameter ordering on `Client` and `Agent`, removal of `PromptRequest.message_id` and `set_session_model`, elicitation support (`create_elicitation`, `complete_elicitation`), `AgentPlanContentUpdate` / `AgentPlanRemovedUpdate`, and `AcpMcpServer`. |
|
|
71
|
+
| [`docs/migration-guide-0.8.md`](docs/migration-guide-0.8.md) | **Migration Guide: 0.8** | Upgrading to 0.8 (`schema-v0.10.8`): removal of `TerminalHandle` (use `CreateTerminalResponse.terminal_id`), `SessionInfoUpdate`, and 50MB default `stdio_buffer_limit_bytes`. |
|
|
72
|
+
| [`docs/migration-guide-0.7.md`](docs/migration-guide-0.7.md) | **Migration Guide: 0.7** | Upgrading to 0.7: `snake_case` Pydantic fields (`by_alias=True` when dumping), `run_agent` / `connect_to_agent` replacing manual `AgentSideConnection` / `ClientSideConnection`, and expanded method signatures. |
|
|
73
|
+
| [`docs/releasing.md`](docs/releasing.md) | **Releasing & Schema Sync** | Regenerating schema bindings (`ACP_SCHEMA_VERSION=... make gen-all`), running `make check` / `make test`, and publishing releases. |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 💻 Mirrored Code Examples (`examples/`)
|
|
78
|
+
|
|
79
|
+
All upstream example scripts are mirrored locally under [`examples/`](examples/):
|
|
80
|
+
|
|
81
|
+
| File | Role / Transport | Description & Key APIs Demonstrated |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| [`examples/echo_agent.py`](examples/echo_agent.py) | Minimal Agent (stdio) | Smallest streaming agent: subclasses `Agent`, captures `Client` connection in `on_connect`, handles `initialize`, `new_session`, and streams `AgentMessageChunk` via `self._conn.session_update()` inside `prompt()`, launched with `run_agent()`. |
|
|
84
|
+
| [`examples/agent.py`](examples/agent.py) | Full-Featured Agent (stdio) | Implements `initialize` (with `AgentCapabilities` and `Implementation`), `authenticate`, `new_session`, `load_session`, `set_session_mode`, `prompt`, `cancel`, `ext_method`, and `ext_notification`. |
|
|
85
|
+
| [`examples/client.py`](examples/client.py) | Interactive Client (stdio) | Spawns an agent subprocess, wires stdio with `connect_to_agent()`, implements `Client` callbacks (`request_permission`, `read_text_file`, `write_text_file`, terminal methods, `create_elicitation`, `complete_elicitation`, `session_update`), and runs an interactive console prompt loop. |
|
|
86
|
+
| [`examples/duet.py`](examples/duet.py) | Client + Agent Duet (stdio) | Uses `spawn_agent_process(client, sys.executable, str(agent_path))` context manager to launch [`examples/agent.py`](examples/agent.py) and drive it interactively with `ExampleClient` from [`examples/client.py`](examples/client.py). |
|
|
87
|
+
| [`examples/gemini.py`](examples/gemini.py) | Gemini CLI Bridge (stdio) | Complete ACP client driving `gemini --acp` (or `--experimental-acp`): implements file read/write (`FileSystemCapabilities`), terminal callbacks, interactive or `--yolo` auto-approval permission flows (`AllowedOutcome` / `DeniedOutcome`), and `:cancel` handling. |
|
|
88
|
+
| [`examples/http_server.py`](examples/http_server.py) | Remote Agent Server (HTTP/2 + WS) | Wraps an `EchoAgent` in a Starlette ASGI app using `create_asgi_app(lambda conn: EchoAgent())` and serves both Streamable HTTP and WebSocket on `http://localhost:8000/acp` via Hypercorn with HTTP/2 enabled (`alpn_protocols = ["h2", "http/1.1"]`). |
|
|
89
|
+
| [`examples/http_client.py`](examples/http_client.py) | Remote Client (Streamable HTTP) | Connects to a remote ACP server using `create_http_stream("http://localhost:8000/acp")` and `connect_to_agent()`. |
|
|
90
|
+
| [`examples/ws_client.py`](examples/ws_client.py) | Remote Client (WebSocket) | Connects to a remote ACP server using `await create_websocket_stream("ws://localhost:8000/acp")` and `connect_to_agent()`. |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 🚀 Core Usage Patterns & Quick Reference
|
|
95
|
+
|
|
96
|
+
### 1. Implementing a Streaming ACP Agent (stdio)
|
|
97
|
+
|
|
98
|
+
Subclass `acp.Agent`, store the peer `Client` connection in `on_connect`, stream updates via `session_update`, and start the stdio loop with `run_agent()`:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import asyncio
|
|
102
|
+
from typing import Any
|
|
103
|
+
from uuid import uuid4
|
|
104
|
+
|
|
105
|
+
from acp import Agent, InitializeResponse, NewSessionResponse, PromptResponse, run_agent
|
|
106
|
+
from acp.interfaces import Client
|
|
107
|
+
from acp.schema import AgentMessageChunk, ClientCapabilities, Implementation, TextContentBlock
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class MyAgent(Agent):
|
|
111
|
+
_conn: Client
|
|
112
|
+
|
|
113
|
+
def on_connect(self, conn: Client) -> None:
|
|
114
|
+
self._conn = conn
|
|
115
|
+
|
|
116
|
+
async def initialize(
|
|
117
|
+
self,
|
|
118
|
+
protocol_version: int,
|
|
119
|
+
client_capabilities: ClientCapabilities | None = None,
|
|
120
|
+
client_info: Implementation | None = None,
|
|
121
|
+
**kwargs: Any,
|
|
122
|
+
) -> InitializeResponse:
|
|
123
|
+
return InitializeResponse(protocol_version=protocol_version)
|
|
124
|
+
|
|
125
|
+
async def new_session(self, cwd: str, **kwargs: Any) -> NewSessionResponse:
|
|
126
|
+
return NewSessionResponse(session_id=uuid4().hex)
|
|
127
|
+
|
|
128
|
+
async def prompt(self, session_id: str, prompt: list[Any], **kwargs: Any) -> PromptResponse:
|
|
129
|
+
await self._conn.session_update(
|
|
130
|
+
session_id=session_id,
|
|
131
|
+
update=AgentMessageChunk(content=TextContentBlock(text="Processing prompt...")),
|
|
132
|
+
)
|
|
133
|
+
return PromptResponse(stop_reason="end_turn")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
if __name__ == "__main__":
|
|
137
|
+
asyncio.run(run_agent(MyAgent()))
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 2. Programmatically Spawning & Driving an Agent from Python
|
|
141
|
+
|
|
142
|
+
Use `spawn_agent_process` (or `spawn_client_process`) to manage child process lifecycle and stdio framing automatically:
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
import asyncio
|
|
146
|
+
import sys
|
|
147
|
+
from typing import Any
|
|
148
|
+
|
|
149
|
+
from acp import PROTOCOL_VERSION, spawn_agent_process
|
|
150
|
+
from acp.interfaces import Client
|
|
151
|
+
from acp.schema import TextContentBlock
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class SimpleClient(Client):
|
|
155
|
+
async def request_permission(self, session_id: str, tool_call: Any, options: Any, **kwargs: Any) -> Any:
|
|
156
|
+
return {"outcome": {"outcome": "cancelled"}}
|
|
157
|
+
|
|
158
|
+
async def session_update(self, session_id: str, update: Any, **kwargs: Any) -> None:
|
|
159
|
+
print("update:", session_id, update)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
async def main() -> None:
|
|
163
|
+
async with spawn_agent_process(SimpleClient(), sys.executable, "examples/echo_agent.py") as (conn, _proc):
|
|
164
|
+
await conn.initialize(protocol_version=PROTOCOL_VERSION)
|
|
165
|
+
session = await conn.new_session(cwd=".", mcp_servers=[])
|
|
166
|
+
await conn.prompt(
|
|
167
|
+
session_id=session.session_id,
|
|
168
|
+
prompt=[TextContentBlock(text="Hello from Python client!")],
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
asyncio.run(main())
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 3. Remote Web Transports (Streamable HTTP & WebSocket)
|
|
176
|
+
|
|
177
|
+
Requires `pip install "agent-client-protocol[http]"`. See [`docs/web-transport.md`](docs/web-transport.md) for full details.
|
|
178
|
+
|
|
179
|
+
- **Server (`acp.http.asgi.create_asgi_app`)**:
|
|
180
|
+
Creates a Starlette application serving both Streamable HTTP (`POST`/`GET` SSE/`DELETE`) and WebSocket upgrades at `/acp` (configurable via `path="/rpc"`).
|
|
181
|
+
> ⚠️ **HTTP/2 Requirement**: Streamable HTTP requires an HTTP/2-capable ASGI server such as **Hypercorn**, Daphne, or Granian (Uvicorn only supports WebSocket, not HTTP/2).
|
|
182
|
+
- **Client (`acp.http.create_http_stream` / `acp.ws.create_websocket_stream`)**:
|
|
183
|
+
```python
|
|
184
|
+
from acp import connect_to_agent
|
|
185
|
+
from acp.http import create_http_stream
|
|
186
|
+
from acp.ws import create_websocket_stream
|
|
187
|
+
|
|
188
|
+
# Streamable HTTP
|
|
189
|
+
transport = create_http_stream("http://localhost:8000/acp")
|
|
190
|
+
conn = connect_to_agent(my_client, transport)
|
|
191
|
+
|
|
192
|
+
# Or WebSocket
|
|
193
|
+
transport = await create_websocket_stream("ws://localhost:8000/acp")
|
|
194
|
+
conn = connect_to_agent(my_client, transport)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 4. Additional v1 Protocol Methods & Unstable Opt-In
|
|
198
|
+
|
|
199
|
+
In `schema-v1.23.0`, `session/delete` (`delete_session`) and `logout` (`logout`) are stable. Unstable methods require `use_unstable_protocol=True` on the receiving connection or `run_agent()`:
|
|
200
|
+
- **Agent receivers**: `delete_session` (stable), `logout` (stable), `list_providers`, `set_provider`, `disable_provider`, `start_nes`, `suggest_nes`, `close_nes`, `accept_nes`, `reject_nes`, `did_open`, `did_change`, `did_close`, `did_save`, `did_focus`.
|
|
201
|
+
- **Client receivers**: `connect_mcp`, `disconnect_mcp`, `create_elicitation`, `complete_elicitation`.
|
|
202
|
+
- **Either peer**: `mcp_message` (request), `notify_mcp` (notification).
|
|
203
|
+
|
|
204
|
+
See [`docs/quickstart.md`](docs/quickstart.md#additional-v1-protocol-methods) and [`docs/migration-guide-0.11.md`](docs/migration-guide-0.11.md#4-handle-elicitation-if-your-agent-or-client-advertises-it) for handler signatures.
|
|
205
|
+
|
|
206
|
+
### 5. Experimental Contrib Utilities (`acp.contrib`)
|
|
207
|
+
|
|
208
|
+
See [`docs/contrib.md`](docs/contrib.md) for stateful helpers:
|
|
209
|
+
- **`acp.contrib.session_state.SessionAccumulator`**: Reconciles streamed `SessionNotification` events (`tool_call`, `tool_call_update`, plans, messages) into immutable `SessionSnapshot` Pydantic models with `apply()`, `snapshot()`, and `subscribe()`.
|
|
210
|
+
- **`acp.contrib.tool_calls.ToolCallTracker`**: Emits canonical `ToolCallStart` / `ToolCallProgress` updates (`start()`, `progress()`, `append_stream_text()`) and tracks in-memory tool call views.
|
|
211
|
+
- **`acp.contrib.permissions.PermissionBroker`**: Wraps `requestPermission` RPCs (`request_for()`) with default Approve / Approve for session / Reject options (`default_permission_options()`), syncing state with `ToolCallTracker`.
|
|
212
|
+
|
|
213
|
+
### 6. Experimental Protocol v2 & Dual-Version Routing (`acp.experimental`)
|
|
214
|
+
|
|
215
|
+
See [`docs/experimental-v2.md`](docs/experimental-v2.md) for draft `schema-v2.0.0-alpha.5` support:
|
|
216
|
+
- Import `from acp.experimental import v2` for `v2.Agent`, `v2.Client`, `v2.connect_to_agent`, `v2.run_agent`, and `v2.schema`.
|
|
217
|
+
- Use `AgentProtocolRouter(v1=lambda conn: V1Agent(conn), v2=lambda conn: V2Agent(conn))` from `acp.experimental` to serve both v1 and v2 clients from a single agent process.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Experimental Contrib Modules
|
|
2
|
+
|
|
3
|
+
The helpers under `acp.contrib` package recurring patterns we saw in integrations such as Toad, kimi-cli, and Gemini. Keep in mind they are experimental—APIs can still shift as we learn. Use this page as a menu:
|
|
4
|
+
|
|
5
|
+
- **`session_state.SessionAccumulator`** — build a canonical, immutable snapshot of every session update so UIs can render tool calls and plans without re-implementing state machines.
|
|
6
|
+
- **`tool_calls.ToolCallTracker` + `permissions.PermissionBroker`** — coordinate streamed tool call updates and permission prompts from one place.
|
|
7
|
+
|
|
8
|
+
## SessionAccumulator (`acp.contrib.session_state`)
|
|
9
|
+
|
|
10
|
+
**Use it when:** you need a live, merged view of `SessionNotification` events (e.g. tool calls, plan entries, user/agent messages) to drive UI widgets.
|
|
11
|
+
|
|
12
|
+
**Key capabilities**
|
|
13
|
+
|
|
14
|
+
- `SessionAccumulator.apply(notification)` reconciles `tool_call` and `tool_call_update` payloads, even if the start event arrives late.
|
|
15
|
+
- `snapshot()` returns an immutable `SessionSnapshot` Pydantic model containing the plan, current mode, commands, and ordered message history.
|
|
16
|
+
- Raw tool input/output payloads are copied when applying notifications and creating snapshots, so nested payload mutations do not change the accumulated state.
|
|
17
|
+
- `subscribe(callback)` lets you push snapshots into stores or UI components whenever state changes.
|
|
18
|
+
- Automatic reset on session-change (toggle with `auto_reset_on_session_change`).
|
|
19
|
+
|
|
20
|
+
> Tip: Create one accumulator per UI controller. Feed every raw `SessionNotification` into it and render from `snapshot.tool_calls` / `snapshot.user_messages` instead of mutating state manually.
|
|
21
|
+
|
|
22
|
+
## ToolCallTracker & PermissionBroker (`acp.contrib.tool_calls`, `acp.contrib.permissions`)
|
|
23
|
+
|
|
24
|
+
**Use them when:** your agent runtime synthesises tool call IDs, streams arguments, and prompts the user for approval. The helpers centralise the bookkeeping so you don’t juggle raw Pydantic models.
|
|
25
|
+
|
|
26
|
+
- `ToolCallTracker.start()/progress()/append_stream_text()` emits canonical `ToolCallStart` / `ToolCallProgress` updates and keeps an in-memory view via `view()` or `tool_call_model()`.
|
|
27
|
+
- `PermissionBroker.request_for()` wraps `requestPermission` RPCs. It reuses tracker state (or a provided `ToolCall`), lets you append extra content, and defaults to Approve / Approve for session / Reject options.
|
|
28
|
+
- Omit `options` or pass `None` to use broker defaults. An explicit empty option list raises `MissingPermissionOptionsError` before the permission request is sent; the same applies to empty `default_options` when no per-request options are supplied.
|
|
29
|
+
- `default_permission_options()` exposes that canonical option triple if you need to customise it.
|
|
30
|
+
|
|
31
|
+
> Tip: Keep one tracker near the agent event loop. Emit notifications through it and share the tracker with `PermissionBroker` so permission prompts always match the latest tool call state.
|
|
32
|
+
|
|
33
|
+
## Design Guardrails
|
|
34
|
+
|
|
35
|
+
To stay aligned with the ACP schema, the contrib layer follows a few rules:
|
|
36
|
+
|
|
37
|
+
- Schema data classes continue to live in `acp.schema`. Contrib helpers clone them with `.model_copy(deep=True)` before mutation.
|
|
38
|
+
- The core runtime never imports contrib modules implicitly—you opt in when they help.
|
|
39
|
+
- Helpers focus on painful bookkeeping (tool call aggregation, permission UX) and leave product-specific policy to your application.
|
|
40
|
+
|
|
41
|
+
Try the contrib modules, then open an issue or PR with feedback so we know which APIs should graduate into the stable surface.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Experimental Protocol v2
|
|
2
|
+
|
|
3
|
+
> **Experimental.** Protocol v2 is a draft. Import it from `acp.experimental` and
|
|
4
|
+
> expect its API and generated models to change with the upstream schema.
|
|
5
|
+
|
|
6
|
+
The bindings use `schema-v2.0.0-alpha.5`.
|
|
7
|
+
|
|
8
|
+
The v2 runtime is separate from the stable v1 API. Like v1, connection methods
|
|
9
|
+
and agent/client handlers accept expanded, snake-case parameters. Responses and
|
|
10
|
+
nested values (content blocks, updates, capabilities) use `v2.schema` models.
|
|
11
|
+
Extra keyword arguments carry request `_meta`.
|
|
12
|
+
|
|
13
|
+
Install update handlers before opening a session because updates are independent
|
|
14
|
+
connection traffic:
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from typing import Any
|
|
18
|
+
from acp.experimental import v2
|
|
19
|
+
|
|
20
|
+
class MyClient(v2.Client):
|
|
21
|
+
async def session_update(
|
|
22
|
+
self, session_id: str, update: Any, **kwargs: Any,
|
|
23
|
+
) -> None:
|
|
24
|
+
handle_update(session_id, update)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
connection = v2.connect_to_agent(MyClient(), transport)
|
|
28
|
+
initialized = await connection.initialize(
|
|
29
|
+
protocol_version=v2.PROTOCOL_VERSION,
|
|
30
|
+
info=v2.schema.Implementation(name="my-client", version="1.0.0"),
|
|
31
|
+
)
|
|
32
|
+
session = await connection.new_session(cwd="/workspace")
|
|
33
|
+
accepted = await connection.prompt(
|
|
34
|
+
session_id=session.session_id,
|
|
35
|
+
prompt=[v2.schema.TextContentBlock(text="Hello")],
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Implement an agent with the same expanded handler style:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
class MyAgent(v2.Agent):
|
|
43
|
+
async def initialize(
|
|
44
|
+
self,
|
|
45
|
+
protocol_version: int,
|
|
46
|
+
info: v2.schema.Implementation,
|
|
47
|
+
capabilities: v2.schema.ClientCapabilities | None = None,
|
|
48
|
+
**kwargs: Any,
|
|
49
|
+
) -> v2.schema.InitializeResponse:
|
|
50
|
+
return v2.schema.InitializeResponse(
|
|
51
|
+
protocol_version=v2.PROTOCOL_VERSION,
|
|
52
|
+
info=v2.schema.Implementation(name="my-agent", version="1.0.0"),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
async def new_session(
|
|
56
|
+
self,
|
|
57
|
+
cwd: str,
|
|
58
|
+
additional_directories: list[str] | None = None,
|
|
59
|
+
mcp_servers: list[Any] | None = None,
|
|
60
|
+
**kwargs: Any,
|
|
61
|
+
) -> v2.schema.NewSessionResponse:
|
|
62
|
+
return v2.schema.NewSessionResponse(session_id="session-1")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
await v2.run_agent(MyAgent())
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`v2.Agent` and `v2.Client` describe the v2 handler signatures; subclassing is
|
|
69
|
+
optional. Implement only the methods you support. Unimplemented requests return
|
|
70
|
+
method-not-found, and unimplemented notifications are ignored. The v2 protocols
|
|
71
|
+
are separate from v1 because initialization, prompt responses, permissions, and
|
|
72
|
+
session updates have different contracts. Both versions use `param_model`
|
|
73
|
+
metadata to derive their routes. V2 retains strict request/response validation
|
|
74
|
+
and requires successful initialization before other traffic.
|
|
75
|
+
|
|
76
|
+
Previously, v2 methods accepted a whole request model. Replace
|
|
77
|
+
`connection.new_session(v2.schema.NewSessionRequest(cwd="/workspace"))` with
|
|
78
|
+
`connection.new_session(cwd="/workspace")`, and expand handler parameters likewise.
|
|
79
|
+
|
|
80
|
+
Union requests also use expanded parameters:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
await connection.set_config_option(config_id="thinking", session_id=session.session_id, value=True)
|
|
84
|
+
# type defaults to "boolean" for bool values and "id" otherwise.
|
|
85
|
+
await connection.set_config_option(
|
|
86
|
+
config_id="vendor/limit", session_id=session.session_id, value=10, type="vendor/number",
|
|
87
|
+
)
|
|
88
|
+
await agent_connection.create_elicitation(
|
|
89
|
+
message="Sign in", mode="url", session_id=session.session_id,
|
|
90
|
+
elicitation_id="sign-in-1", url="https://example.com/login",
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
For elicitation, `session_id` selects session scope; otherwise `request_id`
|
|
95
|
+
selects request scope (including `None`). Pass `requested_schema` for form mode,
|
|
96
|
+
or `elicitation_id` and `url` for URL mode. Handlers receive the validated
|
|
97
|
+
branch's fields, including `type` for config options and `mode` for elicitation.
|
|
98
|
+
|
|
99
|
+
`session/prompt` returns after the agent inserts the user message into the ACP
|
|
100
|
+
conversation, without waiting for processing to finish. The response requires a
|
|
101
|
+
non-null `message_id`. Agents return `v2.schema.PromptResponse(message_id=...)`
|
|
102
|
+
and echo the user message in a `UserMessageUpdate` or `UserMessageChunk` carrying
|
|
103
|
+
the same ID. That update may arrive before or after the response; use
|
|
104
|
+
`accepted.message_id` to match it. Other session updates are independent traffic
|
|
105
|
+
and do not carry a prompt identifier.
|
|
106
|
+
|
|
107
|
+
Agents can send `v2.schema.SessionNotice(severity="warning", title="Context is nearly full")`
|
|
108
|
+
with `await agent_connection.session_update(session_id=session_id, update=notice)`. V2 notices require no client capability and
|
|
109
|
+
are live advisory events, outside retained session history. Clients may ignore
|
|
110
|
+
them. Titles must be non-empty, and severity also accepts custom or future strings.
|
|
111
|
+
|
|
112
|
+
For patch fields in session updates, omit a field to leave its current
|
|
113
|
+
value unchanged, or explicitly pass `None` to clear it. For example,
|
|
114
|
+
`v2.schema.SessionToolCallUpdate(tool_call_id="tool-1", name=None)` clears the
|
|
115
|
+
tool name, while omitting `name` leaves it unchanged. This also applies to
|
|
116
|
+
terminal updates and patch metadata. When applying received patches, use
|
|
117
|
+
`update.model_dump(by_alias=True, exclude_unset=True)` to retain that distinction.
|
|
118
|
+
|
|
119
|
+
Setting `replay_from=v2.schema.ReplayFromStartVariant()` on `connection.resume_session(...)`
|
|
120
|
+
requests all retained conversation history; agents need not retain every message.
|
|
121
|
+
Accepted elicitation content validates scalar values and string lists; nested
|
|
122
|
+
objects are not valid form values.
|
|
123
|
+
|
|
124
|
+
Agents that serve both versions use `AgentProtocolRouter`:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from acp.experimental import AgentProtocolRouter
|
|
128
|
+
|
|
129
|
+
router = AgentProtocolRouter(
|
|
130
|
+
v1=lambda connection: V1Agent(connection),
|
|
131
|
+
v2=lambda connection: V2Agent(connection),
|
|
132
|
+
)
|
|
133
|
+
await router.run()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The selected factory is called once per connection. Return a fresh agent from
|
|
137
|
+
each call to avoid sharing connection state.
|
|
138
|
+
|
|
139
|
+
Extension method names are explicit and must include the protocol-required `_`
|
|
140
|
+
prefix:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
result = await connection.send_extension_request("_vendor/method", {"value": 1})
|
|
144
|
+
await connection.send_extension_notification("_vendor/event", {"value": 1})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The selected runtime remains strict after initialization: v1 messages are not
|
|
148
|
+
accepted by a v2 connection, and v2 messages are not translated into v1 calls.
|
|
149
|
+
Only the initial v2 request is reduced to the common v1 initialization fields
|
|
150
|
+
when an agent selects v1.
|
|
151
|
+
|
|
152
|
+
Client-side fallback is application controlled and may require opening a new
|
|
153
|
+
transport. Protocol-level request cancellation (`$/cancel_request`) is handled
|
|
154
|
+
by the shared connection layer, as in v1: cancelling the task awaiting a request
|
|
155
|
+
sends a best-effort cancellation to the peer, and an incoming cancellation
|
|
156
|
+
cancels the handler task, which answers with its result or `-32800`.
|
|
157
|
+
`session/cancel` remains available for cancelling active session work.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<a href="https://agentclientprotocol.com/">
|
|
2
|
+
<img alt="Agent Client Protocol" src="https://zed.dev/img/acp/banner-dark.webp">
|
|
3
|
+
</a>
|
|
4
|
+
|
|
5
|
+
# Agent Client Protocol SDK (Python)
|
|
6
|
+
|
|
7
|
+
Ship ACP-compatible agents and clients in Python without rebuilding JSON-RPC transports or schema models. This SDK mirrors each ACP release so your integrations stay interoperable with editors, CLIs, and hosted clients.
|
|
8
|
+
|
|
9
|
+
## Install & verify
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install agent-client-protocol
|
|
13
|
+
# or
|
|
14
|
+
uv add agent-client-protocol
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Next steps live in the [Quickstart](quickstart.md): launch the echo agent, wire it to Zed (or another ACP client), and exercise the programmatic spawn helpers.
|
|
18
|
+
|
|
19
|
+
## ACP at a glance
|
|
20
|
+
|
|
21
|
+
- ACP is the stdio protocol that lets “clients” (editors, shells, CLIs) orchestrate AI “agents.”
|
|
22
|
+
- Sessions exchange structured payloads (`session/update`, permission prompts, tool calls) defined in the upstream schema.
|
|
23
|
+
- Matching the schema version keeps your Python integrations compatible with tools such as Zed, Gemini CLI, or kimi-cli.
|
|
24
|
+
|
|
25
|
+
## SDK building blocks
|
|
26
|
+
|
|
27
|
+
- `acp.schema`: generated Pydantic models with defaults for protocol discriminator fields.
|
|
28
|
+
- `acp.agent` / `acp.client`: async base classes, JSON-RPC supervision, and lifecycle orchestration.
|
|
29
|
+
- `acp.contrib`: experimental utilities (session accumulators, permission brokers, tool call trackers) harvested from production deployments.
|
|
30
|
+
- `examples/`: runnable agents, clients, duet demos, and the Gemini CLI bridge.
|
|
31
|
+
|
|
32
|
+
## Quick links
|
|
33
|
+
|
|
34
|
+
| Need | Link |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| Quickstart walkthrough | [quickstart.md](quickstart.md) |
|
|
37
|
+
| Real-world adopters | [use-cases.md](use-cases.md) |
|
|
38
|
+
| Contrib helpers | [contrib.md](contrib.md) |
|
|
39
|
+
| Releasing workflow | [releasing.md](releasing.md) |
|
|
40
|
+
| Upgrade to 0.11 | [migration-guide-0.11.md](migration-guide-0.11.md) |
|
|
41
|
+
| Example scripts | [github.com/agentclientprotocol/python-sdk/tree/main/examples](https://github.com/agentclientprotocol/python-sdk/tree/main/examples) |
|
|
42
|
+
|
|
43
|
+
## Choose a path
|
|
44
|
+
|
|
45
|
+
- **Just exploring?** Skim [use-cases.md](use-cases.md) to see how kimi-cli, agent-client-kernel, and others use the SDK.
|
|
46
|
+
- **Building agents?** Copy `examples/echo_agent.py` or `examples/agent.py`, then use the generated models directly. Use `acp.contrib` for permission workflows and other stateful patterns.
|
|
47
|
+
- **Embedding clients?** Start with `examples/client.py` or the `spawn_agent_process` / `spawn_client_process` helpers in the [Quickstart](quickstart.md#programmatic-launch).
|
|
48
|
+
|
|
49
|
+
## Reference material
|
|
50
|
+
|
|
51
|
+
- [Quickstart](quickstart.md) — installation, editor wiring, and programmatic launch walkthroughs.
|
|
52
|
+
- [Use Cases](use-cases.md) — real adopters with succinct descriptions of what they build.
|
|
53
|
+
- [Experimental Contrib](contrib.md) — deep dives on the `acp.contrib` utilities.
|
|
54
|
+
- [Releasing](releasing.md) — schema upgrade process, versioning policy, and publishing checklist.
|
|
55
|
+
- [0.11 Migration Guide](migration-guide-0.11.md) — interface signature updates, elicitation, and schema notes for 0.10 users.
|
|
56
|
+
|
|
57
|
+
Need API-level details? Browse the source in `src/acp/` or generate docs with `mkdocstrings`.
|
|
58
|
+
|
|
59
|
+
## Feedback & support
|
|
60
|
+
|
|
61
|
+
- Open issues or discussions on GitHub for bugs, feature requests, or integration help.
|
|
62
|
+
- Join [GitHub Discussions](https://github.com/agentclientprotocol/python-sdk/discussions) to swap ideas.
|
|
63
|
+
- Chat with the community on [agentclientprotocol.zulipchat.com](https://agentclientprotocol.zulipchat.com/).
|
|
64
|
+
- Follow ACP roadmap updates at [agentclientprotocol.com](https://agentclientprotocol.com/).
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Migrating to ACP Python SDK 0.11
|
|
2
|
+
|
|
3
|
+
ACP Python SDK 0.11 updates the generated bindings to `schema-v1.16.0` and aligns the high-level interfaces with the new schema. Most applications only need to update method signatures and review the new unstable capabilities. Agents and clients that already pass keyword arguments are the easiest to migrate.
|
|
4
|
+
|
|
5
|
+
## 1. Regenerate schema-derived code
|
|
6
|
+
|
|
7
|
+
If your project vendors ACP schema files, generated models, or protocol metadata, regenerate them against the same upstream schema tag:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
ACP_SCHEMA_VERSION=schema-v1.16.0 make gen-all
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The SDK package version is `0.11.0`, while the protocol schema tag is `schema-v1.16.0`.
|
|
14
|
+
|
|
15
|
+
## 2. Update interface method signatures
|
|
16
|
+
|
|
17
|
+
Several generated request models changed field order or fields. The SDK now exposes those shapes through `Agent` and `Client` protocol methods. Prefer keyword calls when invoking connection helpers; keyword calls are stable across field-order changes.
|
|
18
|
+
|
|
19
|
+
### Client methods
|
|
20
|
+
|
|
21
|
+
Update client implementations from the 0.10 positional order:
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
async def request_permission(self, options, session_id, tool_call, **kwargs): ...
|
|
25
|
+
async def write_text_file(self, content, path, session_id, **kwargs): ...
|
|
26
|
+
async def read_text_file(self, path, session_id, limit=None, line=None, **kwargs): ...
|
|
27
|
+
async def create_terminal(self, command, session_id, args=None, cwd=None, env=None, **kwargs): ...
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
to the 0.11 order:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
async def request_permission(self, session_id, tool_call, options, **kwargs): ...
|
|
34
|
+
async def write_text_file(self, session_id, path, content, **kwargs): ...
|
|
35
|
+
async def read_text_file(self, session_id, path, line=None, limit=None, **kwargs): ...
|
|
36
|
+
async def create_terminal(self, session_id, command, args=None, env=None, cwd=None, **kwargs): ...
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Agent methods
|
|
40
|
+
|
|
41
|
+
Update agent implementations from the 0.10 prompt and mode signatures:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
async def set_session_mode(self, mode_id, session_id, **kwargs): ...
|
|
45
|
+
async def prompt(self, prompt, session_id, message_id=None, **kwargs): ...
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
to the 0.11 signatures:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
async def set_session_mode(self, session_id, mode_id, **kwargs): ...
|
|
52
|
+
async def prompt(self, session_id, prompt, **kwargs): ...
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The `message_id` field was removed from `PromptRequest`. If your client generated a user message ID before calling `conn.prompt(...)`, stop passing it there. Message IDs now belong to streamed content chunks such as `UserMessageChunk` and `AgentMessageChunk`.
|
|
56
|
+
|
|
57
|
+
## 3. Remove `session/model` handling
|
|
58
|
+
|
|
59
|
+
The generated `SetSessionModelRequest` and `SetSessionModelResponse` types are no longer exported, and the `Agent.set_session_model(...)` protocol method is gone. If your agent used this endpoint to switch models, move that behavior into session modes or configuration options exposed through `set_session_mode(...)` and `set_config_option(...)`.
|
|
60
|
+
|
|
61
|
+
## 4. Handle elicitation if your agent or client advertises it
|
|
62
|
+
|
|
63
|
+
0.11 adds schema and connection support for the unstable `elicitation/create` request and `elicitation/complete` notification.
|
|
64
|
+
|
|
65
|
+
Clients that advertise elicitation support should implement:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from typing import Any
|
|
69
|
+
|
|
70
|
+
from acp import AcceptElicitationResponse, Client, CreateElicitationResponse, ElicitationMode
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class MyClient(Client):
|
|
74
|
+
async def create_elicitation(
|
|
75
|
+
self,
|
|
76
|
+
message: str,
|
|
77
|
+
mode: ElicitationMode,
|
|
78
|
+
**kwargs: Any,
|
|
79
|
+
) -> CreateElicitationResponse:
|
|
80
|
+
return AcceptElicitationResponse(action="accept", content={})
|
|
81
|
+
|
|
82
|
+
async def complete_elicitation(self, elicitation_id: str, **kwargs: Any) -> None:
|
|
83
|
+
...
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Agents can request structured input through the connected client:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from acp import (
|
|
90
|
+
ElicitationFormSessionMode,
|
|
91
|
+
ElicitationSchema,
|
|
92
|
+
ElicitationStringPropertySchema,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
response = await client_conn.create_elicitation(
|
|
96
|
+
message="Choose a deployment target",
|
|
97
|
+
mode=ElicitationFormSessionMode(
|
|
98
|
+
session_id=session_id,
|
|
99
|
+
requested_schema=ElicitationSchema(
|
|
100
|
+
properties={"target": ElicitationStringPropertySchema(type="string")},
|
|
101
|
+
required=["target"],
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
For URL-based flows, use `ElicitationUrlSessionMode` or `ElicitationUrlRequestMode` and call `complete_elicitation(...)` once the external flow finishes.
|
|
108
|
+
|
|
109
|
+
## 5. Review new session update variants
|
|
110
|
+
|
|
111
|
+
Clients that exhaustively match `session_update` variants should add the new plan update variants:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from acp.schema import AgentPlanContentUpdate, AgentPlanRemovedUpdate
|
|
115
|
+
|
|
116
|
+
async def session_update(self, session_id, update, **kwargs):
|
|
117
|
+
if isinstance(update, AgentPlanContentUpdate):
|
|
118
|
+
...
|
|
119
|
+
elif isinstance(update, AgentPlanRemovedUpdate):
|
|
120
|
+
...
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The existing full-plan `AgentPlanUpdate` variant remains available.
|
|
124
|
+
|
|
125
|
+
## 6. Review MCP server configuration types
|
|
126
|
+
|
|
127
|
+
Session creation, loading, forking, and resuming now accept `AcpMcpServer` in addition to HTTP, SSE, and stdio MCP server definitions:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from acp.schema import AcpMcpServer, HttpMcpServer, McpServerStdio, SseMcpServer
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If you validate `mcp_servers` with your own union, add `AcpMcpServer` to keep accepting all SDK-supported server types.
|
|
134
|
+
|
|
135
|
+
## 7. Re-run examples and checks
|
|
136
|
+
|
|
137
|
+
After changing signatures, run the standard gates:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
make check
|
|
141
|
+
make test
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Also run any example or integration that subclasses `Agent` or `Client`. Positional argument bugs usually surface there first; using keyword arguments for connection calls avoids most of them.
|