Skip to content

feat(local): replace Ollama with a bundled llama.cpp runtime, a curated GGUF catalog, and a hardware-aware fit estimator - #1819

Merged
AnishSarkar22 merged 61 commits into
MODSetter:devfrom
AnishSarkar22:feat/llama-cpp
Sep 22, 2026
Merged

AnishSarkar22 merged 61 commits into
MODSetter:devfrom
AnishSarkar22:feat/llama-cpp

Conversation

@AnishSarkar22

@AnishSarkar22 AnishSarkar22 commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

What

  • Replaces Ollama with llama-server running in router mode as an Electron sidecar; a pinned llama.cpp build is staged at package time and the release workflow smoke-tests llama-server instead of Ollama, on a pinned ubuntu-22.04.
  • Adds the llamacpp provider (modules/llm/providers/llamacpp/): presets, model download, vision projector loading, thinking-block handling, capability detection, and a router client that lets the router own model loads rather than the backend racing it.
  • Deletes the Ollama provider and its catalog, and drops the llmfit recommendation path; ModelStore and other now-unused protocol surface go with them.
  • Adds modules/llm/gguf/: reads GGUF headers through llama.cpp's own key table and derives model shape from a local or remote source, with file-kind detection.
  • Adds modules/llm/hardware/: probes ggml devices out of process, reports whether the runtime can reach the GPU at all, budgets unified memory as a single pool, and covers per-OS GPU discovery for darwin/linux/windows.
  • Adds modules/llm/fit/: estimates KV cache (including sliding-window and latent/MLA caches, priced per layer), sizes compute buffers from the widest tensor a layer builds, itemises what a load allocates, counts offload in layers, and separates residency from refusal so a CPU-only machine is still judged fairly.
  • Picks one KV cache precision that the UI badge and the loader both read, so the estimate shown and the load performed agree.
  • Adds modules/llm/catalog/: a curated curated-models.json manifest at schema 4 carrying the widened model shape, Hugging Face–backed search with eligibility filtering and non-chat-model rejection, recommendation gating on speed, and rows priced at the precision the loader will actually choose.
  • Gates installs on the GGUF file's own header via a single denylist, instead of a generated allowlist or repo-summary/name heuristics.
  • Warns when a searched repo ships no chat template, and serves a GPU diagnosis that is warmed off the boot path.
  • Splits the ollama_pull egress grant into model_download and model_* grants; Alembic revision 0012_llamacpp_provider migrates selected models and existing egress grants off Ollama.
  • Chat: budgets the prompt from the model's real context window rather than a fixed number, prices history with the model's own tokenizer and caches /props, and budgets the first token separately from subsequent ones.
  • Secrets: raises UnreadableSecretError instead of leaking InvalidToken, and chat classifies an unreadable stored key as a provider auth error.
  • Frontend: model catalog shows fit badges, model search, the GPU diagnosis, and the chat-template warning; Ollama-era copy and tests renamed for the llama.cpp path.
  • Adds a curated-model refresh script that authors entries from the header's tensor table, and ships the curated manifest from its catalog path in the PyInstaller bundle.
  • Docs/plans: new phase 7 (07-llamacpp-runtime.md) and phase 8 (08-cuda-backend.md) specs — Vulkan ships everywhere now, CUDA deferred to phase 8 — plus updates to the umbrella plan, diagrams, data model, 05a/05c, install UX, and the local README.

Why

Fixes #

How to test

AnishSarkar22 and others added 30 commits September 19, 2026 12:59
Phase 7 now replaces the Ollama sidecar with a packaged llama-server
and stops shipping llmfit entirely. Hardware comes from
ggml_backend_dev_memory() via ctypes; scoring moves offline to a
maintainer machine and ships as data in curated-models.json.

- 07-llamacpp-runtime: add Contracts, authoring and appendix sections;
  pin one quantization per entry, fix context at load, defer manifest
  growth and speed gating out of v1
- 05c-packaging: replace the llmfit section with llama-server staging,
  split the catalog and Hugging Face search routes, make .gguf import
  a first-class offline path
- 05b-connections: rename provider ollama -> llamacpp, note revision
  0012 rebuilds selected_models for the CHECK constraint
- 00c-data-model: rename egress destinations to model_download and
  model_search
- 00b-diagrams, frontend/01-shell, frontend/05-install-ux: follow the
  same rename and drop the scan step from the install flow
…d llmfit

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… Ollama

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ettings

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…r remote files

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…gh ggml

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… model

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…-compatible provider

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…s, and thinking control

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d Hugging Face search

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…on module

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…provider

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…el_search

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ision 0012

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…oken

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… runtime

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…g Face

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…time

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d guess

Three failure modes existed even at the old 16384 floor:

- A prompt that outgrew the window surfaced as "provider temporarily
  unavailable" instead of the true, retry-proof cause. Classify
  llama.cpp's own exceed_context_size_error as its own ChatErrorKind
  with copy that tells the user what actually happened.
- The answer had no max_tokens, so a reply could run into the window's
  edge and stop mid-sentence with no error at all. Reserve tokens for
  it up front and cap the request.
