@mars-sea/dsh-commandcode-provider 0.11.16 → 0.12.0
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/CHANGELOG.md +56 -0
- package/README.md +17 -29
- package/README.zh-CN.md +14 -26
- package/lib/client.js +526 -766
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +422 -499
- package/lib/index.js +1893 -2175
- package/lib/index.js.map +1 -1
- package/package.json +37 -37
package/lib/index.d.ts
CHANGED
|
@@ -7,16 +7,63 @@ import { Context } from "@deepseek-ai/cordis";
|
|
|
7
7
|
import { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
8
8
|
import { CommandDefinition } from "@deepseek-ai/dsh-commands";
|
|
9
9
|
//#region src/adapter.d.ts
|
|
10
|
-
declare const COMMAND_CODE_CLI_VERSION = "1.
|
|
10
|
+
declare const COMMAND_CODE_CLI_VERSION = "1.68.0";
|
|
11
11
|
declare const DEFAULT_API_BASE = "https://api.commandcode.ai";
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The output budget this bundle asks for, and the ceiling it will never exceed.
|
|
14
|
+
*
|
|
15
|
+
* 131 072, chosen against a measured provider limit rather than a round guess.
|
|
16
|
+
* Probing `/alpha/generate` directly on 2026-09-28: 64 000 → 200, 131 072 → 200,
|
|
17
|
+
* 196 608 → 200, **200 000 → 200, 200 704 → 400**, 1 000 000 → 400. The server
|
|
18
|
+
* therefore caps `max_tokens` at 200 000, and it does so identically for a
|
|
19
|
+
* 262 144-window model (`stealth/pixel-canary`) and a 1 000 000-window one
|
|
20
|
+
* (`stealth/space-bunny-alpha`) — the cap is global, not per model. 131 072
|
|
21
|
+
* keeps a 35 % margin under it while covering the real output ceiling of the
|
|
22
|
+
* models that have one (Claude 64 K, Gemini 64 K, several at 128 K).
|
|
23
|
+
*
|
|
24
|
+
* The old 64 000 was never a provider requirement: it cost nothing in latency
|
|
25
|
+
* (a 64 000 request answered headers in 1.28 s against 1.57 s for 131 072) but
|
|
26
|
+
* it did cap what a model could ever say in one turn.
|
|
27
|
+
*
|
|
28
|
+
* This is only an UPPER bound. `requestContextBudget` lowers it per request
|
|
29
|
+
* from the prompt actually being sent, so raising the ceiling cannot push a
|
|
30
|
+
* large session over its window.
|
|
31
|
+
*/
|
|
32
|
+
declare const DEFAULT_GENERATE_MAX_TOKENS = 131072;
|
|
33
|
+
/**
|
|
34
|
+
* The fallback when the catalog carries no output ceiling for a model.
|
|
35
|
+
*
|
|
36
|
+
* `/provider/v1/models` publishes only `context_length` — no output limit — so
|
|
37
|
+
* the catalog cannot learn one per model and derives a stand-in from the
|
|
38
|
+
* window instead. Kept equal to {@link DEFAULT_GENERATE_MAX_TOKENS} on purpose:
|
|
39
|
+
* a lower value here would silently re-cap every request through
|
|
40
|
+
* `Math.min(contextLength, this)` before the ceiling above is ever consulted.
|
|
41
|
+
*/
|
|
42
|
+
declare const DEFAULT_MAX_OUTPUT_TOKENS = 131072;
|
|
14
43
|
/** How long the picker's plan-filter billing facts stay cached before refetching. */
|
|
15
44
|
declare const BILLING_ACCESS_TTL_MS: number;
|
|
16
45
|
/** Endpoint protocol selected for one generate call. */
|
|
17
46
|
type CommandCodeProtocol = 'cli' | 'openai';
|
|
18
|
-
/**
|
|
19
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Head-of-request timeout: how long to wait for the first response byte.
|
|
49
|
+
*
|
|
50
|
+
* 300 s, and that number is the official CLI's, not a round choice. Decompiled
|
|
51
|
+
* from `command-code@1.66.0`: its `createNodeTransport` fetch passes only the
|
|
52
|
+
* caller's `signal` and sets no timeout at all, so the model request inherits
|
|
53
|
+
* Node/undici's own default — measured at 301.0 s against a local server that
|
|
54
|
+
* accepts the connection and never sends headers. The previous 60 s default was
|
|
55
|
+
* five times stricter than the CLI it emulates, and being stricter only ever
|
|
56
|
+
* costs legitimate requests: a slow upstream first token on the Provider API
|
|
57
|
+
* route can outlast 60 s, and the official CLI simply waits it out. Measured
|
|
58
|
+
* headers (2026-09-28, 26 250-token prompt, `max_tokens: 16` to separate the
|
|
59
|
+
* header from the generation): `/alpha/generate` 2.12 / 2.56 / 2.75 s,
|
|
60
|
+
* `/provider/v1/chat/completions` 5.52 / 2.98 / 3.70 s — a ~1.1 s median gap
|
|
61
|
+
* with the Provider API route varying over a 2.5 s span against the CLI route's
|
|
62
|
+
* 0.6 s. A gateway that is genuinely dead now takes longer to name itself,
|
|
63
|
+
* which is what the consecutive-timeout streak exists to bound (three
|
|
64
|
+
* attempts, then a diagnosis instead of another re-send).
|
|
65
|
+
*/
|
|
66
|
+
declare const DEFAULT_REQUEST_TIMEOUT_MS = 300000;
|
|
20
67
|
/** Stream idle timeout: a generation that stalls this long is a dead connection. */
|
|
21
68
|
declare const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300000;
|
|
22
69
|
declare function projectSlugFromPath(pathName: string): string;
|
|
@@ -46,13 +93,23 @@ interface CommandCodeConnectionOptions {
|
|
|
46
93
|
/** Model catalog cache path. */
|
|
47
94
|
modelsCachePath: string;
|
|
48
95
|
/**
|
|
49
|
-
* Milliseconds to wait for generate response headers / first byte (default
|
|
96
|
+
* Milliseconds to wait for generate response headers / first byte (default
|
|
97
|
+
* 300s, the official CLI's own budget — see
|
|
98
|
+
* {@link DEFAULT_REQUEST_TIMEOUT_MS}).
|
|
50
99
|
* Must not bound the subsequent body stream — long generations are gated by
|
|
51
100
|
* {@link streamIdleTimeoutMs} and the caller AbortSignal instead.
|
|
52
101
|
*/
|
|
53
102
|
requestTimeoutMs: number;
|
|
54
103
|
/** Milliseconds a stream may stall before it is treated as a dead connection (default 300s). */
|
|
55
104
|
streamIdleTimeoutMs: number;
|
|
105
|
+
/**
|
|
106
|
+
* Opt-in CLI cache mitigation: after this same model has answered with an
|
|
107
|
+
* image in its history, ask dsh's durable image-offload surface to replace
|
|
108
|
+
* that image before the next replay. This protects the growing text prefix
|
|
109
|
+
* when Command Code's multimodal cache retreats to the first image, but the
|
|
110
|
+
* model cannot inspect the old pixels again without a fresh tool/user image.
|
|
111
|
+
*/
|
|
112
|
+
offloadSeenImagesForCache?: boolean;
|
|
56
113
|
/**
|
|
57
114
|
* Whether the picker hides models above the account's subscription tier
|
|
58
115
|
* (default true). The filter fails open: unknown plan, billing-endpoint
|
|
@@ -93,8 +150,6 @@ interface CommandCodeConnectionOptions {
|
|
|
93
150
|
* `CMD_ZDR=1`). Default false. Every chat request carries the header when
|
|
94
151
|
* enabled. The provider refuses a model without a ZDR-capable upstream with
|
|
95
152
|
* 422 `cmd_zdr_no_providers`; never retry that request without the header.
|
|
96
|
-
* The decision endpoint (`/provider/v1/systemone`) is deliberately never
|
|
97
|
-
* reached through this connection option — see `./systemone.ts`.
|
|
98
153
|
*/
|
|
99
154
|
zdr?: boolean;
|
|
100
155
|
}
|
|
@@ -110,12 +165,11 @@ type ResolveAttachments = () => AttachmentStore | undefined;
|
|
|
110
165
|
* `invalid-credential` are the three the pool records as marks; `unavailable`
|
|
111
166
|
* is an account-scoped rejection that must NOT become a mark — the account's
|
|
112
167
|
* key is valid and its windows may be open, the ACCOUNT just cannot serve THIS
|
|
113
|
-
* request
|
|
114
|
-
* without remembering anything.
|
|
168
|
+
* request — so the pool moves on without remembering anything.
|
|
115
169
|
*
|
|
116
170
|
* The window/throttle split decides what the pool may CLAIM, never whether it
|
|
117
|
-
* rotates
|
|
118
|
-
*
|
|
171
|
+
* rotates (issue #54); the evidence that separates them is in
|
|
172
|
+
* {@link classifyAccountRejection}.
|
|
119
173
|
*/
|
|
120
174
|
type AccountRotationReason = 'rate-limit' | 'throttled' | 'invalid-credential' | 'unavailable';
|
|
121
175
|
/** What the rotation hook knows about the request it is rotating within. */
|
|
@@ -149,11 +203,10 @@ interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = Comman
|
|
|
149
203
|
* with several accounts a rejection that does not mark the key (a plan or
|
|
150
204
|
* balance rejection is model-specific, not account-fatal) would otherwise
|
|
151
205
|
* re-offer the same account on every attempt and the pool could never reach
|
|
152
|
-
* the accounts behind it.
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* instead of waiting for a billing probe to learn the same fact.
|
|
206
|
+
* the accounts behind it. `rotation.resetAtMs` carries the provider's own
|
|
207
|
+
* reset time when the rejection body published one, so the host can hold the
|
|
208
|
+
* key out until then instead of waiting for a billing probe to learn the
|
|
209
|
+
* same fact.
|
|
157
210
|
*/
|
|
158
211
|
rotateApiKey?: (rejectedKey: string, rejection: AccountRotationReason, connection: C, model?: string, rotation?: AccountRotationContext) => Promise<string | undefined>;
|
|
159
212
|
/**
|
|
@@ -283,7 +336,29 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
283
336
|
private readonly billingAccess;
|
|
284
337
|
private readonly billingAccessInflight;
|
|
285
338
|
private readonly protocolCache;
|
|
339
|
+
/**
|
|
340
|
+
* Consecutive header timeouts for the last request shape, counted ACROSS
|
|
341
|
+
* `stream()` calls: dsh-llm-retry re-invokes this same instance, so this is
|
|
342
|
+
* the only place a streak can live. One slot rather than a map is the point —
|
|
343
|
+
* the claim is "consecutive", and a single record cannot grow.
|
|
344
|
+
*/
|
|
345
|
+
private headerTimeoutStreak;
|
|
286
346
|
constructor(deps: CommandCodeAdapterDeps<C>);
|
|
347
|
+
/**
|
|
348
|
+
* Grade one failed attempt: a headers timeout that repeats on an unchanged
|
|
349
|
+
* payload eventually leaves the retryable whitelist.
|
|
350
|
+
*
|
|
351
|
+
* `providerRetryPolicy()` cannot express this itself — dsh-llm's
|
|
352
|
+
* `NormalRetryPolicyConfig` carries a single scalar `maxRetries` next to the
|
|
353
|
+
* code list, so there is no per-code limit to lower. Escalating from here is
|
|
354
|
+
* the only way to keep `RATE_LIMIT` / `SERVER` / `TRANSPORT` retryable (each
|
|
355
|
+
* carries a real "try again later" signal) while stopping the one code that,
|
|
356
|
+
* repeated unchanged, only burns the user's session.
|
|
357
|
+
*
|
|
358
|
+
* @returns the error to surface: unchanged for any other failure, the
|
|
359
|
+
* original timeout below the threshold, and a terminal one at it.
|
|
360
|
+
*/
|
|
361
|
+
private gradeHeaderTimeout;
|
|
287
362
|
/**
|
|
288
363
|
* Display metadata for the picker's provider group header. The base class
|
|
289
364
|
* returns the raw route id (`commandcode`, all lowercase) as the name, which
|
|
@@ -298,13 +373,13 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
298
373
|
* unbounded loop): `RATE_LIMIT`/`SERVER`/`TIMEOUT`/`TRANSPORT`/
|
|
299
374
|
* `EMPTY_RESPONSE` retry up to 1000 times with waits doubling from 500 ms
|
|
300
375
|
* and capping at 15 minutes (±10% jitter), so an exhausted 5-hour window
|
|
301
|
-
* recovers in-session instead of failing after two tries. Permanent
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
376
|
+
* recovers in-session instead of failing after two tries. Permanent failures
|
|
377
|
+
* (an invalid key's `INVALID_CREDENTIAL`, `UNSUPPORTED_CONTENT`, plan
|
|
378
|
+
* rejections) are absent from the whitelist and surface immediately instead
|
|
379
|
+
* of looping. Waits the pool/adapter attach as `providerRetryAfterMs` are
|
|
380
|
+
* honored verbatim at or below the 15-minute cap and never attached above it
|
|
381
|
+
* (in normal mode a longer attached wait makes the executor abandon the
|
|
382
|
+
* retry outright — see RETRY_MAX_DELAY_MS).
|
|
308
383
|
*
|
|
309
384
|
* Captured once at route registration (dsh-llm snapshots this value), so a
|
|
310
385
|
* future config knob for it would apply on profile restart, not per request.
|
|
@@ -318,12 +393,8 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
318
393
|
* session reports far less context than it is actually carrying. The price is
|
|
319
394
|
* computed at the dimensions this route would send (the same request target
|
|
320
395
|
* `readImageRequest` encodes to), so the estimate tracks the wire rather than
|
|
321
|
-
* the stored original.
|
|
322
|
-
*
|
|
323
|
-
* Both payload generations are handled, because they disagree: ≤0.1.5 hands
|
|
324
|
-
* over bare `ImageAttachmentRef`s, ≥0.1.6 hands over `ImageBlock`s that also
|
|
325
|
-
* carry the surface's `offloaded` mark. Returning a price per occurrence, in
|
|
326
|
-
* order, is a hard requirement — the meter throws when the counts differ.
|
|
396
|
+
* the stored original. One price per occurrence, in order, is a hard
|
|
397
|
+
* requirement — the meter throws when the counts differ.
|
|
327
398
|
*/
|
|
328
399
|
imageRequestPricing(_provider: string, model: string): LlmImageRequestPricing | undefined;
|
|
329
400
|
/** Refresh the catalog (live fetch, cache fallback) and return it. */
|
|
@@ -331,22 +402,35 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
331
402
|
listModels(provider: string, opts?: {
|
|
332
403
|
unfiltered?: boolean;
|
|
333
404
|
}): Promise<readonly LlmModelInfo[]>;
|
|
405
|
+
/**
|
|
406
|
+
* The per-model allowance bracket this account POOL falls into, or undefined
|
|
407
|
+
* when there is nothing honest to show.
|
|
408
|
+
*
|
|
409
|
+
* The pricing page publishes a per-model monthly allowance for GOAT and Pro
|
|
410
|
+
* only — its own words are "the boost is a per-model allowance, so it lives on
|
|
411
|
+
* the plans that have them" — so a pool whose highest plan is Go, Provider,
|
|
412
|
+
* Max or Ultra gets undefined rather than a neighbouring tier's figure. Taking
|
|
413
|
+
* the HIGHEST tier matches the question the picker already answers for a pool
|
|
414
|
+
* (see `modelVisibleForAnyAccount`): what the user can reach, not what the one
|
|
415
|
+
* account serving this request happens to be. The fail-open shape is the same
|
|
416
|
+
* too — an unreachable billing endpoint yields undefined, which hides the
|
|
417
|
+
* allowance instead of inventing one.
|
|
418
|
+
*/
|
|
419
|
+
allowanceTier(): Promise<'goat' | 'pro' | undefined>;
|
|
334
420
|
resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
|
|
335
421
|
/** The headers every authenticated account endpoint shares. */
|
|
336
422
|
private accountHeaders;
|
|
337
423
|
/**
|
|
338
|
-
* Fetch one
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
* back without a record; only a fetch failure propagates to the caller.
|
|
424
|
+
* Fetch one JSON GET and return its HTTP status with a parsed record. The
|
|
425
|
+
* catalog, billing probe, and usage report each apply their own failure
|
|
426
|
+
* policy. Non-2xx and invalid JSON bodies come back without a record; only
|
|
427
|
+
* a fetch failure propagates to the caller.
|
|
343
428
|
*
|
|
344
|
-
* `timeoutMs` is the caller's budget
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* account query is not held to a stricter (and invisible) limit than chat.
|
|
429
|
+
* `timeoutMs` is the caller's budget, unless it provides its own signal.
|
|
430
|
+
* The usage report passes the connection's request budget rather than the
|
|
431
|
+
* catalog/picker's shorter default.
|
|
348
432
|
*/
|
|
349
|
-
private
|
|
433
|
+
private fetchJson;
|
|
350
434
|
/**
|
|
351
435
|
* Every account's billing facts behind the picker's plan filter, in the
|
|
352
436
|
* pool's rotation order and cached per key for {@link BILLING_ACCESS_TTL_MS}
|
|
@@ -354,9 +438,6 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
354
438
|
* per picker load). `undefined` means the filter cannot be evaluated at all
|
|
355
439
|
* — no key resolved — which {@link modelVisibleForAnyAccount} reads as
|
|
356
440
|
* "show everything".
|
|
357
|
-
*
|
|
358
|
-
* The serving account is only the first entry: with several accounts the
|
|
359
|
-
* model list must not depend on which of them rotation happens to be using.
|
|
360
441
|
*/
|
|
361
442
|
private loadPoolBillingAccess;
|
|
362
443
|
/**
|
|
@@ -401,10 +482,9 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
401
482
|
* but a hard refusal. `/alpha/generate` routes every one of them, so this
|
|
402
483
|
* costs nothing.
|
|
403
484
|
*
|
|
404
|
-
* That decision is deliberately NOT written to `protocolCache
|
|
405
|
-
* keyed by API key alone
|
|
406
|
-
*
|
|
407
|
-
* which the Provider API serves correctly — off it until the entry expired.
|
|
485
|
+
* That decision is deliberately NOT written to `protocolCache`, which is
|
|
486
|
+
* keyed by API key alone: remembering it would pin the whole ACCOUNT to the
|
|
487
|
+
* CLI transport and drag every other model off it until the entry expired.
|
|
408
488
|
*/
|
|
409
489
|
private resolveProtocol;
|
|
410
490
|
/**
|
|
@@ -418,18 +498,14 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
418
498
|
* the default resolves the currently active account.
|
|
419
499
|
*
|
|
420
500
|
* Two failure modes are NOT "the network is down", and the report must say
|
|
421
|
-
* so rather than let {@link classifyTotalFailure} blame the connection:
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
* (`connection.requestTimeoutMs`, default 60 s), not the catalog's 10 s
|
|
430
|
-
* probe budget: on a slow link a 10 s cap made every account query time
|
|
431
|
-
* out while chat kept working, which is exactly a "check your network"
|
|
432
|
-
* banner that never clears.
|
|
501
|
+
* so rather than let {@link classifyTotalFailure} blame the connection: a
|
|
502
|
+
* key that no HTTP header can carry (a stray newline from a paste, a
|
|
503
|
+
* full-width character) makes `fetch` throw a `TypeError` before any I/O,
|
|
504
|
+
* for every endpoint at once, so this path runs `assertUsableApiKey` too and
|
|
505
|
+
* answers `blocked: 'invalid-key'`; and the four endpoints get the SAME
|
|
506
|
+
* per-request budget as a chat call (`connection.requestTimeoutMs`, default
|
|
507
|
+
* 60 s), not the catalog's 10 s probe budget, because on a slow link a 10 s
|
|
508
|
+
* cap made every account query time out while chat kept working.
|
|
433
509
|
*/
|
|
434
510
|
getUsage(apiKey?: string): Promise<CommandCodeUsageReport>;
|
|
435
511
|
/**
|
|
@@ -443,17 +519,16 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
443
519
|
* the same time (the two are metered separately), and reading only the
|
|
444
520
|
* shorter one revived such an account as "usable" — the pool then handed it
|
|
445
521
|
* out, the provider rejected the request again, and the next all-marked pass
|
|
446
|
-
* revived it once more
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
522
|
+
* revived it once more (issue #51's follow-up: "切到一个不可用账号").
|
|
523
|
+
* `exceeded` is therefore true when ANY published window is exceeded, and
|
|
524
|
+
* `resetAt` is the LATEST reset among the exceeded ones — the binding
|
|
525
|
+
* constraint, because a clear five-hour window buys nothing while the weekly
|
|
526
|
+
* quota is spent.
|
|
451
527
|
*
|
|
452
528
|
* Returns `undefined` when the probe itself failed (transport, non-200, or a
|
|
453
529
|
* payload with no window limits at all) — a failed probe never changes pool
|
|
454
|
-
* state. The
|
|
455
|
-
*
|
|
456
|
-
* time, and the server remains the final gate on them.
|
|
530
|
+
* state. The credit balances are deliberately NOT part of this answer: they
|
|
531
|
+
* carry no reset time, and the server remains the final gate on them.
|
|
457
532
|
*/
|
|
458
533
|
probeWindowLimits(apiKey: string): Promise<{
|
|
459
534
|
exceeded: boolean;
|
|
@@ -486,18 +561,17 @@ interface CommandCodeAccountSlot {
|
|
|
486
561
|
allowAuthFile: boolean;
|
|
487
562
|
}
|
|
488
563
|
/**
|
|
489
|
-
* Why a key stopped serving requests
|
|
564
|
+
* Why a key stopped serving requests, split by EVIDENCE — what the pool may
|
|
565
|
+
* claim about it — rather than by what it does.
|
|
490
566
|
*
|
|
491
567
|
* `rate-limit` is a USAGE-WINDOW rejection: the provider named one of its
|
|
492
568
|
* metered windows (`error.rateLimit.window`, or a message saying the plan's
|
|
493
569
|
* usage limit was reached — the only two shapes the official CLI's own
|
|
494
|
-
* `parseWindowLimitError`/`resolveWindowLabel` accept). `throttled` is the
|
|
495
|
-
*
|
|
496
|
-
* window, so the
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
* while the turn failed with "all 1 Command Code account(s) have exhausted
|
|
500
|
-
* their usage window".
|
|
570
|
+
* `parseWindowLimitError`/`resolveWindowLabel` accept). `throttled` is the plain
|
|
571
|
+
* 429: the key leaves rotation for now, but the provider said nothing about a
|
|
572
|
+
* window, so the pool must not describe one as exhausted. Collapsing the two is
|
|
573
|
+
* issue #54: a bare 429 was reported as a spent window while the account card
|
|
574
|
+
* showed both windows barely used.
|
|
501
575
|
*/
|
|
502
576
|
type AccountRejection = 'rate-limit' | 'throttled' | 'invalid-credential';
|
|
503
577
|
/** One key's rotation state. */
|
|
@@ -510,11 +584,11 @@ interface CommandCodeAccountState {
|
|
|
510
584
|
/** Marked by a 401: skipped until the stored credential changes. */
|
|
511
585
|
'disabled';
|
|
512
586
|
/**
|
|
513
|
-
* The evidence behind the mark — what the pool may CLAIM when it reports
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
587
|
+
* The evidence behind the mark — what the pool may CLAIM when it reports that
|
|
588
|
+
* no account can serve. `window`: the provider named a usage window, or a
|
|
589
|
+
* `/alpha/billing/credits` probe read one as exceeded. `throttle`: a 429 that
|
|
590
|
+
* said nothing about a window (a burst limiter, or a model-/spend-level limit
|
|
591
|
+
* the billing endpoint cannot show). `auth`: a 401.
|
|
518
592
|
*/
|
|
519
593
|
cause: 'window' | 'throttle' | 'auth';
|
|
520
594
|
/** Human-readable reason for the mark (e.g. `rate limited (429)`). */
|
|
@@ -547,43 +621,34 @@ interface CommandCodeAccountPoolDeps {
|
|
|
547
621
|
resolveRef(ref: CredentialRef): Promise<string | undefined>;
|
|
548
622
|
/** The official CLI auth-file key (`~/.commandcode/auth.json`); default slot only. */
|
|
549
623
|
authFileKey(): string | undefined;
|
|
550
|
-
/**
|
|
551
|
-
* Probe one key's usage windows — BOTH windows the endpoint publishes (the
|
|
552
|
-
* five-hour and the weekly one), not just the five-hour one; see
|
|
553
|
-
* {@link AccountWindowProbe}. Undefined when the probe itself failed.
|
|
554
|
-
*/
|
|
624
|
+
/** Probe one key's usage windows (BOTH windows the endpoint publishes); undefined when it failed. */
|
|
555
625
|
probeWindow(apiKey: string): Promise<AccountWindowProbe | undefined>;
|
|
556
626
|
/**
|
|
557
|
-
* The manually selected account
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
* the fallback lasts only as long as the window really is exceeded.
|
|
627
|
+
* The manually selected account slot id, re-read per resolution. It serves
|
|
628
|
+
* whenever it is usable; an unknown id or an exhausted preferred account falls
|
|
629
|
+
* back to the first usable slot — and an exhausted one is re-probed on the way
|
|
630
|
+
* (see {@link CommandCodeAccountPool.resolveKey}), so the fallback lasts only
|
|
631
|
+
* as long as the window really is exceeded.
|
|
563
632
|
*/
|
|
564
633
|
preferredId?(): string | undefined;
|
|
565
634
|
/**
|
|
566
635
|
* Model → account routing rules, re-read per resolution so settings changes
|
|
567
|
-
* apply live.
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
* before the preferred/rotation selection; an unusable routed account falls
|
|
571
|
-
* back to the normal selection (the router is a hint, never a hard gate).
|
|
636
|
+
* apply live. A matching, usable routed account serves before the
|
|
637
|
+
* preferred/rotation selection; an unusable one falls back to the normal
|
|
638
|
+
* selection — the router is a hint, never a hard gate.
|
|
572
639
|
*/
|
|
573
640
|
modelAccountRules?(): readonly CommandCodeModelAccountRule[];
|
|
574
641
|
/**
|
|
575
|
-
* Clock seam for the explicit-account probe throttle
|
|
576
|
-
* "
|
|
577
|
-
*
|
|
578
|
-
* waiting a real minute; production reads `Date.now()`.
|
|
642
|
+
* Clock seam for the explicit-account probe throttle, so the "the interval
|
|
643
|
+
* elapsed" half of {@link CommandCodeAccountPool.canProbeExplicit} is testable
|
|
644
|
+
* without waiting a real minute. Production reads `Date.now()`.
|
|
579
645
|
*/
|
|
580
646
|
now?(): number;
|
|
581
647
|
}
|
|
582
648
|
/**
|
|
583
649
|
* One "route these models to that account" rule. `models` lists catalog ids
|
|
584
|
-
* (`deepseek/deepseek-v4-pro`, …); `account` is a slot id (`default` or an
|
|
585
|
-
*
|
|
586
|
-
* list routes to that account. The first matching rule in list order wins.
|
|
650
|
+
* (`deepseek/deepseek-v4-pro`, …); `account` is a slot id (`default` or an extra
|
|
651
|
+
* account's credential reference). The first matching rule in list order wins.
|
|
587
652
|
*/
|
|
588
653
|
interface CommandCodeModelAccountRule {
|
|
589
654
|
/** Catalog model ids to match against the request's model. */
|
|
@@ -599,10 +664,10 @@ interface CommandCodeModelAccountRule {
|
|
|
599
664
|
*/
|
|
600
665
|
declare function accountUsable(state: CommandCodeAccountState | undefined): boolean;
|
|
601
666
|
/**
|
|
602
|
-
* Pick the account that should serve now: the manually preferred slot when it
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
667
|
+
* Pick the account that should serve now: the manually preferred slot when it is
|
|
668
|
+
* usable, otherwise the first usable account in rotation order; undefined when
|
|
669
|
+
* no account is usable. Shared by the pool (request path) and the plugin entry
|
|
670
|
+
* (the usage view's active badge) so both always agree.
|
|
606
671
|
*/
|
|
607
672
|
declare function selectActiveAccount(accounts: readonly ResolvedAccount[], preferredId: string | undefined): ResolvedAccount | undefined;
|
|
608
673
|
/**
|
|
@@ -643,27 +708,18 @@ declare class CommandCodeAccountPool {
|
|
|
643
708
|
*/
|
|
644
709
|
describeAccounts(): Promise<ResolvedAccount[]>;
|
|
645
710
|
/**
|
|
646
|
-
* Hand out the key for a request: the model-routed account when
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
* `
|
|
652
|
-
* `INVALID_CREDENTIAL` when accounts exist but none can serve.
|
|
653
|
-
*
|
|
654
|
-
* `options.model` is the request's model id; routing rules re-read per
|
|
655
|
-
* resolution, so a settings change applies live.
|
|
656
|
-
*
|
|
657
|
-
* `options.tried` lists the keys this request has already used — the
|
|
658
|
-
* just-rejected one included. They are removed from the resolution entirely,
|
|
659
|
-
* which is what lets one request walk a four-account pool: an account-scoped
|
|
660
|
-
* rejection that does not mark the key (no credits, a model outside the
|
|
661
|
-
* account's plan) would otherwise be offered again on every attempt, and the
|
|
662
|
-
* accounts behind it would never be reached.
|
|
711
|
+
* Hand out the key for a request: the model-routed account when usable, else
|
|
712
|
+
* the manually preferred account when usable, else the first usable account
|
|
713
|
+
* in rotation order. Returns `undefined` when no account resolves any key,
|
|
714
|
+
* or when an account this request already used is still UNMARKED — the
|
|
715
|
+
* caller's own rejection is the honest answer then. Throws `RATE_LIMIT` /
|
|
716
|
+
* `INVALID_CREDENTIAL` when every account is marked.
|
|
663
717
|
*
|
|
664
|
-
*
|
|
665
|
-
*
|
|
666
|
-
*
|
|
718
|
+
* `options.tried` lists the keys this request already used; they are removed
|
|
719
|
+
* from the resolution entirely, which is what lets one request walk a
|
|
720
|
+
* four-account pool. An explicit selection (pin or model rule) that a
|
|
721
|
+
* rate-limit mark would demote is probed first, so a fallback never becomes
|
|
722
|
+
* permanent (issue #51). Rules re-read per resolution, so settings apply live.
|
|
667
723
|
*/
|
|
668
724
|
resolveKey(options?: {
|
|
669
725
|
tried?: readonly string[];
|
|
@@ -673,53 +729,46 @@ declare class CommandCodeAccountPool {
|
|
|
673
729
|
slot: CommandCodeAccountSlot;
|
|
674
730
|
} | undefined>;
|
|
675
731
|
/**
|
|
676
|
-
* Record a rejection against one key. `
|
|
677
|
-
*
|
|
678
|
-
*
|
|
679
|
-
*
|
|
680
|
-
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
* (`invalid-credential`) disables the key until the stored credential
|
|
732
|
+
* Record a rejection against one key. A `throttled` rejection (the plain 429
|
|
733
|
+
* that named no window) marks the key with the `throttle` cause, leaving
|
|
734
|
+
* rotation exactly like a window mark but keeping the pool's own diagnosis at
|
|
735
|
+
* "rate limited" rather than inventing an exhausted window. `rate-limit`
|
|
736
|
+
* marks a `cooldown` until `resetAtMs` when the body named the provider's own
|
|
737
|
+
* reset, otherwise an `unknown` mark whose window is probed lazily.
|
|
738
|
+
* `invalid-credential` (401) disables the key until the stored credential
|
|
684
739
|
* changes.
|
|
685
740
|
*
|
|
686
|
-
* `resetAtMs` is seconds-to-millis converted by the adapter from
|
|
687
|
-
*
|
|
688
|
-
*
|
|
689
|
-
* provider said. It only applies to a window mark; a plain throttle keeps the
|
|
690
|
-
* window unknown on purpose, so a probe can still find out.
|
|
741
|
+
* `resetAtMs` is seconds-to-millis converted by the adapter from
|
|
742
|
+
* `error.rateLimit.reset`; it applies to a window mark only. A plain throttle
|
|
743
|
+
* keeps its window unknown on purpose, so a probe can still find out.
|
|
691
744
|
*/
|
|
692
745
|
markRejected(apiKey: string, rejection: AccountRejection, resetAtMs?: number): void;
|
|
693
746
|
/**
|
|
694
747
|
* One account's key: literal → credential seam → auth file (default slot).
|
|
695
748
|
*
|
|
696
749
|
* Every source is normalized here, at the single point where a slot's key
|
|
697
|
-
* enters the pool. The adapter sends the key through
|
|
698
|
-
* `assertUsableApiKey()`, which trims it
|
|
699
|
-
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
* no mark, and the usage endpoints would 401 while chat kept working.
|
|
704
|
-
* Normalizing once makes resolution, probing, marking, and the request path
|
|
705
|
-
* agree on one string.
|
|
750
|
+
* enters the pool. The adapter sends the key through
|
|
751
|
+
* `assertUsableApiKey()`, which trims it, and reports that trimmed form back
|
|
752
|
+
* to {@link markRejected}: returning the raw value would file every 429/401
|
|
753
|
+
* mark under a key no later lookup can find — rotation would re-offer the same
|
|
754
|
+
* account, the account card would show no mark, and the usage endpoints would
|
|
755
|
+
* 401 while chat kept working.
|
|
706
756
|
*/
|
|
707
757
|
private resolveSlotKey;
|
|
708
758
|
/**
|
|
709
|
-
* The account the user explicitly asked for: the slot a model rule routes
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
*
|
|
713
|
-
* {@link
|
|
714
|
-
* usable, which is exactly what {@link resolveKey} re-probes.
|
|
759
|
+
* The account the user explicitly asked for: the slot a model rule routes the
|
|
760
|
+
* request to when that id exists among the resolved slots, else the manually
|
|
761
|
+
* pinned slot. Consulted only on the fallback path, so — unlike
|
|
762
|
+
* {@link selectAccountForModel} — it does NOT require the account to be usable,
|
|
763
|
+
* which is exactly what {@link resolveKey} re-probes.
|
|
715
764
|
*/
|
|
716
765
|
private explicitAccount;
|
|
717
766
|
/**
|
|
718
767
|
* Whether an explicitly selected account's mark is due for a window probe.
|
|
719
768
|
* Only an `unknown` mark (a 429 whose reset was never learned) is worth
|
|
720
|
-
* re-probing: a `cooldown`
|
|
721
|
-
*
|
|
722
|
-
*
|
|
769
|
+
* re-probing: a `cooldown` carries its reset and expires by itself, and a
|
|
770
|
+
* `disabled` (401) key stays out until the stored credential changes. The
|
|
771
|
+
* interval bounds a probe endpoint that keeps failing.
|
|
723
772
|
*/
|
|
724
773
|
private canProbeExplicit;
|
|
725
774
|
/** The clock the probe throttle reads; injected so a test can travel in time. */
|
|
@@ -727,49 +776,32 @@ declare class CommandCodeAccountPool {
|
|
|
727
776
|
/**
|
|
728
777
|
* Probe one explicitly selected account's window and apply the answer. A
|
|
729
778
|
* window that is no longer exceeded drops the mark, so the user's own
|
|
730
|
-
* selection serves again on this very request
|
|
731
|
-
*
|
|
779
|
+
* selection serves again on this very request; an exceeded one is stamped as
|
|
780
|
+
* a cooldown carrying the provider's reset time, after which
|
|
732
781
|
* {@link accountUsable} lets the account back in with no further probe. A
|
|
733
782
|
* probe that fails changes nothing: the mark stays `unknown` and the next
|
|
734
783
|
* attempt waits out the interval.
|
|
735
784
|
*/
|
|
736
785
|
private probeExplicit;
|
|
786
|
+
/**
|
|
787
|
+
* Stamp a probe-read window onto one key. A known reset becomes a cooldown
|
|
788
|
+
* that expires by itself; without one the mark stays `unknown`, so a later
|
|
789
|
+
* probe can still learn it — and a mark that already carries a cooldown
|
|
790
|
+
* keeps it, never trading a known reset for an unknown one. The cause is
|
|
791
|
+
* `window` either way: a probe that read a window as exceeded IS window
|
|
792
|
+
* evidence, whatever the key was marked for. An `until: 0` cooldown would
|
|
793
|
+
* read as "never usable again" to {@link accountUsable}, so `unknown` it is.
|
|
794
|
+
*/
|
|
795
|
+
private stampWindowMark;
|
|
737
796
|
/** Hand out the chosen account's key. */
|
|
738
797
|
private pick;
|
|
739
798
|
}
|
|
740
799
|
//#endregion
|
|
741
|
-
//#region src/
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
* level is the probability every verdict must reach before the guard grants
|
|
745
|
-
* `allowed-once`; a higher level approves less, on stronger evidence. Three
|
|
746
|
-
* presets replace a free-form probability because the useful range is narrow
|
|
747
|
-
* and a hand-typed 0.6 silently turns the guard into a rubber stamp.
|
|
748
|
-
*/
|
|
749
|
-
type CommandGuardLevel = 'high' | 'medium' | 'low';
|
|
800
|
+
//#region src/plan-tiers.d.ts
|
|
801
|
+
declare const PLAN_LABELS: Readonly<Record<string, string>>;
|
|
802
|
+
declare const PLAN_ORDER: Readonly<Record<string, number>>;
|
|
750
803
|
//#endregion
|
|
751
804
|
//#region src/capabilities.d.ts
|
|
752
|
-
/**
|
|
753
|
-
* Static capability snapshot for the Command Code provider: model →
|
|
754
|
-
* reasoning-effort levels, vision/thinking flags, model → minimum plan tier,
|
|
755
|
-
* subscription-plan labels, deals, and hourly (peak/off-peak) pricing.
|
|
756
|
-
*
|
|
757
|
-
* Everything in this module is synced from official sources (the command-code
|
|
758
|
-
* CLI bundle's model table and the official plan/pricing/model docs — see the
|
|
759
|
-
* dsh-commandcode-upstream skill for the exact extraction procedures), and
|
|
760
|
-
* changes whenever an upstream CLI release reshuffles models/plans/prices.
|
|
761
|
-
* Keeping the snapshot in its own module confines those frequent sync diffs
|
|
762
|
-
* here: src/adapter.ts holds only the stable wire/runtime logic and imports
|
|
763
|
-
* these tables + read helpers.
|
|
764
|
-
*
|
|
765
|
-
* Snapshot read helpers (planLabel, dealLabel, formatContext,
|
|
766
|
-
* capabilityDescription, peakPricing*, compareByPlan, modelVisibleInPlan,
|
|
767
|
-
* subscriptionPlanInfo, isFreeModel) live here too — they exist only to read
|
|
768
|
-
* the tables, so a sync never has to touch src/adapter.ts.
|
|
769
|
-
*
|
|
770
|
-
* Ported from pi-commandcode-provider (MIT); originally part of src/adapter.ts
|
|
771
|
-
* and split out so upstream syncs stay reviewable.
|
|
772
|
-
*/
|
|
773
805
|
declare const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>>;
|
|
774
806
|
/**
|
|
775
807
|
* Models whose Capabilities include Vision, per the official Command Code
|
|
@@ -789,20 +821,23 @@ declare const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>>;
|
|
|
789
821
|
declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
|
|
790
822
|
/**
|
|
791
823
|
* Models WITHOUT a zero-data-retention upstream, per the official CLI's own
|
|
792
|
-
* registry (`command-code@1.
|
|
793
|
-
*
|
|
794
|
-
*
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
824
|
+
* registry (`command-code@1.68.0` `dist/cli.mjs`): `modelSupportsZdr(id)` is
|
|
825
|
+
* exactly `!nonZdrSet.has(canonicalize(id))`, and `knownModelSupportsZdr`
|
|
826
|
+
* carries the same membership in the sibling route table — the UNION of both
|
|
827
|
+
* is this set. Reading only the sibling route table would drop `meituan/
|
|
828
|
+
* LongCat-2.0`, which appears in `modelSupportsZdr` alone (re-read from the
|
|
829
|
+
* 1.66.0 / 1.67.0 / 1.68.0 artifacts on 2026-09-29: the two stealth-preview
|
|
830
|
+
* rows sit in BOTH sets, so LongCat is the only divergence). The official docs (commandcode.ai/docs/resources/
|
|
831
|
+
* zdr) put it in prose — "99% of our models have ZDR-capable upstreams … only
|
|
832
|
+
* a small handful of models are affected" — so the CLI's exclusion list is
|
|
833
|
+
* the only per-model evidence there is; a ZDR request naming one of these
|
|
834
|
+
* fails with HTTP 422 `cmd_zdr_no_providers` instead of routing through a
|
|
835
|
+
* provider that retains.
|
|
801
836
|
*
|
|
802
837
|
* Why a NEGATIVE set, and why "not listed" answers TRUE: 99% of the catalog is
|
|
803
838
|
* covered, so the maintained difference is the exception list. This helper is
|
|
804
839
|
* informational; the adapter sends the ZDR header for EVERY request when the
|
|
805
|
-
* switch is on
|
|
840
|
+
* switch is on — the provider remains the routing authority and refuses an
|
|
806
841
|
* unsupported model rather than silently dropping the privacy guarantee.
|
|
807
842
|
*
|
|
808
843
|
* `minimax/minimax-m3-free` is the one entry the public catalog
|
|
@@ -813,16 +848,11 @@ declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
|
|
|
813
848
|
* Keep in sync via the dsh-commandcode-upstream skill: the CLI's registry data
|
|
814
849
|
* (its `zdr:{only:[…]}` provider routes and the per-provider `zdr`/`noTraining`
|
|
815
850
|
* flags) is upstream-internal routing, not a per-model contract, so this table
|
|
816
|
-
* is the snapshot of the exclusion set and nothing more.
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
820
|
-
*
|
|
821
|
-
* joins (`stealth/space-bunny-alpha`), and it is in both anchors. `meituan/
|
|
822
|
-
* LongCat-2.0` is the one member the two anchors disagree about (it is in
|
|
823
|
-
* `modelSupportsZdr`'s set in both releases and in neither `knownModelSupportsZdr`
|
|
824
|
-
* set), so the union is
|
|
825
|
-
* what this table follows; reading only the sibling route table would drop it.
|
|
851
|
+
* is the snapshot of the exclusion set and nothing more. It is a rare change:
|
|
852
|
+
* 20 members held across 1.62.0 → 1.64.0, 1.65.0 and 1.66.0 each added exactly
|
|
853
|
+
* one (the two stealth-preview models below), 1.67.0 added one
|
|
854
|
+
* (`deepseek/deepseek-v4.1-flash-fast`), and 1.68.0 changed nothing — 23
|
|
855
|
+
* members as of 2026-09-29.
|
|
826
856
|
*/
|
|
827
857
|
declare const KNOWN_NON_ZDR_MODELS: ReadonlySet<string>;
|
|
828
858
|
/**
|
|
@@ -832,65 +862,30 @@ declare const KNOWN_NON_ZDR_MODELS: ReadonlySet<string>;
|
|
|
832
862
|
*/
|
|
833
863
|
declare function supportsZeroDataRetention(modelId: string): boolean;
|
|
834
864
|
/**
|
|
835
|
-
* Models the official CLI's model table
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
*
|
|
840
|
-
*
|
|
841
|
-
* description — it exists for programmatic consumers.
|
|
865
|
+
* Models the official CLI's model table marks `reasoning:!0` but defines no
|
|
866
|
+
* selectable `reasoning_effort` levels — they think automatically, with
|
|
867
|
+
* Command Code driving the depth. `KNOWN_EFFORTS` (which mirrors the CLI's
|
|
868
|
+
* effort map exactly) stays the sole source for selectable effort levels, and
|
|
869
|
+
* this snapshot is not surfaced in the picker's compact description — it exists
|
|
870
|
+
* for programmatic consumers.
|
|
842
871
|
*
|
|
843
|
-
* Source: the
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*
|
|
847
|
-
*
|
|
848
|
-
* joined this set in command-code@1.37.0 — reasoning:!0, no efforts, 1M
|
|
849
|
-
* context, routed through OpenRouter — then gained selectable
|
|
850
|
-
* `['low', 'medium', 'high']` efforts in command-code@1.38.0 and moved to
|
|
851
|
-
* `KNOWN_EFFORTS`. `moonshotai/Kimi-K3` followed the same path in
|
|
852
|
-
* command-code@1.39.3 — it gained `['low', 'high', 'max']` efforts and moved
|
|
853
|
-
* to `KNOWN_EFFORTS`. command-code@1.42.0 added LongCat 2.0 (then
|
|
854
|
-
* `meituan/LongCat-2.0:free`, now the paid `meituan/LongCat-2.0`; reasoning:!0,
|
|
855
|
-
* no efforts). command-code@1.45.0 gave the Muse Spark family
|
|
856
|
-
* (1.1, 1.2, 1.2-contributor, 1.3, 1.3-contributor) selectable
|
|
857
|
-
* `['low', 'medium', 'high', 'xhigh']` efforts — they moved to `KNOWN_EFFORTS`.
|
|
858
|
-
* command-code@1.51.3 gave `MiniMaxAI/MiniMax-M3` selectable
|
|
859
|
-
* `['low', 'medium', 'high']` efforts — it moved to `KNOWN_EFFORTS` too.
|
|
860
|
-
* command-code@1.52.0 added `inclusionai/ling-3.0-flash-sante:free`
|
|
861
|
-
* (reasoning:!0, no efforts).)
|
|
862
|
-
* command-code@1.53.0 added `deepseek/deepseek-v4.1-flash` with selectable
|
|
863
|
-
* ['low', 'high', 'max'] efforts, so it lives in `KNOWN_EFFORTS`, not here.)
|
|
864
|
-
* Keep in sync via the dsh-commandcode-upstream skill.
|
|
872
|
+
* Source: the bundled model table (dist/cli.mjs), cross-checked with
|
|
873
|
+
* https://commandcode.ai/docs/reference/cli/models. Keep in sync via the
|
|
874
|
+
* dsh-commandcode-upstream skill; a model that GAINS selectable efforts leaves
|
|
875
|
+
* this set for `KNOWN_EFFORTS` (Tencent Hy4 Preview, Kimi K3, the Muse Spark
|
|
876
|
+
* family and MiniMax M3 all took that path).
|
|
865
877
|
*/
|
|
866
878
|
declare const KNOWN_THINKING_MODELS: ReadonlySet<string>;
|
|
867
879
|
/**
|
|
868
880
|
* The minimum subscription plan a model is included in, per the official plan
|
|
869
|
-
* pages (`/docs/plans/go`, `/docs/plans/goat`, `/docs/plans/pro`,
|
|
870
|
-
* and `/docs/resources/pricing-limits`). Each plan's model
|
|
871
|
-
* the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max.
|
|
872
|
-
* plan list (Claude Opus/Fable, Fugu Ultra) are
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
876
|
-
*
|
|
877
|
-
* command-code@1.41.0 added `Qwen/Qwen3.8-Max-0902` (Go) and 1.42.0 added
|
|
878
|
-
* LongCat 2.0 (Go — a free promo until 2026-09-19, when the backend renamed
|
|
879
|
-
* `meituan/LongCat-2.0:free` to the paid `meituan/LongCat-2.0`); 1.43.0 added
|
|
880
|
-
* `google/gemini-3.8-flash` (GOAT) and 1.44.0 added `meta/muse-spark-1.3`
|
|
881
|
-
* (GOAT) plus its Contributor sibling (Go); command-code@1.52.0 added the
|
|
882
|
-
* free `inclusionai/ling-3.0-flash-sante:free` (Go); command-code@1.53.0
|
|
883
|
-
* added `deepseek/deepseek-v4.1-flash` (Go); command-code@1.56.0 added
|
|
884
|
-
* `Qwen/Qwen3.8-Omni-Flash` (Go); command-code@1.57.0 added
|
|
885
|
-
* `z-ai/glm-5.3-flashx` (Go); command-code@1.59.0 added `xai/grok-4.7` (GOAT)
|
|
886
|
-
* and 1.60.0 added `stepfun/Step-5-Preview` (Go); command-code@1.62.0 added the
|
|
887
|
-
* MiMo V2.6 family — `xiaomi/mimo-v2.6-flash` + `xiaomi/mimo-v2.6-pro` (Go) and
|
|
888
|
-
* `xiaomi/mimo-v2.6-pro-ultraspeed` (GOAT) — so the 1.58.0 -> 1.62.0 window's
|
|
889
|
-
* only tier changes are additions and the superset chain still holds. The
|
|
890
|
-
* 1.62.0 -> 1.65.0 window continues the pattern: 1.64.0 added
|
|
891
|
-
* `claude-opus-5-5` (Provider/Max), `gpt-6-sol` (Pro) and `gpt-6-luna` (Go),
|
|
892
|
-
* and 1.65.0 added `stealth/space-bunny-alpha` (Go, every tier) — additions
|
|
893
|
-
* only, no tier moves.
|
|
881
|
+
* pages (`/docs/plans/go`, `/docs/plans/goat`, `/docs/plans/pro`,
|
|
882
|
+
* `/docs/plans/max` and `/docs/resources/pricing-limits`). Each plan's model
|
|
883
|
+
* list is a superset of the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max.
|
|
884
|
+
* Models absent from every plan list (Claude Opus/Fable, Fugu Ultra) are
|
|
885
|
+
* Provider-tier. Re-verified at command-code@1.68.0 (2026-09-29): 84 catalog
|
|
886
|
+
* ids at 53/62/76/84 cumulative, a strict superset chain — every release since
|
|
887
|
+
* 1.49.0 has been additive with no tier move, and per-entry tags below name the
|
|
888
|
+
* release that added each row.
|
|
894
889
|
*
|
|
895
890
|
* The Provider API exposes no plan metadata, so this snapshot is the source of
|
|
896
891
|
* truth for the picker's plan annotation — it answers "which plan do I need to
|
|
@@ -901,13 +896,6 @@ declare const KNOWN_THINKING_MODELS: ReadonlySet<string>;
|
|
|
901
896
|
* dsh-commandcode-upstream skill).
|
|
902
897
|
*/
|
|
903
898
|
declare const KNOWN_PLANS: Readonly<Record<string, string>>;
|
|
904
|
-
/** Official display labels for each plan tier. */
|
|
905
|
-
declare const PLAN_LABELS: Readonly<Record<string, string>>;
|
|
906
|
-
/**
|
|
907
|
-
* Plan-tier sort weights, low to high. Models outside the snapshot (unknown
|
|
908
|
-
* plans) sort after every known tier, keeping known models predictable.
|
|
909
|
-
*/
|
|
910
|
-
declare const PLAN_ORDER: Readonly<Record<string, number>>;
|
|
911
899
|
/**
|
|
912
900
|
* Comparator for the model picker: free models first (zero credit cost, usable
|
|
913
901
|
* by every account), then by plan tier (lowest first), then by model name,
|
|
@@ -922,11 +910,11 @@ declare function compareByPlan(a: {
|
|
|
922
910
|
}): number;
|
|
923
911
|
/**
|
|
924
912
|
* Subscription plan table, synced from the official CLI bundle's plan maps
|
|
925
|
-
* (located by the `"individual-go"` key in
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
913
|
+
* (located by the `"individual-go"` key in `dist/cli.mjs`, re-verified unchanged
|
|
914
|
+
* through command-code@1.68.0): subscription `planId` prefix → display name and
|
|
915
|
+
* the plan's monthly credit total. This is the account's own subscription
|
|
916
|
+
* (from `/alpha/billing/subscriptions`) — distinct from {@link KNOWN_PLANS},
|
|
917
|
+
* which maps catalog models to their minimum tier.
|
|
930
918
|
*
|
|
931
919
|
* `tierWeight` is plugin-added (not from the CLI maps): the plan's rank on
|
|
932
920
|
* the {@link PLAN_ORDER} scale, used by the picker's plan filter
|
|
@@ -982,8 +970,13 @@ declare function modelVisibleInPlan(modelId: string, access: CommandCodeBillingA
|
|
|
982
970
|
* render time against `Date.now()`), the deal label is hidden until the
|
|
983
971
|
* snapshot is refreshed from the official page. `undefined` means
|
|
984
972
|
* "no expiry" (permanent).
|
|
985
|
-
* - `free` marks models whose requests cost no credits
|
|
986
|
-
*
|
|
973
|
+
* - `free` marks models whose requests cost no credits, shown as a `FREE`
|
|
974
|
+
* badge; it degrades to a plain discount once the deal lapses.
|
|
975
|
+
*
|
|
976
|
+
* A deal whose promo ENDS is removed here rather than left to lapse on
|
|
977
|
+
* `expiresAt`: the pricing page drops the entry, so a lapsed row would badge a
|
|
978
|
+
* model the catalog now serves at full price (Grok 4.7 reverts to $2.00 in /
|
|
979
|
+
* $6.00 out after its 2026-09-27 window).
|
|
987
980
|
*
|
|
988
981
|
* Keep in sync with the official pricing page when deals change (see the
|
|
989
982
|
* dsh-commandcode-upstream skill).
|
|
@@ -1003,24 +996,11 @@ declare const KNOWN_DEALS: Readonly<Record<string, KnownDeal>>;
|
|
|
1003
996
|
* charges by the hour: peak hours are 01:00–04:00 and 06:00–10:00 UTC (7h per
|
|
1004
997
|
* weekday, full price) **Monday to Friday only**; the other 17 hours of a
|
|
1005
998
|
* weekday and every hour of Saturday/Sunday (UTC) are off-peak at half price.
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
* The picker shows the
|
|
1012
|
-
* *current* state as a compact
|
|
1013
|
-
* label (`Peak`/`Half`) matching the English noun style of the other markers
|
|
1014
|
-
* (`Image`, `FREE`), so a developer can tell at a glance whether calling the
|
|
1015
|
-
* model right now is cheap or expensive.
|
|
1016
|
-
*
|
|
1017
|
-
* Authoritative extraction: the pricing page embeds a model JSON array whose
|
|
1018
|
-
* hourly-priced entries carry a `timeOfDay` block
|
|
1019
|
-
* (`{ windows: "01–04 & 06–10 UTC, Mon–Fri", peakHoursPerDay: 7,
|
|
1020
|
-
* offPeakHoursPerDay: 17, peak: {...}, offPeak: {...} }`). Exactly four models
|
|
1021
|
-
* carry it: V4 Pro, V4 Flash, V4 Flash Vision (exp), and V4.1 Flash (added in
|
|
1022
|
-
* command-code@1.53.0 at $0.15/$0.60 off-peak, $0.30/$1.20 peak — the same
|
|
1023
|
-
* schedule as the other three).
|
|
999
|
+
* Exactly five models carry the page's `timeOfDay` block (the five rows below).
|
|
1000
|
+
* The picker shows the *current* state as a compact label (`Peak`/`Half`)
|
|
1001
|
+
* matching the English noun style of the other markers (`Image`, `FREE`), so a
|
|
1002
|
+
* developer can tell at a glance whether calling the model right now is cheap
|
|
1003
|
+
* or expensive.
|
|
1024
1004
|
*
|
|
1025
1005
|
* Extraction caution: the rendered HTML rows are a trap. Each annotation div
|
|
1026
1006
|
* sits inside its OWN row's container, immediately before the NEXT row starts,
|
|
@@ -1028,18 +1008,19 @@ declare const KNOWN_DEALS: Readonly<Record<string, KnownDeal>>;
|
|
|
1028
1008
|
* to the model printed after it — that is how `deepseek/deepseek-v4-flash-fast`
|
|
1029
1009
|
* was wrongly added here (its row is flat-priced at $0.28/$0.56/$0.07 and has
|
|
1030
1010
|
* no `timeOfDay` block). Trust the embedded JSON's `timeOfDay` membership and
|
|
1031
|
-
* the 2× price relation, never the flat-text neighbor.
|
|
1011
|
+
* the 2× price relation, never the flat-text neighbor. A rate that is
|
|
1012
|
+
* internally consistent can still be the wrong row (the V4 Flash Vision (exp)
|
|
1013
|
+
* variant is priced from the page's own `timeOfDay` block, not from 2× its own
|
|
1014
|
+
* off-peak figures), which is why the vendored price table
|
|
1015
|
+
* (`./model-prices.ts`) is synced from the page and not hand-kept.
|
|
1032
1016
|
*
|
|
1033
1017
|
* Keep in sync with the official pricing page when the model set, the peak
|
|
1034
1018
|
* windows, or the weekday rule change (see the dsh-commandcode-upstream skill).
|
|
1035
1019
|
*/
|
|
1036
1020
|
declare const KNOWN_PEAK_PRICING: ReadonlySet<string>;
|
|
1037
1021
|
/**
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
* official rule charges Saturday and Sunday completely off-peak for all 24
|
|
1041
|
-
* hours, so a weekend timestamp is off-peak even inside `PEAK_HOUR_RANGES`.
|
|
1042
|
-
* `undefined` for models outside the snapshot.
|
|
1022
|
+
* As {@link isPeakPricingHour}, plus the {@link KNOWN_PEAK_PRICING} membership
|
|
1023
|
+
* test; `undefined` for models outside the snapshot.
|
|
1043
1024
|
*/
|
|
1044
1025
|
declare function peakPricingState(modelId: string, now?: number): 'peak' | 'off-peak' | undefined;
|
|
1045
1026
|
/**
|
|
@@ -1122,6 +1103,20 @@ interface CommandCodeCatalogModel {
|
|
|
1122
1103
|
* capability snapshot, so the Host stamps it per entry.
|
|
1123
1104
|
*/
|
|
1124
1105
|
tier?: string;
|
|
1106
|
+
/**
|
|
1107
|
+
* Per-model MONTHLY allowance in USD: how much of the plan's monthly credit
|
|
1108
|
+
* pool this one model may draw, already resolved by the Host against the
|
|
1109
|
+
* account pool's highest plan (the pricing page publishes an allowance for
|
|
1110
|
+
* GOAT and Pro only). Undefined when that plan has no published allowance
|
|
1111
|
+
* (Go, Provider, Max, Ultra) or when billing could not be read — the browser
|
|
1112
|
+
* shows nothing rather than guessing a neighbouring tier's figure.
|
|
1113
|
+
*
|
|
1114
|
+
* Deliberately a plain number and not the `{ goat, pro }` pair: the bracket is
|
|
1115
|
+
* a Host decision that already depends on facts the browser does not hold, and
|
|
1116
|
+
* shipping both figures would invite a second, divergent rule here. Note this
|
|
1117
|
+
* is dollars per MONTH, unlike every rate in `CommandCodePriceTable`.
|
|
1118
|
+
*/
|
|
1119
|
+
allowance?: number;
|
|
1125
1120
|
}
|
|
1126
1121
|
/** The model-catalog Remote result: the full catalog, sorted for picking. */
|
|
1127
1122
|
interface CommandCodeCatalog {
|
|
@@ -1193,19 +1188,16 @@ interface CommandCodePriceTable {
|
|
|
1193
1188
|
//#endregion
|
|
1194
1189
|
//#region src/command-locales.d.ts
|
|
1195
1190
|
/**
|
|
1196
|
-
*
|
|
1197
|
-
*
|
|
1198
|
-
*
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1201
|
-
* `pickCommandLocale()`. The image-gate wrapper also lives on the client
|
|
1202
|
-
* but is reached from a non-React path that has no `t` in scope, so the
|
|
1203
|
-
* same dictionaries serve both surfaces.
|
|
1191
|
+
* zh/en copy for the Host-side `/commandcode` usage command, as plain
|
|
1192
|
+
* constants: the command runs on the Host and has no access to the client's
|
|
1193
|
+
* `ctx.locale`, so the active locale is resolved by `pickCommandLocale()` and
|
|
1194
|
+
* the dictionaries are read by direct lookup. Distinct from
|
|
1195
|
+
* `./client/locales.ts` (the settings-page `settings.commandcode` namespace).
|
|
1204
1196
|
*
|
|
1205
|
-
* zh is the source of truth for the key set; en must carry the
|
|
1206
|
-
* keys
|
|
1197
|
+
* zh is the source of truth for the key set; `en` must carry exactly the same
|
|
1198
|
+
* keys, which the `Record` type makes a compile error.
|
|
1207
1199
|
*/
|
|
1208
|
-
/** Active locale id
|
|
1200
|
+
/** Active locale id for the `/commandcode` command. */
|
|
1209
1201
|
type LocaleId = 'zh' | 'en';
|
|
1210
1202
|
//#endregion
|
|
1211
1203
|
//#region src/commands.d.ts
|
|
@@ -1220,11 +1212,9 @@ interface CommandCodeCommandDeps<C extends CommandCodeConnectionOptions = Comman
|
|
|
1220
1212
|
*/
|
|
1221
1213
|
reports?: () => Promise<CommandCodeAccountsReport>;
|
|
1222
1214
|
/**
|
|
1223
|
-
* Resolve the active locale for one command run
|
|
1224
|
-
*
|
|
1225
|
-
*
|
|
1226
|
-
* with the default locale (`'zh'`) — historically the only language the
|
|
1227
|
-
* command ever shipped in.
|
|
1215
|
+
* Resolve the active locale for one command run; the plugin entry wires it
|
|
1216
|
+
* from `Config.lang` and the shell's `LC_ALL`/`LANG`. Absent (notably in
|
|
1217
|
+
* tests), the command renders with the default locale `'zh'`.
|
|
1228
1218
|
*/
|
|
1229
1219
|
getLocale?: () => LocaleId;
|
|
1230
1220
|
}
|
|
@@ -1286,9 +1276,9 @@ declare const loginStatusSchema: TypertSchema<CommandCodeLoginStatus>;
|
|
|
1286
1276
|
/**
|
|
1287
1277
|
* The browser-login face the usage service exposes (`commandcode/login*`).
|
|
1288
1278
|
* Backed by the Host-half {@link !CommandCodeLoginFlow} when the plugin entry
|
|
1289
|
-
* wired one; absent, `status`/`cancel` degrade to the idle status
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1279
|
+
* wired one; absent, `status`/`cancel` degrade to the idle status and `begin`
|
|
1280
|
+
* rejects with a plain message, so the page's manual paste path stays the
|
|
1281
|
+
* fallback instead of hanging.
|
|
1292
1282
|
*/
|
|
1293
1283
|
interface LoginFlowFacade {
|
|
1294
1284
|
/** Start (or rejoin) an attempt; rejects when it cannot start at all. */
|
|
@@ -1309,10 +1299,9 @@ interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandC
|
|
|
1309
1299
|
*/
|
|
1310
1300
|
reports?: () => Promise<CommandCodeAccountsReport>;
|
|
1311
1301
|
/**
|
|
1312
|
-
* Model-catalog source for the settings page's model editors
|
|
1313
|
-
*
|
|
1314
|
-
*
|
|
1315
|
-
* editors degrade to the empty state.
|
|
1302
|
+
* Model-catalog source for the settings page's model editors. Absent, the
|
|
1303
|
+
* `models` endpoint answers an empty list — the page's editors degrade to
|
|
1304
|
+
* the empty state.
|
|
1316
1305
|
*/
|
|
1317
1306
|
listModels?: () => Promise<CommandCodeCatalog>;
|
|
1318
1307
|
/**
|
|
@@ -1322,11 +1311,7 @@ interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandC
|
|
|
1322
1311
|
* only to stub it in a test.
|
|
1323
1312
|
*/
|
|
1324
1313
|
prices?: () => CommandCodePriceTable;
|
|
1325
|
-
/**
|
|
1326
|
-
* The browser-login flow (wired by the plugin entry). Absent means the
|
|
1327
|
-
* login endpoints answer `idle` / reject with a plain message — the page's
|
|
1328
|
-
* manual paste path stays the fallback.
|
|
1329
|
-
*/
|
|
1314
|
+
/** The browser-login flow (wired by the plugin entry); see {@link LoginFlowFacade}. */
|
|
1330
1315
|
login?: LoginFlowFacade;
|
|
1331
1316
|
}
|
|
1332
1317
|
/**
|
|
@@ -1340,34 +1325,30 @@ declare class CommandCodeUsageService<C extends CommandCodeConnectionOptions = C
|
|
|
1340
1325
|
private readonly deps;
|
|
1341
1326
|
constructor(ctx: Context, deps: CommandCodeUsageDeps<C>);
|
|
1342
1327
|
/**
|
|
1343
|
-
* Account, usage, and credit state for the settings page's account card
|
|
1344
|
-
*
|
|
1345
|
-
*
|
|
1346
|
-
*
|
|
1347
|
-
* `MISSING_CREDENTIAL` when no key resolves, which the Gateway folds into
|
|
1348
|
-
* the failure branch the page renders as a hint.
|
|
1328
|
+
* Account, usage, and credit state for the settings page's account card.
|
|
1329
|
+
* Degrades per endpoint like the `/commandcode` command (failures land in
|
|
1330
|
+
* `report.failures`); throws `MISSING_CREDENTIAL` when no key resolves, which
|
|
1331
|
+
* the Gateway folds into the failure branch the page renders as a hint.
|
|
1349
1332
|
*/
|
|
1350
1333
|
report(): Promise<CommandCodeAccountsReport>;
|
|
1351
1334
|
/**
|
|
1352
|
-
* The full model catalog for the settings page's model editors
|
|
1353
|
-
*
|
|
1354
|
-
*
|
|
1355
|
-
*
|
|
1356
|
-
* the live list instead of typed by hand.
|
|
1335
|
+
* The full model catalog for the settings page's model editors. The browser
|
|
1336
|
+
* never calls the Command Code API directly — the Host serves the catalog
|
|
1337
|
+
* (already fetched/cached by the adapter) so models can be picked from the
|
|
1338
|
+
* live list instead of typed by hand.
|
|
1357
1339
|
*/
|
|
1358
1340
|
models(): Promise<CommandCodeCatalog>;
|
|
1359
1341
|
/**
|
|
1360
1342
|
* The model price table the composer prices an in-progress session with.
|
|
1361
|
-
* Static vendored data
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1343
|
+
* Static vendored data, served Host-side so the browser bundle never carries
|
|
1344
|
+
* a copy that could drift from the snapshot, and so a price update reaches an
|
|
1345
|
+
* open page without a rebuild.
|
|
1364
1346
|
*/
|
|
1365
1347
|
prices(): Promise<CommandCodePriceTable>;
|
|
1366
1348
|
/**
|
|
1367
1349
|
* Start (or rejoin) a browser-login attempt and return its fresh status —
|
|
1368
1350
|
* `waiting` carrying the Studio URL. Rejects when the flow cannot start
|
|
1369
|
-
* (no free loopback port, disposed plugin)
|
|
1370
|
-
* into the failure branch the page renders.
|
|
1351
|
+
* (no free loopback port, disposed plugin).
|
|
1371
1352
|
*/
|
|
1372
1353
|
loginBegin(targetRef?: string): Promise<CommandCodeLoginStatus>;
|
|
1373
1354
|
/** Poll a login attempt's status. */
|
|
@@ -1469,16 +1450,15 @@ declare class CommandCodeLoginFlow {
|
|
|
1469
1450
|
* asynchronously (`complete()`), and that window is open to a cancel or a
|
|
1470
1451
|
* fresh `begin()`; the generation lets a late completion recognize that it
|
|
1471
1452
|
* no longer owns the status face and stop instead of storing a credential
|
|
1472
|
-
* the user cancelled
|
|
1453
|
+
* the user cancelled.
|
|
1473
1454
|
*/
|
|
1474
1455
|
private attemptSeq;
|
|
1475
1456
|
/**
|
|
1476
|
-
* The start currently binding a port, if any. Every `begin()`
|
|
1477
|
-
*
|
|
1478
|
-
*
|
|
1479
|
-
*
|
|
1480
|
-
*
|
|
1481
|
-
* the port window so browser login dies until the Host restarts.
|
|
1457
|
+
* The start currently binding a port, if any. Every `begin()` arriving before
|
|
1458
|
+
* it settles joins it: two independent starts would each bind a loopback
|
|
1459
|
+
* server, and only the LAST one is reachable by `teardown()` — the orphan
|
|
1460
|
+
* keeps answering `/callback` for the process's lifetime, and ten of them
|
|
1461
|
+
* exhaust the port window so browser login dies until the Host restarts.
|
|
1482
1462
|
*/
|
|
1483
1463
|
private starting;
|
|
1484
1464
|
/** A live attempt's destination; different rows may not rejoin it. */
|
|
@@ -1551,32 +1531,25 @@ declare class CommandCodeLoginFlow {
|
|
|
1551
1531
|
declare const COMMANDCODE_SEARCH_PROVIDER_ID = "commandcode";
|
|
1552
1532
|
/**
|
|
1553
1533
|
* The factory-declared search provider id dsh ships by default (from
|
|
1554
|
-
* `dsh-base`'s cordis patch `web.config.searchProvider`).
|
|
1555
|
-
*
|
|
1556
|
-
*
|
|
1557
|
-
* {@link applyCommandCodeSearchSelection}) — it never forces this default,
|
|
1558
|
-
* because forcing it is what used to silence sibling search plugins such as
|
|
1559
|
-
* modsearch even with Command Code search turned off (issue #26).
|
|
1534
|
+
* `dsh-base`'s cordis patch `web.config.searchProvider`). A documented
|
|
1535
|
+
* reference only: disabling this plugin's `webSearch` toggle restores the
|
|
1536
|
+
* PREVIOUSLY selected backend, never this default (issue #26).
|
|
1560
1537
|
*/
|
|
1561
1538
|
declare const DEFAULT_WEB_SEARCH_PROVIDER_ID = "deepseek-official";
|
|
1562
1539
|
/**
|
|
1563
1540
|
* Tracked web-search selection state for one mounted `WebRuntime`.
|
|
1564
1541
|
*
|
|
1565
|
-
* `owner` marks whether this plugin currently owns the selection
|
|
1566
|
-
*
|
|
1567
|
-
*
|
|
1568
|
-
*
|
|
1569
|
-
* configured, leave auto-select" and must round-trip untouched: writing the
|
|
1570
|
-
* factory default instead would still override a sibling plugin's own
|
|
1571
|
-
* constructor-time pin.
|
|
1542
|
+
* `owner` marks whether this plugin currently owns the selection. `displaced`
|
|
1543
|
+
* is the backend it took over — restored on disable or unload — and
|
|
1544
|
+
* `undefined` means "nothing was configured, leave auto-select" and must
|
|
1545
|
+
* round-trip untouched.
|
|
1572
1546
|
*
|
|
1573
1547
|
* `preexisting` is the one fact `displaced` cannot carry: an `undefined`
|
|
1574
1548
|
* `displaced` means EITHER "the field was unset when we took over" (give
|
|
1575
|
-
* `undefined` back
|
|
1576
|
-
*
|
|
1577
|
-
*
|
|
1578
|
-
*
|
|
1579
|
-
* search — the moment this plugin was disabled or unloaded.
|
|
1549
|
+
* `undefined` back) OR "the field already read `commandcode`" (touch
|
|
1550
|
+
* nothing). Collapsing the two is what turned a user's own
|
|
1551
|
+
* `searchProvider: commandcode` pin into an auto-select, and then into
|
|
1552
|
+
* `WEB_PROVIDER_AMBIGUOUS` on every search.
|
|
1580
1553
|
*/
|
|
1581
1554
|
interface CommandCodeSearchSelection {
|
|
1582
1555
|
owner: boolean;
|
|
@@ -1591,24 +1564,15 @@ declare function commandCodeSearchSelection(): CommandCodeSearchSelection;
|
|
|
1591
1564
|
* providers (issue #26).
|
|
1592
1565
|
*
|
|
1593
1566
|
* - Enabling writes `commandcode` and remembers whatever it displaced. When
|
|
1594
|
-
* the plugin already owns the selection
|
|
1595
|
-
*
|
|
1596
|
-
*
|
|
1597
|
-
* - Disabling hands the selection back to the remembered backend
|
|
1598
|
-
*
|
|
1599
|
-
*
|
|
1600
|
-
*
|
|
1601
|
-
* auto-select
|
|
1602
|
-
*
|
|
1603
|
-
* surviving runtime the plugin did not set, or a manual
|
|
1604
|
-
* `searchProvider: commandcode` pin), `displaced` stays undefined and
|
|
1605
|
-
* `preexisting` is set, so the later disable is a no-op rather than a guess
|
|
1606
|
-
* at the factory default. A "no-op" means the field is left ALONE: writing
|
|
1607
|
-
* that `undefined` back would destroy the user's own pin, and dsh-web reads
|
|
1608
|
-
* a cleared `searchProviderId` as auto-select — where a second usable
|
|
1609
|
-
* provider (the shipped `deepseek-official` is usable whenever a DeepSeek
|
|
1610
|
-
* key resolves) makes EVERY later search throw
|
|
1611
|
-
* `WEB_PROVIDER_AMBIGUOUS`.
|
|
1567
|
+
* the plugin already owns the selection, the original `displaced` is kept —
|
|
1568
|
+
* the field currently holds our own id, which must never be mistaken for the
|
|
1569
|
+
* user's backend.
|
|
1570
|
+
* - Disabling hands the selection back to the remembered backend only when
|
|
1571
|
+
* this plugin actually took it over. A fresh boot straight into
|
|
1572
|
+
* `webSearch: false`, or a `preexisting` field, leaves it ALONE: writing the
|
|
1573
|
+
* empty memory back would clear the user's own `searchProvider: commandcode`
|
|
1574
|
+
* pin and hand the selection to dsh-web's auto-select, where a second usable
|
|
1575
|
+
* provider makes every later search throw `WEB_PROVIDER_AMBIGUOUS`.
|
|
1612
1576
|
*
|
|
1613
1577
|
* Never throws: like the low-level rewrite, a hardened runtime shape degrades
|
|
1614
1578
|
* to registered-but-unselected.
|
|
@@ -1624,11 +1588,11 @@ interface CommandCodeSearchProviderDeps {
|
|
|
1624
1588
|
fetchImpl?: typeof fetch;
|
|
1625
1589
|
}
|
|
1626
1590
|
/**
|
|
1627
|
-
* A `ctx.web` search provider backed by the Command Code Provider API
|
|
1628
|
-
* the plugin's credential chain and `apiBase
|
|
1629
|
-
*
|
|
1630
|
-
*
|
|
1631
|
-
*
|
|
1591
|
+
* A `ctx.web` search provider backed by the Command Code Provider API, reusing
|
|
1592
|
+
* the plugin's credential chain and `apiBase` so the model-facing `web_search`
|
|
1593
|
+
* tool needs no separate configuration. Selection between multiple search
|
|
1594
|
+
* providers is the web seam's job (pin `searchProvider: commandcode` if
|
|
1595
|
+
* ambiguous).
|
|
1632
1596
|
*/
|
|
1633
1597
|
declare class CommandCodeSearchProvider implements WebSearchProvider {
|
|
1634
1598
|
private readonly deps;
|
|
@@ -1650,11 +1614,9 @@ interface TuiLocalizedText {
|
|
|
1650
1614
|
type TuiSettingsFieldKind = 'text' | 'number' | 'boolean' | 'select';
|
|
1651
1615
|
/** One choice of an options-bearing field. */
|
|
1652
1616
|
interface TuiSettingsFieldOption {
|
|
1653
|
-
/** Stored value. */
|
|
1654
1617
|
readonly value: string;
|
|
1655
1618
|
/** Display label (English; also the fallback). */
|
|
1656
1619
|
readonly label: string;
|
|
1657
|
-
/** Provider-owned translations for the label. */
|
|
1658
1620
|
readonly descriptions?: TuiLocalizedText;
|
|
1659
1621
|
}
|
|
1660
1622
|
/** The write one field's draft stages when the section is saved. */
|
|
@@ -1670,11 +1632,9 @@ interface TuiSettingsField {
|
|
|
1670
1632
|
readonly path: readonly string[];
|
|
1671
1633
|
/** Short field label (English; also the fallback). */
|
|
1672
1634
|
readonly label: string;
|
|
1673
|
-
/** Provider-owned translations for the label. */
|
|
1674
1635
|
readonly descriptions?: TuiLocalizedText;
|
|
1675
1636
|
/** Optional one-line help rendered under the field. */
|
|
1676
1637
|
readonly hint?: string;
|
|
1677
|
-
/** Provider-owned translations for the hint. */
|
|
1678
1638
|
readonly hintDescriptions?: TuiLocalizedText;
|
|
1679
1639
|
/** Optional group id; grouped fields render on that group's subpage. */
|
|
1680
1640
|
readonly group?: string;
|
|
@@ -1706,7 +1666,6 @@ interface TuiSettingsGroup {
|
|
|
1706
1666
|
readonly id: string;
|
|
1707
1667
|
/** Group title (English; also the fallback). */
|
|
1708
1668
|
readonly title: string;
|
|
1709
|
-
/** Provider-owned translations for the title. */
|
|
1710
1669
|
readonly descriptions?: TuiLocalizedText;
|
|
1711
1670
|
}
|
|
1712
1671
|
/** One plugin's section inside the dsh-TUI settings screen. */
|
|
@@ -1715,7 +1674,6 @@ interface TuiSettingsSection {
|
|
|
1715
1674
|
readonly ns: string;
|
|
1716
1675
|
/** Section title (English; also the fallback). */
|
|
1717
1676
|
readonly title: string;
|
|
1718
|
-
/** Provider-owned translations for the title. */
|
|
1719
1677
|
readonly descriptions?: TuiLocalizedText;
|
|
1720
1678
|
/** Optional navigation groups, in display order. */
|
|
1721
1679
|
readonly groups?: readonly TuiSettingsGroup[];
|
|
@@ -1783,25 +1741,22 @@ interface CommandCodeTuiSettingsDeps {
|
|
|
1783
1741
|
* Build the section descriptor. Pure, so tests can pin the exact fields
|
|
1784
1742
|
* without a dsh-TUI host.
|
|
1785
1743
|
*
|
|
1786
|
-
*
|
|
1787
|
-
* `
|
|
1788
|
-
*
|
|
1789
|
-
*
|
|
1790
|
-
*
|
|
1791
|
-
* unset
|
|
1792
|
-
*
|
|
1793
|
-
* the screen's "(empty)".
|
|
1744
|
+
* The two option-bearing fields (`activeAccount`, `lang`) are `text` +
|
|
1745
|
+
* `options` rather than `select`, because a `select` cannot express "unset" —
|
|
1746
|
+
* cycling only ever lands on a declared option, so it would strand the user on
|
|
1747
|
+
* a pinned value with no way back to automatic. The `auto` sentinel plus a
|
|
1748
|
+
* `parse` that clears the path keeps unset reachable. `filterModelsByPlan`
|
|
1749
|
+
* formats its EFFECTIVE default (unset means true at the adapter) so a fresh
|
|
1750
|
+
* install reads true instead of the screen's "(empty)".
|
|
1794
1751
|
*/
|
|
1795
1752
|
declare function buildCommandCodeTuiSection(deps: CommandCodeTuiSettingsDeps): TuiSettingsSection;
|
|
1796
1753
|
/**
|
|
1797
1754
|
* Register the Command Code section on a dsh-TUI host.
|
|
1798
1755
|
*
|
|
1799
|
-
* @param ctx - the context of an activated `tuiSettingsSections` injection.
|
|
1800
|
-
* @param deps - plugin-owned facts the section reads.
|
|
1801
1756
|
* @returns a refresh function that re-registers the section when a fact it
|
|
1802
|
-
* renders changed
|
|
1803
|
-
*
|
|
1804
|
-
* inert after the fiber is torn down.
|
|
1757
|
+
* renders changed — the plugin entry calls it from its
|
|
1758
|
+
* `loader/volatile-update` listener — or `undefined` when the seam is
|
|
1759
|
+
* unusable. The returned function is inert after the fiber is torn down.
|
|
1805
1760
|
*/
|
|
1806
1761
|
declare function applyCommandCodeTuiSettings(ctx: Context, deps: CommandCodeTuiSettingsDeps): (() => void) | undefined;
|
|
1807
1762
|
//#endregion
|
|
@@ -1834,16 +1789,20 @@ interface Config {
|
|
|
1834
1789
|
requestTimeoutMs?: number;
|
|
1835
1790
|
/** Milliseconds a stream may stall before being treated as a dead connection; defaults to 300s. */
|
|
1836
1791
|
streamIdleTimeoutMs?: number;
|
|
1792
|
+
/**
|
|
1793
|
+
* Opt-in cache mitigation for the CLI route: after this model has answered,
|
|
1794
|
+
* durably offload its earlier images before later turns. Old pixels then
|
|
1795
|
+
* require a fresh read/attachment if the model needs to inspect them again.
|
|
1796
|
+
* Defaults to false to preserve full image history.
|
|
1797
|
+
*/
|
|
1798
|
+
offloadSeenImagesForCache?: boolean;
|
|
1837
1799
|
/**
|
|
1838
1800
|
* Transport failures one request absorbs before the failure is surfaced;
|
|
1839
|
-
* defaults to 5. The route's retry policy is near-unbounded on purpose
|
|
1840
|
-
* attempts, waits doubling to 15 minutes) because that shape is for
|
|
1841
|
-
* failures a provider asks to have retried
|
|
1842
|
-
*
|
|
1843
|
-
*
|
|
1844
|
-
* after the failures before them, so ~15.5 s of grace), and after that the
|
|
1845
|
-
* wait is pure stall, so the retries are capped here. Raise it on a genuinely
|
|
1846
|
-
* flaky link; 0 surfaces every transport failure immediately.
|
|
1801
|
+
* defaults to 5. The route's retry policy is near-unbounded on purpose
|
|
1802
|
+
* (1000 attempts, waits doubling to 15 minutes) because that shape is for
|
|
1803
|
+
* the failures a provider asks to have retried; a transport failure is not
|
|
1804
|
+
* one of those, and after ~15.5 s of grace the wait is pure stall, so it is
|
|
1805
|
+
* capped here (issue #39). 0 surfaces every transport failure immediately.
|
|
1847
1806
|
*/
|
|
1848
1807
|
transportMaxRetries?: number;
|
|
1849
1808
|
/**
|
|
@@ -1855,8 +1814,7 @@ interface Config {
|
|
|
1855
1814
|
filterModelsByPlan?: boolean;
|
|
1856
1815
|
/**
|
|
1857
1816
|
* Visible-model allowlist: catalog model ids shown in pickers. Empty or
|
|
1858
|
-
* unset means "show everything"
|
|
1859
|
-
* filter card; applies after the subscription-tier filter.
|
|
1817
|
+
* unset means "show everything"; applied after the subscription-tier filter.
|
|
1860
1818
|
*/
|
|
1861
1819
|
visibleModels?: string[];
|
|
1862
1820
|
/**
|
|
@@ -1864,117 +1822,82 @@ interface Config {
|
|
|
1864
1822
|
* list, keyed by catalog id (`true` = listed, `false` = hidden). An id here
|
|
1865
1823
|
* decides that model on its own; an id absent here follows `visibleModels`.
|
|
1866
1824
|
* dsh-TUI keys a staged edit by the field's path, so the checkboxes need one
|
|
1867
|
-
* path per model — a map
|
|
1868
|
-
* is a member of the array".
|
|
1825
|
+
* path per model — a map.
|
|
1869
1826
|
*/
|
|
1870
1827
|
modelVisibility?: Record<string, boolean>;
|
|
1871
1828
|
/**
|
|
1872
1829
|
* Extra accounts for multi-account rotation. The top-level
|
|
1873
1830
|
* `apiKey`/`apiKeyEnv` (plus the CLI auth file) always form the first
|
|
1874
|
-
* (`default`) account; each entry here adds one more
|
|
1875
|
-
*
|
|
1876
|
-
*
|
|
1877
|
-
* request fails with a `RATE_LIMIT` error naming the earliest window
|
|
1878
|
-
* reset. Entries without `apiKey` or `apiKeyEnv` are ignored.
|
|
1831
|
+
* (`default`) account; each entry here adds one more, and an entry with
|
|
1832
|
+
* neither `apiKey` nor `apiKeyEnv` is ignored. A pre-stream 429/401 marks
|
|
1833
|
+
* the key and the next account's key is retried transparently.
|
|
1879
1834
|
*/
|
|
1880
1835
|
accounts?: CommandCodeAccountConfig[];
|
|
1881
1836
|
/**
|
|
1882
1837
|
* Manually selected active account: a slot id — `default`, or an extra
|
|
1883
|
-
* account's credential reference (e.g. `COMMANDCODE_API_KEY_2`).
|
|
1884
|
-
*
|
|
1885
|
-
*
|
|
1886
|
-
* rotation still applies). Unset means "first usable account".
|
|
1838
|
+
* account's credential reference (e.g. `COMMANDCODE_API_KEY_2`). It serves
|
|
1839
|
+
* whenever usable; an unknown id or an exhausted one falls back to rotation
|
|
1840
|
+
* order. Unset means "first usable account".
|
|
1887
1841
|
*/
|
|
1888
1842
|
activeAccount?: string;
|
|
1889
1843
|
/**
|
|
1890
|
-
* Model → account routing rules
|
|
1891
|
-
* account slot id
|
|
1892
|
-
*
|
|
1893
|
-
*
|
|
1894
|
-
* the passive rotation order. A routed account that is exhausted or invalid
|
|
1895
|
-
* falls back to the normal selection, so the router is a hint, never a hard
|
|
1896
|
-
* gate. The first matching rule wins.
|
|
1844
|
+
* Model → account routing rules, each listing catalog model ids for an
|
|
1845
|
+
* account slot id. A matching rule's account serves before {@link
|
|
1846
|
+
* activeAccount} and the passive rotation order; an unusable routed account
|
|
1847
|
+
* falls back, so the router is a hint, never a hard gate. First match wins.
|
|
1897
1848
|
*/
|
|
1898
1849
|
modelAccountRules?: CommandCodeModelAccountRule[];
|
|
1899
1850
|
/**
|
|
1900
1851
|
* Whether to use Command Code as the backend for dsh's model-facing
|
|
1901
|
-
* `web_search` tool.
|
|
1902
|
-
*
|
|
1903
|
-
*
|
|
1904
|
-
*
|
|
1905
|
-
*
|
|
1906
|
-
*
|
|
1907
|
-
*
|
|
1908
|
-
* rides dsh's internal `searchProviderId`, which is read per search call,
|
|
1909
|
-
* so a setting change lands on the next search without a restart.
|
|
1910
|
-
* Defaults to true.
|
|
1852
|
+
* `web_search` tool. Enabled registers a `commandcode` search provider on
|
|
1853
|
+
* `ctx.web` AND selects it over the shipped `deepseek-official` (or a
|
|
1854
|
+
* sibling plugin's pin), reusing the SAME key and apiBase as chat. Disabling
|
|
1855
|
+
* hands the selection back to whichever backend was there before, so a
|
|
1856
|
+
* sibling search plugin (e.g. modsearch) keeps working (issue #26). The
|
|
1857
|
+
* write rides dsh's internal `searchProviderId`, read per search call, so a
|
|
1858
|
+
* setting change lands on the next search without a restart. Defaults true.
|
|
1911
1859
|
*/
|
|
1912
1860
|
webSearch?: boolean;
|
|
1913
1861
|
/**
|
|
1914
1862
|
* Whether the Web sidebar shows the plans & quota card
|
|
1915
|
-
* (`sidebar.footer.action`). Defaults to false
|
|
1916
|
-
*
|
|
1917
|
-
*
|
|
1918
|
-
*
|
|
1919
|
-
* the toggle is on. Read by the browser client; the adapter ignores it.
|
|
1863
|
+
* (`sidebar.footer.action`). Defaults to false, so an unset document mounts
|
|
1864
|
+
* no sidebar quota surface and no background usage poll for it; the
|
|
1865
|
+
* dashboard cell behind it stays registered. Read by the browser client; the
|
|
1866
|
+
* adapter ignores it.
|
|
1920
1867
|
*/
|
|
1921
1868
|
showSidebarQuota?: boolean;
|
|
1922
|
-
/**
|
|
1923
|
-
* Whether the Command Code decision model (`typesafe/jev`) may auto-approve
|
|
1924
|
-
* shell commands that dsh was about to ask about. Defaults to FALSE: the
|
|
1925
|
-
* guard turns a model's opinion into a one-shot approval grant, so it is
|
|
1926
|
-
* opt-in, and the command text (plus the agent's own description of it) is
|
|
1927
|
-
* sent to Command Code to judge. Only commands a policy already wanted a
|
|
1928
|
-
* human to look at are ever judged, and only a confident "safe" verdict
|
|
1929
|
-
* (`commandGuardLevel`) skips the prompt — every other outcome, including
|
|
1930
|
-
* any failure of the decision call itself, delegates to the normal approval
|
|
1931
|
-
* flow. See `./command-guard.ts`.
|
|
1932
|
-
*/
|
|
1933
|
-
commandGuard?: boolean;
|
|
1934
|
-
/**
|
|
1935
|
-
* How confident every verdict must be before the guard skips the approval
|
|
1936
|
-
* prompt: `high` (0.95), `medium` (0.9, the default) or `low` (0.8). A lower
|
|
1937
|
-
* level approves more, on less evidence. The decision budget is fixed
|
|
1938
|
-
* (`COMMAND_GUARD_TIMEOUT_MS`), so this is the guard's only tuning knob.
|
|
1939
|
-
*/
|
|
1940
|
-
commandGuardLevel?: CommandGuardLevel;
|
|
1941
1869
|
/**
|
|
1942
1870
|
* Whether requests enforce zero data retention: the provider then routes
|
|
1943
1871
|
* them only through upstreams that keep no prompts/completions and never
|
|
1944
1872
|
* train on them (its own opt-in, `CMD_ZDR=1` in the CLI / `x-cmd-zdr: 1` on
|
|
1945
1873
|
* the Provider API). Defaults to FALSE: `zdr` changes WHERE a request is
|
|
1946
|
-
* served. Every chat request carries the header when enabled
|
|
1947
|
-
* no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers`
|
|
1948
|
-
*
|
|
1949
|
-
*
|
|
1950
|
-
*
|
|
1951
|
-
* Command Code's Studio). The decision endpoint behind the command guard is
|
|
1952
|
-
* never ZDR-enforced — see `./systemone.ts`.
|
|
1874
|
+
* served. Every chat request carries the header when enabled, and a model
|
|
1875
|
+
* with no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers` rather
|
|
1876
|
+
* than losing the guarantee. ZDR capacity is priced pass-through and usually
|
|
1877
|
+
* costs more; the price readout keeps quoting the ordinary catalog rates
|
|
1878
|
+
* (the real per-request price shows in Command Code's Studio).
|
|
1953
1879
|
*/
|
|
1954
1880
|
zdr?: boolean;
|
|
1955
1881
|
/**
|
|
1956
1882
|
* Language override for the `/commandcode` Host-side command's user-facing
|
|
1957
|
-
* copy. Host commands cannot read the client's `ctx.locale`, so this is
|
|
1958
|
-
*
|
|
1959
|
-
*
|
|
1960
|
-
*
|
|
1961
|
-
*
|
|
1962
|
-
*
|
|
1963
|
-
*
|
|
1964
|
-
* `pickCommandLocale`.
|
|
1883
|
+
* copy. Host commands cannot read the client's `ctx.locale`, so this is the
|
|
1884
|
+
* explicit knob: `'zh'` or `'en'`, defaulting to `'zh'`. The web settings
|
|
1885
|
+
* page is unaffected — it follows the browser's language preference on its
|
|
1886
|
+
* own. The declared type is `string` (the schemastery `pattern` cannot
|
|
1887
|
+
* narrow literal types); `pickCommandLocale` treats an unknown value as
|
|
1888
|
+
* "unset" and then reads `LC_ALL`/`LANG`, which is only reachable when
|
|
1889
|
+
* `lang` is absent from a programmatically built config.
|
|
1965
1890
|
*/
|
|
1966
1891
|
lang?: string;
|
|
1967
1892
|
}
|
|
1968
1893
|
/**
|
|
1969
1894
|
* The Config schema: every field volatile except the composition-only `apiKey`
|
|
1970
|
-
* secret.
|
|
1971
|
-
*
|
|
1972
|
-
*
|
|
1973
|
-
*
|
|
1974
|
-
*
|
|
1975
|
-
*
|
|
1976
|
-
* without remounting this fiber (the `loader/volatile-update` listener at the
|
|
1977
|
-
* bottom of `apply` covers the facts that are not re-derived per read).
|
|
1895
|
+
* secret. 0.1.7's settings forms are projected from the schema's
|
|
1896
|
+
* `meta.volatile` nodes, so an unmarked field would be invisible to AND
|
|
1897
|
+
* unwritable from the settings page. The loader also hands `apply()` a live
|
|
1898
|
+
* reference per marked field, so writes commit in place without remounting
|
|
1899
|
+
* this fiber — the `loader/volatile-update` listener at the bottom of `apply`
|
|
1900
|
+
* re-derives the two facts that are not re-read per request.
|
|
1978
1901
|
*/
|
|
1979
1902
|
declare const Config: z<Config>;
|
|
1980
1903
|
/** One resolution's complete request facts: connection plus credential reference. */
|
|
@@ -1985,7 +1908,7 @@ interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {
|
|
|
1985
1908
|
* The one explicit resolve step from raw config to validated connection
|
|
1986
1909
|
* facts. Programmatic construction may bypass Schemastery normalization, so
|
|
1987
1910
|
* every default is re-judged here — for the composition entry at load and for
|
|
1988
|
-
*
|
|
1911
|
+
* every settings-backed read.
|
|
1989
1912
|
*/
|
|
1990
1913
|
declare function resolveAdapterOptions(config: Config): ResolvedCommandCodeOptions;
|
|
1991
1914
|
declare function apply(ctx: Context, config: Config): void;
|