pi-bifrost-gateway
Pi extension for a Bifrost LLM gateway: chain models from VK routing rules and/or the full upstream model catalogue, with optional per-family native protocol surfaces
Package details
Install pi-bifrost-gateway from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-bifrost-gateway- Package
pi-bifrost-gateway- Version
0.3.3- Published
- Nov 3, 2026
- Downloads
- 753/mo · 115/wk
- Author
- mikemacleod
- License
- MIT
- Types
- extension
- Size
- 72.4 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-bifrost-gateway
Pi extension for a Bifrost LLM gateway:
publishes the gateway's models as first-class pi models — chain models from
the VK's routing rules, the full upstream model catalogue, or both — instead
of a hand-maintained models.json block. Optional per-family native
protocol surfaces let OpenAI-family models speak the Responses API and
Anthropic-family models speak Messages end to end.
Companion-package note: this is the management-API flavor (governance-aware: virtual-key discovery and routing-rule chains). It fills the same provider slot as lxdlam/pi-bifrost-provider (standalone-instance flavor) — install one OR the other, not both.
Install
From npm:
pi install npm:pi-bifrost-gateway
Or from a local checkout:
pi install ~/repos/pi-bifrost-gateway
Then configure it (~/.pi/agent/pi-bifrost-gateway.json) — there is no
built-in gateway URL, so an unconfigured install registers zero models:
{
"baseUrl": "https://your-bifrost.example/v1",
"publishChains": true,
"publishUpstream": false
}
Auth: /login bifrost (stores the virtual key AND the gateway URL on the
credential in auth.json — sufficient on its own) or the BIFROST_API_KEY
env var.
How it works
Two publishing modes, selectable independently:
Chains mode (publishChains: true) — requires a gateway with
chains-first routing rules. fetchModels (runs on startup, /model,
/reload, /login) does, live:
GET /v1/models(your VK Bearer) — member catalog with per-member pricing and context windows.GET /api/governance/virtual-keys— matches your stored credential value to discover which virtual key you are (the rule filter'sscope_id).GET /api/routing/rules?scope=virtual_key&scope_id=<vk>— the VK's chain rules; CELmodel == "x"pairs give chain names, targets +fallbacks[]give member ids.
From that it emits one pi model per chain (bifrost/<chain>, e.g.
bifrost/glm-5.3-flash), with contextWindow = min member window. A rules
set with no usable chains fails discovery loud.
Member-only mode (publishChains: false, the default) — the inference
plane alone: one GET /v1/models and the full upstream catalogue is
published as direct-selectable models (provider/model, e.g.
hyper/glm-5.3-flash) with real per-member pricing and context windows. No
management-API access at all, so it works against a stock gateway with
governance disabled entirely. Both modes can be combined (publishChains: true + publishUpstream: true) — chains first, then the catalogue.
In both modes, nativeProtocols (see Configuration) can switch matching
model families from chat completions to their native wire — openai-responses
for the gpt family, anthropic-messages for the claude family — so the
client protocol matches what your gateway/upstream speaks.
Auth
/login bifrost prompts for both the gateway URL and the virtual key and
stores them together on the credential in auth.json (URL in the
credential's BIFROST_URL env slot) — after login no config file is needed.
Alternatively set baseUrl via config/BIFROST_BASE_URL env and /login
with the URL left blank to keep that ambient resolution.
URL precedence: login-stored credential URL → config-file baseUrl →
BIFROST_BASE_URL env. Key: stored credential → BIFROST_API_KEY env.
A stored credential under the legacy gateway provider id is migrated to
bifrost on load; re-running /login bifrost upgrades an old key-only
credential to carry its URL.
Configuration
~/.pi/agent/pi-bifrost-gateway.json (all keys optional). Defaults are
CONSERVATIVE — publishChains false, chat completions everywhere:
{
"publishChains": true,
"publishUpstream": true,
"nativeProtocols": { "responses": true, "messages": true }
}
publishChains(default false): emit thebifrost/<chain>models from the VK's routing rules. Requires a gateway with chains-first routing rules for the credential's VK; a rules set without usable chains fails discovery loud. Leave it off (the default) for a stock gateway — member-only mode needs no governance at all.publishUpstream: falsehides the direct-selectable upstream catalog (hyper/glm-5.3-flash,pareto/glm-5.3-flash, …) with real per-member pricing.publishMembersis accepted as a legacy alias.baseUrl(optional) gateway/v1URL; then envBIFROST_BASE_URL. There is NO built-in default URL: with neither set (and no URL stored by/login bifrost), the plugin registers zero models.managementApiKey(optional) bearer for the management plane (/api/governance/virtual-keys,/api/routing/rules). Defaults to the inference credential (the VK) — correct for dashboard-auth-disabled deployments that accept the VK on/api/*. Set it when the management plane expects a different credential than inference. The VK-value match (VK self-identification) always uses the INFERENCE credential, never this key.nativeProtocols(optional; both toggles default false) selects the client wire per model family:responses: true— models matching the built-in [OI]-native family heuristic (gpt-*exceptgpt-oss*,o<n>,codex*) publish asopenai-responses. Requires a gateway servingPOST /v1/responses.messages: true— models matching the built-in Anthropic family heuristic (claude-*in the NAME) publish asanthropic-messages, pointed at the gateway's/anthropicintegration route. Requires a gateway with the Anthropic integration prefix registered.responsesModels/messagesModels(optional arrays of exact bare model names, e.g.["gpt-6-luna"]): when set, the list REPLACES the built-in heuristic for that surface — list membership is the only path to the native wire. Name matching is case-insensitive, last path segment (the serving prefix never decides).- Both off (default): every model publishes chat completions — the only wire every Bifrost serves; the gateway translates at the boundary.
Prompt cache
Models declare promptCache lifetimes (short 300s, long 3600s) so pi's
cache warmer can keep a prefix alive across idle gaps — without a declared
lifetime pi treats the model as un-warmable and never refreshes it.
Retention is selected by pi, not by this extension:
| goal | how |
|---|---|
| 5-minute cache (default) | nothing to do |
| 1-hour cache | PI_CACHE_RETENTION=long |
| per-provider only | put PI_CACHE_RETENTION=long in the credential env bag in auth.json |
| keep a session warm | "warmChains": true (see below) |
The ttl:"1h" breakpoint only appears when long retention is requested;
declaring the lifetimes does not turn it on. On a Bifrost → InferHub gateway
the 1h tier costs no more per write than the 5m tier (InferHub bills both at
the plain input rate), so long retention is the better default there.
A per-provider value is forwarded from the credential's env bag, which is where pi reads provider-scoped settings:
// ~/.pi/agent/auth.json
"bifrost": { "type": "api_key", "key": "...", "env": { "PI_CACHE_RETENTION": "long" } }
Keeping a chain warm (warmChains)
promptCache makes a model eligible for pi's cache warmer, but chains are
still skipped: they publish zero cost by design, so pi's savings estimate is
zero and it never refreshes them. "warmChains": true adds a
cache_warming_decision handler that warms a bifrost/<chain> while a run is
streaming, and stays quiet once the agent is idle. Refreshes are real,
billable requests (a cache read of the prefix), which is why it is off by
default.
Cost
Chain models carry zero cost by design: pi recomputes cost from catalog
rates and cannot know which member actually served a chain request. Bifrost
/api/logs (cost + cost_breakdown per request) remains the system of record.
Upstream catalogue models carry real $/Mtok rates from /v1/models.
Commands
/bifrost — auth, baseUrl, config, and loaded-model status.