RecordUsage treats a missing price as zero cost on the first pass, but
the Free Fast Standard re-evaluation returned the same pricing error.
Requests in a free_openai_fast group sent at priority/fast tier to a
model without pricing therefore lost their usage log entirely.
Ignore pricing-unavailable errors on the Standard pass and keep the
zero-cost entry, matching the first pass.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The personal-access-token /v1/alpha/search fallback turned any upstream
Responses SSE body into a 200 search result and billed one web search call.
Error, response.failed and response.incomplete events, a response.completed
with a non-success status or without its response, a truncated stream and a
bare [DONE] were all accepted, returning partial text as a successful and
billable search.
Parse the stream strictly: those shapes now return an error, so nothing is
written to the client and no WebSearchCalls result is produced. A successful
response.completed keeps the existing output and citation handling. The
existing PAT metadata test now feeds a Responses SSE stream, which is what
that upstream path returns.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The API-key Responses capability probe treated every 404 as conclusive and
stored responses_supported=false. The probe model is the first mapped
upstream model in lexical order, so on third-party accounts it is often an
auxiliary entry such as codex-auto-review; a model_not_found answer then
permanently routed the account away from /v1/responses although the
endpoint works.
A 400/404 whose error code/type or message says the probe model does not
exist or is unavailable is now inconclusive, so the stored capability is not
overwritten. Plain 404/405 still mean the endpoint is missing. The probe
also prefers a general gpt-* text model (not an image model) among the
mapped models before falling back to the first one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a channel pricing entry left image_output_price empty,
GetModelPricingWithChannel and the pricing resolver zeroed the image
output price and marked it explicit, so image output tokens were billed
at $0. image_input_price followed the same "unset means zero" rule and
fell back to the text input price instead of the catalog image input
price. A channel that lists an image model such as gpt-image-2 in token
mode without filling in prices therefore generated images without
charging for image output tokens, while the available-channels view
(#2475) displayed the catalog image price for the same entry.
#2930 wanted an explicit 0 on the channel to stop falling back to the
catalog; the change applied the same treatment to unset values as well.
Treat the two image fields like every other token price field:
- Set on the channel (including 0): override the catalog. An explicit
image_output_price keeps ImageOutputPriceExplicit, so 0 stays free.
- Left empty: keep the catalog price (LiteLLM or built-in fallback). If
the catalog has none, computeTokenBreakdown still falls back to the
text input/output price.
The admin UI saves an empty field as null and only an entered 0 as 0,
so the two cases stay distinguishable. The flat, interval and
GetModelPricingWithChannel paths now share applyChannelImagePriceOverrides.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Close the existing catalog identity test before the new capability test and
assert that an explicit null capability remains present. Update the quota
snapshot fixture to the pointer parameter already used by the current base.
Verified six full backend unit packages, scoped lint and CGO-disabled build.
Validate mapped targets for default image models as well as aliases. Preserve native image choices in passthrough and cover mapping changes over the shared catalog cache.