Skip to content

Fix Telegram plugin callback routing#97174

Merged
steipete merged 7 commits into
openclaw:mainfrom
goldmar:agent/fix-telegram-code-agent-callback-routing-main
Jul 1, 2026
Merged

Fix Telegram plugin callback routing#97174
steipete merged 7 commits into
openclaw:mainfrom
goldmar:agent/fix-telegram-code-agent-callback-routing-main

Conversation

@goldmar

@goldmar goldmar commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Telegram inline-button callbacks such as code-agent:<uuid> can fall through to the generic callback text path when the global plugin interactive handler state is empty, causing raw callback_data: code-agent:<uuid> messages to be sent instead of routing to the OpenClaw Code Agent plugin handler.

Why This Change Was Made

The fix restores plugin interactive handlers from the live plugin registry before reporting an interactive callback as unmatched, keeps the existing raw callback_data fallback for callbacks no plugin claims, and makes registry-stored interactive handlers participate in loader snapshot/restore rollback so failed plugin registration cannot leave executable handlers reachable.

User Impact

Telegram users pressing OpenClaw Code Agent inline buttons should get the intended plugin action, including button cleanup, instead of seeing raw callback data text in the chat. Failed plugin registration also no longer leaves stale interactive handlers available through the registry-backed recovery path.

Evidence

  • node scripts/run-vitest.mjs src/plugins/loader.test.ts -- -t "rolls back global side effects when registration fails"
  • node scripts/run-vitest.mjs src/plugins/interactive.test.ts extensions/telegram/src/bot.test.ts -- -t "restores active registry interactive handlers before reporting unmatched callbacks|routes code-agent callbacks to plugin handlers and clears original buttons"

Notes

This is the clean re-cut of the single task commit onto current origin/main, avoiding the release/2026.6.10 branch history that made the previous worktree appear thousands of commits ahead.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: telegram Channel integration: telegram triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. size: S labels Jun 27, 2026
@clawsweeper

clawsweeper Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 1, 2026, 2:46 PM ET / 18:46 UTC.

Summary
The PR updates plugin interactive registration and dispatch so Telegram callback data matching a live registry-owned plugin namespace routes to that plugin handler before the raw callback text fallback.

Reproducibility: yes. Current-main source can miss registry-backed plugin handlers and fall through to callback_data: text; the PR adds focused tests and has redacted Telegram Desktop/TDLib proof for the fixed path.

Review metrics: 2 noteworthy metrics.

  • Current-main merge result: 12 files affected. The raw 200-file PR list is stale-base noisy; the simulated current-main merge result is the useful reviewer surface.
  • Executable callback registry state: 1 registry-backed collection added. Interactive handler ownership changes, so rollback and stale-registry behavior matter before merge.

Stored data model
Persistent data-model change detected: persistent cache schema: docs/reference/prompt-caching.md, persistent cache schema: docs/reference/token-use.md, unknown-truncated-pull-files, vector/embedding metadata: docs/reference/token-use.md, vector/embedding metadata: ui/src/ui/controllers/cron.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Risk before merge

  • [P2] Merging changes Telegram callback precedence: registered plugin namespaces consume matching callback data before the generic raw callback_data: text fallback.
  • [P1] Exact current-head or current-main merge checks should be green before landing; some live check rollup entries were still in progress when inspected.

Maintainer options:

  1. Accept callback precedence after green checks (recommended)
    Land the current-main merge result if maintainers agree registered Telegram plugin callbacks should preempt raw fallback text and the refreshed checks pass.
  2. Pause for callback-boundary redesign
    Pause this PR if maintainers want plugin-looking callback payloads to keep reaching the generic text lane instead of plugin handlers.

Next step before merge

  • [P2] The remaining action is maintainer acceptance of the message-delivery precedence change plus refreshed current checks, not an automated repair.

Security
Cleared: No concrete security or supply-chain regression was found in the current-main merge-result callback/registry changes.

Review details

Best possible solution:

Land the narrowed current-main merge result once maintainers accept the callback precedence boundary and exact current-head/current-main checks are green.

Do we have a high-confidence way to reproduce the issue?

Yes. Current-main source can miss registry-backed plugin handlers and fall through to callback_data: text; the PR adds focused tests and has redacted Telegram Desktop/TDLib proof for the fixed path.

Is this the best way to solve the issue?

Yes. Resolving through live plugin registries keeps ownership at the plugin runtime boundary, avoids Telegram-specific plugin hardcoding, and avoids copying handlers back into stale global state.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 24ce672e06a8.

Label changes

Label justifications:

  • P1: The PR fixes a real Telegram inline-button workflow where plugin actions can be misdelivered as fallback chat text.
  • merge-risk: 🚨 message-delivery: The merge result changes whether Telegram callback data is consumed by plugin handlers or delivered to the chat as fallback text.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): Redacted Telegram Desktop/TDLib logs show after-fix real callback routing, button cleanup, plugin reply completion, and no raw fallback callback text.
  • proof: sufficient: Contributor real behavior proof is sufficient. Redacted Telegram Desktop/TDLib logs show after-fix real callback routing, button cleanup, plugin reply completion, and no raw fallback callback text.
  • mantis: telegram-visible-proof: Mantis should capture Telegram visible proof. This PR changes visible Telegram callback behavior and already includes useful Telegram Desktop/TDLib proof.
Evidence reviewed

What I checked:

  • Repository policy applied: Root and scoped AGENTS.md files were read; plugin registry ownership, Telegram callback proof, and message-delivery merge-risk guidance apply to this review. (AGENTS.md:1, 24ce672e06a8)
  • Current-main fallback path: Current main resolves plugin callbacks from the process-global interactive map only; if no match is found, Telegram callback data can continue to the raw callback_data: fallback text path. (src/plugins/interactive.ts:44, 24ce672e06a8)
  • Current-main merge result: A read-only merge simulation of current main 24ce672e with PR head d96c21d produced tree 6a106165; its diff is 12 files limited to Telegram docs/tests and plugin interactive registry/runtime files. (6a106165fa5b)
  • PR callback resolution: The merge result resolves non-global registry-owned handlers through live plugin registries, avoiding stale retired registries while letting live plugin namespaces claim matching callbacks. (src/plugins/interactive.ts:37, 6a106165fa5b)
  • Registry ownership and rollback: The registry stores successful interactive handler registrations and the loader snapshots/restores interactiveHandlers, covering rollback symmetry for failed plugin registration. (src/plugins/registry.ts:2863, 6a106165fa5b)
  • Focused regression coverage: The Telegram regression test registers a code-agent callback handler, clicks matching callback data, asserts the handler ran, clears buttons, and verifies no fallback reply was sent. (extensions/telegram/src/bot.create-telegram-bot.test.ts:1286, 6a106165fa5b)

Likely related people:

  • steipete: Assigned on this PR, authored the head follow-up commit refining registry-owned callback retirement, and has recent current-main plugin interactive/registry commits. (role: reviewer/adopter and recent area contributor; confidence: high; commits: d96c21d08451, d33664aef0b1, 7e3f345ee934; files: src/plugins/interactive.ts, src/plugins/interactive-registry.ts, src/plugins/registry.ts)
  • Vincent Koc: Recent history includes interactive callback dedupe/state refactors and Telegram handler work near this callback surface. (role: recent plugin interactive and Telegram contributor; confidence: high; commits: d1e3ed374398, 2e1ec9653c37, ba36291a8c8b; files: src/plugins/interactive.ts, src/plugins/interactive-registry.ts, extensions/telegram/src/bot-handlers.runtime.ts)
  • Alex Knight: Authored the live hook registry composition pattern adjacent to this PR's live registry callback lookup. (role: adjacent live-registry owner; confidence: medium; commits: 23eadfa27783; files: src/plugins/loader.ts, src/plugins/runtime.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jun 27, 2026
@goldmar
goldmar force-pushed the agent/fix-telegram-code-agent-callback-routing-main branch from 4dd6c35 to 9d3e68e Compare June 27, 2026 07:04
@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 27, 2026
@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. label Jun 27, 2026
@goldmar

goldmar commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@openclaw-mantis telegram desktop proof: verify code-agent Telegram callback buttons route to the plugin handler, clear buttons, and do not send fallback callback_data text.

@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts size: M and removed size: S labels Jul 1, 2026
@goldmar

goldmar commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Local Telegram Desktop proof for PR #97174 is complete. Sensitive Telegram identifiers are intentionally redacted from this public comment.

Environment:

  • Branch/commit used for proof: agent/fix-telegram-code-agent-callback-routing-main @ 8a2de26b56a
  • Runner: local Crabbox local-container, Debian 13 desktop, Telegram Desktop, real production Telegram supergroup
  • SUT gateway: disposable local gateway on this PR branch, loaded plugins telegram + telegram-code-agent-proof
  • QA actor: real Telegram user, redacted
  • QA group: real Telegram supergroup, redacted
  • SUT bot: redacted

What was verified:

  • A real Telegram Desktop user clicked an inline callback button whose callback data used the plugin-owned namespace code-agent:*.
  • TDLib getCallbackQueryAnswer returned ok for the click.
  • The PR branch routed the callback to the registered plugin handler instead of falling through to synthetic chat text.
  • The plugin handler completed clearButtons and reply through the Telegram response context.
  • TDLib search found the plugin proof replies and found no callback_data: fallback messages.

Final click artifact summary, redacted:

{
  "chatId": "<redacted-supergroup-id>",
  "messageId": "<redacted-tdlib-message-id>",
  "button": {
    "text": "Approve",
    "data": "<base64 callback data for code-agent:instrumented-proof-97174>"
  },
  "answer": {
    "@type": "callbackQueryAnswer",
    "show_alert": false,
    "text": "",
    "url": ""
  },
  "ok": true
}

Plugin handler marker for the same callback, redacted:

{"stage":"received","callbackId":"<redacted>","chatId":"<redacted-supergroup-id>","messageId":"<redacted-bot-message-id>","namespace":"code-agent","payload":"instrumented-proof-97174","senderId":"<redacted-qa-user-id>"}
{"stage":"clearButtons:ok","callbackId":"<redacted>","chatId":"<redacted-supergroup-id>","messageId":"<redacted-bot-message-id>","namespace":"code-agent","payload":"instrumented-proof-97174","senderId":"<redacted-qa-user-id>"}
{"stage":"reply:ok","callbackId":"<redacted>","chatId":"<redacted-supergroup-id>","messageId":"<redacted-bot-message-id>","namespace":"code-agent","payload":"instrumented-proof-97174","senderId":"<redacted-qa-user-id>"}
{"stage":"return","callbackId":"<redacted>","chatId":"<redacted-supergroup-id>","messageId":"<redacted-bot-message-id>","namespace":"code-agent","payload":"instrumented-proof-97174","senderId":"<redacted-qa-user-id>"}

TDLib search proof:

{
  "queries": [
    { "query": "PR #97174 proof handled", "count": 5 },
    { "query": "callback_data:", "count": 0 },
    { "query": "instrumented plugin handler", "count": 1 }
  ]
}

Validation run locally:

  • node scripts/run-vitest.mjs extensions/telegram/src/bot.create-telegram-bot.test.ts -> 112 tests passed
  • python3 -m py_compile scripts/e2e/telegram-user-driver.py -> passed
  • pnpm exec oxfmt --check scripts/e2e/telegram-user-crabbox-proof.ts extensions/telegram/src/bot.create-telegram-bot.test.ts qa/convex-credential-broker/convex/http.ts qa/convex-credential-broker/convex/payloadValidation.ts scripts/e2e/fixtures/telegram-code-agent-proof-plugin/index.cjs scripts/e2e/fixtures/telegram-code-agent-proof-plugin/openclaw.plugin.json -> passed
  • git diff --check -> passed

I also pushed follow-up coverage/tooling in 8a2de26b56a:

  • regression test covering plugin callback routing with no fallback callback_data text
  • TDLib click-callback support for real-user proof runs
  • proof fixture plugin registering code-agent for local E2E proof
  • local Crabbox/TDLib proof-run hardening discovered while setting up the zero-cost local-container path

@goldmar

goldmar commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jul 1, 2026
@steipete

steipete commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Land-ready after maintainer fixups.

  • Root cause/fix: interactive handlers registered during scoped plugin loads could disappear from the process-global map while the live gateway registry still owned them. Dispatch now resolves registry-owned handlers through live registries, while preserving direct process-global SDK registrations (src/plugins/interactive.ts:37, src/plugins/interactive-registry.ts:96, src/plugins/registry.ts:2864).
  • Lifecycle hardening: registry-owned handlers no longer survive registry retirement through the compatibility global map. The regression covers dispatch while live and no match after retirement (src/plugins/interactive.test.ts:652).
  • Best-fix judgment: yes. Ownership stays with the plugin registry instead of copying live handlers back into global state; this keeps cache/rollback behavior while avoiding stale executable handlers.
  • Scope cleanup: removed PR-only proof fixtures/driver changes, duplicate Telegram coverage, and unrelated QA/type edits from the landing diff.

Verification:

  • node scripts/run-vitest.mjs src/plugins/interactive.test.ts src/plugins/loader.test.ts extensions/telegram/src/bot.create-telegram-bot.test.ts — 297 tests passed.
  • pnpm docs:list — passed.
  • pnpm build — passed locally.
  • ../../node_modules/.bin/oxfmt --check docs/channels/telegram.md extensions/telegram/src/bot.create-telegram-bot.test.ts src/plugins/interactive-registry.ts src/plugins/interactive-shared.ts src/plugins/interactive-state.ts src/plugins/interactive.test.ts src/plugins/interactive.ts src/plugins/loader.test.ts src/plugins/loader.ts src/plugins/registry-empty.ts src/plugins/registry-types.ts src/plugins/registry.ts — passed.
  • git diff --check origin/main...HEAD — passed.
  • Fresh autoreview — clean, no accepted/actionable findings.
  • Exact prepared head: 657b6cd64e2ab0d13be94841e8d400abcf38bd43.
  • Exact-head hosted CI/Testbox: run 28539770964 — passed, including build, lint, production/test types, plugin/channel contracts, QA smoke, and all selected test shards.

The contributor's real Telegram Desktop proof on this PR remains the live user-path evidence. I did not repeat that external Telegram run after the lifecycle refactor; the focused retirement regression and exact-head hosted CI cover the maintainer changes.

@steipete
steipete merged commit 5db7c37 into openclaw:main Jul 1, 2026
96 checks passed
@steipete

steipete commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

liuhao1024 pushed a commit to liuhao1024/openclaw that referenced this pull request Jul 1, 2026
* fix telegram plugin callback routing

* Add Telegram callback proof coverage

* Fix proof script lint

* Fix Telegram proof CI regressions

* test: fix telegram callback proof CI regressions

* fix: retire registry-owned callbacks

* fix: retire registry-owned callbacks

---------

Co-authored-by: Peter Steinberger <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 2, 2026
* fix telegram plugin callback routing

* Add Telegram callback proof coverage

* Fix proof script lint

* Fix Telegram proof CI regressions

* test: fix telegram callback proof CI regressions

* fix: retire registry-owned callbacks

* fix: retire registry-owned callbacks

---------

Co-authored-by: Peter Steinberger <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
* fix telegram plugin callback routing

* Add Telegram callback proof coverage

* Fix proof script lint

* Fix Telegram proof CI regressions

* test: fix telegram callback proof CI regressions

* fix: retire registry-owned callbacks

* fix: retire registry-owned callbacks

---------

Co-authored-by: Peter Steinberger <[email protected]>
sheyanmin pushed a commit to sheyanmin/openclaw that referenced this pull request Jul 8, 2026
* fix telegram plugin callback routing

* Add Telegram callback proof coverage

* Fix proof script lint

* Fix Telegram proof CI regressions

* test: fix telegram callback proof CI regressions

* fix: retire registry-owned callbacks

* fix: retire registry-owned callbacks

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling app: ios App: ios app: macos App: macos app: web-ui App: web-ui channel: discord Channel integration: discord channel: feishu Channel integration: feishu channel: telegram Channel integration: telegram channel: whatsapp-web Channel integration: whatsapp-web cli CLI command changes commands Command implementations docs Improvements or additions to documentation extensions: codex extensions: inworld Extension: inworld extensions: memory-wiki extensions: opencode-go extensions: qa-lab gateway Gateway runtime mantis: telegram-visible-proof Mantis should capture Telegram visible proof. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. scripts Repository scripts size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants