mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-09 17:19:02 +00:00
* fix(model): disambiguate providers sharing a model id by baseUrl (#5173) When multiple modelProviders.openai entries share the same model id but have different baseUrl values, selecting one in the model picker was not remembered across restarts — startup always resolved to the first id match. The gap was at the persistence -> startup-resolution boundary: - persistModelSelection only saved model.name, dropping the baseUrl that distinguishes the providers. - resolveCliGenerationConfig matched providers by id alone (first hit). Fix (CLI only; runtime switching and ModelRegistry composite keys were already correct): - Add optional model.baseUrl setting paired with model.name. - ModelDialog persists the selected provider's baseUrl, and clears it when the selection has none (prevents a stale disambiguator). - /model <id> is an id-only switch, so it clears model.baseUrl too. - resolveCliGenerationConfig disambiguates by the persisted baseUrl when the model comes from settings, falling back to the first id match when the paired provider was edited/removed or no baseUrl was saved. This keeps the persistence layer consistent with ModelRegistry's existing id+baseUrl composite key and syncAfterAuthRefresh's exact-match path. * fix(model): clear model.baseUrl on ACP setModel and provider install Round-1 review follow-up: extend the "any writer of model.name must set or clear model.baseUrl" invariant to the remaining id-only persistence paths so a stale disambiguator from a prior model-picker selection can't restore the wrong provider on next launch. - ACP Session.setModel clears model.baseUrl alongside model.name. - Provider install plan (core) clears model.baseUrl when selecting a model id. * fix(auth): disambiguate provider by baseUrl in pre-flight auth validation Round-2 review follow-up: validateAuthMethod / hasApiKeyForAuth looked up the provider by model id only, so for duplicate-id configs the auth and Anthropic baseUrl checks could validate the first provider's credentials instead of the selected one. - findModelConfig now prefers the exact id+baseUrl match and falls back to the first id match (mirrors resolveCliGenerationConfig). - New resolveSelectedModel helper pairs the resolved/persisted model id with its baseUrl (runtime generationConfig first, then settings.model.{name,baseUrl}). - Thread the baseUrl into both the API-key and Anthropic-baseUrl lookups. * fix(auth): pair model with its own baseUrl; document cross-scope assumption Round-3 review follow-up: - resolveSelectedModel no longer falls back to settings.model.baseUrl when a live Config is present, so a runtime-selected model is never paired with a stale persisted baseUrl from a previous selection. - Document the merged-settings assumption at the resolver disambiguation site: every writer pairs model.name + model.baseUrl in the same scope, and the id-only fallback bounds the blast radius if a hand-edited config desyncs them across scopes. * fix(model): use empty-string tombstone to clear model.baseUrl across scopes Round-4 review follow-up: clearing model.baseUrl by writing undefined drops the key from JSON, so a higher-priority scope's clear could not override a stale model.baseUrl left in a lower-priority scope — the stale disambiguator would resurface on merge and re-select the wrong duplicate provider after restart (e.g. pick a provider in user scope, then /model <id> in a workspace that has its own modelProviders). All clear sites (model picker, /model, ACP setModel, provider install) now write an empty-string tombstone, which is a present value that overrides lower scopes on merge. The resolver and auth lookup already treat '' as "no disambiguator". * fix(acp): clear model.baseUrl when setCoreValue sets model.name Round-5 review follow-up: the generic qwen/settings/setCoreValue RPC (ACP/serve) can change model.name directly without touching model.baseUrl, leaving a stale disambiguator from a prior model-picker selection that would re-select the wrong duplicate provider on next launch. Clear it with the same empty-string tombstone used by the other id-only model.name writers. * fix(model): warn on silent provider fallback; pair baseUrl with resolved config Address review comments: - Emit a warning when the persisted model.baseUrl no longer matches any provider and resolution falls back to the first id match (thread 1 [Critical]). - Source effectiveBaseUrl from the resolved config (after?.baseUrl) rather than the picker entry alone, so the persisted (model.name, model.baseUrl) pair stays consistent even if switchModel transforms the id (thread 2 [Critical]). * test(model): cover effectiveBaseUrl fallback to picker entry baseUrl Add a ModelDialog test where switchModel succeeds but getContentGeneratorConfig returns a config without baseUrl, exercising the 'after?.baseUrl ?? selectedEntry?.model.baseUrl' fallback. Without coverage, a regression there would silently write an empty-string tombstone and resolve the wrong same-id provider on next launch. |
||
|---|---|---|
| .. | ||
| src | ||
| index.ts | ||
| package.json | ||
| test-setup.ts | ||
| tsconfig.json | ||
| vitest.config.ts | ||