fix(cron): accept list-form deliver values so deliver=['telegram'] works (#17456)

The cron schema contracts deliver as a string ("local", "origin",
"telegram", "telegram:chat_id[:thread_id]", or comma-separated combos),
but MCP clients and scripts sometimes pass an array like ['telegram'].

Before this change, the list was written to jobs.json verbatim, and
the scheduler's str(deliver).split(',') then tried to resolve the
literal string "['telegram']" as a platform — returning None and
logging 'no delivery target resolved for deliver=[\'telegram\']'.

Fix on both ends:
- tools/cronjob_tools.py: normalize deliver at the API boundary on
  create and update, so storage is always a string.
- cron/scheduler.py: normalize deliver in _resolve_delivery_targets,
  so existing jobs.json entries with list-form deliver are handled
  gracefully without requiring users to edit the file.

Closes #17139
This commit is contained in:
Teknium 2026-04-29 06:35:34 -07:00 committed by GitHub
parent 7141cda967
commit 398945e7b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 140 additions and 4 deletions

View file

@ -279,6 +279,44 @@ class TestResolveDeliveryTarget:
"thread_id": None,
}
def test_list_form_deliver_is_normalized(self, monkeypatch):
"""deliver=['telegram'] (Python list) should resolve like 'telegram' string.
Regression test for #17139: MCP clients / scripts that pass the deliver
field as an array-shaped value used to fail with "no delivery target
resolved for deliver=['telegram']" because ``str(['telegram'])`` was
passed through to ``split(',')`` verbatim.
"""
monkeypatch.setenv("TELEGRAM_HOME_CHANNEL", "-4004")
job = {
"deliver": ["telegram"],
"origin": None,
}
assert _resolve_delivery_target(job) == {
"platform": "telegram",
"chat_id": "-4004",
"thread_id": None,
}
def test_list_form_multiple_platforms_normalized(self, monkeypatch):
"""deliver=['telegram', 'discord'] resolves to multiple targets."""
from cron.scheduler import _resolve_delivery_targets
monkeypatch.setenv("TELEGRAM_HOME_CHANNEL", "-111")
monkeypatch.setenv("DISCORD_HOME_CHANNEL", "-222")
job = {"deliver": ["telegram", "discord"], "origin": None}
targets = _resolve_delivery_targets(job)
platforms = sorted(t["platform"] for t in targets)
assert platforms == ["discord", "telegram"]
def test_empty_list_form_deliver_resolves_to_local(self):
"""deliver=[] is treated as local (no delivery)."""
from cron.scheduler import _resolve_delivery_targets
assert _resolve_delivery_targets({"deliver": []}) == []
class TestDeliverResultWrapping:
"""Verify that cron deliveries are wrapped with header/footer and no longer mirrored."""