Background
PR #1045 (streaming tool-call execution) establishes the streaming tool-call contract — tools yield IAsyncEnumerable<ToolCallUpdate> and are monitored by a per-call inactivity watchdog. Every existing tool inherits a single-completion-item default; only spawn_agent currently opts into real streaming.
This issue tracks Phase F of the OpenSpec change streaming-tool-call-execution: opting ShellTool and WebFetchTool into streaming.
Scope
ShellTool — override ExecuteStreamAsync to emit stdout/stderr as ToolActivityUpdate items while the process runs, terminated by a ToolCompletedUpdate with the assembled, clamped result. This replaces the current buffer-everything-then-truncate behavior and lets a long-running command keep its per-call watchdog satisfied while it produces output. Note: ShellTool also self-bounds via its own ShellTimeoutSeconds; making it genuinely long-running-friendly means reconciling that with the per-call watchdog.
WebFetchTool — optionally emit fetch-progress activity items.
Why deferred
ShellTool is delicate — process-pipe-deadlock handling, kill-on-timeout, pipe-close races — and self-bounds via its own timeout today, so streaming it is a careful standalone rework rather than a mechanical opt-in. It was deferred from #1045 to keep that PR's blast radius contained. The streaming contract is already in place, so this needs no new infrastructure.
Acceptance
ShellTool emits stdout/stderr as activity items; the LLM still receives one clamped terminal result.
WebFetchTool progress (optional).
- Tests cover the streaming path for each.
Follow-up to #1045.
Background
PR #1045 (streaming tool-call execution) establishes the streaming tool-call contract — tools yield
IAsyncEnumerable<ToolCallUpdate>and are monitored by a per-call inactivity watchdog. Every existing tool inherits a single-completion-item default; onlyspawn_agentcurrently opts into real streaming.This issue tracks Phase F of the OpenSpec change
streaming-tool-call-execution: optingShellToolandWebFetchToolinto streaming.Scope
ShellTool— overrideExecuteStreamAsyncto emit stdout/stderr asToolActivityUpdateitems while the process runs, terminated by aToolCompletedUpdatewith the assembled, clamped result. This replaces the current buffer-everything-then-truncate behavior and lets a long-running command keep its per-call watchdog satisfied while it produces output. Note:ShellToolalso self-bounds via its ownShellTimeoutSeconds; making it genuinely long-running-friendly means reconciling that with the per-call watchdog.WebFetchTool— optionally emit fetch-progress activity items.Why deferred
ShellToolis delicate — process-pipe-deadlock handling, kill-on-timeout, pipe-close races — and self-bounds via its own timeout today, so streaming it is a careful standalone rework rather than a mechanical opt-in. It was deferred from #1045 to keep that PR's blast radius contained. The streaming contract is already in place, so this needs no new infrastructure.Acceptance
ShellToolemits stdout/stderr as activity items; the LLM still receives one clamped terminal result.WebFetchToolprogress (optional).Follow-up to #1045.