mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-20 08:32:25 +00:00
refactor(loop): address code review nits
- Fix _assemble_outbound on_stream type annotation (Callable[[str], Awaitable[None]] | None) - Use last_msg consistently in _state_save instead of re-indexing - Remove dead fallback in _state_respond (guaranteed non-None by _state_save) - Change pending_summary type from Any to str | None - Make session optional in TurnContext to avoid redundant fetch - Add defensive dispatch with RuntimeError for missing handlers
This commit is contained in:
parent
8a6b769219
commit
6ef1b2c842
@ -198,9 +198,9 @@ class TurnState(Enum):
|
|||||||
@dataclass
|
@dataclass
|
||||||
class TurnContext:
|
class TurnContext:
|
||||||
msg: InboundMessage
|
msg: InboundMessage
|
||||||
session: Session
|
|
||||||
session_key: str
|
session_key: str
|
||||||
state: TurnState
|
state: TurnState
|
||||||
|
session: Session | None = None
|
||||||
|
|
||||||
history: list[dict[str, Any]] = field(default_factory=list)
|
history: list[dict[str, Any]] = field(default_factory=list)
|
||||||
initial_messages: list[dict[str, Any]] = field(default_factory=list)
|
initial_messages: list[dict[str, Any]] = field(default_factory=list)
|
||||||
@ -223,7 +223,7 @@ class TurnContext:
|
|||||||
on_retry_wait: Callable[[str], Awaitable[None]] | None = None
|
on_retry_wait: Callable[[str], Awaitable[None]] | None = None
|
||||||
|
|
||||||
pending_queue: asyncio.Queue | None = None
|
pending_queue: asyncio.Queue | None = None
|
||||||
pending_summary: Any = None
|
pending_summary: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class AgentLoop:
|
class AgentLoop:
|
||||||
@ -1253,7 +1253,10 @@ class AgentLoop:
|
|||||||
)
|
)
|
||||||
|
|
||||||
while ctx.state is not TurnState.DONE:
|
while ctx.state is not TurnState.DONE:
|
||||||
handler = getattr(self, f"_state_{ctx.state.name.lower()}")
|
handler_name = f"_state_{ctx.state.name.lower()}"
|
||||||
|
handler = getattr(self, handler_name, None)
|
||||||
|
if handler is None:
|
||||||
|
raise RuntimeError(f"Missing state handler for {ctx.state}")
|
||||||
ctx.state = await handler(ctx)
|
ctx.state = await handler(ctx)
|
||||||
|
|
||||||
return ctx.outbound
|
return ctx.outbound
|
||||||
@ -1266,7 +1269,7 @@ class AgentLoop:
|
|||||||
stop_reason: str,
|
stop_reason: str,
|
||||||
had_injections: bool,
|
had_injections: bool,
|
||||||
generated_media: list[str],
|
generated_media: list[str],
|
||||||
on_stream: Callable | None,
|
on_stream: Callable[[str], Awaitable[None]] | None,
|
||||||
) -> OutboundMessage | None:
|
) -> OutboundMessage | None:
|
||||||
"""Assemble the final outbound message from turn results."""
|
"""Assemble the final outbound message from turn results."""
|
||||||
# MessageTool suppression
|
# MessageTool suppression
|
||||||
@ -1307,7 +1310,10 @@ class AgentLoop:
|
|||||||
preview = msg.content[:80] + "..." if len(msg.content) > 80 else msg.content
|
preview = msg.content[:80] + "..." if len(msg.content) > 80 else msg.content
|
||||||
logger.info("Processing message from {}:{}: {}", msg.channel, msg.sender_id, preview)
|
logger.info("Processing message from {}:{}: {}", msg.channel, msg.sender_id, preview)
|
||||||
|
|
||||||
ctx.session = self.sessions.get_or_create(ctx.session_key)
|
# Session is already fetched by the caller (_process_message) but
|
||||||
|
# ensure it exists in case this handler is invoked independently.
|
||||||
|
if ctx.session is None:
|
||||||
|
ctx.session = self.sessions.get_or_create(ctx.session_key)
|
||||||
mark_webui_session(ctx.session, msg.metadata)
|
mark_webui_session(ctx.session, msg.metadata)
|
||||||
|
|
||||||
if self._restore_runtime_checkpoint(ctx.session):
|
if self._restore_runtime_checkpoint(ctx.session):
|
||||||
@ -1404,9 +1410,9 @@ class AgentLoop:
|
|||||||
ctx.generated_media = generated_image_paths_from_messages(skip_msgs)
|
ctx.generated_media = generated_image_paths_from_messages(skip_msgs)
|
||||||
last_msg = ctx.all_messages[-1] if ctx.all_messages else None
|
last_msg = ctx.all_messages[-1] if ctx.all_messages else None
|
||||||
if ctx.generated_media and last_msg and last_msg.get("role") == "assistant":
|
if ctx.generated_media and last_msg and last_msg.get("role") == "assistant":
|
||||||
existing_media = ctx.all_messages[-1].get("media")
|
existing_media = last_msg.get("media")
|
||||||
media = existing_media if isinstance(existing_media, list) else []
|
media = existing_media if isinstance(existing_media, list) else []
|
||||||
ctx.all_messages[-1]["media"] = list(dict.fromkeys([*media, *ctx.generated_media]))
|
last_msg["media"] = list(dict.fromkeys([*media, *ctx.generated_media]))
|
||||||
|
|
||||||
self._save_turn(ctx.session, ctx.all_messages, ctx.save_skip)
|
self._save_turn(ctx.session, ctx.all_messages, ctx.save_skip)
|
||||||
ctx.session.enforce_file_cap(on_archive=self.context.memory.raw_archive)
|
ctx.session.enforce_file_cap(on_archive=self.context.memory.raw_archive)
|
||||||
@ -1424,7 +1430,7 @@ class AgentLoop:
|
|||||||
async def _state_respond(self, ctx: TurnContext) -> TurnState:
|
async def _state_respond(self, ctx: TurnContext) -> TurnState:
|
||||||
ctx.outbound = self._assemble_outbound(
|
ctx.outbound = self._assemble_outbound(
|
||||||
ctx.msg,
|
ctx.msg,
|
||||||
ctx.final_content or "",
|
ctx.final_content,
|
||||||
ctx.all_messages,
|
ctx.all_messages,
|
||||||
ctx.stop_reason,
|
ctx.stop_reason,
|
||||||
ctx.had_injections,
|
ctx.had_injections,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user