Skip to content

agent: Progress callbacks per tool execution #672

Description

@iamnbutler

Context

Claude Code provides per-tool progress callbacks that allow real-time updates during tool execution:

From Claude Code (Tool.ts:338-340, services/tools/toolExecution.ts):

type ToolCallProgress<P> = (progress: ToolProgress<P>) => void

// Tool.call signature:
call(
  args: z.infer<Input>,
  context: ToolUseContext,
  canUseTool: CanUseToolFn,
  parentMessage: AssistantMessage,
  onProgress?: ToolCallProgress<P>  // Progress callback
): Promise<ToolResult<Output>>

Progress types vary by tool:

  • BashProgress: stdout chunks, stderr, running state
  • WebSearchProgress: search results as they arrive
  • AgentToolProgress: subagent output streaming

Current Behavior

Our StreamChunk enum handles response-level streaming but not tool-level progress:

pub enum StreamChunk {
    Text(String),
    Thinking(String),
    ToolUseStart { id: String, name: String },
    ToolUseInput(String),
    Complete(Response),
    Error(String),
}

Proposal

Tool execution with progress

pub type ToolProgressCallback = Box<dyn Fn(ToolProgress) + Send + Sync>;

pub struct ToolProgress {
    pub tool_use_id: String,
    pub progress_type: ProgressType,
    pub data: String,
}

pub enum ProgressType {
    Stdout,
    Stderr, 
    Output(String),  // Named output stream
}

// In session.rs or chain.rs
pub async fn execute_tool_with_progress(
    tool_call: &ToolCall,
    on_progress: Option<ToolProgressCallback>,
) -> ToolResult {
    // For Bash tool, stream stdout/stderr
    // For file tools, report progress on large files
    // For search tools, stream results
}

Integration with protocol

Progress updates can be forwarded via the protocol to the host:

// In supervisor
while let Some(progress) = tool_progress_rx.recv().await {
    send_event(Event::ToolProgress(ToolProgressEvent {
        tool_use_id: progress.tool_use_id,
        progress_type: progress.progress_type.into(),
        data: serde_json::to_value(&progress.data)?,
    })).await;
}

Use Cases

  1. Long-running commands: Stream cargo build output in real-time
  2. Large file reads: Show progress on multi-MB files
  3. Search operations: Stream grep/find results as found
  4. Subagent output: Forward nested agent progress

References

  • ../cc/Tool.ts:338-340 - ToolCallProgress type
  • ../cc/types/tools.ts - Progress data types
  • ../cc/services/tools/toolExecution.ts - Progress handling during execution

Priority: P2 - Medium Impact

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions