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.
Oh My Pi kept the unresolved $COMMAND_CODE_API_KEY placeholder as a literal config API key that shadowed its /login credential store and was sent as the Bearer token (401). The placeholder is now registered only on pi, where it keeps the API-key auth method and --api-key working next to OAuth; on OMP the provider omits apiKey unless a real key is configured. Host-supplied placeholders are resolved or stripped on every stream path, and the legacy generate transport uses the same rule.
Stored /login OAuth and API-key credentials, --api-key, and env keys are now covered end to end on both pi and Oh My Pi, and CI runs the pi suite against a real binary.
Co-authored-by: ebreen <ebreen@users.noreply.github.com>
0.6.1 imported registerApiProvider from @earendil-works/pi-ai/compat as
a named import. Oh My Pi maps that specifier onto its own pi-ai, which
has no such export and instead registers custom APIs inside
registerProvider, so omp plugin install rejected the extension with
"Export named 'registerApiProvider' not found".
Import the compat module as a namespace and call registerApiProvider
only when the host provides it. pi keeps the sibling-extension fix from
#68; omp loads again and its own custom-api registry covers that case.
Verified with omp 18.1.2: plugin install of the linked checkout succeeds
and tests/test-omp-compat.mjs passes; tests/test-pi-local.mjs still
covers the compat registry path on pi.
Closes#74
Every host start awaited a full catalog request before the provider
registered, costing one HTTPS round-trip (up to the discovery timeout on a
hanging connection) even when a cache written seconds earlier was on disk.
Register the cached catalog immediately and run the live refresh in the
background; the live result re-registers the provider when it arrives. A
first start without a cache still awaits the live catalog. The background
refresh is aborted on session_shutdown so print mode does not wait for it.
Closes#63
(cherry picked from commit 142191f9420fe90460cdc3cbae70e26d0c000860)
pi routes the main chat through the registered provider, but sibling
extensions that call streamSimple from @earendil-works/pi-ai/compat with
the active Command Code model resolve model.api through the compat
api-registry, which only knows built-in APIs. On plain pi that failed
with "No API provider registered for api: commandcode-custom".
Register commandcode-custom there and delegate to the transport router.
The registry resolves no credentials for extension providers, so fall
back to the configured Command Code key when the caller passes none.
Closes#68
(cherry picked from commit 7e9659e672771c6a9223b95938e50fb2a051a0a7)
Fetches live account quota from Command Code alpha usage endpoints
(whoami, billing/credits, billing/subscriptions, usage/summary) and
renders a plain-text dashboard via ui.notify.
- Graceful degradation: optional endpoint transport/timeout/parse
failures degrade to null sections instead of aborting; only 401/403
are hard failures. 429 is transient, not fatal.
- Overall deadline bounds the whole command to QUOTA_TIMEOUT_MS
(per-request controllers are chained; post-deadline phases fail fast).
- OMP auth: filter unresolved $COMMANDCODE_API_KEY placeholder and fall
back to the host resolver via pickCommandCodeApiKey.
- ZDR privacy header respected on quota requests.
- Redaction reuses redactCommandCodeErrorText plus JSON-quoted
credential fields; outer-catch errors are redacted too.
- resetAt parsed from seconds, ms, numeric string, or ISO string.
- 21 hermetic unit tests wired into npm test (test:quota).
omp 17.4.0's host registry rejects registerCustomApi calls under
built-in api names ("Cannot register custom API '<name>': built-in
API names are reserved"). The provider and its models registered
under "openai-completions", so the extension failed to load.
Register under "commandcode-custom" instead (matches the published
npm build) and restore the real wire api via apiForModelId before
dispatching to the native compat stream inside the transport router.
The host's model registry also stores provider-supplied compat under
model.compatConfig internally, only copying it back to model.compat
inside its own dispatch-time patches. Since the transport router calls
the native compat stream directly, it must read compatConfig itself or
requests crash with 'baseCompat is undefined' before any network call.
Verified against a local mock Provider API server with the extension
linked into omp 17.4.0: model discovery lists all Command Code models,
and a streamed chat completion sends the resolved x-cmd-zdr header and
Authorization header end to end.
Resolve the Command Code model cache through the host's getAgentDir helper so pi, OMP, and PI_CODING_AGENT_DIR use their own agent state directory instead of the official Command Code client directory.
Persist the last valid Command Code model catalog and use it when live model discovery fails. Keep first-time offline startup non-fatal, surface clear warnings, and cover cached model selection with unit and pi integration regression tests.
The model fetch at startup throws and blocks pi from starting when
there's no network. Catch the error and register the provider with
an empty model list instead.
Use the explicit $COMMANDCODE_API_KEY environment variable reference expected by newer pi versions while keeping compatibility with the legacy placeholder handling.
DeepSeek V4 Flash cache-read rate was /bin/bash.01/1M but docs list ~/bin/bash.028.
Added xiaomi/mimo-v2.5-pro and xiaomi/mimo-v2.5 to MODEL_COSTS so they
don't display as zero-cost models (pricing TBD, currently set to 0).
- Removed unnecessary blank lines and improved formatting for better readability in index.ts and converters.ts.
- Updated package-lock.json to downgrade several dependencies for compatibility, including @protobufjs/eventemitter, @protobufjs/fetch, and others.
- Enhanced error message in core.ts to clarify configuration options for the Command Code API key.
- Added a test to ensure the correct handling of environment variable values in test-stream.ts.
Support OMP as a host alongside pi:
- Convert OMP's array-format system prompts to string via systemPromptToText
- Guard against OMP passing the literal env-var name as the API key value
- Add ~/.omp/agent/auth.json to default auth path lookup
- Fix --list-models output to check both stdout and stderr
- Add OMP compatibility smoke test with isolated temp HOME and mock server
- Deduplicate usage section in README, add OMP install and usage docs
pi 0.75.5 renamed the npm namespace from @mariozechner/ to @earendil-works/.
Importing from the old namespace causes 'fetch failed' errors at startup.
Changes:
- index.ts: @mariozechner/pi-ai → @earendil-works/pi-ai
- index.ts: @mariozechner/pi-coding-agent → @earendil-works/pi-coding-agent
- package.json: bump deps from 0.72.0 to 0.75.5
- package-lock.json: regenerated with new packages (242 deps)
- tsc --noEmit: zero errors
The Provider API does not expose pricing yet. Overlay a static MODEL_COSTS
map on top of the dynamically fetched model list so pi can display per-model
costs. Models not in the table fall back to zero cost. When the Provider API
adds a cost field, the static table can be removed.
- Add scripts/extract-models.ts to parse command-code npm dist file
- Generate models.json (21 models, 15 pricing entries) with contextWindow
and maxOutputTokens pre-filled; no nulls or hardcoded fallbacks in index.ts
- Rewrite index.ts to load model list and costs from models.json
- Cap gateway model maxOutputTokens at 65536 (API limit for Baseten/Vercel)
- Add 'Update models' section to README documenting the generation flow
- Add npm run extract-models script