dsh-provider-usage 0.3.10 → 0.3.12
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/client.js +3 -0
- package/lib/client.js.map +1 -1
- package/lib/index.js +71 -27
- package/package.json +10 -9
|
@@ -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/client.js
CHANGED
|
@@ -1040,6 +1040,9 @@ window.__ModuleLoader__.load({
|
|
|
1040
1040
|
tone halo stacks on top. */
|
|
1041
1041
|
.dsh-usage-ball {
|
|
1042
1042
|
position: fixed; z-index: 999; width: 32px; height: 32px; border-radius: 50%;
|
|
1043
|
+
/* The shell's theme opts every element into squircle corners
|
|
1044
|
+
(corner-shape: superellipse) under @supports; a ball must stay round. */
|
|
1045
|
+
corner-shape: round;
|
|
1043
1046
|
cursor: pointer; touch-action: none;
|
|
1044
1047
|
display: inline-flex; align-items: center; justify-content: center;
|
|
1045
1048
|
border: 1px solid var(--dsw-alias-border-l2);
|