From a64ced0ccc9487d6e009a054e42c49aece512730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Sun, 12 Jul 2026 22:09:48 +0200 Subject: [PATCH] fix(agent): stream assistant text only in the REPL Streaming defaulted on for every mode, so one-shot `--task` and script runs interleaved intermediate assistant commentary into stdout, which wrappers treat as the answer. Gate the stream hook on `Terminal.isRepl` so non-interactive modes keep the buffered final answer. --- src/agent/Agent.zig | 6 ++++-- src/agent/Terminal.zig | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/agent/Agent.zig b/src/agent/Agent.zig index 36401ed43..141253599 100644 --- a/src/agent/Agent.zig +++ b/src/agent/Agent.zig @@ -604,9 +604,11 @@ fn endStreamedText(self: *Agent) void { } /// The text-delta hook, or null when `/stream off` — a null hook makes -/// `runTools` fall back to a buffered response. +/// `runTools` fall back to a buffered response. Streaming is an interactive +/// REPL affordance; one-shot (`--task`) and script modes keep stdout to the +/// buffered final answer so wrappers can parse it cleanly. fn streamHook(self: *Agent) ?zenai.provider.Client.TextDeltaHook { - if (!self.stream_enabled) return null; + if (!self.stream_enabled or !self.terminal.isRepl()) return null; return .{ .context = @ptrCast(self), .onText = streamAssistantDelta }; } diff --git a/src/agent/Terminal.zig b/src/agent/Terminal.zig index e5c013e62..298b9a659 100644 --- a/src/agent/Terminal.zig +++ b/src/agent/Terminal.zig @@ -186,7 +186,7 @@ pub fn init(allocator: std.mem.Allocator, history_paths: ?HistoryPaths, verbosit }; } -fn isRepl(self: *const Terminal) bool { +pub fn isRepl(self: *const Terminal) bool { return self.repl_arena != null; }