fix(cli): keep trace output under assistant header

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xubin Ren
2026-05-13 09:13:16 +00:00
co-authored by Cursor
parent 9d50f1b933
commit 3fab736262
4 changed files with 103 additions and 14 deletions
+26
View File
@@ -1,4 +1,5 @@
import asyncio
from contextlib import nullcontext
from unittest.mock import AsyncMock, MagicMock, call, patch
import pytest
@@ -96,6 +97,31 @@ def test_print_cli_progress_line_pauses_spinner_before_printing():
assert order == ["start", "stop", "print", "start", "stop"]
def test_print_cli_progress_line_opens_renderer_header_before_trace():
"""Trace lines should appear under the assistant header, not under You."""
order: list[str] = []
renderer = MagicMock()
renderer.console.print.side_effect = lambda *_args, **_kwargs: order.append("print")
renderer.ensure_header.side_effect = lambda: order.append("header")
renderer.pause_spinner.return_value = nullcontext()
commands._print_cli_progress_line("tool running", None, renderer)
assert order == ["header", "print"]
def test_print_cli_progress_line_stops_live_before_trace():
"""A trace line should not leak the current transient Live frame."""
mock_live = MagicMock()
renderer = stream_mod.StreamRenderer(show_spinner=False)
renderer._live = mock_live
commands._print_cli_progress_line("tool running", None, renderer)
mock_live.stop.assert_called_once()
assert renderer._live is None
@pytest.mark.asyncio
async def test_print_interactive_progress_line_pauses_spinner_before_printing():
"""Interactive progress output should also pause spinner cleanly."""
+19
View File
@@ -50,6 +50,25 @@ async def test_reasoning_displayed_when_show_reasoning_enabled():
assert calls == ["Let me think about this..."]
@pytest.mark.asyncio
async def test_reasoning_delta_displayed_when_show_reasoning_enabled():
"""Streamed reasoning delta frames should use the reasoning renderer."""
calls: list[str] = []
channels_config = SimpleNamespace(
send_progress=True, send_tool_hints=False, show_reasoning=True,
)
msg = SimpleNamespace(
content="I should search first.",
metadata={"_progress": True, "_reasoning_delta": True},
)
with patch("nanobot.cli.commands._print_cli_reasoning", side_effect=lambda t, th, r=None: calls.append(t)):
handled = await commands._maybe_print_interactive_progress(msg, None, channels_config)
assert handled is True
assert calls == ["I should search first."]
@pytest.mark.asyncio
async def test_reasoning_hidden_when_show_reasoning_disabled():
"""Reasoning content should be suppressed when show_reasoning is False."""