@yieldcraft/dynamic-router

Configurable dynamic model router for Pi. Registers a virtual provider that routes each request to the best already-configured model for the situation.

Packages

Package details

extension

Install @yieldcraft/dynamic-router from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@yieldcraft/dynamic-router
Package
@yieldcraft/dynamic-router
Version
0.0.3
Published
Jul 15, 2026
Downloads
258/mo · 258/wk
Author
marcus-yieldcraft
License
MIT
Types
extension
Size
35.1 KB
Dependencies
0 dependencies · 4 peers
Pi manifest JSON
{
  "extensions": [
    "./extensions"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@yieldcraft/dynamic-router

A configurable dynamic model router for Pi.

The package registers a virtual provider (dynamic-router) that exposes a few "router" models. Each request sent to a router model is transparently routed to the best already-configured Pi model for the current situation — based on whether the request contains an image, whether it looks security/critical, and how large the context is.

The selected target model, the routing reason, and any skipped candidates are shown live in the Pi footer status line and persisted as a collapsible trace entry in the session (never sent to the LLM).

The defaults below are YieldCraft's preferences. Every route is fully configurable — see Configuring your own models.

Why this exists

I regularly work with models from several providers, including Ollama, OpenAI, and Anthropic. I choose between them based on capability, cost, speed, and personal preference.

For example, I often prefer GLM-5.2 for serious coding work, but it does not support vision. Whenever a prompt contains a screenshot, I have to remember to switch to a vision-capable model before sending it. That manual step is tedious and easy to forget.

The opposite problem is using an expensive frontier model when the task does not require one. Tasks such as writing Markdown documentation, producing summaries, or running a tightly scoped coding worker can often be handled by a faster and cheaper model—for example GPT-5.6 Terra or Luna, Kimi K2.7 Code, or a model such as GPT-5.4 Mini.

Dynamic Router automates these choices while keeping the routing policy explicit, observable, and fully configurable. The included model lists are only defaults: users can replace them with any models available in their own Pi registry.

Install

pi install npm:@yieldcraft/dynamic-router

Requires Pi and at least one real provider configured in Pi's model registry (ollama-cloud, openai-codex, anthropic, …). The router never stores API keys; it delegates auth to Pi's existing model registry.

Virtual models

Model id When to use
dynamic-router/auto General work. Routes to non-vision, or vision when an image is present.
dynamic-router/critical High-stakes work (security, wallets, migrations, prod incidents). Uses the critical-vision route when an image is present.
dynamic-router/cheap Bounded / fresh-context fallback. Uses the vision route when an image is present.
dynamic-router/vision Image / screenshot analysis. Uses the critical-vision route when the request also looks critical.

Select one in Pi with /model and pick dynamic-router/auto (or any of the above), or start Pi with:

pi --model dynamic-router/auto

How routing decides

For each request the router:

  1. Picks a route from the selected router model + request signals:
    • auto — default non-vision.
    • vision — an image/screenshot is present.
    • criticalVision — an image is present and the request looks critical.
    • cheap — bounded fallback.
  2. Walks the route's ordered fallback list of model references (provider/id).
  3. Skips candidates that are: unavailable in the registry, over the configured context-token limit, or lacking image support when an image is present.
  4. Streams from the first available candidate, preserving streaming, tool calls, usage metadata, and errors from the target provider.

A request only "looks critical" when the latest user message contains an explicit high-risk signal such as critical, production incident, security breach, data loss, funds at risk, wallet compromised, leaked credentials, a critical/actively exploited vulnerability, or a zero-day. The system prompt and older conversation messages are deliberately ignored so that ordinary words such as debug, auth, wallet, production, or migration do not escalate a simple task. Select /router critical when you want to force the critical mode.

Configuring your own models

There are two ways to configure routes.

1. Interactive command (recommended)

Run inside Pi:

/dynamic-router

(or the alias /router). The menu lets you:

  • show config — print the current config and config file path.
  • configure auto models / configure cheap models / configure vision models / configure critical models — choose both the primary and backup model for each route. The model picker filters live as you type, using a case-insensitive substring match against the model name and provider/id (for example, gpt).
  • toggle trace (on/off) — show/hide the routing trace.
  • reset defaults — restore the built-in defaults.

Command arguments (also available through autocomplete):

/router auto             # select dynamic-router/auto
/router cheap            # select dynamic-router/cheap
/router vision           # select dynamic-router/vision
/router critical         # select dynamic-router/critical
/dynamic-router show     # print current config
/dynamic-router trace    # toggle trace on/off
/dynamic-router reset    # restore defaults

/router and /dynamic-router are aliases, so either command name accepts all of the arguments above.

If Pi reports the command as /dynamic-router:1, /dynamic-router:2, etc., the extension has been loaded more than once. Use the suffixed command shown by Pi, or disable the duplicate package with pi config.

2. Edit the config file directly

The config lives at ~/.pi/agent/dynamic-router.json. Shape:

{
  "version": 1,
  "trace": true,
  "routes": {
    "auto":            { "models": ["ollama-cloud/glm-5.2", "openai-codex/gpt-5.6-terra"] },
    "vision":          { "models": ["openai-codex/gpt-5.6-terra", "ollama-cloud/kimi-k2.7-code"] },
    "criticalVision":  { "models": ["openai-codex/gpt-5.6-sol", "openai-codex/gpt-5.6-terra"] },
    "cheap":           { "models": ["ollama-cloud/kimi-k2.7-code", "openai-codex/gpt-5.6-luna"] }
  },
  "heuristics": {
    "avoidModelsWhenContextTokensAbove": [
      { "model": "ollama-cloud/kimi-k2.7-code", "tokens": 120000 }
    ]
  }
}
  • routes.<name>.models — ordered fallback list of provider/id references. The first available candidate wins. You can list any model configured in your Pi registry; references to dynamic-router/* are ignored (no recursive routing).
  • heuristics.avoidModelsWhenContextTokensAbove — skip a model once the estimated context exceeds tokens. Useful to avoid models that hallucinate on large contexts.
  • trace — persist routing decisions as collapsible TUI-only entries (default true). Never sent to the LLM.

Invalid or empty route lists fall back to the defaults above. Unknown / malformed heuristic rules are dropped.

Example: route everything to a single provider

{
  "version": 1,
  "trace": true,
  "routes": {
    "auto":           { "models": ["anthropic/claude-sonnet-4"] },
    "vision":         { "models": ["anthropic/claude-sonnet-4"] },
    "criticalVision": { "models": ["anthropic/claude-sonnet-4"] },
    "cheap":          { "models": ["anthropic/claude-haiku-4"] }
  },
  "heuristics": { "avoidModelsWhenContextTokensAbove": [] }
}

Routing trace

When trace is on, every routed assistant turn surfaces its decision:

  • Footer status line (real-time, while streaming): → <target> (route=…, img=…, crit=…, ~tokens) plus skipped candidates.
  • Session trace entry (TUI-only, never sent to the LLM): a compact collapsible row with the router model, route, target, reason, skipped candidates, and signals.

Toggle with /dynamic-routertoggle trace (on/off) or /dynamic-router trace.

Supported target APIs

The router delegates to any Pi provider whose API is one of:

  • openai-completions
  • openai-responses
  • openai-codex-responses
  • anthropic-messages
  • google-generative-ai
  • google-vertex
  • mistral-conversations

Development

npm install
npm run typecheck
npm run pack:dry

Test locally with Pi:

pi -e ./extensions/index.ts --list-models
pi -e ./extensions/index.ts --model dynamic-router/auto

If the package is already installed, disable that installed copy with pi config before testing with -e. Otherwise Pi loads both copies and disambiguates their commands as /dynamic-router:1, /dynamic-router:2, etc.

License

MIT