Skip to content

feat(models): show OpenCode Go provider usage quota - #844

Open
TiAmo-chen wants to merge 1 commit into
agegr:mainfrom
TiAmo-chen:feat/opencode-go-provider-usage
Open

TiAmo-chen wants to merge 1 commit into
agegr:mainfrom
TiAmo-chen:feat/opencode-go-provider-usage

Conversation

@TiAmo-chen

Copy link
Copy Markdown

Summary

Adds an OpenCode Go usage adapter so the provider usage card works for opencode-go (the provider added by the pi model catalog; it is already listed in the app, with icon, and authenticated through auth.json).

Today the request is rejected before any network call:

POST /api/provider-usage/query  {"providerId":"opencode-go"}
HTTP 400  {"error":"Unsupported provider"}

With this change the card shows the plan's rolling / weekly / monthly usage with their reset times.

Changes

  • lib/provider-usage-ids.ts — add opencode-go to PROVIDER_USAGE_IDS. ProviderUsageSummary gates rendering on this list, so no UI change is needed.
  • lib/provider-usage.ts
    • endpoint https://opencode.ai/zen/go/v1/usage and display name OpenCode Go;
    • normalizeOpenCodeGo() maps usage.{rolling,weekly,monthly}.percentremaining and the ISO resetsAt → epoch seconds (the client renders new Date(1000 * resetsAt));
    • queryProviderUsage() falls back to the first model's baseUrl when the provider itself has none (see below).
  • lib/provider-usage.test.mjs — coverage for the new adapter, the id predicate and the origin guard.

Why the baseUrl fallback is required

opencode-go is a catalog provider whose base URL is defined per model, so provider.baseUrl is undefined and the existing guard fails even after whitelisting:

provider.baseUrl                  = undefined
provider.getModels()[0].baseUrl   = https://opencode.ai/zen/go

isOfficialProviderUsageOrigin("opencode-go", provider.baseUrl)               → false
isOfficialProviderUsageOrigin("opencode-go", models[0].baseUrl)              → true
isOfficialProviderUsageOrigin("opencode-go", "https://proxy.example.com/…")  → false

The auth.baseUrl check inside fetchJson() is untouched, so pointing the provider at a custom origin is still rejected for official queries.

Response shape

GET https://opencode.ai/zen/go/v1/usage        (Authorization: Bearer <key from auth.json>)

{ "usage": {
    "rolling": { "status": "ok", "percent": 3,  "resetsAt": "2026-09-14T05:53:50.774Z" },
    "weekly":  { "status": "ok", "percent": 1,  "resetsAt": "2026-09-21T00:00:00.774Z" },
    "monthly": { "status": "ok", "percent": 98, "resetsAt": "2026-09-19T02:38:27.774Z" } } }

Only the used percentage and a reset timestamp are reported (no dollar amounts), so this produces three unit: "percent" buckets and no metrics.

Verification

  • node --experimental-strip-types --test lib/provider-usage.test.mjs5/5 pass, including the new
    normalizes OpenCode Go windows into remaining percentages and reset times.
  • Live call through queryProviderUsage("opencode-go") on this branch: status: "ready" with
    Rolling 95% / Weekly 98% / Monthly 2% remaining and reset timestamps.
  • The same logic was also exercised against the shipped 0.9.1 build artifact and through a real HTTP
    round-trip of /api/provider-usage/query, plus regression checks that deepseek still returns its
    balances and that unsupported ids still answer 400 Unsupported provider.

Notes

  • The query uses the credential pi has in auth.json. Setups that rotate a key pool will only see that
    single key; per-key rows could be a follow-up if wanted.
  • OpenCode Go reports no window length, only resetsAt, so the buckets carry no windowMinutes.
  • The payload's per-window status (ok / rate-limited) is currently unused; it could later map onto the
    existing period: "Unlimited" / rate-limit affordances.

PROVIDER_USAGE_IDS gains opencode-go with an adapter for
GET https://opencode.ai/zen/go/v1/usage (rolling/weekly/monthly used
percent plus reset time).

The provider's base URL lives on its models, not on the provider, so
queryProviderUsage() falls back to the first model's baseUrl before the
official-origin check. Custom origins stay rejected.
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.

1 participant