From c813222671433760b18a8bfbfb66c247c9d5fdff Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 27 Mar 2026 20:54:00 +0000 Subject: [PATCH] fix(ci): support discord rate limit ctor drift --- .../discord/src/monitor/provider.test.ts | 17 +++++++++++- .../discord/src/send.creates-thread.test.ts | 27 +++++++++++++++---- extensions/discord/src/voice-message.ts | 27 +++++++++++++++---- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/extensions/discord/src/monitor/provider.test.ts b/extensions/discord/src/monitor/provider.test.ts index 97e6c2677b3..74d28cf7039 100644 --- a/extensions/discord/src/monitor/provider.test.ts +++ b/extensions/discord/src/monitor/provider.test.ts @@ -1,4 +1,5 @@ import { EventEmitter } from "node:events"; +import { RateLimitError } from "@buape/carbon"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { AcpRuntimeError } from "../../../../src/acp/runtime/errors.js"; import type { OpenClawConfig } from "../../../../src/config/config.js"; @@ -39,6 +40,19 @@ const { let monitorDiscordProvider: typeof import("./provider.js").monitorDiscordProvider; let providerTesting: typeof import("./provider.js").__testing; +function createCompatRateLimitError( + response: Response, + body: { message: string; retry_after: number; global: boolean }, + request?: Request, +): RateLimitError { + const RateLimitErrorCtor = RateLimitError as unknown as new ( + response: Response, + body: { message: string; retry_after: number; global: boolean }, + request?: Request, + ) => RateLimitError; + return new RateLimitErrorCtor(response, body, request); +} + function createConfigWithDiscordAccount(overrides: Record = {}): OpenClawConfig { return { channels: { @@ -626,7 +640,7 @@ describe("monitorDiscordProvider", () => { const request = new Request("https://discord.com/api/v10/applications/commands", { method: "PUT", }); - const rateLimitError = new RateLimitError( + const rateLimitError = createCompatRateLimitError( new Response(null, { status: 429, headers: { @@ -639,6 +653,7 @@ describe("monitorDiscordProvider", () => { retry_after: 193.632, global: false, }, + request, ); rateLimitError.discordCode = 30034; clientHandleDeployRequestMock.mockRejectedValueOnce(rateLimitError); diff --git a/extensions/discord/src/send.creates-thread.test.ts b/extensions/discord/src/send.creates-thread.test.ts index 2536f23498e..aaf07fdec7b 100644 --- a/extensions/discord/src/send.creates-thread.test.ts +++ b/extensions/discord/src/send.creates-thread.test.ts @@ -23,6 +23,19 @@ let timeoutMemberDiscord: typeof import("./send.js").timeoutMemberDiscord; let uploadEmojiDiscord: typeof import("./send.js").uploadEmojiDiscord; let uploadStickerDiscord: typeof import("./send.js").uploadStickerDiscord; +function createCompatRateLimitError( + response: Response, + body: { message: string; retry_after: number; global: boolean }, + request?: Request, +): RateLimitError { + const RateLimitErrorCtor = RateLimitError as unknown as new ( + response: Response, + body: { message: string; retry_after: number; global: boolean }, + request?: Request, + ) => RateLimitError; + return new RateLimitErrorCtor(response, body, request); +} + beforeAll(async () => { vi.resetModules(); ({ @@ -423,11 +436,15 @@ function createMockRateLimitError(retryAfter = 0.001): RateLimitError { "X-RateLimit-Bucket": "test-bucket", }, }); - return new RateLimitError(response, { - message: "You are being rate limited.", - retry_after: retryAfter, - global: false, - }); + return createCompatRateLimitError( + response, + { + message: "You are being rate limited.", + retry_after: retryAfter, + global: false, + }, + request, + ); } describe("retry rate limits", () => { diff --git a/extensions/discord/src/voice-message.ts b/extensions/discord/src/voice-message.ts index 6da3f7349d2..22fe268862c 100644 --- a/extensions/discord/src/voice-message.ts +++ b/extensions/discord/src/voice-message.ts @@ -29,6 +29,19 @@ const SUPPRESS_NOTIFICATIONS_FLAG = 1 << 12; const WAVEFORM_SAMPLES = 256; const DISCORD_OPUS_SAMPLE_RATE_HZ = 48_000; +function createRateLimitError( + response: Response, + body: { message: string; retry_after: number; global: boolean }, + request?: Request, +): RateLimitError { + const RateLimitErrorCtor = RateLimitError as unknown as new ( + response: Response, + body: { message: string; retry_after: number; global: boolean }, + request?: Request, + ) => RateLimitError; + return new RateLimitErrorCtor(response, body, request); +} + export type VoiceMessageMetadata = { durationSecs: number; waveform: string; // base64 encoded @@ -283,11 +296,15 @@ export async function sendDiscordVoiceMessage( retry_after?: number; global?: boolean; }; - throw new RateLimitError(res, { - message: retryData.message ?? "You are being rate limited.", - retry_after: retryData.retry_after ?? 1, - global: retryData.global ?? false, - }); + throw createRateLimitError( + res, + { + message: retryData.message ?? "You are being rate limited.", + retry_after: retryData.retry_after ?? 1, + global: retryData.global ?? false, + }, + uploadUrlRequest, + ); } const errorBody = (await res.json().catch(() => null)) as { code?: number;