fix(webui): deliver late subagent results as new turns (#4992)

This commit is contained in:
chengyongru
2026-07-22 23:04:36 +08:00
committed by GitHub
parent aa8387fb4d
commit 66690fdb0c
12 changed files with 740 additions and 218 deletions
+3 -3
View File
@@ -148,7 +148,7 @@ def prepare_save_boundary(ctx: Any) -> None:
message_metadata=ctx.msg.metadata,
initial_message_count=len(ctx.initial_messages),
history_count=len(ctx.history),
user_persisted_early=ctx.user_persisted_early,
input_persisted_early=ctx.input_persisted_early,
)
@@ -183,7 +183,7 @@ def _save_skip_for_turn(
message_metadata: Mapping[str, Any] | None,
initial_message_count: int,
history_count: int,
user_persisted_early: bool,
input_persisted_early: bool,
) -> int:
"""Return the persisted-message append boundary for this turn."""
if message_metadata and message_metadata.get(SKIP_USER_PERSIST_META) is True:
@@ -193,7 +193,7 @@ def _save_skip_for_turn(
# build_messages may merge the current message into a same-role history tail.
# Runner-appended messages start at initial_message_count in either shape.
has_standalone_current = initial_message_count > 1 + history_count
if has_standalone_current and not user_persisted_early:
if has_standalone_current and not input_persisted_early:
return initial_message_count - 1
return initial_message_count
+38 -1
View File
@@ -5,11 +5,13 @@ from __future__ import annotations
import re
import time
from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field
from dataclasses import dataclass, field, replace
from typing import Any
from uuid import uuid4
from loguru import logger
from nanobot.agent.turn_delivery import TurnRoute
from nanobot.bus import progress as bus_progress
from nanobot.bus.events import InboundMessage
from nanobot.bus.outbound_events import (
@@ -37,6 +39,7 @@ from nanobot.session.history_visibility import is_hidden_history_message
from nanobot.session.manager import Session, SessionManager
from nanobot.utils.helpers import strip_think, truncate_text
from nanobot.utils.llm_runtime import LLMRuntime
from nanobot.webui.metadata import WEBUI_TURN_METADATA_KEY
WEBUI_SESSION_METADATA_KEY = "webui"
WEBUI_TITLE_METADATA_KEY = "title"
@@ -235,6 +238,40 @@ async def publish_turn_run_status(
),
)
@dataclass(frozen=True)
class WebuiTurnRoutePolicy:
"""Expose independently dispatched late subagent turns to WebUI sessions."""
sessions: SessionManager
def __call__(
self,
msg: InboundMessage,
session_key: str,
route: TurnRoute,
) -> TurnRoute:
"""Make an independently dispatched late subagent result visible in WebUI."""
if (
msg.channel != "system"
or msg.sender_id != "subagent"
or msg.metadata.get("injected_event") != "subagent_result"
or route.channel != "websocket"
):
return route
session = self.sessions.get_or_create(session_key)
if session.metadata.get(WEBUI_SESSION_METADATA_KEY) is not True:
return route
metadata = dict(route.metadata)
metadata.update({
WEBUI_SESSION_METADATA_KEY: True,
"_wants_stream": True,
WEBUI_TURN_METADATA_KEY: f"subagent:{uuid4().hex}",
})
return replace(route, metadata=metadata, publish_lifecycle=True)
@dataclass
class WebuiTurnCoordinator:
"""Translate generic runtime events into WebUI/WebSocket wire messages."""