This repository has been archived on 2026-07-17. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tao.chen 79292c9f38 docs: update plan.md
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.
2026-07-06 17:19:28 +08:00

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

  1. Backend: forward tool_call events through the stream

    • In internal/acp/handleNotification, when sessionUpdate == "tool_call", emit a StreamEvent to 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/history returns it (so reloading the panel shows past tool calls). The Message model gains an optional Kind: string and ToolCallID: string field; Role stays as "agent" for v1 (or add a new role "tool" — TBD).
    • The Update struct in internal/acp/messages.go already carries ToolCallID string. Capture the full up.Update payload for the history entry.
  2. Frontend: ToolCallBlock component

    • New web/src/components/acp/ToolCallBlock.tsx.
    • Props: { kind, title, status, content? } where:
      • kind is the tool name (e.g. "read", "edit", "bash", "fetch", "grep").
      • title is a short human-readable summary (the agent's intent).
      • status is one of "pending" | "running" | "completed" | "failed" (the ACP tool_call update lifecycle — pending → running → completed/failed). Map to icons: Loader2 (spinning) for running, Circle for pending, CheckCircle2 for completed, XCircle for failed.
      • content is optional: for kind: read the file path or first lines; for kind: edit the diff; for kind: bash the 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 content is large (e.g. a long file), truncate to a preview and show "show more".
  3. 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 ToolCall items 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).
  4. Data model

    • Extend AcpMessage / internal/acp/history.go Message:
      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/update with sessionUpdate: "tool_call" updates the tool call's status (pending → running → completed/failed). Correlate by toolCallId.
  5. Tests

    • internal/acp/client_test.go: extend TestClientStreamEmitsChunkAndComplete (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) or client_test.go: verify AppendOrCreate on tool calls works (or add a separate History.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 edit calls (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 content field for non-trivial tool calls? — For read, the file content; for edit, a diff; for bash, the output. Inspect a real session/update payload before settling the field name (content vs output vs result).
  • Status transitions: does the agent send multiple tool_call updates with the same toolCallId (pending → running → completed), or just one final update? — Likely multiple; need to verify against a real opencode acp session.