fix(gemini): Gemini CLI .jsonl sessions not detected (#348) - #393
Conversation
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>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdds support for Gemini CLI's append-only JSONL session file format alongside the existing legacy JSON format. A new ChangesGemini JSONL Session Format Support
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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.
⚠️ 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
.jsonand.jsonlGemini session files during scanning. - Add a unified
parse_gemini_sessionhelper and routeload_messages,search, andextract_session_metadatathrough it to support both on-disk formats (including$setupdates and$rewindTomarkers). - 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.
| let (record, messages) = | ||
| parse_gemini_session(&data).ok_or_else(|| "Failed to parse session".to_string())?; |
| 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)); | ||
| } | ||
| } |
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-*.jsonobject to an append-onlysession-*.jsonllog (upstream google-gemini/gemini-cli#23749, issue #15292). Ourproviders/gemini.rs:is_session_fileonly accepted thejsonextension →.jsonlfiles were skipped →session_countstayed 0 →scan_projects_from_pathdropped the entire project, so it never appeared.load_messages/search/extract_session_metadataparsed the whole file with a singleserde_json::from_strexpecting a top-levelmessages[]array, which fails on line-delimited JSONL.The machine that still works has old-style
.json; a reporter whose sessions are all new.jsonlsees nothing. macOS is incidental — the real variable is Gemini CLI version / file format.Fix
A new
parse_gemini_sessionhelper normalizes both formats and returns(metadata, messages):.json: single object withmessages[]..jsonl: first line = session metadata (stringsessionId+projectHash); subsequent lines = message records (stringid);{"$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_messageunchanged.load_messages,search, andextract_session_metadatanow route through the helper, andis_session_fileaccepts.jsonl.Verification
Confirmed the exact JSONL schema against the upstream
chatRecordingService.ts/chatRecordingTypes.tsbefore implementing. New unit tests cover both formats,$set/$rewindTohandling, metadata-only sessions, and end-to-end conversion.cargo test(592 lib tests),clippy --all-targets --all-features -D warnings, andcargo fmt --checkall clean locally.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements