This builds the model catalog from per-provider definitions and
models.dev v2 data.
It eplacer `generate-models.ts` with one `defineProvider()` file per
built-in provider, shared model-family rules (Claude, GPT, DeepSeek,
Kimi, Google), and source adapters. models.dev is read through its v2
API. Outputs and CLI flags are unchanged.
Fix docs and `--help` drift: update the provider checklist to the
`src/api` layout, fix broken MCP anchors, and document `/mcp`, `pi mcp
add|remove`, `PI_CLEAR_ON_SHRINK`, and `"disabled"` timeouts.
closes#11243
Use authoritative OpenRouter billing for Chat Completions and Anthropic Messages while retaining catalog component estimates and fallback behavior.
Fixes#9980
Add Usage.cost.totalFromProvider to record whether cost.total is the
billed cost reported by the provider or an estimate from catalog rates.
Catalog-derived totals set it to false; a missing value also means
false. combineUsage marks a sum as provider-reported only when both
parts are.
Jev (TypeSafe, Workers AI), Clef (Workers AI), and OpenRouter decision
models now accept ClassifierContext.images. Each service takes its own
wire form: TypeSafe assets with the opt-in header, Clef images data URLs,
or OpenRouter image_url parts in the state. A new SystemOneCompat
(imageInput, sendImageOptInHeader) selects the form; catalog entries set
it explicitly and models.json provider compat now applies to classifiers.
Adds Clef Omni and Jev 1.14 on Workers AI and fixes Clef Flash and
Workers AI Jev catalog pricing.
- ClientAttribution is { name, url, categories? } with required name and url, so
OpenRouter always gets an HTTP-Referer. identity.ts maps the fields to each
provider's headers; NVIDIA gets the name with its first letter upper-cased.
attribution: null turns it off. PI_ATTRIBUTION is pi's, including the
cli-agent category; agent-core, durable, and the coding agent use it.
- Categories are a string array, joined for OpenRouter.
- withClientIdentity() is a typed wrapper instead of a Proxy and keeps a
MutableModels mutable. Durable no longer caches wrappers in a WeakMap.
- The Codex originator stays pi; login agentName no longer follows attribution.
- Models and the coding agent's ModelRuntime add x-opencode-session for custom
providers pointing at OpenCode, replacing the coding agent's transformHeaders.
pi-ai gets a ClientIdentity request option and createModels() default that choose the User-Agent (detailed with version, short, or custom) and provider attribution headers for OpenRouter, NVIDIA NIM, and OpenCode. Attribution is off by default in pi-ai and on by default in pi-agent-core and pi-durable (HarnessOptions.identity). pi-coding-agent sets its identity from the telemetry setting instead of adding headers itself.
Models with additional_tools declare every tool in additional_tools items, starting with one at the head of the input, like Codex. A later item replaces same-name definitions from earlier items but cannot replace a top-level tool or remove a tool, so removals are announced as text and later updates restate the tools that are still unavailable.
Tool search and Kimi tool messages move the top-level tool list once per removal or redeclared name and keep later loads anchored, instead of resending the current tool list on every load after the first removal.
fixes#10940
- pi-ai: AI_TELEMETRY_SCHEMA; pi.ai.request and pi.ai.poll spans around Models requests via a lazyStream observer
(no provider changes), first_chunk and block events (never per delta), usage/cost end attributes, provider_error
status with a bounded message, aborted stays ok; duration, first-chunk, token and cost metrics; option renamed
telemetryContext -> telemetry (a parent span)
- pi-telemetry: TelemetryContext carries readonly metrics and propagation capabilities on every span
- chord/context: Context.telemetry is always a TelemetrySpan (NOOP default); withTelemetry takes spans
- durable: DURABLE_TELEMETRY_SCHEMA; pi.durable.submit (inputs start their own trace linked to the caller) and
pi.durable.phase spans for every task phase; stored carriers on submissions and tasks (TaskOptions.trace, links);
entry, submission, checkpoint, replay and report events after commit; resumed tasks stay in their trace; phase
duration, active task and report metrics; failed phases carry fixed categories with bounded messages
When switching models, thinking blocks from earlier assistant messages
produced by a different model were sent as plain text. The new model saw
the old model's reasoning as part of its replies and could start writing
its own reasoning into the visible answer. These blocks are now dropped;
text and tool calls are kept.
closes#10995
Adds the openai-decisions classifier API with gpt-6-luna on the openai provider. bool questions map to predicates with the criteria in the instructions, refusals fail the result, and gateway timeouts (504) are not retried. The model needs an API key and is hidden from availability while openai uses Sign in with ChatGPT.
Adds optional images to ClassifierContext. Models without image input and APIs that cannot send images return an error result. Codemode's models.classify() accepts images.
Moves the shared classifier HTTP code out of system-one-shared.ts into classifier-shared.ts.
This adds llama.cpp support for classifiers. Classifier models (Julia-1, Laya, Kev, lev, OpenJev) are listed as typesafe-system-one classifiers instead of chat models; other models keep the llama-cpp-classify fallback. Only 501 and 404 mark a model as chat, and classifier models restored from the model store are checked again once loaded.
Switch native Anthropic tool changes to the inline-tools-2026-09-15 beta. Later tools are defined by value in tool_addition blocks, so the top-level tool list stays fixed and same-name redefinitions no longer fall back to resending the full tool list. The deferred placeholder is kept.
Upgrade @anthropic-ai/sdk to 0.129.0 and deprecate hasToolRedefinitions().
Durable generation imports retry helpers from pi-ai/utils/retry; examples use
pi-ai/models and pi-ai/providers/faux. Entry graph budgets and an import
footprint test guard the models entry.
System One services (TypeSafe, OpenRouter, OpenCode Zen, Cloudflare Workers AI) return usage.input_tokens/output_tokens. ClassifierResult now carries usage priced from the model catalog like chat usage.
Vercel evaluation models are generated from the AI Gateway catalog and
routed through its TypeSafe-compatible /typesafe/v1/systemone endpoint.
OpenCode Zen's jev-1.13 and jev-1.13-free are routed through
/zen/v1/systemone.
Add the llama-cpp-classify classifier API. Each question becomes one chat prompt with single-token answer labels; llama-server's pre-sampling next-token log-probabilities give the softmax over those labels. Missing labels are retried with deeper readouts and then reported as errors.
OpenRouter decision models use its TypeSafe-compatible /api/v1/systemone endpoint. Cloudflare Workers AI gets a cloudflare-workers-ai-system-one classifier API for the /ai/run envelope. Request and answer parsing is shared in system-one-shared.ts.
Device authorization flow against auth.meta.com mints a Model API key via the Muse Code key-mint endpoint. Identity token stored as refresh, minted key as access; daily re-mint via the standard OAuth scheduler. Identity is non-renewable (no refresh grant), so mint 401/403 directs to /login meta. Models sourced from models.dev; default muse-spark-1.3.
Remove SystemMessage.replace. A prompt forced from before_agent_start is a rendering
of the current prompt for the run, not conversation state: persisting it as a
replacing system message wrote the full prompt and tool list on every change,
lost the structured sections while forced, and disabled mid-conversation system
messages for the rest of the session once a replacement existed.
The transcript now always records section patches. AgentSession wraps
transformContext and, when a forced prompt is active, collapses the system
messages into one head carrying the forced text and the current tools. Providers
receive the same request as before; nothing is persisted and the projection ends
with the run.
The evals harness validated the without_docs variant from the transcript, which
relied on the persisted replacement. Its transform extension now records the
prompt it forced and validates that instead.
Add SystemMessage.replace: replaying a system message with the flag discards the
accumulated prompt content, sections, and tools before applying it, and providers
collapse the transcript into one leading system message whenever a later message
replaces it.
A forced prompt from before_agent_start is opaque, so it is persisted as a replace
message holding the text in content with no sections (the agent loop fills in the
full tool set). Leaving force mode persists another replace message with the
structured sections. Previously the forced prompt became a preamble section patch,
so models with native mid-conversation system messages kept the original prompt
as their leading system prompt and received the forced one as a later update.
This change makes system prompt text and tool changes part of the transcript rather than silently rewriting its starting conditions. This lets Pi record when instructions changed or tools became available, restore that state after resuming or navigating branches, and preserve cached prompt prefixes where the upstream supports it.
Send x-session-id for OpenRouter Chat Completions and Anthropic Messages requests while preserving explicit opt-out and cache-disabled behavior.
closes#9102
#7638 hardcoded vLLM's thinking_token_budget. Map thinkingBudgets through
thinkingTokenBudgetField, keep the boolean as a vLLM alias, clamp so the
answer keeps 1024 tokens, and document it.
fixes#8274
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
* feat(ai): route xAI models through Responses and default to Grok 4.6
Send built-in xAI catalog models through the Responses API with
store: false and include reasoning.encrypted_content so encrypted
reasoning is requested and replayed, including future models.dev
additions. Thinking levels come from models.dev reasoning_options
(grok-4.6 exposes xhigh); models without verified options
(grok-build-0.1) keep reasoning always on and never send unsupported
"none"/"minimal" efforts. Narrow the xAI provider to the Responses API,
send pi's runtime User-Agent on xAI requests for provider-side
attribution, and make Grok 4.6 the default xAI model.
* fix(ai): drop duplicate xAI encrypted-reasoning tests
Azure already covers the shared replay path; keep the xAI-specific include-without-effort case next to the existing request tests.
---------
Co-authored-by: Jaaneek <Jaaneek@users.noreply.github.com>
Add the constrained sampling API and provider plumbing for OpenAI and Anthropic tool calls, including grammar sampling variants and model capability metadata.
Add Alibaba Cloud Model Studio Token Plan subscription service as two
built-in API-key providers: qwen-token-plan (international, Singapore)
and qwen-token-plan-cn (China, Beijing).
Each provider exposes 15 text-generation models (Qwen, DeepSeek, GLM,
Kimi, MiniMax) via the OpenAI-compatible endpoint with DashScope
enable_thinking support. Model metadata is sourced from models.dev;
qwen3.8-max-preview is hardcoded until models.dev includes it.
Also fixes kimi-coding test references (k2p7 -> kimi-for-coding) after
models.dev catalog update picked up by generate-models.
Closes#6850