What happened?
The documentation states that
For providers with partial OpenAI compatibility, use the compat field.
<snip>
| Field |
Description |
openRouterRouting |
OpenRouter provider routing preferences. This object is sent as-is in the provider field of the OpenRouter API request. |
However, in reality the provider field is only sent if baseUrl contains "openrouter.ai":
|
if (model.baseUrl.includes("openrouter.ai") && model.compat?.openRouterRouting) { |
There are cases, when baseUrl could be different from "openrouter.ai", but sending the provider field should still be sent:
-
Some LLM providers support many options from the OpenRouter API extensions (including the provider object), not just the ai-sdk/openai-compatible subset.
-
It's possible that baseUrl points to a proxy / gateway of some kind that eventually forwards the requests to openrouter.ai. In that case, checking model.baseUrl.includes("openrouter.ai") doesn't make sense.
Steps to reproduce
-
Run a local HTTP server that simply logs all HTTP requests before forwarding them to openrouter.ai.
-
Use the following models.json:
{
"providers": {
"local-openrouter-proxy": {
"baseUrl": "http://127.0.0.1:8000/api/v1",
"api": "openai-completions",
"apiKey": "whatever",
"models": [
{
"id": "deepseek/deepseek-v4-pro",
"compat": {"openRouterRouting": {"only": ["DeepSeek"], "allow_fallbacks": false}}
}
]
}
}
}
-
Observe the fact that pi silently ignores the openRouterRouting key (no provider object is inserted into the requests).
Expected behavior
The openRouterRouting key should always insert a provider object into the request, no matter what baseUrl is.
I am temporarily working around this issue with this extension:
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.on("before_provider_request", (event, ctx) => {
const provider = ctx.model?.compat?.openRouterRouting;
if (provider !== undefined) {
return { ...event.payload, provider };
}
});
}
But ideally, I think, this should be fixed in pi itself.
Version
0.76.0
What happened?
The documentation states that
However, in reality the
providerfield is only sent ifbaseUrlcontains"openrouter.ai":pi/packages/ai/src/providers/openai-completions.ts
Line 613 in ea3465a
There are cases, when
baseUrlcould be different from"openrouter.ai", but sending theproviderfield should still be sent:Some LLM providers support many options from the OpenRouter API extensions (including the
providerobject), not just theai-sdk/openai-compatiblesubset.It's possible that
baseUrlpoints to a proxy / gateway of some kind that eventually forwards the requests toopenrouter.ai. In that case, checkingmodel.baseUrl.includes("openrouter.ai")doesn't make sense.Steps to reproduce
Run a local HTTP server that simply logs all HTTP requests before forwarding them to
openrouter.ai.Use the following
models.json:{ "providers": { "local-openrouter-proxy": { "baseUrl": "http://127.0.0.1:8000/api/v1", "api": "openai-completions", "apiKey": "whatever", "models": [ { "id": "deepseek/deepseek-v4-pro", "compat": {"openRouterRouting": {"only": ["DeepSeek"], "allow_fallbacks": false}} } ] } } }Observe the fact that
pisilently ignores theopenRouterRoutingkey (noproviderobject is inserted into the requests).Expected behavior
The
openRouterRoutingkey should always insert aproviderobject into the request, no matter whatbaseUrlis.I am temporarily working around this issue with this extension:
But ideally, I think, this should be fixed in
piitself.Version
0.76.0