dsh-any-deepseek 0.0.14 → 0.0.15
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/lib/channels.d.ts +4 -1
- package/lib/client.js +9 -0
- package/lib/http.d.ts +66 -3
- package/lib/index.js +66 -13
- package/lib/presets.d.ts +3 -1
- package/package.json +1 -1
package/lib/channels.d.ts
CHANGED
|
@@ -102,7 +102,10 @@ export interface ResolvedChannel {
|
|
|
102
102
|
* How this endpoint's remaining balance can be read, when it can be.
|
|
103
103
|
*
|
|
104
104
|
* Absent means "no balance API" — a real state, not a missing value. See `presets.ts` for the
|
|
105
|
-
*
|
|
105
|
+
* four verified shapes. Note the two different kinds of "no number": OpenCode Go reports usage
|
|
106
|
+
* WINDOWS rather than money (it does have a surface), while Open Design publishes no surface at
|
|
107
|
+
* all (measured: seven candidates, all 404). The panel distinguishes them, and checks liveness
|
|
108
|
+
* for the latter instead of inventing an amount.
|
|
106
109
|
*/
|
|
107
110
|
balance?: BalanceProbe;
|
|
108
111
|
/** Facts the user should see because a default was applied rather than declared. */
|
package/lib/client.js
CHANGED
|
@@ -27,12 +27,20 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
*
|
|
28
28
|
* Deliberately total: every status produces words, never an empty string. A blank cell beside a
|
|
29
29
|
* working channel is indistinguishable from "zero balance" — the one thing this must never imply.
|
|
30
|
+
*
|
|
31
|
+
* 🔴 **`alive` is worded as 「余额未尽」, never as a number.** The check behind it is one minimal
|
|
32
|
+
* live request, which proves the endpoint serves and the account is not blocked for lack of
|
|
33
|
+
* credit. It does not measure an amount, so printing one — or printing `0.00` — would invent the
|
|
34
|
+
* very figure this status exists to avoid inventing (owner directive 2026-10-23: 「不支持查余额的,
|
|
35
|
+
* 改成直接测通,通则说明余额还是有的,没用完」).
|
|
30
36
|
* @param row - one row from `/balance`.
|
|
31
37
|
* @returns a short human label.
|
|
32
38
|
*/
|
|
33
39
|
function formatBalance(row) {
|
|
40
|
+
if (row.status === "alive") return `余额未尽(无余额接口,实测可用:${row.responded === void 0 ? `${Math.round(row.ms)}ms` : `${row.responded} · ${Math.round(row.ms)}ms`})`;
|
|
34
41
|
if (row.status !== "ok") {
|
|
35
42
|
if (row.status === "no-key") return "未配置密钥";
|
|
43
|
+
if (row.code === "QUOTA") return "余额不足(实测被拒)";
|
|
36
44
|
if (row.status === "unavailable") return row.code === "HTTP_404" ? "不支持查询" : "读取失败";
|
|
37
45
|
return "不支持查询";
|
|
38
46
|
}
|
|
@@ -508,6 +516,7 @@ window.__ModuleLoader__.load({
|
|
|
508
516
|
type: "button",
|
|
509
517
|
className: "ad-link",
|
|
510
518
|
disabled: balancesLoading || rows.length === 0,
|
|
519
|
+
title: "无余额接口的渠道会用一次最小真实请求测通(消耗一两个 token)",
|
|
511
520
|
onClick: () => {
|
|
512
521
|
refreshBalances();
|
|
513
522
|
},
|
package/lib/http.d.ts
CHANGED
|
@@ -121,10 +121,11 @@ export declare function reportedName(text: string): string;
|
|
|
121
121
|
/**
|
|
122
122
|
* Fetch one channel's remaining balance from whatever surface it declares.
|
|
123
123
|
*
|
|
124
|
-
* 🔴 **Absence is a normal answer here, and is reported as such.**
|
|
124
|
+
* 🔴 **Absence is a normal answer here, and is reported as such.** Outcomes are kept apart
|
|
125
125
|
* because they mean different things to the user:
|
|
126
|
-
* · `unsupported` — the preset declares no balance shape
|
|
127
|
-
*
|
|
126
|
+
* · `unsupported` — the preset declares no balance shape. This is no longer the end of the story
|
|
127
|
+
* for the panel: `/{@link balanceRow}` turns it into a liveness verdict, because "the endpoint
|
|
128
|
+
* will not tell me the amount" and "the account is fine" are different facts and both matter.
|
|
128
129
|
* · `unavailable` — a shape was declared but the endpoint did not answer as expected (404,
|
|
129
130
|
* non-JSON, unexpected body). The relay may simply not implement it.
|
|
130
131
|
* · `ok` — a reading, which itself may carry only a note (e.g. "unlimited, used $3.20").
|
|
@@ -147,6 +148,68 @@ export declare function fetchBalance(channel: ResolvedChannel, key: string, sign
|
|
|
147
148
|
detail: string;
|
|
148
149
|
code?: string;
|
|
149
150
|
}>;
|
|
151
|
+
/**
|
|
152
|
+
* One row of `/balance`, as it travels to the panel.
|
|
153
|
+
*
|
|
154
|
+
* `alive` is the fourth outcome and exists because of an owner directive (2026-10-23):
|
|
155
|
+
* 「对于不支持查余额的,改成直接测通,通则说明余额还是有的,没用完,显示出来(消耗一两个token)」.
|
|
156
|
+
*
|
|
157
|
+
* 🔴 **`alive` is NOT a balance number and must never be rendered as one.** It is the result of a
|
|
158
|
+
* minimal real inference request, and it proves exactly three things: the key works, the endpoint
|
|
159
|
+
* serves, and the account is not blocked for lack of credit (a $0 account answers 402/quota, it
|
|
160
|
+
* does not answer 200). It says nothing about HOW MUCH is left. The panel wording therefore says
|
|
161
|
+
* 「余额未尽」 — "not exhausted" — which is the strongest true claim available here, and stops
|
|
162
|
+
* short of the number a reader might otherwise assume.
|
|
163
|
+
*/
|
|
164
|
+
export type BalanceRowWire = {
|
|
165
|
+
id: string;
|
|
166
|
+
label: string;
|
|
167
|
+
status: 'ok';
|
|
168
|
+
reading: BalanceReading;
|
|
169
|
+
} | {
|
|
170
|
+
id: string;
|
|
171
|
+
label: string;
|
|
172
|
+
status: 'unsupported';
|
|
173
|
+
detail: string;
|
|
174
|
+
} | {
|
|
175
|
+
id: string;
|
|
176
|
+
label: string;
|
|
177
|
+
status: 'unavailable';
|
|
178
|
+
detail: string;
|
|
179
|
+
code?: string;
|
|
180
|
+
} | {
|
|
181
|
+
id: string;
|
|
182
|
+
label: string;
|
|
183
|
+
status: 'alive';
|
|
184
|
+
/** How long the liveness request took. */
|
|
185
|
+
ms: number;
|
|
186
|
+
/** What the relay called its model — a serving endpoint answers with a name. */
|
|
187
|
+
responded?: string;
|
|
188
|
+
detail: string;
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* The stated reason an `alive` row carries no number.
|
|
192
|
+
*
|
|
193
|
+
* Kept as a constant so the server and every reader of the payload say the same thing: this row
|
|
194
|
+
* is about liveness, not about a balance.
|
|
195
|
+
*/
|
|
196
|
+
export declare const ALIVE_DETAIL: string;
|
|
197
|
+
/**
|
|
198
|
+
* Build one `/balance` row, falling back to a liveness probe when there is no balance surface.
|
|
199
|
+
*
|
|
200
|
+
* 🔴 **The fallback spends tokens, so it is scoped as tightly as possible**: it runs ONLY when the
|
|
201
|
+
* balance surface is absent (`unsupported`), never for a channel whose balance API answered `ok`
|
|
202
|
+
* and never for one that exists but failed (`unavailable` — that is a "try again" state, and
|
|
203
|
+
* probing it would replace a transient error with a different-looking success).
|
|
204
|
+
*
|
|
205
|
+
* The cost is one prompt plus one output token on a completions channel (`max_tokens: 1` in
|
|
206
|
+
* {@link probeRequest}); the Responses cap is a ceiling, not a spend.
|
|
207
|
+
* @param channel - the resolved channel.
|
|
208
|
+
* @param key - its resolved credential (already resolved by the caller, so a probe and a real
|
|
209
|
+
* request never read the key differently).
|
|
210
|
+
* @returns the row, always resolved — one dead relay must not blank the others.
|
|
211
|
+
*/
|
|
212
|
+
export declare function balanceRow(channel: ResolvedChannel, key: string): Promise<BalanceRowWire>;
|
|
150
213
|
/**
|
|
151
214
|
* Register the panel's routes.
|
|
152
215
|
* @param ctx - plugin context (only used to bind the disposer when the host offers one).
|
package/lib/index.js
CHANGED
|
@@ -2235,10 +2235,11 @@ function reportedName(text) {
|
|
|
2235
2235
|
/**
|
|
2236
2236
|
* Fetch one channel's remaining balance from whatever surface it declares.
|
|
2237
2237
|
*
|
|
2238
|
-
* 🔴 **Absence is a normal answer here, and is reported as such.**
|
|
2238
|
+
* 🔴 **Absence is a normal answer here, and is reported as such.** Outcomes are kept apart
|
|
2239
2239
|
* because they mean different things to the user:
|
|
2240
|
-
* · `unsupported` — the preset declares no balance shape
|
|
2241
|
-
*
|
|
2240
|
+
* · `unsupported` — the preset declares no balance shape. This is no longer the end of the story
|
|
2241
|
+
* for the panel: `/{@link balanceRow}` turns it into a liveness verdict, because "the endpoint
|
|
2242
|
+
* will not tell me the amount" and "the account is fine" are different facts and both matter.
|
|
2242
2243
|
* · `unavailable` — a shape was declared but the endpoint did not answer as expected (404,
|
|
2243
2244
|
* non-JSON, unexpected body). The relay may simply not implement it.
|
|
2244
2245
|
* · `ok` — a reading, which itself may carry only a note (e.g. "unlimited, used $3.20").
|
|
@@ -2319,6 +2320,61 @@ async function fetchBalance(channel, key, signal) {
|
|
|
2319
2320
|
reading
|
|
2320
2321
|
};
|
|
2321
2322
|
}
|
|
2323
|
+
/**
|
|
2324
|
+
* The stated reason an `alive` row carries no number.
|
|
2325
|
+
*
|
|
2326
|
+
* Kept as a constant so the server and every reader of the payload say the same thing: this row
|
|
2327
|
+
* is about liveness, not about a balance.
|
|
2328
|
+
*/
|
|
2329
|
+
const ALIVE_DETAIL = "this endpoint publishes no balance API; a minimal live request succeeded, so it is serving and its credit is not exhausted (no amount is readable)";
|
|
2330
|
+
/**
|
|
2331
|
+
* Build one `/balance` row, falling back to a liveness probe when there is no balance surface.
|
|
2332
|
+
*
|
|
2333
|
+
* 🔴 **The fallback spends tokens, so it is scoped as tightly as possible**: it runs ONLY when the
|
|
2334
|
+
* balance surface is absent (`unsupported`), never for a channel whose balance API answered `ok`
|
|
2335
|
+
* and never for one that exists but failed (`unavailable` — that is a "try again" state, and
|
|
2336
|
+
* probing it would replace a transient error with a different-looking success).
|
|
2337
|
+
*
|
|
2338
|
+
* The cost is one prompt plus one output token on a completions channel (`max_tokens: 1` in
|
|
2339
|
+
* {@link probeRequest}); the Responses cap is a ceiling, not a spend.
|
|
2340
|
+
* @param channel - the resolved channel.
|
|
2341
|
+
* @param key - its resolved credential (already resolved by the caller, so a probe and a real
|
|
2342
|
+
* request never read the key differently).
|
|
2343
|
+
* @returns the row, always resolved — one dead relay must not blank the others.
|
|
2344
|
+
*/
|
|
2345
|
+
async function balanceRow(channel, key) {
|
|
2346
|
+
const outcome = await fetchBalance(channel, key);
|
|
2347
|
+
if (outcome.status !== "unsupported") return {
|
|
2348
|
+
id: channel.id,
|
|
2349
|
+
label: channel.label,
|
|
2350
|
+
...outcome
|
|
2351
|
+
};
|
|
2352
|
+
const verdict = await probeChannel(channel, key, `probe:${channel.id}`);
|
|
2353
|
+
if (!verdict.ok)
|
|
2354
|
+
/**
|
|
2355
|
+
* The liveness request failed, so nothing was learned about the account.
|
|
2356
|
+
*
|
|
2357
|
+
* It is reported as `unavailable` rather than as a verdict of its own because that is what it
|
|
2358
|
+
* is: we tried to find out and did not. `code` is passed through untouched, which is what lets
|
|
2359
|
+
* the panel tell the one FAILURE THAT IS ACTUALLY AN ANSWER (`QUOTA` — the account is out of
|
|
2360
|
+
* credit) from the ones that are just errors.
|
|
2361
|
+
*/
|
|
2362
|
+
return {
|
|
2363
|
+
id: channel.id,
|
|
2364
|
+
label: channel.label,
|
|
2365
|
+
status: "unavailable",
|
|
2366
|
+
detail: `no balance API, and the liveness request failed: ${verdict.message ?? verdict.code ?? "unknown"}`,
|
|
2367
|
+
...verdict.code === void 0 ? {} : { code: verdict.code }
|
|
2368
|
+
};
|
|
2369
|
+
return {
|
|
2370
|
+
id: channel.id,
|
|
2371
|
+
label: channel.label,
|
|
2372
|
+
status: "alive",
|
|
2373
|
+
ms: verdict.ms,
|
|
2374
|
+
...verdict.responded === void 0 || verdict.responded === "" ? {} : { responded: verdict.responded },
|
|
2375
|
+
detail: ALIVE_DETAIL
|
|
2376
|
+
};
|
|
2377
|
+
}
|
|
2322
2378
|
/** Map an HTTP status from a probe onto the same codes the runtime uses. */
|
|
2323
2379
|
function probeCode(status, body) {
|
|
2324
2380
|
if (status === 401 || status === 403) return "AUTH";
|
|
@@ -2469,10 +2525,12 @@ function registerStatsRoutes(ctx, webServer, deps) {
|
|
|
2469
2525
|
/**
|
|
2470
2526
|
* Remaining balance per channel.
|
|
2471
2527
|
*
|
|
2472
|
-
* GET because it
|
|
2473
|
-
*
|
|
2474
|
-
*
|
|
2475
|
-
*
|
|
2528
|
+
* GET because it is a read, but 🔴 **it is no longer free**: a channel whose endpoint has no
|
|
2529
|
+
* balance surface is now checked with one minimal live request (owner directive 2026-10-23),
|
|
2530
|
+
* which costs a prompt plus one output token. The route stays GET because the panel's
|
|
2531
|
+
* button is what triggers it — nothing here fires on render. Every channel is attempted
|
|
2532
|
+
* independently: one relay without a balance API, or one that is down, must not blank the
|
|
2533
|
+
* others — the same rule the channel list follows for a broken entry.
|
|
2476
2534
|
*/
|
|
2477
2535
|
kind: "exact",
|
|
2478
2536
|
path: `${ROUTE_PREFIX}/balance`,
|
|
@@ -2486,12 +2544,7 @@ function registerStatsRoutes(ctx, webServer, deps) {
|
|
|
2486
2544
|
status: "no-key",
|
|
2487
2545
|
detail: "no key configured"
|
|
2488
2546
|
};
|
|
2489
|
-
|
|
2490
|
-
return {
|
|
2491
|
-
id: channel.id,
|
|
2492
|
-
label: channel.label,
|
|
2493
|
-
...outcome
|
|
2494
|
-
};
|
|
2547
|
+
return balanceRow(channel, key);
|
|
2495
2548
|
})) });
|
|
2496
2549
|
}
|
|
2497
2550
|
}
|
package/lib/presets.d.ts
CHANGED
|
@@ -98,7 +98,9 @@ export interface ChannelPreset {
|
|
|
98
98
|
*
|
|
99
99
|
* Absent means "this endpoint has no balance API we know of" — a real and common state, not an
|
|
100
100
|
* omission. The panel says so explicitly rather than leaving a blank cell that could be read
|
|
101
|
-
* as zero
|
|
101
|
+
* as zero, and then checks the endpoint is ALIVE with one minimal live request (owner directive
|
|
102
|
+
* 2026-10-23): "no amount is readable" and "the credit is spent" are different facts, and a
|
|
103
|
+
* successful call proves the second is not true. See `http.ts`'s `balanceRow`.
|
|
102
104
|
*/
|
|
103
105
|
balance?: BalanceProbe;
|
|
104
106
|
/** One-line note for the panel, when the relay needs explaining. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-any-deepseek",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "One DeepSeek V4.1 Flash provider for DeepSeek Harness: paste a key per channel, switch channels manually, token usage booked per real upstream.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|