Skip to content

Mid-stream resume duplicates the reasoning block on an empty-summary turn #1344

Description

@oztune

TanStack AI version

0.53.0

Framework/Library version

None (plain Node / @tanstack/ai-client 0.31.0)

Describe the bug and the steps to reproduce it

Reload the page while a reasoning turn is still streaming and the turn ends up with an extra "Thought for a few seconds" after the answer. Normal streaming and a full reload are both fine; only the mid-stream reconnect does it.

On the reconnect the client hydrates the saved message and then replays the run. The saved reasoning part has no stepId, because the store form drops it (modelMessageToUIMessage). The replay re-sends that reasoning's REASONING_ENCRYPTED_VALUE, which is keyed by stepId, and updateThinkingPart matches parts by stepId. It can't match the stepId-less hydrated part, so it appends a second thinking part after the text.

This only surfaces when the summary is empty (no REASONING_MESSAGE_CONTENT), so the thinking part exists only because of the encrypted value.

Steps: open the linked sandbox (it prints the result and also serves it on the preview). Same events, three reconstructions:

NORMAL STREAM : ["thinking","text"]
RESUME        : ["thinking","text","thinking"]   (extra trailing thinking)
DB RELOAD     : ["thinking","text"]

The resumed message's parts show it: the hydrated thinking with no stepId, and a duplicate keyed to the step.

thinking  stepId=null             content=""
text      "ASO = App Store Optimization."
thinking  stepId="openai-step-1"  content=""

Fix: on resume, match the replayed reasoning to the hydrated part even when it has no stepId, or carry the stepId through the store form so it can match. The match is in updateThinkingPart (activities/chat/stream/message-updaters.ts); the stepId is dropped in modelMessageToUIMessage (activities/chat/messages.ts).

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)

https://codesandbox.io/s/9nlkxm

Screenshots or Videos (Optional)

No response

Do you intend to try to help solve this bug with your own PR?

No, because I do not have time to dig into it

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions