Skip to content

Conversation

@mldangelo
Copy link
Member

Summary

Major refactor of the Google provider architecture to align with the official @google/genai SDK v1.34.0 patterns and reduce code duplication between Google AI Studio and Vertex AI providers.

Key Changes

  • New centralized auth module (auth.ts): GoogleAuthManager class handling all authentication with SDK-aligned priority order
  • New abstract base class (base.ts): GoogleGenericProvider with shared functionality (MCP integration, tool normalization, cleanup)
  • New unified provider (provider.ts): GoogleGenericGeminiProvider combining AI Studio and Vertex AI implementations
  • SDK-aligned features: googleAuthOptions passthrough, scopes, keyFilename, strictMutualExclusivity
  • Express mode auto-detection: Automatically enables express mode when API key is present in Vertex AI
  • Cache security: Auth headers now included in cache key to prevent cross-tenant cache pollution
  • Documentation updates: Updated Google and Vertex AI docs to reflect new configuration options

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    GoogleGenericProvider                     │
│                      (base.ts)                               │
│  - MCP client integration                                    │
│  - Tool normalization                                        │
│  - Function callback execution                               │
│  - Resource cleanup                                          │
└─────────────────────────────────────────────────────────────┘
                             ▲
                             │ extends
┌─────────────────────────────────────────────────────────────┐
│               GoogleGenericGeminiProvider                    │
│                    (provider.ts)                             │
│  - Unified API call implementation                           │
│  - Streaming support                                         │
│  - Tool execution with agentic loops                         │
│  - Express mode (API key) + OAuth mode (ADC)                 │
└─────────────────────────────────────────────────────────────┘
                             │
                             │ uses
┌─────────────────────────────────────────────────────────────┐
│                    GoogleAuthManager                         │
│                      (auth.ts)                               │
│  - API key resolution (SDK priority order)                   │
│  - Vertex mode detection                                     │
│  - OAuth client creation                                     │
│  - Project/region resolution                                 │
│  - Mutual exclusivity validation                             │
└─────────────────────────────────────────────────────────────┘

SDK Alignment Details

Feature Before After (SDK Aligned)
API key priority GEMINI_API_KEY first GOOGLE_API_KEY first
Default region us-central1 always global for OAuth mode
Auth passthrough Not supported googleAuthOptions passthrough
Mutual exclusivity Not enforced apiKey + projectId throws error
Express mode Manual Auto-detect from API key

New Configuration Options

providers:
  - id: vertex:gemini-2.5-pro
    config:
      # SDK-aligned auth passthrough
      googleAuthOptions:
        universeDomain: my-universe.googleapis.com
        clientOptions:
          timeout: 30000
      
      # Custom scopes
      scopes:
        - https://www.googleapis.com/auth/cloud-platform
        - https://www.googleapis.com/auth/generative-language
      
      # Service account key file path
      keyFilename: /path/to/service-account.json
      
      # Control mutual exclusivity validation (default: true)
      strictMutualExclusivity: false

Breaking Changes

⚠️ Mutual Exclusivity Enforcement: Configs that explicitly set both apiKey AND projectId/region will now throw an error by default. This matches the official SDK behavior. Set strictMutualExclusivity: false to restore permissive behavior.

Files Changed

New Files:

  • src/providers/google/auth.ts - Centralized authentication manager (513 lines)
  • src/providers/google/base.ts - Abstract base class (358 lines)
  • src/providers/google/provider.ts - Unified provider implementation (613 lines)
  • src/providers/google/index.ts - Clean re-exports (18 lines)

Updated Files:

  • src/providers/google/types.ts - New config options (+100 lines)
  • src/providers/google/ai.studio.ts - Extends new base class
  • src/providers/google/vertex.ts - Simplified, uses new provider
  • src/providers/google/util.ts - Delegates to auth module
  • src/providers/google/live.ts - Minor updates
  • src/cache.ts - Auth headers in cache key (+65 lines)

Tests:

  • test/providers/google/auth.test.ts - Comprehensive auth tests (603 lines)
  • test/providers/google/base.test.ts - Base class tests (486 lines)
  • test/providers/google/provider.test.ts - Provider tests (670 lines)
  • Updated existing tests for compatibility

Documentation:

  • site/docs/providers/google.md - AI Studio docs
  • site/docs/providers/vertex.md - Vertex AI docs (+117 lines)

Test Plan

  • All existing Google provider tests pass
  • New auth.test.ts covers API key priority, Vertex mode detection, OAuth
  • New base.test.ts covers MCP integration, tool normalization
  • New provider.test.ts covers streaming, tool execution, express mode
  • Cache key tests verify auth header inclusion
  • Manual testing with Google AI Studio examples
  • Manual testing with Vertex AI examples

🤖 Generated with Claude Code

mldangelo and others added 7 commits January 4, 2026 04:20
Previously, authentication headers like x-goog-api-key were stripped from
the cache key, allowing different API keys to share cached responses. This
was a security vulnerability where User A's cached response could be served
to User B if they made the same request.

Changes:
- Hash auth-related headers (Authorization, x-goog-api-key, x-api-key, etc.)
- Include hash suffix in cache key when auth headers are present
- Bump cache key version from v2 to v3

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Align authentication behavior with the official @google/genai SDK v1.34.0:

Auth changes:
- Centralize auth logic in new auth.ts module (GoogleAuthManager)
- Gate Vertex express mode behind explicit expressMode: true flag
- SDK defaults to OAuth/ADC for Vertex, not API key auth
- Warn on non-SDK env vars (GEMINI_API_KEY, PALM_API_KEY, VERTEX_API_KEY)
- Recommend SDK-aligned vars (GOOGLE_API_KEY, GOOGLE_CLOUD_PROJECT)
- Add mutual exclusivity check for apiKey + projectId/region

API version:
- Allow apiVersion override in AI Studio mode via config
- Previously auto-detected based on model, now allows explicit override

New modules:
- auth.ts: Centralized GoogleAuthManager with API key resolution
- base.ts: Shared GoogleGenericProvider base class
- provider.ts: Unified provider supporting both AI Studio and Vertex
- index.ts: Clean exports

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documentation updates for SDK alignment changes:

Vertex docs:
- Express mode requires explicit expressMode: true
- Updated env vars to prioritize SDK-aligned names
  (GOOGLE_API_KEY, GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION)
- Legacy vars marked as such (VERTEX_API_KEY, VERTEX_PROJECT_ID)
- Add SDK Feature Comparison table showing supported/unsupported features
- Document Files API, Caching API, Live API as unsupported
- Point to google:image: for image generation

Google AI Studio docs:
- Add migration notes for SDK alignment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reverts the version bump from v2 to v3 while keeping the auth header
hash suffix for security. This ensures existing cache entries remain
valid.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused imports (GoogleAuth, parseChatPrompt, GoogleAuthManager, EnvOverrides, etc.)
- Remove unused cloudLocation variable in validateAndWarn()
- Rename unused parameters to underscore prefix (_context, _provider)
- Add block statements for single-line if statements per Biome rules

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Express mode is now invisible to users - just provide an API key and it
works automatically. No need to set `expressMode: true`.

Changes:
- Express mode auto-enables when API key is available in Vertex mode
- Users can opt-out with `expressMode: false` if they need OAuth features
- Changed apiKey+credentials warning to debug level (API key now takes precedence)
- Updated tests to reflect automatic behavior
- Updated vertex.md documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove explicit references to @google/genai and Python SDK
- Rename "SDK Feature Comparison" → "Supported Features"
- Simplify "SDK Alignment" tips → "Recommended Environment Variables"
- Clean up mutual exclusivity note
- Remove redundant legacy env var examples

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@mldangelo mldangelo requested review from a team, MrFlounder, swarnap and typpo as code owners January 4, 2026 09:22
@use-tusk
Copy link
Contributor

use-tusk bot commented Jan 4, 2026

⏩ No test execution environment matched (5e7061f) View output ↗


View check history

Commit Status Output Created (UTC)
491166f ⏩ No test execution environment matched Output Jan 4, 2026 9:22AM
b13480a ⏩ No test execution environment matched Output Jan 4, 2026 9:34AM
a2a42da ⏩ No test execution environment matched Output Jan 4, 2026 9:37AM
8e500ce ⏩ No test execution environment matched Output Jan 4, 2026 9:38AM
b474656 ⏩ No test execution environment matched Output Jan 4, 2026 9:49AM
2979004 ⏩ No test execution environment matched Output Jan 4, 2026 9:55AM
121dffd ⏩ No test execution environment matched Output Jan 4, 2026 9:59AM
5806fb8 ⏩ No test execution environment matched Output Jan 4, 2026 10:12AM
5297b4d ⏩ No test execution environment matched Output Jan 4, 2026 8:15PM
5e7061f ⏩ No test execution environment matched Output Jan 8, 2026 7:28AM

View output in GitHub ↗

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 4, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive refactoring of the Google AI providers architecture alongside authentication centralization and caching improvements. Documentation updates clarify environment variable precedence and authentication modes for both Google AI Studio and Vertex AI. A new centralized GoogleAuthManager module handles API key resolution from multiple environment variables with conflict detection. A shared GoogleGenericProvider base class consolidates MCP integration, tool handling, and external function loading. A unified GoogleProvider class supports both AI Studio and Vertex AI modes for Gemini models with auto-detection. The Google AI Studio provider is refactored to extend the new base and use header-based API key authentication. Vertex providers are updated similarly with simplified express-mode handling. Cache functionality is enhanced to include auth header hashing to prevent different credentials from sharing cached responses. Comprehensive test coverage validates the new auth manager, base provider, unified provider, and updated AI Studio provider.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely describes the main refactoring effort: consolidating Google AI Studio and Vertex AI providers with SDK alignment, which directly matches the core objective of reducing duplication and aligning with the @google/genai SDK.
Description check ✅ Passed The PR description comprehensively documents the refactor with summaries, key changes, architecture diagrams, SDK alignment details, configuration examples, breaking changes, and file listings that directly relate to the changeset.
✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/providers/google/ai.studio.ts (1)

492-501: Default providers should use AIStudioChatProvider instead of AIStudioGenericProvider.

The default grading and suggestion providers use AIStudioGenericProvider, but this is inconsistent with the codebase pattern. Google Vertex defaults use VertexChatProvider (the specialized chat class), and all other providers (OpenAI, Mistral, GitHub, etc.) use their chat-specific implementations for defaults. AIStudioChatProvider exists in the codebase and extends GoogleGenericProvider with proper API endpoint handling for AI Studio—it should be used for these defaults instead of the generic provider.

🧹 Nitpick comments (11)
test/providers/google/base.test.ts (1)

104-115: Strengthen test isolation by resetting mocks, not just clearing call history

beforeEach and afterEach both use vi.clearAllMocks(), which preserves mock implementations (important for hoisted mocks like mockMcpInstance and MockMCPClient). To better align with the testing guidelines and avoid subtle cross‑test coupling, consider switching the afterEach to vi.resetAllMocks() so implementations are reset as well.

test/providers/google/ai.studio.test.ts (1)

131-165: Endpoint and header assertions are good; consider reducing brittleness and resetting mocks

  • The new tests around getApiEndpoint, apiHost/apiBaseUrl, header‑based API key usage, and apiVersion override accurately reflect the refactored AI Studio behavior.
  • A few places hard‑code the entire URL (e.g. 'https://rendered-generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent'). That couples tests to both the default host and the Nunjucks stub; using expect.stringContaining('v1beta/models/gemini-pro:generateContent') plus a separate host assertion (as in other tests) would make them more resilient to future host/version tweaks.
  • Mocks like mockMaybeLoadToolsFromExternalFile and templates.getNunjucksEngine are reconfigured in individual tests but only vi.clearAllMocks() is called in beforeEach, which does not reset implementations. Adding an afterEach with vi.resetAllMocks() (or explicitly mockReset() on the long‑lived mocks) would improve test isolation.

Also applies to: 449-477, 887-930, 1032-1043, 1144-1153, 1241-1250, 1342-1355, 1425-1435

test/providers/google/auth.test.ts (1)

39-59: Tighten mock cleanup for GoogleAuthManager tests

The auth behavior tests are thorough and correctly exercise the new precedence and mutual‑exclusivity rules. To avoid any leftover mock implementations (especially for getEnvString, logger, and maybeLoadFromExternalFile), consider switching the afterEach cleanup from vi.clearAllMocks() to vi.resetAllMocks(), or explicitly mockReset() the long‑lived mocks you override per test.

test/providers/google/provider.test.ts (2)

97-115: Add afterEach reset for consistent mock cleanup

This suite reconfigures shared mocks (cache.fetchWithCache, fetchWithProxy, file utilities, envars) across tests but only calls vi.clearAllMocks() in beforeEach. Adding an afterEach with vi.resetAllMocks() (or targeted mockReset() calls) would align with the testing guidelines and reduce the chance of state leaking between tests.


638-658: Update expressMode comment to match current auto-detect behavior

In the express‑mode error test, the config includes expressMode: true with a comment saying “must be explicit”, but isExpressMode() now auto‑enables express mode whenever an API key is present and expressMode is not false. The explicit expressMode: true is harmless but no longer required; updating the comment (or dropping the flag) would better reflect the current semantics.

src/providers/google/provider.ts (1)

409-608: Response parsing covers guardrails, thinking tokens, grounding metadata, and tool callbacks

  • Normalizing GeminiApiResponse to an array, treating promptFeedback.blockReason as a guardrails output (not an error), and mapping safety finishReason values into structured GuardrailResponse objects aligns with the updated Vertex/AI Studio tests.
  • Token usage correctly tracks cached vs non‑cached responses and includes completionDetails.reasoning when thoughtsTokenCount is present, matching the “thinking token” tests.
  • Grounding metadata extraction walks all candidates and surfaces groundingMetadata, groundingChunks, groundingSupports, and webSearchQueries in metadata, which matches the Google Search tests.
  • Function tool callbacks are executed only when functionToolCallbacks is present and the output JSON contains a functionCall, with JSON normalization of args before delegation to executeFunctionCallback.

One small polish point: in the blockReason branch, metadata.modelArmor is set to undefined for non‑Model Armor cases. Using a conditional spread (e.g. ...(isModelArmor && { modelArmor: {...} })) would avoid creating an explicitly undefined property, but this is cosmetic and doesn’t affect behavior or tests.

src/providers/google/ai.studio.ts (2)

162-171: Duplicated API host resolution logic.

The getApiHost() and getApiBaseUrl() methods share identical logic for resolving the API host from config and environment variables. This duplication could lead to maintenance issues if the precedence order changes.

🔎 Consider extracting shared logic
+  private resolveApiHostFromConfig(): string | undefined {
+    const apiHost =
+      this.config.apiHost ||
+      this.env?.GOOGLE_API_HOST ||
+      this.env?.PALM_API_HOST ||
+      getEnvString('GOOGLE_API_HOST') ||
+      getEnvString('PALM_API_HOST');
+    return apiHost ? getNunjucksEngine().renderString(apiHost, {}) : undefined;
+  }
+
   getApiHost(): string {
-    const apiHost =
-      this.config.apiHost ||
-      this.env?.GOOGLE_API_HOST ||
-      this.env?.PALM_API_HOST ||
-      getEnvString('GOOGLE_API_HOST') ||
-      getEnvString('PALM_API_HOST') ||
-      DEFAULT_API_HOST;
-    return getNunjucksEngine().renderString(apiHost, {});
+    return this.resolveApiHostFromConfig() || DEFAULT_API_HOST;
   }

Also applies to: 176-187


190-200: Non-null assertion is safe but could be clearer.

The ! on line 198 is safe because the preceding condition guarantees one value is truthy. However, this pattern is somewhat fragile if the condition logic changes.

🔎 Consider a clearer approach
-    if (
-      this.config.apiBaseUrl ||
-      this.env?.GOOGLE_API_BASE_URL ||
-      getEnvString('GOOGLE_API_BASE_URL')
-    ) {
-      return (
-        this.config.apiBaseUrl ||
-        this.env?.GOOGLE_API_BASE_URL ||
-        getEnvString('GOOGLE_API_BASE_URL')!
-      );
-    }
+    const apiBaseUrl =
+      this.config.apiBaseUrl ||
+      this.env?.GOOGLE_API_BASE_URL ||
+      getEnvString('GOOGLE_API_BASE_URL');
+    if (apiBaseUrl) {
+      return apiBaseUrl;
+    }
src/providers/google/auth.ts (3)

214-225: ADC check is synchronous but hasDefaultCredentials() is async.

The validateAndWarn method is synchronous, so it can't use the async hasDefaultCredentials() method. The current approach of checking GOOGLE_APPLICATION_CREDENTIALS directly is a reasonable approximation, but note that ADC can also work via metadata server (GCE/GKE) or gcloud credentials without this env var being set.

Consider adding a comment explaining this limitation, or making validateAndWarn async in a future iteration to use the more accurate hasDefaultCredentials() check.


293-307: Credentials not validated as JSON before return.

The loadCredentials method returns credentials as a raw string without validating that it's valid JSON. Invalid JSON will only fail later in getOAuthClient at line 362, potentially with a less clear error message.

🔎 Consider adding JSON validation
   static loadCredentials(credentials?: string): string | undefined {
     if (!credentials) {
       return undefined;
     }

+    let result: string;
     if (credentials.startsWith('file://')) {
       try {
-        return maybeLoadFromExternalFile(credentials) as string;
+        result = maybeLoadFromExternalFile(credentials) as string;
       } catch (error) {
         throw new Error(`Failed to load credentials from file: ${error}`);
       }
+    } else {
+      result = credentials;
     }

-    return credentials;
+    // Validate JSON structure
+    try {
+      JSON.parse(result);
+    } catch (error) {
+      throw new Error(`Invalid credentials JSON: ${error}`);
+    }
+
+    return result;
   }

398-434: Returns empty string instead of undefined when no project ID found.

Line 432 returns an empty string '' as the final fallback when no project ID is resolved. This could mask configuration issues, as calling code may not distinguish between "no project configured" and "project is empty string".

Consider returning undefined and letting callers handle the missing project ID explicitly, or throwing an error if this is a required value for Vertex mode.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e2bf31d and 491166f.

📒 Files selected for processing (20)
  • site/docs/providers/google.md
  • site/docs/providers/vertex.md
  • src/cache.ts
  • src/providers/google/ai.studio.ts
  • src/providers/google/auth.ts
  • src/providers/google/base.ts
  • src/providers/google/index.ts
  • src/providers/google/live.ts
  • src/providers/google/provider.ts
  • src/providers/google/types.ts
  • src/providers/google/util.ts
  • src/providers/google/vertex.ts
  • test/cache.test.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
  • test/providers/google/base.test.ts
  • test/providers/google/live.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/util.test.ts
  • test/providers/google/vertex.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
test/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (test/AGENTS.md)

test/**/*.test.{ts,tsx}: Never increase test timeouts - fix the slow test instead
Never use .only() or .skip() in committed code
Always clean up mocks in afterEach using vi.resetAllMocks()
All tests require explicit imports from vitest: import { afterEach, describe, expect, it, vi } from 'vitest'
Use Vitest's mocking utilities (vi.mock, vi.fn, vi.spyOn) and prefer shallow mocking over deep mocking
Use vi.clearAllMocks() to clear call history, but use mockReset() for full isolation when mocking with mockReturnValue() or vi.hoisted() in beforeEach
Clean up any test data or mocks after each test
Globals are disabled in vitest configuration. All test utilities must be explicitly imported from vitest

Backend tests in test/ should use Vitest with globals enabled (describe, it, expect available without imports)

Files:

  • test/providers/google/util.test.ts
  • test/providers/google/live.test.ts
  • test/cache.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/base.test.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with strict type checking

Files:

  • test/providers/google/util.test.ts
  • src/providers/google/live.ts
  • test/providers/google/live.test.ts
  • src/providers/google/index.ts
  • test/cache.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/base.test.ts
  • src/providers/google/types.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
  • src/providers/google/provider.ts
  • src/cache.ts
  • src/providers/google/base.ts
  • src/providers/google/ai.studio.ts
  • src/providers/google/vertex.ts
  • src/providers/google/auth.ts
  • src/providers/google/util.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Follow consistent import order (Biome handles sorting)
Use consistent curly braces for all control statements
Prefer const over let; avoid var
Use object shorthand syntax whenever possible
Use async/await for asynchronous code
Use consistent error handling with proper type checks
Avoid re-exporting from files; import directly from the source module
Use the logger with object context (auto-sanitized)

Files:

  • test/providers/google/util.test.ts
  • src/providers/google/live.ts
  • test/providers/google/live.test.ts
  • src/providers/google/index.ts
  • test/cache.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/base.test.ts
  • src/providers/google/types.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
  • src/providers/google/provider.ts
  • src/cache.ts
  • src/providers/google/base.ts
  • src/providers/google/ai.studio.ts
  • src/providers/google/vertex.ts
  • src/providers/google/auth.ts
  • src/providers/google/util.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx}: Use Vitest for all tests (both test/ and src/app/)
Test both success and error cases for all functionality

Files:

  • test/providers/google/util.test.ts
  • test/providers/google/live.test.ts
  • test/cache.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/base.test.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
src/providers/**/*.ts

📄 CodeRabbit inference engine (src/providers/AGENTS.md)

src/providers/**/*.ts: Implement ApiProvider interface from src/types/providers.ts for LLM provider integrations
Provider must transform prompts to provider-specific API format and return normalized ProviderResponse
If your provider allocates resources (Python workers, connections, child processes), implement a cleanup() method and register with providerRegistry for automatic cleanup
Use logger with object context (auto-sanitized) for logging as specified in docs/agents/logging.md
OpenAI-compatible providers should extend OpenAiChatCompletionProvider base class
Config priority order: Explicit options > Environment variables > Provider defaults

Files:

  • src/providers/google/live.ts
  • src/providers/google/index.ts
  • src/providers/google/types.ts
  • src/providers/google/provider.ts
  • src/providers/google/base.ts
  • src/providers/google/ai.studio.ts
  • src/providers/google/vertex.ts
  • src/providers/google/auth.ts
  • src/providers/google/util.ts
src/providers/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Document provider configurations following examples in existing code

Files:

  • src/providers/google/live.ts
  • src/providers/google/index.ts
  • src/providers/google/types.ts
  • src/providers/google/provider.ts
  • src/providers/google/base.ts
  • src/providers/google/ai.studio.ts
  • src/providers/google/vertex.ts
  • src/providers/google/auth.ts
  • src/providers/google/util.ts
site/docs/**/*.md

📄 CodeRabbit inference engine (site/AGENTS.md)

site/docs/**/*.md: Don't modify heading text in documentation (often externally linked)
Avoid embellishment words like 'sophisticated' in documentation
Include front matter with title (under 60 chars), description (150-160 chars), and sidebar_position on all documentation pages
Add title="filename.yaml" attribute only to code blocks containing complete, runnable files
Don't add titles to code block fragments (only complete, runnable files)
Use // highlight-next-line directive to emphasize specific lines in code blocks
Never remove existing highlight directives from code blocks
Use admonition syntax (:::note, :::warning, :::danger) with empty lines around content

Files:

  • site/docs/providers/google.md
  • site/docs/providers/vertex.md
site/**/*.{md,ts,tsx,js,json}

📄 CodeRabbit inference engine (site/AGENTS.md)

site/**/*.{md,ts,tsx,js,json}: Use 'eval' not 'evaluation' in commands and documentation
Use 'Promptfoo' when referring to the company or product, 'promptfoo' when referring to the CLI command or in code

Files:

  • site/docs/providers/google.md
  • site/docs/providers/vertex.md
🧠 Learnings (25)
📚 Learning: 2025-12-11T07:30:27.904Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2025-12-11T07:30:27.904Z
Learning: Applies to test/providers/*.test.{ts,tsx} : For provider tests, cover: success case, error cases (4xx, 5xx, rate limits), configuration validation, and token usage tracking

Applied to files:

  • test/providers/google/util.test.ts
  • test/providers/google/live.test.ts
  • test/cache.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/base.test.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-09T06:09:06.028Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/providers/AGENTS.md:0-0
Timestamp: 2025-12-09T06:09:06.028Z
Learning: Applies to src/providers/test/providers/**/*.ts : Provider tests must NEVER make real API calls - mock all HTTP requests using `vi.mock`

Applied to files:

  • test/providers/google/util.test.ts
  • test/providers/google/live.test.ts
  • test/cache.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/base.test.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-11T07:30:27.904Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2025-12-11T07:30:27.904Z
Learning: Applies to test/**/*.test.{ts,tsx} : Use `vi.clearAllMocks()` to clear call history, but use `mockReset()` for full isolation when mocking with `mockReturnValue()` or `vi.hoisted()` in `beforeEach`

Applied to files:

  • test/providers/google/util.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-11T07:30:27.904Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2025-12-11T07:30:27.904Z
Learning: Applies to test/**/*.test.{ts,tsx} : Always clean up mocks in `afterEach` using `vi.resetAllMocks()`

Applied to files:

  • test/providers/google/util.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-28T00:26:53.714Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/app/AGENTS.md:0-0
Timestamp: 2025-12-28T00:26:53.714Z
Learning: Applies to src/app/src/**/*.test.{ts,tsx} : Use Vitest with `vi.fn()` for mocks and `vi.mock()` for modules. See 'src/app/src/hooks/usePageMeta.test.ts' for patterns

Applied to files:

  • test/providers/google/util.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-11T07:30:27.904Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2025-12-11T07:30:27.904Z
Learning: Applies to test/**/*.test.{ts,tsx} : Use Vitest's mocking utilities (`vi.mock`, `vi.fn`, `vi.spyOn`) and prefer shallow mocking over deep mocking

Applied to files:

  • test/providers/google/util.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-09T06:09:06.028Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/providers/AGENTS.md:0-0
Timestamp: 2025-12-09T06:09:06.028Z
Learning: Applies to src/providers/**/*.ts : Config priority order: Explicit options > Environment variables > Provider defaults

Applied to files:

  • src/providers/google/live.ts
  • test/providers/google/base.test.ts
  • src/providers/google/types.ts
  • test/providers/google/ai.studio.test.ts
  • src/providers/google/provider.ts
  • site/docs/providers/vertex.md
  • src/providers/google/ai.studio.ts
  • src/providers/google/auth.ts
📚 Learning: 2025-12-09T06:09:06.028Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/providers/AGENTS.md:0-0
Timestamp: 2025-12-09T06:09:06.028Z
Learning: Applies to src/providers/test/providers/**/*.ts : Test provider success AND error cases, including rate limits, timeouts, and invalid configs

Applied to files:

  • test/providers/google/live.test.ts
  • test/cache.test.ts
  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/base.test.ts
  • test/providers/google/ai.studio.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-09T06:09:06.028Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/providers/AGENTS.md:0-0
Timestamp: 2025-12-09T06:09:06.028Z
Learning: Applies to src/providers/**/*.ts : OpenAI-compatible providers should extend `OpenAiChatCompletionProvider` base class

Applied to files:

  • src/providers/google/index.ts
  • test/providers/google/base.test.ts
  • src/providers/google/types.ts
  • test/providers/google/ai.studio.test.ts
  • src/providers/google/provider.ts
  • src/providers/google/base.ts
  • src/providers/google/ai.studio.ts
  • src/providers/google/vertex.ts
📚 Learning: 2025-12-30T02:42:00.890Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T02:42:00.890Z
Learning: Applies to src/providers/**/*.{ts,tsx} : Document provider configurations following examples in existing code

Applied to files:

  • src/providers/google/index.ts
  • test/providers/google/base.test.ts
  • src/providers/google/types.ts
  • src/providers/google/base.ts
  • src/providers/google/vertex.ts
📚 Learning: 2025-12-09T06:09:06.028Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/providers/AGENTS.md:0-0
Timestamp: 2025-12-09T06:09:06.028Z
Learning: Applies to src/providers/**/*.ts : Implement `ApiProvider` interface from `src/types/providers.ts` for LLM provider integrations

