Repository navigation
Conversation
✅ Core Implementation 1. Extended Schema: Added optional requestId and message.id fields to the UsageDataSchema 2. Deduplication Logic: Implemented createUniqueHash() function that creates unique identifiers from message ID + request ID combinations 3. Global Deduplication: Added deduplication across all files in both loadDailyUsageData() and loadSessionData() functions 4. Backward Compatibility: Entries without IDs are processed normally (no breaking changes) ✅ Key Features - Prevents Double-Counting: Skips duplicate message+request ID combinations globally across all conversation branches - Handles Edge Cases: Processes entries without IDs normally, allows same message ID with different request IDs - Session Integrity: Ensures session entries are created even if all messages are deduplicated (prevents missing sessions) - Cost Accuracy: Only calculates costs for unique messages, preventing inflated usage numbers in branched conversations
There was a problem hiding this comment.
Hello @ryoppippi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
Summary of Changes
Hello team,
Gemini here with a summary of this pull request. This PR, authored by @ryoppippi, addresses issue #19 by implementing a mechanism to resolve duplicate message IDs when loading usage data. The core problem was that the data loading process might encounter the same usage entry multiple times, leading to inflated usage counts and costs. This change introduces a deduplication step based on the combination of message.id and requestId.
The changes involve updating the data schema to include these IDs, adding a helper function to create a unique hash from them, and modifying the data loading functions (loadDailyUsageData and loadSessionData) to track and skip entries that have already been processed based on this unique hash. Extensive tests have been added to verify the deduplication logic works correctly in various scenarios, including across different files and within the same file, while ensuring entries without these IDs are still processed.
Highlights
- Deduplication Logic: Introduces a deduplication mechanism in
loadDailyUsageDataandloadSessionDatato prevent processing the same usage entry multiple times. - Unique Identifier: A new helper function
createUniqueHashis added to generate a unique identifier for each usage entry based on the combination ofmessage.idandrequestId. - Schema Update: The
UsageDataSchemais updated to include optionalmessage.idandrequestIdfields, which are necessary for the deduplication process. - Comprehensive Testing: New test suites are added to
data-loader.test.tsto specifically cover thecreateUniqueHashfunction and the deduplication functionality in both daily and session data loading, including edge cases.
Changelog
- src/data-loader.test.ts
- Imported
createUniqueHashfunction (L7). - Added new test suite for
createUniqueHashfunction (L38-90). - Added new test suite for deduplication functionality in
loadDailyUsageDataandloadSessionData(L92-334).
- Imported
- src/data-loader.ts
- Updated
UsageDataSchemato include optionalmessage.id(L28) andrequestId(L31). - Added
createUniqueHashhelper function (L86-99). - Implemented deduplication logic in
loadDailyUsageDatausing aSetandcreateUniqueHash(L168, L186-196). - Implemented deduplication logic in
loadSessionDatausing aSetandcreateUniqueHash(L289, L316-326).
- Updated
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
commit: |
There was a problem hiding this comment.
Code Review
This pull request successfully addresses the issue of duplicate message IDs by introducing a deduplication mechanism based on the combination of message ID and request ID. The changes include adding the necessary fields to the UsageData schema, implementing a helper function to create a unique hash, and applying this logic in both loadDailyUsageData and loadSessionData. The added tests are comprehensive and cover various scenarios, which is great for ensuring the correctness of the new functionality.
Summary of Findings
- Code Duplication in Data Loading: The core logic for deduplicating usage entries based on the message ID and request ID is duplicated in both
loadDailyUsageDataandloadSessionData. Extracting this into a shared helper function could improve maintainability and reduce the risk of inconsistencies if the deduplication logic needs to be modified in the future. - Hash Function Choice (Not commented on due to settings): The
createUniqueHashfunction uses simple string concatenation (msgId:reqId). While this is likely sufficient for the current use case and faster than cryptographic hashing, depending on the expected format and potential for collisions in message/request IDs, a more robust hashing mechanism (likecrypto.createHash) could be considered if collision resistance becomes a concern. (Note: This was not commented on directly due to review settings).
Merge Readiness
The core functionality to fix the duplicate message ID issue is correctly implemented and well-tested. The added tests are thorough and cover the intended behavior of the deduplication logic. The main point for improvement is the code duplication in the data loading functions, which is a medium severity maintainability issue. While the code is functional as is, addressing the duplication would make it easier to maintain going forward. I recommend addressing the medium severity issue before merging, but the decision is ultimately up to the maintainers. As a reviewer, I am unable to directly approve this pull request; please ensure other reviewers approve before merging.
| // Check for duplicate message + request ID combination | ||
| const uniqueHash = createUniqueHash(data); | ||
| if (uniqueHash && processedRequests.has(uniqueHash)) { | ||
| // Skip duplicate message | ||
| continue; | ||
| } | ||
|
|
||
| // Mark this combination as processed | ||
| if (uniqueHash) { | ||
| processedRequests.add(uniqueHash); | ||
| } |
There was a problem hiding this comment.
The logic for checking for duplicate message+request ID combinations and adding the unique hash to the processedRequests set is duplicated here and in the loadSessionData function. While it works correctly, duplicating logic can make the code harder to maintain if the deduplication method needs to be updated in the future.
Could this logic be extracted into a small helper function that takes the data entry and the processedRequests set, returning a boolean indicating whether the entry should be skipped? Or perhaps the parsing loop could be refactored slightly to handle deduplication in a more centralized way?
| // Check for duplicate message + request ID combination | ||
| const uniqueHash = createUniqueHash(data); | ||
| if (uniqueHash && processedRequests.has(uniqueHash)) { | ||
| // Skip duplicate message | ||
| continue; | ||
| } | ||
|
|
||
| // Mark this combination as processed | ||
| if (uniqueHash) { | ||
| processedRequests.add(uniqueHash); | ||
| } |
There was a problem hiding this comment.
|
We might consider implementing some kind of sorting mechanism if we're using a hash of requestID and message.id and we're expecting some duplicates... we only want to "count" the first time we see the duplicate and ideally we're processing these in order from oldest (first occurrence) to newest (last occurrence). But if we're using glob and processing these alphabetically by a randomly assigned UUID, we might want to look at something like first timestamp in the files to make sure we process them in order. I don't know for sure, but it seems like order matters if we're filtering out duplicates and hoping to keep the session aggregation as accurate as possible. AI summary and suggestion - Deduplication Fix SummaryOriginal Issue: Duplicate Message CountingProblem DescriptionWhen using Claude Code with branched conversations (editing and retrying messages), the usage tracking system was counting the same messages multiple times. This occurred because:
Original Fix (Commit 36fd76d)Author: ryoppippi Core Implementation
Key Features
Enhancement: Chronological File ProcessingProblem DiscoveredWhile the original fix correctly identified and skipped duplicates, it had a subtle issue with which duplicate to keep:
Example ScenarioWhy This Matters
Solution ImplementedNew Function:
|
|
I'm not on my desktop right now to check, but have you checked if the timestamp of the carried over messages aren't the same for the original conversation and the branched one? I also feel like just reading every line into a single list, adding the conversation id to the object and then doing some data manipulation would be simpler than some kind of tracking. |
|
True if the time stamps remain the same. Then we don't really need to handle them, just filter out based on hashed key is sufficient. I'm away from my computer too now, but those timestamps are probably something to check if changing or staying the same when duplicated. |
|
I checked and it changes the timestamp, sets it all to the same date as the new message, so you'd have to also only count the chronologically first unique message. |
|
It sounds nice. Could you implement it with new PR? |
|
I've created a new draft PR to address this issue here: #58 @Richard-Weiss - Would you be able to clone that branch/PR and test the output vs what you expect? |
|
close this because #58 is better one |
fixes: #19