From ea16949422768d759941272f630c0e25e40f9689 Mon Sep 17 00:00:00 2001 From: Myeongwon Choi Date: Tue, 7 Apr 2026 07:43:30 +0900 Subject: [PATCH] fix(cron): suppress delivery when [SILENT] appears anywhere in response Previously the scheduler checked startswith('[SILENT]'), so agents that appended [SILENT] after an explanation (e.g. 'N items filtered.\n\n[SILENT]') would still trigger delivery. Change the check to 'in' so the marker is caught regardless of position. Add test_silent_trailing_suppresses_delivery to cover this case. --- cron/scheduler.py | 2 +- tests/cron/test_scheduler.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cron/scheduler.py b/cron/scheduler.py index 63018d6f..5f3feba0 100644 --- a/cron/scheduler.py +++ b/cron/scheduler.py @@ -817,7 +817,7 @@ def tick(verbose: bool = True, adapters=None, loop=None) -> int: # output is already saved above). Failed jobs always deliver. deliver_content = final_response if success else f"⚠️ Cron job '{job.get('name', job['id'])}' failed:\n{error}" should_deliver = bool(deliver_content) - if should_deliver and success and deliver_content.strip().upper().startswith(SILENT_MARKER): + if should_deliver and success and SILENT_MARKER in deliver_content.strip().upper(): logger.info("Job '%s': agent returned %s — skipping delivery", job["id"], SILENT_MARKER) should_deliver = False diff --git a/tests/cron/test_scheduler.py b/tests/cron/test_scheduler.py index 33f265de..c1282897 100644 --- a/tests/cron/test_scheduler.py +++ b/tests/cron/test_scheduler.py @@ -709,6 +709,18 @@ class TestSilentDelivery: tick(verbose=False) deliver_mock.assert_not_called() + def test_silent_trailing_suppresses_delivery(self): + """Agent appended [SILENT] after explanation text — must still suppress.""" + response = "2 deals filtered out (like<10, reply<15).\n\n[SILENT]" + with patch("cron.scheduler.get_due_jobs", return_value=[self._make_job()]), \ + patch("cron.scheduler.run_job", return_value=(True, "# output", response, None)), \ + patch("cron.scheduler.save_job_output", return_value="/tmp/out.md"), \ + patch("cron.scheduler._deliver_result") as deliver_mock, \ + patch("cron.scheduler.mark_job_run"): + from cron.scheduler import tick + tick(verbose=False) + deliver_mock.assert_not_called() + def test_silent_is_case_insensitive(self): with patch("cron.scheduler.get_due_jobs", return_value=[self._make_job()]), \ patch("cron.scheduler.run_job", return_value=(True, "# output", "[silent] nothing new", None)), \