@henryqw/pi-task-models
Shared task model profiles and routing for HenryQW Pi extensions.
Package details
Install @henryqw/pi-task-models from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@henryqw/pi-task-models- Package
@henryqw/pi-task-models- Version
9.5.0- Published
- Nov 13, 2026
- Downloads
- 6,105/mo · 943/wk
- Author
- henrywang
- License
- MIT
- Types
- extension
- Size
- 507.1 KB
- Dependencies
- 1 dependency · 3 peers
Pi manifest JSON
{
"image": "https://raw.githubusercontent.com/HenryQW/pi-harness/main/extensions/pi-task-models/example.png",
"extensions": [
"./extensions/task-models.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@henryqw/pi-task-models
Configure shared Task Profiles for fast, balanced, frontier, and fav. Each Task Route pairs a model with a thinking level; each consumer owns its Model Tasks and defaults.

Install
pi install npm:@henryqw/pi-task-models
Requires Pi 1.5.0 or later in the 1.x series.
Works with
| Package | Relationship | Purpose |
|---|---|---|
@henryqw/pi-auto-compact |
Consumer | Compaction defaults to fast. |
@henryqw/pi-cron |
Consumer | Scheduled jobs default to fast. |
@henryqw/pi-herdr-tools |
Consumer | Side-thread and rename tasks default to fast. |
@henryqw/pi-memory |
Consumer | Candidate review, /remember preparation, and /dream promotion default to balanced. |
@henryqw/pi-multi-codex |
Improves | Numbered Codex slots become one route. |
@henryqw/pi-subagent |
Consumer | Delegation defaults to fast. Callers can declare their own task. |
Use
Type /task-models to see the available actions. The command without arguments opens profile and task settings.
Run /task-models, select fast, then choose a primary model and thinking level. Choose a different fallback model and thinking level, or None. Reopen /task-models: fast shows the saved route instead of not configured.
| Surface | Type | Purpose |
|---|---|---|
/task-models |
command | Configure profiles and assign them to active tasks. |
/task-models preset |
command | Apply a saved profile setup. |
/task-models sync-delegates |
command | Overwrite delegate role models and thinking levels from task routes. |
Option+S / Alt+S in /task-models |
shortcut | Save configured profiles as a named preset in the interactive terminal. |
| Session start | ui | Warn about missing config and config or preset problems. Show an error when routing is disabled. |
Configure each profile your consumers require. fav has no fallback. Select an active task to override its declared profile; choosing its declared default removes the override.
Delegate routes
/task-models lists the billion-context acp_delegate roles. Researcher defaults to fast; reviewer, worker, planner, and oracle default to balanced. Assign a profile to each role as needed. The first available route supplies the model and thinking level.
Run /task-models sync-delegates to write the available routes to the external delegate role settings. This overwrites the model and thinking level for each role with an available route. Startup, prompts, and other task model saves do not sync delegate settings. The command runs only when the registered acp_delegate comes from npm:billion-context. Other delegate providers are skipped.
When pi.subagents is an object or true in the billion-context config, the sync updates its role settings. When it is false or has enabled: false, the sync stays inactive. When it is absent, billion-context uses the legacy acp.json files.
The sync updates the project file when it has a delegate setting; otherwise, it updates the global file. It creates the global file only when a route is available. The sync preserves other settings and does not change a disabled legacy delegate. Project delegate settings replace the global delegate object.
The config path is BILI_CONFIG_FILE when set, otherwise billion-context/billion-context.json under XDG_CONFIG_HOME, or ~/.config when that variable is unset. The legacy paths are ~/.pi/acp.json and .pi/acp.json in the session working directory; the directory name follows Pi.
Sync requires strict JSON in these files, even if the billion-context loader accepts comments or trailing commas. If a file is not strict JSON, sync shows a warning and leaves it unchanged. Remove comments and trailing commas, and use quoted keys and strings to repair it.
Sync also leaves files unchanged if delegate role settings are invalid, if they are symbolic or hard links, or if permissions or metadata are unsupported. Files with numbers that would change during JSON serialization are also left unchanged. Route or write problems show a warning and do not block Pi. Explicit delegate call settings still take priority.
Billion-context loads delegate config at session initialization. Start a new session after sync to use the changes.
Presets
Run /task-models preset and choose a name. Included profiles replace complete routes, thinking levels, and fallbacks in one atomic update. Omitted profiles and task assignments stay unchanged. Applying can create missing active config.
To save, open /task-models, press Option+S (macOS) or Alt+S, then enter a name. The preset contains all configured profiles, not task assignments. Other presets stay unchanged. Cancelling a preset prompt writes nothing.
The shortcut requires an interactive terminal that sends Option/Alt as Meta (Escape); RPC does not support it.
Flow
The menu shows effective profiles for active tasks. Disabled consumers' assignments remain stored but hidden.
Menus list your scoped models and pinned thinking levels, or all available text models when no scope is set. Duplicate numbered Codex aliases collapse into one choice; fallback choices exclude the primary.
Config
Package-owned: ~/.pi/agent/config/pi-task-models/config.json. Only explicit /task-models actions save it. Use exact model IDs from Pi's registry, not these placeholders:
{
"profiles": {
"fast": {
"primary": { "model": "<provider>/<model>", "thinkingLevel": "low" }
}
},
"tasks": {}
}
| Name | Description | Values | Default |
|---|---|---|---|
profiles |
Stores shared routes. | Object keyed by fast, balanced, frontier, or fav. |
{} |
profiles.<profile>.primary.model |
Required primary model. | Canonical provider/model without whitespace or NUL. |
— |
profiles.<profile>.primary.thinkingLevel |
Required primary thinking level. | off, minimal, low, medium, high, xhigh, or max; model support required at resolution. |
— |
profiles.<profile>.fallback |
Route to try when the primary is unavailable. | Object requiring model and thinkingLevel, with primary rules. Forbidden for fav. |
No fallback. |
tasks |
Explicit profile overrides. | Object mapping <package>/<task> IDs to profiles. |
{} |
tasks.<taskId> |
Overrides the declared profile. | fast, balanced, frontier, or fav. |
Task declaration's defaultProfile. |
Task defaults belong to consumer declarations. Existing overrides equal to those defaults remain valid.
Preset file
You can edit ~/.pi/agent/config/pi-task-models/presets.json manually. It maps preset names to any subset of the four profiles, each in the profiles.<profile> format above. The picker sorts names alphabetically.
Missing, empty, or invalid files do not change active config. Invalid names, presets, and profiles produce warnings and are ignored; valid entries remain available.
Saving never overwrites a preset file that has problems; a conflict message asks you to try again.
API
| Surface | Type | Purpose |
|---|---|---|
PROFILE_NAMES, THINKING_LEVELS |
constant | List the profile names and thinking levels. |
ProfileName, ThinkingLevel, ModelTask, TaskModelRoute, TaskModelProfile, TaskModelsConfig, AvailableModel, ResolvedTaskRoute, TaskRouteErrorCode, TaskRouteError |
type | Name profiles, thinking levels, Model Tasks, Task Routes, Task Profiles, config, registry models, resolved routes, and route errors with taskRouteCode and optional profileName. |
registerModelTask(pi, task) |
function | Registers a consumer declaration at extension load. |
loadTaskModelsConfig(agentDir?) |
function | Reads and validates config; throws when disabled. |
registerTaskModelsConfigReporting(pi, agentDir?) |
function | Reports problems at session start; returns report(ctx) for later problems. |
canonicalModelReference(model) |
function | Validates and canonicalizes provider/model, including numbered Codex aliases. |
modelReference(model) |
function | Formats provider/model. |
dedupeAvailableModels(models, preferredProvider?) |
function | Removes duplicate canonical references, with optional provider preference. |
resolveAvailableModel(models, reference, preferredProvider?) |
function | Finds a reference, including numbered Codex aliases. |
availableTaskModels(ctx) |
function | Lists scoped text models, or registry models when scope is empty. |
taskThinkingLevels(ctx, model) |
function | Lists supported levels, respecting session-pinned thinking. |
resolveTaskModelRoute(ctx, route, thinking?) |
function | Resolves one available route. |
resolveConfiguredTaskRoute(ctx, task, agentDir?, thinking?, onFallback?) |
function | Resolves the first usable task route. |
resolveConfiguredTaskRoutes(ctx, task, agentDir?, thinking?, onFallback?) |
function | Resolves configured task route candidates. |
executeTaskRoutes(routes, attempt, { shouldFallback, signal? }) |
function | Tries resolved routes in order; returns first success. |
orderedProfileRoutes(profile) |
function | Returns primary, then optional fallback. |
createTaskModelsExtension(pi, options?) (also default export) |
function | Registers /task-models, missing-config warnings, and issue reporting. |
Profile thinking is authoritative; resolution uses config.tasks[task.id] ?? task.defaultProfile.
The optional onFallback(profileName, route) callback reports when the first usable route is the configured fallback. It does not run when the primary is usable or when no route is usable. It does not report execution failures or retries. Consumers own warning delivery and duplicate suppression.
Consumers must not read or write shared config; call report(ctx) before resolution.
executeTaskRoutes() rejects empty lists and checks signal before each route. Cancellation or shouldFallback(error) === false stops execution. Allowed failures end with the final error unchanged. Each route call must be atomic and safe to repeat.
Limits and recovery
Problems appear at session start and when /task-models opens. For the shared rules, see Config files. Resolution throws TaskRouteError with a taskRouteCode:
| Problem | Code | Recovery |
|---|---|---|
Unknown key, misspelled tasks, unknown profile name, invalid task ID or task profile. |
None | None needed. Tasks without valid overrides use declared defaults. |
| Config is absent. | config-missing |
Run /task-models to create it. |
File problem, non-object profiles, misspelled profiles such as profile. Routing is disabled for every task. |
config-disabled |
Repair the file or save through /task-models. |
Profile is absent, or Pi warns and ignores an invalid profile, route, or fallback in fav. |
profile-missing |
Configure the profile in /task-models. |
| No available route. | no-route |
Choose an available model and thinking level in /task-models. |
Saves retain only valid settings, including valid tasks when profiles is invalid. If the file changed while /task-models was open, saving writes nothing; reopen /task-models.
Saving refuses oversized, unreadable, or non-regular files. Fix, shrink, or remove the file first.
Consumers may silence only config-missing, and only with a safe current-session fallback.
