npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pi-llamacpp-provider

v0.2.0

Published

pi extension that registers your llama.cpp server as a provider and auto-discovers every model it exposes at /v1/models — context size, vision and thinking support included

Downloads

346

Readme

pi-llamacpp-provider

npm CI license: MIT

A pi extension that registers your llama.cpp server as a provider and discovers its models automatically. Add a preset to the server, restart pi, and it is in /model — no models.json entry, no code change.

$ pi --list-models llamacpp
provider  model            context  max-out  thinking  images
llamacpp  fastcontext      80K      16.4K    no        no
llamacpp  gemma4-12b       131.1K   16.4K    yes       yes
llamacpp  gemma4-31b       100K     16.4K    yes       no
llamacpp  ornith-35b       262.1K   16.4K    yes       yes
llamacpp  qwen36a3b-35b    262.1K   16.4K    yes       yes

thinking is read from each model's chat template — the same thing llama.cpp itself uses to decide whether a model reasons — not guessed from its name.

Install

pi install npm:pi-llamacpp-provider

Or straight from git, or pinned, or just for one run:

pi install git:github.com/T0mSIlver/pi-llamacpp-provider
pi install npm:[email protected]   # pinned, skipped by pi update
pi -e npm:pi-llamacpp-provider              # try without installing

If your server is not on localhost:8080, point the extension at it:

export LLAMACPP_BASE_URL=http://gpu-box.lan:8080

Then select a model:

pi --model 'llamacpp/gemma4-31b'
pi --models 'llamacpp/*'    # cycle every llama.cpp model with Ctrl+P
/model                      # or pick one inside the TUI

What it reads from your server

At startup the extension calls GET /v1/models, then probes each model once at GET /props, and maps every entry to a pi model. Two server shapes are supported, because their payloads differ:

| Server | What the payload gives us | |---|---| | Router (llama-server with no model, multi-preset) | status.args — the full llama-server argv per preset — plus status.preset and architecture.input_modalities. A meta block appears only for a preset that is currently loaded. | | Plain llama-server (single model) | a meta block with n_ctx / n_ctx_train, and everything else from /props. |

From that, per model:

| pi field | Derived from | |---|---| | contextWindow | What one conversation actually gets: the per-slot n_ctx from /props or meta when the model is loaded (already divided by --parallel), else --ctx-size ÷ --parallel, else meta.n_ctx_train ÷ --parallel, else llama.cpp's own 4096 default. Reported honestly, even when it is small. | | maxTokens | Max output tokens for one turn — not the context window. The preset's --predict / -n / --n-predict if it pins one, else LLAMACPP_MAX_OUTPUT_TOKENS (16384 by default), clamped to the context window. llama.cpp's own default is -1, "generate until the context is full", which is not a number pi can budget against. | | reasoning | The model's chat template — see below. | | input | ["text", "image"] when the model reports an image modality (a router says so in architecture, a plain server in /props modalities), else ["text"]. Audio is dropped — pi models declare text and image only. | | cost | Zero — local inference is free, and pi's session cost readout should say so. | | compat | supportsDeveloperRole: false (llama.cpp chat templates expect a system role) and maxTokensField: "max_tokens" (it rejects max_completion_tokens). |

How thinking support is detected

llama.cpp decides whether a model reasons by rendering its chat template and looking at what comes out (common_chat_templates_support_enable_thinking). That template is the only honest answer, and it is published at GET /props. So that is what this extension reads, in this order:

  1. LLAMACPP_THINKING_MODELS / LLAMACPP_NON_THINKING_MODELS — comma-separated globs (gemma4-*,qwen3?-*). Your word is final.
  2. Flags that make thinking impossible: --reasoning off and --no-jinja. Those two are the only ones llama.cpp consults — enable_thinking = enable_reasoning != 0 && template_supports_thinking — so either settles it. --reasoning-budget 0 is not one of them: it cuts the thinking block short at the sampler, it does not remove the model's ability to think.
  3. The chat template, fetched live from GET /props?model=<id>&autoload=0. The autoload=0 matters: without it a router would load the model — spawning a llama-server and filling VRAM — just to answer us. With it, a router answers for what it already has in memory and replies "not loaded" for the rest, which we take as "no answer", never as a failure. The template is matched against the markers llama.cpp itself keys on: enable_thinking, reasoning_content, <think> and its variants, [THINK], <|channel|>analysis (gpt-oss), <|channel>thought (Gemma 4). This is validated against all 59 chat templates shipped in llama.cpp's models/templates, and it is why Gemma 4 is a thinking model here and Qwen3-Coder is not.
  4. A cached verdict. A router only answers /props for what it has loaded, so a template we read once is remembered under $XDG_CACHE_HOME/pi-llamacpp-provider/, keyed by the preset's argv — edit the preset and the entry is dropped. A model the router has since unloaded keeps the answer its own template gave.
  5. The preset, finally: a --chat-template-kwargs carrying a thinking switch (enable_thinking, preserve_thinking, …), a positive --reasoning-budget, or --reasoning on. A preset only configures a thinking switch for a model that has one.
  6. Otherwise: no. No evidence, no claim — the model id is never consulted, because a name is not a capability.

Thinking models get compat.thinkingFormat = "chat-template" with chat_template_kwargs: { enable_thinking, preserve_reasoning, preserve_thinking }, so pi toggles thinking the way llama.cpp expects rather than through OpenAI's reasoning_effort, which llama.cpp does not implement.

Set LLAMACPP_PROBE=0 to skip probing altogether; detection then falls back to steps 1, 2, 5 and 6.

When the server is down

Discovery never blocks pi from starting. On a connection refusal, timeout, non-2xx response, malformed body, or empty model list, the extension registers the provider anyway with a single default model and warns once at session start:

[pi-llamacpp-provider] Model discovery from http://127.0.0.1:8080/v1 failed
(fetch failed). Registered provider "llamacpp" with a single "default" model.
Start the server and run /reload, or set LLAMACPP_BASE_URL.

Start the server and /reload — no restart needed.

Environment overrides

| Variable | Default | Effect | |---|---|---| | LLAMACPP_BASE_URL | http://127.0.0.1:8080 | Server address. /v1 is appended if you leave it off. | | LLAMACPP_API_KEY | sk-llamacpp-local | Sent as Authorization: Bearer …. llama.cpp ignores it unless started with --api-key, but pi needs a non-empty key to treat the provider as authenticated. | | LLAMACPP_TIMEOUT_MS | 4000 | How long discovery may take before falling back. | | LLAMACPP_PROVIDER | llamacpp | Provider name, i.e. the …/model-id prefix. Change it to avoid clashing with a llamacpp provider defined in models.json. | | LLAMACPP_MAX_OUTPUT_TOKENS | 16384 | maxTokens for models whose preset does not pin a --predict. | | LLAMACPP_THINKING_MODELS | — | Comma-separated globs forced to reasoning: true, e.g. gemma4-*,my-model. | | LLAMACPP_NON_THINKING_MODELS | — | The same, forced to reasoning: false. | | LLAMACPP_PROBE | 1 | Set to 0 to skip the /props probe entirely. |

All of them are read on every load, so /reload picks up a change without a reinstall.

Test evidence

Verified against a live llama.cpp router serving 9 presets: all 9 appear in pi --list-models with correct context windows, vision flags and thinking flags; text and thinking models both complete a real prompt end-to-end; killing the server degrades to the default model instead of breaking startup. Full transcripts: docs/test-evidence.md.

Development

npm install
npm run verify        # typecheck + test suite (needs Node ≥ 22.19)
pi install .          # smoke-test the package manifest against a local pi

test/provider.mjs runs the extension against throwaway HTTP servers — a router payload captured from a real llama.cpp router, a plain llama-server payload, and every failure mode (500, timeout, refused connection, malformed JSON, empty list) — asserting the fallback and the once-per-process warning. Thinking detection is checked against real chat templates lifted from llama.cpp's models/templates (test/fixtures/templates/): Gemma 4, Qwen3, gpt-oss and Ministral-Reasoning must all reason; Qwen3-Coder and Llama 3.3 must not.

License

MIT