Skip to content

fix(ai-persistence): persist chat run usage - #1129

Merged
AlemTuzlak merged 3 commits into
TanStack:mainfrom
kolaworld:fix/1128-persist-chat-run-usage
Aug 18, 2026
Merged

fix(ai-persistence): persist chat run usage#1129
AlemTuzlak merged 3 commits into
TanStack:mainfrom
kolaworld:fix/1128-persist-chat-run-usage

Conversation

@kolaworld

@kolaworldkolaworld commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Fixes#1128

🎯 Changes

  • Accumulates usage across every provider call in a chat invocation.
  • Persists known usage when a run completes, interrupts, fails, or aborts.
  • Preserves accumulated usage across same-run continuations.
  • Sums numeric usage fields while retaining the latest opaque providerUsageDetails.
  • Continues omitting usage when the adapter reports none.
  • Updates store conformance, persistence tests, provider-free E2E coverage, and documentation.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features

    • Chat runs now retain and accumulate token usage across multiple model calls, tool calls, interruptions, failures, aborts, and resumed executions.
    • Persisted usage includes prompt, completion, and total token counts, while preserving the latest provider-specific details.
    • Interrupted runs can resume with their previously recorded usage.
  • Bug Fixes

    • Usage is no longer lost when runs are cancelled or fail during structured-output processing.
  • Documentation

    • Expanded guidance on usage reporting, run lifecycle behavior, continuation, and persistence semantics.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ea2be4b6-ad2f-4ffa-8586-1a5b27c7614a

📥 Commits

Reviewing files that changed from the base of the PR and between 2c6d142 and 9fa0e0b.

📒 Files selected for processing (2)
  • packages/ai-persistence/src/middleware.ts
  • packages/ai-persistence/tests/with-persistence.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ai-persistence/tests/with-persistence.test.ts
  • packages/ai-persistence/src/middleware.ts

Included review availability: Your plan includes up to 8 reviews per rolling hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The persistence middleware now aggregates token usage across provider calls and preserves it through interrupted, completed, failed, and aborted runs. Tests, an end-to-end scenario, documentation, and a patch changeset cover the behavior.

Changes

Usage persistence

