dsh-provider-usage 0.3.10 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -9
- package/README_ZH.md +45 -8
- package/docs/panel-codex-en.png +0 -0
- package/docs/panel-codex-zh.png +0 -0
- package/docs/panel-ds-en.png +0 -0
- package/docs/panel-ds-zh.png +0 -0
- package/docs/provider-quota-endpoints.json +184 -0
- package/docs/provider-quota-endpoints.md +274 -0
- package/lib/index.js +71 -27
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -15,15 +15,15 @@
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
17
17
|
- **Auto-detection** — enumerates the provider routes registered in the current profile (`ctx.llm`); zero configuration for well-known routes.
|
|
18
|
-
- **Per-kind wire adapters** — routes with no public balance/
|
|
18
|
+
- **Per-kind wire adapters** — routes with no public balance/usage API (Google, Mistral, Groq, Bedrock, Azure, Qwen Token Plan, …) are listed as `unsupported` instead of being silently dropped:
|
|
19
19
|
|
|
20
20
|
| kind | routes | query | shows |
|
|
21
21
|
|---|---|---|---|
|
|
22
22
|
| `deepseek` | `deepseek-official`, `deepseek` | `GET {baseURL}/user/balance` | total / granted / topped-up balance |
|
|
23
23
|
| `moonshot` | `moonshotai-cn`, `moonshotai` | `GET {baseURL}/users/me/balance` | available / voucher / cash balance |
|
|
24
|
-
| `kimi-coding` | `kimi-coding` | `GET {baseURL}/v1/usages` | weekly
|
|
24
|
+
| `kimi-coding` | `kimi-coding` | `GET {baseURL}/v1/usages` | weekly usage + rate-limit windows, reset countdown |
|
|
25
25
|
| `openrouter` | `openrouter` | `GET {origin}/api/v1/credits` | credits used / total |
|
|
26
|
-
| `github-copilot` | `github-copilot` | `GET api.github.com/copilot_internal/user` | plan
|
|
26
|
+
| `github-copilot` | `github-copilot` | `GET api.github.com/copilot_internal/user` | plan usage snapshots (paid) or monthly usage (free) |
|
|
27
27
|
| `openai-codex` | `openai-codex` | `GET {baseURL}/wham/usage` | ChatGPT subscription 5h / weekly windows + credits + spend control (**OAuth login**, not an API key — see [OpenAI Codex via OAuth](#openai-codex-via-oauth)) |
|
|
28
28
|
| `openai` | `openai` | `GET {origin}/v1/organization/costs` | current-month spend (**admin key required**; a regular key fails with 403) |
|
|
29
29
|
| `anthropic` | `anthropic` | `GET {baseURL}/v1/organizations/cost_report` | current-month spend (**admin key required**, `x-api-key` auth) |
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
| `vercel-ai-gateway` | `vercel-ai-gateway` | `GET {baseURL}/v1/credits` | team credit balance |
|
|
34
34
|
| `xai` | `xai` | `GET {baseURL}/billing/credits` | prepaid balance (USD) |
|
|
35
35
|
- **Credentials stay safe** — API keys are resolved per request through the harness credentials service (environment variables / `~/.dsh/.credentials.yaml`); never cached, never written to disk. For OAuth providers (OpenAI Codex) the plugin reads the grant record the sign-in flow stored, and refreshes it transparently when it is about to expire.
|
|
36
|
-
- **Floating ball widget** — a draggable floating ball opens the usage panel. Drop it anywhere in the viewport (position persisted); it docks by default at the bottom-left of the chat area with equal margins, and the panel-header home button sends it back. The panel scrolls when the provider list grows past its height, and its top edge is draggable to resize it taller or shorter (height persisted). The halo around the ball encodes the health of the provider **in use** — the focused session's own selection (its composer's model seat), tracked live on the client, so switching sessions re-highlights that session's provider immediately without re-selecting a model: green all good, amber
|
|
36
|
+
- **Floating ball widget** — a draggable floating ball opens the usage panel. Drop it anywhere in the viewport (position persisted); it docks by default at the bottom-left of the chat area with equal margins, and the panel-header home button sends it back. The panel scrolls when the provider list grows past its height, and its top edge is draggable to resize it taller or shorter (height persisted). The halo around the ball encodes the health of the provider **in use** — the focused session's own selection (its composer's model seat), tracked live on the client, so switching sessions re-highlights that session's provider immediately without re-selecting a model: green all good, amber when a usage window has under 30% left or a balance below the yellow threshold, red on query failure / missing key / usage ≥90% / balance below the red threshold. Idle providers running low do not color the ball — switch to another provider with enough headroom and the ball turns green again; the panel marks the in-use provider and still lists every provider's numbers.
|
|
37
37
|
- **Version badge** — the panel header shows the running plugin version next to the title, so it is obvious which release is loaded.
|
|
38
38
|
- **Bilingual panel** — built-in Chinese/English UI; follows the harness language by default, with a one-click toggle in the panel header (persisted in localStorage).
|
|
39
39
|
- **Configurable refresh** — adjustable in the panel (15s–30min, persisted in localStorage); the default comes from the plugin config.
|
|
@@ -50,7 +50,7 @@ The floating ball (bottom-left, with the green healthy halo) and the open usage
|
|
|
50
50
|
|
|
51
51
|
## OpenAI Codex via OAuth
|
|
52
52
|
|
|
53
|
-
OpenAI Codex is a **ChatGPT-subscription** provider: it authenticates with an OAuth access token, not an API key, so there is nothing to paste into a key field. dsh itself has no OAuth *button* for this route — but this plugin can still query its
|
|
53
|
+
OpenAI Codex is a **ChatGPT-subscription** provider: it authenticates with an OAuth access token, not an API key, so there is nothing to paste into a key field. dsh itself has no OAuth *button* for this route — but this plugin can still query its usage, because it reads the OAuth grant out of the harness credential store. Set the provider up once, and the usage panel shows your real 5-hour / weekly Codex windows.
|
|
54
54
|
|
|
55
55
|
### 1. Make sure the route exists
|
|
56
56
|
|
|
@@ -80,7 +80,7 @@ records:
|
|
|
80
80
|
|
|
81
81
|
> The grant must land in the harness credential store (the record above). Codex clients that keep their own credential file (e.g. `dsh-codex`'s `$DSH_HOME/.openai-codex-auth.json`, or the Codex CLI's `~/.codex/auth.json`) do not write this record, so this plugin cannot see them.
|
|
82
82
|
|
|
83
|
-
### 3. Watch the
|
|
83
|
+
### 3. Watch the usage
|
|
84
84
|
|
|
85
85
|
That's it. The route is auto-detected (`ctx.llm` lists `openai-codex`), and the plugin:
|
|
86
86
|
|
|
@@ -90,6 +90,37 @@ That's it. The route is auto-detected (`ctx.llm` lists `openai-codex`), and the
|
|
|
90
90
|
|
|
91
91
|
The panel then shows your subscription's **5h limit**, **weekly** windows (used %, reset countdown) plus **credits** and **spend control** balances when the plan reports them. If the grant is missing the card reads "OAuth authorization missing (llm-pi-ai/openai-codex)" — sign in again with step 2.
|
|
92
92
|
|
|
93
|
+
### 4. Troubleshooting: intermittent "Our servers are currently overloaded"
|
|
94
|
+
|
|
95
|
+
The Codex backend occasionally answers with `Codex error: Our servers are currently overloaded. Please try again later.`, and the harness fails the round with `PI_AI_ERROR`. This is **transient overload on OpenAI's side** (account, quota, and network are usually fine — `GET /wham/usage` confirms window headroom), yet the default configuration never retries, for two reasons:
|
|
96
|
+
|
|
97
|
+
1. pi-ai's Codex client recognizes `overloaded` as retryable, but its default retry count is 0 (`dsh-llm-pi-ai` explicitly passes `maxRetries: 0`);
|
|
98
|
+
2. once the error bubbles up, its text contains no `5xx` / `rate limit` / `timeout` keyword, so it is classified as the catch-all `PI_AI_ERROR` — which is **not** among `dsh-llm-retry`'s default retryable codes (`EMPTY_RESPONSE` / `RATE_LIMIT` / `SERVER` / `TIMEOUT` / `TRANSPORT`), so the round fails immediately.
|
|
99
|
+
|
|
100
|
+
Add a `retryPolicy` for this provider in `~/.dsh/settings.yaml` that includes `PI_AI_ERROR` in the retryable codes (takes effect on a new session):
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
llm-pi-ai:
|
|
104
|
+
providers:
|
|
105
|
+
openai-codex:
|
|
106
|
+
retryPolicy:
|
|
107
|
+
mode: normal
|
|
108
|
+
maxRetries: 10
|
|
109
|
+
retryableCodes:
|
|
110
|
+
- EMPTY_RESPONSE
|
|
111
|
+
- RATE_LIMIT
|
|
112
|
+
- SERVER
|
|
113
|
+
- TIMEOUT
|
|
114
|
+
- TRANSPORT
|
|
115
|
+
- PI_AI_ERROR
|
|
116
|
+
backoff:
|
|
117
|
+
initialDelayMs: 2000 # first retry delay, doubled each attempt
|
|
118
|
+
maxDelayMs: 60000 # per-attempt delay cap
|
|
119
|
+
jitterRatio: 0.2 # ±20% jitter
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Do not confuse this with the other, **deterministic** failure: some models are unavailable to ChatGPT-subscription accounts, and the backend answers `400 The '<model>' model is not supported when using Codex with a ChatGPT account.` (observed with e.g. `gpt-5.3-codex-spark`, `gpt-5-codex`). That is a permanent error — retrying won't help; switch to a model your account supports (e.g. the `gpt-5.4` / `gpt-5.5` / `gpt-5.6` families).
|
|
123
|
+
|
|
93
124
|
## Install
|
|
94
125
|
|
|
95
126
|
> [!NOTE]
|
|
@@ -112,7 +143,7 @@ pnpm pack # produces dsh-provider-usage-<version>.tgz
|
|
|
112
143
|
dsh plugin --profile web add ./dsh-provider-usage-<version>.tgz
|
|
113
144
|
```
|
|
114
145
|
|
|
115
|
-
Install the **tarball**, not the repo directory: `dsh plugin add .` links the repo, whose own `node_modules` then shadows the harness's shared `@deepseek-ai/cordis` instance and the host half never registers (RPC 404). The link form is still handy for client-only UI iteration — the browser bundle is self-contained, so a rebuild + page refresh picks it up — but switch to the tarball (or the npm release) whenever you need the host half. If pnpm fails with `EPERM ... symlink` while replacing a linked install, delete the stale `node_modules/dsh-provider-usage` junction in the profile directory and retry.
|
|
146
|
+
Install the **tarball**, not the repo directory: `dsh plugin --profile web add .` links the repo, whose own `node_modules` then shadows the harness's shared `@deepseek-ai/cordis` instance and the host half never registers (RPC 404). The link form is still handy for client-only UI iteration — the browser bundle is self-contained, so a rebuild + page refresh picks it up — but switch to the tarball (or the npm release) whenever you need the host half. If pnpm fails with `EPERM ... symlink` while replacing a linked install, delete the stale `node_modules/dsh-provider-usage` junction in the profile directory and retry.
|
|
116
147
|
|
|
117
148
|
Restart `dsh web` after changing the plugin set (a plugin add/remove requires a restart; afterwards, code changes only need a rebuild + re-add + page refresh).
|
|
118
149
|
|
|
@@ -122,7 +153,7 @@ Restart `dsh web` after changing the plugin set (a plugin add/remove requires a
|
|
|
122
153
|
dsh plugin --profile web add dsh-provider-usage@latest
|
|
123
154
|
```
|
|
124
155
|
|
|
125
|
-
Then restart `dsh web` and refresh the page. If the release you want was published very recently, your profile's supply-chain cooldown (`minimumReleaseAge`) may silently keep the older version — pin the exact version instead (`dsh plugin --profile web add dsh-provider-usage@0.3.
|
|
156
|
+
Then restart `dsh web` and refresh the page. If the release you want was published very recently, your profile's supply-chain cooldown (`minimumReleaseAge`) may silently keep the older version — pin the exact version instead (`dsh plugin --profile web add dsh-provider-usage@0.3.10`) and dsh will exempt it automatically. The version badge in the panel header confirms which release is actually loaded.
|
|
126
157
|
|
|
127
158
|
## Configuration
|
|
128
159
|
|
|
@@ -136,6 +167,9 @@ Defaults work out of the box: the plugin auto-detects every provider route of th
|
|
|
136
167
|
balanceRedThreshold: 10 # balance below this turns red (per the balance's own currency)
|
|
137
168
|
balanceYellowThreshold: 30 # balance below this turns yellow (per the balance's own currency)
|
|
138
169
|
autoDetect: true # enumerate provider routes from the llm registry
|
|
170
|
+
queryTimeoutMs: 20000 # per-attempt query timeout; each retry gets a fresh timeout
|
|
171
|
+
queryRetries: 2 # retries for transient errors (timeout/network/HTTP 408/425/429/5xx)
|
|
172
|
+
queryRetryDelayMs: 2000 # base retry delay, doubled per attempt, capped at 10s
|
|
139
173
|
providers: [] # manual specs; an id matching a detected route overrides it
|
|
140
174
|
```
|
|
141
175
|
|
|
@@ -145,6 +179,9 @@ Defaults work out of the box: the plugin auto-detects every provider route of th
|
|
|
145
179
|
| `balanceRedThreshold` | number | `10` | Balance below this amount turns red, compared in the balance's own currency |
|
|
146
180
|
| `balanceYellowThreshold` | number | `30` | Balance below this amount turns yellow, compared in the balance's own currency |
|
|
147
181
|
| `autoDetect` | boolean | `true` | Enumerate live provider routes from the llm registry |
|
|
182
|
+
| `queryTimeoutMs` | number | `20000` | Per-attempt query timeout (1000–120000); each retry gets a fresh timeout |
|
|
183
|
+
| `queryRetries` | number | `2` | Retries for transient errors — timeout / network / HTTP 408, 425, 429, 5xx (0–10); permanent 4xx errors fail immediately |
|
|
184
|
+
| `queryRetryDelayMs` | number | `2000` | Base delay between retries (100–60000), doubled per attempt, capped at 10s |
|
|
148
185
|
| `providers` | array | `[]` | Manual provider specs: `{id, kind, baseURL, apiKeyEnv, displayName?, enabled?}`; `kind` is one of the adapter table above |
|
|
149
186
|
|
|
150
187
|
The same fields can be hot-updated under the `provider-usage:` namespace in `~/.dsh/settings.yaml`.
|
|
@@ -163,7 +200,7 @@ config:
|
|
|
163
200
|
|
|
164
201
|
## How it works
|
|
165
202
|
|
|
166
|
-
- **Host half** (`src/index.ts`): `UsageService extends TypertRemoteService` exposes `usage/list` via
|
|
203
|
+
- **Host half** (`src/index.ts`): `UsageService extends TypertRemoteService` exposes `usage/list` via the `Remote('list')` marker, applied without decorator syntax (SRC mode, no codegen). Config is declared with schemastery, and the settings provider's `installSection` enables hot updates from the settings document.
|
|
167
204
|
- **Client half** (`src/client/`): a `window.__ModuleLoader__.load({id, factory})` bundle (built by tsdown) mounts through the `sidebar.footer.action` slot (used purely as a mount point — the trigger itself is a floating ball portaled to `document.body`) and polls `usage/list` through `ctx.connection.rpc.call('/api', 'usage/list', {args:{}})` on its own interval. The service stays stateless — every poll fetches live values.
|
|
168
205
|
|
|
169
206
|
## License
|
package/README_ZH.md
CHANGED
|
@@ -10,20 +10,20 @@
|
|
|
10
10
|
|
|
11
11
|
# dsh-provider-usage
|
|
12
12
|
|
|
13
|
-
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件:在 Web GUI 上悬浮一个可任意拖动的用量球,实时查看所有已配置 LLM provider
|
|
13
|
+
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件:在 Web GUI 上悬浮一个可任意拖动的用量球,实时查看所有已配置 LLM provider 的账户余额与用量——不用再逐个登录 provider 控制台确认。
|
|
14
14
|
|
|
15
15
|
## 功能
|
|
16
16
|
|
|
17
17
|
- **自动探测** —— 自动枚举当前 profile 中已注册的 provider 路由(`ctx.llm`),常见路由零配置。
|
|
18
|
-
- **按 provider 类型查询额度** ——
|
|
18
|
+
- **按 provider 类型查询额度** —— 没有公开余额/用量接口的路由(Google、Mistral、Groq、Bedrock、Azure、Qwen Token Plan 等)会在面板中标注为「不支持」,而不是被静默忽略:
|
|
19
19
|
|
|
20
20
|
| kind | 路由 | 查询接口 | 展示内容 |
|
|
21
21
|
|---|---|---|---|
|
|
22
22
|
| `deepseek` | `deepseek-official`、`deepseek` | `GET {baseURL}/user/balance` | 余额(含赠送/充值明细) |
|
|
23
23
|
| `moonshot` | `moonshotai-cn`、`moonshotai` | `GET {baseURL}/users/me/balance` | 可用/代金券/现金余额 |
|
|
24
|
-
| `kimi-coding` | `kimi-coding` | `GET {baseURL}/v1/usages` |
|
|
24
|
+
| `kimi-coding` | `kimi-coding` | `GET {baseURL}/v1/usages` | 每周用量及各限速窗口,含重置倒计时 |
|
|
25
25
|
| `openrouter` | `openrouter` | `GET {origin}/api/v1/credits` | credit 已用/总额 |
|
|
26
|
-
| `github-copilot` | `github-copilot` | `GET api.github.com/copilot_internal/user` |
|
|
26
|
+
| `github-copilot` | `github-copilot` | `GET api.github.com/copilot_internal/user` | 付费档用量快照 / 免费档月度用量 |
|
|
27
27
|
| `openai-codex` | `openai-codex` | `GET {baseURL}/wham/usage` | ChatGPT 订阅 5h/周窗口 + credits + spend control(**OAuth 登录**,非 API key,见 [通过 OAuth 添加 OpenAI Codex](#通过-oauth-添加-openai-codex)) |
|
|
28
28
|
| `openai` | `openai` | `GET {origin}/v1/organization/costs` | 当月花费(**需 Admin key**,普通 key 会 403) |
|
|
29
29
|
| `anthropic` | `anthropic` | `GET {baseURL}/v1/organizations/cost_report` | 当月花费(**需 Admin key**,`x-api-key` 头) |
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
| `vercel-ai-gateway` | `vercel-ai-gateway` | `GET {baseURL}/v1/credits` | 团队 credit 余额 |
|
|
34
34
|
| `xai` | `xai` | `GET {baseURL}/billing/credits` | 预付余额(USD) |
|
|
35
35
|
- **密钥安全** —— 通过 harness 凭据服务按次解析(环境变量 / `~/.dsh/.credentials.yaml`),不缓存、不落地。对 OAuth 类 Provider(OpenAI Codex)则直接读取登录流程存入的授权记录,并在令牌临近过期时自动刷新。
|
|
36
|
-
- **悬浮球入口** —— 可任意拖动的悬浮球点击弹出用量面板,位置持久化;默认停靠在主对话区域左下角(左边距 = 底边距),面板头部的归位按钮一键回到默认位置;Provider 列表超过面板高度时自动滚动,面板**顶部边缘可拖拽**调整面板高度(变长/变短,localStorage 持久化);球体光晕表达**当前正在使用**的 Provider——即**当前聚焦 session 自己的模型选择**(composer 模型座同源,客户端实时跟踪),因此切换 session 后无需重新选择模型,面板会立即把"使用中"标记切到该 session 的 Provider
|
|
36
|
+
- **悬浮球入口** —— 可任意拖动的悬浮球点击弹出用量面板,位置持久化;默认停靠在主对话区域左下角(左边距 = 底边距),面板头部的归位按钮一键回到默认位置;Provider 列表超过面板高度时自动滚动,面板**顶部边缘可拖拽**调整面板高度(变长/变短,localStorage 持久化);球体光晕表达**当前正在使用**的 Provider——即**当前聚焦 session 自己的模型选择**(composer 模型座同源,客户端实时跟踪),因此切换 session 后无需重新选择模型,面板会立即把"使用中"标记切到该 session 的 Provider:绿色正常、黄色用量窗口剩余不足 30% 或余额低于黄阈值、红色查询失败/缺密钥/用量 ≥90% 或余额低于红阈值。闲置的 Provider 余量不足不再影响悬浮球颜色——切换到余量充足的另一个 Provider 后球体会恢复绿色;面板会标注"使用中"的 Provider,并照常列出所有 Provider 的用量明细。
|
|
37
37
|
- **版本徽章** —— 面板标题旁显示当前运行的插件版本,一眼确认加载的是哪个发布版。
|
|
38
38
|
- **中英双语** —— 面板内置中英文界面,默认跟随 harness 系统语言,标题栏按钮一键切换(localStorage 持久化)。
|
|
39
39
|
- **刷新周期可调** —— 面板内调整(15s–30min,localStorage 持久化),默认值由插件配置提供。
|
|
@@ -90,6 +90,37 @@ records:
|
|
|
90
90
|
|
|
91
91
|
面板随即展示订阅的 **5h 上限**、**每周**窗口(已用百分比 + 重置倒计时),以及计划上报的 **credits** 与 **spend control** 余额。若授权记录缺失,卡片会显示「未完成 OAuth 授权(llm-pi-ai/openai-codex)」,按第 2 步重新登录即可。
|
|
92
92
|
|
|
93
|
+
### 4. 故障排除:间歇性 "Our servers are currently overloaded"
|
|
94
|
+
|
|
95
|
+
Codex 后端偶尔会返回 `Codex error: Our servers are currently overloaded. Please try again later.`,harness 随即以 `PI_AI_ERROR` 判本轮失败。这是 **OpenAI 端的间歇性过载**(账号、配额、网络通常都正常——可用 `GET /wham/usage` 确认窗口余量),但默认配置下不会自动重试,原因有两层:
|
|
96
|
+
|
|
97
|
+
1. pi-ai 的 Codex 客户端内部认得 `overloaded` 是可重试错误,但默认重试次数为 0(`dsh-llm-pi-ai` 显式传 `maxRetries: 0`);
|
|
98
|
+
2. 错误冒泡后,其文本不含 `5xx` / `rate limit` / `timeout` 等关键词,被归类为兜底的 `PI_AI_ERROR`——而它**不在** `dsh-llm-retry` 的默认可重试码(`EMPTY_RESPONSE` / `RATE_LIMIT` / `SERVER` / `TIMEOUT` / `TRANSPORT`)里,于是整轮直接失败。
|
|
99
|
+
|
|
100
|
+
在 `~/.dsh/settings.yaml` 中给该 provider 加一段 `retryPolicy`,把 `PI_AI_ERROR` 纳入可重试码即可(重开 session 后生效):
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
llm-pi-ai:
|
|
104
|
+
providers:
|
|
105
|
+
openai-codex:
|
|
106
|
+
retryPolicy:
|
|
107
|
+
mode: normal
|
|
108
|
+
maxRetries: 10
|
|
109
|
+
retryableCodes:
|
|
110
|
+
- EMPTY_RESPONSE
|
|
111
|
+
- RATE_LIMIT
|
|
112
|
+
- SERVER
|
|
113
|
+
- TIMEOUT
|
|
114
|
+
- TRANSPORT
|
|
115
|
+
- PI_AI_ERROR
|
|
116
|
+
backoff:
|
|
117
|
+
initialDelayMs: 2000 # 首次重试延迟,指数翻倍
|
|
118
|
+
maxDelayMs: 60000 # 单次延迟上限
|
|
119
|
+
jitterRatio: 0.2 # ±20% 抖动
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
注意区分另一类**必然失败**:部分模型对 ChatGPT 订阅账号不可用,后端直接返回 `400 The '<model>' model is not supported when using Codex with a ChatGPT account.`(实测如 `gpt-5.3-codex-spark`、`gpt-5-codex`)。这类是永久错误,重试无效——请换用账号支持的模型(如 `gpt-5.4` / `gpt-5.5` / `gpt-5.6` 系列)。
|
|
123
|
+
|
|
93
124
|
## 安装
|
|
94
125
|
|
|
95
126
|
> [!NOTE]
|
|
@@ -112,7 +143,7 @@ pnpm pack # 产出 dsh-provider-usage-<version>.tgz
|
|
|
112
143
|
dsh plugin --profile web add ./dsh-provider-usage-<version>.tgz
|
|
113
144
|
```
|
|
114
145
|
|
|
115
|
-
注意要安装 **tarball** 而不是仓库目录:`dsh plugin add .` 会链接整个仓库,仓库自带 `node_modules` 里的 `@deepseek-ai/cordis` 会遮蔽 harness 的共享实例,导致 host 半注册不上(RPC 404)。link 方式仍适合纯 UI 迭代(浏览器 bundle 自包含,重新 build + 刷新页面即生效),但需要 host 半时请切换到 tarball 或 npm 正式版。若替换 link 安装时 pnpm 报 `EPERM ... symlink`,手动删除 profile 目录下残留的 `node_modules/dsh-provider-usage` 联结后重试即可。
|
|
146
|
+
注意要安装 **tarball** 而不是仓库目录:`dsh plugin --profile web add .` 会链接整个仓库,仓库自带 `node_modules` 里的 `@deepseek-ai/cordis` 会遮蔽 harness 的共享实例,导致 host 半注册不上(RPC 404)。link 方式仍适合纯 UI 迭代(浏览器 bundle 自包含,重新 build + 刷新页面即生效),但需要 host 半时请切换到 tarball 或 npm 正式版。若替换 link 安装时 pnpm 报 `EPERM ... symlink`,手动删除 profile 目录下残留的 `node_modules/dsh-provider-usage` 联结后重试即可。
|
|
116
147
|
|
|
117
148
|
插件集合变化后需重启 `dsh web`;之后仅改动代码时重新 build + 重新 add + 刷新页面即可。
|
|
118
149
|
|
|
@@ -122,7 +153,7 @@ dsh plugin --profile web add ./dsh-provider-usage-<version>.tgz
|
|
|
122
153
|
dsh plugin --profile web add dsh-provider-usage@latest
|
|
123
154
|
```
|
|
124
155
|
|
|
125
|
-
然后重启 `dsh web` 并刷新页面。如果目标版本刚发布不久,profile 的供应链冷静期(`minimumReleaseAge`)可能会静默停留在旧版——这时指定精确版本号(如 `dsh plugin --profile web add dsh-provider-usage@0.3.
|
|
156
|
+
然后重启 `dsh web` 并刷新页面。如果目标版本刚发布不久,profile 的供应链冷静期(`minimumReleaseAge`)可能会静默停留在旧版——这时指定精确版本号(如 `dsh plugin --profile web add dsh-provider-usage@0.3.10`),dsh 会自动豁免该版本。面板标题旁的版本徽章可以确认实际加载的版本。
|
|
126
157
|
|
|
127
158
|
## 配置说明
|
|
128
159
|
|
|
@@ -136,6 +167,9 @@ dsh plugin --profile web add dsh-provider-usage@latest
|
|
|
136
167
|
balanceRedThreshold: 10 # 余额低于该值变红(按余额自身币种比较)
|
|
137
168
|
balanceYellowThreshold: 30 # 余额低于该值变黄(按余额自身币种比较)
|
|
138
169
|
autoDetect: true # 自动枚举 llm 注册表中的 provider
|
|
170
|
+
queryTimeoutMs: 20000 # 单次查询超时(毫秒),每次重试独立计时
|
|
171
|
+
queryRetries: 2 # 瞬时错误(超时/网络/HTTP 408/425/429/5xx)重试次数
|
|
172
|
+
queryRetryDelayMs: 2000 # 重试基础延迟(毫秒),逐次翻倍,封顶 10 秒
|
|
139
173
|
providers: [] # 手动补充/覆盖 provider(id 相同则覆盖自动探测结果)
|
|
140
174
|
```
|
|
141
175
|
|
|
@@ -145,6 +179,9 @@ dsh plugin --profile web add dsh-provider-usage@latest
|
|
|
145
179
|
| `balanceRedThreshold` | number | `10` | 余额低于该值变红,按余额自身币种比较 |
|
|
146
180
|
| `balanceYellowThreshold` | number | `30` | 余额低于该值变黄,按余额自身币种比较 |
|
|
147
181
|
| `autoDetect` | boolean | `true` | 从 llm 注册表自动枚举 provider |
|
|
182
|
+
| `queryTimeoutMs` | number | `20000` | 单次查询超时(毫秒),1000–120000,每次重试独立计时 |
|
|
183
|
+
| `queryRetries` | number | `2` | 瞬时错误(超时/网络/HTTP 408/425/429/5xx)的重试次数,0–10;4xx 永久错误不重试 |
|
|
184
|
+
| `queryRetryDelayMs` | number | `2000` | 重试基础延迟(毫秒),100–60000,指数翻倍,封顶 10 秒 |
|
|
148
185
|
| `providers` | array | `[]` | 手动 provider 规格:`{id, kind, baseURL, apiKeyEnv, displayName?, enabled?}`,`kind` 取上表中的任一适配器 |
|
|
149
186
|
|
|
150
187
|
也可以在 `~/.dsh/settings.yaml` 中通过 `provider-usage:` 命名空间热更新同样字段。
|
|
@@ -163,7 +200,7 @@ config:
|
|
|
163
200
|
|
|
164
201
|
## 架构
|
|
165
202
|
|
|
166
|
-
- **Host 半**(`src/index.ts`):`UsageService extends TypertRemoteService
|
|
203
|
+
- **Host 半**(`src/index.ts`):`UsageService extends TypertRemoteService`,通过 `Remote('list')` 标记(以非装饰器方式应用)暴露 `usage/list`(SRC 模式,无需代码生成);`Config` 用 schemastery 声明,通过 settings provider 的 `installSection` 支持 settings 热更新。
|
|
167
204
|
- **Client 半**(`src/client/`):`window.__ModuleLoader__.load({id, factory})` 格式 bundle(tsdown 构建),通过 `sidebar.footer.action` slot 挂载(仅作为挂载点——触发器本体是 portal 到 `document.body` 的悬浮球),通过 `ctx.connection.rpc.call('/api', 'usage/list', {args:{}})` 轮询。服务本身无状态——每次轮询都取实时值。
|
|
168
205
|
|
|
169
206
|
## 许可证
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "LLM provider 余额/配额查询接口调研结论(机器可读版)。详见 provider-quota-endpoints.md。均经官方文档/开源实现验证,未臆造端点。",
|
|
3
|
+
"providers": [
|
|
4
|
+
{
|
|
5
|
+
"id": "openai",
|
|
6
|
+
"support": "partial",
|
|
7
|
+
"credentialType": "admin_api_key",
|
|
8
|
+
"credentialHint": "OpenAI Admin key (sk-admin-...),platform.openai.com → Organization → Admin keys;普通 sk- key 与 project service-account key 均不可用",
|
|
9
|
+
"endpoints": [
|
|
10
|
+
{
|
|
11
|
+
"kind": "cost",
|
|
12
|
+
"method": "GET",
|
|
13
|
+
"url": "https://api.openai.com/v1/organization/costs",
|
|
14
|
+
"headers": { "Authorization": "Bearer {ADMIN_KEY}" },
|
|
15
|
+
"query": {
|
|
16
|
+
"start_time": "unix 秒,必填",
|
|
17
|
+
"end_time": "unix 秒",
|
|
18
|
+
"bucket_width": "1d|1h|1m",
|
|
19
|
+
"group_by": "project_id|line_item",
|
|
20
|
+
"project_ids": "proj_... 可重复",
|
|
21
|
+
"limit": "int", "page": "cursor"
|
|
22
|
+
},
|
|
23
|
+
"responseShape": "{ object:'page', data:[{ start_time, end_time, results:[{ amount:{value,currency}, line_item, project_id }] }], has_more, next_page }"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"kind": "usage",
|
|
27
|
+
"method": "GET",
|
|
28
|
+
"url": "https://api.openai.com/v1/organization/usage/completions",
|
|
29
|
+
"headers": { "Authorization": "Bearer {ADMIN_KEY}" },
|
|
30
|
+
"query": { "start_time": "unix 秒,必填", "bucket_width": "1d|1h|1m", "group_by": "model|project_id|api_key_id|..." },
|
|
31
|
+
"responseShape": "{ data:[{ results:[{ model, input_tokens, output_tokens, input_cached_tokens, num_model_requests }] }], has_more, next_page }",
|
|
32
|
+
"siblings": ["embeddings", "images", "moderations", "audio_speeches", "audio_transcriptions", "vector_stores", "code_interpreter_sessions"]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"kind": "balance_legacy_best_effort",
|
|
36
|
+
"method": "GET",
|
|
37
|
+
"url": "https://api.openai.com/v1/dashboard/billing/credit_grants",
|
|
38
|
+
"headers": { "Authorization": "Bearer {LEGACY_USER_KEY}" },
|
|
39
|
+
"responseShape": "{ object:'credit_summary', total_granted, total_used, total_available, expires_at }",
|
|
40
|
+
"warnings": ["不在现行公开 API 文档", "多数普通 key 已失效", "仅作静默兜底,失败视为不可用"]
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"consoleUrl": "https://platform.openai.com/usage",
|
|
44
|
+
"sources": [
|
|
45
|
+
"https://developers.openai.com/api/reference/resources/admin/subresources/organization/subresources/usage/methods/costs",
|
|
46
|
+
"https://github.com/steipete/CodexBar/blob/main/docs/openai.md"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "openai-codex",
|
|
51
|
+
"support": "yes_oauth_only",
|
|
52
|
+
"credentialType": "oauth_access_token",
|
|
53
|
+
"credentialHint": "~/.codex/auth.json 中的 ChatGPT/Codex OAuth access token;stale 时引导用户运行 codex CLI,不要自行回写 auth.json",
|
|
54
|
+
"endpoints": [
|
|
55
|
+
{
|
|
56
|
+
"kind": "rate_limit_windows",
|
|
57
|
+
"method": "GET",
|
|
58
|
+
"url": "https://chatgpt.com/backend-api/wham/usage",
|
|
59
|
+
"headers": { "Authorization": "Bearer {OAUTH_TOKEN}" },
|
|
60
|
+
"responseShape": "{ plan_type, rate_limit:{ allowed, limit_reached, primary_window:{used_percent,limit_window_seconds,reset_after_seconds,reset_at}, secondary_window:{...} }, additional_rate_limits:[], credits:{has_credits,unlimited,balance} }",
|
|
61
|
+
"mapping": { "primary_window": "5 小时会话窗口", "secondary_window": "周窗口" }
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"kind": "reset_credits",
|
|
65
|
+
"method": "GET",
|
|
66
|
+
"url": "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits",
|
|
67
|
+
"headers": { "Authorization": "Bearer {OAUTH_TOKEN}" }
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"alternatives": ["本地 codex app-server JSON-RPC: account/read, account/rateLimits/read"],
|
|
71
|
+
"warnings": ["未公开内部接口,可能随时变更"],
|
|
72
|
+
"consoleUrl": "https://chatgpt.com/codex/settings/usage",
|
|
73
|
+
"sources": ["https://github.com/steipete/CodexBar/blob/main/docs/codex.md"]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "anthropic",
|
|
77
|
+
"support": "partial",
|
|
78
|
+
"credentialType": "admin_api_key",
|
|
79
|
+
"credentialHint": "Anthropic Admin key (sk-ant-admin-...),Console → Settings → Admin keys;普通 sk-ant-api key 不可用;认证头是 x-api-key 而非 Bearer",
|
|
80
|
+
"endpoints": [
|
|
81
|
+
{
|
|
82
|
+
"kind": "usage",
|
|
83
|
+
"method": "GET",
|
|
84
|
+
"url": "https://api.anthropic.com/v1/organizations/usage_report/messages",
|
|
85
|
+
"headers": { "x-api-key": "{ADMIN_KEY}", "anthropic-version": "2023-06-01" },
|
|
86
|
+
"query": {
|
|
87
|
+
"starting_at": "RFC3339,必填",
|
|
88
|
+
"ending_at": "RFC3339",
|
|
89
|
+
"bucket_width": "1d|1h",
|
|
90
|
+
"group_by": "workspace_id|api_key_id|model|service_tier|context_window(多值)",
|
|
91
|
+
"models": "多值", "workspace_ids": "多值", "limit": "≤1000", "page": "cursor"
|
|
92
|
+
},
|
|
93
|
+
"responseShape": "{ data:[{ starting_at, ending_at, results:[{ model, workspace_id, api_key_id, service_tier, uncached_input_tokens, output_tokens, cache_read_input_tokens, cache_creation_5m_input_tokens, cache_creation_1h_input_tokens, server_tool_use }] }], has_more, next_page }"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"kind": "cost",
|
|
97
|
+
"method": "GET",
|
|
98
|
+
"url": "https://api.anthropic.com/v1/organizations/cost_report",
|
|
99
|
+
"headers": { "x-api-key": "{ADMIN_KEY}", "anthropic-version": "2023-06-01" },
|
|
100
|
+
"query": { "starting_at": "RFC3339,必填", "group_by": "workspace_id|description", "limit": "int", "page": "cursor" },
|
|
101
|
+
"responseShape": "{ data:[{ starting_at, ending_at, results:[{ amount(字符串美元), currency, cost_type, description, model, workspace_id, service_tier }] }], has_more, next_page }",
|
|
102
|
+
"warnings": ["bucket_width 仅支持 1d"]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"kind": "subscription_usage_oauth",
|
|
106
|
+
"method": "GET",
|
|
107
|
+
"url": "https://api.anthropic.com/api/oauth/usage",
|
|
108
|
+
"headers": { "Authorization": "Bearer {CLAUDE_CODE_OAUTH_TOKEN}", "anthropic-beta": "oauth-2025-04-20" },
|
|
109
|
+
"responseShape": "{ five_hour:{utilization,resets_at}, seven_day:{...}, seven_day_sonnet:{...}, ... }",
|
|
110
|
+
"warnings": ["仅 Claude Pro/Max 订阅", "需 user:profile scope", "非 API key 方案"]
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"consoleUrl": "https://console.anthropic.com/",
|
|
114
|
+
"sources": [
|
|
115
|
+
"https://platform.claude.com/docs/en/manage-claude/usage-cost-api",
|
|
116
|
+
"https://platform.claude.com/docs/en/api/admin/usage_report/retrieve_messages",
|
|
117
|
+
"https://github.com/steipete/CodexBar/blob/main/docs/claude.md"
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"id": "gemini",
|
|
122
|
+
"support": "no",
|
|
123
|
+
"credentialType": null,
|
|
124
|
+
"reason": "AI Studio API key 无任何配额/用量/余额查询 HTTP 接口;官方文档无此 API,响应无 rate-limit 头,社区仅能靠 429 反推。",
|
|
125
|
+
"greyArea": {
|
|
126
|
+
"comment": "Gemini CLI 私有 OAuth 接口,非 API key 方案,且 Google 已对个人账号关闭",
|
|
127
|
+
"endpoints": [
|
|
128
|
+
{ "method": "POST", "url": "https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota", "body": "{ project }", "responseShape": "buckets[].{modelId, remainingFraction, resetTime}" },
|
|
129
|
+
{ "method": "POST", "url": "https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist", "body": "{ metadata:{ideType,pluginType} }", "responseShape": "{ paidTier, currentTier }" }
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"consoleUrl": "https://aistudio.google.com/usage",
|
|
133
|
+
"sources": [
|
|
134
|
+
"https://github.com/steipete/CodexBar/blob/main/docs/gemini.md",
|
|
135
|
+
"https://discuss.ai.google.dev/t/gemini-api-429-resource-exhausted-error-on-tier-1/114413"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"id": "xai",
|
|
140
|
+
"support": "yes",
|
|
141
|
+
"credentialType": "management_key",
|
|
142
|
+
"credentialHint": "xAI Management key(console.x.ai → Management Keys;xai- 前缀但与推理 key 不同),需相应 ACL;team_id 在 console Team settings 复制;baseURL 是 management-api.x.ai 不是 api.x.ai",
|
|
143
|
+
"endpoints": [
|
|
144
|
+
{
|
|
145
|
+
"kind": "balance",
|
|
146
|
+
"method": "GET",
|
|
147
|
+
"url": "https://management-api.x.ai/v1/billing/teams/{team_id}/prepaid/balance",
|
|
148
|
+
"headers": { "Authorization": "Bearer {MANAGEMENT_KEY}" },
|
|
149
|
+
"responseShape": "{ total:{val}, changes:[{ teamId, changeOrigin:PURCHASE|SPEND|REFUND|MANUAL|AUTO_PURCHASE, topupStatus, amount:{val}, createTime }] }",
|
|
150
|
+
"warnings": ["金额单位=美元美分", "符号反直觉:SPEND 为正、PURCHASE 为负;可用余额 = -total.val/100 美元"]
|
|
151
|
+
},
|
|
152
|
+
{ "kind": "spending_limits", "method": "GET", "url": "https://management-api.x.ai/v1/billing/teams/{team_id}/postpaid/spending-limits", "headers": { "Authorization": "Bearer {MANAGEMENT_KEY}" } },
|
|
153
|
+
{ "kind": "invoice_preview", "method": "GET", "url": "https://management-api.x.ai/v1/billing/teams/{team_id}/postpaid/invoice/preview", "headers": { "Authorization": "Bearer {MANAGEMENT_KEY}" } },
|
|
154
|
+
{
|
|
155
|
+
"kind": "usage_analytics",
|
|
156
|
+
"method": "POST",
|
|
157
|
+
"url": "https://management-api.x.ai/v1/billing/teams/{team_id}/usage",
|
|
158
|
+
"headers": { "Authorization": "Bearer {MANAGEMENT_KEY}" },
|
|
159
|
+
"body": "{ analyticsRequest:{ timeRange:{startTime,endTime,timezone}, timeUnit, values:[{name,aggregation}], groupBy:[], filters:[] } }",
|
|
160
|
+
"responseShape": "{ timeSeries:[{ group, groupLabels, dataPoints:[{timestamp, values[]}] }], limitReached }"
|
|
161
|
+
},
|
|
162
|
+
{ "kind": "model_rate_limits", "method": "GET", "url": "https://management-api.x.ai/auth/teams/{teamId}/models", "headers": { "Authorization": "Bearer {MANAGEMENT_KEY}" } },
|
|
163
|
+
{ "kind": "key_validation", "method": "GET", "url": "https://management-api.x.ai/auth/management-keys/validation", "headers": { "Authorization": "Bearer {MANAGEMENT_KEY}" } }
|
|
164
|
+
],
|
|
165
|
+
"consoleUrl": "https://console.x.ai/team/default/billing",
|
|
166
|
+
"sources": [
|
|
167
|
+
"https://docs.x.ai/developers/rest-api-reference/management",
|
|
168
|
+
"https://docs.x.ai/developers/rest-api-reference/management/billing",
|
|
169
|
+
"https://docs.x.ai/console/billing"
|
|
170
|
+
]
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"id": "mistral",
|
|
174
|
+
"support": "no",
|
|
175
|
+
"credentialType": null,
|
|
176
|
+
"reason": "无任何公开余额/用量查询接口;官方文档无 billing API,开源余额工具均标注 Console only。",
|
|
177
|
+
"consoleUrl": "https://console.mistral.ai/usage",
|
|
178
|
+
"sources": [
|
|
179
|
+
"https://github.com/hanmumuHL/check_balance",
|
|
180
|
+
"https://theneuralbase.com/mistral-api/learn/advanced/la-plateforme-dashboard-overview/"
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# LLM Provider 余额/配额查询接口调研结论
|
|
2
|
+
|
|
3
|
+
> 调研日期:2026(已用官方文档 + 开源实现交叉验证,未臆造端点)
|
|
4
|
+
> 用途:「LLM provider 余额/配额查询面板」插件适配器开发依据
|
|
5
|
+
|
|
6
|
+
## 总览
|
|
7
|
+
|
|
8
|
+
| Provider | 可查性 | 认证方式 | 核心端点 |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| openai | partial | Admin key (Bearer) | `GET /v1/organization/costs`, `GET /v1/organization/usage/completions` |
|
|
11
|
+
| openai-codex | yes (OAuth) | OAuth Bearer token | `GET https://chatgpt.com/backend-api/wham/usage` |
|
|
12
|
+
| anthropic | partial | Admin key (`x-api-key` 头) | `GET /v1/organizations/usage_report/messages`, `GET /v1/organizations/cost_report` |
|
|
13
|
+
| gemini | no (API key) | — | 无;仅私有 OAuth 接口 |
|
|
14
|
+
| xai | yes | Management key (Bearer) | `GET https://management-api.x.ai/v1/billing/teams/{team_id}/prepaid/balance` |
|
|
15
|
+
| mistral | no | — | 无,console only |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. openai — partial
|
|
20
|
+
|
|
21
|
+
普通 `sk-...` key **无法**查询余额。需 Organization **Admin key**(`sk-admin...`,platform.openai.com → Organization → Admin keys 创建;不能用于推理)。
|
|
22
|
+
|
|
23
|
+
### 1.1 Costs(推荐,费用为权威口径)
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
GET https://api.openai.com/v1/organization/costs
|
|
27
|
+
?start_time=<unix 秒,必填>
|
|
28
|
+
&end_time=<unix 秒>
|
|
29
|
+
&bucket_width=1d # 1d | 1h | 1m
|
|
30
|
+
&group_by=line_item # project_id | line_item
|
|
31
|
+
&project_ids=proj_... # 可选项目过滤
|
|
32
|
+
&limit=31&page=<cursor>
|
|
33
|
+
Authorization: Bearer sk-admin-...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"object": "page",
|
|
39
|
+
"data": [{
|
|
40
|
+
"object": "bucket",
|
|
41
|
+
"start_time": 1730419200,
|
|
42
|
+
"end_time": 1730505600,
|
|
43
|
+
"results": [{
|
|
44
|
+
"object": "organization.costs.result",
|
|
45
|
+
"amount": { "value": 0.06, "currency": "usd" },
|
|
46
|
+
"line_item": "gpt-4o",
|
|
47
|
+
"project_id": null
|
|
48
|
+
}]
|
|
49
|
+
}],
|
|
50
|
+
"has_more": false,
|
|
51
|
+
"next_page": null
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 1.2 Usage(token/请求量)
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
GET https://api.openai.com/v1/organization/usage/completions?start_time=...&bucket_width=1d&group_by=model
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`results[]` 字段:`model`、`input_tokens`、`output_tokens`、`input_cached_tokens`、`num_model_requests`、`project_id`、`api_key_id`。
|
|
62
|
+
同族端点:`/v1/organization/usage/{embeddings|images|moderations|audio_speeches|audio_transcriptions|vector_stores|code_interpreter_sessions}`。
|
|
63
|
+
|
|
64
|
+
### 1.3 遗留余额接口(仅兜底,勿依赖)
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
GET https://api.openai.com/v1/dashboard/billing/credit_grants
|
|
68
|
+
Authorization: Bearer <旧式 user key>
|
|
69
|
+
# → {"object":"credit_summary","total_granted":..,"total_used":..,"total_available":..,"expires_at":..}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**不在 OpenAI 现行公开 API reference**,历史上主要面向 web session,多数普通 key 已返回错误;适配器应将其失败视为"不可用"而非报错。
|
|
73
|
+
|
|
74
|
+
### 注意事项
|
|
75
|
+
- Admin key 组织级、不能推理;project service-account key(`sk-...svcacct`)**不能**读 organization usage/costs。
|
|
76
|
+
- Admin API 失败时不要降级到 credit_grants 做项目级过滤(该端点无 project 过滤)。
|
|
77
|
+
- 来源:https://developers.openai.com/api/reference/resources/admin/subresources/organization/subresources/usage/methods/costs ;https://github.com/steipete/CodexBar/blob/main/docs/openai.md ;https://github.com/dougschaefer6/swamp-openai-usage
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 2. openai-codex — yes(ChatGPT 订阅 OAuth,非 API key)
|
|
82
|
+
|
|
83
|
+
凭证:OAuth access token。在 dsh 中由 `llm-pi-ai/openai-codex` 授权记录提供(`~/.dsh/.credentials.yaml` 的 `kind: grant`,字段 `type/access/refresh/expires/accountId`);CLI 场景则是 `~/.codex/auth.json`。baseURL:`https://chatgpt.com/backend-api`。
|
|
84
|
+
|
|
85
|
+
### 2.1 用量窗口
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
GET https://chatgpt.com/backend-api/wham/usage
|
|
89
|
+
Authorization: Bearer <oauth access_token>
|
|
90
|
+
ChatGPT-Account-Id: <chatgpt account/workspace id> # 从 access token 的 JWT claim https://api.openai.com/auth.chatgpt_account_id 解析
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"plan_type": "plus",
|
|
96
|
+
"rate_limit": {
|
|
97
|
+
"allowed": true,
|
|
98
|
+
"limit_reached": false,
|
|
99
|
+
"primary_window": { "used_percent": 23, "limit_window_seconds": 18000, "reset_after_seconds": 3600, "reset_at": 1730000000 },
|
|
100
|
+
"secondary_window": { "used_percent": 5, "limit_window_seconds": 604800, "reset_after_seconds": 86400, "reset_at": 1730500000 }
|
|
101
|
+
},
|
|
102
|
+
"additional_rate_limits": [ { "limit_name": "codex", "metered_feature": "codex", "rate_limit": { "...": "模型专属窗口,如 Codex-Spark" } } ],
|
|
103
|
+
"credits": { "has_credits": true, "unlimited": false, "balance": "12.34" },
|
|
104
|
+
"spend_control": { "reached": false, "individual_limit": { "limit": "100", "used": "40", "remaining": "60", "used_percent": 40, "reset_at": 1730000000 } }
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `primary_window` = 5 小时会话窗口;`secondary_window` = 周窗口。
|
|
109
|
+
- `credits.balance`、`spend_control.individual_limit` 的 `limit/used/remaining` 都是**十进制字符串**,不是数字。
|
|
110
|
+
- 401 时刷新一次 OAuth 并重试(本插件已实现:从凭据库读 grant → 临近过期自动 refresh → `Bearer` + `ChatGPT-Account-Id` 请求 → 401 重试一次)。
|
|
111
|
+
|
|
112
|
+
### 2.2 重置积分(可选)
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
GET https://chatgpt.com/backend-api/wham/rate-limit-reset-credits
|
|
116
|
+
Authorization: Bearer <oauth access_token>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 注意事项
|
|
120
|
+
- **未公开内部接口**,无官方文档,可能随时变更/加 Cloudflare 校验。
|
|
121
|
+
- token 会过期:本插件读取 dsh 凭据库中的 grant 并在临近过期(30s 内)时用 `client_id=app_EMoamEEZ73f0CkXaXp7hrann` 刷新一次,把旋转后的 grant 通过凭据库的 `modifyRecord` 写回(带跨进程锁,不会与 LLM 请求的刷新互相覆盖)。
|
|
122
|
+
- 网页兜底:`https://chatgpt.com/codex/settings/usage`(需 cookie,不推荐)。
|
|
123
|
+
- 来源:https://github.com/openai/codex (`backend-client/src/client/rate_limit_resets.rs`、`model-provider/src/bearer_auth_provider.rs`);https://github.com/steipete/CodexBar/blob/main/docs/codex.md
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 3. anthropic — partial
|
|
128
|
+
|
|
129
|
+
普通 `sk-ant-api...` key **无法**查询。需 **Admin API key**(`sk-ant-admin...`,Console → Settings → Admin keys 创建;不能用于推理)。
|
|
130
|
+
|
|
131
|
+
### 3.1 Token 用量报表
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
GET https://api.anthropic.com/v1/organizations/usage_report/messages
|
|
135
|
+
?starting_at=2025-11-01T00:00:00Z # RFC3339,必填
|
|
136
|
+
&ending_at=...
|
|
137
|
+
&bucket_width=1d # 1d | 1h
|
|
138
|
+
&group_by=model # workspace_id | api_key_id | model | service_tier | context_window(可多值)
|
|
139
|
+
&models=claude-...&workspace_ids=...&limit=20&page=<cursor>
|
|
140
|
+
x-api-key: sk-ant-admin-...
|
|
141
|
+
anthropic-version: 2023-06-01
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"data": [{
|
|
147
|
+
"starting_at": "2025-11-01T00:00:00Z",
|
|
148
|
+
"ending_at": "2025-11-02T00:00:00Z",
|
|
149
|
+
"results": [{
|
|
150
|
+
"model": "claude-sonnet-4-5",
|
|
151
|
+
"workspace_id": null,
|
|
152
|
+
"uncached_input_tokens": 861880,
|
|
153
|
+
"output_tokens": 42000,
|
|
154
|
+
"cache_read_input_tokens": 1200000,
|
|
155
|
+
"cache_creation_5m_input_tokens": 3000,
|
|
156
|
+
"cache_creation_1h_input_tokens": 0,
|
|
157
|
+
"server_tool_use": { "web_search_requests": 12 }
|
|
158
|
+
}]
|
|
159
|
+
}],
|
|
160
|
+
"has_more": false,
|
|
161
|
+
"next_page": null
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 3.2 费用报表
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
GET https://api.anthropic.com/v1/organizations/cost_report?starting_at=...&group_by=workspace_id
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`results[]` 字段:`amount`(字符串美元)、`currency`、`cost_type`(如 `tokens`)、`description`、`model`、`workspace_id`、`service_tier`、`starting_at`/`ending_at`。cost_report 的 bucket_width 仅支持 `1d`。
|
|
172
|
+
|
|
173
|
+
### 3.3 Claude 订阅侧(Pro/Max,OAuth,非 API key)
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
GET https://api.anthropic.com/api/oauth/usage
|
|
177
|
+
Authorization: Bearer <claude code oauth token>
|
|
178
|
+
anthropic-beta: oauth-2025-04-20
|
|
179
|
+
# 需 user:profile scope;返回 five_hour / seven_day / seven_day_sonnet 等窗口 utilization
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 注意事项
|
|
183
|
+
- 认证头是 `x-api-key`,**不是** `Authorization: Bearer`。
|
|
184
|
+
- 没有"剩余余额"概念——只有花费/用量报表。
|
|
185
|
+
- 来源:https://platform.claude.com/docs/en/manage-claude/usage-cost-api ;https://platform.claude.com/docs/en/api/admin/usage_report/retrieve_messages ;https://platform.claude.com/cookbook/observability-usage-cost-api ;https://github.com/steipete/CodexBar/blob/main/docs/claude.md
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 4. gemini — no(API key 不可查)
|
|
190
|
+
|
|
191
|
+
AI Studio key(generativelanguage.googleapis.com)**没有任何**查询配额/用量/余额的 HTTP 接口:
|
|
192
|
+
|
|
193
|
+
- 官方 rate limits 文档只给静态限额表;tier 状态只能看 AI Studio 网页。
|
|
194
|
+
- 响应无标准 rate-limit 头;社区只能靠 429 反推。
|
|
195
|
+
- 开源配额工具(CodexBar)对 `api-key` 认证类型直接报"不支持"。
|
|
196
|
+
|
|
197
|
+
### 灰区参考(私有 OAuth,非 API key,慎用)
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
POST https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota
|
|
201
|
+
Authorization: Bearer <google oauth token> # ~/.gemini/oauth_creds.json(gemini CLI 产生)
|
|
202
|
+
{ "project": "<projectId>" } # → buckets[].{modelId, remainingFraction, resetTime}
|
|
203
|
+
|
|
204
|
+
POST https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist
|
|
205
|
+
{ "metadata": { "ideType": "GEMINI_CLI", "pluginType": "GEMINI" } } # → paidTier / currentTier(tier 检测)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
注意:未公开 internal API;Google 已于 2026-06 停止对个人/AI Pro/Ultra 账号的该 OAuth 通道。
|
|
209
|
+
|
|
210
|
+
**适配器结论:标记 no,UI 给 https://aistudio.google.com/usage 链接。**
|
|
211
|
+
|
|
212
|
+
来源:https://github.com/steipete/CodexBar/blob/main/docs/gemini.md ;https://discuss.ai.google.dev/t/gemini-api-429-resource-exhausted-error-on-tier-1/114413
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 5. xai — yes(需 Management key)
|
|
217
|
+
|
|
218
|
+
普通推理 key(`xai-...`,api.x.ai)**不可用**。需 **Management key**(console.x.ai → Management Keys 创建),baseURL 为 `https://management-api.x.ai`,Bearer 认证。`team_id` 在 console Team settings 页复制。
|
|
219
|
+
|
|
220
|
+
### 5.1 预付余额
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
GET https://management-api.x.ai/v1/billing/teams/{team_id}/prepaid/balance
|
|
224
|
+
Authorization: Bearer <management key>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{
|
|
229
|
+
"total": { "val": "-1000" },
|
|
230
|
+
"changes": [{
|
|
231
|
+
"teamId": "65c1e471-...",
|
|
232
|
+
"changeOrigin": "PURCHASE", // PURCHASE|SPEND|REFUND|MANUAL|AUTO_PURCHASE
|
|
233
|
+
"topupStatus": "SUCCEEDED",
|
|
234
|
+
"amount": { "val": "-1000" },
|
|
235
|
+
"createTime": "2025-02-24T15:28:02.308840Z"
|
|
236
|
+
}]
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
⚠️ 单位是**美元美分**,且符号反直觉:`SPEND` 为正、`PURCHASE` 为负;`total.val` 为**负值**表示持有额度(可用余额 = `-total.val / 100` 美元)。
|
|
241
|
+
|
|
242
|
+
### 5.2 配套端点
|
|
243
|
+
|
|
244
|
+
| 方法 | 路径 | 用途 |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| GET | `/v1/billing/teams/{team_id}/postpaid/invoice/preview` | 当前账期应付、`effectiveSpendingLimit`、`prepaidCredits` |
|
|
247
|
+
| GET | `/v1/billing/teams/{team_id}/postpaid/spending-limits` | 月度软硬限额 |
|
|
248
|
+
| POST | `/v1/billing/teams/{team_id}/usage` | 历史用量聚合(body: `analyticsRequest.{timeRange,timeUnit,values,groupBy,filters}`) |
|
|
249
|
+
| GET | `/auth/teams/{teamId}/models` | 每模型价格与 rate limit(rps/rpm/tpm/tier) |
|
|
250
|
+
| GET | `/auth/management-keys/validation` | 校验 management key、查看 scope/ACL |
|
|
251
|
+
|
|
252
|
+
### 注意事项
|
|
253
|
+
- Management key 需在 console 授予相应 ACL;与推理 key 完全分开。
|
|
254
|
+
- 来源:https://docs.x.ai/developers/rest-api-reference/management ;https://docs.x.ai/developers/rest-api-reference/management/billing ;https://docs.x.ai/console/billing
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## 6. mistral — no
|
|
259
|
+
|
|
260
|
+
无任何公开余额/用量查询接口。官方文档无 billing API;开源工具 check_balance 明确标注 "⚠️ Console only / 未开放余额查询 API",控制台 https://console.mistral.ai/usage 。429 是唯一程序化信号。
|
|
261
|
+
|
|
262
|
+
**适配器结论:标记 no,UI 给 console 链接。**
|
|
263
|
+
|
|
264
|
+
来源:https://github.com/hanmumuHL/check_balance ;https://theneuralbase.com/mistral-api/learn/advanced/la-plateforme-dashboard-overview/
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## 适配器落地建议
|
|
269
|
+
|
|
270
|
+
1. **三类管理凭证分开存**:OpenAI Admin key / Anthropic Admin key(走 `x-api-key` 头)/ xAI Management key(不同 baseURL),均与推理 key 不同,配置 UI 需单独字段+引导文案。
|
|
271
|
+
2. **Codex** 只读 `~/.codex/auth.json`,token stale 时不要自行回写,引导用户跑 codex CLI。
|
|
272
|
+
3. **Gemini / Mistral** 返回 `{ supported: false, consoleUrl: ... }`,不要臆造端点。
|
|
273
|
+
4. OpenAI `credit_grants` 仅 best-effort,失败静默降级。
|
|
274
|
+
5. xAI 余额注意美分单位与负号语义。
|
package/lib/index.js
CHANGED
|
@@ -93,7 +93,7 @@ async function refreshOpenAiCodexGrant(refreshToken, signal) {
|
|
|
93
93
|
const name = "provider-usage";
|
|
94
94
|
/** Own package version, baked in by tsdown `define` at build time (the
|
|
95
95
|
fallback only fires if the sources are compiled some other way). */
|
|
96
|
-
const version = "0.3.
|
|
96
|
+
const version = "0.3.11";
|
|
97
97
|
/** Settings namespace this plugin owns (registered through `ctx.settings`). */
|
|
98
98
|
const NS = "provider-usage";
|
|
99
99
|
const PROVIDER_KINDS = [
|
|
@@ -131,6 +131,12 @@ const Config = z.object({
|
|
|
131
131
|
balanceYellowThreshold: z.number().step(.01).min(0).default(30),
|
|
132
132
|
/** Enumerate live provider routes from the llm registry. */
|
|
133
133
|
autoDetect: z.boolean().default(true),
|
|
134
|
+
/** Per-attempt query timeout in milliseconds; each retry gets a fresh timeout. */
|
|
135
|
+
queryTimeoutMs: z.number().step(1).min(1e3).max(12e4).default(2e4),
|
|
136
|
+
/** Retries after the first failed attempt for transient errors (timeout, network, HTTP 408/425/429/5xx). */
|
|
137
|
+
queryRetries: z.number().step(1).min(0).max(10).default(2),
|
|
138
|
+
/** Base delay between retries in milliseconds; doubles each attempt, capped at 10s. */
|
|
139
|
+
queryRetryDelayMs: z.number().step(1).min(100).max(6e4).default(2e3),
|
|
134
140
|
/** Manual provider specs; an id matching a detected route overrides it. */
|
|
135
141
|
providers: z.array(ProviderSpec).default([])
|
|
136
142
|
});
|
|
@@ -447,6 +453,39 @@ function okView(base) {
|
|
|
447
453
|
message: null
|
|
448
454
|
};
|
|
449
455
|
}
|
|
456
|
+
/** Retryable HTTP statuses below 500 (the whole 5xx range is retryable). */
|
|
457
|
+
const TRANSIENT_HTTP_STATUS = /* @__PURE__ */ new Set([
|
|
458
|
+
408,
|
|
459
|
+
425,
|
|
460
|
+
429
|
|
461
|
+
]);
|
|
462
|
+
/**
|
|
463
|
+
* Whether a failed provider query is worth retrying: per-attempt timeouts,
|
|
464
|
+
* undici network failures, HTTP 408/425/429/5xx (including OAuth refresh
|
|
465
|
+
* failures carrying `(HTTP <status>)`), and transient socket text. Permanent
|
|
466
|
+
* 4xx (400/401/403/404/422, e.g. a model-unsupported or invalid_grant reply)
|
|
467
|
+
* and adapter-side data errors fail immediately.
|
|
468
|
+
*/
|
|
469
|
+
function isTransientQueryError(error) {
|
|
470
|
+
if (!(error instanceof Error)) return false;
|
|
471
|
+
if (error.name === "TimeoutError" || error.name === "AbortError") return true;
|
|
472
|
+
const status = Number(/HTTP (\d+)/.exec(error.message)?.[1] ?? NaN);
|
|
473
|
+
if (Number.isFinite(status)) return status >= 500 || TRANSIENT_HTTP_STATUS.has(status);
|
|
474
|
+
if (error instanceof TypeError) return true;
|
|
475
|
+
return /\b(?:fetch failed|ECONN[A-Z]+|ETIMEDOUT|EAI_AGAIN|socket hang up|other side closed|premature close)\b/i.test(error.message);
|
|
476
|
+
}
|
|
477
|
+
/** Delay that resolves early (without throwing) when the outer signal aborts. */
|
|
478
|
+
function sleep(ms, signal) {
|
|
479
|
+
return new Promise((resolve) => {
|
|
480
|
+
const timer = setTimeout(done, ms);
|
|
481
|
+
function done() {
|
|
482
|
+
clearTimeout(timer);
|
|
483
|
+
signal?.removeEventListener("abort", done);
|
|
484
|
+
resolve();
|
|
485
|
+
}
|
|
486
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
487
|
+
});
|
|
488
|
+
}
|
|
450
489
|
function failView(id, displayName, kind, status, message, active) {
|
|
451
490
|
return {
|
|
452
491
|
id,
|
|
@@ -990,33 +1029,38 @@ var UsageService = class extends TypertRemoteService {
|
|
|
990
1029
|
usages: null,
|
|
991
1030
|
active
|
|
992
1031
|
};
|
|
993
|
-
const
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1032
|
+
const options = this.options();
|
|
1033
|
+
const maxAttempts = options.queryRetries + 1;
|
|
1034
|
+
for (let attempt = 1;; attempt++) {
|
|
1035
|
+
const signal = AbortSignal.any([AbortSignal.timeout(options.queryTimeoutMs), ...outerSignal ? [outerSignal] : []]);
|
|
1036
|
+
try {
|
|
1037
|
+
let apiKey;
|
|
1038
|
+
let refresh;
|
|
1039
|
+
if (spec.kind === "openai-codex" && spec.apiKeyEnv === void 0) {
|
|
1040
|
+
refresh = async (refreshSignal) => {
|
|
1041
|
+
const grant = await this.resolveOpenAiCodexGrant(refreshSignal);
|
|
1042
|
+
if (grant === void 0) throw new Error("OpenAI Codex OAuth authorization missing");
|
|
1043
|
+
return grant.access;
|
|
1044
|
+
};
|
|
1045
|
+
const grant = await this.resolveOpenAiCodexGrant(signal);
|
|
1046
|
+
if (grant === void 0) return failView(spec.id, spec.displayName, adapter.view, "missing-authorization", "llm-pi-ai/openai-codex", active);
|
|
1047
|
+
apiKey = grant.access;
|
|
1048
|
+
} else {
|
|
1049
|
+
const resolved = await this.resolveApiKey(spec.apiKeyEnv);
|
|
1050
|
+
if (resolved === void 0) return failView(spec.id, spec.displayName, adapter.view, "missing-credential", spec.apiKeyEnv, active);
|
|
1051
|
+
apiKey = resolved;
|
|
1052
|
+
}
|
|
1053
|
+
const payload = await adapter.fetch(spec.baseURL, apiKey, signal, refresh);
|
|
1054
|
+
return okView({
|
|
1055
|
+
...base,
|
|
1056
|
+
...payload
|
|
1057
|
+
});
|
|
1058
|
+
} catch (error) {
|
|
1059
|
+
if (outerSignal?.aborted) throw error;
|
|
1060
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1061
|
+
if (attempt >= maxAttempts || !isTransientQueryError(error)) return failView(spec.id, spec.displayName, adapter.view, "error", message, active);
|
|
1062
|
+
await sleep(Math.min(options.queryRetryDelayMs * 2 ** (attempt - 1), 1e4), outerSignal);
|
|
1010
1063
|
}
|
|
1011
|
-
const payload = await adapter.fetch(spec.baseURL, apiKey, signal, refresh);
|
|
1012
|
-
return okView({
|
|
1013
|
-
...base,
|
|
1014
|
-
...payload
|
|
1015
|
-
});
|
|
1016
|
-
} catch (error) {
|
|
1017
|
-
if (outerSignal?.aborted) throw error;
|
|
1018
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1019
|
-
return failView(spec.id, spec.displayName, adapter.view, "error", message, active);
|
|
1020
1064
|
}
|
|
1021
1065
|
}
|
|
1022
1066
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-provider-usage",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "DeepSeek Harness plugin: live account balance/usage panel for every configured LLM provider (draggable floating-ball widget, configurable refresh interval and balance thresholds)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"files": [
|
|
27
27
|
"lib",
|
|
28
28
|
"cordis.patch.yml",
|
|
29
|
+
"docs",
|
|
29
30
|
"README_ZH.md"
|
|
30
31
|
],
|
|
31
32
|
"license": "MIT",
|
|
@@ -69,19 +70,19 @@
|
|
|
69
70
|
},
|
|
70
71
|
"peerDependencies": {
|
|
71
72
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
72
|
-
"@deepseek-ai/dsh-credentials": "^0.1.
|
|
73
|
-
"@deepseek-ai/dsh-launch-environment": "^0.1.
|
|
74
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
75
|
-
"@deepseek-ai/dsh-typert-protocol": "^0.1.
|
|
73
|
+
"@deepseek-ai/dsh-credentials": "^0.1.2-alpha.3",
|
|
74
|
+
"@deepseek-ai/dsh-launch-environment": "^0.1.2-alpha.3",
|
|
75
|
+
"@deepseek-ai/dsh-settings": "^0.1.2-alpha.3",
|
|
76
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.3",
|
|
76
77
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
77
78
|
"react": "^18.2.0"
|
|
78
79
|
},
|
|
79
80
|
"devDependencies": {
|
|
80
81
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
81
|
-
"@deepseek-ai/dsh-credentials": "0.1.
|
|
82
|
-
"@deepseek-ai/dsh-launch-environment": "0.1.
|
|
83
|
-
"@deepseek-ai/dsh-settings": "0.1.
|
|
84
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.
|
|
82
|
+
"@deepseek-ai/dsh-credentials": "0.1.2-alpha.3",
|
|
83
|
+
"@deepseek-ai/dsh-launch-environment": "0.1.2-alpha.3",
|
|
84
|
+
"@deepseek-ai/dsh-settings": "0.1.2-alpha.3",
|
|
85
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.2-alpha.3",
|
|
85
86
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
86
87
|
"@types/node": "^24.13.3",
|
|
87
88
|
"@types/react": "~18.3.1",
|