"""Progress callback helpers for user-visible output. These helpers convert agent progress callbacks into outbound chat messages. Runtime state notifications such as turn lifecycle and model changes live in ``nanobot.bus.runtime_events``. """ from __future__ import annotations from collections.abc import Awaitable, Callable from typing import Any from nanobot.bus.events import InboundMessage, OutboundMessage from nanobot.bus.queue import MessageBus def build_bus_progress_callback( bus: MessageBus, msg: InboundMessage, ) -> Callable[..., Awaitable[None]]: """Return a callback that publishes progress as outbound messages.""" async def _publish_progress( content: str, *, tool_hint: bool = False, tool_events: list[dict[str, Any]] | None = None, file_edit_events: list[dict[str, Any]] | None = None, reasoning: bool = False, reasoning_end: bool = False, ) -> None: meta = dict(msg.metadata or {}) meta["_progress"] = True meta["_tool_hint"] = tool_hint if reasoning: meta["_reasoning_delta"] = True if reasoning_end: meta["_reasoning_end"] = True if tool_events: meta["_tool_events"] = tool_events if file_edit_events: meta["_file_edit_events"] = file_edit_events await bus.publish_outbound( OutboundMessage( channel=msg.channel, chat_id=msg.chat_id, content=content, metadata=meta, ) ) async def _bus_progress( content: str, *, tool_hint: bool = False, tool_events: list[dict[str, Any]] | None = None, file_edit_events: list[dict[str, Any]] | None = None, reasoning: bool = False, reasoning_end: bool = False, ) -> None: await _publish_progress( content, tool_hint=tool_hint, tool_events=tool_events, file_edit_events=file_edit_events, reasoning=reasoning, reasoning_end=reasoning_end, ) return _bus_progress