Skip to content

fix(ai-persistence): make RunStore.findActiveRun required - #1004

Merged
tombeckenham merged 1 commit into
mainfrom
fix/run-store-find-active-run-required
Jul 28, 2026
Merged

fix(ai-persistence): make RunStore.findActiveRun required#1004
tombeckenham merged 1 commit into
mainfrom
fix/run-store-find-active-run-required

Conversation

@tombeckenham

@tombeckenhamtombeckenham commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

🎯 Changes

findActiveRun was optional on the RunStore contract and feature-detected at the call site (store.findActiveRun?.(threadId)). That made a backend which hadn't implemented it indistinguishable from one whose thread is genuinely idle — both answer null — so reconnect silently turned off in production instead of failing at build time. A client reloading (or switching back to) a still-generating thread restored the transcript but never resumed the live reply, with nothing to detect it.

  • Make findActiveRunrequired on RunStore; drop the optional call in reconstructChat.
  • Record the evolution policy in types.ts: store methods are required, and capability tiers belong at the store level (omit runs, declare ChatTranscriptStores) — never at the method level. An absent store is caught by the type system; an incomplete one fails silently at runtime.
  • Drop the conformance skip so every backend providing runs must satisfy the invariants (most-recent-running wins, thread-scoped, null when idle); implement findActiveRun in the test fixture store.
  • Update the adapter guide, the ai-persistence stores skill, and the defineRunStore changeset accordingly.
  • Enable migrate: true in the ts-react-chat persistent store example.

Breaking for adapter authors: any external RunStore implementation without findActiveRun now gets a compile error — which is the point.

✅ 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

    • Active-run detection is now required for persistence adapters, enabling reconnection to in-progress replies without a client-held run ID.
    • SQLite persistence examples now enable automatic schema migration on first database open.
  • Bug Fixes

    • Active runs are consistently identified by selecting the most recently started running reply.
    • Invalid adapters now fail clearly instead of silently appearing idle.
  • Documentation

    • Updated adapter guidance, examples, and contract documentation to reflect required active-run support and handling for backends without run lifecycle tracking.

`findActiveRun` was optional on the `RunStore` contract and feature-detected
at the call site (`store.findActiveRun?.(threadId)`). That made a backend
which had not implemented it indistinguishable from one whose thread is
genuinely idle — both answer `null` — so reconnect silently turned off in
production instead of failing at build time.
- Make `findActiveRun` required on `RunStore`; drop the optional call in
`reconstructChat`.
- Record the evolution policy in `types.ts`: store methods are required,
capability tiers belong at the store level (omit `runs`, declare
`ChatTranscriptStores`), never at the method level.
- Drop the conformance skip so every backend providing `runs` must satisfy
the invariants; implement `findActiveRun` in the test fixture store.
- Update the adapter guide, the stores skill, and the changeset accordingly.
- Enable `migrate: true` in the ts-react-chat persistent store example.
@coderabbitai

coderabbitaiBot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

RunStore.findActiveRun is now required when a runs store is provided. Reconstruction calls it directly, conformance fixtures implement latest-running-run lookup, documentation reflects the contract, and the SQLite example enables migrations.

Changes

RunStore contract enforcement

Layer / File(s)Summary
Required active-run contract
.changeset/*, packages/ai-persistence/src/types.ts, packages/ai-persistence/skills/..., docs/persistence/...
findActiveRun is required, must return the latest running run or null, and stores without run lifecycle should omit runs.
Active-run lookup enforcement
packages/ai-persistence/src/reconstruct.ts, packages/ai-persistence/src/testkit/conformance.ts, packages/ai-persistence/tests/persistence-fixtures.ts
Reconstruction invokes findActiveRun directly; conformance tests and fixtures require and implement the lookup.
SQLite example initialization
examples/ts-react-chat/src/lib/persistent-chat-store.ts, docs/config.json
The SQLite example enables migrations and the related documentation timestamp is updated.

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

Possibly related PRs

  • TanStack/ai#984: Introduces reconstructChat, which this change updates to use required active-run lookup.

Suggested reviewers:alemtuzlak

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 75.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 summarizes the main change: making RunStore.findActiveRun required.
Description check✅ PassedThe description follows the template with Changes, Checklist, and Release Impact sections and includes the key migration and breaking-change context.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/run-store-find-active-run-required

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.

@tombeckenham
tombeckenham requested review from a team and AlemTuzlakJuly 27, 2026 23:47
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

16 package(s) bumped directly, 34 bumped as dependents.

🟥 Major bumps

PackageVersionReason
@tanstack/ai-angular0.3.1 → 1.0.0Changeset
@tanstack/ai-durable-stream0.0.0 → 1.0.0Changeset
@tanstack/ai-memory0.0.0 → 1.0.0Changeset
@tanstack/ai-openrouter0.15.10 → 1.0.0Changeset
@tanstack/ai-persistence0.0.0 → 1.0.0Changeset
@tanstack/ai-preact0.11.1 → 1.0.0Changeset
@tanstack/ai-react0.18.1 → 1.0.0Changeset
@tanstack/ai-sandbox0.2.4 → 1.0.0Changeset
@tanstack/ai-solid0.15.1 → 1.0.0Changeset
@tanstack/ai-svelte0.15.1 → 1.0.0Changeset
@tanstack/ai-vue0.15.1 → 1.0.0Changeset
@tanstack/ai-acp0.2.3 → 1.0.0Dependent
@tanstack/ai-anthropic0.16.3 → 1.0.0Dependent
@tanstack/ai-bedrock0.1.4 → 1.0.0Dependent
@tanstack/ai-claude-code0.2.3 → 1.0.0Dependent
@tanstack/ai-code-mode0.3.8 → 1.0.0Dependent
@tanstack/ai-code-mode-skills0.3.11 → 1.0.0Dependent
@tanstack/ai-codex0.2.3 → 1.0.0Dependent
@tanstack/ai-elevenlabs0.2.34 → 1.0.0Dependent
@tanstack/ai-fal0.9.12 → 1.0.0Dependent
@tanstack/ai-gemini0.20.1 → 1.0.0Dependent
@tanstack/ai-grok0.14.9 → 1.0.0Dependent
@tanstack/ai-grok-build0.2.3 → 1.0.0Dependent
@tanstack/ai-groq0.5.3 → 1.0.0Dependent
@tanstack/ai-isolate-node0.1.47 → 1.0.0Dependent
@tanstack/ai-isolate-quickjs0.1.47 → 1.0.0Dependent
@tanstack/ai-mistral0.2.3 → 1.0.0Dependent
@tanstack/ai-ollama0.8.16 → 1.0.0Dependent
@tanstack/ai-openai0.17.1 → 1.0.0Dependent
@tanstack/ai-opencode0.2.3 → 1.0.0Dependent
@tanstack/ai-react-ui0.8.15 → 1.0.0Dependent
@tanstack/ai-sandbox-cloudflare0.2.4 → 1.0.0Dependent
@tanstack/ai-sandbox-daytona0.2.0 → 1.0.0Dependent
@tanstack/ai-sandbox-docker0.2.0 → 1.0.0Dependent
@tanstack/ai-sandbox-local-process0.2.0 → 1.0.0Dependent
@tanstack/ai-sandbox-sprites0.2.1 → 1.0.0Dependent
@tanstack/ai-sandbox-vercel0.2.0 → 1.0.0Dependent
@tanstack/ai-solid-ui0.7.14 → 1.0.0Dependent
@tanstack/openai-base0.9.9 → 1.0.0Dependent

🟨 Minor bumps

PackageVersionReason
@tanstack/ai0.42.0 → 0.43.0Changeset
@tanstack/ai-client0.22.1 → 0.23.0Changeset
@tanstack/ai-devtools-core0.4.24 → 0.5.0Changeset
@tanstack/ai-event-client0.6.8 → 0.7.0Changeset

🟩 Patch bumps

PackageVersionReason
@tanstack/ai-mcp0.2.5 → 0.2.6Changeset
@tanstack/ai-isolate-cloudflare0.2.38 → 0.2.39Dependent
@tanstack/ai-vue-ui0.2.34 → 0.2.35Dependent
@tanstack/preact-ai-devtools0.1.67 → 0.1.68Dependent
@tanstack/react-ai-devtools0.2.67 → 0.2.68Dependent
@tanstack/solid-ai-devtools0.2.67 → 0.2.68Dependent
ag-ui0.0.2 → 0.0.3Dependent

@nx-cloud

nx-cloudBot commented Jul 27, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit e83018c

CommandStatusDurationResult
nx affected --targets=test:sherif,test:knip,tes...✅ Succeeded42sView ↗
nx run-many --targets=build --exclude=examples/...✅ Succeeded3sView ↗

☁️ Nx Cloud last updated this comment at 2026-07-27 23:50:02 UTC

@pkg-pr-new

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

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

@tanstack/ai-acp

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

@tanstack/ai-angular

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

@tanstack/ai-anthropic

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

@tanstack/ai-bedrock

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

@tanstack/ai-claude-code

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

@tanstack/ai-client

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

@tanstack/ai-code-mode

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

@tanstack/ai-code-mode-skills

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

@tanstack/ai-codex

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

@tanstack/ai-devtools-core

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

@tanstack/ai-durable-stream

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

@tanstack/ai-elevenlabs

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

@tanstack/ai-event-client

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

@tanstack/ai-fal

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

@tanstack/ai-gemini

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

@tanstack/ai-grok

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

@tanstack/ai-grok-build

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

@tanstack/ai-groq

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

@tanstack/ai-isolate-cloudflare

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

@tanstack/ai-isolate-node

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

@tanstack/ai-isolate-quickjs

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

@tanstack/ai-mcp

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

@tanstack/ai-memory

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

@tanstack/ai-mistral

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

@tanstack/ai-ollama

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

@tanstack/ai-openai

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

@tanstack/ai-opencode

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

@tanstack/ai-openrouter

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

@tanstack/ai-persistence

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

@tanstack/ai-preact

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

@tanstack/ai-react

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

@tanstack/ai-react-ui

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

@tanstack/ai-sandbox

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

@tanstack/ai-sandbox-cloudflare

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

@tanstack/ai-sandbox-daytona

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

@tanstack/ai-sandbox-docker

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

@tanstack/ai-sandbox-local-process

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

@tanstack/ai-sandbox-sprites

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

@tanstack/ai-sandbox-vercel

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

@tanstack/ai-solid

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

@tanstack/ai-solid-ui

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

@tanstack/ai-svelte

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

@tanstack/ai-utils

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

@tanstack/ai-vue

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

@tanstack/ai-vue-ui

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

@tanstack/openai-base

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

@tanstack/preact-ai-devtools

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

@tanstack/react-ai-devtools

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

@tanstack/solid-ai-devtools

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

commit: e83018c

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/config.json`:
- Line 269: Update the updatedAt field in the documentation configuration to use
today’s review date, 2026-07-27, instead of the future date 2026-07-28.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 213dd69f-61ae-4151-8051-aeb565fe1628

📥 Commits

Reviewing files that changed from the base of the PR and between 4ab149f and e83018c.

📒 Files selected for processing (10)
  • .changeset/define-store-helpers.md
  • .changeset/run-store-find-active-run-required.md
  • docs/config.json
  • docs/persistence/build-your-own-adapter.md
  • examples/ts-react-chat/src/lib/persistent-chat-store.ts
  • packages/ai-persistence/skills/ai-persistence/stores/SKILL.md
  • packages/ai-persistence/src/reconstruct.ts
  • packages/ai-persistence/src/testkit/conformance.ts
  • packages/ai-persistence/src/types.ts
  • packages/ai-persistence/tests/persistence-fixtures.ts

Comment threaddocs/config.json
"to": "persistence/build-your-own-adapter",
"addedAt": "2026-07-24",
"updatedAt": "2026-07-27"
"updatedAt": "2026-07-28"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use today’s date for updatedAt.

The current review date is July 27, 2026, but this value is future-dated as 2026-07-28. Change it to 2026-07-27.

As per coding guidelines, documentation timestamps must use today’s date for content changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/config.json` at line 269, Update the updatedAt field in the
documentation configuration to use today’s review date, 2026-07-27, instead of
the future date 2026-07-28.

Source: Coding guidelines

@tombeckenhamtombeckenham added the persistence Durable chat state: @tanstack/ai-persistence, client persistence, adapters, locks label Jul 28, 2026
@tombeckenham
tombeckenham merged commit 1120f0f into mainJul 28, 2026
10 checks passed
@tombeckenham
tombeckenham deleted the fix/run-store-find-active-run-required branch July 28, 2026 03:57
AlemTuzlak added a commit that referenced this pull request Jul 31, 2026
main squash-merged the two PRs this branch was stacked on (#988 sandbox
instance durability, #1011 generation run persistence), so this branch's own
copy of that foundation collided with the squashes. 17 files conflicted.
Notable resolutions, beyond taking the union:
- #1004 made `RunStore.findActiveRun` REQUIRED, and main added an explicit
store-contract evolution policy naming that exact regression. This branch had
relocated `RunStore` into `@tanstack/ai` with `findActiveRun?` optional, and
`run-store.ts` merged CLEANLY -- so keeping our side would have silently
reverted #1004. `findActiveRun` is now required in core too, dropped from the
conformance suite's `skipMethods` union, and `fenceRunStore` forwards it
unconditionally. `listByThread`/`listReclaimable` stay optional.
- Generation persistence moved to main's `generationRuns` store, but main writes
`status: 'interrupted'` with a `finishedAt` on abort. This branch made
`interrupted` non-terminal ("parked, waiting for a human"), so that pairing
would leave an aborted generation looking permanently active. Now writes
`'aborted'`.
- `snapshotStatus` in `reconstruct-generation.ts` switched exhaustively over the
old 4-member `RunStatus`; ours adds `aborted`, so an aborted generation fell
through and the function returned `undefined`. Now maps to `'error'`.
- `chat-persistence.md`: kept main's new lifecycle mermaid diagram, corrected to
the current semantics (completed/failed/aborted terminal, interrupted parked,
detached stays running).
- `docs/sandbox/durability.md`: kept our real `import` over main's
`declare const`, per the repo's kiira snippet rule.
Verified: 17 typechecks green (including examples/ts-react-chat and
testing/e2e), oxlint green, kiira 911/911, test:docs, sherif, knip and oxfmt all
clean. Unit: ai 1409, ai-persistence 150, ai-client 585, ai-react 176,
ai-durable-stream 45, ai-sandbox 602/603 (pre-existing Windows path case).
E2E not run: port 4010 is held by an unrelated showcase-aimock container and
another worktree's in-flight Playwright run.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

persistenceDurable chat state: @tanstack/ai-persistence, client persistence, adapters, locks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tombeckenham@jherr