- History was trimmed against a hardcoded 3000-token constant that had
  no relationship to the model's actual n_ctx. Derive the budget from
  the real window instead, read once via a new context_tokens() on the
  Generator protocol (llama.cpp answers it from /props; a remote
  endpoint honestly returns None and keeps today's fixed fallback).

CONTEXT_FLOOR_TOKENS drops from 16384 to 8192, and plan_load now widens
across a fixed set of rungs (8192/16384/32768) instead of an unbounded
binary search, so the catalog badge, the preset, and the actual load
can only ever agree on one of a small, testable set of windows. 8192
is only safe because of the history-budget fix above: a constant sized
for 16384 would have silently overflowed the narrower floor.
…ops per load

Two related fixes to the local runtime seam:

- Generator.token_count() reads llama.cpp's /tokenize endpoint, so
  history trimming uses the model's real tokenizer instead of a
  ~4 chars/token heuristic that could under-count dense text by
  15-20%. A remote endpoint has no equivalent, so it keeps the
  heuristic exactly as before.
- LlamaCppProvider.capabilities() now caches its /props read per
  model instead of fetching it fresh on every message. context_tokens()
  and chat()'s own template shaping were each issuing an independent
  /props round trip on every single turn; measured live, that showed up
  as real, avoidable latency layered onto an already slow load. The
  cache is cleared the one time it can go stale: _ensure_loaded()
  issuing a fresh load.
…ication

A build's badge and its star eligibility were computed by two
independent thresholds over the same offload_fraction: copy.py drew
lines at 0.25/0.5 to choose wording, recommendation.py drew a separate
line at 0.75 (MAX_OFFLOAD) to choose whether to star it. Nothing kept
them in step, so a build could be starred while its own badge read
"Too big for the GPU, so part runs on the CPU" or worse.

New modules/llm/fit/speed.py classifies a verdict into one SpeedTier
once; copy.py renders wording from the tier instead of its own bands,
and recommendation.py's eligibility is RECOMMENDABLE_TIERS (FULL and
LIGHT_SPILL) on that same tier. MAX_OFFLOAD is gone. A recommended
build can now only ever carry "Full speed" or "Most of it still fits"
wording, by construction.

test_badge_matches_the_load.py gains a property test sweeping every
curated model against every budget shape, asserting a starred row's
badge is never spill wording. Three test_recommendation.py fixtures
tuned to the old 0.75 cutoff are recomputed against the tighter one,
one of them (the module's founding case) with numbers that had gone
stale independent of this change.
The gate was two lists answering one question: a 152 name table generated
from the pinned libllama, and a 21 name exclusion set beside it. The table
was the only thing that could tell "llama.cpp has no builder for this yet"
from everything else, and it cost a script run at every pin bump, a datas
entry, and a file that had to ship on Windows because the symbol it reads
is not exported there.

Measured against the 1000 most downloaded GGUF repos, it bought less than
it looked like. Dropping it lets 18 of 979 install and then fail, all of
them chat architectures released in the last few weeks. That is accepted:
curated models are the default path, search is opt in, and the failure now
says so instead of telling the reader to try again shortly.

What replaces it is one denylist, grouped by what a model is rather than
by which fact named it, so a GGUF architecture and a repo pipeline tag
share the table. The tag exists because a header can be honest and still
mislead: an embedding model declares mistral3, a voice model declares
qwen3, a reranker declares qwen3. Refusing those architectures would
refuse Mistral and Qwen, so only the tag catches them. It rides along on
the listing call read_repo_facts already makes.

Measured over the same 1000 repos: 75 installs that fail become 18, with
zero refusals of a model that would have worked. The tags that mean chat
are held out by a test, since image-text-to-text alone is 28% of admitted
repos and denying it would empty the search screen.

scripts/audit_gate.py replaces the guard the generated table used to give.
A test held every denylist key against the names llama.cpp defines, which
is how granite-moe, granite-hybrid and nemotron-h were caught refusing
nothing. With no table, a misspelling now shows up in the audit as an
entry that matched no repo in the sample.
…summaries

One denylist replaces the generated architecture table and its script. The
gate reads the candidate build's header instead of Hugging Face's repo
summary, which parses one file per repo and reported a chat model shipped
beside a vision sidecar as `clip`.

Measured over the top 1000 GGUF repos: wrong refusals 17 to 0, installs that
then fail 75 to 18, and those now say so instead of asking the reader to retry.
_ensure_loaded read /models then posted /models/load, losing to the request
already loading the model: 400 `model is already running`, which failed title
generation. The proxy autoloads, so the call was a duplicate.
@vercel

vercel Bot commented Sep 22, 2026

Copy link
Copy Markdown

@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.

@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 74426afb-1847-4b33-8422-fc72dd792c8d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AnishSarkar22 AnishSarkar22 changed the title Feat/llama cpp feat(local): replace Ollama with a bundled llama.cpp runtime, a curated GGUF catalog, and a hardware-aware fit estimator Sep 22, 2026
@AnishSarkar22
AnishSarkar22 merged commit 431914f into MODSetter:dev Sep 22, 2026
3 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant