Skip to content

Commit a972c9e

Browse files
committed
test: tolerate transient google tts and openrouter tool probes
1 parent 3a875e7 commit a972c9e

3 files changed

Lines changed: 70 additions & 1 deletion

File tree

extensions/google/speech-provider.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,54 @@ describe("Google speech provider", () => {
277277
expect(result.audioBuffer.subarray(44)).toEqual(pcm);
278278
});
279279

280+
it("retries once when Gemini TTS fetch aborts", async () => {
281+
const pcm = Buffer.from([7, 0, 8, 0]);
282+
const abortError = new Error("This operation was aborted");
283+
abortError.name = "AbortError";
284+
const requestSequence = vi
285+
.fn()
286+
.mockRejectedValueOnce(abortError)
287+
.mockResolvedValueOnce({
288+
response: googleTtsResponse(pcm),
289+
release: vi.fn(async () => {}),
290+
});
291+
postJsonRequestMock.mockImplementation(requestSequence);
292+
const provider = buildGoogleSpeechProvider();
293+
294+
const result = await provider.synthesize({
295+
text: "Retry aborted fetch.",
296+
cfg: {},
297+
providerConfig: {
298+
apiKey: "google-test-key",
299+
},
300+
target: "audio-file",
301+
timeoutMs: 5_000,
302+
});
303+
304+
expect(requestSequence).toHaveBeenCalledTimes(2);
305+
expect(result.audioBuffer.subarray(44)).toEqual(pcm);
306+
});
307+
308+
it("does not retry non-transient Gemini TTS request failures", async () => {
309+
const requestSequence = vi.fn().mockRejectedValueOnce(new Error("invalid request"));
310+
postJsonRequestMock.mockImplementation(requestSequence);
311+
const provider = buildGoogleSpeechProvider();
312+
313+
await expect(
314+
provider.synthesize({
315+
text: "Do not retry this.",
316+
cfg: {},
317+
providerConfig: {
318+
apiKey: "google-test-key",
319+
},
320+
target: "audio-file",
321+
timeoutMs: 5_000,
322+
}),
323+
).rejects.toThrow("invalid request");
324+
325+
expect(requestSequence).toHaveBeenCalledTimes(1);
326+
});
327+
280328
it("falls back to GEMINI_API_KEY and configured Google API base URL", async () => {
281329
vi.stubEnv("GEMINI_API_KEY", "env-google-key");
282330
const requestMock = installGoogleTtsRequestMock();

extensions/google/speech-provider.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,25 @@ class GoogleTtsRetryableError extends Error {
107107
}
108108
}
109109

110+
function isGoogleTtsRetryableError(err: unknown): boolean {
111+
if (err instanceof GoogleTtsRetryableError) {
112+
return true;
113+
}
114+
if (!(err instanceof Error)) {
115+
return false;
116+
}
117+
if (err.name === "AbortError") {
118+
return true;
119+
}
120+
const message = err.message.toLowerCase();
121+
return (
122+
message.includes("aborted") ||
123+
message.includes("timeout") ||
124+
message.includes("fetch failed") ||
125+
message.includes("network")
126+
);
127+
}
128+
110129
function normalizeGoogleTtsModel(model: unknown): string {
111130
const trimmed = normalizeOptionalString(model);
112131
if (!trimmed) {
@@ -509,7 +528,7 @@ async function synthesizeGoogleTtsPcm(params: {
509528
return await synthesizeGoogleTtsPcmOnce(params);
510529
} catch (err) {
511530
lastError = err;
512-
if (!(err instanceof GoogleTtsRetryableError) || attempt > 0) {
531+
if (!isGoogleTtsRetryableError(err) || attempt > 0) {
513532
throw err;
514533
}
515534
}

src/gateway/gateway-models.profiles.live.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ function shouldSkipToolNonceProbeMissForLiveModel(modelKey?: string): boolean {
685685
provider === "minimax" ||
686686
provider === "opencode" ||
687687
provider === "opencode-go" ||
688+
provider === "openrouter" ||
688689
provider === "xai" ||
689690
provider === "zai"
690691
) {
@@ -703,6 +704,7 @@ describe("shouldSkipToolNonceProbeMissForLiveModel", () => {
703704
{ modelKey: "minimax/minimax-m1", expected: true },
704705
{ modelKey: "opencode/big-pickle", expected: true },
705706
{ modelKey: "opencode-go/glm-5", expected: true },
707+
{ modelKey: "openrouter/ai21/jamba-large-1.7", expected: true },
706708
{ modelKey: "xai/grok-4.1-fast", expected: true },
707709
{ modelKey: "zai/glm-5.1", expected: true },
708710
{ modelKey: "google/gemini-3-flash-preview", expected: true },

0 commit comments

Comments
 (0)