fix(telegram): ignore implicit topic root replies (#175)
This commit is contained in:
@@ -76,6 +76,11 @@ Explicit invocation includes any of:
|
|||||||
- Replying to a bot message.
|
- Replying to a bot message.
|
||||||
- Built-in or plugin slash commands (for example `/agent`, `/model`, `/reasoning`, `/file`, `/trigger`).
|
- Built-in or plugin slash commands (for example `/agent`, `/model`, `/reasoning`, `/file`, `/trigger`).
|
||||||
|
|
||||||
|
Note: In forum topics, some Telegram clients include `reply_to_message` on every
|
||||||
|
message, pointing at the topic’s root service message (`message_id ==
|
||||||
|
message_thread_id`). Takopi treats those as implicit topic references, not
|
||||||
|
explicit replies, so they do not trigger mentions-only mode.
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
|
|
||||||
- `/trigger` shows the current mode and defaults.
|
- `/trigger` shows the current mode and defaults.
|
||||||
|
|||||||
@@ -110,6 +110,11 @@ def _parse_incoming_message(
|
|||||||
media_group_id = msg.media_group_id
|
media_group_id = msg.media_group_id
|
||||||
thread_id = msg.message_thread_id
|
thread_id = msg.message_thread_id
|
||||||
is_topic_message = msg.is_topic_message
|
is_topic_message = msg.is_topic_message
|
||||||
|
if thread_id is not None and reply_to_message_id == thread_id:
|
||||||
|
reply_to_message_id = None
|
||||||
|
reply_to_text = None
|
||||||
|
reply_to_is_bot = None
|
||||||
|
reply_to_username = None
|
||||||
return TelegramIncomingMessage(
|
return TelegramIncomingMessage(
|
||||||
transport="telegram",
|
transport="telegram",
|
||||||
chat_id=msg_chat_id,
|
chat_id=msg_chat_id,
|
||||||
|
|||||||
@@ -43,12 +43,17 @@ def should_trigger_run(
|
|||||||
needle = f"@{bot_username}"
|
needle = f"@{bot_username}"
|
||||||
if needle in lowered:
|
if needle in lowered:
|
||||||
return True
|
return True
|
||||||
if msg.reply_to_is_bot:
|
implicit_topic_reply = (
|
||||||
|
msg.thread_id is not None and msg.reply_to_message_id == msg.thread_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if msg.reply_to_is_bot and not implicit_topic_reply:
|
||||||
return True
|
return True
|
||||||
if (
|
if (
|
||||||
bot_username
|
bot_username
|
||||||
and msg.reply_to_username
|
and msg.reply_to_username
|
||||||
and msg.reply_to_username.lower() == bot_username
|
and msg.reply_to_username.lower() == bot_username
|
||||||
|
and not implicit_topic_reply
|
||||||
):
|
):
|
||||||
return True
|
return True
|
||||||
command_id, _ = _parse_slash_command(text)
|
command_id, _ = _parse_slash_command(text)
|
||||||
|
|||||||
@@ -57,6 +57,34 @@ def test_parse_incoming_update_maps_fields() -> None:
|
|||||||
assert msg.raw["message_id"] == 10
|
assert msg.raw["message_id"] == 10
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_incoming_update_ignores_implicit_topic_reply() -> None:
|
||||||
|
update = Update(
|
||||||
|
update_id=1,
|
||||||
|
message=Message(
|
||||||
|
message_id=187,
|
||||||
|
message_thread_id=163,
|
||||||
|
is_topic_message=True,
|
||||||
|
text="Hello",
|
||||||
|
chat=Chat(id=123, type="supergroup", is_forum=True),
|
||||||
|
from_=User(id=99),
|
||||||
|
reply_to_message=MessageReply(
|
||||||
|
message_id=163,
|
||||||
|
from_=User(id=77, is_bot=True, username="TakopiBot"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = parse_incoming_update(update, chat_id=123)
|
||||||
|
assert msg is not None
|
||||||
|
assert isinstance(msg, TelegramIncomingMessage)
|
||||||
|
assert msg.thread_id == 163
|
||||||
|
assert msg.is_topic_message is True
|
||||||
|
assert msg.reply_to_message_id is None
|
||||||
|
assert msg.reply_to_text is None
|
||||||
|
assert msg.reply_to_is_bot is None
|
||||||
|
assert msg.reply_to_username is None
|
||||||
|
|
||||||
|
|
||||||
def test_parse_incoming_update_filters_non_matching_chat() -> None:
|
def test_parse_incoming_update_filters_non_matching_chat() -> None:
|
||||||
update = Update(
|
update = Update(
|
||||||
update_id=1,
|
update_id=1,
|
||||||
|
|||||||
@@ -83,6 +83,32 @@ def test_should_trigger_run_reply_to_bot() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_trigger_run_ignores_implicit_topic_reply_to_root() -> None:
|
||||||
|
runtime = _runtime()
|
||||||
|
msg = TelegramIncomingMessage(
|
||||||
|
transport="telegram",
|
||||||
|
chat_id=1,
|
||||||
|
message_id=187,
|
||||||
|
text="hello",
|
||||||
|
reply_to_message_id=163,
|
||||||
|
reply_to_text=None,
|
||||||
|
reply_to_is_bot=True,
|
||||||
|
reply_to_username="TakopiBot",
|
||||||
|
sender_id=1,
|
||||||
|
thread_id=163,
|
||||||
|
is_topic_message=True,
|
||||||
|
chat_type="supergroup",
|
||||||
|
is_forum=True,
|
||||||
|
)
|
||||||
|
assert not should_trigger_run(
|
||||||
|
msg,
|
||||||
|
bot_username=None,
|
||||||
|
runtime=runtime,
|
||||||
|
command_ids=set(),
|
||||||
|
reserved_chat_commands=set(RESERVED_CHAT_COMMANDS),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_should_trigger_run_known_commands() -> None:
|
def test_should_trigger_run_known_commands() -> None:
|
||||||
runtime = _runtime()
|
runtime = _runtime()
|
||||||
assert should_trigger_run(
|
assert should_trigger_run(
|
||||||
|
|||||||
Reference in New Issue
Block a user