docs(spec): add Claude ACP raw SDK message support design
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
# Claude ACP Raw SDK Message Support Design
|
||||
|
||||
- Date: 2026-04-14
|
||||
- Status: Approved (implementation pending)
|
||||
- Scope: Protocol support only (backend receives and forwards, frontend event layer receives)
|
||||
|
||||
## 1. Background
|
||||
|
||||
Upstream PR `agentclientprotocol/claude-agent-acp#527` was merged on **2026-04-13**.
|
||||
It introduces opt-in emission of Claude Code SDK raw stream messages via ACP extension notification:
|
||||
|
||||
- Method: `"_claude/sdkMessage"`
|
||||
- Params shape:
|
||||
- `sessionId: string`
|
||||
- `message: object` (raw SDK message)
|
||||
|
||||
Opt-in is configured via session `_meta`:
|
||||
|
||||
```json
|
||||
{
|
||||
"claudeCode": {
|
||||
"emitRawSDKMessages": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
User decision for this project:
|
||||
|
||||
- Keep npm/registry at current version (`0.27.0`)
|
||||
- Implement **protocol support only**
|
||||
- Enable raw SDK messages for Claude by default with `true`
|
||||
|
||||
## 2. Goals and Non-Goals
|
||||
|
||||
### Goals
|
||||
|
||||
1. For `AgentType::ClaudeCode`, send `_meta.claudeCode.emitRawSDKMessages = true` in session setup.
|
||||
2. Receive `"_claude/sdkMessage"` notifications in backend connection loop.
|
||||
3. Convert and forward notifications to frontend via existing `acp://event` event bridge.
|
||||
4. Extend frontend `AcpEvent` typing to accept this event without changing UI behavior.
|
||||
|
||||
### Non-Goals
|
||||
|
||||
1. No UI visualization for raw SDK messages in this change.
|
||||
2. No DB persistence for raw SDK messages.
|
||||
3. No behavior changes for non-Claude agents.
|
||||
4. No protocol generalization for all extension notifications in this iteration.
|
||||
|
||||
## 3. Selected Approach
|
||||
|
||||
Selected approach: **Claude-specific minimal integration**.
|
||||
|
||||
Why:
|
||||
|
||||
- Minimal risk and smallest change surface.
|
||||
- Matches explicit scope: protocol plumbing only.
|
||||
- Preserves current runtime and rendering behavior.
|
||||
|
||||
Rejected for now:
|
||||
|
||||
- Global extension-notification bus (larger scope, more noise, higher maintenance).
|
||||
- Persistence/debug history (extra storage and lifecycle complexity).
|
||||
|
||||
## 4. Architecture Changes
|
||||
|
||||
## 4.1 Backend session meta injection
|
||||
|
||||
File: `src-tauri/src/acp/connection.rs`
|
||||
|
||||
When constructing `NewSessionRequest` and `LoadSessionRequest`:
|
||||
|
||||
- If `agent_type == AgentType::ClaudeCode`, set request `meta` with:
|
||||
- `claudeCode.emitRawSDKMessages = true`
|
||||
|
||||
This preserves opt-in semantics upstream while default-enabling for Claude in Codeg.
|
||||
|
||||
## 4.2 Backend extension notification handling
|
||||
|
||||
File: `src-tauri/src/acp/connection.rs`
|
||||
|
||||
Current code mainly consumes typed `SessionNotification` updates. This change adds a path for untyped notifications:
|
||||
|
||||
- Match dispatch notification method.
|
||||
- If method is `"_claude/sdkMessage"`, parse params:
|
||||
- `sessionId`
|
||||
- `message`
|
||||
- Emit new app event through `acp://event`.
|
||||
- Ignore parse failures and continue session loop.
|
||||
|
||||
## 4.3 Backend event model extension
|
||||
|
||||
File: `src-tauri/src/acp/types.rs`
|
||||
|
||||
Add a new `AcpEvent` variant:
|
||||
|
||||
- `ClaudeSdkMessage`
|
||||
- `connection_id: String`
|
||||
- `session_id: String`
|
||||
- `message: serde_json::Value`
|
||||
|
||||
This keeps payload raw and unopinionated.
|
||||
|
||||
## 4.4 Frontend type and event switch support
|
||||
|
||||
Files:
|
||||
|
||||
- `src/lib/types.ts`
|
||||
- `src/contexts/acp-connections-context.tsx`
|
||||
|
||||
Changes:
|
||||
|
||||
- Extend TS `AcpEvent` union with:
|
||||
- `type: "claude_sdk_message"`
|
||||
- `connection_id: string`
|
||||
- `session_id: string`
|
||||
- `message: unknown`
|
||||
- Add a no-op `case "claude_sdk_message"` in event handling.
|
||||
|
||||
No UI state mutation is required in this iteration.
|
||||
|
||||
## 5. Data Flow
|
||||
|
||||
1. Codeg starts Claude ACP session.
|
||||
2. Codeg sends `session/new` or `session/load` with `_meta.claudeCode.emitRawSDKMessages=true`.
|
||||
3. `claude-agent-acp` emits extension notifications `"_claude/sdkMessage"`.
|
||||
4. Codeg backend parses and maps to `AcpEvent::claude_sdk_message`.
|
||||
5. Event is pushed via existing `acp://event` channel.
|
||||
6. Frontend receives typed event and safely ignores it (for now).
|
||||
|
||||
## 6. Error Handling and Compatibility
|
||||
|
||||
1. If upstream ignores meta, session still works; feature simply produces no raw SDK events.
|
||||
2. If `"_claude/sdkMessage"` payload is malformed, log and ignore that notification.
|
||||
3. Do not fail prompt/session loops due to extension-message parse errors.
|
||||
4. Keep all existing typed `SessionUpdate` flows unchanged.
|
||||
5. Restrict meta injection to Claude only.
|
||||
|
||||
## 7. Validation Plan
|
||||
|
||||
Manual/protocol validation:
|
||||
|
||||
1. Confirm session setup request includes `_meta.claudeCode.emitRawSDKMessages=true` for Claude.
|
||||
2. Confirm `"_claude/sdkMessage"` notifications are received and forwarded as `claude_sdk_message` events.
|
||||
3. Confirm malformed ext payloads do not break turns.
|
||||
4. Confirm non-Claude agents have unchanged behavior.
|
||||
|
||||
Project checks:
|
||||
|
||||
1. `pnpm eslint .`
|
||||
2. `pnpm build`
|
||||
3. `cd src-tauri && cargo check`
|
||||
4. `cd src-tauri && cargo check --bin codeg-server --no-default-features`
|
||||
|
||||
## 8. Acceptance Criteria
|
||||
|
||||
1. Claude connections default-enable raw SDK emission via session meta.
|
||||
2. Backend forwards raw SDK notifications into frontend event layer.
|
||||
3. Frontend compiles and receives new event type without UI regressions.
|
||||
4. No persistence and no visual rendering changes.
|
||||
5. No regressions on existing ACP message paths.
|
||||
Reference in New Issue
Block a user