Add OpenRouter platform: wire-served metadata (provider 8)

The 11th registry row and the first THIRD-PARTY wire_serves_metadata=true
provider: id "openrouter", OPENROUTER_API_KEY > auth.json "openrouter"
scope, https://openrouter.ai/api/v1 (note /api/v1) with
KIGI_OPENROUTER_BASE_URL override, Bearer, OpenAI listing +
ChatCompletions + Passthrough.

OpenRouter's public /models serves context_length for every model
(verified live: 340/340), so it needs NO enrichment: models_dev_id=None,
wire_serves_metadata=true, restrict_to_enriched=false. An OpenRouter-only
user makes zero models.dev calls; context comes straight from the listing.
Slashed ids (anthropic/claude-opus-4.8) round-trip through the managed key
via the first-slash split; the native id rides the wire. The e2e pins all
of this with the models.dev refresh disabled.

Review-confirmed defect fixed (and independently re-verified with live
curls): OpenRouter's /models is PUBLIC — GET /models returns 200 for ANY
key — so login key-validation would false-accept a bad key, deferring the
failure to the first chat 401. New spec field key_validation_path lets a
public-listing platform validate against an auth-requiring endpoint;
OpenRouter uses /key (401s for bad keys). Reusable for Vercel (also
public). Tests pin the /key validation and no regression to the default
/models path.

Gate caught a fixture regression: the kimi_import test used openrouter.ai
to represent a CUSTOM provider, which now correctly dedupes to the builtin
OpenRouter — moved the fixture to a reserved llm.example.test host that no
future platform can shadow.
This commit is contained in:
2026-07-21 12:41:14 -04:00
parent 7a2cd8a726
commit e7dbb98207
5 changed files with 257 additions and 15 deletions
+5 -5
View File
@@ -611,7 +611,7 @@ model = "kimi-for-coding"
max_context_size = 262144
[models.my-openai]
provider = "openrouter"
provider = "customllm"
model = "gpt-x"
max_context_size = 128000
@@ -620,9 +620,9 @@ type = "kimi"
base_url = "https://api.kimi.com/coding/v1"
api_key = "sk-kimi-secret"
[providers.openrouter]
[providers.customllm]
type = "openai_legacy"
base_url = "https://openrouter.ai/api/v1"
base_url = "https://llm.example.test/v1"
api_key = "sk-or-secret"
"#,
)
@@ -711,7 +711,7 @@ api_key = "sk-or-secret"
let m = &plan.custom_models[0];
assert_eq!(m.alias, "my-openai");
assert_eq!(m.model, "gpt-x");
assert_eq!(m.base_url, "https://openrouter.ai/api/v1");
assert_eq!(m.base_url, "https://llm.example.test/v1");
assert_eq!(m.api_key.as_deref(), Some("sk-or-secret"));
assert_eq!(m.context_window, Some(128_000));
@@ -850,7 +850,7 @@ api_key = "sk-ms"
assert_eq!(model["model"].as_str().unwrap(), "gpt-x");
assert_eq!(
model["base_url"].as_str().unwrap(),
"https://openrouter.ai/api/v1"
"https://llm.example.test/v1"
);
assert_eq!(model["api_key"].as_str().unwrap(), "sk-or-secret");
assert_eq!(model["context_window"].as_integer().unwrap(), 128_000);