nanobot/nanobot/triggers/local_turns.py

56 lines
2.0 KiB
Python

"""Coordination for local trigger turns."""
from __future__ import annotations
from collections.abc import Awaitable, Callable, Iterable
from nanobot.agent.automation_turns import AutomationTurnCoordinator
from nanobot.bus.events import InboundMessage
from nanobot.triggers.local_session_turns import local_trigger, local_trigger_delivery_id
class LocalTriggerTurnCoordinator(AutomationTurnCoordinator):
"""Manage local trigger turns without mixing them into live injections."""
def __init__(
self,
*,
publish_inbound: Callable[[InboundMessage], Awaitable[None]],
dispatch: Callable[[InboundMessage], Awaitable[object]],
is_running: Callable[[], bool],
deferred_queues: dict[str, list[InboundMessage]] | None = None,
) -> None:
super().__init__(
publish_inbound=publish_inbound,
dispatch=dispatch,
is_running=is_running,
turn_id=lambda msg: local_trigger_delivery_id(msg.metadata),
pending_id=_local_trigger_id,
should_defer_turn=_should_defer_local_trigger_turn,
missing_id_error="local trigger turn metadata must include a delivery_id",
duplicate_id_error=lambda delivery_id: (
f"local trigger delivery {delivery_id!r} is already pending"
),
deferred_queues=deferred_queues,
)
def pending_trigger_ids_for_session(self, session_key: str) -> set[str]:
"""Return local triggers waiting for or running in *session_key*."""
return self.pending_ids_for_session(session_key)
def _should_defer_local_trigger_turn(
msg: InboundMessage,
session_key: str,
active_session_keys: Iterable[str],
) -> bool:
return local_trigger(msg.metadata) is not None and session_key in active_session_keys
def _local_trigger_id(msg: InboundMessage) -> str | None:
trigger = local_trigger(msg.metadata)
if not trigger:
return None
value = trigger.get("trigger_id")
return value if isinstance(value, str) and value else None