feat(acp): per-chat ACP runtime — hot-swap a coding agent from the model picker (ADR 0082 S2+S3)#1995
feat(acp): per-chat ACP runtime — hot-swap a coding agent from the model picker (ADR 0082 S2+S3)#1995mabry1985 wants to merge 4 commits into
Conversation
… chat (ADR 0082 S2) The native-vs-ACP fork now consults the per-tab model: a `model=acp:<agent>` on the turn (A2A metadata / `/v1` / `/api/chat`) routes THIS turn to the real AcpRuntime for that agent, overriding the global agent_runtime — even when the global runtime is native (D1). - runtime/acp_runtime.py: resolve_turn_runtime(model, config) — acp:<agent> per-tab wins, else falls back to the global resolve_runtime. AcpRuntime takes an explicit agent= so it can run on a thread whose global runtime is native/a different agent (D2). - server/chat.py: the ACP session registry is keyed by (thread, agent) — a mid-chat swap builds a fresh session while the previous agent's survives for a resumable swap-back; both dispatch sites (streaming + non-streaming) + _acp_turn_collected thread the agent through. - graph/middleware/model_override.py: guard so an acp:* value can NEVER build create_llm's text-only aux relay as the lead model (D3 / Trap A); acp:* stays valid for the explicit aux slots via create_llm directly. Backend only — the console picker that offers acp:<agent> per-tab is S3. Reachable now via API (model=acp:<agent>). +new tests (resolver, explicit-agent guard, (thread,agent) keying & swap-back, the middleware guard, per-tab-over-native routing); full suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…note (ADR 0082 S3)
The composer model dropdown now lists ACP coding agents (from /api/acp-agents) alongside
gateway models, so an operator can hot-swap a coding agent into a single chat. The per-tab
selection rides the existing `session.model` string (`acp:<id>`) verbatim — chat-store/api
already carry it — and the S2 backend routes the turn accordingly.
- ComposerModelSelect: stops replacing the menu with a static label under a global ACP
runtime; shows the effective agent + a "coding agent" badge; offers gateway models only
under a native global runtime (a gateway pick is inert under global ACP per the routing).
- Option-C boundary note (D4): on a runtime crossing (native↔acp, acp:A↔acp:B — never
gateway↔gateway) it drops a system note via noteToThread ("earlier context isn't carried
across runtimes"), so the fresh-session boundary is explicit rather than silent.
Frontend gates green locally: tsc (both configs), vitest (548), vite build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…82 S3) The composer trigger's accessible name is the e2e locator (getByRole button 'Model for this chat', model-command + quick-settings specs). The picker now also lists coding agents, but the label stays 'Model for this chat' so those specs keep matching. Verified: both specs green locally.
The Option-C boundary note ("Earlier context isn't carried across
runtimes…") should only fire when there's actually prior context to
lose. On a fresh chat with no turns yet, switching runtimes is silent.
System notes (including an earlier boundary note) don't count as
context, so the gate looks only for user/assistant turns — double-
switching an empty chat stays quiet too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Triage: keep held. S2/S3 genuinely aren't on main ( |
Draft — for local testing before merge (as requested). This is a runtime behavior change CI can't fully exercise (it needs a real ACP agent driving a chat), so it's held for extensive local testing.
Implements the routing + picker for ADR 0082 (Accepted, #1994). Builds on the agent-registration surface #1993 (S1, merged).
What it does
Pick an ACP coding agent (Claude Code / Codex / proto / …) from a chat tab's model dropdown and that chat runs on it — hot-swapping the runtime the way a gateway model already hot-swaps, per tab.
S2 — routing (backend)
runtime/acp_runtime.py:resolve_turn_runtime(model, config)— a per-tabmodel=acp:<agent>selects the ACP runtime FOR THIS TURN, overriding the globalagent_runtime(even when it's native); anything else falls back to the global.AcpRuntime(agent=…)can now run on a thread whose global runtime is native/a different agent.server/chat.py: the ACP session registry is keyed by(thread, agent)— a mid-chat swap builds a fresh session while the previous agent's survives for a resumable swap-back. Both dispatch sites (streaming + non-streaming) +_acp_turn_collectedthread the agent through.graph/middleware/model_override.py: guard so anacp:*value can never buildcreate_llm's text-only aux relay as the lead model (Trap A).acp:*stays valid for the explicit aux slots.S3 — picker + boundary (console)
ComposerModelSelect.tsx: lists ACP agents alongside gateway models; shows the effective agent + a "coding agent" badge; stops replacing the menu with a static label under a global ACP runtime. Under a global ACP runtime it offers coding agents only (a gateway pick would be inert per the routing).chat-store/apineeded no change —session.modelalready carries an arbitrary string end to end.noteToThread("earlier context isn't carried across runtimes"). Native history (checkpointer) and ACP history (the agent's own stateful session) don't sync, so this is the honest boundary rather than faked continuity.Tests / gates (local)
ruff✓,lint-imports(3 kept) ✓, fullpytest tests/— 3695 passed, 5 skipped. New tests: the resolver, explicit-agent guard,(thread,agent)keying + swap-back-resume, the middleware guard, per-tab-over-native routing.tsc(both configs) ✓,vitest— 548 passed ✓,vite build✓.Please test locally (needs a real ACP agent CLI installed + authed)
/v1, desktop/api/chat) withmodel=acp:<agent>routes to ACP.Out of scope (per ADR 0082)
Cross-runtime history bridging (Option B);
/effort//compact/HITL/skill parity under ACP; a UI to author a customacp.agents.<id>(registration stays config/YAML).🤖 Generated with Claude Code