Skip to content

Conversation

@justingray0
Copy link

@justingray0 justingray0 commented Jan 23, 2026

Amp seems to have changed its data format around Jan 13, 2026 to store usage data in messages[].usage instead of usageLedger.events[].

  • Make message.usage the primary source for token data
  • Fall back to usageLedger for legacy sessions (pre-Jan 13, 2026)
  • Add timestamp field support from message.usage
  • Update CLAUDE.md with current and legacy data structure docs
  • Add test for message-level usage extraction

Summary by CodeRabbit

Release Notes

  • Documentation

    • Updated token usage data structure documentation with current format details and legacy format reference.
  • Refactor

    • Improved token usage extraction logic to prioritize modern data format while maintaining backward compatibility.
    • Enhanced timestamp handling for improved robustness when data is incomplete.

✏️ Tip: You can customize this high-level summary in your review settings.

Amp changed its data format around Jan 13, 2026 to store usage data
in messages[].usage instead of usageLedger.events[].

- Make message.usage the primary source for token data
- Fall back to usageLedger for legacy sessions (pre-Jan 13, 2026)
- Add timestamp field support from message.usage
- Update CLAUDE.md with current and legacy data structure docs
- Add test for message-level usage extraction
@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Updated token usage tracking in AMP to primarily extract usage from message-level data instead of ledger-based events, with fallback support for legacy data format from before January 13, 2026.

Changes

Cohort / File(s) Summary
Documentation Update
apps/amp/CLAUDE.md
Added current format section documenting new message-level usage schema (~Jan 13, 2026 onwards) with fields like inputTokens, outputTokens, cacheCreationInputTokens, cacheReadInputTokens, totalInputTokens, and timestamp; retained legacy format documentation; clarified cache token field availability.
Implementation Migration
apps/amp/src/data-loader.ts
Introduced convertMessageUsageToUsageEvent helper to convert message-level usage to TokenUsageEvent; reworked loadAmpUsageEvents to prioritize message-level usage with fallback to usageLedger events; added timestamp handling from message usage or thread creation; expanded thread parsing for dual-format support; added test coverage for message-based extraction and legacy scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • ryoppippi

Poem

🐰 Tokens once lived in ledgers bright,
Now they dance in messages' light!
Old paths preserved for legacy's sake,
New flows chart the path we take.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: switching to message.usage as the primary data source. It directly summarizes the core objective of the PR and is clear and specific.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/amp/src/data-loader.ts`:
- Around line 185-188: The timestamp fallback currently sets timestamp =
usage.timestamp ?? (threadCreated != null ? new
Date(threadCreated).toISOString() : new Date().toISOString()), which risks
assigning the current time when both usage.timestamp and threadCreated are
missing; change the fallback in the timestamp assignment to use a sentinel
(e.g., null or a constant like UNKNOWN_TIMESTAMP) instead of new
Date().toISOString(), and add a warning log when the sentinel is used so callers
can detect missing event time; update the code around the timestamp variable and
the consuming logic to handle the sentinel rather than assuming a real ISO
timestamp.

Comment on lines +185 to +188
// Use timestamp from usage if available, otherwise estimate from thread created time
const timestamp =
usage.timestamp ??
(threadCreated != null ? new Date(threadCreated).toISOString() : new Date().toISOString());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Timestamp fallback to current time may produce inaccurate data.

When both usage.timestamp and threadCreated are missing, using new Date().toISOString() assigns the current timestamp at parse time rather than the actual event time. This could skew time-based sorting and reports, especially if files are re-parsed later.

Consider using a sentinel value or logging a warning when this fallback is triggered.

Suggested improvement
 	// Use timestamp from usage if available, otherwise estimate from thread created time
+	// Note: Using current time as last resort - data may be inaccurate
 	const timestamp =
 		usage.timestamp ??
-		(threadCreated != null ? new Date(threadCreated).toISOString() : new Date().toISOString());
+		(threadCreated != null ? new Date(threadCreated).toISOString() : (() => {
+			logger.debug('Missing timestamp for message usage, using current time', { threadId, messageId: message.messageId });
+			return new Date().toISOString();
+		})());
🤖 Prompt for AI Agents
In `@apps/amp/src/data-loader.ts` around lines 185 - 188, The timestamp fallback
currently sets timestamp = usage.timestamp ?? (threadCreated != null ? new
Date(threadCreated).toISOString() : new Date().toISOString()), which risks
assigning the current time when both usage.timestamp and threadCreated are
missing; change the fallback in the timestamp assignment to use a sentinel
(e.g., null or a constant like UNKNOWN_TIMESTAMP) instead of new
Date().toISOString(), and add a warning log when the sentinel is used so callers
can detect missing event time; update the code around the timestamp variable and
the consuming logic to handle the sentinel rather than assuming a real ISO
timestamp.

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