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:
@@ -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."""
|
||||
|
||||
@@ -231,3 +231,60 @@ class TestUnifiedCronjobTool:
|
||||
assert updated["success"] is True
|
||||
assert updated["job"]["skills"] == []
|
||||
assert updated["job"]["skill"] is None
|
||||
|
||||
def test_create_normalizes_list_form_deliver(self):
|
||||
"""deliver=['telegram'] (list) is stored as the string 'telegram'.
|
||||
|
||||
Regression for #17139: MCP clients / scripts sometimes pass ``deliver``
|
||||
as an array. Prior to the fix, ``['telegram']`` was written verbatim
|
||||
to ``jobs.json`` and the scheduler then tried to resolve the literal
|
||||
string ``"['telegram']"`` as a platform, failing with
|
||||
"no delivery target resolved".
|
||||
"""
|
||||
from cron.jobs import get_job
|
||||
|
||||
created = json.loads(
|
||||
cronjob(
|
||||
action="create",
|
||||
prompt="Daily briefing",
|
||||
schedule="every 1h",
|
||||
deliver=["telegram"],
|
||||
)
|
||||
)
|
||||
assert created["success"] is True
|
||||
stored = get_job(created["job_id"])
|
||||
assert stored["deliver"] == "telegram"
|
||||
|
||||
def test_create_normalizes_multi_element_list_deliver(self):
|
||||
"""deliver=['telegram', 'discord'] is stored as 'telegram,discord'."""
|
||||
from cron.jobs import get_job
|
||||
|
||||
created = json.loads(
|
||||
cronjob(
|
||||
action="create",
|
||||
prompt="Daily briefing",
|
||||
schedule="every 1h",
|
||||
deliver=["telegram", "discord"],
|
||||
)
|
||||
)
|
||||
assert created["success"] is True
|
||||
stored = get_job(created["job_id"])
|
||||
assert stored["deliver"] == "telegram,discord"
|
||||
|
||||
def test_update_normalizes_list_form_deliver(self):
|
||||
"""update with deliver=['telegram'] stores the canonical string."""
|
||||
from cron.jobs import get_job
|
||||
|
||||
created = json.loads(
|
||||
cronjob(action="create", prompt="x", schedule="every 1h")
|
||||
)
|
||||
updated = json.loads(
|
||||
cronjob(
|
||||
action="update",
|
||||
job_id=created["job_id"],
|
||||
deliver=["telegram"],
|
||||
)
|
||||
)
|
||||
assert updated["success"] is True
|
||||
stored = get_job(created["job_id"])
|
||||
assert stored["deliver"] == "telegram"
|
||||
|
||||
Reference in New Issue
Block a user