Skip to content

Commit a39c2d7

Browse files
committed
fix(minimax): cap tts timeout delays
1 parent 0167f0a commit a39c2d7

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

extensions/minimax/tts.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime";
2+
import { afterEach, describe, expect, it, vi } from "vitest";
3+
4+
const fetchWithSsrFGuardMock = vi.hoisted(() => vi.fn());
5+
6+
vi.mock("openclaw/plugin-sdk/ssrf-runtime", async (importOriginal) => {
7+
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/ssrf-runtime")>();
8+
return {
9+
...actual,
10+
fetchWithSsrFGuard: (...args: unknown[]) => fetchWithSsrFGuardMock(...args),
11+
};
12+
});
13+
14+
import { minimaxTTS } from "./tts.js";
15+
16+
describe("minimaxTTS", () => {
17+
afterEach(() => {
18+
fetchWithSsrFGuardMock.mockReset();
19+
vi.restoreAllMocks();
20+
});
21+
22+
it("caps oversized request timeout before arming abort timers", async () => {
23+
const timeoutSpy = vi.spyOn(globalThis, "setTimeout");
24+
fetchWithSsrFGuardMock.mockResolvedValue({
25+
response: new Response(
26+
JSON.stringify({ data: { audio: Buffer.from("audio").toString("hex") } }),
27+
{ status: 200, headers: { "content-type": "application/json" } },
28+
),
29+
release: vi.fn(async () => undefined),
30+
});
31+
32+
const audio = await minimaxTTS({
33+
text: "hello",
34+
apiKey: "sk-test",
35+
baseUrl: "https://api.minimax.io",
36+
model: "speech-2.8-hd",
37+
voiceId: "English_expressive_narrator",
38+
timeoutMs: Number.MAX_SAFE_INTEGER,
39+
});
40+
41+
expect(audio.toString()).toBe("audio");
42+
expect(timeoutSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS);
43+
expect(fetchWithSsrFGuardMock.mock.calls[0]?.[0]).toMatchObject({
44+
timeoutMs: MAX_TIMER_TIMEOUT_MS,
45+
});
46+
expect(fetchWithSsrFGuardMock.mock.calls[0]?.[0]?.init?.signal).toBeInstanceOf(AbortSignal);
47+
});
48+
});

extensions/minimax/tts.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { clampTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
12
import { assertOkOrThrowProviderError } from "openclaw/plugin-sdk/provider-http";
23
import {
34
fetchWithSsrFGuard,
@@ -64,9 +65,10 @@ export async function minimaxTTS(params: {
6465
sampleRate = 32000,
6566
timeoutMs,
6667
} = params;
68+
const safeTimeoutMs = clampTimerTimeoutMs(timeoutMs) ?? 1;
6769

6870
const controller = new AbortController();
69-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
71+
const timeout = setTimeout(() => controller.abort(), safeTimeoutMs);
7072

7173
try {
7274
const { response, release } = await fetchWithSsrFGuard({
@@ -93,7 +95,7 @@ export async function minimaxTTS(params: {
9395
}),
9496
signal: controller.signal,
9597
},
96-
timeoutMs,
98+
timeoutMs: safeTimeoutMs,
9799
policy: ssrfPolicyFromHttpBaseUrlAllowedHostname(baseUrl),
98100
auditContext: "minimax.tts",
99101
});

0 commit comments

Comments
 (0)