diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2a733ab1a..132d62ee495 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Telegram/Webhook: keep webhook monitors alive until gateway abort signals fire, preventing false channel exits and immediate webhook auto-restart loops. - Signal/RPC: guard malformed Signal RPC JSON responses with a clear status-scoped error and add regression coverage for invalid JSON responses. (#22995) Thanks @adhitShet. - Gateway/Subagents: guard gateway and subagent session-key/message trim paths against undefined inputs to prevent early `Cannot read properties of undefined (reading 'trim')` crashes during subagent spawn and wait flows. - Agents/Workspace: guard `resolveUserPath` against undefined/null input to prevent `Cannot read properties of undefined (reading 'trim')` crashes when workspace paths are missing in embedded runner flows. diff --git a/src/telegram/monitor.test.ts b/src/telegram/monitor.test.ts index 3e4b43ce2f7..ac0e834b32b 100644 --- a/src/telegram/monitor.test.ts +++ b/src/telegram/monitor.test.ts @@ -286,6 +286,25 @@ describe("monitorTelegramProvider (grammY)", () => { expect(runSpy).not.toHaveBeenCalled(); }); + it("webhook mode waits for abort signal before returning", async () => { + const abort = new AbortController(); + const settled = vi.fn(); + const monitor = monitorTelegramProvider({ + token: "tok", + useWebhook: true, + webhookUrl: "https://example.test/telegram", + webhookSecret: "secret", + abortSignal: abort.signal, + }).then(settled); + + await Promise.resolve(); + expect(settled).not.toHaveBeenCalled(); + + abort.abort(); + await monitor; + expect(settled).toHaveBeenCalledTimes(1); + }); + it("falls back to configured webhookSecret when not passed explicitly", async () => { await monitorTelegramProvider({ token: "tok", diff --git a/src/telegram/monitor.ts b/src/telegram/monitor.ts index 86cd6115de2..e90db5fde57 100644 --- a/src/telegram/monitor.ts +++ b/src/telegram/monitor.ts @@ -178,6 +178,15 @@ export async function monitorTelegramProvider(opts: MonitorTelegramOpts = {}) { abortSignal: opts.abortSignal, publicUrl: opts.webhookUrl, }); + if (opts.abortSignal && !opts.abortSignal.aborted) { + await new Promise((resolve) => { + const onAbort = () => { + opts.abortSignal?.removeEventListener("abort", onAbort); + resolve(); + }; + opts.abortSignal.addEventListener("abort", onAbort, { once: true }); + }); + } return; }