feat(chat): Part B(1) backend — session/prompt pipe over the live /acp socket - #48
Merged
Conversation
…p socket
First implementation slice of ADR agent-chat-panel (Part C). Adds the
bidirectional chat pipe on the existing reverse-MCP session; no UI yet
(Part C) and no cross-reconnect session/resume yet (Part B2).
acp-tunnel:
- Session::prompt(text) — builds session/prompt {sessionId, prompt:[text]}
- Session::cancel() — the one-way session/cancel notification
- Inbound::AgentChunk classified from session/update/agent_message_chunk
(other update kinds — thoughts, tool_call — openab doesn't emit yet)
- unit tests for all three (23 pass)
remote.rs:
- RemoteState grows an mpsc write-handle (prompt_tx), published only once
the session is active, retracted by run_reconnecting/disconnect
- run_once's read loop becomes a tokio::select! over inbound frames AND
outbound OutMsg (Prompt/Cancel); write never leaves the task
- prompt results are id-correlated (pending_prompt), not phase-driven —
a method-less frame in SessionActive ends the turn only if its id
matches the in-flight prompt; emits agent-update {kind:"turn_end"}
- agent_message_chunk → emit agent-update {kind:"chunk", text}
lib.rs:
- agent_prompt / agent_cancel commands (delegate to Remote), registered
Verified: acp-tunnel unit tests. studio-desktop compilation left to CI
(separate GUI workspace). Follow-ups: B2 session/resume + persistence,
then Part C the panel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…relay, clearer errors (review #1–4) Addresses the four findings from the Part B(1) backend review: 1〔med〕 In-flight guard for `session/prompt`. A second prompt while a turn was pending unconditionally overwrote `pending_prompt`, orphaning the first turn's result id so its `turn_end` never fired and the panel spinner hung. The single-shot loop now rejects (and logs) a prompt while one is in flight instead of clobbering the pending id. Part C's turn management still gates this, but the backend no longer depends on the UI for correctness. 2〔low〕 Non-blocking sidecar relay. `handle_inner` (`tools/list`/`tools/call`) awaited inline in the select! read arm, stalling queued prompts/cancels and chat chunks behind a slow round-trip. The relay now runs in a spawned task and returns its reply through a new `reply_tx` channel drained by the loop's single writer — responsiveness restored, wire frames still serialized. Each reply carries its own id, so out-of-order completion is fine for MCP. 3〔low〕 Clearer error when the outbound channel's receiver is gone. A send into a torn-down connection reported a bare "connection closed"; it now matches the not-connected message so the teardown window reads correctly. 4〔info〕 out_rx/reply_rx arms use Some(..) patterns, disabling the arm on a closed channel so a None can never busy-spin the loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First implementation slice of ADR
agent-chat-panel(#47). Adds the bidirectional chat pipe on the existing reverse-MCP session. No UI yet (Part C) and no cross-reconnectsession/resumeyet (Part B2).Changes
crates/acp-tunnel(unit-tested, 23 pass locally):Session::prompt(text)→session/prompt {sessionId, prompt:[{type:text,text}]}Session::cancel()→ the one-waysession/cancelnotificationInbound::AgentChunkclassified fromsession/update/agent_message_chunk; other update kinds (thoughts,tool_call) stayOther— openab doesn't emit them yet (per Jellyfish's live eval)src-tauri/src/remote.rs:RemoteStategrows anmpscwrite-handle (prompt_tx), published only once the session is active, retracted byrun_reconnecting/disconnect— so the UI can never prompt a half-open sessionrun_once's read loop becomes atokio::select!over inbound frames and outboundOutMsg(Prompt/Cancel); the WSwritesink never leaves the taskSessionActiveends the turn only if its id matches the in-flight prompt (pending_prompt), never by phase — emitsagent-update {kind:"turn_end", stopReason}agent_message_chunk→agent-update {kind:"chunk", text}(the drop site is now the chat hook)src-tauri/src/lib.rs:agent_prompt/agent_cancelcommands, registered ininvoke_handler!Scope / what's next
session/resume+ persistence store (needs the Session to live across reconnects; the acp-tunnelresume()builder +{sessionId,cwd,mcpServers}re-declaration are already in place and Jellyfish-verified).Verification
cargo test -p acp-tunnel— 23 pass (incl.prompt_needs_a_session_then_builds_a_text_turn,cancel_is_an_idless_notification…,agent_message_chunk_is_classified…).studio-desktopcompilation left to CI (desktop.yml) — separate GUI workspace, not built on the ECS host (OOM).Reference:
brettchien/katashiro.🤖 Generated with Claude Code