feat: zero-config praisonai usage command for local spend/token reporting#3158
feat: zero-config praisonai usage command for local spend/token reporting#3158praisonai-triage-agent[bot] wants to merge 2 commits into
Conversation
… 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>
|
@coderabbitai review |
|
/review |
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
✅ Action performedReview finished.
|
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdds a lazy-registered ChangesUsage reporting
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
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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 |
Greptile SummaryThis PR adds local token and cost reporting to the wrapper CLI. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (2): Last reviewed commit: "fix: preserve project identity, raise sc..." | Re-trigger Greptile |
|
@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
Phase 2: FIX Valid Issues Phase 3: Final Verdict |
|
Claude finished @MervinPraison's task —— View job Final Architecture Review — PR #3158 (
|
There was a problem hiding this comment.
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
📒 Files selected for processing (3)
src/praisonai-code/praisonai_code/cli/app.pysrc/praisonai-code/praisonai_code/cli/commands/__init__.pysrc/praisonai-code/praisonai_code/cli/commands/usage.py
| if project: | ||
| try: | ||
| sessions = get_project_session_store(project_id=project).list_sessions(limit=1000) | ||
| except Exception: | ||
| sessions = [] |
There was a problem hiding this comment.
🩺 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>
Fixes #3155
Summary
Adds a zero-config
praisonai usagecommand that reports aggregate token/cost spend from the already-persisted per-session data on disk — no external observability platform, no network, no configuration.Layer placement
praisonai-code). Core session store already mirrorsmodel/total_tokens/costper session andlist_sessions()surfaces them; this is a read-only reporting/UX surface.costfield (priced by the sameModelPricingas the per-run tracker).Changes
cli/commands/usage.py— new command: iterates the project-scoped + global default session stores (via existinglist_project_sessions), filters by--days/--project, groups byday|model|project, renders a compact rich table (with a Total row) or JSON via--json.usagein the lazy command table (cli/app.py) andcommands/__init__.pyalongsidesession/traces.Test plan
--dayswindow filter (and0= all) works--jsonemits machine-readable output; invalid--byexits 1Generated with Claude Code
Summary by CodeRabbit
usageCLI command for local token and cost reporting.