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

Packages

Package details

extension

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:

  1. GET /v1/models (your VK Bearer) — member catalog with per-member pricing and context windows.
  2. GET /api/governance/virtual-keys — matches your stored credential value to discover which virtual key you are (the rule filter's scope_id).
  3. GET /api/routing/rules?scope=virtual_key&scope_id=<vk> — the VK's chain rules; CEL model == "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 the bifrost/<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: false hides the direct-selectable upstream catalog (hyper/glm-5.3-flash, pareto/glm-5.3-flash, …) with real per-member pricing. publishMembers is accepted as a legacy alias.
  • baseUrl (optional) gateway /v1 URL; then env BIFROST_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-* except gpt-oss*, o<n>, codex*) publish as openai-responses. Requires a gateway serving POST /v1/responses.
    • messages: true — models matching the built-in Anthropic family heuristic (claude-* in the NAME) publish as anthropic-messages, pointed at the gateway's /anthropic integration 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.