pi-budget-model
Auto-select the cheapest available model for background tasks in pi
Package details
Install pi-budget-model from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-budget-model- Package
pi-budget-model- Version
1.0.1- Published
- Mar 7, 2026
- Downloads
- 57/mo · 6/wk
- Author
- mgabor3141
- License
- MIT
- Types
- package
- Size
- 19.4 KB
- Dependencies
- 1 dependency · 2 peers
Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-budget-model
Auto-select the cheapest available model for background tasks — guardrails, summarization, tagging, and anything where cost matters more than peak capability.
Install
npm install pi-budget-model
Usage
import { findBudgetModel, NoBudgetModelError } from "pi-budget-model";
// Simple — cheapest in same provider, latest major version
const { model, apiKey } = await findBudgetModel(ctx);
// Cross-provider — cheapest across all providers with an API key
const { model, apiKey } = await findBudgetModel(ctx, {
strategy: "any-provider",
});
// Include previous major version (often much cheaper)
const { model, apiKey } = await findBudgetModel(ctx, {
majorVersions: 2, // latest + previous major version
costRatio: 0.5, // must be ≤ half the active model's cost
});
// Pin a specific model, skip auto-selection
const { model, apiKey } = await findBudgetModel(ctx, {
modelOverride: "anthropic/claude-haiku-4-5",
});
// Only free models
const { model, apiKey } = await findBudgetModel(ctx, {
costRatio: 0,
});
What gets picked
With default settings (same-provider, costRatio: 0.5, majorVersions: 1):
| Active model | Budget model picked | Why |
|---|---|---|
anthropic/claude-sonnet-4-5 ($3/M) |
claude-haiku-4-5 ($1/M) |
Cheapest Anthropic model in latest major version (4) |
anthropic/claude-opus-4-5 ($5/M) |
claude-haiku-4-5 ($1/M) |
Same |
anthropic/claude-haiku-4-5 ($1/M) |
(none — already cheapest) | No cheaper model in major version 4 |
openai/gpt-5 ($1.25/M) |
gpt-5-nano ($0.05/M) |
25× cheaper, same major version (5) |
openai/gpt-4o ($2.50/M) |
gpt-5-nano ($0.05/M) |
OpenAI's latest major version is 5 — nano is cheapest there |
google/gemini-2.5-pro ($1.25/M) |
gemini-3.1-flash-lite-preview ($0/M) |
Free model in Google's latest major version (3) |
xai/grok-4 ($3/M) |
grok-4-1-fast ($0.20/M) |
Cheapest xAI model in major version 4 |
Note:
majorVersionsselects from the provider's latest N major versions, not from the active model's version. This is why gpt-4o (version 4) gets a gpt-5 budget model — OpenAI's latest major version is 5.
When the active model is already the cheapest (like Haiku 4.5), you can widen the search:
| Option | Effect for claude-haiku-4-5 |
|---|---|
majorVersions: 2 |
Includes previous major version → picks claude-3-haiku ($0.25/M) |
strategy: "any-provider" |
Searches all providers → picks cheapest available across providers |
Options
| Option | Type | Default | Description |
|---|---|---|---|
modelOverride |
"provider/model-id" |
— | Pin a specific model, bypassing auto-selection entirely |
strategy |
"same-provider" | "any-provider" |
"same-provider" |
Where to search for budget models |
costRatio |
0–1 |
0.5 |
Max cost as fraction of active model (0 = free only) |
majorVersions |
0, 1, 2, ... |
1 |
How many major versions to search (1 = latest, 2 = latest + previous, 0 = all) |
Options are validated at runtime with valibot. Invalid values throw immediately.
modelOverride
When set, all other options are ignored. The model is resolved directly from the registry by provider and ID — no strategy, cost ratio, or version filtering applies. Throws NoBudgetModelError if the model doesn't exist or has no API key.
This is useful for pinning a known-good model in config files, or for testing.
Reusable options schema
The BudgetModelOptions valibot schema is exported for embedding in extension configs:
import { BudgetModelOptions } from "pi-budget-model";
import * as v from "valibot";
const MyConfig = v.object({
model: v.optional(BudgetModelOptions, {}), // all budget-model options
});
This gives consumers a consistent model selection interface — users who know modelOverride / strategy / costRatio / majorVersions from one extension will recognize them in others.
Algorithm
For same-provider (default):
- Filter to models in the active provider
- Extract major version from each model ID, select the top N (descending)
- Find the cheapest model(s) by input cost
- Verify the cheapest is within the cost ratio vs the active model
- Among ties: higher version numbers win, aliases preferred over dated snapshots
- Return the first candidate with an available API key
For any-provider: same steps but across all providers, grouped independently per provider then merged.
Error handling
Throws NoBudgetModelError when no suitable model is found. The error includes structured candidates for custom fallback logic:
try {
const { model, apiKey } = await findBudgetModel(ctx);
} catch (err) {
if (err instanceof NoBudgetModelError) {
err.reason; // why it failed
err.sameProvider; // best same-provider candidate (may have failed cost check)
err.cheapestOverall; // cheapest across all providers
}
}
If uncaught in a pi extension, the error propagates to pi's error handler which surfaces a descriptive message to the user identifying the calling extension.
Version extraction
Model IDs use wildly different naming conventions. The version parser handles all of them:
| Model ID | Major version |
|---|---|
claude-sonnet-4-5 |
4 |
gpt-5-nano |
5 |
o3-mini |
3 |
gemini-2.5-flash |
2 |
grok-4-1-fast |
4 |
claude-3-5-haiku-20241022 |
3 |
Date-like tokens (≥8 digits) are skipped. The (\d+) regex extracts the first number from any token, handling prefixed names like o3.