added anthropic/antigravity claude usage#20
Conversation
There was a problem hiding this comment.
Pull request overview
Adds Claude (Anthropic) quota/usage reporting to the mystatus plugin by probing Anthropic OAuth rate-limit headers, and improves Google Antigravity model quota extraction so Claude keys are less likely to be skipped.
Changes:
- Add Claude usage querying via Anthropic Messages API rate-limit headers (OAuth-first; Admin API fallback).
- Extend Google Antigravity model matching with multiple fallback keys and prefix matching.
- Update shared types/i18n plus README docs to reflect Claude support.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| plugin/mystatus.ts | Wires Claude usage into the main /mystatus aggregation flow. |
| plugin/lib/types.ts | Adds Anthropic/Claude auth-related types and config shape. |
| plugin/lib/i18n.ts | Adds Claude section strings and Anthropic API error formatter. |
| plugin/lib/google.ts | Enhances model quota lookup to support altKeys[] and prefix fallback. |
| plugin/lib/claude.ts | Implements Claude OAuth probe + parsing of rate-limit utilization headers, with Admin API fallback. |
| README.md | Documents Claude support and shows sample output (currently has a markdown formatting issue). |
| README.zh-CN.md | Documents Claude support and shows sample output in Chinese. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| async function getValidAccessToken( | ||
| authData: AnthropicAuthData, | ||
| ): Promise<string> { | ||
| if (!authData.access) { | ||
| throw new Error( | ||
| currentLang === "zh" | ||
| ? "缺少 OAuth access token" | ||
| : "Missing OAuth access token", | ||
| ); | ||
| } |
There was a problem hiding this comment.
queryClaudeUsage() treats Anthropic auth as usable when either access or refresh is present, but getValidAccessToken() throws if access is missing. If auth.json ever contains only a refresh token (common in some OAuth flows), Claude usage will always fail even though a refresh is possible. Consider allowing refresh-only by refreshing when access is absent, or by tightening the entry condition to require access before calling getValidAccessToken().
| return { | ||
| success: true, | ||
| output: `${t.account} Anthropic (${currentLang === "zh" ? "组织" : "Organization"})\n\n${currentLang === "zh" ? "管理员 API 已连接" : "Admin API connected"}`, |
There was a problem hiding this comment.
The Admin API fallback makes a network request but discards the response body and always returns a static "connected" message. This means the call provides no actual usage/quota data (and still incurs latency), which is confusing for users and makes the request effectively a health check. Consider parsing the usage report response into meaningful output (or if you only want a connectivity check, switch to a cheaper endpoint/approach and document that behavior).
| return { | |
| success: true, | |
| output: `${t.account} Anthropic (${currentLang === "zh" ? "组织" : "Organization"})\n\n${currentLang === "zh" ? "管理员 API 已连接" : "Admin API connected"}`, | |
| // Parse usage report body and include a minimal, human-readable summary. | |
| let usageReport: any = null; | |
| try { | |
| usageReport = await response.json(); | |
| } catch { | |
| // If parsing fails, we still return a connectivity message below. | |
| } | |
| let usageSummary = ""; | |
| if (usageReport && typeof usageReport === "object") { | |
| // Try to summarize by model if the expected structure is present. | |
| const buckets = (usageReport as any).buckets; | |
| if (Array.isArray(buckets) && buckets.length > 0) { | |
| const perModel: Record<string, number> = {}; | |
| for (const bucket of buckets) { | |
| const model = (bucket as any).group?.model ?? (bucket as any).model; | |
| const tokens = Number((bucket as any).usage?.input_tokens ?? 0) + | |
| Number((bucket as any).usage?.output_tokens ?? 0); | |
| if (model && Number.isFinite(tokens)) { | |
| perModel[model] = (perModel[model] ?? 0) + tokens; | |
| } | |
| } | |
| const lines: string[] = []; | |
| for (const [model, tokens] of Object.entries(perModel)) { | |
| lines.push(`- ${model}: ${tokens} tokens (today)`); | |
| } | |
| if (lines.length > 0) { | |
| usageSummary = | |
| `\n\n${currentLang === "zh" ? "今日按模型统计的使用情况:" : "Today's usage by model:"}\n` + | |
| lines.join("\n"); | |
| } | |
| } | |
| // Fallback: if we couldn't build a per-model summary, show raw JSON. | |
| if (!usageSummary) { | |
| const prettyJson = JSON.stringify(usageReport, null, 2); | |
| usageSummary = | |
| `\n\n${currentLang === "zh" ? "原始使用报告:" : "Raw usage report:"}\n` + | |
| prettyJson; | |
| } | |
| } | |
| const baseLine = | |
| `${t.account} Anthropic (${currentLang === "zh" ? "组织" : "Organization"})\n\n` + | |
| `${currentLang === "zh" ? "管理员 API 已连接" : "Admin API connected"}`; | |
| return { | |
| success: true, | |
| output: usageSummary ? `${baseLine}${usageSummary}` : baseLine, |
| const matchingKey = modelKeys.find((k) => | ||
| k.startsWith(modelConfig.prefix!), | ||
| ); | ||
| if (matchingKey) { | ||
| modelInfo = data.models[matchingKey]; |
There was a problem hiding this comment.
The prefix fallback uses Object.keys(data.models).find(...), which will pick the first key matching the prefix. If the API returns multiple keys with the same prefix (e.g. multiple claude-* variants), this can select an arbitrary model and display the wrong quota under the single "Claude" row. Consider making the selection deterministic (e.g., prefer a prioritized list, sort keys, or detect multiple matches and choose the best match explicitly).
| const matchingKey = modelKeys.find((k) => | |
| k.startsWith(modelConfig.prefix!), | |
| ); | |
| if (matchingKey) { | |
| modelInfo = data.models[matchingKey]; | |
| const matchingKeys = modelKeys | |
| .filter((k) => k.startsWith(modelConfig.prefix!)) | |
| .sort(); | |
| const selectedKey = matchingKeys[0]; | |
| if (selectedKey) { | |
| modelInfo = data.models[selectedKey]; |
| ## Claude (Anthropic) Account Usage | ||
|
|
||
| Account: Claude (Subscription) | ||
|
|
||
| 5-hour session limit | ||
| ███████████████████████░░░░░░░ 73% remaining 🟢 | ||
| Resets in: 3h 45m | ||
|
|
||
| 7-day weekly limit | ||
| ████████████████░░░░░░░░░░░░░░ 55% remaining 🟢 | ||
| Resets in: 4d 12h | ||
|
|
||
| ## Features |
There was a problem hiding this comment.
The README's "Output Example" code block is opened with a triple backtick but never closed before the "## Features" heading, so the rest of the document renders as a code block. Add a closing ``` line after the output example (after the last "Resets in" line) to restore proper markdown formatting.
Add Claude (Anthropic) subscription usage + fix Antigravity Claude model detection
Summary
What it does
Claude OAuth Usage: Makes a minimal API call (
claude-haiku-4-5, ~$0.001) with the user's existing OAuth token fromauth.jsonand reads theanthropic-ratelimit-unified-5h/7d-utilizationresponse headers. Displays 5-hour session and 7-day weekly remaining quota with progress bars, reset countdowns, and status indicators. Auto-refreshes expired tokens. Admin API kept as fallback for org users.Antigravity model fix:
extractModelQuotas()now supports multiple fallback keys (altKeys[]) and prefix matching, so Claude models (which the API may return under different keys likeclaude-sonnet-4-6instead ofclaude-opus-4-5-thinking) are no longer silently skipped.Files changed
plugin/lib/claude.ts— Rewritten from Admin API to OAuth rate-limit headersplugin/lib/types.ts— AddedAnthropicAuthDatainterfaceplugin/lib/i18n.ts— AddedclaudeSessionLimit/claudeWeeklyLimit(zh + en)plugin/mystatus.ts— PassauthData.anthropictoqueryClaudeUsage()plugin/lib/google.ts— ExtendedModelConfigwithaltKeys[]+prefixfallbackREADME.md/README.zh-CN.md— Updated docsReference
OAuth rate-limit header approach based on nsanden/claude-rate-monitor.
新增 Claude (Anthropic) 訂閱用量顯示 + 修復 Antigravity Claude 模型偵測
摘要
功能說明
Claude OAuth 用量: 使用用戶
auth.json中現有的 OAuth token,發送一個簡單的的 API call(claude-haiku-4-5,大概 $0.001),讀取回應中的anthropic-ratelimit-unified-5h/7d-utilization標頭。進度條、重置倒數計時和狀態指示器顯示 5 小時會話和 7 天週剩餘額度。自動刷新過期 token、保留 Admin API 作為備用方案。Antigravity 模型修復:
extractModelQuotas()現在支援多個備用鍵(altKeys[])和前綴匹配,因此 Claude 模型(API 可能以不同的鍵返回,例如claude-sonnet-4-6而非claude-opus-4-5-thinking)不再被靜默跳過。變更檔案
plugin/lib/claude.ts— 從 Admin API 改寫為 OAuth 速率限制標頭plugin/lib/types.ts— 新增AnthropicAuthData介面plugin/lib/i18n.ts— 新增claudeSessionLimit/claudeWeeklyLimit(中文 + 英文)plugin/mystatus.ts— 將authData.anthropic傳入queryClaudeUsage()plugin/lib/google.ts— 擴展ModelConfig,新增altKeys[]+prefix備用匹配README.md/README.zh-CN.md— 更新文件參考
OAuth 速率限制標頭方案參考自 nsanden/claude-rate-monitor。
Current output looks like