Applied to files:

  • src/providers/google/index.ts
  • test/providers/google/base.test.ts
  • src/providers/google/types.ts
  • src/providers/google/provider.ts
  • src/providers/google/base.ts
📚 Learning: 2025-12-20T02:05:23.936Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/redteam/AGENTS.md:0-0
Timestamp: 2025-12-20T02:05:23.936Z
Learning: Applies to src/redteam/test/redteam/**/*.{ts,js} : Add tests for new plugins in the test/redteam/ directory following the reference pattern in src/redteam/plugins/pii.ts

Applied to files:

  • test/cache.test.ts
  • test/providers/google/base.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-11T07:30:27.904Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2025-12-11T07:30:27.904Z
Learning: Applies to test/**/*.test.{ts,tsx} : Globals are disabled in vitest configuration. All test utilities must be explicitly imported from `vitest`

Applied to files:

  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-11T07:30:27.904Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2025-12-11T07:30:27.904Z
Learning: Applies to test/**/*.test.{ts,tsx} : All tests require explicit imports from vitest: `import { afterEach, describe, expect, it, vi } from 'vitest'`

Applied to files:

  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-30T02:42:00.890Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T02:42:00.890Z
Learning: Applies to test/**/*.test.{ts,tsx} : Backend tests in `test/` should use Vitest with globals enabled (`describe`, `it`, `expect` available without imports)

Applied to files:

  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-12-30T02:42:00.890Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T02:42:00.890Z
Learning: Applies to src/app/**/*.test.{ts,tsx} : Frontend tests in `src/app/` should use Vitest with explicit imports

Applied to files:

  • test/providers/google/vertex.test.ts
  • test/providers/google/provider.test.ts
  • test/providers/google/auth.test.ts
📚 Learning: 2025-07-18T17:25:38.445Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: .cursor/rules/examples.mdc:0-0
Timestamp: 2025-07-18T17:25:38.445Z
Learning: Applies to examples/*/README.md : Document any required API keys or credentials in the README

Applied to files:

  • site/docs/providers/google.md
📚 Learning: 2025-07-18T17:25:38.445Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: .cursor/rules/examples.mdc:0-0
Timestamp: 2025-07-18T17:25:38.445Z
Learning: Applies to examples/*/README.md : When creating examples for specific providers, document required environment variables in the README

Applied to files:

  • site/docs/providers/google.md
📚 Learning: 2025-12-09T06:08:22.578Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: examples/AGENTS.md:0-0
Timestamp: 2025-12-09T06:08:22.578Z
Learning: Applies to examples/**/promptfooconfig.yaml : Use current model identifiers for OpenAI, Anthropic, and Google providers from the documentation in `site/docs/providers/`

Applied to files:

  • site/docs/providers/google.md
  • test/providers/google/ai.studio.test.ts
  • src/providers/google/provider.ts
  • site/docs/providers/vertex.md
  • src/providers/google/ai.studio.ts
📚 Learning: 2025-07-18T17:25:38.445Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: .cursor/rules/examples.mdc:0-0
Timestamp: 2025-07-18T17:25:38.445Z
Learning: Applies to examples/*/README.md : For each environment variable, explain its purpose, how to obtain it, and any default values or constraints in the README

Applied to files:

  • site/docs/providers/google.md
📚 Learning: 2025-12-30T02:42:00.890Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T02:42:00.890Z
Learning: Applies to **/*.test.{ts,tsx} : Use Vitest for all tests (both `test/` and `src/app/`)

Applied to files:

  • test/providers/google/provider.test.ts
📚 Learning: 2025-12-11T07:30:27.904Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2025-12-11T07:30:27.904Z
Learning: Applies to test/**/*.test.{ts,tsx} : Clean up any test data or mocks after each test

Applied to files:

  • test/providers/google/provider.test.ts
📚 Learning: 2025-12-09T06:09:06.028Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/providers/AGENTS.md:0-0
Timestamp: 2025-12-09T06:09:06.028Z
Learning: Applies to src/providers/**/*.ts : Provider must transform prompts to provider-specific API format and return normalized `ProviderResponse`

Applied to files:

  • test/providers/google/base.test.ts
  • src/providers/google/provider.ts
  • src/providers/google/ai.studio.ts
📚 Learning: 2025-07-18T17:25:38.445Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: .cursor/rules/examples.mdc:0-0
Timestamp: 2025-07-18T17:25:38.445Z
Learning: Applies to examples/*/promptfooconfig*.yaml : Include a mix of providers when comparing model performance in configuration files

Applied to files:

  • site/docs/providers/vertex.md
📚 Learning: 2025-12-09T06:09:06.028Z
Learnt from: CR
Repo: promptfoo/promptfoo PR: 0
File: src/providers/AGENTS.md:0-0
Timestamp: 2025-12-09T06:09:06.028Z
Learning: Applies to src/providers/**/*.ts : If your provider allocates resources (Python workers, connections, child processes), implement a `cleanup()` method and register with `providerRegistry` for automatic cleanup

Applied to files:

  • src/providers/google/ai.studio.ts
  • src/providers/google/vertex.ts
🧬 Code graph analysis (9)
src/providers/google/live.ts (1)
src/envars.ts (1)
  • getEnvString (417-433)
test/cache.test.ts (1)
src/cache.ts (1)
  • fetchWithCache (183-298)
test/providers/google/vertex.test.ts (1)
src/providers/litellm.ts (1)
  • config (41-43)
test/providers/google/base.test.ts (1)
src/providers/google/auth.ts (1)
  • GoogleAuthManager (90-503)
test/providers/google/auth.test.ts (3)
src/providers/google/auth.ts (1)
  • GoogleAuthManager (90-503)
src/envars.ts (1)
  • getEnvString (417-433)
src/util/file.ts (1)
  • maybeLoadFromExternalFile (56-212)
src/providers/google/provider.ts (4)
src/providers/google/index.ts (2)
  • GoogleProvider (13-13)
  • CompletionOptions (18-18)
src/providers/google/auth.ts (3)
  • loadCredentials (293-307)
  • loadCredentials (506-506)
  • getGoogleClient (507-507)
src/providers/google/util.ts (8)
  • loadCredentials (301-301)
  • getGoogleClient (299-299)
  • geminiFormatAndSystemInstructions (689-734)
  • GeminiApiResponse (94-98)
  • GeminiErrorResponse (60-66)
  • GeminiResponseData (68-77)
  • getCandidate (305-340)
  • formatCandidateContents (342-393)
src/providers/google/types.ts (1)
  • CompletionOptions (112-331)
src/providers/google/base.ts (3)
src/util/templates.ts (1)
  • getNunjucksEngine (15-55)
src/providers/mcp/transform.ts (1)
  • transformMCPToolsToGoogle (84-116)
src/providers/google/util.ts (1)
  • normalizeTools (419-450)
src/providers/google/ai.studio.ts (6)
src/envars.ts (1)
  • getEnvString (417-433)
src/providers/google/base.ts (1)
  • GoogleProviderOptions (38-45)
src/providers/google/shared.ts (1)
  • CHAT_MODELS (1-69)
src/util/templates.ts (1)
  • getNunjucksEngine (15-55)
src/types/providers.ts (2)
  • CallApiContextParams (51-82)
  • ProviderResponse (134-196)
src/cache.ts (1)
  • fetchWithCache (183-298)
src/providers/google/vertex.ts (6)
src/providers/google/index.ts (2)
  • VertexChatProvider (14-14)
  • GoogleProviderOptions (16-16)
src/providers/google/base.ts (1)
  • GoogleProviderOptions (38-45)
src/envars.ts (1)
  • getEnvString (417-433)
src/providers/google/auth.ts (3)
  • loadCredentials (293-307)
  • loadCredentials (506-506)
  • getGoogleClient (507-507)
src/providers/google/util.ts (2)
  • loadCredentials (301-301)
  • getGoogleClient (299-299)
src/util/fetch/index.ts (1)
  • fetchWithProxy (37-140)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (25)
  • GitHub Check: Test on Node 20.x and windows-latest (shard 2/3)
  • GitHub Check: Test on Node 24.x and windows-latest (shard 3/3)
  • GitHub Check: Test on Node 22.x and windows-latest (shard 3/3)
  • GitHub Check: Test on Node 22.x and ubuntu-latest
  • GitHub Check: Test on Node 24.x and windows-latest (shard 2/3)
  • GitHub Check: Test on Node 20.x and macOS-latest
  • GitHub Check: Test on Node 24.x and ubuntu-latest
  • GitHub Check: Test on Node 24.x and windows-latest (shard 1/3)
  • GitHub Check: Test on Node 20.x and windows-latest (shard 1/3)
  • GitHub Check: Test on Node 22.x and windows-latest (shard 2/3)
  • GitHub Check: Test on Node 22.x and windows-latest (shard 1/3)
  • GitHub Check: Test on Node 20.x and ubuntu-latest
  • GitHub Check: Test on Node 20.x and windows-latest (shard 3/3)
  • GitHub Check: Test on Node 22.x and macOS-latest
  • GitHub Check: Redteam (Staging API)
  • GitHub Check: Build on Node 22.x
  • GitHub Check: Redteam (Production API)
  • GitHub Check: Build on Node 24.x
  • GitHub Check: Share Test
  • GitHub Check: Build on Node 20.x
  • GitHub Check: Style Check
  • GitHub Check: Build Docs
  • GitHub Check: webui tests
  • GitHub Check: security-scan
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (34)
site/docs/providers/google.md (1)

74-76: LGTM! Clear documentation of environment variable precedence.

The admonition clearly communicates that GOOGLE_API_KEY takes precedence over GEMINI_API_KEY, which aligns with the SDK standardization goals of this PR.

src/cache.ts (3)

145-181: Auth header hashing implementation is solid.

The function properly handles different HeadersInit formats (Headers object, array, plain object) and creates a stable hash. The 16-character SHA-256 truncation provides a good balance between cache key length and collision resistance.


217-220: Cache key auth suffix correctly prevents cross-credential pollution.

The auth hash suffix ensures that requests with different authentication credentials don't share cached responses, which is critical for multi-tenant scenarios.


125-136: Auth header set is comprehensive and covers all authentication flows.

Verification confirms all auth headers currently used in the codebase are included:

  • authorization (Bearer and Basic auth flows)
  • x-goog-api-key (Google providers)
  • x-api-key (remoteScoring)
  • api-key (Azure provider)
  • x-goog-user-project (valid Google Cloud header for proper cache differentiation)

The set appropriately handles both current usage and potential future headers that affect credential differentiation.

src/providers/google/types.ts (4)

284-296: Express mode documentation is clear and SDK-aligned.

The documentation explicitly states that express mode defaults to false (uses OAuth/ADC), and must be explicitly enabled for API key authentication. This aligns with the SDK's behavior.


298-330: Auth options provide good SDK passthrough capabilities.

The googleAuthOptions, keyFilename, and scopes fields provide both advanced passthrough and convenient shorthand options. The JSDoc clearly documents their purpose and includes helpful examples.


333-382: Breaking change: strictMutualExclusivity defaults to true.

The strictMutualExclusivity field defaults to true, which enforces strict validation that throws errors when both apiKey and projectId/region are set. This is a breaking change as noted in the PR description.

Consider:

  • The default aligns with Google SDK behavior (good for SDK consistency)
  • Users can set to false for backward compatibility
  • The JSDoc clearly documents this behavior

Note: This breaking change should be prominently documented in release notes or migration guides.


1-1: google-auth-library dependency is properly declared. The package is included in package.json at version ^10.5.0, so the GoogleAuthOptions import is available.

src/providers/google/util.ts (1)

296-303: Good refactoring: auth logic centralized with backward compatibility.

Re-exporting the authentication functions from the centralized auth.ts module maintains backward compatibility while improving code organization. This follows the single responsibility principle by separating auth logic from Gemini formatting utilities.

site/docs/providers/vertex.md (6)

11-13: Clear provider selection guidance.

The info box provides concise guidance on when to use vertex: vs google: providers, helping users make the right choice upfront.


269-293: Express mode documentation is clear and accurate.

The updated documentation correctly reflects that:

  1. Express mode is auto-detected when an API key is present
  2. Only GOOGLE_API_KEY is mentioned (aligning with standardization)
  3. Users can opt out with expressMode: false if they need OAuth/ADC features

308-321: Mutual exclusivity note matches implementation.

The admonition clearly documents the breaking change where API key and OAuth configurations are mutually exclusive by default, with the option to disable strict checking. This aligns with the strictMutualExclusivity field in types.ts.


323-353: Comprehensive advanced auth documentation.

The section provides clear examples and a helpful table documenting keyFilename, scopes, and googleAuthOptions. The examples show practical use cases like custom domains and proxy configuration.


361-373: Environment variables table clearly shows preference for GOOGLE_ variables.*

The table properly documents:

  • GOOGLE_CLOUD_PROJECT as the primary project ID variable
  • GOOGLE_CLOUD_LOCATION for region
  • GOOGLE_API_KEY for express mode
  • Legacy variables marked as such with "use X instead" notes

1062-1081: Supported features table provides excellent capability overview.

The table clearly indicates what's supported (✅), not supported (❌), and has caveats (⚠️) with helpful notes. This makes it easy for users to understand provider capabilities at a glance.

src/providers/google/base.ts (1)

79-113: LGTM! Constructor properly initializes provider with auth validation.

The constructor correctly:

  • Determines Vertex mode using GoogleAuthManager
  • Validates auth configuration with comprehensive checks
  • Defers MCP initialization to avoid blocking construction
  • Supports custom provider IDs
test/providers/google/util.test.ts (1)

953-976: LGTM! Test correctly validates per-instance auth behavior.

The updated test properly verifies that auth clients are created per-call rather than globally cached, aligning with the @google/genai SDK patterns. The descriptive comments clearly explain the rationale.

src/providers/google/live.ts (1)

132-135: LGTM! API key fallback properly supports both environment variables.

The addition of GEMINI_API_KEY as a fallback provides backwards compatibility while maintaining the correct priority order (config.apiKey > GOOGLE_API_KEY > GEMINI_API_KEY). The comment clearly documents the Python SDK alignment.

test/providers/google/live.test.ts (1)

404-418: LGTM! Test properly handles both API key environment variables.

