diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index e7393e24b..3350c447b 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -351,6 +351,7 @@ class AgentLoop: on_progress: Callable[..., Awaitable[None]] | None = None, on_stream: Callable[[str], Awaitable[None]] | None = None, on_stream_end: Callable[..., Awaitable[None]] | None = None, + on_retry_wait: Callable[[str], Awaitable[None]] | None = None, *, session: Session | None = None, channel: str = "cli", @@ -428,6 +429,7 @@ class AgentLoop: context_block_limit=self.context_block_limit, provider_retry_mode=self.provider_retry_mode, progress_callback=on_progress, + retry_wait_callback=on_retry_wait, checkpoint_callback=_checkpoint, injection_callback=_drain_pending, )) @@ -738,6 +740,18 @@ class AgentLoop: ) ) + async def _on_retry_wait(content: str) -> None: + meta = dict(msg.metadata or {}) + meta["_retry_wait"] = True + await self.bus.publish_outbound( + OutboundMessage( + channel=msg.channel, + chat_id=msg.chat_id, + content=content, + metadata=meta, + ) + ) + # Persist the triggering user message immediately, before running the # agent loop. If the process is killed mid-turn (OOM, SIGKILL, self- # restart, etc.), the existing runtime_checkpoint preserves the @@ -756,6 +770,7 @@ class AgentLoop: on_progress=on_progress or _bus_progress, on_stream=on_stream, on_stream_end=on_stream_end, + on_retry_wait=_on_retry_wait, session=session, channel=msg.channel, chat_id=msg.chat_id, diff --git a/nanobot/agent/runner.py b/nanobot/agent/runner.py index 9b7d50316..d90c79fe6 100644 --- a/nanobot/agent/runner.py +++ b/nanobot/agent/runner.py @@ -71,6 +71,7 @@ class AgentRunSpec: context_block_limit: int | None = None provider_retry_mode: str = "standard" progress_callback: Any | None = None + retry_wait_callback: Any | None = None checkpoint_callback: Any | None = None injection_callback: Any | None = None @@ -552,7 +553,7 @@ class AgentRunner: "tools": tools, "model": spec.model, "retry_mode": spec.provider_retry_mode, - "on_retry_wait": spec.progress_callback, + "on_retry_wait": spec.retry_wait_callback, } if spec.temperature is not None: kwargs["temperature"] = spec.temperature diff --git a/nanobot/channels/manager.py b/nanobot/channels/manager.py index 0e4821701..c0622a272 100644 --- a/nanobot/channels/manager.py +++ b/nanobot/channels/manager.py @@ -189,6 +189,9 @@ class ChannelManager: if not msg.metadata.get("_tool_hint") and not self.config.channels.send_progress: continue + if msg.metadata.get("_retry_wait"): + continue + # Coalesce consecutive _stream_delta messages for the same (channel, chat_id) # to reduce API calls and improve streaming latency if msg.metadata.get("_stream_delta") and not msg.metadata.get("_stream_end"):