Skip to content

feat: zero-config praisonai usage command for local spend/token reporting#3158

Open
praisonai-triage-agent[bot] wants to merge 2 commits into
mainfrom
claude/issue-3155-20260718-0851
Open

feat: zero-config praisonai usage command for local spend/token reporting#3158
praisonai-triage-agent[bot] wants to merge 2 commits into
mainfrom
claude/issue-3155-20260718-0851

Conversation

@praisonai-triage-agent

@praisonai-triage-agent praisonai-triage-agent Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Fixes #3155

Summary

Adds a zero-config praisonai usage command that reports aggregate token/cost spend from the already-persisted per-session data on disk — no external observability platform, no network, no configuration.

praisonai usage                 # last 30 days, grouped by day
praisonai usage --by model      # grouped by model
praisonai usage --by project    # grouped by project
praisonai usage --days 7        # only the last week
praisonai usage --json          # machine-readable output

Layer placement

  • Wrapper CLI only (praisonai-code). Core session store already mirrors model/total_tokens/cost per session and list_sessions() surfaces them; this is a read-only reporting/UX surface.
  • No core change, no new dependencies, no Agent-class changes. Cost comes from the persisted cost field (priced by the same ModelPricing as the per-run tracker).

Changes

  • cli/commands/usage.py — new command: iterates the project-scoped + global default session stores (via existing list_project_sessions), filters by --days/--project, groups by day|model|project, renders a compact rich table (with a Total row) or JSON via --json.
  • Registered usage in the lazy command table (cli/app.py) and commands/__init__.py alongside session/traces.

Test plan

  • Grouping by day/model/project sums tokens & cost correctly
  • --days window filter (and 0 = all) works
  • --json emits machine-readable output; invalid --by exits 1
  • Empty store prints "No usage recorded yet"
  • End-to-end aggregation over seeded session records verified (1000 + 200 tokens → 1200 total)

Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a usage CLI command for local token and cost reporting.
    • View usage totals grouped by day, model, or project.
    • Filter results by project or recent activity within a specified number of days.
    • Supports table and JSON output formats.
    • Displays per-group and overall totals.

