#9739: #9291 fix(models): preserve existing models in models.json when merging providers
agents
stale
Cluster:
Model Configuration Fixes
When auth profiles are temporarily inaccessible (e.g., macOS keychain locked), the implicit providers don't include qwen-portal. If explicit config has qwen-portal without models array, the previous code replaced the existing provider entirely, losing vision-model.
Now uses mergeProviders() instead of simple spread when merging with existing models.json, which properly merges models at provider level.
Fixes #9291
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR changes `ensureOpenClawModelsJson()` to use a provider-level merge (`mergeProviders`) when combining newly-resolved providers with an existing `models.json`, with the intent of preserving previously persisted models when the incoming provider config omits a `models` array (e.g. when auth profiles/keychain are temporarily inaccessible). It also adds a Vitest regression test file covering the qwen-portal scenario.
In the broader codebase, `ensureOpenClawModelsJson()` is called by model listing, gateway/profile flows, and media tooling to keep `~/.openclaw/agents/*/models.json` up to date; merge-mode behavior directly impacts whether users retain or lose provider model catalogs across intermittent auth/profile failures.
<h3>Confidence Score: 3/5</h3>
- This PR is close to mergeable but has a likely merge-logic bug and a regression test that may not exercise the intended scenario.
- Switching to `mergeProviders()` is directionally correct, but `mergeProviderModels()` can still drop an existing provider's `models` array when the incoming provider omits `models` and the existing provider has no `models` field. The newly added test appears to create auth profiles, which may cause implicit providers to include qwen-portal and mask the problematic path.
- src/agents/models-config.ts; src/agents/models-config.preserves-existing-models-when-new-provider-has-none.test.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#15632: fix: use provider-qualified key in MODEL_CACHE for context window l...
by linwebs · 2026-02-13
81.5%
#9822: fix: allow local/custom model providers for sub-agent inference
by stammtobias91 · 2026-02-05
81.4%
#3322: fix: merge provider config api into registry model
by nulone · 2026-01-28
80.8%
#16988: fix: always regenerate models.json from gateway config
by MisterGuy420 · 2026-02-15
80.3%
#4459: fix: enable image input for Kimi K2.5 and refresh stale config mode...
by manikv12 · 2026-01-30
80.3%
#9583: fix(models): allow models in agents.defaults.models even if not in ...
by hotzen100 · 2026-02-05
80.2%
#12059: feat(agents): Add Azure AI Foundry credential support
by lisanyambere · 2026-02-08
80.0%
#18988: feat(config): add support for config warnings and improve validation
by saurav470 · 2026-02-17
79.6%
#15756: [Security]: strip provider apiKey from models.json before prompt se...
by SecBear · 2026-02-13
79.5%
#19020: bugfix(gateway): Handle invalid model provider API config gracefully\…
by funkyjonx · 2026-02-17
79.3%