Repository navigation
feat(llm): rework the local model catalog around pinned builds and one row shape - #1902
Conversation
The vocabulary walk cost 3.4 s of a 3.5 s parse. Arrays past 4096 items keep only their length, so a Qwen3 header parses in 0.05 s with n_vocab unchanged.
Quantization labels keep the UD- prefix. A build lists every split part and the preferred projector. Imatrix files, drafters, big-endian builds and incomplete splits are skipped.
The default is the first build in the quantization preference order. The recommendation is that default when it runs well here, else the largest smaller build that does, never a larger one.
Replaces the chat-or-refuse denylist with groups that each answer a type: diffusion is image_gen, video is video_gen, speech out is audio_gen, and embedders and projectors are known and typeless. Anything unnamed is text.
A build reads images when its projector's header carries a vision encoder and its width matches the model. Tools and reasoning come from the chat template.
Seven models, most preferred first, including Gemma 3 4B with vision. Every build in the preference order is pinned, each file with its revision, size and sha256, and projectors carry their GGUF keys.
Reads each repo at a pinned commit, pins its builds, and reads the default build's header and projector over range requests. It refuses unreadable builds, mismatched projectors and losses nobody named.
One row shape for curated and downloaded models. Builds are priced with their projector, the star goes to the first model with a recommended build, and an install record keeps each model's projector pairing.
No header is read to draw a repo's builds: sizes are exact and fit is an estimate that over-charges. One build's headers are read before download. Search recommends nothing.
llama.cpp claimed completion for every file on disk, so a downloaded embedder could fill the text_gen slot. Models now carry types from their headers, and local selection uses the same rule as remote.
Installs fetch a build's whole file set, pinned and hash-verified, after a searched build passes its exact check. Deleting a model removes its projector too, and the preset pairs only a recorded projector.
Mounts the new routes and removes the old curated manifest, service, search, the not_chat gate and the lone-projector pairing. The gate audit reads the new classifier.
Each curated row leads with its in-use, installed or recommended build, with the rest behind a disclosure. "Reads images" comes from one field on every row, estimated fits show ~, and model filters use selectable_for.
A badge now warns only when there is something to warn about: a build that runs fully, or spills only a little, carries none, since those are exactly the tiers a build can be recommended at. Moderate and heavy spill, and won't fit, still warn. The recommendation also stops below four bits, since a three or two bit build of a larger model is not clearly better than a four bit build of a smaller one; the star now moves to the smaller model instead. Together these fix the screenshot case: an 8 GB Mac starred Qwen3 8B at a spilling three bit build next to Qwen3 4B running at full speed. It now stars Qwen3 4B, with no warning beside the star.
Which build a curated row shows and its Download fetches now comes from the backend, not a frontend heuristic. lead_build() picks the build in use, else the installed one, else the recommendation, else the largest build at four bits or above that installs, else the default to say the model will not fit, and the reason travels with it as row.lead. Rows sort by the lead build's fit state, so a row's position matches what it actually shows. The frontend's lead-build.ts is removed; the card looks the choice up among the builds the server already sent.
Adds a --warning token, amber and distinct from --destructive, contrast checked at 4.5:1 for text on its own tint in both themes. The notice level fit badge (Reduced speed) now uses it instead of a plain outline, so a build that runs slower reads as a caution rather than a refusal.
preferred_projector() is now shared by builds_in() and search: the one rule that decides whether a repo ships a vision projector, so a search hit and its opened builds can never disagree about it. A hit's siblings, which the listing already carries, are enough to answer reads_images with no extra request; opening the repo and installing a build still confirm it against the projector's own header. The "Reads images" badge moves from outline to secondary everywhere it appears, and now shows on a search hit as well as on its builds.
…ding BuildAction moves into its own file, shared by a curated row, its other builds and a searched repo's builds. Each build now carries its own progress bar rather than one bar for the whole row, so a download on an other build is visible without collapsing the list, and the lead build's row stays expanded while one of its other builds is in flight. Search gains the same Download/Use, phase and progress bar every curated build already had. "Reads images" is renamed to "Vision" everywhere it appears.
|
@AnishSarkar22 is attempting to deploy a commit to the Rohan Verma's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Check the architecture pages the catalog PRs (#1899-#1902) touched against the code, correct what no longer matches, and add the Known gaps found on the way. Fix the model catalog proposal's lines about the present, note its revisions on ADRs 0011 and 0015 and in the ADR index, update the SEO fact table for the new manifest, and mark the plugins tree in AGENTS.md as planned until it lands. Co-authored-by: Cursor <cursoragent@cursor.com>
What
UD-prefix on quantization labels, listing every split part, and skipping imatrix files, drafters, big-endian builds and incomplete splits.image_gen, video isvideo_gen, speech output isaudio_gen, embedders and projectors are known but typeless, and anything unnamed is text.completionfor every file on disk, letting a downloaded embedder fill the text_gen slot; models now carry types from their headers and selection uses the same rule as remote./llm/catalog/localand removes the old curated manifest, service, search, the not_chat gate and the lone-projector pairing.lead_build()), replacing a frontend heuristic; rows sort by the lead build's fit state.--warningamber color token for the reduced-speed badge, replacing a plain outline.preferred_projector()rule), with no extra request, confirmed later by the header at install.BuildActioncomponent used by curated and searched builds alike; renames "Reads images" to "Vision".Why
Fixes #
How to test
High-level PR Summary
This pull request implements a redesigned local model catalog for SurfSense's desktop app, consolidating curated, downloaded, and searched models into a unified row format with enhanced build selection logic. The new catalog supports multi-build recommendations (including a default and recommended build per model), vision model support (including projector pairing and verification), and improved type classification. The manifest now pins every build in a quantization preference order rather than just one, allowing the system to recommend smaller builds of preferred models when the default cannot run well. The catalog operates entirely offline for curated and downloaded models, with search as an opt-in network feature, and badges now function as warnings shown only when necessary rather than status indicators for every model.
⏱️ Estimated Review Time: 3+ hours
💡 Review Order Suggestion
docs/proposals/model-catalog.mddocs/adr/0014-two-tier-model-catalog.mddocs/adr/0026-curated-order-is-list-position.mdsurfsense_local/backend/modules/llm/catalog/local/manifest/schema.pysurfsense_local/backend/modules/llm/catalog/local/builds.pysurfsense_local/backend/modules/llm/catalog/local/build_choice/preference.pysurfsense_local/backend/modules/llm/catalog/local/build_choice/default_build.pysurfsense_local/backend/modules/llm/catalog/local/build_choice/recommended_build.pysurfsense_local/backend/modules/llm/catalog/local/classifier.pysurfsense_local/backend/modules/llm/catalog/local/support.pysurfsense_local/backend/modules/llm/catalog/local/pricing.pysurfsense_local/backend/modules/llm/catalog/local/catalog.pysurfsense_local/backend/modules/llm/catalog/local/recommendation.pysurfsense_local/backend/modules/llm/catalog/local/lead_build.pysurfsense_local/backend/modules/llm/catalog/local/rows.pysurfsense_local/backend/modules/llm/catalog/local/downloaded.pysurfsense_local/backend/modules/llm/catalog/local/installs.pysurfsense_local/backend/modules/llm/catalog/local/search/hits.pysurfsense_local/backend/modules/llm/catalog/local/search/listing.pysurfsense_local/backend/modules/llm/catalog/local/search/repo_row.pysurfsense_local/backend/modules/llm/catalog/local/search/exact_check.pysurfsense_local/backend/modules/llm/catalog/local/search/tickets.pysurfsense_local/backend/modules/llm/catalog/local/service.pysurfsense_local/backend/modules/llm/catalog/local/router.pysurfsense_local/backend/modules/llm/catalog/local/schemas.pysurfsense_local/backend/scripts/local_manifest/entries.pysurfsense_local/backend/scripts/local_manifest/hub.pysurfsense_local/backend/scripts/local_manifest/recorded.pysurfsense_local/backend/scripts/local_manifest/assemble.pysurfsense_local/backend/scripts/local_manifest/guard.pysurfsense_local/backend/scripts/refresh_local_manifest.pysurfsense_local/backend/modules/llm/fit/copy.pysurfsense_local/backend/modules/llm/gguf/header_prefix.pysurfsense_local/backend/modules/llm/providers/llamacpp/provider.pysurfsense_local/backend/modules/llm/router.pysurfsense_local/backend/modules/llm/selection.pysurfsense_local/frontend/src/features/model-catalog/api.tssurfsense_local/frontend/src/features/model-catalog/build-action.tsxsurfsense_local/frontend/src/features/model-catalog/fit-badge.tsxsurfsense_local/frontend/src/features/model-catalog/model-card.tsxsurfsense_local/frontend/src/features/model-catalog/model-search.tsxsurfsense_local/frontend/src/features/model-catalog/model-catalog-page.tsxsurfsense_local/frontend/src/features/model-catalog/use-model-catalog.ts