omp packages

pi-blablador0.1.2

Blablador (Helmholtz / JSC) provider for Pi: live alias discovery, per-family thinking effort, measured context windows

GitHub Actions Published 3 hours ago MIT ~263 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-blablador

Blablador is the research LLM service run by JSC (Forschungszentrum Jülich) for Helmholtz: a rotating set of open models behind an OpenAI-compatible API. This is a Pi provider for it. It discovers the live alias-* catalog on every refresh, maps Pi's thinking levels onto each backend's own reasoning_effort vocabulary, and reports the context window the gateway actually enforces. A models.json entry cannot do any of those three, because the alias set changes without notice and /v1/models only has the data at runtime.

Install

pi install npm:pi-blablador

Then /reload: pi --list-models blablador should list 21 chat models.

Auth

Blablador takes a Helmholtz Codebase personal access token (a GitLab PAT with the read_user scope):

export BLABLADOR_API_TOKEN=glpat-...

Create one at https://codebase.helmholtz.cloud/-/user_settings/personal_access_tokens. Tokens last at most one year — a sudden 401 is usually this.

/login works too: pick Blablador, paste the key, and it is stored in ~/.pi/agent/auth.json, where it takes precedence over the environment variable. The provider id stays lowercase — blablador is what --model blablador/… and the settings resolve against, Blablador is only the label. pi auth check --provider blablador prints ready when a key is resolvable and not_ready when not, which is the fastest way to tell a missing token from a throttled one.

Needs Pi 1.4.0 or newer — the only version this was tested against.

Thinking levels

Every backend has its own reasoning_effort vocabulary and answers HTTP 400 for anything outside it, so the map is per model family:

family accepts
qwen none | low | medium | xhigh
oss (gpt-oss) low | medium | high
kimi none | low | high | max
deepseek none | low | high | xhigh | max
muse low | medium | high | xhigh
generic (glm, minimax, mimo, aleph, …) none | low | medium | high | xhigh
none (apertus, eve, ocr) — (the field is never sent)

Pi's own levels are folded onto these, so you always pick from Pi's list: --thinking high on a Qwen model sends xhigh, --thinking medium on DeepSeek sends high, --thinking minimal sends low.

Context windows

The context windows the gateway enforces: 1,048,576 for the 1M deployments, 262,144 for the Qwen 3.8, Apertus and OCR families, and 131,072 for alias-fast and alias-eve. Output is capped at 16k tokens so reasoning cannot consume the whole answer budget.

Which models appear

alias-* ids, plus two verified unaliased ids (deepseek-v4.1-flash-at-hzdr, Swift-Qwen3.8-27b). The alias is the stable handle — JSC's guide says to use it so the model behind it can change. The rest of the catalog is either a descriptive deployment name ("90 - Kimi-K3 1M on Juwels Booster"), an OpenAI-name shim for the embedding endpoint (gpt-3.5-turbo, text-davinci-003), or a model that cannot call tools (trustllm-*). Embeddings, rerankers, image/video/voice and the anonymizer are not chat models and never appear.

The filter is an allowlist (alias-* plus those two ids), not a blocklist: of the 27 non-alias entries the API returned today, 24 are noise — 16 duplicate "NN - …" deployment names, 3 tool-broken trustllm, 3 embedding shims, an anonymizer, a whisper and two image generators. The price is that a new unaliased chat model stays invisible until it is added here, in a release; the alternative admits backends nobody has probed.

JSC throttles per account tier, so a long agent loop on a busy alias spends real time in backoff. Pi retries 429s on its own; nothing here needs configuring.

Precedence, and keeping this honest

  1. GET /v1/models — live catalog, root, max_model_len, max_input_tokens.
  2. The ceiling probe — for the models the API leaves blank.
  3. The model guide — prose and descriptions. It is a snapshot and can lag the live catalog.

A live answer that shrinks below 5 chat aliases is treated as a gateway glitch and ignored — the last good list is kept, silently. That is the one thing to know if JSC ever serves a genuinely smaller catalog.

Do not hardcode aliases in your own code; JSC says they come and go.

