From 343e5d7a37aceca2917d1d01644b785a1bd2d841 Mon Sep 17 00:00:00 2001 From: chilung Date: Sat, 15 Aug 2026 13:41:21 +0800 Subject: [PATCH 1/6] fix(google): allow direct Gemini wire rename opt-out Keep the existing -tiered mapping by default while allowing AI Studio providers that still serve bare Gemini Flash ids to opt out. Cover both Flash generations and document the provider setting. --- .../docs/reference/configuration/providers.md | 1 + src/adapters/google.ts | 14 +++++----- src/config.ts | 1 + src/types.ts | 6 +++++ tests/google-adapter.test.ts | 26 +++++++++++++++++++ 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 2743d81961..e522fe2a4e 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -122,6 +122,7 @@ differing backup and rewrites known legacy namespaced selected ids to bare ids. | `escapeBuiltinToolNames?` | `boolean` | Escape built-in tool names for Anthropic-compatible gateways and restore them in returned calls. | | `anthropicEofTolerance?` | `boolean` | Let an Anthropic-compatible gateway complete a stream that ends before `message_stop`, only when visible text or a complete JSON-object tool input was received. Off by default. | | `googleMode?` | `"ai-studio" \| "vertex" \| "cloud-code-assist"` | Google transport/auth mode. Default `ai-studio`. | +| `directGeminiWireRenames?` | `boolean` | Google only. When `false`, the AI Studio (direct) path sends Gemini Flash ids to the wire unchanged instead of applying the `-tiered` suffix (`gemini-3.7-flash` -> `gemini-3.7-flash-tiered`). Defaults to the rename; set `false` when the configured upstream still serves the bare ids. | | `project?` | `string` | Vertex or Antigravity Cloud Code Assist project id. | | `location?` | `string` | Vertex location; environment fallback is `GOOGLE_CLOUD_LOCATION`. | | `mcpServers?` | `Record` | Cursor only: stdio or Streamable HTTP MCP servers. | diff --git a/src/adapters/google.ts b/src/adapters/google.ts index ab27089e7d..d19edc1291 100644 --- a/src/adapters/google.ts +++ b/src/adapters/google.ts @@ -48,19 +48,17 @@ const GOOGLE_BREVITY_INSTRUCTION = [ ].join("\n"); /** - * Google renamed the current Gemini Flash generations on the Generative Language API, - * appending a `-tiered` suffix (`gemini-3.7-flash` -> `gemini-3.7-flash-tiered`). The - * old `gemini-3.7-flash` path 404s, so a saved config or registry entry naming the base - * id must be resolved here before it reaches the URL. The user-facing id is deliberately - * left alone: the picker, the catalog, the usage log and the price overlays all stay - * keyed on the base id, and only the wire path learns the new spelling. + * Some Google direct deployments expose current Gemini Flash generations with a `-tiered` + * wire suffix (`gemini-3.7-flash` -> `gemini-3.7-flash-tiered`). Keep the picker-visible id + * stable and make the mapping configurable for deployments that still serve the bare id. */ const GEMINI_DIRECT_WIRE_RENAMES: Record = { "gemini-3.7-flash": "gemini-3.7-flash-tiered", "gemini-3.6-flash": "gemini-3.6-flash-tiered", }; -function resolveDirectGeminiWireModelId(modelId: string): string { +function resolveDirectGeminiWireModelId(modelId: string, applyRenames: boolean): string { + if (!applyRenames) return modelId; return Object.hasOwn(GEMINI_DIRECT_WIRE_RENAMES, modelId) ? GEMINI_DIRECT_WIRE_RENAMES[modelId]! : modelId; @@ -396,7 +394,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte parsed.modelId, mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning), ).wireModelId - : resolveDirectGeminiWireModelId(parsed.modelId); + : resolveDirectGeminiWireModelId(parsed.modelId, provider.directGeminiWireRenames !== false); const { systemInstruction, contents } = messagesToGeminiFormat(parsed, routedModelId); const tools = toolsToGeminiFormat(parsed); diff --git a/src/config.ts b/src/config.ts index d4c0a3a0f3..d879195e88 100644 --- a/src/config.ts +++ b/src/config.ts @@ -741,6 +741,7 @@ const providerConfigSchema = z.object({ upstreamHttpVersion: z.enum(UPSTREAM_HTTP_VERSION_VALUES) .nullish() .transform(value => value ?? undefined), + directGeminiWireRenames: z.boolean().optional(), noStructuredOutputModels: z.array(z.string().min(1)) .transform(normalizeNonBlankStringArray) .optional(), diff --git a/src/types.ts b/src/types.ts index 565118b287..ea0f526e2a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1394,6 +1394,12 @@ export interface OcxProviderConfig { * (current behavior unchanged). Only meaningful for https: base URLs. */ upstreamHttpVersion?: UpstreamHttpVersion; + * Google only. When `false`, the AI Studio (direct) path sends Gemini Flash ids + * unchanged to the wire instead of applying the `-tiered` suffix (`gemini-3.7-flash` + * -> `gemini-3.7-flash-tiered`). Set this to `false` when the configured upstream still + * serves the bare ids. Absent (default) keeps the rename. + */ + directGeminiWireRenames?: boolean; /** Keep provider settings on disk but exclude it from routing and model/catalog listings. */ disabled?: boolean; /** diff --git a/tests/google-adapter.test.ts b/tests/google-adapter.test.ts index 467cf19c37..076f746b57 100644 --- a/tests/google-adapter.test.ts +++ b/tests/google-adapter.test.ts @@ -278,3 +278,29 @@ describe("google adapter — tool_choice on the wire", () => { }); }); }); + +describe("google adapter — direct -tiered wire renames", () => { + function renamedParsed(modelId: string): OcxParsedRequest { + return { + modelId, + stream: false, + options: {}, + context: { messages: [{ role: "user", content: "hi" }], tools: [] }, + } as unknown as OcxParsedRequest; + } + + test("default maps the picker id to the -tiered wire id", async () => { + for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { + const { url } = await createGoogleAdapter(provider).buildRequest(renamedParsed(modelId)); + expect(url).toContain(`/v1beta/models/${modelId}-tiered:generateContent`); + } + }); + + test("directGeminiWireRenames: false keeps the bare wire id", async () => { + const adapter = createGoogleAdapter({ ...provider, directGeminiWireRenames: false }); + for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { + const { url } = await adapter.buildRequest(renamedParsed(modelId)); + expect(url).toContain(`/v1beta/models/${modelId}:generateContent`); + } + }); +}); From d62cc402992df3f6bb6c058dc924f4eca8215bc3 Mon Sep 17 00:00:00 2001 From: chilung Date: Sat, 15 Aug 2026 14:33:22 +0800 Subject: [PATCH 2/6] fix(google): scope direct Gemini rename opt-out --- src/adapters/google.ts | 4 +++- tests/config.test.ts | 32 ++++++++++++++++++++++++++++++++ tests/google-adapter.test.ts | 12 ++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/adapters/google.ts b/src/adapters/google.ts index d19edc1291..ccd5ba9579 100644 --- a/src/adapters/google.ts +++ b/src/adapters/google.ts @@ -394,7 +394,9 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte parsed.modelId, mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning), ).wireModelId - : resolveDirectGeminiWireModelId(parsed.modelId, provider.directGeminiWireRenames !== false); + : provider.googleMode === "vertex" + ? parsed.modelId + : resolveDirectGeminiWireModelId(parsed.modelId, provider.directGeminiWireRenames !== false); const { systemInstruction, contents } = messagesToGeminiFormat(parsed, routedModelId); const tools = toolsToGeminiFormat(parsed); diff --git a/tests/config.test.ts b/tests/config.test.ts index b949b9bd8b..c67ff8846d 100644 --- a/tests/config.test.ts +++ b/tests/config.test.ts @@ -814,6 +814,38 @@ describe("opencodex config defaults", () => { expect(readConfigDiagnostics().error).toContain("responsesSnapshotRepair"); }); + test("direct Gemini wire rename opt-out is a boolean and round-trips", () => { + const base = { + port: 12345, + providers: { + google: { + adapter: "google", + baseUrl: "https://generativelanguage.googleapis.com", + }, + }, + defaultProvider: "google", + }; + writeConfig({ + ...base, + providers: { + google: { ...base.providers.google, directGeminiWireRenames: false }, + }, + }); + const config = loadConfig(); + expect(config.providers.google.directGeminiWireRenames).toBe(false); + saveConfig(config); + expect(loadConfig().providers.google.directGeminiWireRenames).toBe(false); + + writeConfig({ + ...base, + providers: { + google: { ...base.providers.google, directGeminiWireRenames: "false" }, + }, + }); + expect(readConfigDiagnostics().source).toBe("fallback"); + expect(readConfigDiagnostics().error).toContain("directGeminiWireRenames"); + }); + test("accepts a relative responsesPath", () => { writeResponsesPathConfig("/responses"); diff --git a/tests/google-adapter.test.ts b/tests/google-adapter.test.ts index 076f746b57..e24b113ec6 100644 --- a/tests/google-adapter.test.ts +++ b/tests/google-adapter.test.ts @@ -303,4 +303,16 @@ describe("google adapter — direct -tiered wire renames", () => { expect(url).toContain(`/v1beta/models/${modelId}:generateContent`); } }); + + test("directGeminiWireRenames does not affect Vertex requests", async () => { + const vertexProvider = { ...provider, googleMode: "vertex" as const }; + for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { + const parsed = renamedParsed(modelId); + const defaultRequest = await createGoogleAdapter(vertexProvider).buildRequest(parsed); + const optOutRequest = await createGoogleAdapter({ ...vertexProvider, directGeminiWireRenames: false }) + .buildRequest(parsed); + expect(optOutRequest.url).toBe(defaultRequest.url); + expect(optOutRequest.body).toBe(defaultRequest.body); + } + }); }); From 812255d3a2f3efe40033b8ed62ed494d442fe573 Mon Sep 17 00:00:00 2001 From: chilung Date: Sat, 15 Aug 2026 22:10:56 +0800 Subject: [PATCH 3/6] fix(google): use public model id in system identity; cover rename opt-out - identifyRoutedModel now names parsed.modelId so a -tiered wire rename never leaks into the system prompt identity (CodeRabbit finding) - document that directGeminiWireRenames affects only AI Studio direct requests; Vertex and Cloud Code Assist are unchanged - add adapter tests for explicit true and Cloud Code Assist opt-out --- .../docs/reference/configuration/providers.md | 2 +- src/adapters/google.ts | 11 ++++---- tests/google-adapter.test.ts | 28 +++++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index e522fe2a4e..7cf4710497 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -122,7 +122,7 @@ differing backup and rewrites known legacy namespaced selected ids to bare ids. | `escapeBuiltinToolNames?` | `boolean` | Escape built-in tool names for Anthropic-compatible gateways and restore them in returned calls. | | `anthropicEofTolerance?` | `boolean` | Let an Anthropic-compatible gateway complete a stream that ends before `message_stop`, only when visible text or a complete JSON-object tool input was received. Off by default. | | `googleMode?` | `"ai-studio" \| "vertex" \| "cloud-code-assist"` | Google transport/auth mode. Default `ai-studio`. | -| `directGeminiWireRenames?` | `boolean` | Google only. When `false`, the AI Studio (direct) path sends Gemini Flash ids to the wire unchanged instead of applying the `-tiered` suffix (`gemini-3.7-flash` -> `gemini-3.7-flash-tiered`). Defaults to the rename; set `false` when the configured upstream still serves the bare ids. | +| `directGeminiWireRenames?` | `boolean` | Google only. This affects only direct AI Studio requests. When `false`, the AI Studio path sends Gemini Flash ids to the wire unchanged instead of applying the `-tiered` suffix (`gemini-3.7-flash` -> `gemini-3.7-flash-tiered`). Vertex preserves the requested model ID, and Cloud Code Assist routing is unchanged. Defaults to the rename; set `false` when the configured upstream still serves the bare ids. | | `project?` | `string` | Vertex or Antigravity Cloud Code Assist project id. | | `location?` | `string` | Vertex location; environment fallback is `GOOGLE_CLOUD_LOCATION`. | | `mcpServers?` | `Record` | Cursor only: stdio or Streamable HTTP MCP servers. | diff --git a/src/adapters/google.ts b/src/adapters/google.ts index ccd5ba9579..0b7df429ec 100644 --- a/src/adapters/google.ts +++ b/src/adapters/google.ts @@ -143,10 +143,7 @@ function geminiToolResultText(content: string | OcxContentPart[]): string { return hasContent ? contentPartsToText(content) : GEMINI_EMPTY_TOOL_OUTPUT_PLACEHOLDER; } -function messagesToGeminiFormat( - parsed: OcxParsedRequest, - routedModelId = parsed.modelId, -): { systemInstruction?: unknown; contents: unknown[] } { +function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?: unknown; contents: unknown[] } { // Neutralize Codex's GPT-5 identity line (Gemini/Antigravity share this path) so a routed model // never misreports as GPT-5/OpenAI, and never leaks the proxy identity upstream. const toolCatalogNudge = buildNonOpenAIToolCatalogNudgeForTools(parsed.context.tools, parsed.options.toolChoice); @@ -154,7 +151,7 @@ function messagesToGeminiFormat( ...(parsed.context.systemPrompt ?? []), ...(toolCatalogNudge ? [toolCatalogNudge] : []), GOOGLE_BREVITY_INSTRUCTION, - ].join("\n\n"), routedModelId); + ].join("\n\n"), parsed.modelId); const systemInstruction = { parts: [{ text: systemText }] }; const contents: unknown[] = []; @@ -397,7 +394,9 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte : provider.googleMode === "vertex" ? parsed.modelId : resolveDirectGeminiWireModelId(parsed.modelId, provider.directGeminiWireRenames !== false); - const { systemInstruction, contents } = messagesToGeminiFormat(parsed, routedModelId); + // System identity names the public model id (parsed.modelId) so the model never + // self-reports as its -tiered wire spelling; routedModelId is only the wire id in the URL. + const { systemInstruction, contents } = messagesToGeminiFormat(parsed); const tools = toolsToGeminiFormat(parsed); const body: Record = { contents }; diff --git a/tests/google-adapter.test.ts b/tests/google-adapter.test.ts index e24b113ec6..a7e64bc8e6 100644 --- a/tests/google-adapter.test.ts +++ b/tests/google-adapter.test.ts @@ -304,6 +304,34 @@ describe("google adapter — direct -tiered wire renames", () => { } }); + test("directGeminiWireRenames: true still maps to the -tiered wire id", async () => { + const adapter = createGoogleAdapter({ ...provider, directGeminiWireRenames: true }); + for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { + const { url } = await adapter.buildRequest(renamedParsed(modelId)); + expect(url).toContain(`/v1beta/models/${modelId}-tiered:generateContent`); + } + }); + + test("directGeminiWireRenames does not affect Cloud Code Assist requests", async () => { + const ccaProvider = { + ...provider, + googleMode: "cloud-code-assist", + baseUrl: "https://daily-cloudcode-pa.googleapis.com", + project: "proj-123", + } as const; + for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { + const parsed = renamedParsed(modelId); + const defaultRequest = await createGoogleAdapter(ccaProvider).buildRequest(parsed); + const optOutRequest = await createGoogleAdapter({ ...ccaProvider, directGeminiWireRenames: false }) + .buildRequest(parsed); + expect(optOutRequest.url).toBe(defaultRequest.url); + // The envelope's requestId/sessionId are minted per request; compare the wire model only. + const defaultModel = JSON.parse(defaultRequest.body).model as string; + const optOutModel = JSON.parse(optOutRequest.body).model as string; + expect(optOutModel).toBe(defaultModel); + } + }); + test("directGeminiWireRenames does not affect Vertex requests", async () => { const vertexProvider = { ...provider, googleMode: "vertex" as const }; for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { From 8ae045144772054044cf286d8d2dc6e73569c256 Mon Sep 17 00:00:00 2001 From: chilung Date: Sun, 16 Aug 2026 10:29:57 +0800 Subject: [PATCH 4/6] test(google): complete Gemini rename review coverage --- .../docs/reference/configuration/providers.md | 2 +- tests/google-adapter.test.ts | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 7cf4710497..2ba92c2b26 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -122,7 +122,7 @@ differing backup and rewrites known legacy namespaced selected ids to bare ids. | `escapeBuiltinToolNames?` | `boolean` | Escape built-in tool names for Anthropic-compatible gateways and restore them in returned calls. | | `anthropicEofTolerance?` | `boolean` | Let an Anthropic-compatible gateway complete a stream that ends before `message_stop`, only when visible text or a complete JSON-object tool input was received. Off by default. | | `googleMode?` | `"ai-studio" \| "vertex" \| "cloud-code-assist"` | Google transport/auth mode. Default `ai-studio`. | -| `directGeminiWireRenames?` | `boolean` | Google only. This affects only direct AI Studio requests. When `false`, the AI Studio path sends Gemini Flash ids to the wire unchanged instead of applying the `-tiered` suffix (`gemini-3.7-flash` -> `gemini-3.7-flash-tiered`). Vertex preserves the requested model ID, and Cloud Code Assist routing is unchanged. Defaults to the rename; set `false` when the configured upstream still serves the bare ids. | +| `directGeminiWireRenames?` | `boolean` | Google only. Applies only to direct AI Studio requests. Omitted or `true` keeps the `-tiered` wire rename for Gemini Flash ids (`gemini-3.7-flash` -> `gemini-3.7-flash-tiered`); `false` sends the requested bare ids to the wire unchanged. Vertex preserves the requested model ID, and Cloud Code Assist routing is unchanged. Set `false` when the configured upstream still serves the bare ids. | | `project?` | `string` | Vertex or Antigravity Cloud Code Assist project id. | | `location?` | `string` | Vertex location; environment fallback is `GOOGLE_CLOUD_LOCATION`. | | `mcpServers?` | `Record` | Cursor only: stdio or Streamable HTTP MCP servers. | diff --git a/tests/google-adapter.test.ts b/tests/google-adapter.test.ts index a7e64bc8e6..59a3a19bb7 100644 --- a/tests/google-adapter.test.ts +++ b/tests/google-adapter.test.ts @@ -289,6 +289,19 @@ describe("google adapter — direct -tiered wire renames", () => { } as unknown as OcxParsedRequest; } + function identityParsed(modelId: string): OcxParsedRequest { + return { + modelId, + stream: false, + options: {}, + context: { + systemPrompt: ["You are Codex, a coding agent based on GPT-5."], + messages: [{ role: "user", content: "hi" }], + tools: [], + }, + } as unknown as OcxParsedRequest; + } + test("default maps the picker id to the -tiered wire id", async () => { for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { const { url } = await createGoogleAdapter(provider).buildRequest(renamedParsed(modelId)); @@ -307,8 +320,15 @@ describe("google adapter — direct -tiered wire renames", () => { test("directGeminiWireRenames: true still maps to the -tiered wire id", async () => { const adapter = createGoogleAdapter({ ...provider, directGeminiWireRenames: true }); for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { - const { url } = await adapter.buildRequest(renamedParsed(modelId)); + const request = await adapter.buildRequest(identityParsed(modelId)); + const { url } = request; expect(url).toContain(`/v1beta/models/${modelId}-tiered:generateContent`); + const body = JSON.parse(request.body) as { + systemInstruction?: { parts?: Array<{ text?: string }> }; + }; + const systemText = body.systemInstruction?.parts?.[0]?.text ?? ""; + expect(systemText).toContain(`powered by the ${modelId}`); + expect(systemText).not.toContain(`${modelId}-tiered`); } }); From f6c88febfa8faedc6a52ef2fed69fa0175369537 Mon Sep 17 00:00:00 2001 From: chilung Date: Sun, 16 Aug 2026 12:31:07 +0800 Subject: [PATCH 5/6] fix(google): preserve routed identity for CCA aliases --- src/adapters/google.ts | 13 ++++++++----- tests/google-adapter.test.ts | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/adapters/google.ts b/src/adapters/google.ts index 0b7df429ec..72914d9559 100644 --- a/src/adapters/google.ts +++ b/src/adapters/google.ts @@ -143,7 +143,10 @@ function geminiToolResultText(content: string | OcxContentPart[]): string { return hasContent ? contentPartsToText(content) : GEMINI_EMPTY_TOOL_OUTPUT_PLACEHOLDER; } -function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?: unknown; contents: unknown[] } { +function messagesToGeminiFormat( + parsed: OcxParsedRequest, + identityModelId: string, +): { systemInstruction?: unknown; contents: unknown[] } { // Neutralize Codex's GPT-5 identity line (Gemini/Antigravity share this path) so a routed model // never misreports as GPT-5/OpenAI, and never leaks the proxy identity upstream. const toolCatalogNudge = buildNonOpenAIToolCatalogNudgeForTools(parsed.context.tools, parsed.options.toolChoice); @@ -151,7 +154,7 @@ function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?: ...(parsed.context.systemPrompt ?? []), ...(toolCatalogNudge ? [toolCatalogNudge] : []), GOOGLE_BREVITY_INSTRUCTION, - ].join("\n\n"), parsed.modelId); + ].join("\n\n"), identityModelId); const systemInstruction = { parts: [{ text: systemText }] }; const contents: unknown[] = []; @@ -394,9 +397,9 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte : provider.googleMode === "vertex" ? parsed.modelId : resolveDirectGeminiWireModelId(parsed.modelId, provider.directGeminiWireRenames !== false); - // System identity names the public model id (parsed.modelId) so the model never - // self-reports as its -tiered wire spelling; routedModelId is only the wire id in the URL. - const { systemInstruction, contents } = messagesToGeminiFormat(parsed); + // AI Studio's `-tiered` spelling is wire-only; CCA aliases may migrate to another generation. + const identityModelId = provider.googleMode === "cloud-code-assist" ? routedModelId : parsed.modelId; + const { systemInstruction, contents } = messagesToGeminiFormat(parsed, identityModelId); const tools = toolsToGeminiFormat(parsed); const body: Record = { contents }; diff --git a/tests/google-adapter.test.ts b/tests/google-adapter.test.ts index 59a3a19bb7..546ad41d6c 100644 --- a/tests/google-adapter.test.ts +++ b/tests/google-adapter.test.ts @@ -352,6 +352,25 @@ describe("google adapter — direct -tiered wire renames", () => { } }); + test("Cloud Code Assist identity follows a migrated wire model", async () => { + const ccaProvider = { + ...provider, + googleMode: "cloud-code-assist", + baseUrl: "https://daily-cloudcode-pa.googleapis.com", + project: "proj-123", + } as const; + const request = await createGoogleAdapter(ccaProvider).buildRequest(identityParsed("gemini-3.6-flash")); + const envelope = JSON.parse(request.body) as { + model: string; + request: { systemInstruction?: { parts?: Array<{ text?: string }> } }; + }; + const systemText = envelope.request.systemInstruction?.parts?.[0]?.text ?? ""; + + expect(envelope.model).toBe("gemini-3.7-flash-tiered"); + expect(systemText).toContain("powered by the gemini-3.7-flash-tiered"); + expect(systemText).not.toContain("powered by the gemini-3.6-flash."); + }); + test("directGeminiWireRenames does not affect Vertex requests", async () => { const vertexProvider = { ...provider, googleMode: "vertex" as const }; for (const modelId of ["gemini-3.7-flash", "gemini-3.6-flash"]) { From e1c7ec85eeb98cc3de5930bc026ff36400e9c572 Mon Sep 17 00:00:00 2001 From: chilung Date: Mon, 17 Aug 2026 00:17:36 +0800 Subject: [PATCH 6/6] fix(google): retain provider option documentation after rebase --- src/types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/types.ts b/src/types.ts index ea0f526e2a..5564c514c4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1392,8 +1392,9 @@ export interface OcxProviderConfig { * HTTP/2 streaming responses (issue #1668). "http1.1" / "h1" forces HTTP/1.1, * "http2" / "h2" forces HTTP/2. Absent or "auto" keeps Bun's default negotiation * (current behavior unchanged). Only meaningful for https: base URLs. - */ + */ upstreamHttpVersion?: UpstreamHttpVersion; + /** * Google only. When `false`, the AI Studio (direct) path sends Gemini Flash ids * unchanged to the wire instead of applying the `-tiered` suffix (`gemini-3.7-flash` * -> `gemini-3.7-flash-tiered`). Set this to `false` when the configured upstream still