fix(claude-transcript): skip internal Claude record types in transcripts#206
fix(claude-transcript): skip internal Claude record types in transcripts#206danljungstrom wants to merge 1 commit into
Conversation
WalkthroughClaude transcript handling now filters additional internal event types, and UI normalization identifies unknown agent output types in fallback text. ChangesTranscript filtering and output normalization
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR filters new internal Claude records from transcripts and improves unknown-output diagnostics. The main changes are:
Confidence Score: 5/5The changed flow looks mergeable after a small localization cleanup.
apps/ui/sources/sync/typesRaw/normalize.ts
|
| Filename | Overview |
|---|---|
| apps/cli/src/backends/claude/utils/internalClaudeEventTypes.ts | Adds four non-conversational Claude record types to the shared internal-event filter. |
| apps/cli/src/backends/claude/utils/readClaudeSessionJsonlMessages.test.ts | Confirms the JSONL reader drops the new internal records while retaining conversation content. |
| apps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.ts | Confirms the SDK converter returns no transcript output for each new internal record type. |
| apps/ui/sources/sync/typesRaw/normalize.ts | Adds the unknown payload type to the fallback transcript label, but leaves the user-visible template untranslated. |
| apps/ui/sources/sync/typesRaw/normalize.outputInvalidKnownTypeFallback.test.ts | Verifies that the fallback label includes an unknown output type. |
Reviews (1): Last reviewed commit: "fix(claude-transcript): skip internal Cl..." | Re-trigger Greptile
| const unsupportedLabel = typeof unsupportedType === 'string' && unsupportedType.length > 0 | ||
| ? `[Unsupported agent output: ${unsupportedType}]` | ||
| : '[Unsupported agent output]'; |
There was a problem hiding this comment.
Fallback Label Bypasses Localization
When an unknown output type reaches this branch, the transcript displays a new hardcoded English label. Non-English users receive untranslated diagnostic text; use a translated template with the record type passed as an interpolation value.
Context Used: apps/ui/CLAUDE.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
🧹 Nitpick comments (2)
apps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.ts (1)
393-398: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse narrow, justified test fixture typing.
These changed tests introduce broad
anyusage without documenting why. Keep only narrowly required boundary casts with a one-line rationale, and remove the unnecessary annotation from the UI fixture.
apps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.ts#L393-L398: justify or replacesdkMessage as any.apps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.ts#L401-L405: justify or replace the attachmentas anycast.apps/ui/sources/sync/typesRaw/normalize.outputInvalidKnownTypeFallback.test.ts#L67-L79: removeconst raw: anyand rely on inferred typing.As per coding guidelines, broad
anycasts are forbidden except in narrow boundary fixtures/harnesses with a one-line justification.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.ts` around lines 393 - 398, Replace the broad sdkMessage as any cast in sdkToLogConverter.core.test.ts:393-398 with a narrow justified boundary cast, adding a one-line rationale if the cast is required; apply the same treatment to the attachment as any cast at sdkToLogConverter.core.test.ts:401-405. In normalize.outputInvalidKnownTypeFallback.test.ts:67-79, remove const raw: any and rely on inferred typing.Source: Coding guidelines
apps/ui/sources/sync/typesRaw/normalize.ts (1)
756-761: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftKeep the fallback label in the translation layer.
This new user-visible string is hardcoded in the normalization layer. Format it with
t(...)and interpolation, or carry the unsupported type as metadata and localize the label at the rendering boundary.As per coding guidelines, all user-visible strings, accessibility labels, and placeholders must use
t(...)and be added to every locale.Also applies to: 771-771
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/sources/sync/typesRaw/normalize.ts` around lines 756 - 761, Localize the user-visible fallback labels created in the normalization flow around unsupportedType and unsupportedLabel. Move the label formatting to the translation layer or carry the unsupported type as metadata to the rendering boundary, then use t(...) with interpolation and add the translation key to every locale; apply the same change to the related fallback at the additional referenced location.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.ts`:
- Around line 393-398: Replace the broad sdkMessage as any cast in
sdkToLogConverter.core.test.ts:393-398 with a narrow justified boundary cast,
adding a one-line rationale if the cast is required; apply the same treatment to
the attachment as any cast at sdkToLogConverter.core.test.ts:401-405. In
normalize.outputInvalidKnownTypeFallback.test.ts:67-79, remove const raw: any
and rely on inferred typing.
In `@apps/ui/sources/sync/typesRaw/normalize.ts`:
- Around line 756-761: Localize the user-visible fallback labels created in the
normalization flow around unsupportedType and unsupportedLabel. Move the label
formatting to the translation layer or carry the unsupported type as metadata to
the rendering boundary, then use t(...) with interpolation and add the
translation key to every locale; apply the same change to the related fallback
at the additional referenced location.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 21f8b67e-4473-454a-bfdd-cb307916abb3
📒 Files selected for processing (5)
apps/cli/src/backends/claude/utils/internalClaudeEventTypes.tsapps/cli/src/backends/claude/utils/readClaudeSessionJsonlMessages.test.tsapps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.tsapps/ui/sources/sync/typesRaw/normalize.outputInvalidKnownTypeFallback.test.tsapps/ui/sources/sync/typesRaw/normalize.ts
Claude Code began emitting `attachment`, `last-prompt`, `mode`, and `pr-link` records around 2026-06-19. None are conversation content, but they were not in INTERNAL_CLAUDE_EVENT_TYPES, so the SDK-to-log converter forwarded them and the UI normalizer rendered each one as an "[Unsupported agent output]" row. Add the four types to the skip list, and name the payload type in the UI fallback placeholder. The old placeholder discarded `data.type`, which is why this went unnoticed for a month: there was nothing to grep for. Co-Authored-By: Claude Opus 4.8 <[email protected]>
e71772f to
e36bf2d
Compare
|
Thanks @coderabbitai — went through both. 1. 2. i18n fallback label — declining, out of scope. |
|
Tip For best results, initiate chat on the files or code changes.
Would you like me to open a GitHub issue for that follow-up? 🐇 ✏️ Learnings added
If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/ui/sources/sync/typesRaw/normalize.ts`:
- Around line 756-761: Update the unsupported type handling near unsupportedType
and unsupportedLabel to trim string values before checking whether they are
non-empty and before interpolating them. Treat whitespace-only types as missing,
while using the trimmed value for padded types; add regression coverage for both
cases.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7981a99e-1b55-4bf0-b2ee-02a68260b476
📒 Files selected for processing (5)
apps/cli/src/backends/claude/utils/internalClaudeEventTypes.tsapps/cli/src/backends/claude/utils/readClaudeSessionJsonlMessages.test.tsapps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.tsapps/ui/sources/sync/typesRaw/normalize.outputInvalidKnownTypeFallback.test.tsapps/ui/sources/sync/typesRaw/normalize.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/cli/src/backends/claude/utils/internalClaudeEventTypes.ts
- apps/cli/src/backends/claude/utils/sdkToLogConverter.core.test.ts
- apps/cli/src/backends/claude/utils/readClaudeSessionJsonlMessages.test.ts
- apps/ui/sources/sync/typesRaw/normalize.outputInvalidKnownTypeFallback.test.ts
| // Name the payload type: agent CLIs keep adding record types, and an unnamed placeholder | ||
| // leaves nothing to grep for when one starts leaking into transcripts. | ||
| const unsupportedType = (raw.content.data as { type?: unknown }).type; | ||
| const unsupportedLabel = typeof unsupportedType === 'string' && unsupportedType.length > 0 | ||
| ? `[Unsupported agent output: ${unsupportedType}]` | ||
| : '[Unsupported agent output]'; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Treat whitespace-only types as missing.
length > 0 accepts values such as ' ', producing an unhelpful placeholder, and preserves surrounding whitespace for padded types. Trim the value before checking and interpolating it, with regression cases for whitespace-only and padded types.
Also applies to: 771-771
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/ui/sources/sync/typesRaw/normalize.ts` around lines 756 - 761, Update
the unsupported type handling near unsupportedType and unsupportedLabel to trim
string values before checking whether they are non-empty and before
interpolating them. Treat whitespace-only types as missing, while using the
trimmed value for padded types; add regression coverage for both cases.
Problem
Sessions were showing
[Unsupported agent output]rows in the transcript (see below — two in a row mid tool-run).Root cause: Claude Code began emitting new JSONL record types around 2026-06-19 —
attachment,last-prompt,mode,pr-link. None are conversation content, but they were missing fromINTERNAL_CLAUDE_EVENT_TYPES, so the SDK-to-log converter forwarded them and the UI normalizer rendered each unrecognizedoutputpayload as an[Unsupported agent output]placeholder (apps/ui/sources/sync/typesRaw/normalize.ts).Evidence, counts across one daemon host's
~/.claude/projects/**:attachmentlast-promptmodepr-linkattachmentsubtypes are all context injections (hook output, task reminders, tool/skill listings, file snapshots, queued commands) — no transcript content.Fix
attachment,last-prompt,mode,pr-linktoINTERNAL_CLAUDE_EVENT_TYPES. Dropped at read time, feeding the three existing call sites (converter, session scanner, jsonl reader); no new plumbing.[Unsupported agent output: <type>]. The old placeholder discardeddata.type, which is why this went unnoticed for a month — nothing to grep for. The next new record type will name itself.Tests (TDD, RED→GREEN)
readClaudeSessionJsonlMessages.test.ts— internal state records dropped, ordinary content kept.sdkToLogConverter.core.test.ts— converter returns null for the four types.normalize.outputInvalidKnownTypeFallback.test.ts— fallback names the unknown type.Verification
@happier-dev/clitypecheck: pass.@happier-dev/apptypecheck: pass.src/backends/claude/: 219 files, 1796 tests pass.sources/sync/typesRaw/: 34 tests pass.sources/sync/lane: 5 failures insyncSessions.*SocketUpdate.test.ts— confirmed pre-existing ondev(identical failure set on a clean-tree run), unrelated to this change.Out of scope (follow-up)
acceptedPromptTranscriptDiscovery.tshas deadqueue-operation/attachmentbranches — those rows never surviveRawJSONLinesSchema(a closed union), so queued-command prompt discovery silently no-ops. Separate bug; worth its own issue.🤖 Generated with Claude Code
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Note
Skip internal Claude record types (
attachment,last-prompt,mode,pr-link) in transcriptsattachment,last-prompt,mode, andpr-linkto theINTERNAL_CLAUDE_EVENT_TYPESset in internalClaudeEventTypes.ts so these records are filtered out of transcripts and treated as non-conversation content.typefield in the label, changing[Unsupported agent output]to[Unsupported agent output: <type>]when available.Macroscope summarized e36bf2d.
Summary by CodeRabbit