Skip to content

feat(analyzers): add Grok session usage tracking - #229

Merged
mike1858 merged 3 commits into
Piebald-AI:mainfrom
jimyag:feat/grok-support
Aug 1, 2026
Merged

feat(analyzers): add Grok session usage tracking#229
mike1858 merged 3 commits into
Piebald-AI:mainfrom
jimyag:feat/grok-support

Conversation

@jimyag

@jimyag jimyag commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Add local Grok session analysis so Splitrail can report usage from ~/.grok/sessions.

Key changes

  • Parse Grok chat_history.jsonl and authoritative updates.jsonl turn usage.
  • Track input, output, cached, reasoning, tool-call, and file-operation statistics.
  • Add official xAI API standard pricing for grok-4.5 and grok-build-0.1, including the 200k long-context tier and compatibility aliases.
  • Register the Grok analyzer and preserve full-session reload behavior when usage updates change.

Verification

  • cargo fmt --all --quiet
  • cargo build --quiet
  • cargo clippy --quiet -- -D warnings
  • cargo doc --quiet
  • git diff --check
  • Verified local cargo run --quiet -- stats output for the Grok session.

cargo test was not run per the repository instruction not to run task tests proactively.

Notes

Pricing follows the official xAI API pricing documentation:
https://docs.x.ai/developers/pricing

Summary by CodeRabbit

  • New Features
    • Added Grok support for discovering and analyzing conversation sessions.
    • Added tracking for messages, tool usage, tokens, costs, and session metadata.
    • Added pricing support for Grok models, aliases, and context-based tiers.
    • Added support for monitoring session changes and refreshing statistics.
    • Added Grok to the supported tools list.
  • Bug Fixes
    • Improved handling of malformed or synthetic conversation records.

Parse Grok session history and turn usage from ~/.grok/sessions, including token, cache, reasoning, and tool statistics. Add official xAI API pricing with context-aware tiers so Grok costs remain comparable with other analyzers.

Signed-off-by: jimyag <git@jimyag.com>
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jimyag, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0482e4d4-103f-44d1-b045-eee1c90f427b

📥 Commits

Reviewing files that changed from the base of the PR and between 335cae9 and b15b892.

📒 Files selected for processing (1)
  • src/analyzers/grok.rs
📝 Walkthrough

Walkthrough

This change adds Grok session discovery and parsing, context-tiered pricing, application support, analyzer registration, usage aggregation, metadata extraction, and tests.

Changes

Grok support

Layer / File(s) Summary
Context-tiered Grok pricing
src/models.rs, src/types.rs
Adds Grok model pricing, aliases, context-based cost calculation, and the Application::Grok variant.
Session and usage parsing
src/analyzers/grok.rs
Parses Grok chat and usage files, filters synthetic or invalid records, extracts metadata and tools, and calculates message usage and cost.
Analyzer registration and support surface
src/analyzers/mod.rs, src/main.rs, README.md
Exports and registers GrokAnalyzer and adds Grok to the supported tools list.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GrokAnalyzer
  participant GrokSessions
  participant ConversationMessages
  participant GrokPricing
  GrokAnalyzer->>GrokSessions: Discover and read session files
  GrokSessions-->>GrokAnalyzer: Return chat and usage records
  GrokAnalyzer->>ConversationMessages: Build enriched messages
  GrokAnalyzer->>GrokPricing: Calculate context-based costs
  GrokPricing-->>GrokAnalyzer: Return estimated costs
Loading

Possibly related PRs

Suggested reviewers: mike1858

Poem

A rabbit read Grok sessions at night,
And sorted each message just right.
Tokens hopped through pricing tiers,
Tools left tidy tracks and ears.
The analyzer joined the light.

🚥 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 clearly and concisely describes the main change: adding Grok session usage tracking.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@jimyag

jimyag commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author
image

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/analyzers/grok.rs (3)

299-318: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

session_metadata never returns a session name.

Both return paths produce None for the second tuple element. The Option<String> is therefore dead, and the session_name.is_none() check at line 365 is always true. Either read a title field from summary.json into GrokSessionSummary, or change the return type to DateTime<Utc> and derive the name only from the first user message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/analyzers/grok.rs` around lines 299 - 318, The session_metadata function
never produces a session name, making its Option<String> result and downstream
session_name.is_none() check ineffective. Read the title/name field from
summary.json into GrokSessionSummary and return it from both metadata paths,
preserving None only when no summary title exists.

346-349: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider reporting skipped malformed lines.

A parse failure discards the line without any signal. When updates.jsonl and chat_history.jsonl disagree in length, the resulting usage misattribution is then hard to diagnose. crate::utils::warn_once deduplicates messages, so a single warning per file stays quiet in normal operation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/analyzers/grok.rs` around lines 346 - 349, Update the JSON parsing match
in the Grok analyzer to call crate::utils::warn_once when simd_json::from_slice
fails, identifying the affected input file and malformed line, then continue
skipping the record. Use warn_once so repeated parse failures per file remain
deduplicated while preserving the existing successful-record path.

429-458: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the WalkDir depth with the declared glob pattern.

get_data_glob_patterns declares exactly two directory levels below the sessions root. discover_data_sources and is_available walk every depth. The two surfaces therefore accept different file sets. Bound the walk to keep them consistent and to avoid traversing unrelated subtrees.

♻️ Proposed fix to bound the traversal depth
-            .flat_map(|dir| WalkDir::new(dir).into_iter())
+            .flat_map(|dir| WalkDir::new(dir).min_depth(3).max_depth(3).into_iter())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/analyzers/grok.rs` around lines 429 - 458, Limit the WalkDir traversal in
both discover_data_sources and is_available to the same depth represented by
get_data_glob_patterns: exactly two directory levels below the sessions root,
while still matching chat_history.jsonl files at that location. Apply the depth
bound before filtering entries so unrelated deeper subtrees are not traversed.
src/models.rs (1)

1537-1599: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a source URL to the xAI model pricing block.

The grok-4.5 and grok-build-0.1 rates and 200k context thresholds match xAI pricing documentation, but unlike neighboring vendor entries, this block has no source URL comment. Add one to keep future rate changes auditable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models.rs` around lines 1537 - 1599, Add a source URL comment to the xAI
model pricing block containing the grok-4.5 and grok-build-0.1 registrations.
Place it alongside the existing “xAI Models” heading, using the official xAI
pricing documentation URL and leaving both add_model! definitions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/analyzers/grok.rs`:
- Around line 251-254: Update src/analyzers/grok.rs lines 251-254 in the
apply_turn_usage grouping logic to align usage records explicitly rather than
relying on positional zip; skip empty groups without consuming usage, or
otherwise ensure turns lacking turn_completed do not shift usage onto later
turns. Also update the assistant-record handling at src/analyzers/grok.rs lines
392-396 to create an implicit leading assistant group when
assistant_groups.last_mut() is None, so leading assistant messages receive their
token and cost usage.
- Around line 265-282: Update the estimated-cost model lookup to search the
entire group for the first message whose model is present, rather than only
using group.first(). Keep the existing token and cost calculation flow unchanged
once that model is found, while preserving the no-model None behavior.

In `@src/models.rs`:
- Around line 2664-2671: Update the Tiered cache-cost handling in
calculate_context_cost and cache_cost_for_caching so both paths pass the same
cache creation and read token inputs to calculate_tiered_cache_cost. If Tiered
pricing intentionally ignores cache creation tokens because it has no write
rate, document that behavior and add an audit test using different
cache_creation_tokens values; otherwise propagate the creation-token value
through both paths.

---

Nitpick comments:
In `@src/analyzers/grok.rs`:
- Around line 299-318: The session_metadata function never produces a session
name, making its Option<String> result and downstream session_name.is_none()
check ineffective. Read the title/name field from summary.json into
GrokSessionSummary and return it from both metadata paths, preserving None only
when no summary title exists.
- Around line 346-349: Update the JSON parsing match in the Grok analyzer to
call crate::utils::warn_once when simd_json::from_slice fails, identifying the
affected input file and malformed line, then continue skipping the record. Use
warn_once so repeated parse failures per file remain deduplicated while
preserving the existing successful-record path.
- Around line 429-458: Limit the WalkDir traversal in both discover_data_sources
and is_available to the same depth represented by get_data_glob_patterns:
exactly two directory levels below the sessions root, while still matching
chat_history.jsonl files at that location. Apply the depth bound before
filtering entries so unrelated deeper subtrees are not traversed.

In `@src/models.rs`:
- Around line 1537-1599: Add a source URL comment to the xAI model pricing block
containing the grok-4.5 and grok-build-0.1 registrations. Place it alongside the
existing “xAI Models” heading, using the official xAI pricing documentation URL
and leaving both add_model! definitions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fcb63fea-1c86-453c-ba7c-410bcb27b4a8

📥 Commits

Reviewing files that changed from the base of the PR and between f614099 and 58910a8.

📒 Files selected for processing (6)
  • README.md
  • src/analyzers/grok.rs
  • src/analyzers/mod.rs
  • src/main.rs
  • src/models.rs
  • src/types.rs

Comment thread src/analyzers/grok.rs Outdated
Comment thread src/analyzers/grok.rs Outdated
Comment thread src/models.rs
Align turn usage with non-empty assistant groups, recover costs from later model IDs, and preserve leading assistant usage. Improve session metadata, malformed-record diagnostics, discovery bounds, and document tiered cache pricing semantics.

Signed-off-by: jimyag <git@jimyag.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/analyzers/grok.rs (1)

170-201: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Skip blank lines in parse_turn_usages before parsing.

parse_chat_history_file skips blank lines with if line.trim().is_empty() { continue; } before calling simd_json::from_slice. parse_turn_usages has no equivalent check. A blank line in updates.jsonl fails JSON parsing and triggers a "Failed to parse Grok updates file" warning even though the line is not malformed.

Add the same blank-line skip used in the chat-history parser.

🩹 Proposed fix to skip blank lines
         .filter_map(|(line_index, line)| {
+            if line.trim().is_empty() {
+                return None;
+            }
             let mut bytes = line.as_bytes().to_vec();
             let record = match simd_json::from_slice::<GrokUpdateRecord>(&mut bytes) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/analyzers/grok.rs` around lines 170 - 201, Update parse_turn_usages to
