From d0694788c930d943a336b6a431d9fd04a8170129 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 26 Feb 2026 02:24:45 +0100 Subject: [PATCH] fix: recover telegram polling after runner stop (#26447) (thanks @theclawdaddy) --- CHANGELOG.md | 1 + src/gateway/server-methods/agent.test.ts | 1 + src/telegram/monitor.test.ts | 24 ++++++++++++++++++++++++ src/telegram/monitor.ts | 8 +++----- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d71991f6a01..35759185d7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai ### Fixes - Agents/Subagents delivery: refactor subagent completion announce dispatch into an explicit queue/direct/fallback state machine, recover outbound channel-plugin resolution in cold/stale plugin-registry states across announce/message/gateway send paths, finalize cleanup bookkeeping when announce flow rejects, and treat Telegram sends without `message_id` as delivery failures (instead of false-success `"unknown"` IDs). (#26867, #25961, #26803, #25069, #26741) Thanks @SmithLabsLLC and @docaohieu2808. +- Telegram/Polling: keep the polling monitor alive when the grammY runner stops unexpectedly under an active gateway abort lifecycle, auto-restarting with backoff instead of exiting silently. (#26447) Thanks @theclawdaddy. - Slack/Session threads: prevent oversized parent-session inheritance from silently bricking new thread sessions, surface embedded context-overflow empty-result failures to users, and add configurable `session.parentForkMaxTokens` (default `100000`, `0` disables). (#26912) Thanks @markshields-tl. - Security/Signal: enforce DM/group authorization before reaction-only notification enqueue so unauthorized senders can no longer inject Signal reaction system events under `dmPolicy`/`groupPolicy`; reaction notifications now require channel access checks first. This ships in the next npm release (`2026.2.25`). Thanks @tdjackey for reporting. - Security/Discord + Slack reactions: enforce DM policy/allowlist authorization before reaction-event system enqueue in direct messages; Discord reaction handling now also honors DM/group-DM enablement and guild `groupPolicy` channel gating to keep reaction ingress aligned with normal message preflight. This ships in the next npm release (`2026.2.25`). Thanks @tdjackey for reporting. diff --git a/src/gateway/server-methods/agent.test.ts b/src/gateway/server-methods/agent.test.ts index 5d65d262735..c32f352904f 100644 --- a/src/gateway/server-methods/agent.test.ts +++ b/src/gateway/server-methods/agent.test.ts @@ -45,6 +45,7 @@ vi.mock("../../commands/agent.js", () => ({ vi.mock("../../config/config.js", () => ({ loadConfig: () => mocks.loadConfigReturn, + STATE_DIR: "/tmp/openclaw-test-state", })); vi.mock("../../agents/agent-scope.js", () => ({ diff --git a/src/telegram/monitor.test.ts b/src/telegram/monitor.test.ts index 49fbcc13155..533068b7bff 100644 --- a/src/telegram/monitor.test.ts +++ b/src/telegram/monitor.test.ts @@ -229,6 +229,30 @@ describe("monitorTelegramProvider (grammY)", () => { expect(runSpy).toHaveBeenCalledTimes(2); }); + it("restarts polling when runner stops unexpectedly under active abort signal", async () => { + const abort = new AbortController(); + runSpy + .mockImplementationOnce(() => ({ + task: () => Promise.resolve(), + stop: vi.fn(), + isRunning: (): boolean => false, + })) + .mockImplementationOnce(() => ({ + task: () => { + abort.abort(); + return Promise.resolve(); + }, + stop: vi.fn(), + isRunning: (): boolean => false, + })); + + await monitorTelegramProvider({ token: "tok", abortSignal: abort.signal }); + + expect(computeBackoff).toHaveBeenCalled(); + expect(sleepWithAbort).toHaveBeenCalled(); + expect(runSpy).toHaveBeenCalledTimes(2); + }); + it("deletes webhook before starting polling", async () => { const order: string[] = []; api.deleteWebhook.mockReset(); diff --git a/src/telegram/monitor.ts b/src/telegram/monitor.ts index 8c93eee60c9..9df609bdb82 100644 --- a/src/telegram/monitor.ts +++ b/src/telegram/monitor.ts @@ -45,10 +45,8 @@ export function createTelegramRunnerOptions(cfg: OpenClawConfig): RunOptions