What was actually checked

npm run test:live drives the real CLI against the live API and asserts on the --mode json event stream: the checklist from pi's custom-provider guide. --list shows the groups without calling anything, and a partial name runs one: npm run test:live overflow. npm test needs no token and no network — it pins the pi-side mapping (picker names, the effort map under pi's level names, the offline catalog shape) plus the one spawn behaviour that cannot be waited out live: pi ignoring the interrupt. The shared rules (family patterns, effort vocabularies, live merge, token trimming) are pinned by blablador-core, the catalog package this provider depends on; its own live contract test (npm run test:live there) is the check that runs straight against /v1/models. CI runs the offline suites on every push, and a weekly job runs the live ones when the token secret is set. Before a release, npm run test:all runs both halves. Last full live run: 14/14.

ordinary text, usage and cost ✅ in=2482 out=20 cost=0
thinking level on alias-code ✅ --thinking high passes, reasoning comes back (qwen got xhigh)
tool call, empty assistant text, tool result ✅ turn stops with toolUse and no text
image input on alias-code ✅ answers "Red" for a red PNG
unicode round-trip ✅ 🐍 Ω 你好 café é
context overflow ✅ recognised, compaction_start then compaction_end
abort ✅ exits on SIGINT, no hard kill needed
abort, when the interrupt is ignored ✅ offline against a stub: SIGINT → SIGKILL, hard_kill=true
catalog ✅ 21 models listed, thinking column right for qwen, gpt-oss and eve

Deliberately not covered: malformed or partial streams (they need a mock server and live in pi-ai's stream code, which this extension does not touch), cross-provider session handoff (needs a second provider), and the offline/partial-catalog path — where /v1/models omits a root and the merge from the table is the only thing that keeps a Qwen on its own effort map. The hard-kill test proves the escalation mechanism with a 300ms grace; the shipped 30s value is a judgement call about 429 backoff, not a measured number. One failure mode belongs to pi rather than to this extension: when the overflow cannot be compacted away — a single attachment larger than the window — pi exits 0 having printed nothing.

Maintaining it

Re-measure a window. /v1/models leaves max_model_len blank for most aliases, so the bundled windows are measured values, not guide numbers; re-measure them when a deployment changes.

Two things look like bugs and are not. The refresh merges root/max_model_len from the offline table because the live catalog omits them, and it can only add, never overwrite — dropping that reverts Qwen models to the generic effort map, which they answer with HTTP 400. Same for the family match: it reads root, because alias-code is a Qwen whose id never says so. blablador-core's tests pin both, and the live thinking group asks alias-code for --thinking high, which only succeeds if the family map translated it to xhigh. The merge from the table is the half neither can reach: it only happens when /v1/models leaves a root out, which needs a mock server (see "What was actually checked"). When a new alias 400s on every thinking level, it has an unfamiliar effort vocabulary: add a family pattern to FAMILY and an entry to EFFORT in blablador-core — there is no runtime detection.

Shared with OpenCode. The catalog list, family/effort maps, live /v1/models merge and token trimming live in blablador-core; blablador.ts is the thin pi adapter over it (refresh TTL, force/allowNetwork, last-good retention, pi's off level name). Change the rules there, never here — opencode-blablador reads the same rules and must not drift. Both packages live in this monorepo, so a root npm install links the core (no symlinks); publish order when the rules change: blablador-core first, then this package, pins bumped in the same commit.

Publishing. npm publish runs prepublishOnly — typecheck plus npm test — and refuses to ship on a failure. It ships blablador-core as a real dependency, so publish the core first. CI runs the same checks without a token, on purpose: the live suite costs real API calls, so a Blablador-side change (a new effort vocabulary, a renamed alias, a shrunken catalog) is caught by the weekly live job (or by someone running npm run test:live), not by a per-push robot. Tag the commit you publish, not an earlier one.

Publishing an unscoped name puts blablador.ts in a public registry: readable by anyone, cached by mirrors, and not really withdrawn by npm unpublish. The repo being private does not contain it.

MIT licensed.