fix: Discord read/search timeout, session-key fallback, and gateway execution mode#73521
fix: Discord read/search timeout, session-key fallback, and gateway execution mode#73521
Conversation
…xecution mode - Add 15s timeout to readMessagesDiscord and searchMessagesDiscord so they fail fast instead of hanging indefinitely (#73431) - Fall back to CommandTargetSessionKey in dispatchReplyFromConfig when SessionKey is empty, so Discord inbound message:received hooks fire reliably (#73431, refs #33038) - Add resolveExecutionMode to Discord channel actions routing read/search through gateway timeout path, matching Telegram's pattern (#73431)
Greptile SummaryThree targeted bug fixes: a 15 s REST timeout guard on Discord Confidence Score: 4/5Safe to merge; only P2 style feedback remains. No logic or correctness issues found. The single P2 note (real timers in hang-rejection tests adding ~30 s to CI) does not affect production behavior. Score is 4 per the P2-only ceiling. No files require special attention. Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/discord/src/send.messages.test.ts
Line: 27-34
Comment:
**Slow timeout tests use real timers**
Both hang-rejection tests use a real `setTimeout` (15 s) and set the Vitest timeout to `DISCORD_REST_ACTION_TIMEOUT_MS + 5_000` = 20 s each. This adds ~30 s to every CI run for two tests. Using `vi.useFakeTimers()` / `vi.runAllTimersAsync()` would make them instant and remove the large explicit timeout overrides.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix: Discord read/search timeout, sessio..." | Re-trigger Greptile |
| async () => { | ||
| restMock.get.mockReturnValueOnce(new Promise(() => {})); | ||
|
|
||
| await expect(readMessagesDiscord("C1", {}, { cfg: {} as never })).rejects.toThrow( | ||
| /Discord read timed out/, | ||
| ); | ||
| }, | ||
| DISCORD_REST_ACTION_TIMEOUT_MS + 5_000, |
There was a problem hiding this comment.
Slow timeout tests use real timers
Both hang-rejection tests use a real setTimeout (15 s) and set the Vitest timeout to DISCORD_REST_ACTION_TIMEOUT_MS + 5_000 = 20 s each. This adds ~30 s to every CI run for two tests. Using vi.useFakeTimers() / vi.runAllTimersAsync() would make them instant and remove the large explicit timeout overrides.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/discord/src/send.messages.test.ts
Line: 27-34
Comment:
**Slow timeout tests use real timers**
Both hang-rejection tests use a real `setTimeout` (15 s) and set the Vitest timeout to `DISCORD_REST_ACTION_TIMEOUT_MS + 5_000` = 20 s each. This adds ~30 s to every CI run for two tests. Using `vi.useFakeTimers()` / `vi.runAllTimersAsync()` would make them instant and remove the large explicit timeout overrides.
How can I resolve this? If you propose a fix, please make it concise.Inject AbortSignal.timeout into the Discord proxy-request-client fetch wrapper so every Discord REST call gets a 15s timeout at the HTTP level. This replaces the Promise.race wrapper in send.messages.ts — cleaner, covers all calls, and actually aborts the TCP connection.
|
Codex review: keeping this open for maintainer follow-up; there is still a little grit to resolve. Keep this PR open. It is maintainer-authored/protected ( Best possible solution: Keep this PR open for maintainer review. The best path is to revise or land the focused Discord regression fix for #73431, or explicitly supersede it with another PR that adds the same three pieces: Discord read/search timeout, gateway execution routing for read/search, and What I checked:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against c478aeca5a7f. |
…xecution mode (openclaw#73521) * fix: Discord read/search timeout, session-key fallback, and gateway execution mode - Add 15s timeout to readMessagesDiscord and searchMessagesDiscord so they fail fast instead of hanging indefinitely (openclaw#73431) - Fall back to CommandTargetSessionKey in dispatchReplyFromConfig when SessionKey is empty, so Discord inbound message:received hooks fire reliably (openclaw#73431, refs openclaw#33038) - Add resolveExecutionMode to Discord channel actions routing read/search through gateway timeout path, matching Telegram's pattern (openclaw#73431) * fix: move timeout to fetch layer, drop send.messages wrapper Inject AbortSignal.timeout into the Discord proxy-request-client fetch wrapper so every Discord REST call gets a 15s timeout at the HTTP level. This replaces the Promise.race wrapper in send.messages.ts — cleaner, covers all calls, and actually aborts the TCP connection. * fix: remove unused callerController variable in proxy-request-client test * fix: remove unnecessary mergeAbortSignal helper
Summary
Fixes #73431 — Discord
message readandmessage searchhang indefinitely, and Discord inboundmessage_received/inbound_claimhooks do not fire whenSessionKeyis empty.Three targeted fixes, no feature creep:
1. REST timeout on Discord read/search (
extensions/discord/src/send.messages.ts)readMessagesDiscordandsearchMessagesDiscordawaitedrest.get(...)with no timeout or abort signal. If the Discord API hung or was slow, the CLI hung forever with empty stdout.Added a 15-second
withRestTimeoutwrapper that races the promise against a timer and rejects with a structured error message.2. Session-key fallback for inbound hooks (
src/auto-reply/reply/dispatch-from-config.ts)The internal
message:receivedhook (line 722) is gated onsessionKeybeing truthy. The session key was read asctx.SessionKeywith no fallback — but Discord'sSessionKeyderivation can yield empty in edge cases (DMs, misconfigured channels, missing thread context).Now falls back to
ctx.CommandTargetSessionKeyvianormalizeOptionalString, matching the pattern already used byresolveSessionStoreLookupin the same file. This restores the intent of the closed-but-never-landed PR #33038.3.
resolveExecutionModeon Discord channel actions (extensions/discord/src/channel-actions.ts)Discord did not define
resolveExecutionMode, so all actions defaulted to"local"execution — bypassing the gateway's 10-second action timeout that Telegram gets automatically. Now routesreadandsearchthrough"gateway"mode for defense-in-depth.Testing
extensions/discord/src/send.messages.test.ts— verifies timeout behavior for both read and search (happy path + hang rejection)extensions/discord/src/channel-actions.test.ts— verifiesresolveExecutionModereturns"gateway"for read/search,"local"for other actionssrc/auto-reply/reply/dispatch-from-config.test.ts— verifiesCommandTargetSessionKeyfallback fires the internal hook whenSessionKeyis emptypnpm check:changedpasses all lanes (typecheck, lint, import cycles, guards)message read/searchhang indefinitely and Discord channel plugin does not emit standard inbound hooks (message_received/inbound_claim) — possible regression of #31264 / #33038 #73431Diff stats
5 files changed, 72 insertions(+), 3 deletions(-)
Supersedes the approach in #61572 which added ~1000 lines of tangential feature work (compact/raw detail modes, breaking legacy parameter changes) without addressing either root cause.