Skip to content

fix(acp): emit tool output content in ToolCallUpdate for all execution paths#1006

Merged
bug-ops merged 1 commit intomainfrom
worktree-fix/acp-tool-output-1003
Feb 27, 2026
Merged

fix(acp): emit tool output content in ToolCallUpdate for all execution paths#1006
bug-ops merged 1 commit intomainfrom
worktree-fix/acp-tool-output-1003

Conversation

@bug-ops
Copy link
Owner

@bug-ops bug-ops commented Feb 27, 2026

Fixes #1003

Problem

When using Zeph as an ACP agent in Zed, tool call blocks showed no result content. Other ACP agents (e.g. Claude Agent) correctly display tool output inside the tool block.

Root Cause

Two bugs in crates/zeph-core/src/agent/tool_execution.rs:

Bug 1 — streaming tools skipped send_tool_output

if !already_streamed {
    self.channel.send_tool_output(...).await?;
}

When already_streamed = true (bash, shell tools), LoopbackEvent::ToolOutput was never emitted. The ACP layer (loopback_event_to_updates) needs this event to produce ToolCallUpdate with content — without it the tool block in Zed stayed empty.

Bug 2 — fenced-block path passed empty tool_call_id

self.channel.send_tool_output(&name, &display, None, None, None, "", false).await?;

Empty ID with no preceding ToolStart produced orphaned ToolCallUpdate events the ACP client could not match to any tool block.

Fix

  • Bug 1: Remove if !already_streamed guard — send_tool_output is now called unconditionally. TUI deduplication is handled by the TUI channel's own event forwarder.
  • Bug 2: Generate UUID tool_call_id before execution, emit send_tool_start with it, pass the same ID to send_tool_output. Applied to both the Ok(Some) and ConfirmationRequired sub-paths.

Tests

  • handle_tool_result_sends_output_when_streamed_true — regression test for Bug 1
  • handle_tool_result_fenced_emits_tool_start_then_output_via_loopback — verifies ToolStart precedes ToolOutput with matching non-empty UUID

Checklist

  • cargo +nightly fmt --check clean
  • cargo clippy --workspace -- -D warnings clean
  • cargo nextest run --workspace --lib --bins 2944/2944 passed
  • CHANGELOG.md updated
  • README files updated (zeph-core, zeph-acp)
  • Docs updated (advanced/acp.md, advanced/tools.md, advanced/channels.md)

…n paths (#1003)

Two bugs prevented tool results from appearing in ACP tool call blocks in Zed:

- Remove `if !already_streamed` guard in native tool-call path so
  `LoopbackEvent::ToolOutput` is emitted unconditionally; TUI dedup
  is handled by the TUI channel's own event forwarder, not here.

- Generate stable UUID `tool_call_id` in fenced-block execution paths,
  emit `ToolStart` before `send_tool_output`, and pass the same ID to
  both calls — eliminating orphaned `ToolCallUpdate` events with empty ID.

Add regression tests:
- `handle_tool_result_sends_output_when_streamed_true`: verifies
  `send_tool_output` is called when `already_streamed = true` (GAP-1)
- `handle_tool_result_fenced_emits_tool_start_then_output_via_loopback`:
  verifies ToolStart precedes ToolOutput with matching non-empty UUID (GAP-2)

Closes #1003
@github-actions github-actions bot added bug Something isn't working documentation Improvements or additions to documentation rust core size/L and removed bug Something isn't working labels Feb 27, 2026
@bug-ops bug-ops enabled auto-merge (squash) February 27, 2026 01:28
@bug-ops bug-ops disabled auto-merge February 27, 2026 01:36
@bug-ops bug-ops enabled auto-merge (squash) February 27, 2026 01:40
@bug-ops bug-ops merged commit 817f7cc into main Feb 27, 2026
28 checks passed
@bug-ops bug-ops deleted the worktree-fix/acp-tool-output-1003 branch February 27, 2026 01:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core documentation Improvements or additions to documentation rust size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

acp: emit tool output content in ToolCallUpdate for all execution paths

1 participant