Skip to content

fix: update Chutes quota usage display#106

Merged
kargnas merged 6 commits intoopgginc:mainfrom
Daltonganger:fix/chutes-hybrid-usage
Mar 27, 2026
Merged

fix: update Chutes quota usage display#106
kargnas merged 6 commits intoopgginc:mainfrom
Daltonganger:fix/chutes-hybrid-usage

Conversation

@Daltonganger
Copy link
Copy Markdown
Contributor

Summary

  • update Chutes to track both daily request usage and the newer monthly 5× subscription value cap
  • show Chutes as dual quota percentages in the menu while using monthly value usage for status-bar priority
  • add Chutes parsing and percentage tests to cover the new usage model

Update

  • switch Chutes monthly usage date-range generation to UTC month boundaries and add coverage for month-boundary behavior

Verification

  • xcodebuild build -project "CopilotMonitor/CopilotMonitor.xcodeproj" -scheme "CopilotMonitor" -configuration Debug -destination 'platform=macOS' -clonedSourcePackagesDirPath "/Users/rubenbeuker/Library/Developer/Xcode/DerivedData/CopilotMonitor-aggycqisuzewkzczboobrrtuajll/SourcePackages"
  • xcodebuild test -project "CopilotMonitor/CopilotMonitor.xcodeproj" -scheme "CopilotMonitor" -destination 'platform=macOS' -clonedSourcePackagesDirPath "/Users/rubenbeuker/Library/Developer/Xcode/DerivedData/CopilotMonitor-aggycqisuzewkzczboobrrtuajll/SourcePackages" -only-testing:CopilotMonitorTests/ProviderUsageTests
  • launched the Debug app build and checked /usr/bin/log show --last 2m --predicate 'subsystem == "com.opencodeproviders"'

Daltonganger and others added 6 commits February 12, 2026 18:20
Integrate Nano-GPT as a quota-based provider with daily/monthly reset tracking, local icon assets, and auth parsing support. Add UI/CLI wiring and tests so Nano-GPT usage, balances, and the  subscription preset are available end-to-end.
…ations

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
# Conflicts:
#	CopilotMonitor/CopilotMonitor.xcodeproj/project.pbxproj
#	CopilotMonitor/CopilotMonitor/App/StatusBarController.swift
#	CopilotMonitor/CopilotMonitor/Helpers/ProviderMenuBuilder.swift
#	CopilotMonitor/CopilotMonitor/Providers/NanoGptProvider.swift
#	CopilotMonitor/CopilotMonitorTests/NanoGptProviderTests.swift
@op-gg-ai-devops
Copy link
Copy Markdown
Contributor

This PR enhances the Chutes provider by adding monthly value cap tracking (5x subscription cost) alongside daily requests, and introduces a robust fallback mechanism for the Antigravity provider when cache fetching fails.

Solid work here on adding the monthly cap tracking and the Antigravity fallback logic, it's a much-needed reliability boost. ngl, the recursive JSON parsing in extractMonthlyValueUsedUSD is clever, but it might get a bit heavy or unpredictable if the API response grows massive or deeply nested. Also, hardcoding monthlyValueMultiplier = 5.0 works for now, but keep an eye on it in case Chutes changes their billing policy down the road.


For a detailed, line-by-line code review (including bug detection and security checks), please write a comment like @op-gg-ai-devops review this / @op-gg-ai-devops 리뷰해줘, or add @op-gg-ai-devops as a Reviewer (automatically review when a commit is pushed to this PR).

@kargnas
Copy link
Copy Markdown
Member

kargnas commented Mar 27, 2026

@op-gg-ai-devops

@op-gg-ai-devops
Copy link
Copy Markdown
Contributor

op-gg-ai-devops bot commented Mar 27, 2026

✅ AI Code Review Completed

Status Task Result
Gather context: resolved issues, repo context, PR diff Metadata and diff collected.
Read full diff and all changed files for deep analysis All file changes processed.
Analyze code changes for bugs, security, performance, edge cases Comprehensive analysis complete.
Run smoke tests (build/typecheck) Build and typecheck verified.
Check CI status and existing reviews External status checks validated.
Write review_payload.json and update status comment Status update published.
Post review to PR Review posted — APPROVED with 3 inline comments.

Reviewed with anthropic/claude-opus-4-6


📋 View Full Logs

