Skip to content

Latest commit

 

History

History
81 lines (70 loc) · 4.93 KB

decisions-api.md

File metadata and controls

81 lines (70 loc) · 4.93 KB

Native Decisions API routing

The runtime rotation proxy accepts POST /v1/decisions and POST /decisions. The authenticated local bridge also forwards /v1/decisions to the runtime. Requests go to the selected credential's regional /v1/decisions endpoint; they are never translated to Responses or chat completions.

Select api/<model> or zdr/<model> explicitly. Bare subscription models, PSP routes, and speed-tier aliases are rejected before discovery or inference. Existing PSP and Responses routing is unchanged. A zdr/ selection uses only operator-declared ZDR credentials; it does not independently certify the provider project's retention configuration.

Eligibility requires all of the following for the selected credential:

  • The route is enabled and belongs to the explicitly selected API/ZDR pool.
  • Its discovered catalog includes the model, and its visibility policy allows it.
  • The model's operator profile includes supported_endpoints: ["/v1/decisions"].

Set that field in the credential's existing modelProfiles[model] configuration only after verifying the provider supports Decisions for that account/model. A model ID returned by /models alone does not grant endpoint capability. This change neither edits existing profiles nor performs inference probes.

Credentials whose catalog is already fresh are tried first, so a cold or stalled catalog elsewhere in the pool never delays them. Other credentials in the same pool and region are discovered only after the warm ones fail or are rate limited. When no catalog is fresh, the whole pool is discovered before the first send.

Typed predicate, choice (including boolean choices), and score questions are forwarded with the original input and optional cache/safety fields. Only the routing prefix is removed from model. No Responses-only store, stream, or reasoning settings are injected. Native answers, refusals, and usage remain intact. Provider rejection status and safe error code/type/parameter fields are preserved; error messages are sanitized to avoid reflecting private input.

Unsupported endpoint responses (405, 501, and a 404 that names the model or endpoint or carries no structured error) allow another eligible credential in the same pool and region and are cached for five minutes per credential, model, and endpoint. A 404 about request content, such as a missing input file, is returned to the caller without failover or caching. Responses capability state is unaffected. A credential rejected with 401, 403, or a permanent quota 429 (insufficient_quota and similar) is rejected before inference, so the next eligible credential in the same pool and region is tried and the rejected one is not sent again for that request. If every credential is rejected with 401 or 403, the caller gets 503 decisions_pool_unavailable, never a 401 or 403 that would read as its own credential failing; a pool-wide permanent quota rejection stays a sanitized 429. Confirmed temporary rate_limit_exceeded 429 responses use Retry-After and shared backoff. When the shortest cooldown left in the pool outlasts the request deadline, the caller gets 429 rate_limit_exceeded with Retry-After and retry_after_ms set to that cooldown, including when the cooldown was cached by an earlier request. Unclassified 429 rejections, network ambiguity, and other server errors are not replayed. Discovery, admission, response-body reads, and retries share a 60-second deadline and respect cancellation. Answers are buffered up to 64 MiB, the proxy's request cap. A larger answer returns 502 decisions_response_too_large; the provider has already run that request, but its usage cannot be read, so no token counts are recorded. Error bodies are read only until 5 seconds pass without data or 64 KiB arrive, so a stalled rejection cannot hold failover until the deadline.

The usage ledger records the decisions operation and actual provider token counts, including for responses larger than the generic stream scanner's cap. The full provider usage object is returned to the caller. Endpoint-specific pricing is not configured: estimated cost remains unknown (null), never zero or a Responses-model estimate. Callers must not present these requests as free.

Every budget window counts all ledger rows, whatever the budget's key, and a cost budget whose window holds usage of unknown cost cannot be evaluated and fails closed for all traffic until the window ends. So while any --cost budget exists, the runtime proxy refuses Decisions requests with 403 policy_blocked before discovery or inference, and the reason names the cost budgets responsible. Budget on --requests or --tokens to allow Decisions. Decisions usage recorded before a cost budget was created still makes that budget fail closed until the usage leaves its window.

Provider contract references: Decisions guide and create endpoint.