fix(triggers): require channel enablement predicate
This commit is contained in:
@@ -2076,7 +2076,7 @@ def _run_gateway(
|
|||||||
run_local_trigger_queue(
|
run_local_trigger_queue(
|
||||||
store=trigger_store,
|
store=trigger_store,
|
||||||
submit_turn=getattr(agent, "submit_local_trigger_turn", None),
|
submit_turn=getattr(agent, "submit_local_trigger_turn", None),
|
||||||
is_channel_available=lambda name: name in channels.channels,
|
is_channel_enabled=lambda name: channels.get_channel(name) is not None,
|
||||||
),
|
),
|
||||||
name="nanobot-local-triggers",
|
name="nanobot-local-triggers",
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ async def run_local_trigger_queue(
|
|||||||
*,
|
*,
|
||||||
store: LocalTriggerStore,
|
store: LocalTriggerStore,
|
||||||
submit_turn: Callable[[InboundMessage], Awaitable[OutboundMessage | None]] | None = None,
|
submit_turn: Callable[[InboundMessage], Awaitable[OutboundMessage | None]] | None = None,
|
||||||
is_channel_available: Callable[[str], bool] | None = None,
|
is_channel_enabled: Callable[[str], bool],
|
||||||
poll_interval_s: float = 0.5,
|
poll_interval_s: float = 0.5,
|
||||||
batch_size: int = 20,
|
batch_size: int = 20,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -47,7 +47,7 @@ async def run_local_trigger_queue(
|
|||||||
store,
|
store,
|
||||||
delivery,
|
delivery,
|
||||||
submit_turn=submit_turn,
|
submit_turn=submit_turn,
|
||||||
is_channel_available=is_channel_available,
|
is_channel_enabled=is_channel_enabled,
|
||||||
)
|
)
|
||||||
store.complete_delivery(delivery)
|
store.complete_delivery(delivery)
|
||||||
except asyncio.CancelledError as exc:
|
except asyncio.CancelledError as exc:
|
||||||
@@ -132,14 +132,14 @@ async def _deliver_delivery(
|
|||||||
delivery: TriggerDelivery,
|
delivery: TriggerDelivery,
|
||||||
*,
|
*,
|
||||||
submit_turn: Callable[[InboundMessage], Awaitable[OutboundMessage | None]],
|
submit_turn: Callable[[InboundMessage], Awaitable[OutboundMessage | None]],
|
||||||
is_channel_available: Callable[[str], bool] | None = None,
|
is_channel_enabled: Callable[[str], bool],
|
||||||
) -> None:
|
) -> None:
|
||||||
trigger = store.get(delivery.trigger_id)
|
trigger = store.get(delivery.trigger_id)
|
||||||
if trigger is None:
|
if trigger is None:
|
||||||
raise _TerminalDeliveryError("trigger not found")
|
raise _TerminalDeliveryError("trigger not found")
|
||||||
if not trigger.enabled:
|
if not trigger.enabled:
|
||||||
raise _TerminalDeliveryError("trigger is disabled")
|
raise _TerminalDeliveryError("trigger is disabled")
|
||||||
if is_channel_available is not None and not is_channel_available(trigger.channel):
|
if not is_channel_enabled(trigger.channel):
|
||||||
raise _TerminalDeliveryError(f"target channel is not enabled: {trigger.channel}")
|
raise _TerminalDeliveryError(f"target channel is not enabled: {trigger.channel}")
|
||||||
|
|
||||||
store.write_delivery_run_record(delivery, trigger=trigger, status="processing")
|
store.write_delivery_run_record(delivery, trigger=trigger, status="processing")
|
||||||
|
|||||||
@@ -2748,7 +2748,10 @@ def test_gateway_local_trigger_queue_submits_agent_turns(
|
|||||||
enabled_channels: list[str] = []
|
enabled_channels: list[str] = []
|
||||||
|
|
||||||
def __init__(self, *_args, **_kwargs) -> None:
|
def __init__(self, *_args, **_kwargs) -> None:
|
||||||
self.channels: dict[str, object] = {}
|
return None
|
||||||
|
|
||||||
|
def get_channel(self, name: str) -> object | None:
|
||||||
|
return object() if name == "websocket" else None
|
||||||
|
|
||||||
async def start_all(self) -> None:
|
async def start_all(self) -> None:
|
||||||
await asyncio.Event().wait()
|
await asyncio.Event().wait()
|
||||||
@@ -2776,7 +2779,8 @@ def test_gateway_local_trigger_queue_submits_agent_turns(
|
|||||||
assert kwargs["store"] is agent_kwargs["local_trigger_store"]
|
assert kwargs["store"] is agent_kwargs["local_trigger_store"]
|
||||||
assert "bus" not in kwargs
|
assert "bus" not in kwargs
|
||||||
assert kwargs["submit_turn"] is agent.submit_local_trigger_turn
|
assert kwargs["submit_turn"] is agent.submit_local_trigger_turn
|
||||||
assert kwargs["is_channel_available"]("websocket") is False
|
assert kwargs["is_channel_enabled"]("websocket") is True
|
||||||
|
assert kwargs["is_channel_enabled"]("telegram") is False
|
||||||
|
|
||||||
|
|
||||||
def test_gateway_workspace_override_does_not_migrate_legacy_cron(
|
def test_gateway_workspace_override_does_not_migrate_legacy_cron(
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ from nanobot.triggers.local_types import LocalTrigger, TriggerDelivery
|
|||||||
from nanobot.webui.metadata import WEBUI_MESSAGE_SOURCE_METADATA_KEY, WEBUI_TURN_METADATA_KEY
|
from nanobot.webui.metadata import WEBUI_MESSAGE_SOURCE_METADATA_KEY, WEBUI_TURN_METADATA_KEY
|
||||||
|
|
||||||
|
|
||||||
|
def _channel_is_enabled(_name: str) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _write_delivery_file(path: Path, *, trigger_id: str, delivery_id: str) -> None:
|
def _write_delivery_file(path: Path, *, trigger_id: str, delivery_id: str) -> None:
|
||||||
path.write_text(
|
path.write_text(
|
||||||
json.dumps(
|
json.dumps(
|
||||||
@@ -257,7 +261,12 @@ async def test_local_trigger_queue_submits_bound_inbound_message(tmp_path: Path)
|
|||||||
return OutboundMessage(channel=msg.channel, chat_id=msg.chat_id, content="done")
|
return OutboundMessage(channel=msg.channel, chat_id=msg.chat_id, content="done")
|
||||||
|
|
||||||
task = asyncio.create_task(
|
task = asyncio.create_task(
|
||||||
run_local_trigger_queue(store=store, submit_turn=_submit_turn, poll_interval_s=0.01)
|
run_local_trigger_queue(
|
||||||
|
store=store,
|
||||||
|
submit_turn=_submit_turn,
|
||||||
|
is_channel_enabled=_channel_is_enabled,
|
||||||
|
poll_interval_s=0.01,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
for _ in range(100):
|
for _ in range(100):
|
||||||
@@ -319,7 +328,7 @@ async def test_local_trigger_queue_rejects_unavailable_target_channel(tmp_path:
|
|||||||
run_local_trigger_queue(
|
run_local_trigger_queue(
|
||||||
store=store,
|
store=store,
|
||||||
submit_turn=_submit_turn,
|
submit_turn=_submit_turn,
|
||||||
is_channel_available=lambda name: name == "websocket",
|
is_channel_enabled=lambda name: name == "websocket",
|
||||||
poll_interval_s=0.01,
|
poll_interval_s=0.01,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -369,6 +378,7 @@ async def test_local_trigger_queue_waits_for_submitted_turn_before_ack(
|
|||||||
run_local_trigger_queue(
|
run_local_trigger_queue(
|
||||||
store=store,
|
store=store,
|
||||||
submit_turn=_submit_turn,
|
submit_turn=_submit_turn,
|
||||||
|
is_channel_enabled=_channel_is_enabled,
|
||||||
poll_interval_s=0.01,
|
poll_interval_s=0.01,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -428,6 +438,7 @@ async def test_local_trigger_queue_requeues_when_submitted_turn_is_interrupted(
|
|||||||
run_local_trigger_queue(
|
run_local_trigger_queue(
|
||||||
store=store,
|
store=store,
|
||||||
submit_turn=_submit_turn,
|
submit_turn=_submit_turn,
|
||||||
|
is_channel_enabled=_channel_is_enabled,
|
||||||
poll_interval_s=0.01,
|
poll_interval_s=0.01,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -473,6 +484,7 @@ async def test_local_trigger_queue_does_not_retry_completed_agent_failure(
|
|||||||
run_local_trigger_queue(
|
run_local_trigger_queue(
|
||||||
store=store,
|
store=store,
|
||||||
submit_turn=_submit_turn,
|
submit_turn=_submit_turn,
|
||||||
|
is_channel_enabled=_channel_is_enabled,
|
||||||
poll_interval_s=0.01,
|
poll_interval_s=0.01,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -521,7 +533,12 @@ async def test_local_trigger_queue_recovers_processing_delivery_on_start(
|
|||||||
|
|
||||||
restarted = LocalTriggerStore(tmp_path)
|
restarted = LocalTriggerStore(tmp_path)
|
||||||
task = asyncio.create_task(
|
task = asyncio.create_task(
|
||||||
run_local_trigger_queue(store=restarted, submit_turn=_submit_turn, poll_interval_s=0.01)
|
run_local_trigger_queue(
|
||||||
|
store=restarted,
|
||||||
|
submit_turn=_submit_turn,
|
||||||
|
is_channel_enabled=_channel_is_enabled,
|
||||||
|
poll_interval_s=0.01,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
for _ in range(100):
|
for _ in range(100):
|
||||||
|
|||||||
Reference in New Issue
Block a user