… reporting (fixes #3155)

Aggregates already-persisted per-session total_tokens/cost from the local
session store(s) and reports by day/model/project with --days/--project/--json
filters. Wrapper-only reporting surface; no core change, no new deps.

Co-authored-by: MervinPraison <MervinPraison@users.noreply.github.com>
@MervinPraison

Copy link
Copy Markdown
Owner

@coderabbitai review

@MervinPraison

Copy link
Copy Markdown
Owner

/review

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@MervinPraison MervinPraison added pipeline/blocked:ci Blocked: CI not green on HEAD pipeline/blocked:no-final Blocked: no FINAL @claude trigger yet pipeline/final-claude-pending Reviews done; waiting for FINAL @claude labels Jul 18, 2026
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b20e3a1c-2f59-45d0-a02d-f9705ee90ff6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a lazy-registered praisonai usage command that reads local session records, filters and groups token/cost usage by day, model, or project, and emits table or JSON output.

Changes

Usage reporting

Layer / File(s) Summary
Lazy command registration
src/praisonai-code/praisonai_code/cli/app.py, src/praisonai-code/praisonai_code/cli/commands/__init__.py
Registers usage in the CLI registry and exposes its lazily loaded command app as usage_app.
Session usage aggregation
src/praisonai-code/praisonai_code/cli/commands/usage.py
Parses timestamps, reads local session stores, normalizes token and cost fields, filters by days, and groups results by day, model, or project.
Usage command output
src/praisonai-code/praisonai_code/cli/commands/usage.py
Validates --by, computes overall totals, and prints either JSON or a formatted table, including empty-data handling and invalid-option exit behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant LocalSessionStores
  participant OutputController
  CLI->>LocalSessionStores: Read session records
  LocalSessionStores-->>CLI: Return usage rows
  CLI->>CLI: Filter and group usage
  CLI->>OutputController: Emit JSON or table totals
Loading

Suggested reviewers: mervinpraison

🚥 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 summarizes the main change: a zero-config local usage reporting command.
Linked Issues check ✅ Passed The PR adds a local usage command with day/model/project grouping, days and project filters, table/JSON output, and lazy CLI registration.
Out of Scope Changes check ✅ Passed The changes stay focused on the usage command and its registration, with no evident unrelated scope added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/issue-3155-20260718-0851

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.

@greptile-apps

greptile-apps Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds local token and cost reporting to the wrapper CLI. The main changes are:

  • A new praisonai usage command with day, model, and project grouping.
  • Date and project filters with table or JSON output.
  • Lazy command registration and package export updates.
  • Separate reads for project and global session stores.
  • Store error reporting and duplicate-session handling.

Confidence Score: 5/5

This looks safe to merge.

  • No additional blocking issues qualify for this follow-up review.
  • The latest changes surface store errors and preserve separate store labels.

Important Files Changed

Filename Overview
src/praisonai-code/praisonai_code/cli/commands/usage.py Adds local session usage collection, filtering, aggregation, and output.
src/praisonai-code/praisonai_code/cli/app.py Registers the usage command in the lazy command table.
src/praisonai-code/praisonai_code/cli/commands/init.py Exports the usage command through the existing lazy import pattern.

Reviews (2): Last reviewed commit: "fix: preserve project identity, raise sc..." | Re-trigger Greptile

Comment thread src/praisonai-code/praisonai_code/cli/commands/usage.py Outdated
Comment thread src/praisonai-code/praisonai_code/cli/commands/usage.py Outdated
Comment thread src/praisonai-code/praisonai_code/cli/commands/usage.py Outdated
@MervinPraison

Copy link
Copy Markdown
Owner

@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Focus ONLY on Python packages (praisonaiagents, praisonai). Do NOT modify praisonai-rust or praisonai-ts. Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.

Phase 1: Review per AGENTS.md

  1. Protocol-driven: check heavy implementations vs core SDK
  2. Backward compatible: ensure zero feature regressions
  3. Performance: no hot-path regressions
  4. SDK value: review in depth whether the change genuinely adds value to the SDK — never add features for the sake of adding them. It must strengthen the SDK (simpler, more user-friendly, robust, world-class, secure). If it does not clearly add value, request changes or recommend rejecting/closing rather than merging scope creep
  5. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params.
  6. Repo routing: agent-callable tools → PraisonAI-Tools; lifecycle plugins → PraisonAI-Plugins; optional sandbox backends → PraisonAI-Plugins (praisonai.sandbox entry point) — request changes if wrongly added to praisonaiagents/

Phase 2: FIX Valid Issues
7. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix
8. Also independently identify and fix any gaps or issues you find in the changed code — do not rely only on prior reviewer feedback
9. Push all code fixes directly to THIS branch (do NOT create a new PR)
10. Comment a summary of exact files modified and what you skipped

Phase 3: Final Verdict
11. If all issues are resolved, approve the PR / close the Issue
12. If blocking issues remain, request changes / leave clear action items

@MervinPraison MervinPraison added pipeline/awaiting-merge-gate FINAL done; waiting for merge gate / CI pipeline/blocked:cooldown Blocked: post-push or @claude cooldown and removed pipeline/final-claude-pending Reviews done; waiting for FINAL @claude pipeline/blocked:no-final Blocked: no FINAL @claude trigger yet labels Jul 18, 2026
@praisonai-triage-agent

praisonai-triage-agent Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Claude finished @MervinPraison's task —— View job


Final Architecture Review — PR #3158 (praisonai usage)

Verdict: ✅ Approve — architecture is sound and all three P1 reviewer findings are fixed.


Phase 1 — Architecture (per AGENTS.md)

  • Layer placement correct — wrapper-only (praisonai-code CLI), read-only reporting over the already-persisted total_tokens/cost/model session fields.
  • No core change, no new deps, no Agent bloat — reuses existing session-store plumbing.
  • Registration follows the lazy __getattr__ command pattern in commands/__init__.py + app.py.
  • Genuine SDK value — zero-config local spend/token visibility with no network egress or observability platform. Not scope creep.

Phase 2 — Fixes pushed (commit c1830d3)

All in src/praisonai-code/praisonai_code/cli/commands/usage.py:

  • Github actions fix #1 Session-limit truncation — raised per-store scan from 1000100_000 (bounded constant _STORE_SCAN_LIMIT), so realistic stores and --days 0 no longer silently drop older sessions.
  • Merge pull request #1 from MervinPraison/develop #2 Merged stores lose project identity — the no---project path now reads the current-project and global stores separately, tagging rows current/global (de-duplicating shared session ids). praisonai usage --by project reports each source distinctly instead of collapsing to one current bucket.
  • Main #3 Store failures reported as empty usage — store open/read exceptions are now surfaced: a print_warning("Usage may be incomplete: …") in table mode and a new errors[] field in JSON. No usage recorded yet prints only when there were no errors, so a missing/damaged store is distinguishable from genuinely empty usage.

Testing

  • ✅ Logic verified: model split (gpt-4o=1000, claude=200), project split preserved (current=1200, global=500), total = 1700, --days window filter.
  • Note: typer is not installed in this CI sandbox, so the full Typer command couldn't be exercised end-to-end here; pure aggregation/grouping/collection helpers were tested in isolation and pass. No dedicated test_usage* file exists in the repo.

Skipped / not changed

  • No changes to app.py / __init__.py (registration already correct).
  • No core (praisonaiagents) changes; nothing routed to Tools/Plugins (this is a CLI reporting surface, correctly in the wrapper).
    · Branch claude/issue-3155-20260718-0851

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

Actionable comments posted: 1

🤖 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/praisonai-code/praisonai_code/cli/commands/usage.py`:
- Around line 49-53: Update the project-session retrieval exception handling in
usage to avoid silently replacing read failures with an empty list: accept or
otherwise access the output controller, report the caught error through
output.print_error, and update the usage caller to pass output while preserving
the existing successful session-list behavior.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d394d27-a67e-4cb3-817d-ec3dbc87ad3c

📥 Commits

Reviewing files that changed from the base of the PR and between 74b5f0f and 5b74461.

📒 Files selected for processing (3)
  • src/praisonai-code/praisonai_code/cli/app.py
  • src/praisonai-code/praisonai_code/cli/commands/__init__.py
  • src/praisonai-code/praisonai_code/cli/commands/usage.py

Comment on lines +49 to +53
if project:
try:
sessions = get_project_session_store(project_id=project).list_sessions(limit=1000)
except Exception:
sessions = []

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Avoid silently catching Exception.

Catching a broad exception and silently returning an empty list can hide legitimate issues, such as a corrupted SQLite database, missing permissions, or an invalid project ID. The user will simply see "No usage recorded yet" instead of knowing there was a read error.

Consider logging the error or printing a warning using output.print_error so the user is aware the data could not be retrieved.

💡 Suggested fix (using output controller)
-def _collect_rows(project: Optional[str]) -> List[Dict[str, Any]]:
+def _collect_rows(project: Optional[str], output: Any = None) -> List[Dict[str, Any]]:
     """Read session records from the local store(s) as flat usage rows.
 
     When ``project`` is given, only that project's scoped store is read;
     otherwise the current project store is merged with the global default
     store (mirrors ``session list`` semantics).
     """
     from ..state.project_sessions import (
         get_project_session_store,
         list_project_sessions,
     )
 
     if project:
         try:
             sessions = get_project_session_store(project_id=project).list_sessions(limit=1000)
-        except Exception:
+        except Exception as e:
+            if output:
+                output.print_error(f"Failed to read session store for project '{project}': {e}")
             sessions = []
     else:

Then, update the caller in usage to pass output.

🧰 Tools
🪛 Ruff (0.15.21)

[warning] 52-52: Do not catch blind exception: Exception

(BLE001)

🤖 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/praisonai-code/praisonai_code/cli/commands/usage.py` around lines 49 -
53, Update the project-session retrieval exception handling in usage to avoid
silently replacing read failures with an empty list: accept or otherwise access
the output controller, report the caught error through output.print_error, and
update the usage caller to pass output while preserving the existing successful
session-list behavior.

Source: Linters/SAST tools

…failures in usage

Addresses reviewer P1 findings on `praisonai usage`:
- Read current-project and global stores separately so `--by project`
  no longer collapses both sources into a single `current` bucket.
- Raise per-store scan limit (1000 -> 100_000) so large stores are not
  silently truncated (also affects `--days 0`).
- Surface store-open/read failures via warnings (table) and an `errors`
  field (JSON) instead of reporting them as empty usage.

Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
@MervinPraison MervinPraison added pipeline/blocked:stale-final Blocked: FINAL stale after new commits and removed pipeline/blocked:stale-final Blocked: FINAL stale after new commits labels Jul 18, 2026
@praisonai-triage-agent praisonai-triage-agent Bot removed the pipeline/blocked:cooldown Blocked: post-push or @claude cooldown label Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pipeline/awaiting-merge-gate FINAL done; waiting for merge gate / CI pipeline/blocked:ci Blocked: CI not green on HEAD

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Zero-config local spend/usage command: aggregate token and cost visibility across sessions

1 participant