fix(providers): byte-sync vertex SSOT into core registry (P1.8 / #561) #2333

Merged
claude-ceo-assistant merged 1 commits from fix/vertex-ssot-registry-drift into main 2026-06-06 05:05:51 +00:00
3 changed files with 39 additions and 9 deletions
@@ -16,7 +16,7 @@ const SchemaVersion = 1
// Fingerprint is a stable content hash of the generated projection (schema
// version + provider catalog + runtime native sets). It changes iff the
// registry DATA changes (comment-only YAML edits do not churn it).
const Fingerprint = "e457249eb0fd77a2"
const Fingerprint = "9d129c96c9df9689"
// GenProvider is the generated projection of one provider catalog entry —
// the subset a downstream consumer needs to derive + display a provider.
@@ -56,7 +56,7 @@ var Providers = []GenProvider{
{Name: "kimi-coding", DisplayName: "Moonshot Kimi (coding-tuned)", Protocol: "anthropic", AuthMode: "third_party_anthropic_compat", AuthEnv: []string{"KIMI_API_KEY", "ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"}, ModelPrefixMatch: "^kimi-", IsPlatform: false},
{Name: "deepseek", DisplayName: "DeepSeek", Protocol: "anthropic", AuthMode: "third_party_anthropic_compat", AuthEnv: []string{"DEEPSEEK_API_KEY", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_API_KEY"}, ModelPrefixMatch: "^deepseek[-:/]", IsPlatform: false},
{Name: "google", DisplayName: "Google Gemini", Protocol: "openai", AuthMode: "third_party_anthropic_compat", AuthEnv: []string{"GEMINI_API_KEY", "GOOGLE_API_KEY"}, ModelPrefixMatch: "^gemini-", IsPlatform: false},
{Name: "vertex", DisplayName: "Google Vertex AI (keyless ADC)", Protocol: "openai", AuthMode: "third_party_anthropic_compat", AuthEnv: []string{"GOOGLE_APPLICATION_CREDENTIALS"}, ModelPrefixMatch: "^vertex:", IsPlatform: false},
{Name: "vertex", DisplayName: "Google Vertex AI (keyless ADC)", Protocol: "openai", AuthMode: "wif_adc", AuthEnv: []string{"GOOGLE_APPLICATION_CREDENTIALS"}, ModelPrefixMatch: "^vertex:", IsPlatform: false},
{Name: "alibaba", DisplayName: "Alibaba Qwen (DashScope)", Protocol: "openai", AuthMode: "third_party_anthropic_compat", AuthEnv: []string{"DASHSCOPE_API_KEY", "ALIBABA_API_KEY"}, ModelPrefixMatch: "(?i)^(qwen|alibaba[:/])", IsPlatform: false},
{Name: "nousresearch", DisplayName: "Nous Research (Hermes)", Protocol: "openai", AuthMode: "third_party_anthropic_compat", AuthEnv: []string{"NOUSRESEARCH_API_KEY"}, ModelPrefixMatch: "^nousresearch[:/]", IsPlatform: false},
{Name: "openrouter", DisplayName: "OpenRouter (any model)", Protocol: "openai", AuthMode: "third_party_anthropic_compat", AuthEnv: []string{"OPENROUTER_API_KEY"}, ModelPrefixMatch: "^openrouter[:/]", IsPlatform: false},
@@ -28,9 +28,20 @@
# display_name canvas dropdown label
# vendor_logo canvas asset key
# protocol openai | anthropic (proxy wire format)
# auth_mode anthropic_api | oauth | third_party_anthropic_compat
# base_url_template base URL for the openai-protocol surface (null = CLI/SDK default)
# auth_mode anthropic_api | oauth | third_party_anthropic_compat |
# wif_adc (keyless AWS→GCP WIF server-side mint; the one
# value the proxy ACTS on — triggers vertexauth.Token)
# base_url_template base URL for the openai-protocol surface (null = CLI/SDK
# default). MAY contain {placeholder} tokens resolved at
# resolution time from endpoint_vars (RFC vertex-provider-
# ssot-endpoint §Design 1) — e.g. vertex's {location}/{project}.
# base_url_anthropic base URL for the anthropic-protocol surface (where applicable)
# endpoint_vars OPTIONAL map placeholder -> {env, default}: how each
# {placeholder} in base_url_template is resolved (env when
# set + non-empty, else default — the structured form of the
# proxy's envOr). Empty/absent = static URL (today's shape).
# wire_model_prefix OPTIONAL publisher prefix the upstream expects on the wire
# model id ("google/" for vertex). Empty = unprefixed.
# auth_env env var names accepted (NAMES ONLY — never secrets); any one satisfies auth
# auth_token_env env var the adapter projects the vendor key INTO (default ANTHROPIC_AUTH_TOKEN)
# model_prefix_match RE2 regex unifying proxy inferLLMProvider prefixes +
@@ -428,15 +439,34 @@ providers:
#
# NOTE: display_name ("keyless ADC") and auth_env (GOOGLE_APPLICATION_CREDENTIALS)
# are now VESTIGIAL — no consumer reads auth_env post-leak-fix, but it must stay
# non-empty (providers.go validate). Left as-is to keep this a comment-only,
# regen-free change; retiring them is a registry-regen follow-up.
# non-empty (providers.go validate). Retiring them is a follow-up.
#
# RFC vertex-provider-ssot-endpoint (Phase 1): the endpoint that used to live
# ONLY in llm_proxy.go's `case "google", "vertex":` fmt.Sprintf is now
# expressed HERE as a templated base_url_template + endpoint_vars, and the
# keyless WIF mint is declared via auth_mode: wif_adc. The proxy resolves this
# row through Manifest.ResolveEndpoint — the interpolated URL is BYTE-IDENTICAL
# to the former fmt.Sprintf (drift-gated by TestProxyEndpointsMatchManifest).
# wire_model_prefix replaces the proxy's inline `if !HasPrefix(wireModel,
# "google/")`. (Phase 2 migrates the remaining static providers; out of scope.)
- name: vertex
display_name: "Google Vertex AI (keyless ADC)"
vendor_logo: "google"
protocol: openai
auth_mode: third_party_anthropic_compat
base_url_template: null
# wif_adc (AuthModeWIFADC): keyless AWS→GCP Workload Identity Federation
# server-side token mint (internal/vertexauth.Token). The ONE auth_mode the
# proxy acts on — it triggers the mint instead of a hardcoded `case "vertex"`.
auth_mode: wif_adc
# Templated endpoint: {location}/{project} interpolated from endpoint_vars
# below. Reproduces the proxy's former
# fmt.Sprintf("https://%s-aiplatform.googleapis.com/v1beta1/projects/%s/locations/%s/endpoints/openapi", loc, proj, loc).
base_url_template: "https://{location}-aiplatform.googleapis.com/v1beta1/projects/{project}/locations/{location}/endpoints/openapi"
base_url_anthropic: null
endpoint_vars:
location: { env: MOLECULE_VERTEX_LOCATION, default: us-central1 }
project: { env: MOLECULE_VERTEX_PROJECT, default: molecule-vertex }
# Vertex requires the publisher-prefixed model id on the wire (google/<model>).
wire_model_prefix: "google/"
auth_env: [GOOGLE_APPLICATION_CREDENTIALS]
auth_token_env: ANTHROPIC_AUTH_TOKEN
model_prefix_match: "^vertex:"
@@ -29,7 +29,7 @@ import (
// canonicalProvidersYAMLSHA256 is the sha256 of the canonical providers.yaml as
// synced from molecule-controlplane. Bumped deliberately on each re-sync (see
// file doc). Cross-checked live by the sync-providers-yaml CI workflow.
const canonicalProvidersYAMLSHA256 = "9eb6f97fc37b528c91936be4a75dd87f6c7172742b4535d76b9bb2231ee18e80"
const canonicalProvidersYAMLSHA256 = "58bc38648674e77c6ffa6ffe41e911bec8c68da56d028550f2e39dedc4aa25ae"
func TestSyncedYAMLMatchesCanonicalSHA(t *testing.T) {
sum := sha256.Sum256(embeddedYAML)