The test correctly:

  • Saves and restores both GOOGLE_API_KEY and GEMINI_API_KEY
  • Deletes both before testing the error case
  • Validates the updated error message
  • Conditionally restores only defined values
test/cache.test.ts (1)

326-361: LGTM! Tests properly validate auth-based cache isolation.

These tests correctly verify that:

  • Requests with the same auth credentials hit the cache
  • Requests with different auth credentials result in separate cache entries
  • Both x-goog-api-key and Authorization headers are properly handled

This is a critical security enhancement to prevent cross-tenant cache pollution.

test/providers/google/vertex.test.ts (1)

101-121: GoogleAuthManager mock correctly isolates Vertex tests from real auth state

Overriding getApiKey, determineVertexMode, resolveRegion, and resolveProjectId while spreading actual.GoogleAuthManager is a clean way to keep behavior aligned with the real implementation but avoid accidental dependence on host env/config. This should make the Vertex tests deterministic across environments.

src/providers/google/index.ts (1)

1-18: Public Google provider barrel looks coherent

The index cleanly groups legacy AI Studio provider, unified GoogleProvider, Vertex providers, base class, auth manager, and related types into a single entry point. This should simplify imports without changing behavior.

src/providers/google/provider.ts (3)

72-185: API host/base URL and version resolution are consistent and configurable

The split between getApiHost()/getApiBaseUrl() plus getApiVersion() nicely covers:

  • Vertex vs AI Studio hosts (including region === 'global' and VERTEX_API_HOST/GOOGLE_API_HOST overrides),
  • explicit apiVersion overrides,
  • auto‑detection of v1alpha for thinking and gemini‑3 models vs v1beta defaults.

The priority order (config > env overrides > defaults) matches the documented config precedence.


190-227: Auth header and express-mode logic match the new API-key semantics

  • getAuthHeaders() centralizes Content-Type and merges config.headers, while only attaching x-goog-api-key when in AI Studio or Vertex express mode. This cleanly avoids mixing API-key and OAuth flows.
  • isExpressMode() auto‑enables express mode whenever a key is available unless expressMode: false is set, which matches the PR description (automatic express with opt‑out). This is a good simplification; just be aware that a global GOOGLE_API_KEY can implicitly flip a Vertex config with projectId into express mode if expressMode is not explicitly disabled.

If you want to double‑check real-world behavior, it’s worth manually testing a Vertex config that has both projectId and an environment GOOGLE_API_KEY to ensure the chosen mode (express vs OAuth) matches expectations in your deployment environments.


246-404: Gemini call path cleanly separates AI Studio, Vertex OAuth, and Vertex express

The callGeminiApi implementation appropriately:

  • Merges base and prompt config,
  • Uses the shared geminiFormatAndSystemInstructions helper,
  • Pulls MCP + config tools via getAllTools,
  • Applies responseSchema with file/JSON handling and variable substitution, and
  • Routes to:
    • Vertex OAuth via getClientWithCredentials and projects/{project}/locations/{region} URL,
    • Vertex express via fetchWithProxy and x-goog-api-key,
    • AI Studio via fetchWithCache and header-based API key.

Error handling distinguishes structured gaxios-style errors from generic exceptions and logs detailed error payloads only in the gaxios case, which is a reasonable balance.

src/providers/google/ai.studio.ts (1)

228-244: LGTM!

The callApi method correctly awaits MCP initialization before proceeding, validates the API key early with a clear error message, and properly routes to Gemini or legacy PaLM paths based on model name.

src/providers/google/auth.ts (3)

106-158: LGTM!

The getApiKey method correctly implements the config priority order (explicit options > environment variables), aligns with Python SDK patterns, and provides helpful warnings for deprecated or non-standard environment variables. The PALM_API_KEY exclusion for Vertex mode is appropriate.


318-382: LGTM!

The getOAuthClient method correctly handles dynamic import of google-auth-library with a clear error message if missing, properly merges auth options with precedence for explicit values, and gracefully handles project ID detection failures by deferring to resolveProjectId.


450-479: LGTM!

The resolveRegion method correctly implements SDK-aligned defaults ('global' for OAuth mode, 'us-central1' for API key mode) and follows the config priority order with appropriate warnings for non-standard environment variables.

src/providers/google/vertex.ts (5)

66-158: LGTM!

The VertexChatProvider class correctly forces Vertex mode, implements proper API host resolution based on region (with special handling for 'global'), and the getAuthHeaders method appropriately adds the API key header only in express mode.


333-350: LGTM!

The isExpressMode logic correctly auto-enables express mode when an API key is available while allowing users to opt out with expressMode: false. This aligns with the PR's goal of simplifying the user experience.


218-331: LGTM!

The callClaudeApi method correctly uses OAuth authentication (no express mode for Anthropic models on Vertex) and properly constructs the rawPredict endpoint with project and location.


995-1004: LGTM!

The VertexEmbeddingProvider.getClientWithCredentials method is properly updated to use the new object-based getGoogleClient API, forwarding all relevant auth configuration options consistently with VertexChatProvider.


370-388: LGTM!

The Gemini API correctly uses getAllTools(context) from the base class to consolidate MCP and config-defined tools, maintaining consistency with the AI Studio provider implementation.

Comment on lines 459 to 468
if (this.isExpressMode()) {
// Express mode: use simplified endpoint with API key
const apiKey = this.getApiKey();
const url = `https://aiplatform.googleapis.com/${this.getApiVersion()}/publishers/${this.getPublisher()}/models/${this.modelName}:${endpoint}?key=${apiKey}`;
// Express mode: use simplified endpoint with API key in header
const url = `https://aiplatform.googleapis.com/${this.getApiVersion()}/publishers/${this.getPublisher()}/models/${this.modelName}:${endpoint}`;

const res = await fetchWithProxy(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
headers: await this.getAuthHeaders(),
body: JSON.stringify(body),
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/providers/google/vertex.ts | sed -n '450,500p'

Repository: promptfoo/promptfoo

Length of output: 182


🏁 Script executed:

# Check the getApiHost() implementation
rg -A 5 "getApiHost\(\)" src/providers/google/vertex.ts

Repository: promptfoo/promptfoo

Length of output: 1899


🏁 Script executed:

# Check if there's documentation about express mode
fd -t f -e md . | xargs rg -l -i "express.*mode" 2>/dev/null | head -20

Repository: promptfoo/promptfoo

Length of output: 228


🏁 Script executed:

# Look for config.apiHost usage in the vertex provider
rg "apiHost" src/providers/google/vertex.ts

Repository: promptfoo/promptfoo

Length of output: 169


🏁 Script executed:

# Check standard mode URL construction to understand the pattern
rg -B 5 -A 10 "getApiVersion\(\).*publishers" src/providers/google/vertex.ts

Repository: promptfoo/promptfoo

Length of output: 3470


🏁 Script executed:

cat site/docs/providers/vertex.md | head -200

Repository: promptfoo/promptfoo

Length of output: 8207


🏁 Script executed:

# Search for express mode and apiHost documentation
rg -A 10 -B 5 "express" site/docs/providers/vertex.md

Repository: promptfoo/promptfoo

Length of output: 4448


🏁 Script executed:

# Check configuration reference for apiHost documentation
rg -A 5 -B 5 "VERTEX_API_HOST|apiHost" site/docs/configuration/reference.md | head -100

Repository: promptfoo/promptfoo

Length of output: 45


Express mode ignores VERTEX_API_HOST configuration.

Express mode on line 461 hardcodes aiplatform.googleapis.com instead of using getApiHost(), which means the VERTEX_API_HOST environment variable and config.apiHost overrides are silently ignored. This contradicts the documented configuration option that specifies VERTEX_API_HOST as a valid override for proxies or custom endpoints. While express mode uses a simplified global endpoint by design, users attempting to configure a proxy will find their settings unexpectedly ignored.

🤖 Prompt for AI Agents
In src/providers/google/vertex.ts around lines 459-468, express mode currently
hardcodes the host "aiplatform.googleapis.com" which ignores
VERTEX_API_HOST/config.apiHost; change the URL construction to use
this.getApiHost() (or the existing getApiVersion()/getPublisher()/modelName and
endpoint) so the host can be overridden by configuration or env var, and ensure
getAuthHeaders()/fetchWithProxy still receive the correct full URL; update any
tests or callers if they depended on the hardcoded host.

mldangelo and others added 2 commits January 4, 2026 04:33
- Remove duplicate OAuthClientOptions export in auth.ts
- Add ImageGenerationResponse interface in image.ts
- Fix client.request type arguments (use `as` casting instead of type parameters)
- Add status/statusText to FetchWithCacheResult mocks in provider.test.ts
- Fix credentials type (should be JSON string, not object)
- Fix parameter type 'object' -> 'OBJECT' for Gemini schema

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@mldangelo mldangelo force-pushed the feat/google-provider-refactor branch from a2a42da to 8e500ce Compare January 4, 2026 09:38
@mldangelo mldangelo marked this pull request as draft January 4, 2026 09:40
mldangelo and others added 3 commits January 4, 2026 04:49
Reverts cache.ts changes and implements auth-aware cache key discrimination
directly in the Google provider layer instead.

The new approach:
- Adds createAuthCacheDiscriminator() helper in util.ts to hash auth headers
- Passes _authHash property to fetchWithCache options (included in cache key)
- Prevents cross-tenant cache pollution without modifying core cache logic

This keeps the cache.ts module unchanged and contains the auth-aware caching
logic within the Google provider where it's needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates test mocks to include createAuthCacheDiscriminator returning
empty string to prevent _authHash from being added to fetchWithCache
calls, keeping test assertions unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors Google provider architecture to consolidate AI Studio and Vertex AI implementations, aligning with the official @google/genai SDK v1.34.0 patterns.

Key changes:

  • Centralized authentication via GoogleAuthManager with SDK-aligned priority order (GOOGLE_API_KEY > GEMINI_API_KEY)
  • New abstract GoogleGenericProvider base class with shared MCP integration and tool handling
  • Unified GoogleProvider for both AI Studio and Vertex AI modes
  • Express mode auto-detection for Vertex AI when API key is present
  • Auth headers in cache key to prevent cross-tenant pollution

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/providers/google/auth.ts New centralized auth manager handling API keys, OAuth, credentials loading
src/providers/google/base.ts Abstract base class with MCP, tool normalization, function callbacks
src/providers/google/provider.ts Unified provider implementation for AI Studio and Vertex modes
src/providers/google/vertex.ts Simplified to extend base class, delegates auth to manager
src/providers/google/ai.studio.ts Refactored to extend base class
src/providers/google/util.ts Auth functions delegated to auth.ts, added cache discriminator
src/providers/google/types.ts New config options for SDK alignment
test/providers/google/*.test.ts Comprehensive test coverage for new architecture
site/docs/providers/*.md Updated documentation for new auth patterns

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 283 to 294
/**
* Control Vertex AI express mode (API key authentication).
* Enable Vertex AI express mode (API key authentication).
*
* SDK Alignment: Express mode must be EXPLICITLY enabled. Vertex AI defaults
* to OAuth/ADC authentication. Using API keys for Vertex may hit different
* quotas or fail with project-scoped features (files, caches).
*
* Express mode is AUTOMATIC when an API key is available and no explicit
* projectId or credentials are configured. Set to `false` to force OAuth
* authentication even when an API key is present.
* Set to `true` to use API key authentication instead of OAuth/ADC.
* Requires an API key (via GOOGLE_API_KEY or config.apiKey).
*
* @default undefined (automatic detection)
* @default false (uses OAuth/ADC)
* @see https://cloud.google.com/vertex-ai/generative-ai/docs/start/express-mode
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description for expressMode states it must be "EXPLICITLY enabled" and defaults to false (uses OAuth/ADC). However, the implementation in isExpressMode() shows it's automatically enabled when an API key is present (unless expressMode: false). This is inconsistent with the documented behavior. The comment should reflect that express mode is AUTOMATIC when an API key is available, not that it must be explicitly enabled.

Copilot uses AI. Check for mistakes.
config: {
vertexai: true,
apiKey: 'vertex-api-key',
expressMode: true, // SDK aligned: must be explicit
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "SDK aligned: must be explicit" but the code shows expressMode: true is explicitly set. However, according to the PR description and other parts of the code, express mode should be AUTOMATIC when an API key is present. This test appears to contradict the documented behavior. Either the test should remove the explicit expressMode: true to test automatic detection, or the comment should be updated to explain why explicit mode is being tested here.

Suggested change
expressMode: true, // SDK aligned: must be explicit
// Explicitly enable express mode here to test this path; normally it's auto-enabled when an apiKey is present.
expressMode: true,

Copilot uses AI. Check for mistakes.
Comment on lines 495 to 503
/**
* Clear the cached auth client (useful for testing).
* @deprecated No longer uses global caching; each call creates a new auth instance.
*/
static clearCache(): void {
// No-op: Global caching was removed in favor of per-call auth instances
// This matches Google's official SDK behavior
}
}
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "SDK aligned, no global cache" but this describes a significant behavior change where previously cached auth clients are now created per-call. This could have performance implications for applications making many API calls. The implementation should either document this performance impact or reconsider the no-caching approach for frequently-accessed clients.

Copilot uses AI. Check for mistakes.
mldangelo and others added 4 commits January 4, 2026 05:12
- Fix express mode URLs in vertex.ts and provider.ts to use getApiHost()
  instead of hardcoded aiplatform.googleapis.com
- Update expressMode JSDoc to accurately reflect auto-enable behavior
  when API key is present

Addresses PR review comments:
- CodeRabbit: Express mode now respects VERTEX_API_HOST config
- Copilot: Documentation now matches implementation behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update test comment at provider.test.ts:668 to clarify express mode
  is auto-enabled when apiKey is present (not "must be explicit")
- Clarify auth.ts clearCache() comment to explain that token caching
  is handled internally by google-auth-library, not removed entirely

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolve conflicts:
- src/providers/google/live.ts: Keep detailed OAuth2 error message from main
- src/providers/google/util.ts: Keep re-exports from auth.ts, add clearCachedAuth
- test/providers/google/live.test.ts: Update test to match new error message

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants