fix: defer streaming iteration linebreak to prevent blank line stacking
Follow-up to 669c60a6 (cherry-pick of PR #2187, fixes #2177).
The original fix emits a "\n\n" delta immediately after every
_execute_tool_calls() invocation. When the model runs multiple
consecutive tool iterations before producing text (common with
search → read → analyze flows), each iteration appends its own
paragraph break, resulting in 4-6+ blank lines before the actual
response.
Replace the immediate delta with a deferred flag
(_stream_needs_break). _fire_stream_delta() checks the flag and
prepends a single "\n\n" only when the first real text delta
arrives, so multiple back-to-back tool iterations still produce
exactly one paragraph break.
This commit is contained in:
19
run_agent.py
19
run_agent.py
@@ -670,6 +670,9 @@ class AIAgent:
|
||||
# Internal stream callback (set during streaming TTS).
|
||||
# Initialized here so _vprint can reference it before run_conversation.
|
||||
self._stream_callback = None
|
||||
# Deferred paragraph break flag — set after tool iterations so a
|
||||
# single "\n\n" is prepended to the next real text delta.
|
||||
self._stream_needs_break = False
|
||||
|
||||
# Optional current-turn user-message override used when the API-facing
|
||||
# user message intentionally differs from the persisted transcript
|
||||
@@ -3471,6 +3474,13 @@ class AIAgent:
|
||||
|
||||
def _fire_stream_delta(self, text: str) -> None:
|
||||
"""Fire all registered stream delta callbacks (display + TTS)."""
|
||||
# If a tool iteration set the break flag, prepend a single paragraph
|
||||
# break before the first real text delta. This prevents the original
|
||||
# problem (text concatenation across tool boundaries) without stacking
|
||||
# blank lines when multiple tool iterations run back-to-back.
|
||||
if getattr(self, "_stream_needs_break", False) and text and text.strip():
|
||||
self._stream_needs_break = False
|
||||
text = "\n\n" + text
|
||||
for cb in (self.stream_delta_callback, self._stream_callback):
|
||||
if cb is not None:
|
||||
try:
|
||||
@@ -6756,8 +6766,13 @@ class AIAgent:
|
||||
_msg_count_before_tools = len(messages)
|
||||
self._execute_tool_calls(assistant_message, messages, effective_task_id, api_call_count)
|
||||
|
||||
# Signal iteration boundary to stream consumers to prevent text concatenation
|
||||
self._fire_stream_delta("\n\n")
|
||||
# Signal that a paragraph break is needed before the next
|
||||
# streamed text. We don't emit it immediately because
|
||||
# multiple consecutive tool iterations would stack up
|
||||
# redundant blank lines. Instead, _fire_stream_delta()
|
||||
# will prepend a single "\n\n" the next time real text
|
||||
# arrives.
|
||||
self._stream_needs_break = True
|
||||
|
||||
# Refund the iteration if the ONLY tool(s) called were
|
||||
# execute_code (programmatic tool calling). These are
|
||||
|
||||
Reference in New Issue
Block a user