Skip to content

ACP: Display agent terminal command output in ToolCallCard #355

Description

@julianromli

Problem or Opportunity

The ACP terminal capability lets an agent request that the client (Termul) run a command in a sandboxed subprocess. The Rust backend implements this fully and correctly — all five terminal RPCs (terminal/create, terminal/output, terminal/wait_for_terminal_exit, terminal/kill, terminal/release) are wired in src-tauri/src/acp/manager.rs:898-1022, with TerminalRegistry providing UTF-8-safe buffering, front-truncation, exit polling, and release_all on teardown (src-tauri/src/acp/terminal.rs).

However, the renderer only shows a static label for these tool calls and never displays the command output. In ToolCallCard.tsx:69-82:

if (item.type === 'terminal') {
  // The ACP `terminal` content variant only references a terminal by id; its
  // live output is fetched separately via `terminal/output` (not embedded in
  // the tool call), so we surface the reference rather than inline output.
  const terminalId = (item as { terminalId?: string }).terminalId
  return (
    <div ... >
      {terminalId ? `Terminal ${terminalId}` : 'Terminal'}
    </div>
  )
}

The comment claims output is "fetched separately via terminal/output", but there is no UI code that actually fetches and displays it. The terminal/* RPCs are agent→client requests serviced by the backend; the renderer has no IPC command to retrieve an ACP terminal's output — it only sees tool-call updates that reference a terminalId.

Result: when an agent exercises the terminal capability (e.g. runs npm test, git status, a build script), the command executes correctly on the backend, but the user has no way to see what the command printed. The tool-call card just says "Terminal term-3". This makes the highest-risk client capability (arbitrary command execution) effectively unauditable from the UI, which is a significant trust/usability problem for production use.

Proposed Solution

  1. Expose a read-only IPC surface for ACP terminal output. Add a Tauri command (e.g. acp_terminal_output(agent_id, terminal_id)) that returns the current buffered output + running flag + exit status from TerminalRegistry::output (src-tauri/src/acp/terminal.rs). Keep it read-only; the agent remains the sole writer.
  2. Render output in ToolCallCard. When a tool-call content item has type === 'terminal', fetch and render the output (collapsible by default, expandable on click). Poll or subscribe while the terminal is running; stop once it exits.
  3. Surface exit status. Show exit code / signal (SIGINT/SIGKILL/SIGTERM on Unix) alongside the output, reusing the existing TerminalExitStatus shape.
  4. Respect the buffer cap. If output was front-truncated (the truncated flag), show an indicator like "output truncated (first N bytes omitted)".

Success Criteria

  • When an agent invokes the terminal capability, the user can see the command's stdout/stderr in the ToolCallCard.
  • Output streams/polls while the command runs and settles once it exits.
  • Exit code / signal is visible.
  • Truncation is indicated when the buffer cap is hit.
  • No regression to the agent-side terminal lifecycle (create/output/wait/kill/release still honored).

Additional Context

  • Backend (complete, no change needed): src-tauri/src/acp/terminal.rs, src-tauri/src/acp/manager.rs:898-1022.
  • Frontend gap: src/renderer/components/chat/ToolCallCard.tsx:69-82.
  • The allow_terminal capability defaults to false on AgentConfig (src-tauri/src/acp/config.rs:87-92) and is advertised in client_capabilities (src-tauri/src/acp/client.rs:30-32) — that gating is correct and should stay.
  • Related: this is the renderer-side completion of the agent terminal capability (ADR-tagged M6 in client.rs:30-32).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions