Retry known strict tool capacity rejections once with preferred tools using their original non-strict schemas. Preserve required constraints and payload hooks, and never retry a started stream.
closes#10409
On each OpenRouter refresh, combine the catalog (built-in models plus a newer pi.dev catalog) with GET /models/user for the user's key: keep only the listed chat models and take their context size, max output and prices from it. Image and classifier models are kept. The combined list is saved and replaces the OpenRouter catalog, including offline.
- ai: add personalizeOpenRouterCatalog and RefreshModelsContext.baseUrl, so the request follows a base URL configured in models.json (regional endpoints)
- ai: share OpenRouter price conversion with the generator; negative prices (router models such as openrouter/auto) become 0
- coding-agent: add withPersonalizedCatalog next to withRemoteCatalog
- docs: OpenRouter section in providers.md
fixes#10353
Radius omits providerThinkingLevel from pi-messages done events, so replayed
signed thinking has no effort marker and Anthropic drops it (block_binding
drop_block). Compares follow-up input tokens with and without the thinking
block against an Anthropic control.
Remove hardcoded Opus 5.5, Sonnet 5.5, and Haiku 5.5 fallbacks now that models.dev lists them. Fix the Sonnet 5.5 test to expect the official cache read price of 0.1.
Long Mistral streams (e.g. extended thinking) were aborted once timeoutMs
elapsed, even while data was still arriving. The timeout now covers only
waiting for response headers; body stalls are left to the HTTP client idle
timeout.
fixes#10609
models.dev now lists the input rate as Kimi K3's cache write cost on Moonshot, which does not bill cache writes. Claude Haiku 5.5 uses adaptive thinking, so the metadata test now expects it.
models.dev loaders for opencode, opencode-go, google, minimax, and others built costs by hand and dropped tiers; they now use getModelsDevCost. OpenRouter prompt-length overrides and Vercel AI Gateway per-rate tiers are parsed into request-wide tiers. Rates a tier does not list keep the base price. OpenRouter time-of-day overrides are skipped.
Adds claude-haiku-5-5 to the anthropic provider with its prompt-length pricing tier (5x above 100k input tokens), adaptive thinking with xhigh/max effort, per-message effort, and mid-conversation system messages and tool changes. Bedrock requests detect Haiku 5.5 for adaptive thinking, native xhigh, block binding, and prompt caching.
Mistral reports transient server failures as finish_reason "error". Its
error message now includes "server error" so the retry classifier treats
it as retryable.
closes#10487
Try 53692 first so forwarded setups keep working, then let the OS pick a
free loopback port when 53692 cannot be bound (e.g. Hyper-V/WSL port
exclusions on Windows). The authorize URL, paste prompt and token exchange
use the bound redirect URI.
closes#10571
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.
The faux provider's prompt-cache usage estimate compared the previous and
current prompt as two joined strings, character by character, on every
call. It now compares the prompts message by message and compares
characters only from the first differing message. Usage numbers are
unchanged.
Replaces the WeakMap workaround. streamProxy and the agent and coding-agent test
mocks reimplemented AssistantMessageEventStream as plain EventStream subclasses;
they now use createAssistantMessageEventStream().
The response timing added private fields, which made test and host streams built on
EventStream no longer assignable to StreamFn. Keep the start in a WeakMap instead.
pi-ai's AssistantMessageEventStream sets AssistantMessage.durationMs with a
monotonic clock for every API implementation. The agent loop and the durable
tool task set ToolResultMessage.durationMs around execute(). Durable task
records carry startedAt/endedAt stamped by the Session. The coding agent's bash
renderer shows Took from the recorded duration, also after a reload.
closes#10549
buildAdditionalModelRequestFields only handled Claude, so the configured
thinking level never reached OpenAI models on Bedrock and they always ran at
Bedrock's default effort. gpt-oss now gets the flat reasoning_effort, clamped
to low/medium/high. Other GPT models (GPT-5.x, GPT-6) get nested
reasoning.effort, with minimal sent as low since Bedrock rejects it.
closes#9331
Increase estimated input size to leave more room when calculating
output limits. Verified against OpenRouter DeepSeek V4 Flash: the
same large input now succeeds with an explicit output limit.
Fixes#10497
StreamOptions.headers documents that caller values override provider
defaults, and every other provider applies model/caller headers after its
User-Agent default. The Codex provider set originator and User-Agent after
merging caller headers, so they could not be overridden. Set the defaults
first; Authorization and chatgpt-account-id stay fixed.
Co-authored-by: Lucas Meijer <308974+lucasmeijer@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: David Brailovsky <davidbrai@gmail.com>
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.
Bedrock's HTTP/2 connection can stall until the SDK's 5-minute session
timeout, which fails the request with "The pending stream has been
canceled" (ERR_HTTP2_STREAM_CANCEL). The request was never sent, so it
is safe to retry, but the message was only retried when a DNS cause was
appended.
closes#10379
* feat(ai): support Azure Foundry Chat Completions deployments
The Azure provider only implemented the Responses API, so Foundry
deployments that speak Chat Completions could not be used. On Chat
Completions the deepseek/deepseek-v4-pro model sends `thinking` and
`prompt_cache_key`, both of which Azure rejects with 400.
The provider now dispatches openai-completions alongside
azure-openai-responses. A stream wrapper resolves the Azure endpoint
onto the model first, since the shared openai-completions
implementation reads it off the model.
The request-shape differences are catalog compat rather than api code:
reasoning_effort instead of DeepSeek's thinking field, no prompt cache
parameters, reasoning_content kept on assistant turns so the prefix
Foundry cached stays byte-identical, and effort clamped to the
low/medium/high the deployment accepts.
The provider is renamed from azure-openai-responses to azure, since it
now serves more than the Responses API. The azure-openai-responses api
id is unchanged. Breaking: auth.json and models.json entries keyed on
azure-openai-responses must move to azure, and existing sessions see a
different provider on their next turn.
closes#9645
* feat(ai): apply the Azure deployment name map to Chat Completions
The Responses path already sent the deployment name from
AZURE_OPENAI_DEPLOYMENT_NAME_MAP. The Chat Completions path sent the
catalog model id, so any deployment not named after the model 404'd.
The Azure provider now swaps the deployment name into the request via
onPayload before dispatch, then runs the caller's own onPayload on it.
model.id stays the catalog id. The map helpers move to
azure-openai-config.ts so the provider can share them without
importing the SDK.
* docs(ai,coding-agent): add changelog entries for the Azure provider rename
Breaking: the azure-openai-responses provider is now azure. Users rename
the key in auth.json, models.json, and settings.json; SDK users switch to
getModel("azure", ...) and providers/azure.
Also note Azure Foundry Chat Completions support (DeepSeek V4 Pro).
---------
Co-authored-by: David Brailovsky <davidbrai@gmail.com>
Cancelling a request or model refresh while an OAuth token refresh was in
flight discarded the rotated credential. Providers that rotate refresh tokens
(e.g. Sign in with ChatGPT) had already invalidated the old token, so the next
request failed with refresh_token_invalidated.
The caller's signal now cancels only the wait for the credential lock. Once a
refresh starts, it completes and is persisted, bounded by the refresh timeout.
Request auth and model-list refresh share this path.
Add missing entries for the Together DeepSeek V4 Pro fix and the Nix flake, duplicate user-facing ai and tui changes into coding-agent, and add the New Features section.
Send thinking.block_binding with prefix_mismatch_behavior=drop_block and
the thinking-binding-controls-2026-08-01 beta for Bedrock Claude Opus 4.7+,
Sonnet 5+, and Fable 5, matching the Anthropic provider. Opus 4.6 and
Sonnet 4.6 reject the field, and GovCloud is skipped.
closes#10324
Add a Nix flake that builds Pi from the checkout on aarch64/x86_64 Linux
and macOS. The build is offline: provider model data is hydrated from a
pi.dev model catalog revision pinned in nix/model-catalog.json, and the
runtime dependency tree comes from packages/coding-agent/install-lock with
internal packages built from source.
The Nix workflow keeps the catalog pin current on main, builds release
tags on all systems, and fast-forwards the stable branch to each release
that builds. The release script refreshes the pin before tagging.