Changelog

This changelog covers public developer-docs and API-contract changes.

On this page 1 of 28

Entries summarize customer-visible documentation and compatibility updates for the paid beta public API. Private operational and deployment notes stay out of the public changelog.

2026-09-25#

  • When a platform dependency is temporarily unavailable, the 503 provider_unavailable response now advertises a retry horizon between 5 and 15 seconds in Retry-After, retry-after-ms, and the stream frame's retry_after_seconds, instead of one second. The value varies per request so clients refused together do not retry together. A stream that fails mid-response for the same reason now ends with the same provider_unavailable frame instead of internal_error.
  • Every other retriable response that carries Retry-After now advertises a horizon that varies per request, so clients refused together do not retry together. The value is the previous horizon lengthened by up to a quarter, and by at most 30 seconds; it is never shorter than before, and a horizon of 60 seconds or less stays at or below 60 seconds so the OpenAI and Anthropic SDKs keep honoring it. retry-after-ms, error.details.retry_after_seconds, and the stream frame's retry_after_seconds carry the same per-request value. Retry-After rounds it up to a whole second, so a response that sent Retry-After: 1 now almost always sends 2; read retry-after-ms for the spread. A 503 raised by a platform lookup outage now carries retry-after-ms alongside Retry-After, and a 503 for a request that timed out waiting for routing capacity advertises at least the time it already waited instead of one second. See Retry-After.
  • eb1-frontier-preview now reports a context_window (and max_input_tokens) of 869811 in /v1/models, up from 400000, and accepts prompts up to that size on every request: a prompt too long for the model the router would otherwise pick is now served by a model that holds it, instead of being refused. The other public eb1 models stay at 400000. The figure is a floor the API honors whatever max_output_tokens you set, and a prompt past it returns context_length_exceeded with the limit. Requests remain subject to the organization's per-minute token budget (request_exceeds_capacity). Existing Codex, OpenCode, and Pi setups pick up the new window on their next setup run; Claude Code sessions keep the default model's 400000 window.

2026-09-10#

  • Reasoning tokens on eb1 models are now itemized inside the output count on every surface: output_tokens / completion_tokens is the delivered text plus the reasoning tokens, total_tokens is input plus output, and the reasoning share appears in output_tokens_details.reasoning_tokens (Responses) and completion_tokens_details.reasoning_tokens (Chat Completions); on Messages it is inside output_tokens as on Anthropic's own API. The reasoning count is the serving model's own report and is no longer clamped to the length of the reply, so the four counts on a record multiply by the rate card to exactly the amount billed. See "Reasoning tokens" under Token counting on the usage and billing page.

2026-09-09#

  • A request whose body does not arrive in full within 60 seconds of the gateway starting to read it is now refused with 408 and the new error code request_body_timeout. The error is retriable, and the OpenAI and Anthropic SDKs retry a 408 by default. Before this change a stalled upload held its connection open until the server restarted.

2026-09-07#

  • Token counts on every eb1 model are now reported and billed in one unit, the o200k_base meter, independent of which model served the request. The same request body yields the same prompt_tokens / input_tokens on every call, completion_tokens / output_tokens is the meter count of the delivered output, and total_tokens is their sum. Cache-read and cache-write counts are reported as proportional subsets of the metered prompt. The 400,000-token input window, /v1/messages/count_tokens, and rate-limit token accounting use the same unit. Counts you can reproduce locally with tiktoken's o200k_base encoding.
  • Follow-up corrections to the meter: image and file requests now report the same prompt count that is billed (the per-part media minimum), tool results sent as content-part lists and custom tool outputs are counted, and a safety refusal the gateway authors carries zero usage on streams as it already did on synchronous requests.
  • POST /v1/messages/count_tokens now counts an accepted body exactly as the request would be billed, tool definitions and tool history included; a body the Messages endpoint would reject still receives an advisory estimate.
  • A streamed request that ends early after delivering output (client disconnect or provider error) is billed for the delivered output and its prompt, in meter units, whether or not the provider reported usage; a stream that delivered nothing is not billed.

