feat(ai): add Google Cloud Code Assist provider

- Add new API type 'google-cloud-code-assist' for Gemini CLI / Antigravity auth
- Extract shared Google utilities to google-shared.ts
- Implement streaming provider for Cloud Code Assist endpoint
- Add 7 models: gemini-3-pro-high/low, gemini-3-flash, claude-sonnet/opus, gpt-oss

Models use OAuth authentication and have sh cost (uses Google account quota).
OAuth flow will be implemented in coding-agent in a follow-up.
This commit is contained in:
Mario Zechner 2025-12-20 10:20:30 +01:00
parent 04dcdebbc6
commit 36e17933d5
10 changed files with 1208 additions and 178 deletions

View file

@ -2,6 +2,10 @@ import { ThinkingLevel } from "@google/genai";
import { supportsXhigh } from "./models.js";
import { type AnthropicOptions, streamAnthropic } from "./providers/anthropic.js";
import { type GoogleOptions, streamGoogle } from "./providers/google.js";
import {
type GoogleCloudCodeAssistOptions,
streamGoogleCloudCodeAssist,
} from "./providers/google-cloud-code-assist.js";
import { type OpenAICompletionsOptions, streamOpenAICompletions } from "./providers/openai-completions.js";
import { type OpenAIResponsesOptions, streamOpenAIResponses } from "./providers/openai-responses.js";
import type {
@ -77,6 +81,13 @@ export function stream<TApi extends Api>(
case "google-generative-ai":
return streamGoogle(model as Model<"google-generative-ai">, context, providerOptions);
case "google-cloud-code-assist":
return streamGoogleCloudCodeAssist(
model as Model<"google-cloud-code-assist">,
context,
providerOptions as GoogleCloudCodeAssistOptions,
);
default: {
// This should never be reached if all Api cases are handled
const _exhaustive: never = api;
@ -196,6 +207,29 @@ function mapOptionsForApi<TApi extends Api>(
} satisfies GoogleOptions;
}
case "google-cloud-code-assist": {
// Cloud Code Assist uses thinking budget tokens like Gemini 2.5
if (!options?.reasoning) {
return { ...base, thinking: { enabled: false } } satisfies GoogleCloudCodeAssistOptions;
}
const effort = clampReasoning(options.reasoning)!;
const budgets: Record<ClampedReasoningEffort, number> = {
minimal: 1024,
low: 2048,
medium: 8192,
high: 16384,
};
return {
...base,
thinking: {
enabled: true,
budgetTokens: budgets[effort],
},
} satisfies GoogleCloudCodeAssistOptions;
}
default: {
// Exhaustiveness check
const _exhaustive: never = model.api;