Skip to content

Commit aef09fe

Browse files
committed
doc: add a migration guide
Signed-off-by: Frost Ming <me@frostming.com>
1 parent 2a05aa1 commit aef09fe

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

docs/migration-guide-0.7.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Migrating to ACP Python SDK 0.7
2+
3+
ACP 0.7 reshapes the public surface so that Python-facing names, runtime helpers, and schema models line up with the evolving Agent Client Protocol schema. This guide covers the major changes in 0.7.0 and calls out the mechanical steps you need to apply in downstream agents, clients, and transports.
4+
5+
## 1. `acp.schema` models now expose `snake_case` fields
6+
7+
- Every generated model in `acp.schema` (see `src/acp/schema.py`) now uses Pythonic attribute names such as `session_id`, `stop_reason`, and `field_meta`. The JSON aliases (e.g., `alias="sessionId"`) stay intact so over-the-wire payloads remain camelCase.
8+
- Instantiating a model or accessing response values must now use the `snake_case` form:
9+
10+
```python
11+
# Before (0.6 and earlier)
12+
PromptResponse(stopReason="end_turn")
13+
params.sessionId
14+
15+
# After (0.7 and later)
16+
PromptResponse(stop_reason="end_turn")
17+
params.session_id
18+
```
19+
20+
- If you relied on `model_dump()` to emit camelCase keys automatically, switch to `model_dump(by_alias=True)` (or use helpers such as `text_block`, `start_tool_call`, etc.) so responses continue to match the protocol.
21+
- `field_meta` stays available for extension data. Any extra keys that were nested under `_meta` should now be provided via keyword arguments when constructing the schema models (see section 3).
22+
23+
## 2. `acp.run_agent` and `acp.connect_to_agent` replace manual connection wiring
24+
25+
`AgentSideConnection` and `ClientSideConnection` still exist internally, but the top-level entry points now prefer the helper functions implemented in `src/acp/core.py`.
26+
27+
### Updating agents
28+
29+
- Old pattern:
30+
31+
```python
32+
conn = AgentSideConnection(lambda conn: Agent(), writer, reader)
33+
await asyncio.Event().wait() # keep running
34+
```
35+
36+
- New pattern:
37+
38+
```python
39+
await run_agent(MyAgent(), input_stream=writer, output_stream=reader)
40+
```
41+
42+
- When your agent just runs over stdio, call `await run_agent(MyAgent())` and the helper will acquire asyncio streams via `stdio_streams()` for you.
43+
44+
### Updating clients and tests
45+
46+
- Old pattern:
47+
48+
```python
49+
conn = ClientSideConnection(lambda conn: MyClient(), proc.stdin, proc.stdout)
50+
```
51+
52+
- New pattern:
53+
54+
```python
55+
conn = connect_to_agent(MyClient(), proc.stdin, proc.stdout)
56+
```
57+
58+
- `spawn_agent_process` / `spawn_client_process` now accept concrete `Agent`/`Client` instances instead of factories that received the connection. Instantiate your implementation first and pass it in.
59+
- Importing the legacy connection classes via `acp.AgentSideConnection` / `acp.ClientSideConnection` issues a `DeprecationWarning` (see `src/acp/__init__.py:82-96`). Update your imports to `run_agent` and `connect_to_agent` to silence the warning.
60+
61+
## 3. `Agent` and `Client` interface methods take explicit parameters
62+
63+
Both interfaces in `src/acp/interfaces.py` now look like idiomatic Python protocols: methods use `snake_case` names and receive the individual schema fields rather than a single request model.
64+
65+
### What changed
66+
67+
- Method names follow `snake_case` (`request_permission`, `session_update`, `new_session`, `set_session_model`, etc.).
68+
- Parameters represent the schema fields, so there is no need to unpack `params` manually.
69+
- Each method is decorated with `@param_model(...)`. Combined with the `compatible_class` helper (see `src/acp/utils.py`), this keeps the camelCase wrappers alive for callers that still pass a full Pydantic request object—but those wrappers now emit `DeprecationWarning`s to encourage migration.
70+
71+
### How to update your implementations
72+
73+
1. Rename your method overrides to their `snake_case` equivalents.
74+
2. Replace `params: Model` arguments with the concrete fields plus `**kwargs` to collect future `_meta` keys.
75+
3. Access schema data directly via those parameters.
76+
77+
Example migration for an agent:
78+
79+
```python
80+
# Before
81+
class EchoAgent:
82+
async def prompt(self, params: PromptRequest) -> PromptResponse:
83+
text = params.prompt[0].text
84+
return PromptResponse(stopReason="end_turn")
85+
86+
# After
87+
class EchoAgent:
88+
async def prompt(self, prompt, session_id, **kwargs) -> PromptResponse:
89+
text = prompt[0].text
90+
return PromptResponse(stop_reason="end_turn")
91+
```
92+
93+
Similarly, a client method such as `requestPermission` becomes:
94+
95+
```python
96+
class RecordingClient(Client):
97+
async def request_permission(self, options, session_id, tool_call, **kwargs):
98+
...
99+
```
100+
101+
### Additional notes
102+
103+
- The connection layers automatically assemble the right request/response models using the `param_model` metadata, so callers do not need to build Pydantic objects manually anymore.
104+
- For extension points (`field_meta`), pass keyword arguments from the connection into your handler signature: they arrive inside `**kwargs`.
105+
106+
### Backward compatibility
107+
108+
- The change should be 100% backward compatible as long as you update your method names and signatures. The `compatible_class` wrapper ensures that existing callers passing full request models continue to work. The old style API will remain functional before the next major release(1.0).
109+
- Because camelCase wrappers remain for now, you can migrate file-by-file while still running against ACP 0.7. Just watch for the new deprecation warnings in your logs/tests.

0 commit comments

Comments
 (0)