Skip to content

fix(ai-persistence): ignore empty TEXT_MESSAGE_START message ids so they are not stored - #1117

Merged
tombeckenham merged 5 commits into
TanStack:mainfrom
kolaworld:fix/1087-empty-text-message-start-id
Aug 18, 2026
Merged

fix(ai-persistence): ignore empty TEXT_MESSAGE_START message ids so they are not stored#1117
tombeckenham merged 5 commits into
TanStack:mainfrom
kolaworld:fix/1087-empty-text-message-start-id

Conversation

@kolaworld

@kolaworldkolaworld commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

🎯 Changes

  • Ignore empty TEXT_MESSAGE_START messageId values in persistence so they are not stored as the in-progress stream id.
  • That leaves streamingMessageId unset, so a later TOOL_CALL_START can still apply parentMessageId.
  • Regression: empty start id + parentMessageId: 'stream-assistant' + mid-stream crash with snapshotStreaming still persists id: 'stream-assistant'.

✅ 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

  • Bug Fixes

    • Fixed streaming persistence when text message IDs are empty.
    • Preserved the correct assistant message association for tool calls and partial responses, including interrupted or failed streams.
    • Prevented message associations from carrying over incorrectly between turns.
  • Tests

    • Added regression coverage for interrupted streaming, failed snapshots, tool-call workflows, and multi-turn conversations.

An empty start id was stored and blocked the TOOL_CALL_START parentMessageId fallback.
@coderabbitai

coderabbitaiBot commented Aug 15, 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: 99c378b8-2e14-410c-acbf-164bc93a560a

📥 Commits

Reviewing files that changed from the base of the PR and between 4eebc69 and 58183f0.

📒 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 (1)
  • packages/ai-persistence/src/middleware.ts

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


📝 Walkthrough

Walkthrough

The persistence middleware ignores empty TEXT_MESSAGE_START message IDs. Tests verify tool-call parent ID preservation, partial snapshots after failures, and streaming state reset across turns. A patch changeset documents the fix.

Changes

Streaming persistence

Layer / File(s)Summary
Preserve non-empty streaming message IDs
packages/ai-persistence/src/middleware.ts, packages/ai-persistence/tests/with-persistence.test.ts, .changeset/fix-empty-text-message-start-id.md
The middleware stores only non-empty chunk.messageId values. Regression tests cover tool-call linkage, partial output, mid-stream failure, and multi-turn state reset. The changeset documents the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk:⚪ Minimal · up to 58183

This localized persistence change prevents empty stream message IDs from being stored while preserving later parent-message association; no actionable merge-blocking risk remains after normal checks.

Suggested reviewers:alemtuzlak, mikemikimike

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description check✅ PassedThe description covers the change, motivation, regression case, checklist, testing, and release impact, and it includes the required changeset.
Title check✅ PassedThe title clearly and concisely describes the main fix: ignoring empty TEXT_MESSAGE_START message IDs in ai-persistence.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 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.

@github-actionsgithub-actionsBot added the waiting-on: maintainer The ball is in the maintainers’ court label Aug 15, 2026
@nx-cloud

nx-cloudBot commented Aug 17, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 8b4eccf

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

☁️ Nx Cloud last updated this comment at 2026-08-17 23:45:02 UTC

@pkg-pr-new

pkg-pr-newBot commented Aug 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

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

@tanstack/ai-acp

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

@tanstack/ai-angular

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

@tanstack/ai-anthropic

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

@tanstack/ai-bedrock

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

@tanstack/ai-byteplus

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

@tanstack/ai-claude-code

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

@tanstack/ai-client

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

@tanstack/ai-code-mode

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

@tanstack/ai-code-mode-snippets

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

@tanstack/ai-codex

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

@tanstack/ai-cohere

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

@tanstack/ai-devtools-core

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

@tanstack/ai-durable-stream

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

@tanstack/ai-elevenlabs

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

@tanstack/ai-event-client

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

@tanstack/ai-fal

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

@tanstack/ai-gemini

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

@tanstack/ai-grok

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

@tanstack/ai-grok-build

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

@tanstack/ai-groq

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

@tanstack/ai-isolate-cloudflare

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

@tanstack/ai-isolate-daytona

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

@tanstack/ai-isolate-node

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

@tanstack/ai-isolate-quickjs

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

@tanstack/ai-isolate-quickjs-bun

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

@tanstack/ai-mcp

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

@tanstack/ai-memory

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

@tanstack/ai-mistral

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

@tanstack/ai-ollama

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

@tanstack/ai-openai

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

@tanstack/ai-opencode

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

@tanstack/ai-openrouter

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

@tanstack/ai-perplexity

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

@tanstack/ai-persistence

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

@tanstack/ai-preact

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

@tanstack/ai-react

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

@tanstack/ai-react-ui

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

@tanstack/ai-sandbox

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

@tanstack/ai-sandbox-cloudflare

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

@tanstack/ai-sandbox-daytona

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

@tanstack/ai-sandbox-docker

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

@tanstack/ai-sandbox-local-process

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

@tanstack/ai-sandbox-sprites

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

@tanstack/ai-sandbox-vercel

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

@tanstack/ai-solid

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

@tanstack/ai-solid-ui

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

@tanstack/ai-svelte

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

@tanstack/ai-utils

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

@tanstack/ai-vercel-gateway

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

@tanstack/ai-vue

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

@tanstack/ai-vue-ui

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

@tanstack/openai-base

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

@tanstack/preact-ai-devtools

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

@tanstack/react-ai-devtools

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

@tanstack/solid-ai-devtools

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

commit: 58183f0

…tarts
Gate only the streamingMessageId capture on a non-empty (and string-typed)
messageId instead of skipping the whole TEXT_MESSAGE_START branch. Skipping
the branch also skipped the per-turn reset of streamingText and
streamingMessageCreatedAt, so in a multi-turn agent run with empty-id starts
a crash-window snapshot persisted turn 1's text concatenated with turn 2's,
stamped with turn 1's tool-call id — two persisted messages sharing one id.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tombeckenham
tombeckenham self-requested a review August 17, 2026 23:43

@tombeckenhamtombeckenham 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.

Thanks for this. Corrected the guard and approving

@tombeckenham
tombeckenham merged commit 3e94871 into TanStack:mainAug 18, 2026
9 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 17, 2026
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.

3 participants

@kolaworld@AlemTuzlak@tombeckenham