Copy link
Copy Markdown
Contributor

@op-gg-ai-devops op-gg-ai-devops bot left a comment

Choose a reason for hiding this comment

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

Review Summary

nice work overall — the Chutes dual-quota model (daily requests + monthly 5× value cap) is well thought out and cleanly integrated. the Antigravity accounts fallback is a solid reliability improvement too. tests cover the new static methods and even the UTC month-boundary edge case, which is great.

a few things worth calling out:

Good stuff:

  • the extractMonthlyValueUsedUSD recursive parser is clever with its fallback chain (aggregate → nested → item sum). handles both structured and flat API responses gracefully.
  • UTC date handling for month boundaries is correct and the test proves it (2026-03-01T00:30:00+14:00 → February in UTC). that's exactly the edge case people forget.
  • Antigravity fallback account resolution logic is thorough — preferred index → active index → first enabled account, with proper validation at each step.
  • all CI checks pass (Build, Test, Lint, CI) ✅

Minor concerns (see inline comments):

  • JSON string interpolation in the Antigravity fallback request body is a latent injection risk
  • the balance-based fallback for monthly value tracking has an assumption that may not hold
  • the generic key matching in extractMonthlyValueUsedUSD could pick up unrelated fields

none of these are blockers — the PR is solid and ready to merge with a couple of things to keep in mind for future iterations.


The bot will re-review automatically when a new commit is pushed to this branch, or you can trigger a review by mentioning @op-gg-ai-devops in a comment. You can also add specific directions, e.g.:

  • @op-gg-ai-devops review typos
  • @op-gg-ai-devops review security
  • @op-gg-ai-devops focus on performance

request.httpMethod = "POST"
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = "{\"project\":\"\(account.projectId)\"}".data(using: .utf8)
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.

Minor: Security String-interpolated JSON body: injection risk
String interpolation inside a raw JSON literal means if projectId ever contains a double-quote, backslash, or other JSON-special character, this produces malformed JSON (or worse, allows structure injection).

The existing GeminiCLIProvider does the same thing so it's a pre-existing pattern, but since you're adding a new callsite it's worth fixing here:

Suggested change
request.httpBody = "{\"project\":\"\(account.projectId)\"}".data(using: .utf8)
let bodyDict = ["project": account.projectId]
request.httpBody = try JSONSerialization.data(withJSONObject: bodyDict)

This guarantees proper escaping regardless of projectId contents.

}

if balance >= 0, balance <= monthlyValueCapUSD {
let inferredUsed = max(0, monthlyValueCapUSD - balance)
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.

Minor: Edge Case Balance-based fallback: may misattribute unrelated balance
This fallback assumes balance directly tracks the monthly value cap (i.e., used = cap - balance). But ChutesUserProfile.balance looks like it's an independent credits/wallet balance, not the remaining monthly value allowance.

If a user deposited extra credits, balance could exceed monthlyValueCapUSD, and this branch is skipped (the balance <= monthlyValueCapUSD guard). But if a user has a low balance for unrelated reasons, inferredUsed would be artificially high.

Consider adding a comment explaining when this heuristic is valid, or gate it behind a more specific condition (e.g., only use it for plans where balance actually tracks cap consumption).

let encodedUserId = userId.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? userId
var components = URLComponents(string: "https://api.chutes.ai/users/\(encodedUserId)/usage")
components?.queryItems = [
URLQueryItem(name: "page", value: "1"),
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.

Minor: Edge Case Pagination cap + generic key matching: potential undercount
Two things about this endpoint call:

  1. Pagination: limit=500 is hardcoded with no continuation. If a heavy user has 500+ usage records in a month, sumMonthlyValueUsedUSD will underreport the total cost. Consider either bumping the limit or adding pagination (fetch page 2+ until results are exhausted).

  2. Generic key matching in extractMonthlyValueUsedUSD: The fallback key list ("cost", "amount_usd", etc.) is very broad and searches recursively. If the API response contains a field like "cost" meaning per-unit cost rate rather than total cost, or a nested object happens to have "cost" for something unrelated, the extracted value would be wrong. This is a reasonable defensive approach when the API schema isn't documented, but worth a TODO to lock it down once the actual response shape is confirmed.

@kargnas kargnas merged commit 2f89701 into opgginc:main Mar 27, 2026
8 checks passed
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