fix(proxy): bill cancelled and failed batches that still produced an output file - #37205
Conversation
Greptile SummaryThe PR bills failed and cancelled terminal batches when they produced output, while preserving unbilled finalization for terminal batches without output
Confidence Score: 5/5The PR appears safe to merge No blocking failure remains
|
| Filename | Overview |
|---|---|
| enterprise/litellm_enterprise/proxy/common_utils/check_batch_cost.py | Expands output-file billing to all provider terminal statuses and centralizes unbilled terminal-job finalization |
| tests/proxy_unit_tests/test_check_batch_cost.py | Updates terminal managed-file assertions and covers billing for expired, cancelled, and failed batches with output |
Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/lit..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
… instead of retrying
…itellm_lit5663_terminal_batch_output_cost
|
bugbot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Terminal batches skipped by poller
- Removed failed/expired/cancelled from the primary find_many
not_infilter so the poller re-selects terminal rows written by retrieve_batch or cancel_batch and bills their output, relying onbatch_processed=Falseto gate reprocessing.
- Removed failed/expired/cancelled from the primary find_many
Or push these changes by commenting:
@cursor push 1fbb43efed
Preview (1fbb43efed)
diff --git a/enterprise/litellm_enterprise/proxy/common_utils/check_batch_cost.py b/enterprise/litellm_enterprise/proxy/common_utils/check_batch_cost.py
--- a/enterprise/litellm_enterprise/proxy/common_utils/check_batch_cost.py
+++ b/enterprise/litellm_enterprise/proxy/common_utils/check_batch_cost.py
@@ -786,19 +786,18 @@
# every subsequent poll cycle.
if self._has_batch_processed_column:
try:
- # Include "complete"/"completed" batches: the retrieve_batch
- # endpoint may transition a batch to "complete" before
- # CheckBatchCost runs. The batch_processed=False filter
- # already prevents reprocessing finished batches.
+ # Include every provider-terminal batch (complete/completed as well as
+ # failed/expired/cancelled): retrieve_batch or cancel_batch may write
+ # any of those statuses before CheckBatchCost runs, and a terminal batch
+ # with an output_file_id still needs to be billed. The batch_processed=False
+ # filter already prevents reprocessing finalized rows, so only stale_expired
+ # (retired by the fallback schema path) is excluded here.
jobs = await self.prisma_client.db.litellm_managedobjecttable.find_many(
where={
"file_purpose": "batch",
"batch_processed": False,
"status": {
"not_in": [
- "failed",
- "expired",
- "cancelled",
"stale_expired",
]
},
diff --git a/tests/proxy_unit_tests/test_check_batch_cost.py b/tests/proxy_unit_tests/test_check_batch_cost.py
--- a/tests/proxy_unit_tests/test_check_batch_cost.py
+++ b/tests/proxy_unit_tests/test_check_batch_cost.py
@@ -174,13 +174,12 @@
assert find_call[1]["order"] == {"created_at": "asc"}
not_in = find_call[1]["where"]["status"]["not_in"]
assert "stale_expired" in not_in
- # "complete"/"completed" are intentionally NOT excluded from the
- # primary query — the batch_processed=False filter is sufficient.
- # This allows CheckBatchCost to pick up batches that were
- # transitioned to "complete" by the retrieve_batch endpoint
- # before CheckBatchCost had a chance to process them.
- assert "complete" not in not_in
- assert "completed" not in not_in
+ # No provider-terminal status is excluded from the primary query, the
+ # batch_processed=False filter is sufficient. This lets CheckBatchCost pick up
+ # batches that retrieve_batch or cancel_batch transitioned to complete/completed
+ # or failed/expired/cancelled before CheckBatchCost had a chance to bill them.
+ for terminal in ("complete", "completed", "failed", "expired", "cancelled"):
+ assert terminal not in not_in
assert find_call[1]["where"]["batch_processed"] is False
assert check_batch_cost_instance.batch_processed_support_confirmed is TrueYou can send follow-ups to the cloud agent here.
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
1 issue from previous review remains unresolved.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit b34cbb1. Configure here.
…9.1) (#104)
This PR contains the following updates:
| Package | Update | Change |
|---|---|---|
| [ghcr.io/berriai/litellm](https://images.chainguard.dev/directory/image/wolfi-base/overview) ([source](https://github.com/BerriAI/litellm)) | minor | `v1.98.0` → `v1.99.1` |
---
### Release Notes
<details>
<summary>BerriAI/litellm (ghcr.io/berriai/litellm)</summary>
### [`v1.99.1`](https://github.com/BerriAI/litellm/releases/tag/v1.99.1)
[Compare Source](https://github.com/BerriAI/litellm/compare/v1.99.0...v1.99.1)
#### Docker-only release
**This release ships container images only. There is no PyPI package for `1.99.1`.**
`pip install litellm==1.99.1` will not resolve — install the images below, or stay on `1.99.0` on PyPI. The git tag and this release exist so the images are traceable to an exact commit.
| Image | Tags |
| ------------------------------------------------------------------------- | ------------------- |
| `ghcr.io/berriai/litellm` · `docker.io/litellm/litellm` | `1.99.1`, `v1.99.1` |
| `ghcr.io/berriai/litellm-database` · `docker.io/litellm/litellm-database` | `1.99.1`, `v1.99.1` |
| `ghcr.io/berriai/litellm-non_root` · `docker.io/litellm/litellm-non_root` | `1.99.1`, `v1.99.1` |
This is the newest stable image, so the rolling `latest` and `main-stable` image tags now point at `1.99.1`.
It carries one fix on top of `1.99.0`: OpenTelemetry v2 spans now emit cache token counts (`gen_ai.usage.cache_creation.input_tokens` and `gen_ai.usage.cache_read.input_tokens`) alongside the cache cost that was already reported. If you compute spend from OTel token counts rather than from LiteLLM's own cost fields, prompt-caching workloads were previously under-counted.
***
#### Verify Docker Image Signature
All LiteLLM Docker images are signed with [cosign](https://docs.sigstore.dev/cosign/overview/). Every release is signed with the same key introduced in [commit `0112e53`](https://github.com/BerriAI/litellm/commit/0112e53046018d726492c814b3644b7d376029d0).
**Verify using the pinned commit hash (recommended):**
A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:
```bash
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
ghcr.io/berriai/litellm:v1.99.1
```
**Verify using the release tag (convenience):**
Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:
```bash
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/v1.99.1/cosign.pub \
ghcr.io/berriai/litellm:v1.99.1
```
Expected output:
```
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
```
***
#### What's Changed
- chore(release): backport [#​38716](https://github.com/BerriAI/litellm/issues/38716) to stable/1.99.x and cut 1.99.1 by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​39179](https://github.com/BerriAI/litellm/pull/39179)
**Full Changelog**: <https://github.com/BerriAI/litellm/compare/v1.99.0...v1.99.1>
### [`v1.99.0`](https://github.com/BerriAI/litellm/releases/tag/v1.99.0)
[Compare Source](https://github.com/BerriAI/litellm/compare/v1.98.0...v1.99.0)
#### Verify Docker Image Signature
All LiteLLM Docker images are signed with [cosign](https://docs.sigstore.dev/cosign/overview/). Every release is signed with the same key introduced in [commit `0112e53`](https://github.com/BerriAI/litellm/commit/0112e53046018d726492c814b3644b7d376029d0).
**Verify using the pinned commit hash (recommended):**
A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:
```bash
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
ghcr.io/berriai/litellm:v1.99.0
```
**Verify using the release tag (convenience):**
Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:
```bash
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/v1.99.0/cosign.pub \
ghcr.io/berriai/litellm:v1.99.0
```
Expected output:
```
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
```
***
#### What's Changed
- chore(typing): drop 1.3k basedpyright errors across 30 Any hotspot files by [@​mateo-berri](https://github.com/mateo-berri) in [#​37073](https://github.com/BerriAI/litellm/pull/37073)
- fix(proxy): register WebSocket passthrough for OpenAI prefixes by [@​LHMQ878](https://github.com/LHMQ878) in [#​36151](https://github.com/BerriAI/litellm/pull/36151)
- fix(bedrock): report uploaded size in the FileObject returned by managed batch uploads by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​36392](https://github.com/BerriAI/litellm/pull/36392)
- fix(batches): support AWS Bedrock batch cancellation via `StopModelInvocationJob` by [@​ArjunPakhan](https://github.com/ArjunPakhan) in [#​34087](https://github.com/BerriAI/litellm/pull/34087)
- feat: Async Rust OCR Bridge and MCP OAuth UI Restore by [@​ArjunPakhan](https://github.com/ArjunPakhan) in [#​31453](https://github.com/BerriAI/litellm/pull/31453)
- fix(batches): don't crash logging when a completed batch has no output file by [@​MUSE-CODE-SPACE](https://github.com/MUSE-CODE-SPACE) in [#​34067](https://github.com/BerriAI/litellm/pull/34067)
- fix(UI): add default model pin to complexity router UI by [@​tin-berri](https://github.com/tin-berri) in [#​36615](https://github.com/BerriAI/litellm/pull/36615)
- feat(ui): add Lite mixed-provider auto-router preset by [@​tin-berri](https://github.com/tin-berri) in [#​37068](https://github.com/BerriAI/litellm/pull/37068)
- feat(ui): link key info header to its user, creator, team, and organization by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37187](https://github.com/BerriAI/litellm/pull/37187)
- fix(guardrails): scan text on /guardrails/apply\_guardrail for Azure Content Safety by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​36894](https://github.com/BerriAI/litellm/pull/36894)
- feat(bedrock): forward LiteLLM identity and metadata into Bedrock requestMetadata by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​36861](https://github.com/BerriAI/litellm/pull/36861)
- fix(azure): rename max\_tokens to max\_completion\_tokens for gpt-5-chat deployments by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​36857](https://github.com/BerriAI/litellm/pull/36857)
- fix(bedrock): preserve cache token usage when invocationMetrics replace the usage block by [@​brian5021](https://github.com/brian5021) in [#​36878](https://github.com/BerriAI/litellm/pull/36878)
- fix(proxy): registry caches stop per-request tag and end-user Postgres reads in auth by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​36801](https://github.com/BerriAI/litellm/pull/36801)
- test(e2e): replay a real tool-search assistant turn back to Bedrock Invoke by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​36856](https://github.com/BerriAI/litellm/pull/36856)
- fix(proxy): return 400 naming the missing required param on POST /v1/batches by [@​mateo-berri](https://github.com/mateo-berri) in [#​37199](https://github.com/BerriAI/litellm/pull/37199)
- fix(ci): bump sqlparse to 0.6.0 to resolve osv-scan CVEs by [@​mateo-berri](https://github.com/mateo-berri) in [#​37200](https://github.com/BerriAI/litellm/pull/37200)
- fix(ui): stop pairing key spend with the team budget when a key has no budget by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37196](https://github.com/BerriAI/litellm/pull/37196)
- fix(guardrails): record MCP tool guardrail evaluations and blocks in … by [@​Scott-Wilson-ZocDoc](https://github.com/Scott-Wilson-ZocDoc) in [#​36978](https://github.com/BerriAI/litellm/pull/36978)
- fix(proxy): return 400 for non-object metadata and litellm\_metadata instead of silent drop or 500 by [@​mateo-berri](https://github.com/mateo-berri) in [#​37203](https://github.com/BerriAI/litellm/pull/37203)
- fix(anthropic): preserve optional Responses tool properties by [@​Scott-Wilson-ZocDoc](https://github.com/Scott-Wilson-ZocDoc) in [#​36979](https://github.com/BerriAI/litellm/pull/36979)
- feat(ui): add user ID request log filter by [@​daniel-meismer-zocdoc](https://github.com/daniel-meismer-zocdoc) in [#​36781](https://github.com/BerriAI/litellm/pull/36781)
- fix(anthropic): stop emitting empty thinking blocks on the Responses adapter by [@​Scott-Wilson-ZocDoc](https://github.com/Scott-Wilson-ZocDoc) in [#​36033](https://github.com/BerriAI/litellm/pull/36033)
- fix(ui): make per-user usage filter searchable by [@​daniel-meismer-zocdoc](https://github.com/daniel-meismer-zocdoc) in [#​36790](https://github.com/BerriAI/litellm/pull/36790)
- refactor(ui): decouple bulk invite from the invite user button by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37061](https://github.com/BerriAI/litellm/pull/37061)
- fix(helm): bound the migrations Job so a blocked migration cannot stall the release by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​36975](https://github.com/BerriAI/litellm/pull/36975)
- feat(proxy): let USE\_V2\_MIGRATION\_RESOLVER select the v2 migration resolver by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​36258](https://github.com/BerriAI/litellm/pull/36258)
- fix(mcp): scope authorization server issuer by [@​irosh-colombage-ZocDoc2](https://github.com/irosh-colombage-ZocDoc2) in [#​36482](https://github.com/BerriAI/litellm/pull/36482)
- fix(responses): unwrap object-form tool\_choice before calling the Responses API by [@​Scott-Wilson-ZocDoc](https://github.com/Scott-Wilson-ZocDoc) in [#​36032](https://github.com/BerriAI/litellm/pull/36032)
- test(ui): query antd controls accessibly instead of by internal CSS class by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37014](https://github.com/BerriAI/litellm/pull/37014)
- fix(proxy): bill cancelled and failed batches that still produced an output file by [@​mateo-berri](https://github.com/mateo-berri) in [#​37205](https://github.com/BerriAI/litellm/pull/37205)
- fix(bedrock): read batch usage by payload shape, not by provider name by [@​marty-sullivan](https://github.com/marty-sullivan) in [#​37078](https://github.com/BerriAI/litellm/pull/37078)
- fix(ui): self-contained searchable user filter on the Usage page by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37206](https://github.com/BerriAI/litellm/pull/37206)
- revert: don't fix mcp scope authorization server issuer by [@​mateo-berri](https://github.com/mateo-berri) in [#​37220](https://github.com/BerriAI/litellm/pull/37220)
- fix(mcp): scope authorization server issuer for named MCP servers by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37204](https://github.com/BerriAI/litellm/pull/37204)
- test(ui): gate dashboard test assertions with testing-library and jest-dom rules by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37018](https://github.com/BerriAI/litellm/pull/37018)
- feat(shadow-eval): name the shadowed key in job responses and the UI headline by [@​tin-berri](https://github.com/tin-berri) in [#​37221](https://github.com/BerriAI/litellm/pull/37221)
- test(ui): assert what collaborators are called with, not merely that they were by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37019](https://github.com/BerriAI/litellm/pull/37019)
- fix(logging): stop deepcopying results redaction cannot redact by [@​marty-sullivan](https://github.com/marty-sullivan) in [#​36638](https://github.com/BerriAI/litellm/pull/36638)
- fix(gemini): price gemini 3.6 flash at Google's introductory rates on every service tier by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37197](https://github.com/BerriAI/litellm/pull/37197)
- perf(guardrails): stop sending the conversation twice in the noma v2 payload by [@​itaimodi](https://github.com/itaimodi) in [#​36764](https://github.com/BerriAI/litellm/pull/36764)
- fix(streaming): track provider-reported cost when caller omits include\_usage by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​35013](https://github.com/BerriAI/litellm/pull/35013)
- fix: stop rust flag from leaking into upstream provider request bodies by [@​mateo-berri](https://github.com/mateo-berri) in [#​37218](https://github.com/BerriAI/litellm/pull/37218)
- fix(proxy): return 404 instead of 500 for unresolvable batch and file ids on /v1/batches by [@​mateo-berri](https://github.com/mateo-berri) in [#​37201](https://github.com/BerriAI/litellm/pull/37201)
- fix(bedrock): validate file-content retrieval against the configured output bucket ([#​26335](https://github.com/BerriAI/litellm/issues/26335)) by [@​kingdoooo](https://github.com/kingdoooo) in [#​31435](https://github.com/BerriAI/litellm/pull/31435)
- fix(proxy): reject out-of-range limit on GET /v1/batches with OpenAI-parity 400 by [@​mateo-berri](https://github.com/mateo-berri) in [#​37198](https://github.com/BerriAI/litellm/pull/37198)
- fix(batches): price a retrieved batch from its deployment's model and rates (internal copy of [#​37077](https://github.com/BerriAI/litellm/issues/37077)) by [@​mateo-berri](https://github.com/mateo-berri) in [#​37219](https://github.com/BerriAI/litellm/pull/37219)
- feat(ocr): return Azure Document Intelligence's native payload from /v1/ocr via req\_format=native by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37194](https://github.com/BerriAI/litellm/pull/37194)
- fix(anthropic): fold guardrail-modified leading system rows into top-level system param by [@​mateo-berri](https://github.com/mateo-berri) in [#​37231](https://github.com/BerriAI/litellm/pull/37231)
- fix(shadow\_eval): copy messages before router call and raise judge output cap by [@​tin-berri](https://github.com/tin-berri) in [#​37232](https://github.com/BerriAI/litellm/pull/37232)
- feat(proxy): add Amazon Comprehend Medical passthrough provider by [@​mateo-berri](https://github.com/mateo-berri) in [#​37229](https://github.com/BerriAI/litellm/pull/37229)
- test(ui): settle the in-flight search before the loading tests end by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37227](https://github.com/BerriAI/litellm/pull/37227)
- test(cli): use example.com placeholder host in base-url trailing slash test by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37240](https://github.com/BerriAI/litellm/pull/37240)
- feat(complexity\_router): operator-defined tier sets for the LLM classifier by [@​tin-berri](https://github.com/tin-berri) in [#​37226](https://github.com/BerriAI/litellm/pull/37226)
- feat(ui): configure the auto router's heuristic scorer from the Admin UI by [@​tin-berri](https://github.com/tin-berri) in [#​37216](https://github.com/BerriAI/litellm/pull/37216)
- fix(shadow\_eval): drop unused judge reasoning field and salvage truncated verdicts by [@​tin-berri](https://github.com/tin-berri) in [#​37239](https://github.com/BerriAI/litellm/pull/37239)
- feat(proxy): proactive model deprecation alerts and `/model/deprecations` endpoint by [@​mateo-berri](https://github.com/mateo-berri) in [#​26900](https://github.com/BerriAI/litellm/pull/26900)
- refactor(ui): move dashboard toasts from antd message/notification onto sonner by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37207](https://github.com/BerriAI/litellm/pull/37207)
- feat(guardrails): track bedrock guardrail usage units per invocation by [@​mateo-berri](https://github.com/mateo-berri) in [#​37225](https://github.com/BerriAI/litellm/pull/37225)
- fix(proxy): strip callback credentials from the auth object stamped into request metadata by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37233](https://github.com/BerriAI/litellm/pull/37233)
- fix(guardrails): retry usage upserts only on connection errors by [@​mateo-berri](https://github.com/mateo-berri) in [#​37247](https://github.com/BerriAI/litellm/pull/37247)
- fix(mcp): oauth discovery must not cause outages by [@​daniel-meismer-zocdoc](https://github.com/daniel-meismer-zocdoc) in [#​36599](https://github.com/BerriAI/litellm/pull/36599)
- test(ui): await the playground model combobox before clicking it by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​36850](https://github.com/BerriAI/litellm/pull/36850)
- refactor(ui): migrate budget and skill forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37262](https://github.com/BerriAI/litellm/pull/37262)
- refactor(ui): migrate tag and memory forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37266](https://github.com/BerriAI/litellm/pull/37266)
- feat(complexity\_router): plan-mode tier floor for coding-agent clients by [@​tin-berri](https://github.com/tin-berri) in [#​37230](https://github.com/BerriAI/litellm/pull/37230)
- refactor(ui): codemod every toast call site onto lib/toast and delete the antd-era facades by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37253](https://github.com/BerriAI/litellm/pull/37253)
- feat(proxy): add /team/daily/activity/aggregated and switch the Usage team tab to it by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​36562](https://github.com/BerriAI/litellm/pull/36562)
- refactor(ui): migrate user, logging and policy forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37303](https://github.com/BerriAI/litellm/pull/37303)
- refactor(ui): migrate user, policy, and margin forms to shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37305](https://github.com/BerriAI/litellm/pull/37305)
- refactor(ui): migrate the regenerate key and team member forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37300](https://github.com/BerriAI/litellm/pull/37300)
- refactor(ui): migrate CloudZero and cost tracking forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37312](https://github.com/BerriAI/litellm/pull/37312)
- refactor(ui): migrate auto router and credential forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37304](https://github.com/BerriAI/litellm/pull/37304)
- refactor(ui): migrate guardrail and vector store forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37306](https://github.com/BerriAI/litellm/pull/37306)
- refactor(ui): migrate prompt, UI access, plugin and MCP filter forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37297](https://github.com/BerriAI/litellm/pull/37297)
- refactor(ui): drop the unreachable user edit modal by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37327](https://github.com/BerriAI/litellm/pull/37327)
- fix(router): route Responses API input through the auto-router by [@​mateo-berri](https://github.com/mateo-berri) in [#​37333](https://github.com/BerriAI/litellm/pull/37333)
- refactor(ui): migrate the login, onboarding and search tool forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37334](https://github.com/BerriAI/litellm/pull/37334)
- feat(ui): plan-mode override tier in the auto-router create and edit forms by [@​tin-berri](https://github.com/tin-berri) in [#​37319](https://github.com/BerriAI/litellm/pull/37319)
- refactor(ui): retire the tremor date range picker in favour of the shared advanced picker by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37302](https://github.com/BerriAI/litellm/pull/37302)
- fix(proxy): forward Bedrock event-stream content-type on unbuffered passthrough by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​33767](https://github.com/BerriAI/litellm/pull/33767)
- fix(azure\_ai): strip non-OpenAI-spec message fields before request by [@​ayaangazali](https://github.com/ayaangazali) in [#​34445](https://github.com/BerriAI/litellm/pull/34445)
- fix(proxy): stop leaking the client\_side\_timeout marker to providers by [@​mateo-berri](https://github.com/mateo-berri) in [#​37346](https://github.com/BerriAI/litellm/pull/37346)
- refactor(ui): migrate the caching, cost tracking, alerting and user detail forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37350](https://github.com/BerriAI/litellm/pull/37350)
- refactor(ui): migrate pass-through, project and access group forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37354](https://github.com/BerriAI/litellm/pull/37354)
- refactor(ui): migrate the vector store creation form to shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37353](https://github.com/BerriAI/litellm/pull/37353)
- refactor(ui): move the MCP server forms and detail tabs off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37329](https://github.com/BerriAI/litellm/pull/37329)
- feat(complexity\_router): custom classifier plugins via classifier\_type 'custom' by [@​tin-berri](https://github.com/tin-berri) in [#​37249](https://github.com/BerriAI/litellm/pull/37249)
- fix(fireworks): skip accounts/ rewrite for FW-\* Foundry deployment ids by [@​bruno-olivia](https://github.com/bruno-olivia) in [#​37242](https://github.com/BerriAI/litellm/pull/37242)
- fix(advisor): resolve the advisor sub-call through the proxy router by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​36246](https://github.com/BerriAI/litellm/pull/36246)
- fix(router): forward target\_model\_names on file uploads to litellm\_proxy deployments by [@​shivamrawat1](https://github.com/shivamrawat1) in [#​36240](https://github.com/BerriAI/litellm/pull/36240)
- refactor(ui): move the internal user detail view off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37309](https://github.com/BerriAI/litellm/pull/37309)
- fix(responses): strip the responses/ routing prefix on the Responses API path by [@​mateo-berri](https://github.com/mateo-berri) in [#​37345](https://github.com/BerriAI/litellm/pull/37345)
- fix(main): forward store and prompt\_cache\_key params on chat completions by [@​Sujithr07](https://github.com/Sujithr07) in [#​33195](https://github.com/BerriAI/litellm/pull/33195)
- refactor(ui): migrate the model settings and credential rotation modals to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37342](https://github.com/BerriAI/litellm/pull/37342)
- refactor(ui): move the shared key form controls off antd onto shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37348](https://github.com/BerriAI/litellm/pull/37348)
- refactor(ui): move the tag and vector store views off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37311](https://github.com/BerriAI/litellm/pull/37311)
- refactor(ui): migrate SSO, SCIM and vault forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37347](https://github.com/BerriAI/litellm/pull/37347)
- test(ui): cover the edit project modal's required-field validation by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37363](https://github.com/BerriAI/litellm/pull/37363)
- refactor(ui): migrate the guardrail forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37364](https://github.com/BerriAI/litellm/pull/37364)
- refactor(ui): migrate agent forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37357](https://github.com/BerriAI/litellm/pull/37357)
- refactor(ui): migrate the MCP per-user env vars, toolset and tool arguments forms to react-hook-form and shadcn by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37349](https://github.com/BerriAI/litellm/pull/37349)
- fix(anthropic): emit tool\_use content\_block\_start without awaiting the next chunk by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37310](https://github.com/BerriAI/litellm/pull/37310)
- fix(proxy): send SSE keepalives while a slow upstream is still silent by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37322](https://github.com/BerriAI/litellm/pull/37322)
- fix(proxy): let org admins view their organization's usage by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37235](https://github.com/BerriAI/litellm/pull/37235)
- feat(vector\_stores): add Valkey as a managed vector store provider by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37002](https://github.com/BerriAI/litellm/pull/37002)
- refactor(ui): move the virtual key create and edit forms off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37324](https://github.com/BerriAI/litellm/pull/37324)
- refactor(ui): move the add model and credential forms off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37325](https://github.com/BerriAI/litellm/pull/37325)
- feat(team-callbacks): add DELETE /team/{team\_id}/callback/{callback\_name} by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37331](https://github.com/BerriAI/litellm/pull/37331)
- refactor(ui): move the teams page and team detail views off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37317](https://github.com/BerriAI/litellm/pull/37317)
- fix(cost\_calculator): recognize the ultrafast service tier in cost calculation by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37355](https://github.com/BerriAI/litellm/pull/37355)
- refactor(ui): move the cache settings and playground model selector off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37323](https://github.com/BerriAI/litellm/pull/37323)
- feat(guardrails): count bedrock guardrail cost against spend and budgets by [@​mateo-berri](https://github.com/mateo-berri) in [#​37362](https://github.com/BerriAI/litellm/pull/37362)
- refactor(ui): move the admin, SSO, SCIM, alerting and fallback forms off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37315](https://github.com/BerriAI/litellm/pull/37315)
- test(ui): raise vitest test and hook timeouts for CI headroom by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37370](https://github.com/BerriAI/litellm/pull/37370)
- fix(caching): truncate semantic cache embedding input, send extra\_body top-level by [@​mateo-berri](https://github.com/mateo-berri) in [#​37367](https://github.com/BerriAI/litellm/pull/37367)
- fix(guardrails): cap the date window accepted by /guardrails/usage endpoints by [@​mateo-berri](https://github.com/mateo-berri) in [#​37380](https://github.com/BerriAI/litellm/pull/37380)
- fix(ui): show select labels on the trigger instead of raw values by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37372](https://github.com/BerriAI/litellm/pull/37372)
- refactor(ui): move the team member search modal off antd Form by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37383](https://github.com/BerriAI/litellm/pull/37383)
- refactor(ui): move the model alias manager onto design tokens and shadcn controls by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37376](https://github.com/BerriAI/litellm/pull/37376)
- refactor(ui): move the MCP tool test form off antd by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37381](https://github.com/BerriAI/litellm/pull/37381)
- refactor(ui): move the model info view and pass-through endpoint forms off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37308](https://github.com/BerriAI/litellm/pull/37308)
- fix(otel): bound and shut down credential-scoped tracer providers by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​36591](https://github.com/BerriAI/litellm/pull/36591)
- fix(proxy): send SSE keepalives on assistants runs and A2A streams by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37368](https://github.com/BerriAI/litellm/pull/37368)
- test(anthropic): pin one content\_block\_stop per tool\_use block on the Responses adapter by [@​mateo-berri](https://github.com/mateo-berri) in [#​37356](https://github.com/BerriAI/litellm/pull/37356)
- refactor(ui): move the agent, guardrail, prompt, policy and skill forms off tremor by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37320](https://github.com/BerriAI/litellm/pull/37320)
- fix(guardrails): requeue usage rollup rows dropped after retry exhaustion by [@​mateo-berri](https://github.com/mateo-berri) in [#​37387](https://github.com/BerriAI/litellm/pull/37387)
- feat(proxy): add project-level ITPM and OTPM quotas by [@​shivijain2323](https://github.com/shivijain2323) in [#​35110](https://github.com/BerriAI/litellm/pull/35110)
- feat(bedrock): add a config toggle to disable agent-runtime pass-through by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37386](https://github.com/BerriAI/litellm/pull/37386)
- fix(mcp): attach per-user BYOK credential when listing tools for non-oauth2 auth types by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​34787](https://github.com/BerriAI/litellm/pull/34787)
- feat(ui): add success, warning and info status tokens by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37393](https://github.com/BerriAI/litellm/pull/37393)
- refactor(ui): drop [@​tremor/react](https://github.com/tremor/react) and the theming scaffolding it needed by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37394](https://github.com/BerriAI/litellm/pull/37394)
- refactor(ui): move the model info edit form off antd Form by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37392](https://github.com/BerriAI/litellm/pull/37392)
- fix(vector\_stores): stop leaking stored credentials in direct search debug logs by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37373](https://github.com/BerriAI/litellm/pull/37373)
- fix(logging): close three secret-leak paths in verbose logging by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37391](https://github.com/BerriAI/litellm/pull/37391)
- chore: bump litellm-enterprise 0.1.56 -> 0.1.57, litellm-proxy-extras 0.4.86 -> 0.4.87, litellm 1.98.0 -> 1.99.0 by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37395](https://github.com/BerriAI/litellm/pull/37395)
- fix(mcp): bind tool existence check to the selected server by [@​mateo-berri](https://github.com/mateo-berri) in [#​37388](https://github.com/BerriAI/litellm/pull/37388)
- fix(mcp): serve token-forwarding servers when oauth discovery fails by [@​tin-berri](https://github.com/tin-berri) in [#​37399](https://github.com/BerriAI/litellm/pull/37399)
- fix(databricks): add cost map entries for 14 newer Databricks models by [@​epistoteles](https://github.com/epistoteles) in [#​28501](https://github.com/BerriAI/litellm/pull/28501)
- refactor(ui): style the logging settings from semantic tokens by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37385](https://github.com/BerriAI/litellm/pull/37385)
- feat(tinyfish): surface response headers + top-level response extras by [@​ChenluJi](https://github.com/ChenluJi) in [#​32448](https://github.com/BerriAI/litellm/pull/32448)
- refactor(ui): codemod the antd Tooltips outside form files onto the shadcn atom by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37402](https://github.com/BerriAI/litellm/pull/37402)
- test(ocr): update Azure DI supported-params assertion for req\_format by [@​mateo-berri](https://github.com/mateo-berri) in [#​37419](https://github.com/BerriAI/litellm/pull/37419)
- fix(proxy): return no rows when the aggregated activity entity filter is empty by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37414](https://github.com/BerriAI/litellm/pull/37414)
- test: build redaction and batch limiter fixtures the way production does by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37416](https://github.com/BerriAI/litellm/pull/37416)
- test: allow protocol-constrained pass-through routes to declare fewer methods by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37415](https://github.com/BerriAI/litellm/pull/37415)
- test(ui): pin the MCP server edit save payload before the form migration by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37404](https://github.com/BerriAI/litellm/pull/37404)
- test(ui): characterize the create key form payload contract by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37405](https://github.com/BerriAI/litellm/pull/37405)
- refactor(ui): migrate the key edit form off Ant Design onto react-hook-form by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37398](https://github.com/BerriAI/litellm/pull/37398)
- test(ui): repoint the e2e locators at the post-antd form controls by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37421](https://github.com/BerriAI/litellm/pull/37421)
- test: point the live gemini and groq conformance suites at models that still exist by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37422](https://github.com/BerriAI/litellm/pull/37422)
- refactor(ui): extract the create-key payload builder out of create\_key\_button by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37397](https://github.com/BerriAI/litellm/pull/37397)
- fix(types): map nested prompt\_tokens\_details.cache\_creation\_input\_tokens to cache\_write\_tokens by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37377](https://github.com/BerriAI/litellm/pull/37377)
- fix(router): honor key-level tag filtering in pre-routing and pin auto-router e2e regressions by [@​mateo-berri](https://github.com/mateo-berri) in [#​37366](https://github.com/BerriAI/litellm/pull/37366)
- feat(otel): attribute Prisma database spans to PostgreSQL instead of localhost by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​36595](https://github.com/BerriAI/litellm/pull/36595)
- fix(bedrock): degrade gracefully on malformed tool-call arguments by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​33842](https://github.com/BerriAI/litellm/pull/33842)
- test: move the remaining live groq call sites off the retired llama models by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37426](https://github.com/BerriAI/litellm/pull/37426)
- fix(ui): highlight the first member search match so Enter picks it by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37429](https://github.com/BerriAI/litellm/pull/37429)
- chore(ci): promote internal staging to main by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37400](https://github.com/BerriAI/litellm/pull/37400)
- fix(proxy): log spend for OpenAI passthrough embeddings with unmapped models by [@​mateo-berri](https://github.com/mateo-berri) in [#​37425](https://github.com/BerriAI/litellm/pull/37425)
- fix(router): keep acreate\_file fallbacks inside the requested model group by [@​mateo-berri](https://github.com/mateo-berri) in [#​37424](https://github.com/BerriAI/litellm/pull/37424)
- fix(proxy): record estimated input tokens in spend logs for failed dispatched requests by [@​mateo-berri](https://github.com/mateo-berri) in [#​37365](https://github.com/BerriAI/litellm/pull/37365)
- fix: accept bool thinking param instead of crashing with AttributeError by [@​mateo-berri](https://github.com/mateo-berri) in [#​37423](https://github.com/BerriAI/litellm/pull/37423)
- refactor(ui): migrate the teams form graph off antd Form onto react-hook-form by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37417](https://github.com/BerriAI/litellm/pull/37417)
- fix(ui): restore the cache control Role and Index field hints by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37437](https://github.com/BerriAI/litellm/pull/37437)
- feat(ui): add mounted-field projections for the MCP server form graph by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37440](https://github.com/BerriAI/litellm/pull/37440)
- refactor(ui): extract the MCP server edit save payload into a pure builder by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37436](https://github.com/BerriAI/litellm/pull/37436)
- test: derive vertex batch cost expectation from the cost map by [@​mateo-berri](https://github.com/mateo-berri) in [#​37444](https://github.com/BerriAI/litellm/pull/37444)
- refactor(ui): port the create key form off antd Form onto react-hook-form by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37442](https://github.com/BerriAI/litellm/pull/37442)
- refactor(ui): port the add model form off antd Form onto react-hook-form by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37446](https://github.com/BerriAI/litellm/pull/37446)
- refactor(ui): host KeyLifecycleSettings tests in react-hook-form instead of antd Form by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37449](https://github.com/BerriAI/litellm/pull/37449)
- fix(ui): rebuild nested and list paths in the mounted-field projection by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37450](https://github.com/BerriAI/litellm/pull/37450)
- fix(ui): gate the pass-through guardrail field inputs when the section is disabled by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37435](https://github.com/BerriAI/litellm/pull/37435)
- fix(tests): keep a host PROXY\_BASE\_URL out of request-derived URL tests by [@​mateo-berri](https://github.com/mateo-berri) in [#​37451](https://github.com/BerriAI/litellm/pull/37451)
- refactor(ui): port the MCP server forms off antd Form onto react-hook-form by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37483](https://github.com/BerriAI/litellm/pull/37483)
- test(e2e): pin the tag-routing denial to its actual cause by [@​mateo-berri](https://github.com/mateo-berri) in [#​37432](https://github.com/BerriAI/litellm/pull/37432)
- fix(proxy): read through to the DB on registry misses so just-created models, guardrails, and agents resolve on sibling replicas by [@​mateo-berri](https://github.com/mateo-berri) in [#​36263](https://github.com/BerriAI/litellm/pull/36263)
- fix(mcp): forward the per-server auth header on OpenAPI tool calls by [@​tin-berri](https://github.com/tin-berri) in [#​37410](https://github.com/BerriAI/litellm/pull/37410)
- chore(typing): drop 1.3k basedpyright errors across 42 Any hotspot files by [@​mateo-berri](https://github.com/mateo-berri) in [#​37439](https://github.com/BerriAI/litellm/pull/37439)
- test(ui): drive fields with change events where the typing is not the behaviour by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37495](https://github.com/BerriAI/litellm/pull/37495)
- fix(ui): restore tab strip styling and panel persistence lost in the shadcn migration by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37403](https://github.com/BerriAI/litellm/pull/37403)
- feat(spend-logs): add lifecycle timestamps by [@​sytianhe](https://github.com/sytianhe) in [#​37361](https://github.com/BerriAI/litellm/pull/37361)
- refactor(ui): migrate the antd Button call sites onto the shadcn Button by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37505](https://github.com/BerriAI/litellm/pull/37505)
- test(ui): split the vitest suite into unit, component, integration and type projects by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37488](https://github.com/BerriAI/litellm/pull/37488)
- refactor(ptu): give the rollup a source-agnostic deployment record by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37501](https://github.com/BerriAI/litellm/pull/37501)
- feat(auto-router)!: scope shadow eval jobs to multiple keys by [@​tin-berri](https://github.com/tin-berri) in [#​37251](https://github.com/BerriAI/litellm/pull/37251)
- refactor(ui): migrate the antd Alert call sites onto the shared Alert by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37513](https://github.com/BerriAI/litellm/pull/37513)
- chore(ui): upgrade the dashboard to React 19 by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37411](https://github.com/BerriAI/litellm/pull/37411)
- fix(streaming): accept provider cost objects when propagating usage cost by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​36593](https://github.com/BerriAI/litellm/pull/36593)
- fix(complexity-router): gate the reasoning override on a non-SIMPLE score by [@​tin-berri](https://github.com/tin-berri) in [#​37500](https://github.com/BerriAI/litellm/pull/37500)
- fix(mcp): stop reporting failed OpenAPI tool calls as successes by [@​tin-berri](https://github.com/tin-berri) in [#​37496](https://github.com/BerriAI/litellm/pull/37496)
- feat(e2e): add record/replay transport seam and fixture bundle format by [@​mateo-berri](https://github.com/mateo-berri) in [#​37360](https://github.com/BerriAI/litellm/pull/37360)
- fix(proxy): accept inherited model sentinels in project key limits by [@​mateo-berri](https://github.com/mateo-berri) in [#​37515](https://github.com/BerriAI/litellm/pull/37515)
- fix(model\_prices): add provider-announced deprecation\_date to 205 registry entries by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37283](https://github.com/BerriAI/litellm/pull/37283)
- fix(model\_prices): correct gemini 3.1 flash image and deepseek v4 pricing, add openai deprecation dates by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37473](https://github.com/BerriAI/litellm/pull/37473)
- fix(model\_prices): set prompt\_cache\_min\_tokens=4096 for Gemini 3.5/3.6/3.7 Flash and 3.1 Pro Preview by [@​mateo-berri](https://github.com/mateo-berri) in [#​37516](https://github.com/BerriAI/litellm/pull/37516)
- fix(anthropic,bedrock): report provider thinking tokens instead of classifying them as text by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​35998](https://github.com/BerriAI/litellm/pull/35998)
- fix(batches): stop one bad output line from zeroing an entire batch's spend by [@​mateo-berri](https://github.com/mateo-berri) in [#​37457](https://github.com/BerriAI/litellm/pull/37457)
- feat(e2e): canonical content-based match keys for record-and-replay by [@​mateo-berri](https://github.com/mateo-berri) in [#​37525](https://github.com/BerriAI/litellm/pull/37525)
- feat(cli): add `lite login --config-claude` to wire Claude Code at login by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37507](https://github.com/BerriAI/litellm/pull/37507)
- fix(auth): resolve bare model names against wildcard deployments in model access groups by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37492](https://github.com/BerriAI/litellm/pull/37492)
- docs: run only the tests covering your change, leave suites to CI by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37528](https://github.com/BerriAI/litellm/pull/37528)
- feat(complexity-router): make the reasoning override floor configurable by [@​tin-berri](https://github.com/tin-berri) in [#​37537](https://github.com/BerriAI/litellm/pull/37537)
- fix(ui): drop stale user search answers so Enter commits the current match by [@​mateo-berri](https://github.com/mateo-berri) in [#​37504](https://github.com/BerriAI/litellm/pull/37504)
- refactor(ui): migrate the remaining dashboard pages off antd by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37524](https://github.com/BerriAI/litellm/pull/37524)
- feat(proxy): auto-suppress the no-Redis banner for confirmed single-worker deployments by [@​mateo-berri](https://github.com/mateo-berri) in [#​36987](https://github.com/BerriAI/litellm/pull/36987)
- fix(proxy): retry spend updates on Postgres deadlock instead of dropping them by [@​RayJueWang](https://github.com/RayJueWang) in [#​34887](https://github.com/BerriAI/litellm/pull/34887)
- feat(search): add Amazon Bedrock AgentCore web search provider by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​36331](https://github.com/BerriAI/litellm/pull/36331)
- fix(helm): default litellm-helm to the ghcr.io/berriai/litellm image by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37491](https://github.com/BerriAI/litellm/pull/37491)
- refactor(ui): migrate antd Modal onto the shared shadcn Dialog by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37540](https://github.com/BerriAI/litellm/pull/37540)
- fix(ui): toggle unlimited budget when its text is clicked by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37547](https://github.com/BerriAI/litellm/pull/37547)
- feat(proxy): fast-fail validation for batch input files at /v1/files by [@​mateo-berri](https://github.com/mateo-berri) in [#​37527](https://github.com/BerriAI/litellm/pull/37527)
- chore: gitignore CLAUDE.local.md by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37545](https://github.com/BerriAI/litellm/pull/37545)
- perf(otel): build the credential-scoped tracer Resource once per logger by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37542](https://github.com/BerriAI/litellm/pull/37542)
- fix(ci): gate backend unit tests on the pull request's own file list by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37550](https://github.com/BerriAI/litellm/pull/37550)
- chore(codeowners): require pricing owner approval for the model prices jsons by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37551](https://github.com/BerriAI/litellm/pull/37551)
- fix(proxy): initialize the secret manager before resolving os.environ config references by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37544](https://github.com/BerriAI/litellm/pull/37544)
- refactor(ui): swap [@​ant-design/icons](https://github.com/ant-design/icons) for lucide-react by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37553](https://github.com/BerriAI/litellm/pull/37553)
- refactor(ui): migrate shared primitives and common components off antd by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37521](https://github.com/BerriAI/litellm/pull/37521)
- fix(spend-logs): backfill created\_at/updated\_at from row endTime instead of migration time by [@​mateo-berri](https://github.com/mateo-berri) in [#​37554](https://github.com/BerriAI/litellm/pull/37554)
- refactor(ui): migrate the MCP servers pages off antd by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37522](https://github.com/BerriAI/litellm/pull/37522)
- fix(vertex\_ai): apply regional endpoint uplift to cost tracking by [@​mateo-berri](https://github.com/mateo-berri) in [#​37543](https://github.com/BerriAI/litellm/pull/37543)
- fix(proxy): populate deployment attribution on failed-request spend logs by [@​mateo-berri](https://github.com/mateo-berri) in [#​37520](https://github.com/BerriAI/litellm/pull/37520)
- refactor(ui): migrate the model and router settings pages off antd by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37523](https://github.com/BerriAI/litellm/pull/37523)
- perf(ci): gate the lint, MCP and dashboard jobs on the pull request's file list by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37559](https://github.com/BerriAI/litellm/pull/37559)
- feat(router): allow per-tier litellm\_params in complexity autorouter config by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37064](https://github.com/BerriAI/litellm/pull/37064)
- fix(anthropic): log partial stream spend when a /v1/messages client disconnects mid-stream by [@​mateo-berri](https://github.com/mateo-berri) in [#​37558](https://github.com/BerriAI/litellm/pull/37558)
- fix(ui): clear pass-through header rows when the create modal is reopened by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37549](https://github.com/BerriAI/litellm/pull/37549)
- fix(ui): render optional array and object MCP tool parameters as JSON inputs by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37548](https://github.com/BerriAI/litellm/pull/37548)
- feat(proxy)!: default audit logs on for enterprise licenses by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37518](https://github.com/BerriAI/litellm/pull/37518)
- feat(ui): standardize the Teams page header by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​36897](https://github.com/BerriAI/litellm/pull/36897)
- feat(ptu): accrue flat cost for PTU deployments declared in config.yaml by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37556](https://github.com/BerriAI/litellm/pull/37556)
- refactor(ui): migrate the last antd components off antd onto shadcn by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37569](https://github.com/BerriAI/litellm/pull/37569)
- chore(ui): drop the antd dependency and its leftovers by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37574](https://github.com/BerriAI/litellm/pull/37574)
- refactor(ui): map hardcoded Tailwind palette classes onto semantic tokens by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37576](https://github.com/BerriAI/litellm/pull/37576)
- fix(ptu): hand the prune a plain delete filter the query builder can serialise by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37571](https://github.com/BerriAI/litellm/pull/37571)
- feat(proxy): enqueued-token rate limiting for batches with refund on completion and cancellation by [@​mateo-berri](https://github.com/mateo-berri) in [#​37539](https://github.com/BerriAI/litellm/pull/37539)
- fix(ui): restore hover feedback and dark-mode variants lost in the token migration by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37579](https://github.com/BerriAI/litellm/pull/37579)
- fix(ci): run the full dashboard suite when a change reaches outside src/ by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37563](https://github.com/BerriAI/litellm/pull/37563)
- fix(ui): keep semantic button colours on hover after the no-op hover cleanup by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37580](https://github.com/BerriAI/litellm/pull/37580)
- fix: add supports\_mid\_conversation\_system to bare first-party Claude cost-map keys by [@​oneKn8](https://github.com/oneKn8) in [#​36969](https://github.com/BerriAI/litellm/pull/36969)
- feat: add bedrock grok 4.6 to model cost map by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37517](https://github.com/BerriAI/litellm/pull/37517)
- fix: preserve prompt cache for mid-conversation system on unflagged Claude models by [@​oneKn8](https://github.com/oneKn8) in [#​36968](https://github.com/BerriAI/litellm/pull/36968)
- fix(router): routed deployment's own litellm\_params beat forwarded auto\_router marker params by [@​mateo-berri](https://github.com/mateo-berri) in [#​37615](https://github.com/BerriAI/litellm/pull/37615)
- refactor(ci): fold the nine thin unit-shard callers into one matrix by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37590](https://github.com/BerriAI/litellm/pull/37590)
- chore(ci): close the test-census blind spots and move scripts out of workflows/ by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37586](https://github.com/BerriAI/litellm/pull/37586)
- test: retire tests/old\_proxy\_tests, which holds no tests by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37605](https://github.com/BerriAI/litellm/pull/37605)
- feat(ci): ratchet the test suite's zero-assert, mock-echo and global-state debt by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37588](https://github.com/BerriAI/litellm/pull/37588)
- feat(proxy): native CLI login with OAuth authorization code + PKCE by [@​mateo-berri](https://github.com/mateo-berri) in [#​37626](https://github.com/BerriAI/litellm/pull/37626)
- feat(prompt-caching): map cache\_control\_injection\_points to OpenAI prompt\_cache\_breakpoint on GPT-5.6+ targets by [@​mateo-berri](https://github.com/mateo-berri) in [#​37628](https://github.com/BerriAI/litellm/pull/37628)
- fix(realtime): bound Vertex credential resolution and make realtime failures loud by [@​mateo-berri](https://github.com/mateo-berri) in [#​37604](https://github.com/BerriAI/litellm/pull/37604)
- fix(anthropic): map metadata.user\_id to prompt\_cache\_key on the /v1/messages bridge by [@​mateo-berri](https://github.com/mateo-berri) in [#​37623](https://github.com/BerriAI/litellm/pull/37623)
- fix(passthrough): resolve vertex live credentials from db model deployments by [@​mateo-berri](https://github.com/mateo-berri) in [#​37602](https://github.com/BerriAI/litellm/pull/37602)
- fix(prompt\_management): don't route no-prompt\_id requests to prompt managers that can't run them by [@​mateo-berri](https://github.com/mateo-berri) in [#​37575](https://github.com/BerriAI/litellm/pull/37575)
- test: remove the five test functions a later definition shadows by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37591](https://github.com/BerriAI/litellm/pull/37591)
- feat(ci): guard shard assignment across every sharded test tree by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37593](https://github.com/BerriAI/litellm/pull/37593)
- feat(ui): multi-key shadow eval picker and per-key breakdown by [@​tin-berri](https://github.com/tin-berri) in [#​37389](https://github.com/BerriAI/litellm/pull/37389)
- fix(ui): make dark-mode form controls visible by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37648](https://github.com/BerriAI/litellm/pull/37648)
- fix(ui): give status colours a readable foreground and drop the muted 70% step by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37649](https://github.com/BerriAI/litellm/pull/37649)
- fix(ui): make inline styles and code blocks follow the theme by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37651](https://github.com/BerriAI/litellm/pull/37651)
- fix(ui): move the policy flow builder onto theme tokens by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37654](https://github.com/BerriAI/litellm/pull/37654)
- test: settle three allowlist entries that were open questions by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37598](https://github.com/BerriAI/litellm/pull/37598)
- feat(ci): ratchet tests that skip themselves when a credential is absent by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37612](https://github.com/BerriAI/litellm/pull/37612)
- feat(ci): catch files a -k expression deselects from every job by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37601](https://github.com/BerriAI/litellm/pull/37601)
- test: run the 30 test files stranded in the second mirror by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37595](https://github.com/BerriAI/litellm/pull/37595)
- fix(ui): make hardcoded palette surfaces theme-aware by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37650](https://github.com/BerriAI/litellm/pull/37650)
- feat(cli): store the lite login credential in the OS keychain by [@​mateo-berri](https://github.com/mateo-berri) in [#​37566](https://github.com/BerriAI/litellm/pull/37566)
- fix(ui): draw one Per Day savings bar per date on Cost Optimization by [@​tin-berri](https://github.com/tin-berri) in [#​37643](https://github.com/BerriAI/litellm/pull/37643)
- feat(mistral): add zai-glm-5-2 and glm-5-2 model pricing by [@​mubashir1osmani](https://github.com/mubashir1osmani) in [#​37110](https://github.com/BerriAI/litellm/pull/37110)
- feat(complexity\_router): add business classification rubric preset by [@​devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#​37534](https://github.com/BerriAI/litellm/pull/37534)
- feat(ui): serve a dark-mode variant of the LiteLLM logo by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37656](https://github.com/BerriAI/litellm/pull/37656)
- fix(otel): route Phoenix traces to per-key/team projects under otel v2 by [@​mubashir1osmani](https://github.com/mubashir1osmani) in [#​36706](https://github.com/BerriAI/litellm/pull/36706)
- test: replace blind sleeps with deadline waits in callback and caching tests by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37660](https://github.com/BerriAI/litellm/pull/37660)
- fix(cli): keep the --pkce refresh token in the OS keychain, not in token.json by [@​mateo-berri](https://github.com/mateo-berri) in [#​37665](https://github.com/BerriAI/litellm/pull/37665)
- fix(ui): keep keyword tier rules that target operator-defined tiers when hydrating the edit modal by [@​tin-berri](https://github.com/tin-berri) in [#​37413](https://github.com/BerriAI/litellm/pull/37413)
- feat(proxy): add POST /auto\_router/validate\_complexity\_router\_config to dry-run the complexity-router write gate by [@​tin-berri](https://github.com/tin-berri) in [#​37409](https://github.com/BerriAI/litellm/pull/37409)
- feat(ui): let admins supply a dark-mode variant of their custom logo by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37662](https://github.com/BerriAI/litellm/pull/37662)
- fix(proxy): run pre-call guardrails on batch input file uploads by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37519](https://github.com/BerriAI/litellm/pull/37519)
- feat(ui): add a light/dark/system theme toggle to the top bar by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37669](https://github.com/BerriAI/litellm/pull/37669)
- feat(proxy): redact or drop individual batch records instead of rejecting the file by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37561](https://github.com/BerriAI/litellm/pull/37561)
- refactor(ui): mark dark as beta in the theme menu instead of the toolbar by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37680](https://github.com/BerriAI/litellm/pull/37680)
- ci: lint the test tree for undefined names (F821) and fix all 30 by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37671](https://github.com/BerriAI/litellm/pull/37671)
- feat(e2e): move record/replay to the provider edge (LIT-5745) by [@​mateo-berri](https://github.com/mateo-berri) in [#​37565](https://github.com/BerriAI/litellm/pull/37565)
- fix(mcp): let a salt-key-orphaned OAuth credential be replaced by re-authorization by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37672](https://github.com/BerriAI/litellm/pull/37672)
- fix(mcp): normalize auth schemes so MCP egress emits exactly one prefix by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37668](https://github.com/BerriAI/litellm/pull/37668)
- test: add six ruff rules that catch tests which cannot fail by [@​ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#​37709](https://github.com/BerriAI/litellm/pull/37709)
- perf(ci): measure unit-shard coverage with the sys.monitoring core by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37589](https://github.com/BerriAI/litellm/pull/37589)
- test: merge three stranded twins into the files that shadow them by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37600](https://github.com/BerriAI/litellm/pull/37600)
- test(ci): reject coverage-allowlist entries that no longer match a file by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37608](https://github.com/BerriAI/litellm/pull/37608)
- feat(ci): assert .github/workflows holds only workflows, correctly named by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37616](https://github.com/BerriAI/litellm/pull/37616)
- feat(ci): freeze the conftest save/restore inventory so it can only shrink by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37621](https://github.com/BerriAI/litellm/pull/37621)
- fix(a2a): accept the whole JSON-RPC id union the spec defines by [@​yassin-berriai](https://github.com/yassin-berriai) in [#​37704](https://github.com/BerriAI/litellm/pull/37704)
- fix(ptu): refuse an incomplete config.yaml reservation the way the endpoints do by [@​yucheng-berri](https://github.com/yucheng-berri) in [#​37703](https://github.com/BerriAI/litellm/pull/37703)
- chore: bump litellm-enterprise 0.1.57 -> 0.1.58, litellm-proxy-extras 0.4.87 -> 0.4.88 by [@​yuneng-berri](https://github.com/yuneng-berri) in [#​37717](https://github.com/BerriAI/litellm/pull/37717)
- feat(perplexity): add Agent API third-party models by [@​mubashir1osmani](https://github.com/mubashir1osmani) in [#​37112](https://github.com/BerriAI/litellm/pull/37112)
- fix(ui): surface the paginated fallback on Cost Optimization by [@​tin-berri](https://github.com/tin-berri) in [#​37659](https://github.com/BerriAI/litellm/pull/37659)
- feat(shadow\_eval)!: gate the per-key budget on dollar spend instead of turns by [@​tin-berri](https://github.com/tin-berri) in [#​37555](https://github.com/BerriAI/litellm/pull/37555)
- feat(ui): per-model reasoning effort in the complexity tier editor by [@​tin-berri](https://github.com/tin-berri) in [#​37673](https://github.com/Berr…


TLDR
Problem this solves:
How it solves it:
User Flow
Before: a developer cancels an in-progress batch, the provider still completes part of it and serves the results, and the gateway never records any spend for that work
After: the same cancelled batch is billed for its completed work within one poll cycle
Relevant issues
Fixes #37156
Linear ticket
Resolves LIT-5663
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Live proxy against the real OpenAI batch API, real $$$. Both legs ran the identical flow in their own worktree with a fresh Postgres DB, exported
PROXY_BATCH_POLLING_INTERVAL=10(the interval the reporter used), a random free port, and this configNote on statuses: the issue's headline
expiredcase was already billed at the merge base (added by #35360), so the drop reproduces throughcancelled, which hits the identical branch: OpenAI batches only expire after a real 24h window, while a cancel finalizes with a partial output file in minutes. A billed control leg during the repro (a completed 300-request batch at 3b6ae75) recordedaretrieve_batchspend 0.0048375, showing the pipeline prices this exact output-file accounting whenever the status is billableThe PR tip b34cbb1 is a base-sync merge touching only uv.lock, so 2f9d331 is the last behavioral commit. The core-fix commit 2198410 was also independently proven with the same flow (356/2000 completed, billed $0.0057405, tokens matching the output file)
Before (badd737, the merge base)
gpt-5.4-mini-batch:curl -s -X POST "http://localhost:22679/v1/batches/$BATCH/cancel" -H "Authorization: Bearer $KEY"returns HTTP 200 with status cancelling"status": "cancelled","output_file_id": "file-HzaqhkCafEGvQoTpB2QRrm","request_counts": {"total": 2000, "completed": 142, "failed": 0}curl -s "http://localhost:22679/v1/batches/$BATCH" -H "Authorization: Bearer $KEY"shows status cancelled with a populated (unified) output_file_id and counts 142/0/2000GET /v1/files/{output_file_id}/contentwith the customer key returns HTTP 200 with 142 JSONL result lines totaling 2698 prompt + 568 completion = 3266 tokens of real billed workcurl -s "http://localhost:22679/spend/logs?request_id=$BATCH" -H "Authorization: Bearer $MASTER"shows only the $0acreate_batchrow (noaretrieve_batchrow), and/key/inforeports"spend": 0.0; both unchanged when re-checked 90 s later, after the proxy log'sCheckBatchCost: marked job 93dfe2e2-eec4-47fd-8199-1cdb0669e4ad as cancelled in DBretired the batch for goodAfter (2f9d331, the PR's last behavioral commit)
curl -s -X POST "http://localhost:43477/v1/batches/$BATCH/cancel" -H "Authorization: Bearer $KEY"returns HTTP 200 with status cancelling"status": "cancelled","output_file_id": "file-8pYJexZwE5bM66N5TL9oAg","request_counts": {"total": 2000, "completed": 437, "failed": 0}curl -s "http://localhost:43477/v1/batches/$BATCH" -H "Authorization: Bearer $KEY"shows status cancelled with a populated (unified) output_file_id and counts 437/0/2000GET /v1/files/{output_file_id}/contentreturns HTTP 200 with 437 JSONL result lines totaling 8303 prompt + 1748 completion = 10051 tokenscurl -s "http://localhost:43477/spend/logs?request_id=${BATCH}_batch_cost" -H "Authorization: Bearer $MASTER"shows anaretrieve_batchrow with"spend": 0.007046625and tokens 8303/1748/10051, exactly matching the output file, and/key/inforeports"spend": 0.007046625Observations from the runs:
_batch_costsuffix; leaves bug aloneType
🐛 Bug Fix
Caveats (if any)
Vertex AI advertises an output path for every batch, including terminal ones that never wrote it. Since 2f9d331 a terminal batch whose advertised output file 404s at the provider is retired unbilled on the first poll cycle instead of retrying until the staleness sweep. Ambiguous failures (the Vertex GCS downloader raises one error for 404, 403, and network blips alike) still retry and stay bounded by the 7-day sweep
A client that polls its batch through the proxy can still lose the spend: the status poll records the provider's terminal status on the gateway's tracking row, and the poller skips rows already recorded as cancelled or failed, so a poll landing between provider finalization and the next poller cycle (up to an hour apart by default) hides the batch from billing. That race predates this PR (at the merge base every ordering went unbilled, so this PR strictly improves and regresses nothing), needs its own fix (the poller's pickup set plus an upgrade guard against retroactively billing old terminal rows), and is filed with live proof as #37217
Final Attestation
Note
Medium Risk
Changes batch cost polling and spend attribution for terminal statuses; incorrect 404 detection could skip billing or retire jobs early, but behavior is scoped to CheckBatchCost with new unit tests.
Overview
Fixes CheckBatchCost so gateway spend matches provider batch work and terminal jobs do not poll forever.
Billing: Any provider-terminal batch (
completed,complete,failed,expired,cancelled) with anoutput_file_idnow goes through the same output fetch andaretrieve_batchcost path. Cancelled/failed batches that still produced partial results are billed instead of being finalized with zero spend.Retirement: Terminal batches whose advertised output 404s at the provider (e.g. Vertex paths with no file) are finalized unbilled on the first cycle via new
_is_output_file_gone_at_providerand_finalize_unbilled_terminal_job, instead of retrying until the staleness sweep.Refactor:
PROVIDER_TERMINAL_BATCH_STATUSEScentralizes terminal status checks; unbillable terminal handling is consolidated into_finalize_unbilled_terminal_job(managed file IDs +batch_processed). Tests cover billing for expired/cancelled/failed with output and 404 output retirement.Reviewed by Cursor Bugbot for commit b34cbb1. Bugbot is set up for automated code reviews on this repo. Configure here.