Skip to content

fix(core): implement append-only delta patching and bounded history windowing in ChatRecordingService - #29568

Merged
DavidAPierce merged 7 commits into
google-gemini:mainfrom
jvargassanchez-dot:b_561554829
Oct 1, 2026
Merged

DavidAPierce merged 7 commits into
google-gemini:mainfrom
jvargassanchez-dot:b_561554829

Conversation

@jvargassanchez-dot

@jvargassanchez-dot jvargassanchez-dot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This change updates ChatRecordingService (packages/core/src/services/chatRecordingService.ts and packages/core/src/services/chatRecordingTypes.ts) to replace full-history { $set: { messages } } rewrites and unbounded in-memory message retention with incremental append-only delta patching, constant-time change detection, and bounded in-memory message windowing.

From an architectural perspective, this ensures linear $O(n)$ disk serialization across multi-turn sessions, eliminates repeated deep JSON.stringify scans across historical turns and tool call payloads during updateMessagesFromHistory(), and bounds the resident in-memory cachedConversation.messages buffer to a sliding window (MAX_HISTORY_MESSAGES = 50) while preserving full history reconstruction on demand from the backing .jsonl session log.

Details

Problem

Previously, updateMessagesFromHistory() in ChatRecordingService appended { $set: { messages: newMessages } } on every turn, serializing the full message history to disk repeatedly ($O(n^2)$). For a
100-turn session with tool calls, this created single lines exceeding 8.2 million characters and bloated the session file up to ~400 MB, causing V8 heap exhaustion (reaching up to 7+ GB in long sessions,
b/561554829).

Solution

  • Delta Patching ($patch): Migrated to atomic updates ($patch) for mutated tool responses/turn parts, deprecating full-history $set: { messages } appends.
  • Change Detection Optimization: Replaced repetitive JSON.stringify comparisons with WeakRef + fast content hash fingerprints (ContentFingerprint).
  • Memory Bounding: Bounded cachedConversation.messages to MAX_HISTORY_MESSAGES, offloading older history to disk and streaming on-demand for resume/rewind.

Benchmark Results (100 Turns, ~80 KB Tool Output / Turn)

Metric Before Fix (main) After Fix (b_561554829) Improvement
Disk Size (.jsonl) 396.60 MB 7.86 MB -98.0% (Strictly linear $O(n)$)
Max Line Length 8,234,832 chars 82,077 chars -99.0%
Retained Heap 333.3 MB 85.6 MB -74.3%
Process RSS 564.7 MB 285.3 MB -49.5%
Sync Latency / Turn 98.05 ms 64.59 ms -34.1% ($O(1)$ message delta appends)

Related Issues

How to Validate

  1. Run the ChatRecordingService unit and regression test suite:
    npm test -w @google/gemini-cli-core -- src/services/chatRecordingService.test.ts
  2. Run the memory regression benchmark suite:
    npm run bundle && IS_BINARY="" npm run test:memory
  3. Run full workspace preflight validation:
    npm run preflight

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

…indowing in ChatRecordingService

- Add ToolCallPatch, MessagePatch, and MessagePatchRecord ($patch) in chatRecordingTypes.ts and deprecate passing full messages arrays in MetadataUpdateRecord.
- Update updateMessagesFromHistory() in chatRecordingService.ts to append new turns as individual MessageRecord lines, emit $rewindTo for pure tail rollbacks, and emit targeted $patch records for content, tool call result, and ordering updates.
- Extend loadConversationRecord and loadConversationRecordSync via createJsonlRecordAccumulator to process $patch records while maintaining backward compatibility with legacy .json and $set: { messages } session files.
- Replace per-turn JSON.stringify comparisons across historical turns with WeakRef reference checks paired with a compact deterministic digest (computeContentDigest).
- Bound in-memory cachedConversation.messages to MAX_HISTORY_MESSAGES (50) and reconstruct complete conversation records on demand in getConversation() and rewindTo() when older messages have been evicted.
- Add unit and regression tests in chatRecordingService.test.ts covering delta patching, linear O(n) disk scaling, bounded in-memory windowing, and session resumption/rewind.

Fixes google-gemini#28357
@jvargassanchez-dot
jvargassanchez-dot requested a review from a team as a code owner September 29, 2026 21:44
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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!

This PR optimizes the ChatRecordingService by moving from full-history serialization to an incremental, append-only delta patching model. By implementing a bounded in-memory sliding window and efficient content fingerprinting, the service significantly reduces disk usage, heap consumption, and synchronization latency, effectively resolving performance bottlenecks in long-running chat sessions.

Highlights

  • Performance Optimization: Replaced full-history serialization with append-only delta patching, reducing disk I/O complexity from O(n^2) to O(n).
  • Memory Management: Implemented a sliding window for in-memory message retention, bounding the cached conversation to 50 entries to prevent heap exhaustion.
  • Change Detection: Introduced ContentFingerprint using WeakRef to avoid expensive JSON.stringify comparisons during incremental updates.
  • Compatibility: Added support for legacy $set checkpoints while enabling new incremental $patch and $rewindTo operations.
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 by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

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 pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the 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 may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. 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. ↩

@github-actions github-actions Bot added the size/xl An extra large PR label Sep 29, 2026
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

📊 PR Size: size/XL

  • Lines changed: 1543
  • Additions: +1283
  • Deletions: -260
  • Files changed: 3

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces append-only delta patching and memory bounding to the ChatRecordingService to optimize disk usage and limit in-memory message caching to MAX_HISTORY_MESSAGES. It replaces full-history checkpoints with incremental $patch and $rewindTo records, and implements a lightweight indexing mechanism to track message and tool call changes. A critical review comment points out a potential data desynchronization issue in updateMessagesFromHistory when this.hasEvictedMessages is true, where reordering or removing messages in the active trailing window requires reloading the full conversation from disk to maintain correctness.

Comment thread packages/core/src/services/chatRecordingService.ts Outdated
@gemini-cli gemini-cli Bot added priority/p1 Important and should be addressed in the near term. area/core Issues related to User Interface, OS Support, Core Functionality labels Sep 29, 2026
@jvargassanchez-dot

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces append-only delta patching and memory bounding to the ChatRecordingService to optimize disk usage and memory footprint. Instead of rewriting the entire message history using full checkpoints, the service now appends lightweight delta patches ($patch) and rewind records ($rewindTo), while limiting the in-memory cache to MAX_HISTORY_MESSAGES. The loadConversationRecord function has been refactored to use a stream-based accumulator that reconstructs the full conversation from these incremental records. Feedback was provided regarding an unsafe reference-equality optimization in updateFingerprintIfChanged that could lead to silent data corruption, suggesting a fallback to direct content hash comparison instead.

Comment thread packages/core/src/services/chatRecordingService.ts Outdated

@carolteng19930107-cpu carolteng19930107-cpu left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

  • [♾️]_<

@carolteng19930107-cpu

Copy link
Copy Markdown

Summary of Changes

Hello, 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!

This PR optimizes the ChatRecordingService by moving from full-history serialization to an incremental, append-only delta patching model. By implementing a bounded in-memory sliding window and efficient content fingerprinting, the service significantly reduces disk usage, heap consumption, and synchronization latency, effectively resolving performance bottlenecks in long-running chat sessions.

Highlights

  • Performance Optimization: Replaced full-history serialization with append-only delta patching, reducing disk I/O complexity from O(n^2) to O(n).
  • Memory Management: Implemented a sliding window for in-memory message retention, bounding the cached conversation to 50 entries to prevent heap exhaustion.
  • Change Detection: Introduced ContentFingerprint using WeakRef to avoid expensive JSON.stringify comparisons during incremental updates.
  • Compatibility: Added support for legacy $set checkpoints while enabling new incremental $patch and $rewindTo operations.
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 by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

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 pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the 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 may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

88998

Footnotes

  1. 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. ↩

@jvargassanchez-dot

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces append-only delta patching and memory bounding to ChatRecordingService to optimize memory usage and disk space. Instead of rewriting the entire message history, it now appends atomic delta patches and bounds the in-memory cache to MAX_HISTORY_MESSAGES. Feedback on these changes highlights a critical correctness bug in the mixString sampling logic, which can miss in-place mutations of large strings and cause silent data corruption, and a performance issue where getConversation performs synchronous disk I/O that can block the event loop.

Comment thread packages/core/src/services/chatRecordingService.ts
Comment thread packages/core/src/services/chatRecordingService.ts
@jvargassanchez-dot

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces append-only delta patching and memory bounding to ChatRecordingService to optimize disk usage and limit in-memory message caching to MAX_HISTORY_MESSAGES. Feedback on these changes highlights two critical areas for improvement: first, sorting object keys in computeContentDigest to ensure deterministic fingerprinting and prevent redundant disk writes; second, implementing a lazy-loaded cache for reconstructed conversations in getConversation() to avoid blocking the Node.js event loop with repeated synchronous file reads.

Comment thread packages/core/src/services/chatRecordingService.ts
Comment thread packages/core/src/services/chatRecordingService.ts
Comment thread packages/core/src/services/chatRecordingService.ts
@jvargassanchez-dot

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces append-only delta patching and memory bounding to ChatRecordingService to optimize memory usage and disk serialization. It bounds the in-memory cached messages to MAX_HISTORY_MESSAGES and writes incremental $patch and $rewindTo records to the JSONL session file instead of rewriting the entire message history. A review comment correctly identifies that the current implementation of orderChanged evaluates to true on every message append, resulting in redundant $patch records and O(n^2) disk overhead, and suggests a fix to detect pure appends.

Comment thread packages/core/src/services/chatRecordingService.ts
@jvargassanchez-dot

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces append-only delta patching and memory bounding to the ChatRecordingService to optimize disk space usage and limit in-memory message caching to MAX_HISTORY_MESSAGES. It replaces full-history rewrites with incremental $patch records, utilizes content fingerprinting to detect in-place mutations, and adds robust support for legacy checkpoints. Feedback on the changes suggests optimizing performance and reducing garbage collection pressure in updateMessagesFromHistory by executing cache updates only when message content has actually changed.

Comment thread packages/core/src/services/chatRecordingService.ts Outdated
@jvargassanchez-dot

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces append-only delta patching and memory bounding to the ChatRecordingService to optimize memory usage and ensure disk file size scales linearly. It limits the in-memory cached messages to MAX_HISTORY_MESSAGES and writes incremental updates using a new $patch record format instead of rewriting the entire message history. Evicted messages are lazily reloaded from disk when full conversation reconstruction or rewinding is required. Additionally, comprehensive unit tests have been added to validate these memory-bounding and delta-patching behaviors. I have no feedback to provide as there are no review comments.

@DavidAPierce
DavidAPierce added this pull request to the merge queue Sep 30, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 30, 2026
@DavidAPierce
DavidAPierce added this pull request to the merge queue Oct 1, 2026
Merged via the queue into google-gemini:main with commit d1cc08a Oct 1, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality priority/p1 Important and should be addressed in the near term. size/xl An extra large PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory crash due high memory usage

3 participants