feat: rewrite the Command Code provider on pi's native provider API
Replace the previous implementation with one that registers the Provider API catalog through pi's own provider layer instead of shipping a custom transport, cache file, and hand-maintained pricing table. - models: derive the catalog from the published command-code CLI package (context windows, reasoning efforts, image input, output limits, rates) and keep it as the offline baseline; scripts/sync-catalog.mjs regenerates it and supports --check - refresh: use refreshModels plus context.publish so pi persists the live /provider/v1/models listing in models-store.json and restores it offline - auth: /login browser transfer through a localhost callback server with a pasted-key fallback; $COMMAND_CODE_API_KEY, --api-key and auth.json keep working - streaming: pi's native openai-completions and anthropic-messages adapters; the generate-transport fallback and Oh My Pi branches are gone - keep the context-overflow rewrite that enables pi's compaction retry and the /commandcode-quota command - tests: 51 cases under tests/<module>/ covering models, catalog sync, auth, the callback server, overflow handling, quota, and the extension factory Verified against the live API: chat, tool round trip, image input and --thinking max on deepseek/deepseek-v4.1-flash, quota output, and catalog persistence in an interactive session.
This commit is contained in:
@@ -1,218 +1,79 @@
|
||||
# pi-commandcode-provider
|
||||
|
||||
[](https://github.com/patlux/pi-commandcode-provider/actions/workflows/ci.yml)
|
||||
[](https://github.com/patlux/pi-commandcode-provider/actions/workflows/memory-benchmark.yml)
|
||||
Unofficial [Command Code](https://commandcode.ai) provider for [pi](https://github.com/earendil-works/pi),
|
||||
written against pi's current provider API. It registers the Command Code
|
||||
Provider API as the `commandcode` provider and lets pi own authentication,
|
||||
model persistence, and streaming.
|
||||
|
||||
A custom provider for [pi](https://github.com/earendil-works/pi) that connects to the [Command Code](https://commandcode.ai) Provider API.
|
||||
|
||||
> **Disclaimer:** This is an unofficial, community-maintained integration. It is not affiliated with, endorsed by, or supported by Command Code. You need your own Command Code account, API key, and a plan with Provider API access. Command Code's terms, availability, and pricing apply.
|
||||
> Not affiliated with, endorsed by, or supported by Command Code. You need your
|
||||
> own account, API key, and a plan with Provider API access.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
pi install npm:pi-commandcode-provider
|
||||
pi remove npm:pi-commandcode-provider # if the community package is installed
|
||||
pi install /home/cat/pi-commandcode-provider
|
||||
```
|
||||
|
||||
Start or reload pi, then authenticate:
|
||||
Restart pi or run `/reload`, then `/login` → **Command Code** to store the API
|
||||
key (or select the subscription flow for browser login). Pick a model with
|
||||
`/model`.
|
||||
|
||||
```txt
|
||||
/login
|
||||
```
|
||||
## What it registers
|
||||
|
||||
Select **Use a subscription**, then **Command Code**. Choose browser login or paste an API key, then select a model with `/model`.
|
||||
| Piece | Behaviour |
|
||||
| --- | --- |
|
||||
| Provider | `commandcode`, name "Command Code", base URL `https://api.commandcode.ai/provider/v1` |
|
||||
| API | pi's native adapters: `openai-completions` for most models, `anthropic-messages` for `claude-*` |
|
||||
| Auth | `/login` (browser transfer or pasted key), `$COMMAND_CODE_API_KEY`, `--api-key`, `auth.json` |
|
||||
| Catalog | Generated CLI catalog as the offline baseline; pi's catalog refresh replaces it with the live `/provider/v1/models` listing |
|
||||
| Command | `/commandcode-quota` prints credits, plan, usage windows, and the period summary |
|
||||
|
||||
## Oh My Pi
|
||||
Because the model list is registered through pi's own catalog layer, the live
|
||||
listing is cached in `~/.pi/agent/models-store.json` and refreshed by pi itself
|
||||
(interactive startup and the `/model` picker), not by a custom cache file. When
|
||||
the endpoint is unreachable, the persisted catalog stays active; before the
|
||||
first refresh, the generated baseline is used, so `pi --list-models commandcode`
|
||||
works offline.
|
||||
|
||||
Install the same package in [Oh My Pi](https://github.com/can1357/oh-my-pi):
|
||||
### Environment variables
|
||||
|
||||
| Variable | Purpose |
|
||||
| --- | --- |
|
||||
| `COMMAND_CODE_API_KEY` | API key fallback when no credential is stored |
|
||||
| `CMD_ZDR=1` | Send `x-cmd-zdr: 1` (zero data retention); `COMMANDCODE_ZDR=1` still works |
|
||||
| `COMMANDCODE_API_BASE` | Override the Provider API base URL |
|
||||
| `COMMANDCODE_MODELS_URL` | Override the catalog endpoint |
|
||||
| `COMMANDCODE_MODELS_TIMEOUT_MS` | Catalog request timeout (default 10 s) |
|
||||
| `COMMANDCODE_AUTH_TIMEOUT_MS` | Browser login callback timeout (default 120 s) |
|
||||
|
||||
The provider also reads existing keys from `~/.pi/agent/auth.json` and
|
||||
`~/.commandcode/auth.json` for `/commandcode-quota`.
|
||||
|
||||
## Model metadata
|
||||
|
||||
Reasoning support, effort levels, image input, output limits, and prices come
|
||||
from the published `command-code` CLI package, which is the same source the
|
||||
Command Code CLI uses. Regenerate the catalog after a new CLI release:
|
||||
|
||||
```sh
|
||||
omp plugin install pi-commandcode-provider
|
||||
npm run sync:catalog # latest command-code
|
||||
npm run sync:catalog -- --version 1.54.0
|
||||
npm run sync:catalog -- --check # fail when src/catalog.ts is stale
|
||||
```
|
||||
|
||||
Restart OMP or run `/reload`, then use `/login` and select **Use a subscription** followed by **Command Code**.
|
||||
|
||||
## Authentication
|
||||
|
||||
### Login dialog
|
||||
|
||||
Run `/login` in pi or OMP. Select **Use a subscription**, then **Command Code**. Press Enter for browser login, type `key` to open a paste prompt, or paste the API key directly. The selected credential is stored in the host's auth file.
|
||||
|
||||
<img width="1520" height="554" alt="Select Command Code in pi's login dialog" src="https://github.com/user-attachments/assets/071e929a-6f49-4803-bfec-7a31368fb12a" />
|
||||
|
||||
If automatic transfer from the browser fails, copy the API key shown by Command Code and paste it into the terminal prompt.
|
||||
|
||||
On Oh My Pi, `/login` stores those credentials in OMP's credential store and chat uses them directly. If chat still returns `401 Invalid 'Authorization' header`, restart OMP after `/login` and confirm `/commandcode-quota` shows your account.
|
||||
|
||||
### Environment variable
|
||||
|
||||
```sh
|
||||
export COMMAND_CODE_API_KEY="user_..."
|
||||
```
|
||||
|
||||
### Auth file
|
||||
|
||||
The provider also reads existing credentials from:
|
||||
|
||||
- `~/.commandcode/auth.json`
|
||||
- `~/.pi/agent/auth.json`
|
||||
- `~/.omp/agent/auth.json`
|
||||
|
||||
Supported examples:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiKey": "user_..."
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"command-code": {
|
||||
"type": "api",
|
||||
"key": "user_..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"commandcode": "user_..."
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Open `/model` and select one of the models provided by Command Code. Model availability changes over time and is refreshed from the Provider API when the extension loads.
|
||||
|
||||
Other extensions that stream with the active Command Code model, such as background agents or memory workers, use the same connection and the same credentials as the chat, so their requests count against your Command Code usage.
|
||||
|
||||
### Reasoning support
|
||||
|
||||
Reasoning capability and selectable effort levels follow the official CLI catalog independently. Models can therefore be marked as reasoning-capable even when Command Code chooses their depth automatically. Models with explicit effort support register a model-specific `thinkingLevelMap`, so pi and OMP expose only valid levels, including the opt-in `xhigh` and `max` levels. `src/commandcode-catalog-overrides.ts` can add a manual level set for reasoning models that the CLI catalog ships without efforts; it is currently empty because upstream publishes efforts for every selectable model, and the tests fail once upstream publishes levels for a model that still has a manual override. Pi's native OpenAI- and Anthropic-compatible providers translate the selected level for Provider API accounts; the existing Command Code generate transport sends the matching `reasoning_effort` for Go accounts.
|
||||
|
||||
List Command Code models from the terminal:
|
||||
|
||||
```sh
|
||||
pi --list-models commandcode
|
||||
```
|
||||
|
||||
In OMP, use:
|
||||
|
||||
```sh
|
||||
omp models
|
||||
```
|
||||
|
||||
For non-interactive OMP requests, use a provider-qualified model ID shown by `omp models`. For example:
|
||||
|
||||
```sh
|
||||
omp -p "hello" --model commandcode/deepseek/deepseek-v4-flash
|
||||
```
|
||||
|
||||
## Model discovery and offline behavior
|
||||
|
||||
The provider fetches the current model catalog from:
|
||||
|
||||
```txt
|
||||
https://api.commandcode.ai/provider/v1/models
|
||||
```
|
||||
|
||||
The last successful catalog is cached at `<agent-dir>/commandcode-models.json`. For pi this is `~/.pi/agent/commandcode-models.json` by default. Compatible hosts such as OMP use their own agent directory.
|
||||
|
||||
When a valid cache exists, the provider registers the cached catalog immediately and refreshes it from the endpoint in the background, so startup does not wait for the network. The refreshed catalog replaces the cached one as soon as it arrives; `/commandcode-status` reports `source: cache` until then. If the endpoint is temporarily unavailable, the cached catalog stays active. On a first start without a cache, the provider waits for the live catalog; if that fails offline, pi still loads, but Command Code models remain unavailable until the connection is restored and `/commandcode-refresh` succeeds.
|
||||
|
||||
While pi is running, use these provider commands without restarting:
|
||||
|
||||
- `/commandcode-refresh` fetches and re-registers the current model catalog. Overlapping refreshes are coalesced, and a failed refresh keeps the last valid catalog active.
|
||||
- `/commandcode-status` shows redacted discovery diagnostics, including the source, model count, timestamps, cache path, endpoint, and warning.
|
||||
- `/commandcode-quota` shows your Command Code account usage and quota in a dashboard-style layout: credits remaining and used with a percentage, monthly/purchased/free sources, the current plan, available usage totals, the API key name, and the 5-hour and weekly usage windows.
|
||||
|
||||
The `commandcode-quota` command reads from the Command Code alpha usage endpoints (the same ones the `cmd` CLI `/usage` command uses): `whoami`, `billing/credits`, `billing/subscriptions`, and `usage/summary`. It authenticates with the same API key the provider already uses. If the command cannot reach those endpoints or an endpoint schema changes, unavailable sections are reported explicitly instead of being displayed as zero usage. Output is plain text (via `ui.notify`) so it works across pi and compatible hosts such as OMP.
|
||||
|
||||
Set `CMD_ZDR=1` to send Command Code's documented `x-cmd-zdr: 1` zero-data-retention header. The legacy `COMMANDCODE_ZDR=1` alias remains supported.
|
||||
|
||||
The following environment variables are intended for tests, local mocks, and compatible API endpoints:
|
||||
|
||||
- `COMMANDCODE_API_BASE`
|
||||
- `COMMANDCODE_MODELS_URL`
|
||||
- `COMMANDCODE_MODELS_CACHE`
|
||||
- `COMMANDCODE_MODELS_TIMEOUT_MS` (defaults to 10 seconds; invalid or non-positive values use the default)
|
||||
|
||||
## Image input
|
||||
|
||||
The provider advertises image input only for models marked with the `image` input modality in the official Command Code CLI model catalog. The capability snapshot currently follows `command-code@1.53.1`; unknown models default to text-only until their upstream metadata is reviewed. A daily GitHub Actions job synchronizes the CLI version, image capabilities, reasoning flags, reasoning efforts, and model-specific output limits with the latest published CLI package and opens or updates a reviewable pull request when they change. Pricing remains manually reviewed because temporary promotions and long-context tiers require explicit review.
|
||||
|
||||
For vision-capable models, Pi's native provider adapters forward image blocks from user messages and tool results using the documented OpenAI or Anthropic message schema. Unknown and text-only models remain marked text-only in Pi.
|
||||
|
||||
## Pricing display
|
||||
|
||||
The Command Code Provider API does not currently include prices in its model catalog. This extension therefore keeps a static table for models with known prices so pi can display estimated request costs. DeepSeek V4 uses time-dependent rates; pi displays the documented off-peak rate, which applies for 17 hours per day.
|
||||
|
||||
Models missing from that table display zero cost in pi. This does **not** mean that Command Code will bill the request at zero. The Command Code Usage page remains authoritative for each request. Check the current [Command Code pricing](https://commandcode.ai/docs/resources/pricing-limits) before relying on the displayed value.
|
||||
|
||||
## Update and remove
|
||||
|
||||
Update installed pi packages:
|
||||
|
||||
```sh
|
||||
pi update --extensions
|
||||
```
|
||||
|
||||
Remove the provider:
|
||||
|
||||
```sh
|
||||
pi remove npm:pi-commandcode-provider
|
||||
```
|
||||
|
||||
For OMP:
|
||||
|
||||
```sh
|
||||
omp plugin upgrade pi-commandcode-provider
|
||||
omp plugin uninstall pi-commandcode-provider
|
||||
```
|
||||
Prices are display-only estimates; the Command Code usage page remains
|
||||
authoritative.
|
||||
|
||||
## Development
|
||||
|
||||
Start an isolated pi instance with only the current checkout installed and no existing Command Code credentials:
|
||||
|
||||
```sh
|
||||
npm run pi:isolated
|
||||
npm install
|
||||
npm test # unit + extension tests, no network
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
Run `/login` inside pi. Temporary credentials, configuration, and sessions are deleted when pi exits.
|
||||
|
||||
Start the current checkout with your existing pi credentials and only Command Code models in the model picker:
|
||||
|
||||
```sh
|
||||
npm run pi:authenticated
|
||||
```
|
||||
|
||||
Both commands accept additional pi arguments after `--`, for example `npm run pi:authenticated -- --model claude-sonnet-4-6`.
|
||||
|
||||
### Live transport tests
|
||||
|
||||
Keep Go-, GOAT-, and optional Provider-plan test keys in separate secret-manager entries. Pass them through protected files so the keys do not enter shell history:
|
||||
|
||||
```sh
|
||||
COMMANDCODE_E2E_GO_API_KEY_FILE=/path/to/go-key \
|
||||
npm run test:e2e:live:go
|
||||
|
||||
COMMANDCODE_E2E_GOAT_API_KEY_FILE=/path/to/goat-key \
|
||||
npm run test:e2e:live:goat
|
||||
|
||||
COMMANDCODE_E2E_PROVIDER_API_KEY_FILE=/path/to/provider-key \
|
||||
npm run test:e2e:live:provider
|
||||
|
||||
COMMANDCODE_E2E_GO_API_KEY_FILE=/path/to/go-key \
|
||||
COMMANDCODE_E2E_GOAT_API_KEY_FILE=/path/to/goat-key \
|
||||
npm run test:e2e:live:all
|
||||
```
|
||||
|
||||
Each profile runs with an isolated Pi agent directory and asserts transport selection, reasoning across turns, quota plan identity, abort handling, tool calls, and the packed npm artifact. Go must select `generate` and reject unsupported images; GOAT must select `provider` and complete a live vision request. The profile-specific `*_API_KEY` environment variables are also supported for CI secrets, but key files are preferred for local use.
|
||||
|
||||
The Go profile defaults to DeepSeek V4 Flash; GOAT defaults to Grok 4.6 because its Provider API stream exposes reasoning consistently across consecutive turns. Override them with `COMMANDCODE_E2E_GO_MODEL`, `COMMANDCODE_E2E_GOAT_MODEL`, or `COMMANDCODE_E2E_PROVIDER_MODEL`. The GOAT vision phase defaults to GPT-5.6 Luna and can be overridden with `COMMANDCODE_E2E_GOAT_VISION_MODEL`. A successful live Anthropic `/provider/v1/messages` test requires a paid account whose plan includes the selected Claude model.
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and tests. See [RELEASE.md](RELEASE.md) for the release process.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Tests live in `tests/<module>/` next to the module they cover and call the real
|
||||
production code. `tests/extension/provider.test.ts` drives the extension factory
|
||||
with a stub `ExtensionAPI` and a local catalog server; no Command Code
|
||||
credentials are required.
|
||||
|
||||
Reference in New Issue
Block a user