Fix stream ai bug

This commit is contained in:
2026-05-01 23:54:24 -03:00
parent a192bd1912
commit 16868828c6
3 changed files with 59 additions and 16 deletions
+1 -1
View File
@@ -1 +1 @@
__version__ = "6.0.0b4" __version__ = "6.0.0b5"
+14 -5
View File
@@ -271,7 +271,7 @@ class ai:
raise KeyboardInterrupt raise KeyboardInterrupt
chunk_callback(delta.content) chunk_callback(delta.content)
if not debug and not chunk_callback: if not chunk_callback:
if not is_streaming_text: if not is_streaming_text:
# Stop spinner definitively # Stop spinner definitively
if status: if status:
@@ -279,9 +279,15 @@ class ai:
status.stop() status.stop()
except Exception: except Exception:
pass pass
# Create a stable, direct Console to bypass _ConsoleProxy recreation bugs
from rich.console import Console as RichConsole
from .printer import connpy_theme, get_original_stdout
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
live_display = Live( live_display = Live(
Panel(Markdown(full_content), title=title, border_style=border, expand=False), Panel(Markdown(full_content), title=title, border_style=border, expand=False),
console=self.console, console=stable_console,
refresh_per_second=8, refresh_per_second=8,
transient=False transient=False
) )
@@ -303,7 +309,10 @@ class ai:
) )
except Exception: except Exception:
pass pass
try:
live_display.stop() live_display.stop()
except Exception:
pass
# Rebuild complete response from chunks # Rebuild complete response from chunks
try: try:
@@ -989,7 +998,7 @@ class ai:
streamed_response = False streamed_response = False
try: try:
safe_messages = self._sanitize_messages(messages) safe_messages = self._sanitize_messages(messages)
if stream and chunk_callback: if stream:
response, streamed_response = self._stream_completion( response, streamed_response = self._stream_completion(
model=model, messages=safe_messages, tools=tools, api_key=key, model=model, messages=safe_messages, tools=tools, api_key=key,
status=status, label=label, debug=debug, num_retries=3, status=status, label=label, debug=debug, num_retries=3,
@@ -1028,8 +1037,8 @@ class ai:
if msg_dict.get("tool_calls") and msg_dict.get("content") == "": msg_dict["content"] = None if msg_dict.get("tool_calls") and msg_dict.get("content") == "": msg_dict["content"] = None
messages.append(msg_dict) messages.append(msg_dict)
if debug and resp_msg.content: if debug and resp_msg.content and not streamed_response:
# In CLI debug mode, only print intermediate reasoning if there are tool calls. # In CLI debug mode, only print intermediate reasoning if there are tool calls AND it wasn't already streamed.
# If there are no tool calls, this content is the final answer and will be printed by the caller. # If there are no tool calls, this content is the final answer and will be printed by the caller.
if resp_msg.tool_calls: if resp_msg.tool_calls:
if status: if status:
+42 -8
View File
@@ -604,21 +604,33 @@ class AIStub:
if response.debug_message: if response.debug_message:
if debug: if debug:
if live_display:
try: live_display.stop()
except: pass
if status: if status:
try: status.stop() try: status.stop()
except: pass except: pass
printer.console.print(Text.from_ansi(response.debug_message)) printer.console.print(Text.from_ansi(response.debug_message))
if status: if live_display:
try: live_display.start()
except: pass
elif status:
try: status.start() try: status.start()
except: pass except: pass
continue continue
if response.important_message: if response.important_message:
if live_display:
try: live_display.stop()
except: pass
if status: if status:
try: status.stop() try: status.stop()
except: pass except: pass
printer.console.print(Text.from_ansi(response.important_message)) printer.console.print(Text.from_ansi(response.important_message))
if status: if live_display:
try: live_display.start()
except: pass
elif status:
try: status.start() try: status.start()
except: pass except: pass
continue continue
@@ -627,14 +639,33 @@ class AIStub:
if response.text_chunk: if response.text_chunk:
full_content += response.text_chunk full_content += response.text_chunk
if status and not debug: if not live_display:
# Update the spinner line with a preview of the response if status:
preview = full_content.replace("\n", " ").strip() try: status.stop()
if len(preview) > 60: preview = preview[:57] + "..." except: pass
status.update(f"[ai_status]{preview}")
from rich.console import Console as RichConsole
from ..printer import connpy_theme, get_original_stdout
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
# We default to Engineer title during stream, final result will correct it if needed
live_display = Live(
Panel(Markdown(full_content), title="[bold engineer]Network Engineer[/bold engineer]", border_style="engineer", expand=False),
console=stable_console,
refresh_per_second=8,
transient=False
)
live_display.start()
else:
live_display.update(
Panel(Markdown(full_content), title="[bold engineer]Network Engineer[/bold engineer]", border_style="engineer", expand=False)
)
continue continue
if response.is_final: if response.is_final:
if live_display:
try: live_display.stop()
except: pass
# Final stop for status to ensure it disappears before the panel # Final stop for status to ensure it disappears before the panel
if status: if status:
try: status.stop() try: status.stop()
@@ -646,9 +677,12 @@ class AIStub:
role_label = "Network Architect" if responder == "architect" else "Network Engineer" role_label = "Network Architect" if responder == "architect" else "Network Engineer"
title = f"[bold {alias}]{role_label}[/bold {alias}]" title = f"[bold {alias}]{role_label}[/bold {alias}]"
# Always print the final Panel
content_to_print = full_content or final_result.get("response", "") content_to_print = full_content or final_result.get("response", "")
if content_to_print: if content_to_print:
if live_display:
# Re-render the final frame with correct title/colors
live_display.update(Panel(Markdown(content_to_print), title=title, border_style=alias, expand=False))
else:
printer.console.print(Panel(Markdown(content_to_print), title=title, border_style=alias, expand=False)) printer.console.print(Panel(Markdown(content_to_print), title=title, border_style=alias, expand=False))
break break
except Exception as e: except Exception as e: