Repository navigation
Conversation
Relays and pay-as-you-go services report what is left on the key: a wallet, a total quota, time windows, or only what was spent. Core now reads that (contract E, protocol 46) and this shows it where the column already answers "how much is left": the tightest of quota and windows is drawn with the account-quota bar (amber from 80 %), a wallet alone reads "Balance $18.40" over the billing line, a key without limits reads what it spent this month, and a failed read with nothing to show is an amber tag with the reason on hover. An older reading stays on screen when the latest read fails; the failure is in the hover, which lists every window (with its key / account scope), the exact amounts and the expiry. The row menu gets "Refresh balance", Check connection shows the balance it read under the OK line, and balance_updated re-reads the overview like the other upstream-state events. The protocol types are added to src/generated/tw-api.ts by hand until the pinned core is bumped; the Rust side does not build against the current pin because tw_api::ep::RefreshBalance does not exist there yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Merged as part of #318 (2026.10.14). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Depends on the core balances PR (ThinkWatch-Core, branch
feat/upstream-balances, contract E, protocol 46). Until core is released and the pin is bumped, the Rust side of this branch does not build:tw_api::ep::RefreshBalanceis not in the pinned tw-api, andts_bindingswill reportsrc/generated/tw-api.tsas out of date. TypeScript checks and tests pass.What it does
The 额度 / 计费 column of the upstream table shows what an upstream reports about the money or allowance left on its key (
ProviderView.balance). Upstreams without a balance are unchanged; disabled upstreams show the billing line, the same as for account quotas.scope: useradds 「账号额度」 in front (keyadds nothing)$USD,¥CNY, otherwise the code) over the billing line 「按量计费 · 默认价目表」spenterror, nothing read beforeerrorwith an older readingToken and request amounts are counts (「1.2M / 5M token」, 「320 / 1,000 次」). The hover lists the source and read time, the wallet, what was spent, the quota and every current window with its scope and exact amounts, the expiry date and the last failure. Windows whose reset time has passed are left out, the same rule as account quotas.
daily,monthlyand<n>wwindows get names (每天, 每月, 1 周).Also:
POST /providers/{name}/balance/refreshand shows a toast that turns into what was read, or into the failure with its reason; the overview is re-read afterwards.TestLine), amber when the read failed.balance_updatedre-reads the overview the wayauth_changed/proxy_changeddo (same coalescing inuseCoreLink).Formatting lives in
src/upstreams/balance.ts(pure, withbalance.test.tscovering quota, windows incl. the amber threshold and scopes, token / request units, wallet USD / CNY / other, mixed, spent, error with and without a reading, and null) andbalance.i18n.ts(both languages).Protocol types added by hand
To
src/generated/tw-api.ts, matching the core branch's names:Balance,BalanceQuota,BalanceWindow,BalanceScope,BalanceSource,Money,Spent,SpentPeriod;ProviderView.balance: Balance | null;ProviderTestResult.balance(written optional here so the dialog's own failure result inUpstreamDialog.tsx, which is being rewritten in a parallel PR, still type-checks; core sends it asBalance | null); the event{ kind: "balance_updated", id, provider, at_ms }; the endpointRefreshBalanceinENDPOINTS/Endpoints.RefreshBalanceis added to the webview call table in bothsrc/control.tsandsrc-tauri/src/call.rs.ProviderView.balance_settingandProviderInput.balanceare left to the wizard PR. Regenerating the file after the pin bump replaces all of this.The screenshot pipeline's stored overviews (
scripts/shots/core/*/overview.json) get"balance": nullper upstream so the mock type-checks;oracle.shregenerates them after the pin bump. Its mock refusesRefreshBalancelike every other write.Verification
pnpm typecheck: passes.pnpm test: 105 files, 1118 tests pass.cargo fmt --manifest-path src-tauri/Cargo.toml --all --check: passes. Clippy and cargo test need the core bump (see above).?page=upstreams, light, dark and English. The harness mock gave its upstreams one balance per shape: openrouter a USD wallet with a failed later read, deepseek a CNY wallet,relay-hka Sub2API quota,relay-twquota + wallet,relay-sg5h / daily windows (86 %, amber),oneapi-laba New API read failure,corp-gwThinkWatch windows in USD, tokens and requests with key and account scopes (30-day account window at 82 % drawn),corp-devonly spent this month. ItsRefreshBalancere-reads and emitsbalance_updated;TestProviderreturns the balance of the upstream at the same address. Checked: the hovers, the row menu, refresh success and failure toasts, and Check connection for a window, a mixed and a failed balance.Not covered
src/i18n/core.zh.jsononce the core PR lists its message codes; until then the reason shows in English.🤖 Generated with Claude Code