Scope round-reasoning dedup to a positional match; omit phantom empty turns in the plain flow too
The substring fallback for matching a round's persisted reasoning
against the extracted <think> parts scanned the entire remainingParts
array and deleted every part merely containing it as a substring. A
short, unrelated final reasoning block (e.g. "weather") could be
silently deleted just because an earlier round's mismatched reasoning
happened to contain it as a substring (e.g. "Need weather forecast").
Parts are chronologically ordered and rounds are processed oldest-first,
so only the earliest still-unconsumed part can be attributed to the
current round when exact match fails; the fallback no longer scans past
it.
The plain (non-tool-replay) reasoning-attachment branch had the same
phantom-empty-message issue already fixed on the tool-replay path: a
turn interrupted before any visible text, with reasoning gated off or
producer-mismatched, replayed as {role: assistant, content: ""} with
nothing else attached. Omitted entirely in that case, matching the
tool-replay fix.