feat(vertex): add API key (Express Mode) auth with region-specific model discovery - #70562
feat(vertex): add API key (Express Mode) auth with region-specific model discovery#70562ddm667 wants to merge 12 commits into
Conversation
… 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
…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.
UI/UX Integration UpdateAdditional changes pushed to the branch:
|
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.
Desktop Settings UI UpdateAdded The longest-prefix match in Users set their Vertex credentials directly from the Desktop UI: Settings → Providers → Keys → find |
…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).
|
Withdrawing in favor of a new PR with the completed implementation including auth_header propagation, native generateContent endpoint fix, and auxiliary client fix. |
Adds API key (Express Mode) authentication for Google Vertex AI alongside the existing OAuth2/ADC path.