Skip to content

fix(tui): native tool calls not visible — TuiChannel missing send_tool_start implementation #1931

@bug-ops

Description

@bug-ops

Problem

When native tools (MCP tools, bash, web_scrape, etc.) are invoked, the TUI shows no indication:

  • no tool name appears in the chat
  • no spinner or status during execution
  • output only appears if it contains a diff (via send_tool_output)
  • plain text tool results are silently dropped from view

Root Cause

TuiChannel in crates/zeph-tui/src/channel.rs does not implement send_tool_start().

The Channel trait provides a default no-op implementation:

// crates/zeph-core/src/channel.rs:197
fn send_tool_start(&mut self, _event: ToolStartEvent<'_>) -> impl Future<...> {
    async { Ok(()) }  // ← default no-op
}

TuiChannel never overrides this, so every ToolStart event is silently discarded.

Meanwhile, app.rs already handles AgentEvent::ToolStart correctly (lines 505–513):

AgentEvent::ToolStart { tool_name, command } => {
    self.status_label = None;
    self.messages.push(
        ChatMessage::new(MessageRole::Tool, format!("$ {command}\n"))
            .streaming()
            .with_tool(tool_name),
    );
    self.auto_scroll();
}

The event type and TUI handler exist — only the channel bridge is missing.

Additionally, handle_tool_output_event() in app.rs:597 has a comment acknowledging the gap:

// Native tool_use path: no prior ToolStart, create the message now.

This workaround only handles cases where output contains a diff. Plain text native tool output is still invisible.

Fix

Add send_tool_start() to TuiChannel:

async fn send_tool_start(&mut self, event: ToolStartEvent<'_>) -> Result<(), ChannelError> {
    self.agent_event_tx
        .send(AgentEvent::ToolStart {
            tool_name: event.tool_name.to_owned(),
            command: event.command.unwrap_or(event.tool_name).to_owned(),
        })
        .await
        .map_err(|_| ChannelError::ChannelClosed)
}

Also update handle_tool_output_event() in app.rs to remove the native-path workaround comment and handle the case where ToolStart was already sent (streaming message exists).

Affected files

  • crates/zeph-tui/src/channel.rs — add send_tool_start() implementation
  • crates/zeph-tui/src/app.rs — clean up native path workaround in handle_tool_output_event()

Impact

  • Native tool calls (MCP, bash, read, web_scrape) are completely invisible during execution
  • User has no feedback that a tool is running or what it is doing
  • Violates TUI rule: "any background operation must show a visible status indicator"

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions