Remove completed sections (shadcn migration, ACP panel integration, all related out-of-scope items that landed in v1). Add the new task 'AcpPanel tool-call block UI (session/update tool_call type)' as the next phase: forward tool_call events through the stream, store them in history, render them as collapsible blocks above the agent's text bubble.
5.6 KiB
Plan
Roadmap for the next phases of the codespace web IDE.
Next: AcpPanel tool-call block UI
When the agent invokes a tool (e.g. reads a file, runs a command, edits a buffer) it emits a session/update notification with sessionUpdate: "tool_call". Currently the client silently drops these in handleNotification (debug log only), so the user has no visibility into what the agent is doing while the reply streams in. Render them as discrete blocks under the agent bubble so the user can see "the agent read foo.go, ran git status, is now editing bar.go…".
Why
Without tool-call visibility, the streamed agent reply is just text. The user has to guess what the agent is doing. Real coding agents (Claude Code, Cursor, Zed) show tool invocations inline so the user can:
- See which files the agent touched.
- Catch mistakes early (agent edited the wrong file).
- Trust the agent's progress during long-running work.
Scope
-
Backend: forward tool_call events through the stream
- In
internal/acp/handleNotification, whensessionUpdate == "tool_call", emit aStreamEventto all active stream consumers:case StreamEvent{Type: "tool_call", ToolCallID: ..., Kind: ..., Title: ..., Status: ..., Content: ...} - Also append a stable representation of the tool call to history so the next
GET /acp/historyreturns it (so reloading the panel shows past tool calls). TheMessagemodel gains an optionalKind: stringandToolCallID: stringfield;Rolestays as "agent" for v1 (or add a new role "tool" — TBD). - The
Updatestruct ininternal/acp/messages.goalready carriesToolCallID string. Capture the fullup.Updatepayload for the history entry.
- In
-
Frontend: ToolCallBlock component
- New
web/src/components/acp/ToolCallBlock.tsx. - Props:
{ kind, title, status, content? }where:kindis the tool name (e.g. "read", "edit", "bash", "fetch", "grep").titleis a short human-readable summary (the agent's intent).statusis one of "pending" | "running" | "completed" | "failed" (the ACPtool_callupdate lifecycle — pending → running → completed/failed). Map to icons:Loader2(spinning) for running,Circlefor pending,CheckCircle2for completed,XCirclefor failed.contentis optional: forkind: readthe file path or first lines; forkind: editthe diff; forkind: bashthe command. Rendered as a small monospace block (collapsed by default, expand on click).
- Visual: small card, ~border + ~bg-muted, ~rounded-md, ~text-xs. Distinct from message bubbles so it's clear the agent did something, not said something.
- When
contentis large (e.g. a long file), truncate to a preview and show "show more".
- New
-
Frontend: integrate into AcpPanel
- Streaming events with
type: "tool_call"append a ToolCallBlock to a per-prompt list. - The list is shown ABOVE the in-flight agent bubble (so tool calls appear first, then the agent's reply references them). On
complete, the list is "committed" alongside the agent message. - History endpoint returns tool calls; the AcpPanel render path coalesces: history messages + a per-message array of
ToolCallitems that appeared during that turn. - When clicking a ToolCallBlock with a file path, optionally open the file in the editor (nice-to-have, defer to v2 if time-pressed).
- Streaming events with
-
Data model
- Extend
AcpMessage/internal/acp/history.goMessage:type Message struct { Role string // "user" | "agent" Text string Time time.Time MessageID string ToolCalls []ToolCall // NEW: tool calls that occurred during this agent turn } type ToolCall struct { ToolCallID string Kind string Title string Status string Content string } - The
session/updatewithsessionUpdate: "tool_call"updates the tool call's status (pending → running → completed/failed). Correlate bytoolCallId.
- Extend
-
Tests
internal/acp/client_test.go: extendTestClientStreamEmitsChunkAndComplete(or add a new test) that drives a fake tool_call sequence (pending → running → completed) and asserts the history contains the merged tool calls.internal/acp/history_test.go(new) orclient_test.go: verifyAppendOrCreateon tool calls works (or add a separateHistory.SetToolCalls(role, messageId, calls)method).- Frontend: no new test infra; rely on visual verification in the dev server.
Out of scope (deferred to v2)
- Tool-call approval UI (the agent runs everything; no interrupt-and-confirm dialog).
- Re-running a tool call.
- Diff visualization for
editcalls (just show the raw content for v1). - Streaming partial tool-call content.
- Multiple agents / agent switching.
- Cross-workspace agent memory.
- Authentication.
- ACP session persistence across opencode restarts.
Open questions to resolve before implementation
- Should the in-memory history distinguish "agent text" from "tool calls" by message type, or are tool calls an array on the agent message? — Default: array on the agent message (one agent turn can have many tool calls).
- What's the shape of the
contentfield for non-trivial tool calls? — Forread, the file content; foredit, a diff; forbash, the output. Inspect a realsession/updatepayload before settling the field name (contentvsoutputvsresult). - Status transitions: does the agent send multiple
tool_callupdates with the sametoolCallId(pending → running → completed), or just one final update? — Likely multiple; need to verify against a real opencode acp session.