2026-09-06#

  • Content-limit refusals now return 400 invalid_request_error with media-removal or compaction wording recognized by Claude Code. Image, PDF, replay-byte, and content-node limits are unchanged; depth-only errors remain count-free.
  • A request that reaches the platform while an internal service is restarting now completes on a live instance of that service when one is reachable within the request's retry budget. When several instances are down at once and none of them has yet been re-probed, the retries can still all land on down instances and the request fails. When no instance can take the request, the response is 503 server_error with the new code route_unavailable, a retriable condition carrying a Retry-After horizon and the message "A platform service is restarting. Retry the request shortly." These failures previously surfaced as 503 provider_unavailable with "Capacity is temporarily limited", wrongly implying an upstream dependency and a capacity condition; no upstream is involved and an unchanged retry succeeds once the restart completes. provider_unavailable remains reserved for genuine upstream unavailability.
  • The 400,000-token eb1 input window uses unpadded cl100k prompt counts, including tool definitions and replay estimates. Gateway context-overflow errors now report their input count and binding limit in that same unit, so clients can compact and retry using consistent counts. Messages keeps the native prompt is too long: N tokens > M maximum grammar; provider rejections retain the provider's own counts.

2026-09-04#

  • Function tools declared with strict: true now reach Claude-served legs with strict: true, so the served model's tool-call arguments are validated against your schema there just as they already were on OpenAI-served legs; previously the flag was dropped on Claude legs without notice. This applies on /v1/responses, /v1/chat/completions, and /v1/messages alike, and to the custom + input_schema tool spelling. Claude requires a strict schema to set additionalProperties: false and to list every property under required; a strict declaration whose schema does not meet that now returns 400 from a Claude-served leg instead of running without the guarantee. Tool declarations lead the prompt-cache prefix, so the first strict request after this change writes a new cache entry on Claude legs.

2026-09-03#

  • Replayed tool history is validated once per request before any model is called. A duplicated call_id, a result for an unknown call, a second result for the same call, or a call left unanswered before the next user turn now returns 400 with code conversation_invariant and the offending call_id, on /v1/responses, /v1/chat/completions, and /v1/messages alike, instead of a provider-specific error from whichever model was routed.
  • Streaming requests that replay function-call history are now served by Gemini-backed routes as well; they previously routed around Gemini. parallel_tool_calls: false routes around Gemini instead, since Gemini has no single-call mode.
  • Tool names longer than 64 characters or using characters outside [A-Za-z0-9_.:-] (long MCP names, for example) now work on Gemini-backed routes; the model sees a stable alias and every emitted call carries the name you declared.
  • Freeform apply_patch calls served through the compatibility path now carry the same call_eba1_… identity every other tool call carries. Ids issued under the earlier call_eb2.… format keep working for one release.

2026-09-02#

  • previous_response_id is now honored on /v1/responses for every eb1 model. Each response is retained for 24 hours, scoped to your organization, unless the request set store: false; a follow-up request that names the id continues the conversation without resending earlier turns. An unknown or expired id returns 400 with code previous_response_not_found, matching the OpenAI contract. Responses larger than 1 MiB are served normally but not retained for continuation.
  • /v1/messages now forwards output_config.effort and thinking: {"type": "adaptive"} as reasoning effort to the served model instead of dropping them; effort above a model's ceiling is lowered to that ceiling.
  • /v1/responses accepts tool_choice: {"type": "allowed_tools"}, assistant refusal content on replayed turns, array-valued custom_tool_call_output, and input_image.detail: "original". item_reference items and conversation return a 400 naming the parameter.
  • Tool-call identities are now gateway-issued on every surface. A Responses call_id, a Chat Completions tool_calls[].id, and a Messages tool_use.id for the same call all render as the same call_eba1_… alias; hosted web-search correlation ids render as hist_eba1_… and output item ids as item_eba1_…. Replay them verbatim in continuation turns exactly as before; ids issued by earlier responses keep working. Provider-private continuation fields (such as thought_signature) no longer appear in customer payloads; the gateway carries them across turns for you.
  • /v1/messages now serves Anthropic-native web search with both current spellings, web_search_20250305 and web_search_20260209, on every eb1 model; the search runs on the served Claude leg and its server_tool_use and web_search_tool_result blocks come back in place. Previously the native declaration was refused.
  • Anthropic's client-executed agent tools (bash_20250124, the text_editor_* versions, and memory_20250818) are accepted on /v1/messages and served natively when the route lands on Claude; the model's version support still applies. Previously these declarations were refused as unknown tools.

2026-08-27#

  • eb1-fast-preview now reports a context_window (and max_input_tokens) of 400000 in /v1/models, up from 240000. A routing refresh raised the largest window reachable by fast-tier requests, and the published figure tracks the enforced serving bound (capped at the product-wide 400000 ceiling shared by every eb1 model). As before, the figure is a floor the API honors on every request. Existing Codex setups pick up the new window on their next setup run.

2026-08-21#

  • A platform-internal admission refusal that previously surfaced as 500 internal_error now returns 503 server_error with code route_capacity and a Retry-After horizon, the same retriable contract introduced on 2026-08-05. No upstream is involved and an unchanged retry usually succeeds immediately; clients that already honor route_capacity need no changes.

2026-08-20#

  • The Codex model catalog written by the Keiro installer now declares the one reasoning level eb1 models accept. In stock Codex, choosing a model from /model previously applied the change but left the picker on screen until Esc; the picker now closes on selection. Existing installations pick this up by rerunning the installer, which rewrites ~/.codex/keiro.json in place. See Use eb1 with Codex.

2026-08-10#

  • New setup guides for two additional coding agents: OpenCode registers Keiro as an OpenAI-compatible provider in opencode.json, and Pi adds a Keiro provider entry to ~/.pi/agent/models.json. Both pages appear in the Build navigation alongside the existing Codex, Claude Code, and Omnigent guides.

2026-08-08#

  • /v1/messages usage adopts Anthropic's native disjoint input-side semantics for all callers, effective with the next deployment: input_tokens excludes the cached portions of the prompt, and input_tokens + cache_read_input_tokens + cache_creation_input_tokens equals the full prompt. The previous additive-subset shape — the full inclusive count in input_tokens with the cache fields as subsets of it — is retired. Clients that read input_tokens as the inclusive total should sum the three input-side fields to recover it; responses with zero cache activity are unchanged. See Messages.
  • Prompt tokens served from a prompt cache now bill at 0.1x the model's input rate on every public model. Cache writes carry no surcharge and bill at the standard input rate. The usage fields that report cached prompt portions are unchanged; only the billed amount drops. See Usage and billing.

2026-08-05#

  • Requests refused by a platform-internal capacity gate now return 503 server_error with the new code route_capacity, a retriable condition carrying a Retry-After horizon. These refusals previously surfaced as 502 upstream_server_error, wrongly implying an upstream dependency; no upstream is involved and an unchanged retry usually succeeds within seconds. provider_unavailable remains reserved for genuine upstream unavailability.

2026-08-02#

  • eb1-preview and eb1-efficient-preview now report a context_window (and max_input_tokens) of 400000 in /v1/models, up from 120000; eb1-fast-preview reports 240000. The previous figures were aggregated over the smallest reachable execution target, which is only correct for fixed ensembles; routed requests are admitted whenever any evaluated target fits, so the published number understated the window the API was already serving. The published figure remains a floor the API honors on every request; eb1-frontier-preview is unchanged at 400000. Existing Codex setups pick up the new windows on their next setup run.
  • Context-overflow errors now report the enforced bound. The M in prompt is too long: {N} tokens > {M} maximum (and details.context_window) is the largest limit the rejected request was actually evaluated against, in the same units as {N}, rather than the requested model's published window; {N} > {M} holds on every such error, so clients that trim by the reported gap now trim the right amount.

