From 29f1473940d70748e59134cb54ee154c0ab61f17 Mon Sep 17 00:00:00 2001 From: chengyongru <2755839590@qq.com> Date: Fri, 12 Jun 2026 00:15:57 +0800 Subject: [PATCH] fix: keep session automations bound-only --- nanobot/webui/session_automations.py | 30 +++++++------------- tests/channels/test_websocket_http_routes.py | 12 ++++---- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/nanobot/webui/session_automations.py b/nanobot/webui/session_automations.py index c60f05735..19af69a64 100644 --- a/nanobot/webui/session_automations.py +++ b/nanobot/webui/session_automations.py @@ -4,12 +4,16 @@ from __future__ import annotations from typing import Any, Protocol -from nanobot.cron.automation import is_bound_agent_job from nanobot.cron.types import CronJob class _CronServiceLike(Protocol): - def list_jobs(self, *, include_disabled: bool = False) -> list[CronJob]: ... + def list_bound_agent_jobs_for_session( + self, + session_key: str, + *, + include_disabled: bool = True, + ) -> list[CronJob]: ... def session_automation_jobs( @@ -19,11 +23,10 @@ def session_automation_jobs( """Return user automations attached to the WebUI session.""" if cron_service is None: return [] - return [ - job - for job in cron_service.list_jobs(include_disabled=True) - if _matches_webui_session(job, session_key) - ] + return cron_service.list_bound_agent_jobs_for_session( + session_key, + include_disabled=True, + ) def session_automations_payload( @@ -36,19 +39,6 @@ def session_automations_payload( } -def _matches_webui_session(job: CronJob, session_key: str) -> bool: - payload = job.payload - if payload.kind != "agent_turn": - return False - if is_bound_agent_job(job): - return payload.session_key == session_key - return bool( - payload.channel == "websocket" - and payload.to - and session_key == f"websocket:{payload.to}" - ) - - def serialize_automation_jobs(jobs: list[CronJob]) -> list[dict[str, Any]]: return [_serialize_job(job) for job in jobs] diff --git a/tests/channels/test_websocket_http_routes.py b/tests/channels/test_websocket_http_routes.py index c3614c7e2..bc11c2e15 100644 --- a/tests/channels/test_websocket_http_routes.py +++ b/tests/channels/test_websocket_http_routes.py @@ -189,7 +189,7 @@ async def test_session_automations_route_filters_by_webui_session( cron.add_job( name="Legacy same target", schedule=hourly, - message="Legacy job should still show in WebUI", + message="Legacy job should not be treated as bound", deliver=True, channel="websocket", to="abc", @@ -227,15 +227,11 @@ async def test_session_automations_route_filters_by_webui_session( assert resp.status_code == 200 body = resp.json() - assert [job["name"] for job in body["jobs"]] == [ - "Morning check", - "Legacy same target", - ] + assert [job["name"] for job in body["jobs"]] == ["Morning check"] job = body["jobs"][0] assert job["schedule"]["kind"] == "every" assert job["schedule"]["every_ms"] == 3_600_000 assert job["payload"]["message"] == "Check the project status" - assert body["jobs"][1]["payload"]["message"] == "Legacy job should still show in WebUI" finally: await channel.stop() await server_task @@ -747,7 +743,9 @@ async def test_session_delete_can_cascade_bound_automations( assert resp.json()["deleted"] is True assert not path.exists() assert cron.list_bound_agent_jobs_for_session("websocket:doomed") == [] - assert cron.list_jobs(include_disabled=True) == [] + assert [job.name for job in cron.list_jobs(include_disabled=True)] == [ + "Legacy same target" + ] finally: await channel.stop() await server_task