Skip to content

fix: capture every turn's gen_ai.output.messages (0.2.11)#23

Merged
Joshkop merged 1 commit into
mainfrom
fix/ai-conversations-output-capture
May 21, 2026
Merged

fix: capture every turn's gen_ai.output.messages (0.2.11)#23
Joshkop merged 1 commit into
mainfrom
fix/ai-conversations-output-capture

Conversation

@Joshkop
Copy link
Copy Markdown
Owner

@Joshkop Joshkop commented May 21, 2026

Summary

Sentry AI Conversations was showing every user input but only the first assistant output. Two compounding bugs:

  • Output capture raced the transcript flush. closeTurnSpan only ran on the next UserPromptSubmit (or SessionEnd). When the assistant text for turn N wasn't yet on disk at close time, tokens.response was null and gen_ai.output.messages was silently skipped — the existing 200 ms retry only triggered on zero token usage, not on missing text. Fix: wire the Stop hook (previously a no-op) to closeCurrentTurn — Stop fires right after assistant text lands. closeCurrentTurn is idempotent, so a later UserPromptSubmit / SessionEnd close is a harmless no-op. The retry also now triggers when recordOutputs is on and response is null.
  • Synthesized sessions misattributed responses. When the collector spawned (or self-healed) mid-session, record.turnIndex started at -1 while the transcript already held prior real turns. selectTurn's ordinal fallback would then attach an earlier turn's response to the current turn — visible today as a "how are you" turn surfacing turn 0's "Hi! How can I help today?" output. Fix: refuse ordinal matches under synthesis; record claude_code.usage_extraction.status = no_matching_turn_synthesized_ordinal so the gap is observable.

Two regression tests added. 426/426 green.

Test plan

  • pnpm test — 426/426 passing
  • pnpm build — clean
  • After merge + release: confirm in Sentry that the AI Conversations view shows every assistant message for a multi-turn session, not just the first

🤖 Generated with Claude Code

Two bugs combined to drop most assistant outputs from Sentry AI
Conversations:

1. closeTurnSpan only ran on the next UserPromptSubmit / SessionEnd,
   racing the transcript flush. If assistant text wasn't on disk at
   close time, tokens.response was null and gen_ai.output.messages
   was silently skipped — and the 200 ms retry only triggered on
   zero usage, not on missing text. Wire the Stop hook (was a no-op)
   to closeCurrentTurn; closeCurrentTurn is idempotent so the
   follow-up close is harmless. Extend the late-flush retry to also
   trigger when recordOutputs is on and response is null.

2. selectTurn's ordinal fallback misattributed an earlier transcript
   turn's response to the current turn when the collector spawned
   mid-session (synthesized=true, local turnIndex out of sync with
   transcript real-turn index). Refuse ordinal matches under
   synthesis and record usage_extraction.status =
   no_matching_turn_synthesized_ordinal so the gap is observable.

Adds two regression tests covering Stop-based close + the
synthesized-ordinal refusal. All 426 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Joshkop Joshkop merged commit 76b09f4 into main May 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant