Skip to content

Commit 2c88188

Browse files
committed
feat(cli): live tool output streaming
Render ToolOutputDelta live — the tail of a running tool's stdout is shown dimmed under the action (like watching a command run in Codex), then cleared when the tool completes.
1 parent 6b991da commit 2c88188

1 file changed

Lines changed: 16 additions & 0 deletions

File tree

cli/src/main.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ struct App {
115115
/// Accumulated streamed JSON args of the in-progress tool call, so the
116116
/// result line can show what the tool actually did (command/path/pattern).
117117
tool_args: String,
118+
/// Live stdout of the in-progress tool (e.g. a running command), shown
119+
/// dimmed under the action and cleared when the tool completes.
120+
tool_output: String,
118121
/// When true, tool-confirmation prompts are auto-approved (Codex-style
119122
/// approval mode), toggled with `/auto`.
120123
auto_approve: bool,
@@ -396,11 +399,16 @@ impl App {
396399
AgentEvent::ToolStart { name, .. } => {
397400
self.finalize_streaming();
398401
self.tool_args.clear();
402+
self.tool_output.clear();
399403
self.push_line(&Style::new().fg(Color::Cyan).render(&format!(" ⚙ {name}")));
400404
}
401405
AgentEvent::ToolInputDelta { delta } => {
402406
self.tool_args.push_str(&delta);
403407
}
408+
AgentEvent::ToolOutputDelta { delta, .. } => {
409+
self.tool_output.push_str(&delta);
410+
self.update_viewport_with_stream();
411+
}
404412
AgentEvent::ToolEnd {
405413
name,
406414
output,
@@ -418,6 +426,7 @@ impl App {
418426
self.width as usize,
419427
));
420428
self.tool_args.clear();
429+
self.tool_output.clear();
421430
}
422431
AgentEvent::SubagentStart {
423432
agent, description, ..
@@ -562,6 +571,12 @@ impl App {
562571
if !rendered.is_empty() {
563572
blocks.push(rendered);
564573
}
574+
// Live stdout of the running tool — show the tail like a terminal.
575+
if !self.tool_output.trim().is_empty() {
576+
let tail: Vec<&str> = self.tool_output.lines().rev().take(12).collect();
577+
let tail = tail.into_iter().rev().collect::<Vec<_>>().join("\n");
578+
blocks.push(Style::new().fg(Color::BrightBlack).render(&tail));
579+
}
565580
self.viewport.set_content(&blocks.join("\n\n"));
566581
}
567582

@@ -892,6 +907,7 @@ async fn main() -> anyhow::Result<()> {
892907
model: None,
893908
total_tokens: 0,
894909
tool_args: String::new(),
910+
tool_output: String::new(),
895911
auto_approve: false,
896912
cwd: workspace,
897913
width,

0 commit comments

Comments
 (0)