Skip to content

feat(vertex): add API key (Express Mode) auth with region-specific model discovery - #70562

Closed
ddm667 wants to merge 12 commits into
NousResearch:mainfrom
ddm667:feat/vertex-api-key-auth
Closed

feat(vertex): add API key (Express Mode) auth with region-specific model discovery#70562
ddm667 wants to merge 12 commits into
NousResearch:mainfrom
ddm667:feat/vertex-api-key-auth

Conversation

@ddm667

@ddm667 ddm667 commented Jul 24, 2026

Copy link
Copy Markdown

Adds API key (Express Mode) authentication for Google Vertex AI alongside the existing OAuth2/ADC path.

sjneoh93 added 5 commits July 24, 2026 12:13
… discovery

Add dual-auth support for Google Vertex AI:

1. API Key (Express Mode) — the recommended approach. Set
   GOOGLE_VERTEX_API_KEY, GOOGLE_VERTEX_PROJECT, and optionally
   GOOGLE_VERTEX_LOCATION in .env. No google-auth needed.

2. OAuth2 / ADC — legacy path preserved unchanged.

Key changes:

agent/vertex_adapter.py:
  - Add GOOGLE_VERTEX_API_KEY, GOOGLE_VERTEX_PROJECT, GOOGLE_VERTEX_LOCATION
    env var constants
  - Add has_vertex_api_key(), resolve_vertex_api_key(),
    build_vertex_api_key_base_url() functions
  - Update get_vertex_config() to auto-select API key vs OAuth2 path
  - Add discover_vertex_models() — queries Vertex's publisher models.list
    API for region-specific model availability
  - Update has_vertex_credentials() to detect API key

plugins/model-providers/vertex/__init__.py:
  - Add GOOGLE_VERTEX_API_KEY, GOOGLE_VERTEX_PROJECT, GOOGLE_VERTEX_LOCATION
    to env_vars
  - Implement fetch_models() using discover_vertex_models() for API key path

hermes_cli/runtime_provider.py:
  - Update comment and AuthError message for dual auth
  - Set source='vertex-api-key' vs 'vertex-oauth'

hermes_cli/model_setup_flows.py:
  - Rewrite _model_flow_vertex() to detect and advertise API key mode
  - Add dynamic model discovery via discover_vertex_models() when API key
    is set
  - Fall back to curated list when discovery fails or using OAuth2

hermes_cli/models.py:
  - Add curated "vertex" key to _PROVIDER_MODELS with 13 models
  - Update provider description

website/docs/guides/google-vertex.md:
  - Rewrite for dual-auth: API key (recommended) + OAuth2/ADC (legacy)
  - Add model discovery docs
- test_vertex_provider.py: update AuthError message assertion for
  new dual-auth error text (API Key + OAuth2)
- test_vertex_adapter.py: update default region from 'global' to
  'us-central1' to match new DEFAULT_REGION constant
New test coverage:
- has_vertex_api_key() / resolve_vertex_api_key() — env var detection
- build_vertex_api_key_base_url() — global, us-central1, europe-west4
- get_vertex_config() with API key — full config + precedence over ADC
- Missing project ID error handling
- has_vertex_credentials() via API key
- GOOGLE_VERTEX_LOCATION vs VERTEX_REGION precedence
- GOOGLE_VERTEX_PROJECT vs VERTEX_PROJECT_ID precedence
- discover_vertex_models() — parse response, filter by generateContent
- discover_vertex_models() — network errors, HTTP errors, malformed JSON
- discover_vertex_models() — sort order
Vertex API Express Mode requires the key sent as x-goog-api-key header,
not Authorization: Bearer (which only works for OAuth2 tokens).

- get_vertex_config() now returns 3-tuple: (key, base_url, auth_header_type)
  where auth_header_type is 'x-goog-api-key' for API key mode or
  'Authorization' for OAuth2/ADC mode
- runtime_provider.py propagates auth_header to downstream client
- Tests updated for 3-tuple return and new env var isolation
- Model discovery via publishers/google/models confirmed NOT available
  with API key auth (returns 404). Falls back to curated list.
- discover_vertex_models() docstring: explain that publishers/google/models
  returns 404 with API key (Express Mode); only works with OAuth2/ADC
- model_setup_flows.py: improve UX messages when discovery is unavailable
- Live test confirmed: inference with x-goog-api-key returns 200 OK on
  both native generateContent and OpenAI-compatible endpoints
@alt-glitch alt-glitch added type/feature New feature or request comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins provider/gemini Google Gemini (AI Studio, Cloud Code) area/auth Authentication, OAuth, credential pools sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data P3 Low — cosmetic, nice to have duplicate This issue or pull request already exists labels Jul 24, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #29611: both implement the Vertex Express Mode API-key path. #29611 is the earlier open implementation; #56363 is the distinct merged OAuth2/ADC path.

…API key auth

UI/UX changes:

- doctor.py: add GOOGLE_VERTEX_API_KEY, GOOGLE_VERTEX_PROJECT,
  GOOGLE_VERTEX_LOCATION to _PROVIDER_ENV_HINTS so `hermes doctor`
  reports them. Add Vertex to the API key provider health-check list
  (no /models probe since Express Mode has no list method).

- web_server.py: add GOOGLE_VERTEX_API_KEY, GOOGLE_VERTEX_PROJECT,
  GOOGLE_VERTEX_LOCATION as visible env vars in the web dashboard
  Keys tab under the Vertex provider card.

- auxiliary_client.py: update resolve_provider_client to use the
  3-tuple return from get_vertex_config(). When auth_header is
  x-goog-api-key, create the OpenAI client with default_headers
  instead of Authorization: Bearer.
@ddm667

ddm667 commented Jul 24, 2026

Copy link
Copy Markdown
Author

UI/UX Integration Update

Additional changes pushed to the branch:

  • hermes doctor: now detects and reports GOOGLE_VERTEX_API_KEY, GOOGLE_VERTEX_PROJECT, GOOGLE_VERTEX_LOCATION env vars. Shows "key configured" status for Vertex (no /models health check since Express Mode doesn't expose model listing).

  • Web dashboard (hermes dashboard): Vertex provider card now shows the API key env vars in the Keys tab alongside the legacy OAuth2 credential path.

  • auxiliary_client.py: updated the OpenAI client constructor to use x-goog-api-key header (via default_headers) instead of Authorization: Bearer when in API key mode. The OAuth2 path is unchanged.

Add GOOGLE_VERTEX_ prefix to PROVIDER_GROUPS so the Vertex AI API
key env vars (GOOGLE_VERTEX_API_KEY, GOOGLE_VERTEX_PROJECT,
GOOGLE_VERTEX_LOCATION) render as their own "Google Vertex AI"
card in the Desktop settings Keys tab, separate from the Gemini /
Google AI Studio card.

Longest-prefix matching ensures GOOGLE_VERTEX_ (14 chars) wins over
GOOGLE_ (7 chars) for vertex-prefixed variables.
@ddm667

ddm667 commented Jul 24, 2026

Copy link
Copy Markdown
Author

Desktop Settings UI Update

Added GOOGLE_VERTEX_ prefix to PROVIDER_GROUPS in apps/desktop/src/app/settings/constants.ts: the Vertex API key env vars (GOOGLE_VERTEX_API_KEY, GOOGLE_VERTEX_PROJECT, GOOGLE_VERTEX_LOCATION) now render as their own Google Vertex AI card in Settings → Keys, separate from the Gemini / Google AI Studio card.

The longest-prefix match in providerGroup() ensures GOOGLE_VERTEX_ (14 chars) wins over GOOGLE_ (7 chars) for vertex-prefixed variables.

Users set their Vertex credentials directly from the Desktop UI: Settings → Providers → Keys → find Google Vertex AI card → paste API key, project ID, and location.

sjneoh93 added 5 commits July 24, 2026 15:36
…oog-api-key support

The auth_header from resolve_runtime_provider() was being discarded in
model_switch.py, causing the main OpenAI client to send the Vertex API key
as Authorization: Bearer instead of x-goog-api-key, resulting in HTTP 401.

Changes:
- hermes_cli/model_switch.py: add auth_header to ModelSwitchResult + propagate
  from all 3 resolve_runtime_provider() call sites
- cli.py: pass auth_header to agent.switch_model() in all 3 call sites
- run_agent.py switch_model(): accept and forward auth_header
- agent/agent_runtime_helpers.py switch_model(): set default_headers with
  x-goog-api-key when auth_header indicates Express Mode
- run_agent.py _try_refresh_vertex_client_credentials(): handle 3-tuple return
  from get_vertex_config() and set default_headers on credential refresh
- run_agent.py _apply_client_headers_for_base_url(): add Vertex/aiplatform
  branch that detects API key mode via has_vertex_api_key()
Express Mode API keys don't work with Vertex's OpenAI-compatible
/endpoints/openapi/chat/completions endpoint (returns 404). They
only work with the native :generateContent API.

Changes:
- agent/vertex_adapter.py: build_vertex_api_key_base_url() now returns
  https://aiplatform.googleapis.com/v1/publishers/google for the native
  API, not the OpenAI-compatible endpoint URL. The project/region are
  embedded in the API key itself.
- agent/gemini_native_adapter.py: is_native_gemini_base_url() now
  accepts aiplatform.googleapis.com endpoints (not just
  generativelanguage.googleapis.com), so Vertex Express Mode routes
  through GeminiNativeClient which already handles x-goog-api-key auth,
  format conversion, and bare model name stripping.
- agent/auxiliary_client.py: _create_openai_client() detects native
  base URLs and routes through GeminiNativeClient for any provider,
  not just gemini.
- agent/agent_runtime_helpers.py: create_openai_client() detects native
  base URLs by URL pattern instead of checking provider name, so
  both gemini and vertex reach GeminiNativeClient.
- tests: updated URL assertions for the new native endpoint format.
The auxiliary client (title generation, vision, etc.) was creating a raw
OpenAI client for Vertex API key mode, which appends /chat/completions to
the native base URL and fails. Now routes through _create_openai_client
which auto-detects native URLs and creates GeminiNativeClient instead.

Also updates Vertex default_aux_model from google/gemini-3-flash-preview
(not available via Express Mode) to gemini-3.5-flash (verified working).
@ddm667

ddm667 commented Jul 24, 2026

Copy link
Copy Markdown
Author

Withdrawing in favor of a new PR with the completed implementation including auth_header propagation, native generateContent endpoint fix, and auxiliary client fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have provider/gemini Google Gemini (AI Studio, Cloud Code) sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants