Bug Description
Plugin approval buttons on Telegram don't work. There are two independent issues:
Issue 1: TelegramExecApprovalHandler missing plugin approval events
TelegramExecApprovalHandler.handleGatewayEvent() only handles exec.approval.requested/resolved, silently ignoring plugin.approval.requested/resolved. Discord's handler supports all four. Fix in PR #57340 commit 1.
Issue 2: Grammy runner sequentializer deadlocks callback_query processing
Even with the handler fix, clicking approval buttons does nothing. The @grammyjs/runner sequentializer processes all updates for a chat sequentially. When the agent turn is blocked waiting for approval, the callback_query from clicking the button is queued behind it at the runner level — the bot's callback handler never executes.
Exec approvals avoid this because they use a dedicated Unix socket (`exec-approvals.sock`), bypassing the Telegram update pipeline entirely.
Recommended fix: Add a pre-sequentializer middleware that intercepts approval `callback_query` updates (matching `APPROVE_CALLBACK_DATA_RE`) and resolves them directly via the gateway client, before they enter the per-chat sequential queue.
Steps to Reproduce
- Install a plugin that returns `requireApproval` from `before_tool_call` hook
- Configure `channels.telegram.execApprovals` with `enabled: true` and approver user ID
- Configure `approvals.plugin.enabled: true`
- Trigger a tool call that requires plugin approval via Telegram
- Click "Allow Once" button
Expected Behavior
Approval resolves immediately, tool proceeds.
Actual Behavior
- Button shows "loading" briefly, nothing happens
- Agent hangs until approval timeout (300s default)
- After timeout: tool is denied
Root Cause Analysis
Handler (Issue 1): `extensions/telegram/src/exec-approvals-handler.ts` line 361 — `handleGatewayEvent` only matches `exec.approval.*` events. Compare with Discord at `extensions/discord/src/monitor/exec-approvals.ts` line 665 which handles both.
Sequentializer (Issue 2): The Grammy runner queues all updates per chat. The agent message update holds the chat lock while waiting for approval. The callback_query for the same chat is queued behind it. Confirmed by adding a log at the very first line of the callback_query handler — it never executes during an active approval wait.
Environment
- OpenClaw: 2026.3.28
- Channel: Telegram (Bot API, Grammy + @grammyjs/runner)
- Plugin: ClawClip (returns `requireApproval` from `before_tool_call`)
Bug Description
Plugin approval buttons on Telegram don't work. There are two independent issues:
Issue 1: TelegramExecApprovalHandler missing plugin approval events
TelegramExecApprovalHandler.handleGatewayEvent()only handlesexec.approval.requested/resolved, silently ignoringplugin.approval.requested/resolved. Discord's handler supports all four. Fix in PR #57340 commit 1.Issue 2: Grammy runner sequentializer deadlocks callback_query processing
Even with the handler fix, clicking approval buttons does nothing. The
@grammyjs/runnersequentializer processes all updates for a chat sequentially. When the agent turn is blocked waiting for approval, thecallback_queryfrom clicking the button is queued behind it at the runner level — the bot's callback handler never executes.Exec approvals avoid this because they use a dedicated Unix socket (`exec-approvals.sock`), bypassing the Telegram update pipeline entirely.
Recommended fix: Add a pre-sequentializer middleware that intercepts approval `callback_query` updates (matching `APPROVE_CALLBACK_DATA_RE`) and resolves them directly via the gateway client, before they enter the per-chat sequential queue.
Steps to Reproduce
Expected Behavior
Approval resolves immediately, tool proceeds.
Actual Behavior
Root Cause Analysis
Handler (Issue 1): `extensions/telegram/src/exec-approvals-handler.ts` line 361 — `handleGatewayEvent` only matches `exec.approval.*` events. Compare with Discord at `extensions/discord/src/monitor/exec-approvals.ts` line 665 which handles both.
Sequentializer (Issue 2): The Grammy runner queues all updates per chat. The agent message update holds the chat lock while waiting for approval. The callback_query for the same chat is queued behind it. Confirmed by adding a log at the very first line of the callback_query handler — it never executes during an active approval wait.
Environment