fix(coding-agent): resolve provider/id references when the provider id contains a slash (#11397)

`--model "<provider>/<id>"` returned "not found" when the provider id
itself contains a `/`. URL-derived ids such as
`llama-server=http://host:10800` are one example.
`splitProviderPrefix()` in `model-resolver.ts` split the reference at
the first `/`, which turned the prefix into `llama-server=http:`. No
provider has that id, so resolution fell through to not-found.

`splitProviderPrefix()` now compares the text against the provider ids
in the catalog. A provider matches when the text starts with its id
followed by `/`, and the longest matching id wins. Ordinary provider ids
resolve exactly as before.

Testing:
- I added two cases to the `resolveModelReference` table in
`test/model-resolver.test.ts`, using a provider
`llama=http://host:10800`: one plain, one with a `:high` thinking
suffix. Both fail without the change and pass with it. The test runs
every case against the catalog in both orders.
- `node ../../node_modules/vitest/dist/cli.js --run
test/model-resolver.test.ts`: 64 passed.
- `npm run check`: passes.
- Before the change, a standalone check of `resolveModelReference` with
the reporter's exact provider and model
(`llama-server=http://host:10800/unsloth/Qwen3.8-27B-GGUF:BF16`)
returned `not-found`. It now returns `resolved`.
- One test, `test/model-runtime-classifiers.test.ts` ("applies provider
compat from models.json to classifier models"), fails in my environment
both with and without this change. It is unrelated to this fix.

Fixes #11394

Requested by @badlogic

Co-authored-by: triagent <triagent@localhost>
This commit is contained in:
robopipi[bot] 2026-10-25 08:48:27 +01:00 • committed by GitHub
parent 5f960a0e2b
commit 984cf6643d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 24 additions and 7 deletions

View file

@ -128,13 +128,18 @@ function splitProviderPrefix(
text: string,
models: readonly Model<Api>[],
): { provider: string; modelText: string } | undefined {
const slashIndex = text.indexOf("/");
if (slashIndex === -1) return undefined;
const prefix = text.substring(0, slashIndex).trim().toLowerCase();
const modelText = text.substring(slashIndex + 1).trim();
if (!prefix || !modelText) return undefined;
const provider = models.find((model) => model.provider.toLowerCase() === prefix)?.provider;
return provider ? { provider, modelText } : undefined;
// Provider ids may contain "/" themselves (e.g. URL-derived ids), so match known ids, longest first
const lowerText = text.toLowerCase();
let best: { provider: string; modelText: string } | undefined;
for (const { provider } of models) {
const prefix = provider.trim().toLowerCase();
if (!prefix || (best && best.provider.length >= provider.length)) continue;
const slashIndex = lowerText.indexOf("/", prefix.length);
if (slashIndex === -1 || lowerText.substring(0, slashIndex).trim() !== prefix) continue;
const modelText = text.substring(slashIndex + 1).trim();
if (modelText) best = { provider, modelText };
}
return best;
}
/**

View file

@ -115,6 +115,8 @@ const referenceCatalog = [
referenceModel("gw-b", "claude-opus-4-8"),
referenceModel("gw-b", "gw-b/free"),
referenceModel("gw-b", "zz:free"),
// URL-derived provider id containing "/" (#11394)
referenceModel("llama=http://host:10800", "unsloth/qwen-gguf:BF16"),
];
type ReferenceExpected =
@ -152,6 +154,16 @@ const referenceCases: ReferenceCase[] = [
text: "openrouter/qwen/qwen3-coder:exacto:high",
expected: { model: "openrouter/qwen/qwen3-coder:exacto", thinkingLevel: "high" },
},
{
name: "provider id containing a slash",
text: "llama=http://host:10800/unsloth/qwen-gguf:BF16",
expected: { model: "llama=http://host:10800/unsloth/qwen-gguf:BF16" },
},
{
name: "provider id containing a slash, with thinking suffix",
text: "llama=http://host:10800/unsloth/qwen-gguf:BF16:high",
expected: { model: "llama=http://host:10800/unsloth/qwen-gguf:BF16", thinkingLevel: "high" },
},
{
name: "raw id wins when the provider prefix names no matching model",
text: "openai/gpt-4o:extended",