fix(model): infer provider from allowlist for bare model IDs to prevent prefix drift#51580
Conversation
Greptile SummaryThis PR fixes a provider prefix drift bug in The fix is minimal and targeted: before passing Key changes:
One minor gap: the tie-breaking fallback path (where the same bare model ID matches multiple allowlist providers and the session default is used) has no dedicated test, leaving a small surface for silent regressions if Confidence Score: 5/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/model-selection.test.ts
Line: 490-516
Comment:
**Consider adding a test for the ambiguous case**
The fix relies on `inferUniqueProviderFromConfiguredModels` returning `undefined` when the same bare model ID exists under more than one allowlist provider, and then falling back to `params.defaultProvider`. This fallback path isn't exercised by the new test, so a future refactor of `inferUniqueProviderFromConfiguredModels` could silently break it.
A test that configures the same model under two providers and asserts that the session's `defaultProvider` wins would close this gap and document the intended tie-breaking behaviour.
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: "fix(model): infer pr..." |
| it("infers provider from allowlist for bare model ids to prevent prefix drift (#48369)", () => { | ||
| const cfg = { | ||
| agents: { | ||
| defaults: { | ||
| models: { | ||
| "openai-codex/gpt-5.4": {}, | ||
| "opencode-go/kimi-k2.5": {}, | ||
| "opencode-go/glm-5": {}, | ||
| }, | ||
| }, | ||
| }, | ||
| } as OpenClawConfig; | ||
|
|
||
| // When session default is openai-codex, switching to a bare "kimi-k2.5" | ||
| // should resolve to opencode-go/kimi-k2.5, not openai-codex/kimi-k2.5 | ||
| const result = resolveAllowedModelRef({ | ||
| cfg, | ||
| catalog: [], | ||
| raw: "kimi-k2.5", | ||
| defaultProvider: "openai-codex", // session's current provider | ||
| }); | ||
|
|
||
| expect(result).toEqual({ | ||
| key: "opencode-go/kimi-k2.5", | ||
| ref: { provider: "opencode-go", model: "kimi-k2.5" }, | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Consider adding a test for the ambiguous case
The fix relies on inferUniqueProviderFromConfiguredModels returning undefined when the same bare model ID exists under more than one allowlist provider, and then falling back to params.defaultProvider. This fallback path isn't exercised by the new test, so a future refactor of inferUniqueProviderFromConfiguredModels could silently break it.
A test that configures the same model under two providers and asserts that the session's defaultProvider wins would close this gap and document the intended tie-breaking behaviour.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/model-selection.test.ts
Line: 490-516
Comment:
**Consider adding a test for the ambiguous case**
The fix relies on `inferUniqueProviderFromConfiguredModels` returning `undefined` when the same bare model ID exists under more than one allowlist provider, and then falling back to `params.defaultProvider`. This fallback path isn't exercised by the new test, so a future refactor of `inferUniqueProviderFromConfiguredModels` could silently break it.
A test that configures the same model under two providers and asserts that the session's `defaultProvider` wins would close this gap and document the intended tie-breaking behaviour.
How can I resolve this? If you propose a fix, please make it concise.49f3f39 to
b33a928
Compare
b33a928 to
fac0a48
Compare
|
Landed on
Thanks @honwee. |
Fixes #48369
Also related: #48096, #48128, #48224, #48256 (5th reported instance of this bug)
Problem
When switching models across different providers via the Control UI (WebChat), bare model IDs (without
provider/prefix) get resolved against the session's current default provider instead of the correct one from the configured allowlist.Example: if the session default is
openai-codex/gpt-5.4and you switch tokimi-k2.5, it incorrectly resolves toopenai-codex/kimi-k2.5instead ofopencode-go/kimi-k2.5, then fails withmodel not allowed.Root Cause
resolveAllowedModelRef()inmodel-selection.tspassesdefaultProvider: resolvedDefault.provider(the session's current provider) toresolveModelRefFromString(). When the model string has no/,parseModelRef()applies this wrong default provider.Fix
When the model string has no
/, use the existinginferUniqueProviderFromConfiguredModels()to find the correct provider from the allowlist before falling back to the session's current default provider.Test