fix(gemini): support native TTS generateContent endpoint
Pass Gemini AUDIO/TTS generateContent requests through to Google's native v1beta endpoint instead of converting to chat, with per-credential fallback (504 timeout, 502 fetch failure). Accept client keys from Bearer, x-goog-api-key, or ?key= while forwarding only the configured Gemini credential upstream. Expose native v1beta model names and rewrites, and add Gemini 3.1 Flash TTS to the catalogs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -38,7 +38,7 @@ const { proxy, __test__ } = await import("../../src/dashboardGuard.js");
|
||||
function request(pathname, headers = {}) {
|
||||
const normalizedHeaders = new Headers(headers);
|
||||
return {
|
||||
nextUrl: { pathname },
|
||||
nextUrl: { pathname, searchParams: new URL(`http://localhost${pathname}`).searchParams },
|
||||
headers: normalizedHeaders,
|
||||
cookies: { get: vi.fn(() => undefined) },
|
||||
url: `http://localhost${pathname}`,
|
||||
@@ -163,6 +163,29 @@ describe("dashboard guard public LLM API access", () => {
|
||||
expect(response).toBe(mocks.nextResponse);
|
||||
expect(mocks.validateApiKey).toHaveBeenCalledWith("sk-valid");
|
||||
});
|
||||
|
||||
it("allows remote beta public LLM API with valid Google API key header", async () => {
|
||||
mocks.validateApiKey.mockResolvedValue(true);
|
||||
|
||||
const response = await proxy(request("/v1beta/models", {
|
||||
host: "router.example.com",
|
||||
"x-goog-api-key": "sk-valid",
|
||||
}));
|
||||
|
||||
expect(response).toBe(mocks.nextResponse);
|
||||
expect(mocks.validateApiKey).toHaveBeenCalledWith("sk-valid");
|
||||
});
|
||||
|
||||
it("allows remote beta public LLM API with valid Google key query parameter", async () => {
|
||||
mocks.validateApiKey.mockResolvedValue(true);
|
||||
|
||||
const response = await proxy(request("/v1beta/models?key=sk-valid", {
|
||||
host: "router.example.com",
|
||||
}));
|
||||
|
||||
expect(response).toBe(mocks.nextResponse);
|
||||
expect(mocks.validateApiKey).toHaveBeenCalledWith("sk-valid");
|
||||
});
|
||||
});
|
||||
|
||||
describe("dashboard guard local-only access", () => {
|
||||
@@ -244,4 +267,13 @@ describe("dashboard guard helpers", () => {
|
||||
|
||||
expect(__test__.extractApiKey(apiRequest)).toBe("bearer-key");
|
||||
});
|
||||
|
||||
it("extracts Google API keys after x-api-key", () => {
|
||||
const apiRequest = request("/v1beta/models?key=query-key", {
|
||||
"x-api-key": "header-key",
|
||||
"x-goog-api-key": "google-key",
|
||||
});
|
||||
|
||||
expect(__test__.extractApiKey(apiRequest)).toBe("header-key");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user