From 3379b9d341aab6ac425882442ae3955c5d11a910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BA=B7=E7=86=99?= Date: Mon, 16 Feb 2026 14:02:29 +0800 Subject: [PATCH] fix: support OAuth for Gemini embedding API Add parseGeminiAuth() to detect OAuth JSON format ({"token": "...", "projectId": "..."}) and use Bearer token authentication instead of x-goog-api-key header. This allows OAuth users (using gemini-cli-auth extension) to use memory_search with Gemini embedding API. --- src/memory/embeddings-gemini.ts | 37 +++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/memory/embeddings-gemini.ts b/src/memory/embeddings-gemini.ts index b4911163a4f..a1b16e5dc10 100644 --- a/src/memory/embeddings-gemini.ts +++ b/src/memory/embeddings-gemini.ts @@ -37,6 +37,39 @@ function resolveRemoteApiKey(remoteApiKey?: string): string | undefined { return trimmed; } +/** + * Parse Gemini API key and return appropriate auth headers. + * Supports both traditional API keys and OAuth JSON format. + * + * OAuth format: `{"token": "...", "projectId": "..."}` + */ +function parseGeminiAuth(apiKey: string): { headers: Record } { + // Try parsing as OAuth JSON format + if (apiKey.startsWith("{")) { + try { + const parsed = JSON.parse(apiKey) as { token?: string; projectId?: string }; + if (typeof parsed.token === "string" && parsed.token) { + return { + headers: { + Authorization: `Bearer ${parsed.token}`, + "Content-Type": "application/json", + }, + }; + } + } catch { + // Parse failed, fallback to API key mode + } + } + + // Default: traditional API key + return { + headers: { + "x-goog-api-key": apiKey, + "Content-Type": "application/json", + }, + }; +} + function normalizeGeminiModel(model: string): string { const trimmed = model.trim(); if (!trimmed) { @@ -150,9 +183,9 @@ export async function resolveGeminiEmbeddingClient( const rawBaseUrl = remoteBaseUrl || providerConfig?.baseUrl?.trim() || DEFAULT_GEMINI_BASE_URL; const baseUrl = normalizeGeminiBaseUrl(rawBaseUrl); const headerOverrides = Object.assign({}, providerConfig?.headers, remote?.headers); + const authHeaders = parseGeminiAuth(apiKey); const headers: Record = { - "Content-Type": "application/json", - "x-goog-api-key": apiKey, + ...authHeaders.headers, ...headerOverrides, }; const model = normalizeGeminiModel(options.model);