fix(codex): stream progress deltas to channels

This commit is contained in:
hanyuanling
2026-04-27 18:48:05 +08:00
committed by Xubin Ren
parent 2b886ffd1f
commit ae14142a87
7 changed files with 128 additions and 2 deletions
+1
View File
@@ -21,6 +21,7 @@ class AgentHookContext:
tool_calls: list[ToolCallRequest] = field(default_factory=list)
tool_results: list[Any] = field(default_factory=list)
tool_events: list[dict[str, str]] = field(default_factory=list)
streamed_content: bool = False
final_content: str | None = None
stop_reason: str | None = None
error: str | None = None
+1 -1
View File
@@ -114,7 +114,7 @@ class _LoopHook(AgentHook):
async def before_execute_tools(self, context: AgentHookContext) -> None:
if self._on_progress:
if not self._on_stream:
if not self._on_stream and not context.streamed_content:
thought = self._loop._strip_think(
context.response.content if context.response else None
)
+30 -1
View File
@@ -21,6 +21,7 @@ from nanobot.utils.helpers import (
estimate_prompt_tokens_chain,
find_legal_message_start,
maybe_persist_tool_result,
strip_think,
truncate_text,
)
from nanobot.utils.prompt_templates import render_template
@@ -607,14 +608,42 @@ class AgentRunner:
messages,
tools=spec.tools.get_definitions(),
)
if hook.wants_streaming():
wants_streaming = hook.wants_streaming()
wants_progress_streaming = (
not wants_streaming
and spec.progress_callback is not None
and getattr(self.provider, "stream_progress_via_chat_stream", False) is True
)
if wants_streaming:
async def _stream(delta: str) -> None:
if delta:
context.streamed_content = True
await hook.on_stream(context, delta)
coro = self.provider.chat_stream_with_retry(
**kwargs,
on_content_delta=_stream,
)
elif wants_progress_streaming:
stream_buf = ""
async def _stream_progress(delta: str) -> None:
nonlocal stream_buf
if not delta:
return
prev_clean = strip_think(stream_buf)
stream_buf += delta
new_clean = strip_think(stream_buf)
incremental = new_clean[len(prev_clean):]
if incremental:
context.streamed_content = True
await spec.progress_callback(incremental)
coro = self.provider.chat_stream_with_retry(
**kwargs,
on_content_delta=_stream_progress,
)
else:
coro = self.provider.chat_with_retry(**kwargs)
+2
View File
@@ -91,6 +91,8 @@ _SYNTHETIC_USER_CONTENT = "(conversation continued)"
class LLMProvider(ABC):
"""Base class for LLM providers."""
stream_progress_via_chat_stream = False
_CHAT_RETRY_DELAYS = (1, 2, 4)
_PERSISTENT_MAX_DELAY = 60
_PERSISTENT_IDENTICAL_ERROR_LIMIT = 10
@@ -26,6 +26,8 @@ DEFAULT_ORIGINATOR = "nanobot"
class OpenAICodexProvider(LLMProvider):
"""Use Codex OAuth to call the Responses API."""
stream_progress_via_chat_stream = True
def __init__(self, default_model: str = "openai-codex/gpt-5.1-codex"):
super().__init__(api_key=None, api_base=None)
self.default_model = default_model