refactor(agent): remove duplicate progress streaming path

This commit is contained in:
chengyongru
2026-08-27 10:56:07 +08:00
committed by chengyongru
parent 2113870e27
commit 55f85b3c1f
10 changed files with 49 additions and 236 deletions
+24 -23
View File
@@ -15,6 +15,7 @@ import pytest
from agent.runner_helpers import make_run_spec
from nanobot.agent.hook import AgentHook, AgentHookContext
from nanobot.agent.progress_hook import AgentProgressHook
from nanobot.config.schema import AgentDefaults
from nanobot.providers.base import LLMResponse, LLMUsage, ToolCallRequest
@@ -35,6 +36,18 @@ class _RecordingHook(AgentHook):
self.end_calls += 1
class _StreamRecordingHook(_RecordingHook):
def __init__(self) -> None:
super().__init__()
self.streamed: list[str] = []
def wants_streaming(self) -> bool:
return True
async def on_stream(self, _ctx: AgentHookContext, delta: str) -> None:
self.streamed.append(delta)
@pytest.mark.asyncio
async def test_runner_preserves_reasoning_fields_in_assistant_history():
"""Reasoning fields ride along on the persisted assistant message so
@@ -201,7 +214,6 @@ async def test_runner_emits_reasoning_content_even_when_answer_was_streamed():
from nanobot.agent.runner import AgentRunner
provider = MagicMock()
provider.supports_progress_deltas = True
async def chat_stream_with_retry(*, on_content_delta=None, **kwargs):
if on_content_delta:
@@ -218,12 +230,7 @@ async def test_runner_emits_reasoning_content_even_when_answer_was_streamed():
tools = MagicMock()
tools.get_definitions.return_value = []
progress_calls: list[str] = []
async def _progress(content: str, **_kwargs):
progress_calls.append(content)
hook = _RecordingHook()
hook = _StreamRecordingHook()
runner = AgentRunner()
result = await runner.run(make_run_spec(provider,
initial_messages=[{"role": "user", "content": "question"}],
@@ -232,11 +239,10 @@ async def test_runner_emits_reasoning_content_even_when_answer_was_streamed():
max_iterations=3,
max_tool_result_chars=_MAX_TOOL_RESULT_CHARS,
hook=hook,
progress_callback=_progress,
))
assert result.final_content == "The answer."
assert progress_calls, "answer should have streamed via progress callback"
assert hook.streamed == ["The ", "answer."]
assert hook.emitted == ["step-by-step deduction"]
@@ -247,7 +253,6 @@ async def test_runner_does_not_double_emit_when_inline_think_already_streamed():
from nanobot.agent.runner import AgentRunner
provider = MagicMock()
provider.supports_progress_deltas = True
async def chat_stream_with_retry(*, on_content_delta=None, **kwargs):
if on_content_delta:
@@ -263,10 +268,16 @@ async def test_runner_does_not_double_emit_when_inline_think_already_streamed():
tools = MagicMock()
tools.get_definitions.return_value = []
async def _progress(content: str, **_kwargs):
reasoning_events: list[str] = []
async def _progress(content: str, *, reasoning: bool = False, **_kwargs):
if reasoning:
reasoning_events.append(content)
async def _stream(_content: str) -> None:
pass
hook = _RecordingHook()
hook = AgentProgressHook(on_progress=_progress, on_stream=_stream)
runner = AgentRunner()
result = await runner.run(make_run_spec(provider,
initial_messages=[{"role": "user", "content": "question"}],
@@ -275,12 +286,10 @@ async def test_runner_does_not_double_emit_when_inline_think_already_streamed():
max_iterations=3,
max_tool_result_chars=_MAX_TOOL_RESULT_CHARS,
hook=hook,
progress_callback=_progress,
))
assert result.final_content == "The answer."
assert hook.emitted == ["working..."]
assert hook.end_calls >= 1, "reasoning stream must be closed once the answer starts"
assert reasoning_events == ["working..."]
@pytest.mark.asyncio
@@ -320,14 +329,6 @@ async def test_runner_closes_reasoning_stream_after_one_shot_response():
assert hook.end_calls == 1
class _StreamRecordingHook(_RecordingHook):
def wants_streaming(self) -> bool:
return True
async def on_stream(self, _ctx: AgentHookContext, delta: str) -> None:
pass
@pytest.mark.asyncio
async def test_runner_streams_native_thinking_deltas_without_post_hoc_dup():
"""Anthropic-style ``on_thinking_delta`` should fan out to ``emit_reasoning``;