@jopqior/pi-subagents-model-selector

Pi extension that asks for model and thinking before every new pi-subagents run.

Packages

Package details

extension

Install @jopqior/pi-subagents-model-selector from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@jopqior/pi-subagents-model-selector
Package
@jopqior/pi-subagents-model-selector
Version
2.0.0
Published
Sep 20, 2026
Downloads
767/mo · 767/wk
Author
jopqior
License
MIT
Types
extension
Size
38.4 KB
Dependencies
0 dependencies · 4 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

@jopqior/pi-subagents-model-selector

npm version CI License: MIT TypeScript pnpm Pi Package

Ask for model and thinking before every new in-process @jopqior/pi-subagents child session.

Installing or upgrading the core alone does not change selection.

Source history: the repository's git history was restored to the original upstream merge graph. Already-published npm artifacts are unchanged, and artifacts published after that restoration are built from the restored history. See History restoration for what this means for old commit links and existing clones.

Install

Load after @jopqior/pi-subagents. Pi loads packages in the order they are listed in .pi/settings.json, and this extension registers its provider with the subagents service at load time — so the core must load first.

pi install npm:@jopqior/pi-subagents
pi install npm:@jopqior/pi-subagents-model-selector

Then list those two npm: sources in that order:

{
  "packages": [
    "npm:@jopqior/pi-subagents",
    "npm:@jopqior/pi-subagents-model-selector"
  ]
}

Or load from a checkout:

{
  "packages": [
    "../packages/pi-subagents",
    "../packages/pi-subagents-model-selector"
  ]
}

If the core package is absent, the selector's static import fails while modules load, Pi reports the missing @jopqior/pi-subagents module, and the selector is not activated. If the core is installed but its service is absent because the core loaded too late, initialization throws a configuration error naming the required package, the registration method, and the load order. If the service is present but lacks registerSpawnSelectionProvider, the same configuration error applies and the selector registers no hooks and does not activate.

Core compatibility

The selector declares @jopqior/pi-subagents as a required peer dependency with a floor of >=1.0.0. The floor describes the spawn-selection API the selector needs, independently of the core version used for development, so developing against one core version does not move the published range. The floor has been verified against the published core releases 1.0.0, 1.0.1, 1.0.2, and 2.0.0, and the maintainer verification command below keeps that verification current. The open upper bound is a maintenance policy rather than a guarantee that every future core major works without a selector release.

Migrating to the peer dependency

This version is breaking: the core moved from an ordinary dependency to a required peer. Installing only the selector no longer downloads the core, because Pi installs packages with peer resolution disabled. Install the core explicitly and list it before the selector in .pi/settings.json, exactly as the instructions above show. Setups that already install and load both packages in that order need no change.

Release policy

Selector changes and compatibility-declaration changes each require a selector release. A core release alone does not.

Maintainer verification

pnpm run verify:core-compatibility in this package reproduces the packed-compatibility checks behind this policy. It packs the real selector, asserts the packed manifest contract, and repacks an isolated workspace copy across a changed sibling core version to show the public peer range is unchanged. It installs the tarball into disposable consumers with every published core and the pinned Pi host packages, type-checks the packed source against each core, and exercises the Pi loader matrix, including the negative rows and a labeled synthetic incompatible-service row. The command needs network access to npmjs.org, builds every fixture in a temporary directory it removes afterwards, and stays out of the Vitest suite.

Behavior

Every new run in an enabled root's in-process tree opens one /model-style form: model, thinking, and Submit. Foreground tool calls, background tool calls, and SubagentsService.spawn() all go through the same gate.

The operator's pair is applied after ordinary call and config resolution. It overrides defaults, explicit model/thinking arguments, and locked: values for those two fields only. Other locked fields are unchanged.

The all-tab catalogue is every authenticated available model of the session whose manager is spawning — not a process-global list. The scoped tab is ctx.scopedModels intersected with that catalogue, and is hidden when the intersection is empty. Ctrl+S toggles all/scoped when the scoped tab exists. A model that supports only off still shows off and requires an explicit choice on the thinking tab.

Concurrent requests are FIFO at the root chooser. A queued run does not open the form until it is admitted. Cancel the form stops that run without creating a workspace or child session.

A missing TUI, a UI that is not yet attached, an empty catalogue, or an invalid selection fails that run explicitly. Print, JSON, and RPC sessions fail closed — there is no ui.select fallback. There is no default, timeout, remembered choice, or retry.

Nested children still route to the root UI, including when this package is excluded from them. A child that also loads this package receives an inherited registration and installs no second queue.

resume does not re-ask. The parent's active model, thinking level, agent files, and tool-call arguments are not rewritten to carry the choice.

Lifecycle

The extension captures getSubagentsService() once during initialization and registers the provider immediately, before any session_start handler can spawn. It attaches ctx.ui.custom at session_start when ctx.mode is tui, and closes the chooser at session_shutdown. A request that arrives before the UI is attached fails closed rather than waiting for a later sequential handler.

Limitations

  • Out-of-process children and third-party session factories are not covered.
  • The form rebuilds the /model experience without mounting Pi's ModelSelectorComponent (no type-to-filter on the thinking tab, no set-as-default).
  • Public task status stays running while waiting. Pending selection is private widget, foreground, and background wording.

License

MIT