Skip to content

MESSAGES_SNAPSHOT incorrectly replaces existing message ids #1107

Description

@kolaworld

TanStack AI version

0.44.0

Framework/Library version

@tanstack/ai-client: 0.23.2 | @tanstack/ai-persistence: 0.1.3 | @tanstack/ai-svelte: 0.16.2

Describe the bug and the steps to reproduce it

buildMessagesSnapshotChunk() always assigns a new id snapshot_<run>_<index> and never copies ModelMessage.id index.ts#L2145-L2172. The engine emits that snapshot at the native interrupt boundary index.ts#L2296.

A user message that already has a stable id therefore becomes snapshot_<run>_0 after the snapshot. StreamProcessor then adopts those ids: it already keeps a snapshot id when the wire message has one messages.ts#L512-L527. The client cannot recover the original identity once the server has overwritten it.

That breaks deduplication, reconciliation, and in-place rendering keyed on message.id. It is separate from the sequential client-tool resume race: the snapshot rewrite does not create the extra ordinary request. It only makes that request's existing user message look like new input.

Issue #1063 / PR #1066 fixed UI → model conversion so client-supplied ids copy onto ModelMessage.

Issue #1087 / PR #1101 covers engine-constructed assistant turns that never get an id. This path discards an id that is already present.

Expected behavior

A fix would keep message.id on the snapshot when it is present and generate snapshot_<run>_<index> only when it is absent. That matches the client normalizer, which already prefers the wire id and generates one only as a fallback.

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)

https://stackblitz.com/edit/vitejs-vite-pnftan6t?file=package.json,index.html,src%2Fmain.ts

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    has-prAn open PR references this issuewaiting-on: maintainerThe ball is in the maintainers’ court

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions