Class: Agent::Sessions::Adapters::Gemini
- Defined in:
- lib/agent/sessions/adapters/gemini.rb
Overview
Gemini CLI. Verified against a real store on this machine (2026-08-24): 9 project directories, 12 chat files, 121 records.
The store is keyed by an opaque project hash, not by an encoded path:
~/.gemini/tmp/
Constant Summary collapse
- FILENAME =
session-2025-11-29T20-08-b20947ab.json. The trailing hex is NOT a session id: two files in the real store share d4abc9ce while being different sessions, so the whole basename is the id — unique, stable, and derivable without opening the file, which is what Layer 2 is for. The agent's own sessionId lives inside the document and reaches a caller through the reader.
/\Asession-(\d{4})-(\d{2})-(\d{2})T(\d{2})-(\d{2})-\h+\.json\z/
Constants inherited from Base
Constants included from Enumeration
Class Method Summary collapse
Instance Method Summary collapse
- #encode_project(dir) ⇒ Object
-
#project_dir_name(path) ⇒ Object
/tmp/ /chats/ .json — two levels up from the file, not one, so Base's default (the immediate parent) would answer "chats" for every session. -
#project_path_for(path) ⇒ Object
The store groups sessions under a hash of the project directory that this gem cannot reverse: it is not a plain SHA-256 of the path (tested directly against real directories), and the store records the path nowhere else.
- #project_paths ⇒ Object
-
#started_at_for(path, stat) ⇒ Object
UTC, unlike Codex and pi, whose rollout filenames use the local clock.
-
#warnings ⇒ Object
The delta-log variant: tokentelemetry's parser of this same store handles chats written as JSONL with a header line and
$setdeltas.
Methods inherited from Base
#base_dir, fidelity_value, homedir_config, #initialize, #locate, #retention, #retention_source, store_configs, #verify
Methods included from Enumeration
#bytes_for, #session_id_from, #sessions, #sessions_for_project, #updated_at_for
Constructor Details
This class inherits a constructor from Agent::Sessions::Adapters::Base
Class Method Details
Instance Method Details
#encode_project(dir) ⇒ Object
94 95 96 |
# File 'lib/agent/sessions/adapters/gemini.rb', line 94 def encode_project(dir) project_map.key(dir) || super end |
#project_dir_name(path) ⇒ Object
90 91 92 |
# File 'lib/agent/sessions/adapters/gemini.rb', line 90 def project_dir_name(path) File.basename(File.dirname(File.dirname(path))) end |
#project_path_for(path) ⇒ Object
The store groups sessions under a hash of the project directory that
this gem cannot reverse: it is not a plain SHA-256 of the path (tested
directly against real directories), and the store records the path
nowhere else. ~/.gemini/projects.json is the map Gemini itself keeps —
when it exists, this reads it; when it does not, nil is the honest
answer and projects reports nothing rather than inventing a name
from the hash.
82 83 84 85 |
# File 'lib/agent/sessions/adapters/gemini.rb', line 82 def project_path_for(path) hash = project_dir_name(path) hash && project_map[hash] end |
#project_paths ⇒ Object
98 99 100 101 102 103 |
# File 'lib/agent/sessions/adapters/gemini.rb', line 98 def project_paths return [] unless primary_layer.exists? Dir.glob(File.join(escape_glob(primary_layer.path), "*", "chats", "session-*.json")) .filter_map { |path| project_path_for(path) }.uniq.sort end |
#started_at_for(path, stat) ⇒ Object
UTC, unlike Codex and pi, whose rollout filenames use the local clock. Verified rather than assumed: four real filenames match their own document's startTime to the minute when read as UTC (12-42 against 2025-12-12T12:42:50.033Z), and would be three hours out as local time on the machine this was written on.
Minute precision only — the document's startTime carries seconds, but reading it would cost a parse per session, and Layer 2 is stat-only.
65 66 67 68 69 70 71 72 73 |
# File 'lib/agent/sessions/adapters/gemini.rb', line 65 def started_at_for(path, stat) parts = FILENAME.match(File.basename(path))&.captures or return super begin Time.utc(*parts.map(&:to_i)) rescue ArgumentError # digits that do not form a real date super end end |
#warnings ⇒ Object
The delta-log variant: tokentelemetry's parser of this same store
handles chats written as JSONL with a header line and $set deltas.
No such file exists here (zero .jsonl anywhere under the store), so
this adapter reads the verified .json spelling only — and says so
where a user with the other spelling will see it, rather than
silently enumerating nothing for half their sessions.
39 40 41 42 43 44 45 46 47 |
# File 'lib/agent/sessions/adapters/gemini.rb', line 39 def warnings list = super jsonl = Dir.glob(File.join(escape_glob(primary_layer.path), "*", "chats", "*.jsonl")) if jsonl.any? list << "#{jsonl.size} chat file(s) use the JSONL delta format, which this adapter does " \ "not read yet; those sessions are not enumerated" end list end |