import { resolveProviderHttpRequestConfig, type ProviderRequestTransportOverrides, } from "openclaw/plugin-sdk/provider-http"; import { applyAgentDefaultModelPrimary, type OpenClawConfig, } from "openclaw/plugin-sdk/provider-onboard"; import { parseGoogleOauthApiKey } from "./oauth-token-shared.js"; import { DEFAULT_GOOGLE_API_BASE_URL, normalizeGoogleApiBaseUrl, normalizeGoogleGenerativeAiBaseUrl, } from "./provider-policy.js"; export { normalizeAntigravityModelId, normalizeGoogleModelId } from "./model-id.js"; export { DEFAULT_GOOGLE_API_BASE_URL, isGoogleGenerativeAiApi, normalizeGoogleApiBaseUrl, normalizeGoogleGenerativeAiBaseUrl, normalizeGoogleProviderConfig, resolveGoogleGenerativeAiApiOrigin, resolveGoogleGenerativeAiTransport, shouldNormalizeGoogleGenerativeAiProviderConfig, shouldNormalizeGoogleProviderConfig, } from "./provider-policy.js"; export function parseGeminiAuth(apiKey: string): { headers: Record } { const parsed = apiKey.startsWith("{") ? parseGoogleOauthApiKey(apiKey) : null; if (parsed?.token) { return { headers: { Authorization: `Bearer ${parsed.token}`, "Content-Type": "application/json", }, }; } return { headers: { "x-goog-api-key": apiKey, "Content-Type": "application/json", }, }; } function resolveTrustedGoogleGenerativeAiBaseUrl(baseUrl?: string): string { const normalized = normalizeGoogleGenerativeAiBaseUrl(baseUrl ?? DEFAULT_GOOGLE_API_BASE_URL) ?? DEFAULT_GOOGLE_API_BASE_URL; let url: URL; try { url = new URL(normalized); } catch { throw new Error( "Google Generative AI baseUrl must be a valid https URL on generativelanguage.googleapis.com", ); } if ( url.protocol !== "https:" || url.hostname.toLowerCase() !== "generativelanguage.googleapis.com" ) { throw new Error( "Google Generative AI baseUrl must use https://generativelanguage.googleapis.com", ); } return normalized; } export function resolveGoogleGenerativeAiHttpRequestConfig(params: { apiKey: string; baseUrl?: string; headers?: Record; request?: ProviderRequestTransportOverrides; capability: "image" | "audio" | "video"; transport: "http" | "media-understanding"; }) { return resolveProviderHttpRequestConfig({ baseUrl: resolveTrustedGoogleGenerativeAiBaseUrl(params.baseUrl), defaultBaseUrl: DEFAULT_GOOGLE_API_BASE_URL, allowPrivateNetwork: false, headers: params.headers, request: params.request, defaultHeaders: parseGeminiAuth(params.apiKey).headers, provider: "google", api: "google-generative-ai", capability: params.capability, transport: params.transport, }); } export const GOOGLE_GEMINI_DEFAULT_MODEL = "google/gemini-3.1-pro-preview"; export function applyGoogleGeminiModelDefault(cfg: OpenClawConfig): { next: OpenClawConfig; changed: boolean; } { const current = cfg.agents?.defaults?.model as unknown; const currentPrimary = typeof current === "string" ? current.trim() || undefined : current && typeof current === "object" && typeof (current as { primary?: unknown }).primary === "string" ? ((current as { primary: string }).primary || "").trim() || undefined : undefined; if (currentPrimary === GOOGLE_GEMINI_DEFAULT_MODEL) { return { next: cfg, changed: false }; } return { next: applyAgentDefaultModelPrimary(cfg, GOOGLE_GEMINI_DEFAULT_MODEL), changed: true, }; }