Conversation
…elected one (Twigpine#1423) mergeActiveProfileModelOptions was introduced in Twigpine#1361 to surface profile-configured models inside the descriptor-backed picker. The implementation iterated over the profile's saved model list and used that as the complete set of options, meaning a profile with a single saved model (e.g. "mimo-v2.5-pro") would suppress the full route catalog and show only that one entry — exactly the regression reported in Twigpine#1423. Fix: always start with the full route catalog options, then append any profile-configured models that are not already covered by the catalog. This ensures users see every available model for the active provider while still surfacing custom models saved in their profile. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jatmn
left a comment
There was a problem hiding this comment.
I found an issue that needs to be addressed before this is ready.
Findings
- [P1] Keep descriptor catalog picks inside
availableModels
src/commands/model/model.tsx:150
This now copies every descriptor route model into the picker override, but that override bypasses the normal allowlist path:ModelPickerusesoptionsOverrideinstead of thegetModelOptions()result that is filtered byavailableModels, and this interactive/modelhandler writes the selected value directly without theisModelAllowedguard that/model <name>has. In an org/user config that restrictsavailableModelsto a subset, opening the descriptor-backed picker for a provider profile will now show the whole route catalog and let the user select a disallowed model. Please filter the descriptor override with the same allowlist or reject disallowed selections in the interactive handler before updatingmainLoopModel.
…odels allowlist - In loadDescriptorDiscoveryContext, filter routeOptions with isModelAllowed before passing them to mergeActiveProfileModelOptions, so optionsOverride only contains models permitted by the org allowlist. - Add isModelAllowed guard in handleSelect to block selection of disallowed models via the interactive picker (mirrors the existing guard on the /model <name> code path). - Add test verifying that allowlist filtering removes blocked models from the options passed to mergeActiveProfileModelOptions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Fixed in latest commit — two-part:
Test added: |
jatmn
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the changed paths and found an issue that still needs to be addressed.
Findings
- [P2] Keep refreshed descriptor options inside
availableModels
src/commands/model/model.tsx:535
The initial descriptor context now filtersrouteOptionsthroughisModelAllowed, but the refresh path rebuildsnextOptionsdirectly fromdiscoverModelsForRoute()and passes them intomergeActiveProfileModelOptions()without applying the same allowlist. When a descriptor route hasautoRefreshenabled, opening/modelstartsrefreshAvailableModels(false)and replaces the filtered picker options with the unfiltered discovered catalog; the manual in-picker refresh does the same. The newhandleSelectguard prevents selecting a blocked model, but org-restricted users will still see disallowed models reappear in the picker after the refresh completes. Please apply the allowlist filtering to the refreshed descriptor options before callingsetOptionsOverride(), and cover that refresh path in the regression test.
… descriptor path The initial-load path filtered discovered catalog models through isModelAllowed before merging with profile options, but the refreshAvailableModels path called mergeActiveProfileModelOptions directly on the raw discovery results, bypassing the allowlist entirely. A provider refresh (manual or auto-triggered) could therefore re-introduce models that availableModels explicitly excluded. Fix: split the buildRouteCatalogModelOptions call out, filter the result with isModelAllowed (identical predicate to the ~line-250 initial-load path), then merge — keeping profile-only models unfiltered, consistent with initial load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks, @jatmn — good catch on the refresh path. Fix (commit // Before (refresh path bypassed allowlist):
const nextOptions = mergeActiveProfileModelOptions(
discoveryContext.routeId,
buildRouteCatalogModelOptions(...),
)
// After (same filter as initial load):
const discoveredRouteOptions = buildRouteCatalogModelOptions(...)
const allowedRouteOptions = discoveredRouteOptions.filter(o =>
typeof o.value === 'string' ? isModelAllowed(o.value) : true,
)
const nextOptions = mergeActiveProfileModelOptions(
discoveryContext.routeId,
allowedRouteOptions,
)Profile-only models added by |
jatmn
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.
Findings
-
[P2] Keep profile-appended picker options inside
availableModels
src/commands/model/model.tsx:161
The route catalog is now filtered before callingmergeActiveProfileModelOptions(), but the merge then appends every active-profile model that was not present in the filtered catalog. If an org allows onlyopenai/gpt-5-miniand the active provider profile still containsqwen/qwen3-32b(or any blocked catalog model saved in the profile), the blocked model is filtered out ofallowedRouteOptionsand then immediately re-added fromprofileOptions. The newhandleSelectguard rejects it after Enter, but/modelstill exposes disallowed choices on initial load and after refresh, which leaves the previousavailableModelspicker leak partially unresolved. Please filter the merged result, or skip disallowed profile options before appending them. -
[P3] Apply the same filter in
/model refreshsummaries
src/commands/model/model.tsx:819
The non-interactive/model refreshpath still buildsnextOptionsdirectly from the unfiltered discovery result before comparing it todiscoveryContext.optionsOverride, which is now filtered during initial descriptor loading. WithavailableModelsset, a refresh that discovers only blocked models will reportUpdated <provider> models.even though the allowed picker options did not change. Please apply the same allowlist filtering before merging in this path too, so the refresh summary matches the actual visible model set. -
[P3] Cover the real descriptor allowlist paths
src/commands/model/model.test.tsx:490
The new allowlist regression test never exercisesloadDescriptorDiscoveryContext(), the picker refresh path, or the mockedisModelAllowed()import. It manually filtersallCatalogOptionswith a localisModelAllowedFnand then asserts thatmergeActiveProfileModelOptions()returns that already-filtered input, so the test would still pass if the production filters at initial load or refresh were removed. Because the prior review specifically asked to cover the refresh regression, please add coverage that opens or refreshes a descriptor-backed picker withavailableModelsset and verifies the resulting options exclude blocked catalog/profile entries.
…in /model refresh Two gaps in the availableModels enforcement: 1. mergeActiveProfileModelOptions appended profile-configured models that were not already in the filtered catalog, without checking isModelAllowed. A blocked model absent from allowedRouteOptions could be re-added from profileOptions, exposing it in the picker on initial load and after refresh. Fix: skip profile entries where !isModelAllowed(value) before appending. 2. refreshModelsAndSummarize (/model refresh non-interactive path) built nextOptions from raw discovery results without filtering, so the "changed" comparison was apples-to-oranges against discoveryContext.optionsOverride (which is now filtered). A refresh that discovers only blocked models would incorrectly report "Updated <provider> models." without any visible change. Fix: filter the catalog options with the same isModelAllowed predicate before merging, consistent with interactive refresh and initial load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Fixed both issues in commit [P2] Profile-only models now filtered by allowlist ( The loop that appends profile models absent from the filtered catalog now skips entries where // Don't surface profile-configured models that are explicitly blocked by
// the availableModels allowlist. The catalog entries in routeOptions were
// already filtered upstream; without this guard, a blocked model absent
// from the filtered catalog would be re-added here from profileOptions.
if (!isModelAllowed(value)) {
continue
}[P3]
Regarding [P3] test coverage — I'll look at expanding the tests to cover the descriptor allowlist paths more directly in a follow-up commit if you'd like, or happy to do it now as part of this PR. |
jatmn
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the changed paths and found one issue that still needs to be addressed.
Findings
- [P3] Cover the real descriptor allowlist paths
src/commands/model/model.test.tsx:490
The new allowlist regression test still does not exerciseloadDescriptorDiscoveryContext(), the picker refresh path, or the non-interactive/model refreshpath. It manually filtersallCatalogOptionswith a localisModelAllowedFnand then callsmergeActiveProfileModelOptions()with already-filtered input, so it would continue passing if the production filters at initial load, interactive refresh, or refresh summary were removed again. Since the previous regressions were in those production descriptor paths, please add coverage that opens or refreshes a descriptor-backed picker withavailableModelsset and verifies blocked catalog and profile-appended entries stay out of the visible options and refresh comparison.
|
closing, going with #1472 |
Problem
When a third-party provider profile is configured (e.g. Gitlawb Opengateway with
mimo-v2.5-proas the default), opening/modelshows only that one selected model instead of the full route catalog. Reported in #1423.Root Cause
mergeActiveProfileModelOptions(introduced in #1361) iterated over the profile's saved model list and used that as the complete set of options, looking up each entry in the route catalog for better labels. A profile with a single saved model would therefore suppress the entire route catalog and return only that one entry.Fix
Reverse the merge direction: start with all route catalog models, then append any profile-configured models not already covered by the catalog. Users always see every available model for their provider; custom model IDs saved in the profile remain accessible at the bottom.
Tests
Updated the existing
mergeActiveProfileModelOptionstest that had encoded the wrong (buggy) behavior, and added a regression comment referencing #1423. Full suite: 3103 pass, 11 pre-existing failures unrelated to this change.Closes #1423