Conversation
Deleting a model under Settings > Models never removes it from the chat selector when the provider is built into pi's catalog: models.json is an upsert/override layer, so the built-in definition keeps serving the model (agegr#560, agegr#640). The supported lever is the enabledModels scope in ~/.pi/agent/settings.json, which pi-web read but offered no UI to edit — the selector showed every available model with no way to hide any. This adds a "Manage visible models" entry to the model selector dropdown: - ModelSelector grows an onManage hook that renders the entry in the panel footer; ChatInput forwards it from ChatWindow - ModelVisibilityDialog lists every available model (grouped by provider, with filter, per-provider and global tri-state selection) starting from the models the selector currently shows - Saving writes exact provider/modelId patterns via PUT /api/models-visibility; checking every model clears the scope back to pi's show-all default so newly added models keep appearing - GET /api/models-visibility returns the raw patterns plus the full unfiltered catalog; writes invalidate the models cache and bump modelsRefreshKey so the selector reloads immediately (agegr#822) - an empty selection is rejected client- and server-side: pi falls back to showing every model when a scope matches nothing, so saving one would silently undo the edit; the PUT route resolves the scope first and refuses zero-match patterns - scopes that use globs, bare ids, or :thinkingLevel pins are flagged in the dialog before saving replaces them with the explicit list Complements agegr#727 (settings-panel catalog cards) with a lighter, in-flow entry point; both edit the same pi-native setting. Addresses the hiding half of agegr#241 / agegr#324. Tests: lib/model-visibility.test.mjs (pattern computation and validation), components/ModelVisibilityDialog.test.mjs (dialog shell, selector entry wiring). npm test 1032 pass; tsc --noEmit, eslint, and next build clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two long-standing gaps around the model selector:
models.jsonis an upsert/override layer on top of pi's built-in provider catalogs, so a deleted entry just falls back to the built-in definition for any configured provider (Model dialog doesn't clean upenabledModelsin settings.json when a connector/models are removed → persistent 'No models match pattern' warnings #560, After model deletion, the pi-web UI still displays "Model scope warnings," and the newly added Kimi K3 is not in the model dropdown list. #640). PR fix: prune removed models from enabled scope #561's implicit prune was rejected as by-design, and the supported lever — theenabledModelsscope in~/.pi/agent/settings.json— had no UI in pi-web at all.enabledModelsscope, manageable in the TUI via/scoped-modelsbut not from the web UI.Solution
A "Manage visible models" entry at the bottom of the chat model selector dropdown opens a dialog that edits pi's native
enabledModelsscope explicitly:provider/modelIdpatterns; checking every model clears the scope back to the show-all default, so newly added models keep appearing automatically:thinkingLevelpins are flagged in the dialog before saving replaces them with the explicit listAPI
GET /api/models-visibility— rawenabledModelspatterns + the full unfiltered catalog (honors project trust like/api/models)PUT /api/models-visibility— validated write (nullclears), invalidates the models cache and is followed by amodelsRefreshKeybump so the selector reloads immediately (Saving the Models panel does not refresh the session model list (needs /reload or page reload) #822's refresh path)Safety rails
Relation to #727
Complementary rather than overlapping: #727 adds per-provider catalog cards inside Settings → Models with segment-preserving rewrites; this PR is a lighter, in-flow entry point that manages the whole scope in one view. Both edit the same pi-native setting, so they compose. Happy to rework if you'd rather land only one approach — the API safety rails here (zero-match refusal) and the dialog component are reusable either way.
Verification
npm test— 1032 pass (incl. newlib/model-visibility.test.mjsandcomponents/ModelVisibilityDialog.test.mjs)tsc --noEmit,eslint,next buildcleannext dev: GET/PUT round-trip writesenabledModelsto settings.json,/api/modelsreflects the scope immediately (cache invalidation), zero-match and empty-array PUTs return 400,nullrestores the file byte-identicallyFixes the hiding half of #241 / #324; gives #560 / #640 users an in-app escape hatch instead of hand-editing settings.json.