Doubao: query Coding/Agent Plan usage via arkcli CLI - #2221
Conversation
Replace the Volcengine AK/SK signed API approach with arkcli CLI (SSO-based). The signed API was unreliable and required users to obtain AK/SK credentials separately; arkcli uses the same SSO session the user already has, making setup trivial. Changes: - DoubaoUsageFetcher: new fetchCodingPlanUsage(runArkcli:) runs `arkcli usage plan` and decodes the JSON response (items[].periods[] with label/percent/reset_at fields). Old Volcengine signer code removed. - DoubaoAPIFetchStrategy: try arkcli CLI first, fall back to Ark API key rate-limit probe. Removed AK/SK fallback path. - MenuCardView: split Doubao metrics into "Coding Plan" and "Agent Plan" groups with section headers for visual clarity. Other providers are unaffected (guard on provider == .doubao). - ProviderIcon-doubao.svg: replace placeholder smiley with official Volcengine logo SVG (MIT-licensed, from thesvg.org). - Tests: updated to match new arkcli JSON format and strategy interface. Closes steipete#1724.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 30acfec624
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| private struct ArkcliUsageItem: Decodable { | ||
| let product: String | ||
| let subscribed: Bool? | ||
| let periods: [ArkcliPeriod] |
There was a problem hiding this comment.
Decode error-only plan items without failing all usage
When arkcli usage plan returns a per-bucket failure, its usage-plan reference says the bucket is represented with items[].error while other buckets remain usable; making periods required means JSONDecoder rejects the entire stdout whenever one probed product returns an error item, so a single failed team/coding bucket prevents displaying otherwise valid subscribed plan usage.
Useful? React with 👍 / 👎.
| for item in response.items { | ||
| let isAgent = item.product == "agent-plan" | ||
| if let updatedAt = item.updatedAt, updatedAt > 0 { | ||
| updateTime = updateTime ?? Date(timeIntervalSince1970: updatedAt) |
There was a problem hiding this comment.
Treat arkcli updated_at as milliseconds
For CodingPlan items, the usage plan reference documents updated_at as epoch milliseconds, but this line passes the raw value to Date(timeIntervalSince1970:) as seconds; when the CLI emits a normal millisecond timestamp, the snapshot timestamp jumps thousands of years into the future, which makes “updated” labels and any freshness/history logic incorrect.
Useful? React with 👍 / 👎.
| var status: String? | ||
|
|
||
| for item in response.items { | ||
| let isAgent = item.product == "agent-plan" |
There was a problem hiding this comment.
Classify team Agent Plan products as agent windows
The CLI returns both personal and team product ids (agent-plan, coding-plan, agent-plan-team, coding-plan-team), but this exact comparison treats agent-plan-team as a coding product; team Agent Plan quotas therefore get unprefixed, can occupy the Coding Plan primary/secondary/tertiary windows, and disappear from the Agent Plan section.
Useful? React with 👍 / 👎.
| do { | ||
| let usage = try await self.cliUsageLoader() | ||
| return self.makeResult(usage: usage.toUsageSnapshot(), sourceLabel: "cli") |
There was a problem hiding this comment.
Honor explicit API source before running arkcli
When Doubao is configured with source api, this strategy still runs arkcli first and returns its SSO plan data on success, so users who explicitly selected API key probing—especially because arkcli is logged into a different account or they only want Ark rate-limit headers—never reach the API-key fallback despite .api being an advertised source mode.
Useful? React with 👍 / 👎.
|
Codex review: needs changes before merge. Reviewed July 17, 2026, 8:03 PM ET / July 18, 2026, 00:03 UTC. Summary Reproducibility: yes. from source: configure Doubao as Review metrics: 2 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Copy recommended automerge instructionNext step before merge
Security Review findings
Review detailsBest possible solution: Wire the persisted Doubao source setting through the normal refresh path, then add regression coverage proving Do we have a high-confidence way to reproduce the issue? Yes, from source: configure Doubao as Is this the best way to solve the issue? No: the provider strategy split is appropriate, but it must receive the persisted source mode from application refreshes; otherwise the documented source controls do not govern normal usage. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 02456949b895. Label changesLabel changes:
Label justifications:
Evidence reviewedAcceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (6 earlier review cycles)
|
- Split DoubaoAPIFetchStrategy into DoubaoCLIFetchStrategy (kind .cli, arkcli SSO) and DoubaoAPIFetchStrategy (kind .apiToken, AK/SK signed + Ark API key probe) so --source cli selects arkcli and --source api never silently falls through to SSO - Restore fetchCodingPlanUsage(credentials:) and decodeCodingPlanUsage to preserve the shipped AK/SK signed Volcengine API path - Auto-detect updated_at unit (seconds vs milliseconds) by magnitude so real arkcli output (epoch seconds) doesn't render as 1970 - Classify coding-plan-team as agent windows alongside agent-plan-team - Prefix agent extra windows with 'Agent ' for clear menu separation - Surface signed error (not generic missing-key) when AK/SK fails and no API key is configured - Add 20+ tests covering routing, fallback, cancellation, signed decode Co-Authored-By: Claude <noreply@anthropic.com>
Behavior proof (addressing ClawSweeper P1 findings)P1-1: AK/SK compatibility restoredThe signed Volcengine API path is fully restored in P1-2: Source routing fixedarkcli is now a separate
Redacted
|
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36ded78e83
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| pipeline: ProviderFetchPipeline(resolveStrategies: { _ in | ||
| [DoubaoAPIFetchStrategy()] | ||
| })), | ||
| sourceModes: [.auto, .cli, .api], |
There was a problem hiding this comment.
Honor Doubao source settings in the app
Fresh evidence: this commit advertises .cli/.api for Doubao, but app refreshes still get their source from ProviderRegistry → DoubaoProviderImplementation.sourceMode; that implementation does not override the default .auto. As a result, a config such as source: cli with an API key present still goes through auto and selects DoubaoAPIFetchStrategy, while source: api without credentials can still run arkcli, so the explicit modes documented by this change are ignored in the app.
Useful? React with 👍 / 👎.
| for plan in [ | ||
| (levelPrefix: "agent_", idPrefix: "doubao-agent"), | ||
| (levelPrefix: "coding_team_", idPrefix: "doubao-coding-team"), | ||
| (levelPrefix: "agent_team_", idPrefix: "doubao-agent-team"), |
There was a problem hiding this comment.
Surface extra-only Doubao plans in compact views
When arkcli returns only Agent Plan or team plan buckets, this conversion leaves primary/secondary nil and stores every quota only in extraRateWindows. The existing Doubao menu-bar metric path still falls through to snapshot.primary ?? snapshot.secondary in MenuBarMetricWindowResolver, and widget rows only opt into extra windows for Kimi/Antigravity, so those successfully fetched users get no compact quota/status display outside the new menu card.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 98c11fa7c9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| guard capturedStdout.count <= normalizedMaxOutputBytes, | ||
| capturedStderr.count <= normalizedMaxOutputBytes | ||
| else { |
There was a problem hiding this comment.
Keep subprocess output caps opt-in
With this guard on the default path, every existing SubprocessRunner.run caller now throws .outputTooLarge when either stream exceeds 1 MiB instead of receiving the previously truncated prefix. That breaks current expectations such as SubprocessRunnerTests.bounds oversized stdout/stderr and makes callers that use try? for large-but-parseable output (for example process/session scans) drop all data; make the strict failure behavior opt-in for the arkcli call or update the affected callers/tests explicitly.
Useful? React with 👍 / 👎.
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: Doubao: query Coding/Agent Plan usage via arkcli CLI This is item 1/1 in the current shard. Shard 0/1. This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f7bdbc4d6e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| private struct ArkcliUsageItem: Decodable { | ||
| let product: String | ||
| let subscribed: Bool? | ||
| let periods: [ArkcliPeriod]? |
There was a problem hiding this comment.
Decode periods only after filtering supported products
When arkcli includes an unsupported or future product bucket whose periods entries do not have the Doubao label/percent shape, this typed field makes JSONDecoder fail before the loop below can hit default: nil and skip that product. In that scenario, one unrelated bucket hides otherwise valid Coding/Agent Plan usage; decode unsupported item payloads more loosely or defer period decoding until after the product is recognized.
Useful? React with 👍 / 👎.
# Conflicts: # Sources/CodexBar/Resources/ar.lproj/Localizable.strings # Sources/CodexBar/Resources/ca.lproj/Localizable.strings # Sources/CodexBar/Resources/de.lproj/Localizable.strings # Sources/CodexBar/Resources/en.lproj/Localizable.strings # Sources/CodexBar/Resources/es.lproj/Localizable.strings # Sources/CodexBar/Resources/fa.lproj/Localizable.strings # Sources/CodexBar/Resources/fr.lproj/Localizable.strings # Sources/CodexBar/Resources/gl.lproj/Localizable.strings # Sources/CodexBar/Resources/id.lproj/Localizable.strings # Sources/CodexBar/Resources/it.lproj/Localizable.strings # Sources/CodexBar/Resources/ja.lproj/Localizable.strings # Sources/CodexBar/Resources/ko.lproj/Localizable.strings # Sources/CodexBar/Resources/nl.lproj/Localizable.strings # Sources/CodexBar/Resources/pl.lproj/Localizable.strings # Sources/CodexBar/Resources/pt-BR.lproj/Localizable.strings # Sources/CodexBar/Resources/ru.lproj/Localizable.strings # Sources/CodexBar/Resources/sv.lproj/Localizable.strings # Sources/CodexBar/Resources/th.lproj/Localizable.strings # Sources/CodexBar/Resources/tr.lproj/Localizable.strings # Sources/CodexBar/Resources/uk.lproj/Localizable.strings # Sources/CodexBar/Resources/vi.lproj/Localizable.strings # Sources/CodexBar/Resources/zh-Hans.lproj/Localizable.strings # Sources/CodexBar/Resources/zh-Hant.lproj/Localizable.strings
|
Maintainer verification:
Merged as |

Summary
arkcli usage planCLI (SSO-based) for fetching Coding Plan and Agent Plan usageWhy
The signed Volcengine API (
GetCodingPlanUsage/GetAgentPlanUsage) required users to obtain AK/SK credentials separately and did not work well. ThearkcliCLI uses the same SSO session the user already has, making setup trivial - just install arkcli andarkcli auth login.Changes
DoubaoUsageFetcher: newfetchCodingPlanUsage(runArkcli:)runsarkcli usage planand decodes the JSON response. Old Volcengine signer code removed.DoubaoAPIFetchStrategy: try arkcli CLI first, fall back to Ark API key rate-limit probe.MenuCardView: split Doubao metrics into two groups (Coding Plan / Agent Plan) with section headers. Other providers unaffected (guard provider == .doubao).ProviderIcon-doubao.svg: official Volcengine logo (MIT-licensed, from thesvg.org).Closes #1724.