Layer / File(s)Summary
Middleware usage lifecycle
packages/ai-persistence/src/middleware.ts
Run state restores stored usage, accumulates numeric and provider-specific usage, and persists it across lifecycle transitions.
Persistence behavior validation
packages/ai-persistence/src/testkit/conformance.ts, packages/ai-persistence/tests/*
Tests verify cumulative usage, idempotent resumption, and retention across interrupted, failed, aborted, tool-call, and structured-output runs.
End-to-end usage scenario
testing/e2e/src/routes/api.persistence-durability.ts, testing/e2e/tests/persistence-durability.spec.ts
The durability route performs two persisted calls and validates cumulative token usage through an end-to-end test.
Persistence documentation and release metadata
docs/persistence/*, packages/ai-persistence/skills/ai-persistence/stores/SKILL.md, .changeset/persist-chat-run-usage.md
Documentation describes usage aggregation, lifecycle persistence, continuation behavior, and unchanged run restoration. A patch changeset records the package release.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk:⚪ Minimal · up to 9fa0e

This change persists accumulated chat-run usage across completion, interruption, failure, abort, and continuation paths; no actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
participant ChatEngine
participant withPersistence
participant RunRecord
ChatEngine->>withPersistence: emit usage for each provider call
withPersistence->>withPersistence: accumulate usage
withPersistence->>RunRecord: persist aggregate at interruption or terminal state
RunRecord-->>withPersistence: restore usage for continuation
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 25.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly and concisely describes the primary change: persisting chat run usage in ai-persistence.
Description check✅ PassedThe description explains the changes, confirms both checklist items, and identifies the published-code release impact and changeset.
Linked Issues check✅ PassedThe implementation addresses issue #1128 by aggregating and persisting usage across calls, interruptions, continuations, failures, and aborts.
Out of Scope Changes check✅ PassedThe code, tests, end-to-end coverage, documentation, and changeset changes directly support the linked issue and pull request objectives.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kolaworldkolaworld changed the title Fix/1128 persist chat run usagefix(ai-persistence): persist chat run usageAug 17, 2026
@github-actionsgithub-actionsBot added the waiting-on: maintainer The ball is in the maintainers’ court label Aug 18, 2026
@nx-cloud

nx-cloudBot commented Aug 18, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 9fa0e0b

CommandStatusDurationResult
nx run-many --targets=build --exclude=examples/...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2026-08-18 14:19:34 UTC

@pkg-pr-new

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai@1129

@tanstack/ai-acp

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-acp@1129

@tanstack/ai-angular

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-angular@1129

@tanstack/ai-anthropic

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-anthropic@1129

@tanstack/ai-bedrock

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-bedrock@1129

@tanstack/ai-byteplus

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-byteplus@1129

@tanstack/ai-claude-code

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-claude-code@1129

@tanstack/ai-client

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-client@1129

@tanstack/ai-code-mode

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-code-mode@1129

@tanstack/ai-code-mode-snippets

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-code-mode-snippets@1129

@tanstack/ai-codex

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-codex@1129

@tanstack/ai-cohere

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-cohere@1129

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-devtools-core@1129

@tanstack/ai-durable-stream

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-durable-stream@1129

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-elevenlabs@1129

@tanstack/ai-event-client

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-event-client@1129

@tanstack/ai-fal

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-fal@1129

@tanstack/ai-gemini

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-gemini@1129

@tanstack/ai-grok

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-grok@1129

@tanstack/ai-grok-build

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-grok-build@1129

@tanstack/ai-groq

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-groq@1129

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-isolate-cloudflare@1129

@tanstack/ai-isolate-daytona

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-isolate-daytona@1129

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-isolate-node@1129

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-isolate-quickjs@1129

@tanstack/ai-isolate-quickjs-bun

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-isolate-quickjs-bun@1129

@tanstack/ai-mcp

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-mcp@1129

@tanstack/ai-memory

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-memory@1129

@tanstack/ai-mistral

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-mistral@1129

@tanstack/ai-ollama

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-ollama@1129

@tanstack/ai-openai

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-openai@1129

@tanstack/ai-opencode

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-opencode@1129

@tanstack/ai-openrouter

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-openrouter@1129

@tanstack/ai-perplexity

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-perplexity@1129

@tanstack/ai-persistence

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-persistence@1129

@tanstack/ai-preact

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-preact@1129

@tanstack/ai-react

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-react@1129

@tanstack/ai-react-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-react-ui@1129

@tanstack/ai-sandbox

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-sandbox@1129

@tanstack/ai-sandbox-cloudflare

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-sandbox-cloudflare@1129

@tanstack/ai-sandbox-daytona

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-sandbox-daytona@1129

@tanstack/ai-sandbox-docker

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-sandbox-docker@1129

@tanstack/ai-sandbox-local-process

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-sandbox-local-process@1129

@tanstack/ai-sandbox-sprites

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-sandbox-sprites@1129

@tanstack/ai-sandbox-vercel

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-sandbox-vercel@1129

@tanstack/ai-solid

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-solid@1129

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-solid-ui@1129

@tanstack/ai-svelte

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-svelte@1129

@tanstack/ai-utils

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-utils@1129

@tanstack/ai-vercel-gateway

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-vercel-gateway@1129

@tanstack/ai-vue

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-vue@1129

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-vue-ui@1129

@tanstack/openai-base

npm i https://pkg.pr.new/TanStack/ai/@tanstack/openai-base@1129

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/preact-ai-devtools@1129

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/react-ai-devtools@1129

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/solid-ai-devtools@1129

commit: 9fa0e0b

@AlemTuzlak
AlemTuzlak merged commit 302c9f6 into TanStack:mainAug 18, 2026
9 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 18, 2026
AlemTuzlak added a commit that referenced this pull request Aug 18, 2026
Resolved 4 conflicts. Both sides were kept in every case:
- packages/ai/src/adapter-internals.ts
Additive on both sides. Kept the interrupt exports and main's
structured-output-text / structured-output-events exports.
- packages/ai-persistence/src/middleware.ts (onFinish)
Kept this branch's try/catch and its saveThread -> commitPendingResumes
-> completeRun order, so a failed batch write still calls failRun and
leaves pending resumes retryable. Took main's accumulated usage from
#1129: completeRun now gets `state?.usage ?? info.usage`, and failRun in
the catch gets `state?.usage` so every terminal path persists usage the
same way onError already does.
- packages/ai-persistence/tests/interrupts.test.ts
Unioned the imports. Kept this branch's schema fixtures and the
isInterruptFinished predicate, plus main's usage-aware
interruptFinished(runId, usage) signature.
- docs/persistence/chat-persistence.md
Kept this branch's atomic-commitBatch and legacy-sequential-fallback
paragraphs and folded in main's sentence about terminal paths retaining
usage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on: maintainerThe ball is in the maintainers’ court

Projects

None yet

Development

Successfully merging this pull request may close these issues.

withPersistence drops usage from interrupted and multi-call chat runs

2 participants

@kolaworld@AlemTuzlak