# Switch Model for Pi

A single `switch_model` tool for [pi](https://pi.dev) that lets the *active* model switch
itself mid-conversation, on request, in plain language — "implement this with 5.6 sol",
"switch to fable" — with no approval loop and no automatic restore. You stay on whatever
model you switch to until you (or the model) call it again.

This is deliberately simpler than role-locked workflows like pi-duo's executor/reviewer
setup (derived from [jnsahaj/trio](https://github.com/jnsahaj/trio)): there's no phase
state machine, no tool-locking, no session bookkeeping. It's one tool that resolves a
free-text model reference and calls `pi.setModel()`.

Human-driven switching is already covered by pi core's built-in `/model` command; this
package only adds the LLM-facing half.

## Install

```bash
pi install npm:pi-switch-model
```

For local development against this checkout instead of the published package:

```bash
pi -e /path/to/pi-extensions/switch-model
```

## Usage

Just ask, mid-conversation:

> switch to 5.6 sol and implement this

The active model calls `switch_model({ query: "5.6 sol" })`, which resolves the query
against your configured/authenticated models and switches. The rest of the conversation —
history, working tree, tools — is untouched; only the model changes, and it stays changed.

## Resolution

- **Exact `provider/id`** always wins outright.
- Otherwise the query is fuzzy-matched against every available model's `provider/id` and
  display name.
- **One strong match** → switches immediately.
- **No match** → fails with a `ModelNotFoundError`-style message listing the closest
  suggestions (capped at 8) so the calling model can retry with an exact id.
- **Multiple matches** → fails listing the tied candidates so the calling model can pick
  precisely.

This retry-on-error contract is the whole safety net: the tool never guesses on your
behalf, and a wrong first guess self-corrects in one retry because the error itself carries
the real list of available models.

## Develop

```bash
npm run typecheck   # tsc --noEmit
npm test             # node --test test/core.test.ts
```

All resolution and formatting logic lives in `src/core.ts` and is pure (no `ExtensionContext`,
no host imports) — that's the tested seam. `src/index.ts` is thin wiring: it maps the model
registry into `ModelSummary`s, calls `resolveModel`, and turns a failure into a thrown `Error`
so the host reports it back to the calling model as a tool error.
