Skip to content

fix(conversations): Keep repeated user messages in transcript#119041

Merged
obostjancic merged 7 commits into
masterfrom
ognjenbostjancic/tet-2602-michis-second-message-does-not-show-up
Jul 7, 2026
Merged

fix(conversations): Keep repeated user messages in transcript#119041
obostjancic merged 7 commits into
masterfrom
ognjenbostjancic/tet-2602-michis-second-message-does-not-show-up

Conversation

@obostjancic

@obostjancic obostjancic commented Jul 6, 2026

Copy link
Copy Markdown
Member

A user message sent twice in separate turns was dropped from the transcript, even though it shows as two spans in the timeline.

User messages were deduplicated purely by content. That is only correct for cumulative SDKs, where a tool loop replays the same last message across spans in one turn. Non-cumulative SDKs send only the current message, so two spans with the same text are two genuine turns.

The fix deduplicates per generation based on gen_ai.input.messages: a single-message (non-cumulative) input is always kept, while cumulative inputs keep the existing dedup plus a user-message-count check for genuine repeats. Assistant dedup is unchanged, since duplicate assistant output within one turn still needs collapsing.

Fixes TET-2602

The transcript view deduplicated user messages purely by content, so when
a user genuinely sent the same message twice in separate turns, the second
occurrence was dropped and its assistant reply appeared to have no prompt.

Track the number of user messages in each generation's cumulative input
history. A tool-loop follow-up reuses the same last user message and keeps a
stable count, while a genuine repeat grows the count. Emit a user message
when the count grows, in addition to the existing content-based dedup, so
tool loops still collapse but real repeats are preserved.

Refs TET-2602
Co-Authored-By: Claude <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jul 6, 2026

Copy link
Copy Markdown

TET-2602

@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Jul 6, 2026
The transcript deduplicated user messages purely by content, so when a user
sent the same message twice in separate turns the second occurrence — and its
assistant reply — were dropped.

Deduplication only makes sense for cumulative SDKs, where a single turn's tool
loop replays the same last user message across several generation spans. With
non-cumulative SDKs each generation carries only the current message, so two
spans with identical content are two genuine turns.

Detect this per generation from the input history: a single-message input is
non-cumulative and is never deduplicated, while cumulative inputs keep the
existing content dedup plus a user-message-count check so genuine repeats in a
cumulative history are preserved too. The same single-message gate is applied
to assistant messages so an identical answer to a repeated question still
shows.

Refs TET-2602
Co-Authored-By: Claude <noreply@anthropic.com>
The single-message gate must not apply to assistant messages: a non-cumulative
SDK can emit the same assistant output across two spans within one turn, and
that duplicate still needs collapsing. Keep the original global assistant dedup
and scope the fix to user messages only.

Also fold the overlapping dedup test cases into it.each tables and tighten the
comments.

Refs TET-2602
Co-Authored-By: Claude <noreply@anthropic.com>
The MessagesPanel dedup test encoded the old single-message collapse. Reshape
it to the cumulative tool-loop case, where deduplicating a replayed last user
message is still correct.

Refs TET-2602
Co-Authored-By: Claude <noreply@anthropic.com>
Refs TET-2602
Co-Authored-By: Claude <noreply@anthropic.com>
@obostjancic obostjancic marked this pull request as ready for review July 6, 2026 12:21
@obostjancic obostjancic requested a review from a team as a code owner July 6, 2026 12:21
@priscilawebdev

Copy link
Copy Markdown
Member

hasInputHistory counts all messages including system (totalMessageCount = messages.length). So a non-cumulative SDK that prepends a system prompt sends [system, user] every turn → hasInputHistory = true (the always-keep path never fires) and userMessageCount stays 1 (so userCountGrew is false after turn 1). A genuinely repeated user message then falls through to content-dedup and gets dropped ... i.e. the exact bug this PR fixes, just whenever a system prompt is present. Should the counts be based on non-system messages instead of raw messages.length? Is the target SDK guaranteed not to include a system message in gen_ai.input.messages?

A non-cumulative SDK that prepends a system prompt sends [system, user]
every turn. The previous code counted all messages including system, so
totalMessageCount > 1 marked these as cumulative — causing genuine
repeated user messages to be dropped by content-dedup.

Exclude system messages from the count so [system, user] is correctly
recognised as single-message (non-cumulative) input.

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
@obostjancic obostjancic merged commit 33a668f into master Jul 7, 2026
72 checks passed
@obostjancic obostjancic deleted the ognjenbostjancic/tet-2602-michis-second-message-does-not-show-up branch July 7, 2026 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants