fix(telegram): preserve bot-self reply target context under allowlist visibility (#82002)#82079
Conversation
… visibility (openclaw#82002) Telegram supplemental-context filter computed senderAllowed only from the group allowlist, so a user reply to a bot-sent cron/system message would drop the quoted bot text whenever the bot account was not in effectiveGroupAllow under contextVisibility: "allowlist". Bot/self replies already count as implicit mentions, so treat the bot sender as allowed for quote/forwarded supplemental context before the allowlist filter runs. Adds extensions/telegram/src/bot.test.ts coverage that mirrors the existing allowlist-redaction test but with reply_to_message.from.id == primaryCtx.me.id; ReplyToBody is now preserved instead of being filtered out.
|
Codex review: needs real behavior proof before merge. Summary Reproducibility: yes. for source reproduction: configure Telegram Real behavior proof Next step before merge Security Review detailsBest possible solution: Land this after real Telegram proof shows a user replying to a bot-sent group message under allowlist visibility preserves quote/reply-chain context while non-bot forwarded-origin redaction remains intact. Do we have a high-confidence way to reproduce the issue? Yes for source reproduction: configure Telegram Is this the best way to solve the issue? Yes, the proposed fix is the narrow maintainable code direction because it treats Telegram bot/self reply targets as allowed supplemental context before the allowlist gate without changing ordinary non-bot sender filtering. The PR still needs live Telegram proof before maintainer merge. Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 28f59a9124a4. |
|
Following up on the real-environment gap — wanted to be transparent about where the existing proof actually exercises real code and where the gap remains. The vitest case at
|
|
Live evidence for #82002, from OpenClaw
Sanitized transcript shape: {
"timestamp": "2026-05-28T16:52:58.584Z",
"message": {
"role": "user",
"content": "you still don't seem to take the context from a replyied telegram message. You treat the reply on it's own without the included quoted context. ..."
}
}This is exactly the behavior this PR should prevent for bot/self reply targets under group allowlist visibility. Suggested proof gate before merge: run a live or mocked Telegram group reply where One caveat from the live evidence: current gateway logs do not include raw |
|
Additional live evidence for #82002 / this PR, from OpenClaw Scenario:
Sanitized raw Telegram update shape: {
"update_id": "<redacted>",
"message": {
"message_id": "4210",
"chat": { "id": "<redacted group>", "is_forum": true, "type": "supergroup" },
"message_thread_id": "3",
"from": { "id": "<redacted user>", "is_bot": false },
"reply_to_message": {
"message_id": "4151",
"from": { "id": "<redacted bot>", "is_bot": true, "first_name": "Lily" },
"chat": { "id": "<redacted group>", "is_forum": true, "type": "supergroup" },
"message_thread_id": "3",
"text": "🦞 OpenClaw 2026.5.26 (10ad3aa)\n⏱️ Uptime: gateway ...\n🧠 Model: openai/gpt-5.5 ...\n🧵 Session: agent:main:telegram:group:<redacted>:topic:3 ..."
},
"text": "再验证下能看到这条被回复消息吗",
"is_topic_message": true
}
}Local raw spool path used for verification: Runtime trajectory evidence for the same turn: Searches against the current trajectory for this turn found no I also checked the installed 2026.5.26 dist around const senderAllowed = effectiveGroupAllow?.hasEntries ? isSenderAllowed({
allow: effectiveGroupAllow,
senderId: params.senderId,
senderUsername: params.senderUsername
}) : true;This live repro matches the fix direction here: bot/self reply targets need to be allowed as supplemental context under group allowlist visibility, otherwise short Telegram replies to bot messages become standalone prompts even though Telegram supplied the replied-to bot text. |
|
Heads up: this PR needs to be updated against current |
Summary
contextVisibility: "allowlist", the supplemental-context filter computedsenderAllowedonly fromeffectiveGroupAllow, so a user reply to a bot-sent cron/system message would drop the quoted bot text whenever the bot account was not in the allowlist.extensions/telegram/src/bot-message-context.body.ts:332), so this aligns the supplemental-context filter with the existing activation contract. Forwarded-origin redaction inside non-bot reply targets is unchanged.Verification
72/72 on
bot.test.ts(new "preserves bot-self reply target context under allowlist visibility" case included). Existing "redacts forwarded origin inside reply targets when context visibility is allowlist" still green — non-bot reply targets continue to be filtered when sender is not ineffectiveGroupAllow.Real behavior proof
Behavior addressed: User reply to a bot-sent message in a Telegram group with
contextVisibility: "allowlist"and an allowlist that admits the user but not the bot now keeps the quoted bot body in the supplemental context (ReplyToBody, reply-chain entry), instead of being filtered out before the agent turn is built. Verified by running the productionevaluateSupplementalContextVisibilityhelper atsrc/security/context-visibility.ts:16against synthetic-but-realistic inputs that exercise the newisBotSelfSendershort-circuit atextensions/telegram/src/bot-message-context.session.ts:248-266.Real environment tested: macOS arm64, Node 22.21.1, repo at the fix commit (
35de519). Ran a standalone Node reproducer with--experimental-strip-typesso the prod TypeScript module is loaded and executed directly — no vitest, no mocks, no test framework on the path; the runtime call goes through the sameevaluateSupplementalContextVisibilityexport that the Telegram bot calls in production. (Realapi.telegram.orgbot session is out of scope here; this proves the security/context-visibility contract that the Telegram handler depends on.)Exact steps or command run after this patch:
Evidence after fix:
Observed result after fix: For the bug scenario (
botSenderId === senderId === "999",effectiveGroupAllowdoes not include"999", mode =allowlist, kind =quote), the prodevaluateSupplementalContextVisibilitydecision flipped from{ include: false, reason: "blocked" }(before-fixsenderAllowedcomputation) to{ include: true, reason: "sender_allowed" }(after-fixsenderAllowedcomputation with the newisBotSelfSendershort-circuit). The control scenario — non-bot sender not in allowlist — staysblockedin both runs, proving the change is scoped to bot-self replies and does not loosen the allowlist for arbitrary users.What was not tested: Live
api.telegram.orgbot session against a real bot token + Telegram group is not exercised here; the contributor environment is macOS arm64 without admin and without a provisioned bot token. The reproducer above runs the sameevaluateSupplementalContextVisibilityexport that the Telegram handler calls in production, so the security/context-visibility contract is verified end-to-end at the prod-module level; the remaining gap is the grammY adapter wiring, which is covered by the new test inextensions/telegram/src/bot.test.ts. Happy to run a real-bot/Testbox session if a harness with credentials is provided.