skip lines whose trimmed content is empty before converting the line to bytes
and calling simd_json::from_slice, matching the existing behavior in
parse_chat_history_file; continue parsing non-blank lines and preserve current
warning behavior for malformed JSON.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/analyzers/grok.rs`:
- Around line 86-91: Update GrokSessionSummary to deserialize generated_title
and use it as the primary session display name, falling back to session_summary
when generated_title is absent; preserve the existing optional/default handling.

---

Outside diff comments:
In `@src/analyzers/grok.rs`:
- Around line 170-201: Update parse_turn_usages to skip lines whose trimmed
content is empty before converting the line to bytes and calling
simd_json::from_slice, matching the existing behavior in
parse_chat_history_file; continue parsing non-blank lines and preserve current
warning behavior for malformed JSON.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 06e5401f-c2bc-4444-b35d-cb87be2e005b

📥 Commits

Reviewing files that changed from the base of the PR and between 58910a8 and 335cae9.

📒 Files selected for processing (2)
  • src/analyzers/grok.rs
  • src/models.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/models.rs

Comment thread src/analyzers/grok.rs
Ignore blank update records before JSON parsing, and prefer generated session titles with session summaries as the fallback.

Signed-off-by: jimyag <git@jimyag.com>

@mike1858 mike1858 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you! Welcome addition.

@mike1858
mike1858 merged commit d994e9c into Piebald-AI:main Aug 1, 2026
6 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Aug 1, 2026
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