fix(cron): route Telegram cron deliveries to a dedicated topic via TELEGRAM_CRON_THREAD_ID

When Telegram topic mode is enabled, cron messages delivered to the bot's
root DM (TELEGRAM_HOME_CHANNEL without a thread id) land in the system
lobby — replies there are rebuffed with the lobby reminder and
reply_to_message_id is dropped, so users cannot interact with the cron
output (#24409).

Add an optional TELEGRAM_CRON_THREAD_ID env var that overrides
TELEGRAM_HOME_CHANNEL_THREAD_ID for cron deliveries only. Operators can
create a "Cron" forum topic in the DM, point this var at its thread id,
and replies to cron messages will land in that topic's existing session
instead of the lobby. The home-channel thread id (used elsewhere, e.g.
restart notifications) is unchanged, and explicit
deliver="telegram:chat:thread" targets continue to win over the env var.

Per the reporter's clarification on 2026-05-13, option (a) (cron-side
route to a dedicated topic + config knob) was chosen.

Fixes #24409
This commit is contained in:
konsisumer
2026-05-13 06:13:35 +02:00
committed by Teknium
parent 032d4cafc4
commit a4fb0a3ac3
7 changed files with 85 additions and 1 deletions

View File

@@ -243,6 +243,7 @@ _HERMES_BEHAVIORAL_VARS = frozenset({
"TELEGRAM_HOME_CHANNEL",
"TELEGRAM_HOME_CHANNEL_THREAD_ID",
"TELEGRAM_HOME_CHANNEL_NAME",
"TELEGRAM_CRON_THREAD_ID",
"DISCORD_HOME_CHANNEL",
"DISCORD_HOME_CHANNEL_THREAD_ID",
"DISCORD_HOME_CHANNEL_NAME",

View File

@@ -151,6 +151,53 @@ class TestResolveDeliveryTarget:
"thread_id": "topic-7",
}
def test_telegram_cron_thread_id_overrides_home_thread_id(self, monkeypatch):
"""TELEGRAM_CRON_THREAD_ID wins over TELEGRAM_HOME_CHANNEL_THREAD_ID for cron (#24409)."""
monkeypatch.setenv("TELEGRAM_HOME_CHANNEL", "-1001234567890")
monkeypatch.setenv("TELEGRAM_HOME_CHANNEL_THREAD_ID", "5")
monkeypatch.setenv("TELEGRAM_CRON_THREAD_ID", "42")
assert _resolve_delivery_target({"deliver": "telegram"}) == {
"platform": "telegram",
"chat_id": "-1001234567890",
"thread_id": "42",
}
def test_telegram_cron_thread_id_sets_thread_when_home_thread_unset(self, monkeypatch):
"""TELEGRAM_CRON_THREAD_ID supplies a thread when no home thread is configured."""
monkeypatch.setenv("TELEGRAM_HOME_CHANNEL", "-1001234567890")
monkeypatch.delenv("TELEGRAM_HOME_CHANNEL_THREAD_ID", raising=False)
monkeypatch.setenv("TELEGRAM_CRON_THREAD_ID", "42")
assert _resolve_delivery_target({"deliver": "telegram"}) == {
"platform": "telegram",
"chat_id": "-1001234567890",
"thread_id": "42",
}
def test_telegram_cron_thread_id_does_not_leak_to_other_platforms(self, monkeypatch):
"""TELEGRAM_CRON_THREAD_ID is Telegram-only; other platforms keep their own thread resolution."""
monkeypatch.setenv("DISCORD_HOME_CHANNEL", "parent-42")
monkeypatch.setenv("DISCORD_HOME_CHANNEL_THREAD_ID", "topic-7")
monkeypatch.setenv("TELEGRAM_CRON_THREAD_ID", "42")
assert _resolve_delivery_target({"deliver": "discord"}) == {
"platform": "discord",
"chat_id": "parent-42",
"thread_id": "topic-7",
}
def test_explicit_telegram_topic_target_overrides_cron_thread_id(self, monkeypatch):
"""Explicit ``telegram:chat:thread`` targets bypass TELEGRAM_CRON_THREAD_ID."""
monkeypatch.setenv("TELEGRAM_CRON_THREAD_ID", "999")
job = {"deliver": "telegram:-1003724596514:17"}
assert _resolve_delivery_target(job) == {
"platform": "telegram",
"chat_id": "-1003724596514",
"thread_id": "17",
}
def test_explicit_telegram_topic_target_with_thread_id(self):
"""deliver: 'telegram:chat_id:thread_id' parses correctly."""
job = {