Skip to content

fix(gemini): Gemini CLI .jsonl sessions not detected (#348) - #393

Merged
jhlee0409 merged 1 commit into
developfrom
fix/348-gemini-jsonl
Jun 20, 2026
Merged

fix(gemini): Gemini CLI .jsonl sessions not detected (#348)#393
jhlee0409 merged 1 commit into
developfrom
fix/348-gemini-jsonl

Conversation

@jhlee0409

@jhlee0409 jhlee0409 commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Closes #348.

Problem

Gemini CLI conversation history is not detected — the Gemini provider shows but with no sessions, even though history files exist (reporter: macOS arm64).

Root cause

Gemini CLI migrated chat recording from a monolithic session-*.json object to an append-only session-*.jsonl log (upstream google-gemini/gemini-cli#23749, issue #15292). Our providers/gemini.rs:

  • is_session_file only accepted the json extension → .jsonl files were skipped → session_count stayed 0 → scan_projects_from_path dropped the entire project, so it never appeared.
  • load_messages / search / extract_session_metadata parsed the whole file with a single serde_json::from_str expecting a top-level messages[] array, which fails on line-delimited JSONL.

The machine that still works has old-style .json; a reporter whose sessions are all new .jsonl sees nothing. macOS is incidental — the real variable is Gemini CLI version / file format.

Fix

A new parse_gemini_session helper normalizes both formats and returns (metadata, messages):

  • legacy .json: single object with messages[].
  • current .jsonl: first line = session metadata (string sessionId + projectHash); subsequent lines = message records (string id); {"$set": {..}} lines update metadata; {"$rewindTo": ..} markers are skipped.

Message records have the same shape in both formats, so they flow through the existing convert_gemini_message unchanged. load_messages, search, and extract_session_metadata now route through the helper, and is_session_file accepts .jsonl.

Verification

Confirmed the exact JSONL schema against the upstream chatRecordingService.ts/chatRecordingTypes.ts before implementing. New unit tests cover both formats, $set/$rewindTo handling, metadata-only sessions, and end-to-end conversion. cargo test (592 lib tests), clippy --all-targets --all-features -D warnings, and cargo fmt --check all clean locally.

Note: $rewindTo markers are skipped rather than honored — a rewound (undone) message may still be shown. That is far better than the current "nothing shows" behavior and can be refined later if needed.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for Gemini session files in JSONL (append-only) format alongside the existing JSON format.
    • Project discovery now recognizes session files with both .json and .jsonl extensions.
  • Improvements

    • Enhanced session loading and metadata extraction to handle both legacy and current file formats seamlessly.

Gemini CLI migrated chat recording from a monolithic session-*.json object to
an append-only session-*.jsonl log (google-gemini/gemini-cli#23749). The viewer
only accepted the .json extension and parsed each file with a single
serde_json::from_str, so on any machine whose sessions are the new .jsonl
format every session was rejected: is_session_file skipped the file, the
session count stayed 0, and scan_projects_from_path dropped the whole Gemini
project — it never appeared (matching the reporter's macOS screenshot).

Add a parse_gemini_session helper that handles both on-disk formats:
- legacy .json: a single object with a top-level messages[] array.
- current .jsonl: the first line is session metadata (string sessionId +
  projectHash), followed by one message record per line (string id), with
  {"$set": {..}} metadata updates and {"$rewindTo": ..} markers.

Message records share the same shape across both formats, so they flow through
convert_gemini_message unchanged. Route load_messages, search, and
extract_session_metadata through the helper, and accept the .jsonl extension in
is_session_file. Adds unit tests for both formats, $set/$rewindTo handling,
metadata-only sessions, and end-to-end conversion.

Verified locally: cargo test (592 lib tests), clippy, and fmt all clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 17, 2026 14:51
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4b12f0d4-c5e1-401b-a453-96d30ebf4c88

📥 Commits

Reviewing files that changed from the base of the PR and between 281a1b0 and 6f09956.

📒 Files selected for processing (1)
  • src-tauri/src/providers/gemini.rs

Walkthrough

Adds support for Gemini CLI's append-only JSONL session file format alongside the existing legacy JSON format. A new parse_gemini_session helper unifies both formats into (record, Vec<messages>); all callers (load_messages, search, extract_session_metadata) and file discovery (.jsonl extension) are updated to use it, with new unit tests covering edge cases.

Changes

Gemini JSONL Session Format Support

Layer / File(s) Summary
parse_gemini_session implementation
src-tauri/src/providers/gemini.rs
New parse_gemini_session function dispatches on file format: legacy JSON returns (record, record.messages), JSONL classifies lines as metadata, $set updates, ignored $rewindTo markers, or message records (by id presence), returning unified (Value, Vec<Value>) or None for empty/invalid input.
File discovery and all callers updated
src-tauri/src/providers/gemini.rs
Session file detection adds .jsonl extension; load_messages, search, and extract_session_metadata all switch from direct record.messages array access to consuming the (record, messages) pair from parse_gemini_session.
Unit tests for parse_gemini_session
src-tauri/src/providers/gemini.rs
Tests cover legacy JSON, JSONL basic parsing, $set/$rewindTo handling, metadata-only JSONL, empty/malformed inputs, and end-to-end message conversion via convert_gemini_message.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • jhlee0409/claude-code-history-viewer#214: Modifies the same Gemini provider file (gemini.rs), touching load_messages, search, metadata extraction, and session file handling — directly overlapping with this PR's changed functions.

Suggested labels

backend, bug, test

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately identifies the main fix: enabling detection of Gemini CLI .jsonl session files, directly addressing the core issue reported.
Linked Issues check ✅ Passed The PR fully addresses issue #348 by implementing support for both legacy .json and current .jsonl Gemini CLI session formats, enabling proper detection and parsing of conversation history.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing Gemini session file detection and parsing; no unrelated modifications are present.
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
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/348-gemini-jsonl

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.

Copilot AI 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.

⚠️ Not ready to approve

The legacy-JSON parsing path currently clones the full messages array (potentially doubling memory for large sessions) and the new parse error surfaced by load_messages is too generic for effective troubleshooting.

Pull request overview

This PR updates the Gemini provider to correctly detect and load Gemini CLI conversation history after the upstream migration from monolithic session-*.json files to append-only session-*.jsonl logs, preventing projects from being dropped due to a zero detected session count.

Changes:

  • Accept both .json and .jsonl Gemini session files during scanning.
  • Add a unified parse_gemini_session helper and route load_messages, search, and extract_session_metadata through it to support both on-disk formats (including $set updates and $rewindTo markers).
  • Add unit tests covering legacy JSON, JSONL, $set/$rewindTo, metadata-only sessions, and basic end-to-end message conversion.
File summaries
File Description
src-tauri/src/providers/gemini.rs Adds JSONL support for Gemini sessions via a shared parser and updates loading/search/metadata paths plus tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 2

Note

Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +214 to +215
let (record, messages) =
parse_gemini_session(&data).ok_or_else(|| "Failed to parse session".to_string())?;
Comment on lines +398 to +407
if let Ok(record) = serde_json::from_str::<Value>(data) {
if record.get("messages").is_some_and(Value::is_array) {
let messages = record
.get("messages")
.and_then(Value::as_array)
.cloned()
.unwrap_or_default();
return Some((record, messages));
}
}
@jhlee0409
jhlee0409 merged commit 72f142d into develop Jun 20, 2026
8 checks passed
@jhlee0409
jhlee0409 deleted the fix/348-gemini-jsonl branch June 20, 2026 08:57
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.

2 participants