fix: prevent double-prefix for openrouter/auto model

OpenRouter API returns model IDs with the provider prefix already
included (e.g., "openrouter/auto"). This was causing two issues:

1. model-scan was blindly prefixing, creating "openrouter/openrouter/auto"
2. Model lookup failed because pi-ai catalog expects "openrouter/auto"

Fix by normalizing at boundaries:
- Strip prefix at input (model-scan)
- Add fallback lookup at output (resolveModel)

This keeps internal representation clean while handling pi-ai's
catalog structure.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Karun Agarwal 2026-01-27 12:55:29 +05:30
parent 066b222b28
commit 77f6133351
3 changed files with 50 additions and 2 deletions

View File

@ -85,4 +85,40 @@ describe("scanOpenRouterModels", () => {
}
}
});
it("avoids double-prefixing openrouter/ in modelRef", async () => {
const fetchImpl = createFetchFixture({
data: [
{
id: "openrouter/auto",
name: "OpenRouter Auto",
context_length: 128_000,
max_completion_tokens: 4096,
supported_parameters: ["tools"],
modality: "text",
pricing: { prompt: "0", completion: "0" },
},
{
id: "meta-llama/llama-3.3-70b:free",
name: "Llama 3.3 70B",
context_length: 8_192,
supported_parameters: [],
modality: "text",
pricing: { prompt: "0", completion: "0" },
},
],
});
const results = await scanOpenRouterModels({
fetchImpl,
probe: false,
});
// IDs are normalized (prefix stripped), but modelRefs are correct
expect(results.map((entry) => entry.id)).toEqual(["auto", "meta-llama/llama-3.3-70b:free"]);
expect(results.map((entry) => entry.modelRef)).toEqual([
"openrouter/auto",
"openrouter/meta-llama/llama-3.3-70b:free",
]);
});
});

View File

@ -177,8 +177,13 @@ async function fetchOpenRouterModels(fetchImpl: typeof fetch): Promise<OpenRoute
.map((entry) => {
if (!entry || typeof entry !== "object") return null;
const obj = entry as Record<string, unknown>;
const id = typeof obj.id === "string" ? obj.id.trim() : "";
let id = typeof obj.id === "string" ? obj.id.trim() : "";
if (!id) return null;
// Normalize: strip "openrouter/" prefix if present to keep internal IDs clean.
// The prefix will be added back when constructing modelRef.
if (id.startsWith("openrouter/")) {
id = id.slice("openrouter/".length);
}
const name = typeof obj.name === "string" && obj.name.trim() ? obj.name.trim() : id;
const contextLength =

View File

@ -49,7 +49,14 @@ export function resolveModel(
const resolvedAgentDir = agentDir ?? resolveClawdbotAgentDir();
const authStorage = discoverAuthStorage(resolvedAgentDir);
const modelRegistry = discoverModels(authStorage, resolvedAgentDir);
const model = modelRegistry.find(provider, modelId) as Model<Api> | null;
let model = modelRegistry.find(provider, modelId) as Model<Api> | null;
// Fallback: Some models in pi-ai have the provider prefix in their ID (e.g., "openrouter/auto").
// Our internal representation normalizes this to "auto", but pi-ai expects "openrouter/auto".
if (!model && provider === "openrouter") {
model = modelRegistry.find(provider, `${provider}/${modelId}`) as Model<Api> | null;
}
if (!model) {
const providers = cfg?.models?.providers ?? {};
const inlineModels = buildInlineProviderModels(providers);