fix(telegram): dedupe duplicate incoming messages (#198)

This commit is contained in:
banteg
2026-02-08 19:10:34 +04:00
committed by GitHub
parent b293818195
commit fb51708473
5 changed files with 298 additions and 141 deletions
+109
View File
@@ -1649,6 +1649,115 @@ async def test_run_main_loop_routes_reply_to_running_resume() -> None:
tg.cancel_scope.cancel()
@pytest.mark.anyio
async def test_run_main_loop_ignores_duplicate_message_id_for_replies() -> None:
transport = FakeTransport()
bot = FakeBot()
codex_runner = ScriptRunner([Return(answer="codex")], engine=CODEX_ENGINE)
claude_runner = ScriptRunner([Return(answer="claude")], engine="claude")
router = AutoRouter(
entries=[
RunnerEntry(engine=codex_runner.engine, runner=codex_runner),
RunnerEntry(engine=claude_runner.engine, runner=claude_runner),
],
default_engine=claude_runner.engine,
)
runtime = TransportRuntime(router=router, projects=_empty_projects())
cfg = TelegramBridgeConfig(
bot=bot,
runtime=runtime,
chat_id=123,
startup_msg="",
exec_cfg=ExecBridgeConfig(
transport=transport,
presenter=MarkdownPresenter(),
final_notify=True,
),
forward_coalesce_s=FAST_FORWARD_COALESCE_S,
media_group_debounce_s=FAST_MEDIA_GROUP_DEBOUNCE_S,
)
async def poller(_cfg: TelegramBridgeConfig):
yield TelegramIncomingMessage(
transport="telegram",
chat_id=123,
message_id=42,
text="turn on logging in my lemon config for me",
reply_to_message_id=900,
reply_to_text="done\n`codex resume c-123`",
sender_id=123,
chat_type="private",
)
# Telegram can occasionally redeliver the same message id with less reply metadata.
yield TelegramIncomingMessage(
transport="telegram",
chat_id=123,
message_id=42,
text="turn on logging in my lemon config for me",
reply_to_message_id=900,
reply_to_text=None,
sender_id=123,
chat_type="private",
)
await run_main_loop(cfg, poller)
assert len(codex_runner.calls) == 1
assert codex_runner.calls[0][1] == ResumeToken(engine=CODEX_ENGINE, value="c-123")
assert claude_runner.calls == []
@pytest.mark.anyio
async def test_run_main_loop_ignores_duplicate_update_id() -> None:
transport = FakeTransport()
bot = FakeBot()
runner = ScriptRunner([Return(answer="ok")], engine=CODEX_ENGINE)
runtime = TransportRuntime(router=_make_router(runner), projects=_empty_projects())
cfg = TelegramBridgeConfig(
bot=bot,
runtime=runtime,
chat_id=123,
startup_msg="",
exec_cfg=ExecBridgeConfig(
transport=transport,
presenter=MarkdownPresenter(),
final_notify=True,
),
forward_coalesce_s=FAST_FORWARD_COALESCE_S,
media_group_debounce_s=FAST_MEDIA_GROUP_DEBOUNCE_S,
)
async def poller(_cfg: TelegramBridgeConfig):
yield TelegramIncomingMessage(
transport="telegram",
chat_id=123,
message_id=1,
text="first",
reply_to_message_id=None,
reply_to_text=None,
sender_id=123,
chat_type="private",
update_id=9001,
)
# Same Telegram update id redelivered.
yield TelegramIncomingMessage(
transport="telegram",
chat_id=123,
message_id=2,
text="second",
reply_to_message_id=None,
reply_to_text=None,
sender_id=123,
chat_type="private",
update_id=9001,
)
await run_main_loop(cfg, poller)
assert len(runner.calls) == 1
assert runner.calls[0][0] == "first"
@pytest.mark.anyio
async def test_run_main_loop_persists_topic_sessions_in_project_scope(
tmp_path: Path,
+3
View File
@@ -55,6 +55,7 @@ def test_parse_incoming_update_maps_fields() -> None:
assert msg.document is None
assert msg.raw
assert msg.raw["message_id"] == 10
assert msg.update_id == 1
def test_parse_incoming_update_ignores_implicit_topic_reply() -> None:
@@ -83,6 +84,7 @@ def test_parse_incoming_update_ignores_implicit_topic_reply() -> None:
assert msg.reply_to_text is None
assert msg.reply_to_is_bot is None
assert msg.reply_to_username is None
assert msg.update_id == 1
def test_parse_incoming_update_filters_non_matching_chat() -> None:
@@ -295,6 +297,7 @@ def test_parse_incoming_update_callback_query() -> None:
assert msg.callback_query_id == "cbq-1"
assert msg.data == "takopi:cancel"
assert msg.sender_id == 321
assert msg.update_id == 1
def test_parse_incoming_update_topic_fields() -> None: