fix: preserve interactive CLI formatting for async subagent output
This commit is contained in:
@@ -19,10 +19,12 @@ if sys.platform == "win32":
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
from prompt_toolkit import print_formatted_text
|
||||||
from prompt_toolkit import PromptSession
|
from prompt_toolkit import PromptSession
|
||||||
from prompt_toolkit.formatted_text import HTML
|
from prompt_toolkit.formatted_text import ANSI, HTML
|
||||||
from prompt_toolkit.history import FileHistory
|
from prompt_toolkit.history import FileHistory
|
||||||
from prompt_toolkit.patch_stdout import patch_stdout
|
from prompt_toolkit.patch_stdout import patch_stdout
|
||||||
|
from prompt_toolkit.application import run_in_terminal
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.markdown import Markdown
|
from rich.markdown import Markdown
|
||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
@@ -111,8 +113,25 @@ def _init_prompt_session() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _make_console() -> Console:
|
||||||
|
return Console(file=sys.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
def _render_interactive_ansi(render_fn) -> str:
|
||||||
|
"""Render Rich output to ANSI so prompt_toolkit can print it safely."""
|
||||||
|
ansi_console = Console(
|
||||||
|
force_terminal=True,
|
||||||
|
color_system=console.color_system or "standard",
|
||||||
|
width=console.width,
|
||||||
|
)
|
||||||
|
with ansi_console.capture() as capture:
|
||||||
|
render_fn(ansi_console)
|
||||||
|
return capture.get()
|
||||||
|
|
||||||
|
|
||||||
def _print_agent_response(response: str, render_markdown: bool) -> None:
|
def _print_agent_response(response: str, render_markdown: bool) -> None:
|
||||||
"""Render assistant response with consistent terminal styling."""
|
"""Render assistant response with consistent terminal styling."""
|
||||||
|
console = _make_console()
|
||||||
content = response or ""
|
content = response or ""
|
||||||
body = Markdown(content) if render_markdown else Text(content)
|
body = Markdown(content) if render_markdown else Text(content)
|
||||||
console.print()
|
console.print()
|
||||||
@@ -121,6 +140,34 @@ def _print_agent_response(response: str, render_markdown: bool) -> None:
|
|||||||
console.print()
|
console.print()
|
||||||
|
|
||||||
|
|
||||||
|
async def _print_interactive_line(text: str) -> None:
|
||||||
|
"""Print async interactive updates with prompt_toolkit-safe Rich styling."""
|
||||||
|
def _write() -> None:
|
||||||
|
ansi = _render_interactive_ansi(
|
||||||
|
lambda c: c.print(f" [dim]↳ {text}[/dim]")
|
||||||
|
)
|
||||||
|
print_formatted_text(ANSI(ansi), end="")
|
||||||
|
|
||||||
|
await run_in_terminal(_write)
|
||||||
|
|
||||||
|
|
||||||
|
async def _print_interactive_response(response: str, render_markdown: bool) -> None:
|
||||||
|
"""Print async interactive replies with prompt_toolkit-safe Rich styling."""
|
||||||
|
def _write() -> None:
|
||||||
|
content = response or ""
|
||||||
|
ansi = _render_interactive_ansi(
|
||||||
|
lambda c: (
|
||||||
|
c.print(),
|
||||||
|
c.print(f"[cyan]{__logo__} nanobot[/cyan]"),
|
||||||
|
c.print(Markdown(content) if render_markdown else Text(content)),
|
||||||
|
c.print(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
print_formatted_text(ANSI(ansi), end="")
|
||||||
|
|
||||||
|
await run_in_terminal(_write)
|
||||||
|
|
||||||
|
|
||||||
def _is_exit_command(command: str) -> bool:
|
def _is_exit_command(command: str) -> bool:
|
||||||
"""Return True when input should end interactive chat."""
|
"""Return True when input should end interactive chat."""
|
||||||
return command.lower() in EXIT_COMMANDS
|
return command.lower() in EXIT_COMMANDS
|
||||||
@@ -611,14 +658,16 @@ def agent(
|
|||||||
elif ch and not is_tool_hint and not ch.send_progress:
|
elif ch and not is_tool_hint and not ch.send_progress:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
console.print(f" [dim]↳ {msg.content}[/dim]")
|
#await _print_interactive_line(f" ↳ {msg.content}")
|
||||||
|
await _print_interactive_line(f" [dim]↳ {msg.content}[/dim]")
|
||||||
|
|
||||||
elif not turn_done.is_set():
|
elif not turn_done.is_set():
|
||||||
if msg.content:
|
if msg.content:
|
||||||
turn_response.append(msg.content)
|
turn_response.append(msg.content)
|
||||||
turn_done.set()
|
turn_done.set()
|
||||||
elif msg.content:
|
elif msg.content:
|
||||||
console.print()
|
await _print_interactive_response(msg.content, render_markdown=markdown)
|
||||||
_print_agent_response(msg.content, render_markdown=markdown)
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
continue
|
continue
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
|
|||||||
Reference in New Issue
Block a user