2026-07-29#

  • Model IDs the API does not offer now return a uniform 404 model_not_found that names the public IDs, with 403 model_not_available reserved for public models your plan does not include. Previously some unknown IDs surfaced as availability errors.
  • Streamed Messages responses carry thinking summary blocks, delivered through thinking_delta events, when extended thinking is enabled. These blocks contain summary text constructed by the API and are unsigned; do not round-trip them as provider-signed thinking blocks.
  • POST /v1/messages/count_tokens now applies the same per-part minimums to image and document blocks that admission and billing apply, so multimodal estimates rise to match what is charged.
  • Validation errors on /v1/messages now name fields in Messages coordinates (messages[i].content[j]) instead of the Responses spelling.
  • /v1/messages error bodies now carry error.request_id, matching the X-Request-Id header, completing the 2026-07-15 error-identification contract on the Messages surface.
  • The Claude Code installer verifies the key with one authenticated request before storing it, reports incomplete setups honestly, and gains an uninstall command.
  • eb1-frontier-preview now reports a context_window of 400000 in /v1/models, up from 128000. The raised figure remains a floor the API honors on every request: admission continues to validate against every execution target with the same safety margins as before. The 120000 windows on eb1-preview, eb1-fast-preview, and eb1-efficient-preview are unchanged, as are the legacy request identifiers accepted for compatibility. Requests remain subject to the organization's per-minute token budget (request_exceeds_capacity, see 2026-07-19). Existing Codex setups pick up the new window on their next setup run.
  • Routed preview requests rejected purely for context size now return 400 invalid_request_error with code context_length_exceeded, matching every other context-overflow rejection. Previously this one path reported the generic request_requirements_unsatisfied. That code is now reserved for requests whose input, tool, reasoning, or media requirements cannot be satisfied together for reasons beyond context size alone.

2026-07-26#

  • Stream lifetimes are now documented per-effort time entitlements instead of one flat internal timeout. A stream that is actively working is never ended for taking long: streams end early only on a documented idle timeout (90 seconds without model activity; 120 seconds at xhigh and above) or on the wall-clock ceiling for the requested reasoning effort (5 minutes at none/minimal up to 60 minutes at max/ultra). Requests that do not set a reasoning effort resolve no lower than the medium row (10 minutes); eb1-frontier-preview defaults to the max row. Previously, long runs could be interrupted near 600 seconds even while the model was still working.
  • When a stream deadline fires, the run ends with one honest terminal instead of a spurious error: Responses streams carry response.incomplete with incomplete_details.reason of stream_idle_timeout or stream_ceiling_timeout; Chat Completions reports finish_reason length and Messages reports stop_reason max_tokens. Tokens consumed before the stop are billed; the terminal event is truthful about why the run stopped. See Streaming.

2026-07-22#

  • The discoverable model catalog is eb1-preview, eb1-frontier-preview, eb1-fast-preview, and eb1-efficient-preview, superseding the naming contract published on 2026-07-20. The eb1-preview-efficient, eb1-preview-fast, and eb1-preview-delta identifiers remain accepted on requests and in stored conversations with unchanged behavior and pricing, but no longer appear in /v1/models, Console menus, CLI listings, or Codex setup. Responses to requests that use one of those identifiers name the canonical id; responses to eb1-preview-delta requests name eb1-delta-preview, which remains callable but does not appear in discovery.
  • Invalid model-exclusion inputs now return the governed, non-retriable 400 invalid_request_error envelope with code bad_request. Previously these caller-fixable requests could be serialized as a retriable 502 upstream_error. Synchronous responses now carry x-should-retry: false; synchronous bodies and streaming error frames carry retryable: false with no retry horizon.

2026-07-20#

  • Public discovery, Console, CLI, and Codex now use one four-model naming contract: eb1-preview, eb1-preview-efficient, eb1-preview-fast, and eb1-preview-delta. Existing stored configurations using earlier preview spellings remain request-compatible, but new configuration and response identity use the current IDs.
  • Keiro 0.12.22 requests safe reasoning summaries for registered eb1 models and displays available segments while a response is in progress. These segments are terminal activity, not assistant answer text: they do not enter conversation history, copied code blocks, or piped stdout. Python callers can consume the same validated stream separately with ModelsAPI.responses_stream(on_reasoning_summary=...) or its admin sibling. Direct-provider requests receive no implicit summary setting.

2026-07-19#

  • Responses usage now reports provider-supplied prompt-cache reads and writes in input_tokens_details.cached_tokens and cache_write_tokens, instead of always reporting zero. Both are subsets of input_tokens and do not change total_tokens. The Console chat tester preserves those reported cache-read counts and output_tokens_details.reasoning_tokens in a compact Token details disclosure when those subsets are positive; required structural zeroes remain undisclosed because they do not prove provider provenance. It labels arithmetic totals and remainders as derived and does not fabricate system-prompt, history, user-message, or tool-schema buckets that the API does not separately report.
  • Published context windows now match the limit the API enforces end to end. eb1-preview, eb1-efficient-preview, and eb1-fast-preview report a context_window of 120000 in /v1/models, down from the previously published 128000; eb1-frontier-preview is unchanged at 128000. Requests between the two figures could previously be rejected with a context-overflow error despite sitting inside the published window; the published figure is now a floor the API honors on every request.
  • Requests whose selected model cannot satisfy every input, tool, reasoning, and context requirement now fail before dispatch with non-retriable HTTP 400 code request_requirements_unsatisfied.
  • Requests whose token estimate exceeds a full minute of the organization's token-per-minute budget now return a terminal 400 invalid_request_error with code request_exceeds_capacity, instead of a 429 rate limit. The old 429 carried a Retry-After header even though no unchanged retry could ever succeed, trapping status-driven clients in an infinite retry loop. The new response carries x-should-retry: false, no retry horizon, and no x-ratelimit-reset-*-tokens header; the message and details.dimension: "token_budget_request" are unchanged. Reduce the input or max_output_tokens, or raise the limit, and resend.

2026-07-18#

  • Usage objects on OpenAI-format surfaces now itemize reasoning tokens and follow the standard arithmetic exactly. Chat Completions usage gains completion_tokens_details (with reasoning_tokens), and total_tokens always equals prompt_tokens + completion_tokens, with reasoning counted inside completion_tokens. Previously, reasoning-heavy requests could report a total_tokens larger than the visible sum with no breakdown.
  • Responses usage now matches the standard ResponseUsage schema: input_tokens, input_tokens_details.cached_tokens, output_tokens, output_tokens_details.reasoning_tokens, and total_tokens (= input_tokens + output_tokens). The former non-standard flat reasoning_tokens key and the prompt_tokens/completion_tokens aliases are removed. Strict typed SDK clients that previously failed to validate usage now parse it; clients reading the flat keys must switch to the nested fields.
  • /v1/messages output_tokens now includes reasoning tokens, matching the Anthropic convention that thinking is part of output.
  • usage detail objects report cached_tokens: 0 for now; prompt-cache accounting is not yet reflected in usage counts.

2026-07-17#

  • Retired the /v24b versioned endpoint path. It no longer differs from the current default deployment, so requests to /v24b/v1/* now return 410 endpoint_retired instead of routing to current-default weights under a versioned label. Use the default API (/v1).
  • The Keiro CLI no longer offers a v24b endpoint preset. keiro endpoint v24b, saved v24b gateway URLs, and explicit v24b URLs surface the retirement guidance instead of binding to the default gateway.

2026-07-15#

  • Missing pricing for an otherwise valid model now returns the governed, non-retriable 404 model_not_found envelope with x-should-retry: false.
  • Chat Completions stream error frames now nest a full error object (code, type, message, retry signals, retryable, request_id, and details on limit denials) alongside the existing flat fields. OpenAI-compatible SDKs surface it as a typed error instead of failing to parse the frame. The flat fields are deprecated (removal is at least two releases out and gated on usage telemetry); Messages and Responses stream error frames gain the same details object on limit denials.
  • /v1/messages responses now also carry a request-id header (an alias of X-Request-Id) so Anthropic-compatible SDKs populate .request_id.
  • Responses that produced no output because reasoning consumed the entire completion budget now report status: "incomplete" with incomplete_details.reason: "max_output_tokens" and a warning naming the fix, instead of claiming success; Chat Completions report finish_reason: "length". Billed usage is unchanged and still reported.
  • Error messages no longer carry [Error NNNN] / [Recovery: …] bracket furniture; recovery guidance appears as a plain sentence only when it applies to the specific failure. Message text remains non-contractual.
  • Corrected upstream authentication failures to a fixed 502 with code upstream_auth_error. Previously an upstream 401 could pass through as your fault; SDKs raised AuthenticationError and stopped retrying for a platform-side condition. Your API key is valid when you see this code.
  • Replaced the 401 code authentication_error (which duplicated type) with three specific codes: missing_authorization, bearer_scheme_required, and invalid_api_key (with a redacted details.key_hint). Code-matching clients keep working: the old code's value remains as the error type. All 401 responses now carry WWW-Authenticate: Bearer.
  • error.param is now populated with the offending field name where known; previously documented as always null.
  • Documented every error code with per-code anchors, added 413 and 415 to the status table, and removed the never-emitted 408 row.
  • Added retry-signal headers to error responses: retry-after-ms (milliseconds, fractional precision) on retriable denials and x-should-retry: false on denials an unchanged retry cannot clear. Deterministic denials also carry "retryable": false in the error body.
  • Error responses now include error.request_id, matching the X-Request-Id header; stream error frames carry it on the Messages and Responses wires.

2026-07-10#

  • Added an API reference index and dedicated guides for Messages, function tools, image input, API-key lifecycle, usage and billing, and Codex setup.
  • Reworked Quickstart into an install-to-output workflow with one credential policy: saved Keiro credentials, interactive curl/Python secrets, and secret-file references for other runtimes.
  • Reconciled API-key guidance with the console's create, staged-replacement, and delete/revoke workflow.
  • Added contextual related-page paths throughout the documentation.
  • Corrected the subprocessor description: authenticated docs are served by Keiro-operated services, while Netlify hosts the public website, early-access intake, and published status artifact.

2026-07-01#

  • Documented idempotent requests, including the Idempotency-Key header, the X-Idempotent-Replay and X-Original-Request-Id replay headers, and 409 idempotency_key_conflict conflicts.
  • Documented the 409 status code and clarified that the error param field is always null.
  • Added a Responses streaming event taxonomy.
  • Documented Netlify's hosting purpose for the public website, early-access intake, and published status artifact.

2026-06-25#

  • Added shared Keiro Labs web-surface tokens to generated docs.
  • Added skip links, active sidebar navigation, canonical URLs, Open Graph URLs, and table scrolling to the docs shell.
  • Updated docs Markdown rendering for emphasis, blockquotes, h4-h6 headings, and in-list code fences.
  • Updated rate-limit retry guidance to honor Retry-After.

2026-06-15#

  • Added initial paid beta public docs surface.
  • Standardized runnable examples on one public base URL.
  • Documented chat completions, responses, streaming, models, rate limits, errors, SDKs, support, and migration guidance.
  • Kept local keiro gui scoped to chat UX only.

Search Keiro docs

Start typing to search pages and sections.

Start typing to search pages and sections.

Documentation

Console