fix(replay): surface compressed observation content in replay detail#1023
fix(replay): surface compressed observation content in replay detail#1023xianfengpolo wants to merge 1 commit into
Conversation
Replay sessions built from compressed observations (the only format stored after the live-capture and jsonl-import compression pass) showed empty detail panels: every event rendered only a label and timestamp with no tool name, input, output, or prompt text. Root cause: rawFromCompressed() mapped all observation types uniformly to hookType:"post_tool_use" while leaving toolName/toolInput/toolOutput all undefined. Only conversation.userPrompt was partially handled, but the hook type was still wrong (post_tool_use instead of prompt_submit). Fix: branch on obs.type — - "conversation" → hookType:"prompt_submit", userPrompt ← narrative - everything else → hookType:"post_tool_use", toolName ← title, toolInput ← subtitle (optional), toolOutput ← narrative The compressed schema stores exactly these fields during compression (title = tool name, subtitle = raw input, narrative = combined output), so the mapping is lossless for all data retained after compression. Also exports rawFromCompressed as a pure helper for direct unit testing (precedent: src/cli/doctor-diagnostics.ts does the same). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@xianfengpolo is attempting to deploy a commit to the rohitg00's projects Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThe ChangesrawFromCompressed Mapping Fix
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/functions/replay.ts (1)
49-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTrim the WHAT-explaining comment.
Lines 60-64 restate the mapping logic that's already self-evident from the code (
isConversationternaries). Per path instructions, prefer clear naming over comments explaining what the code does; keep only the rationale/history if useful.As per path instructions: "In TypeScript source code, avoid code comments explaining WHAT — use clear naming instead."
🤖 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 `@src/functions/replay.ts` around lines 49 - 66, The block comment above replayObservation is too detailed about WHAT the code does and duplicates the branch logic already shown by the isConversation ternaries. Trim it down by removing the step-by-step mapping bullets and keep only the brief rationale/history for why the shim exists, so the function name and branching remain the primary documentation.Source: Path instructions
🤖 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 `@src/functions/replay.ts`:
- Around line 49-66: The block comment above replayObservation is too detailed
about WHAT the code does and duplicates the branch logic already shown by the
isConversation ternaries. Trim it down by removing the step-by-step mapping
bullets and keep only the brief rationale/history for why the shim exists, so
the function name and branching remain the primary documentation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b2f35464-7af5-49b2-a76f-ebc186c1035e
📒 Files selected for processing (2)
src/functions/replay.tstest/replay.test.ts
Problem
The Replay tab in the viewer steps through session events correctly, but the detail panel is empty for every event — only a label and timestamp are shown.
Root Cause
rawFromCompressed()insrc/functions/replay.tswas the compatibility shim between the compressed storage format and theRawObservationshape expected byprojectTimeline. It had two bugs:hookTypefor all events — hardcoded"post_tool_use"regardless of observation type, so conversation events never rendered as prompts.toolName,toolInput, andtoolOutputwere allundefined. The compressed format does retain this data under different field names (title= tool name,subtitle= raw input,narrative= combined output), but the shim never mapped them.Since the runtime compresses every observation (both live-capture and jsonl-import paths), every replay session was affected.
Fix
Branch on
obs.typeinrawFromCompressed:"conversation"→hookType: "prompt_submit",userPrompt ← narrativehookType: "post_tool_use",toolName ← title,toolInput ← subtitle,toolOutput ← narrativeassistantResponsestaysundefined— the compression pass doesn't preserve a separate assistant-response field.The function is also exported (it was previously unexported) so it can be directly unit-tested. Precedent:
src/cli/doctor-diagnostics.tsdoes the same for its pure helpers.Tests
Four new test cases added to
test/replay.test.tsin the newrawFromCompresseddescribe block:command_runwith subtitlehookType,toolName,toolInput,toolOutputall populatedconversationhookType:"prompt_submit",userPromptpopulated, tool fields undefinedsubtitletoolInputtoundefinedwithout throwingprojectTimelineTimelineEventcarriestoolName/toolInput/toolOutput/bodyTypeScript typecheck (
npx tsc --noEmit): zero errors in changed files (pre-existing errors in unrelated files are unchanged).Checklist
Summary by CodeRabbit
Bug Fixes
Tests