Class: Agent::Sessions::Readers::Grok

Inherits:
Base
  • Object
show all
Defined in:
lib/agent/sessions/readers/grok.rb

Overview

Grok Build sessions. PROVISIONAL, like the adapter: written against tokentelemetry's parser of this format, not against real Grok output.

Two things make this reader unlike every other one here. The session it is handed points at summary.json, while the conversation is in chat_history.jsonl beside it — so the streaming base reads a SIBLING file. And billed usage is not in the session directory at all: it lives in ~/.grok/logs/unified.jsonl, one row per request across every session, keyed by session id. A rotated log means no usage, which is why usage answers nil rather than zero when the log is gone.

Constant Summary collapse

TRANSCRIPT =
"chat_history.jsonl"
UNIFIED_LOG =
"unified.jsonl"
INFERENCE =

The row that records one completed request, per the reference parser.

"shell.turn.inference_done"
ROLES =
{ "user" => :user, "assistant" => :assistant, "system" => :system,
"tool" => :tool }.freeze

Constants inherited from Base

Base::MAX_RECORD_BYTES

Instance Attribute Summary

Attributes inherited from Base

#session

Instance Method Summary collapse

Methods inherited from Base

#branching?, #compactions, #each_message, #fidelity, #initialize, #messages, #partial?, #tree, #warnings

Constructor Details

This class inherits a constructor from Agent::Sessions::Readers::Base

Instance Method Details

#summaryObject

The session's summary.json, exposed because it holds what Layer 2 does not surface: generated_title, session_summary, current_model_id, the git branch and commit the work happened on.



29
30
31
32
33
34
35
36
37
# File 'lib/agent/sessions/readers/grok.rb', line 29

def summary
  @summary ||= begin
    parsed = JSON.parse(File.read(session.path))
    parsed.is_a?(Hash) ? parsed : {}
  rescue SystemCallError, JSON::ParserError
    warn_about("#{session.path} could not be read")
    {}
  end
end

#usageObject

Summed across this session's rows in the shared inference log.

prompt_tokens INCLUDES cached_prompt_tokens (the reference parser subtracts one from the other, as this gem does for Codex and Gemini), so input is the difference and cache_read the cached share. The cached count is clamped to the prompt first: a log row claiming more cached than prompt would otherwise produce a negative input.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/agent/sessions/readers/grok.rb', line 46

def usage
  rows = 0
  input = output = cached = reasoning = 0
  each_log_row do |record|
    ctx = record["ctx"]
    next unless ctx.is_a?(Hash)

    prompt = count_from(ctx["prompt_tokens"]).to_i
    hit = [count_from(ctx["cached_prompt_tokens"]).to_i, prompt].min
    rows += 1
    input += prompt - hit
    cached += hit
    output += count_from(ctx["completion_tokens"]).to_i
    reasoning += count_from(ctx["reasoning_tokens"]).to_i
  end
  return nil if rows.zero?

  Usage.new(input: input, output: output, cache_read: cached, reasoning: reasoning)
end