@eddyskywalker/dsh-chatgpt-subscription 0.46.1 → 0.48.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 +63 -0
- package/README.md +22 -1
- package/lib/client.js +2639 -571
- package/lib/client.js.map +1 -1
- package/lib/index.js +15598 -5902
- package/lib/plan-mode-pipeline.js +419 -0
- package/lib/plan-mode.js +783 -0
- package/lib/tool-result-pruner.js +400 -0
- package/lib/types/client/hub/brand-icons.d.ts +1 -1
- package/lib/types/client/hub/brand-icons.d.ts.map +1 -1
- package/lib/types/client/hub/brand-svg.d.ts +4 -0
- package/lib/types/client/hub/brand-svg.d.ts.map +1 -1
- package/lib/types/client/hub/providers.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +2 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/locales-ru/index.d.ts.map +1 -1
- package/lib/types/client/locales-ru/progress-updates.d.ts.map +1 -1
- package/lib/types/client/locales-ru/workbuddy.d.ts +10 -0
- package/lib/types/client/locales-ru/workbuddy.d.ts.map +1 -0
- package/lib/types/client/progress-updates/locales.d.ts +23 -5
- package/lib/types/client/progress-updates/locales.d.ts.map +1 -1
- package/lib/types/client/progress-updates/settings-binding.d.ts +13 -1
- package/lib/types/client/progress-updates/settings-binding.d.ts.map +1 -1
- package/lib/types/client/progress-updates/settings-section.d.ts +1 -1
- package/lib/types/client/progress-updates/settings-section.d.ts.map +1 -1
- package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts +34 -0
- package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts.map +1 -0
- package/lib/types/client/workbuddy/WorkBuddySection.d.ts +91 -0
- package/lib/types/client/workbuddy/WorkBuddySection.d.ts.map +1 -0
- package/lib/types/client/workbuddy/locales.d.ts +768 -0
- package/lib/types/client/workbuddy/locales.d.ts.map +1 -0
- package/lib/types/client/workbuddy/styles.d.ts +21 -0
- package/lib/types/client/workbuddy/styles.d.ts.map +1 -0
- package/lib/types/client/workbuddy/useWorkBuddySection.d.ts +149 -0
- package/lib/types/client/workbuddy/useWorkBuddySection.d.ts.map +1 -0
- package/lib/types/compat.d.ts +1 -1
- package/lib/types/entry-plan-mode-pipeline.d.ts +206 -0
- package/lib/types/entry-plan-mode-pipeline.d.ts.map +1 -0
- package/lib/types/entry-plan-mode.d.ts +353 -0
- package/lib/types/entry-plan-mode.d.ts.map +1 -0
- package/lib/types/entry-tool-result-pruner.d.ts +255 -0
- package/lib/types/entry-tool-result-pruner.d.ts.map +1 -0
- package/lib/types/host/agent-preset.d.ts.map +1 -1
- package/lib/types/host/cache-warmup/contracts.d.ts +5 -1
- package/lib/types/host/cache-warmup/contracts.d.ts.map +1 -1
- package/lib/types/host/cache-warmup/install.d.ts.map +1 -1
- package/lib/types/host/cache-warmup/projection.d.ts.map +1 -1
- package/lib/types/host/cache-warmup/retrieval-intent.d.ts +18 -0
- package/lib/types/host/cache-warmup/retrieval-intent.d.ts.map +1 -0
- package/lib/types/host/cache-warmup/settings.d.ts +9 -2
- package/lib/types/host/cache-warmup/settings.d.ts.map +1 -1
- package/lib/types/host/common/capabilities.d.ts.map +1 -1
- package/lib/types/host/common/model-request-control.d.ts +1 -1
- package/lib/types/host/common/model-request-control.d.ts.map +1 -1
- package/lib/types/host/common/request-diagnostics.d.ts +1 -1
- package/lib/types/host/common/request-diagnostics.d.ts.map +1 -1
- package/lib/types/host/compaction-policy-guard.d.ts +58 -0
- package/lib/types/host/compaction-policy-guard.d.ts.map +1 -0
- package/lib/types/host/compaction-prompt.d.ts +129 -0
- package/lib/types/host/compaction-prompt.d.ts.map +1 -0
- package/lib/types/host/plan-mode-cache-guard.d.ts +16 -0
- package/lib/types/host/plan-mode-cache-guard.d.ts.map +1 -0
- package/lib/types/host/preset-sync.d.ts.map +1 -1
- package/lib/types/host/ptc-sdk-cache-guard.d.ts +80 -0
- package/lib/types/host/ptc-sdk-cache-guard.d.ts.map +1 -0
- package/lib/types/host/tool-result-pruner-guard.d.ts +34 -0
- package/lib/types/host/tool-result-pruner-guard.d.ts.map +1 -0
- package/lib/types/host/workbuddy/account-pool.d.ts +389 -0
- package/lib/types/host/workbuddy/account-pool.d.ts.map +1 -0
- package/lib/types/host/workbuddy/adapter.d.ts +249 -0
- package/lib/types/host/workbuddy/adapter.d.ts.map +1 -0
- package/lib/types/host/workbuddy/atrest.d.ts +98 -0
- package/lib/types/host/workbuddy/atrest.d.ts.map +1 -0
- package/lib/types/host/workbuddy/checkin.d.ts +150 -0
- package/lib/types/host/workbuddy/checkin.d.ts.map +1 -0
- package/lib/types/host/workbuddy/client.d.ts +214 -0
- package/lib/types/host/workbuddy/client.d.ts.map +1 -0
- package/lib/types/host/workbuddy/dsml.d.ts +55 -0
- package/lib/types/host/workbuddy/dsml.d.ts.map +1 -0
- package/lib/types/host/workbuddy/guardrails.d.ts +111 -0
- package/lib/types/host/workbuddy/guardrails.d.ts.map +1 -0
- package/lib/types/host/workbuddy/identity.d.ts +71 -0
- package/lib/types/host/workbuddy/identity.d.ts.map +1 -0
- package/lib/types/host/workbuddy/mapper.d.ts +238 -0
- package/lib/types/host/workbuddy/mapper.d.ts.map +1 -0
- package/lib/types/host/workbuddy/model-catalog.d.ts +217 -0
- package/lib/types/host/workbuddy/model-catalog.d.ts.map +1 -0
- package/lib/types/host/workbuddy/oauth.d.ts +47 -0
- package/lib/types/host/workbuddy/oauth.d.ts.map +1 -0
- package/lib/types/host/workbuddy/outbound-identity.d.ts +139 -0
- package/lib/types/host/workbuddy/outbound-identity.d.ts.map +1 -0
- package/lib/types/host/workbuddy/routes.d.ts +56 -0
- package/lib/types/host/workbuddy/routes.d.ts.map +1 -0
- package/lib/types/host/workbuddy/token-store.d.ts +370 -0
- package/lib/types/host/workbuddy/token-store.d.ts.map +1 -0
- package/lib/types/host/workbuddy/types.d.ts +179 -0
- package/lib/types/host/workbuddy/types.d.ts.map +1 -0
- package/lib/types/index.d.ts +35 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/workbuddy-contracts.d.ts +531 -0
- package/lib/types/shared/workbuddy-contracts.d.ts.map +1 -0
- package/package.json +14 -2
- package/presets/dispatch/README.md +57 -3
- package/presets/dispatch/agent.cordis.yml +63 -3
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkBuddy's account pool.
|
|
3
|
+
*
|
|
4
|
+
* This line is the one that adopts accounts it does not own: alongside the
|
|
5
|
+
* accounts a user signs in through this plugin, it reads the CodeBuddy desktop
|
|
6
|
+
* client's own `*.info` credentials so an existing IDE sign-in needs no second
|
|
7
|
+
* login. Both kinds take part in scheduling through the shared
|
|
8
|
+
* {@link AccountPoolCore}, and the difference is enforced here:
|
|
9
|
+
*
|
|
10
|
+
* - **managed** accounts were signed in through this plugin. They live in the
|
|
11
|
+
* pool's encrypted storage and may be deleted.
|
|
12
|
+
* - **desktop** accounts belong to the IDE. Their credential is re-read from the
|
|
13
|
+
* IDE's file on every pick, because the IDE rotates it on its own schedule and
|
|
14
|
+
* a cached copy would go stale; they are never deleted, only hidden.
|
|
15
|
+
*/
|
|
16
|
+
import { LlmError } from '@deepseek-ai/dsh-llm';
|
|
17
|
+
import { AccountPoolCore, type PoolAccountShape, type PoolData } from '../common/account-pool.ts';
|
|
18
|
+
import type { CredentialStore } from '../token-store.ts';
|
|
19
|
+
import { FileCredentialStore, type WorkBuddyCredentials } from './token-store.ts';
|
|
20
|
+
import type { PoolAccountQuotaDto } from '../../shared/account-pool-contracts.ts';
|
|
21
|
+
import { type WorkBuddyAccountQuota, type WorkBuddyAccountRestrictionDto, type WorkBuddyAccountSummaryDto, type WorkBuddyPoolStateDto, type WorkBuddyRegion } from '../../shared/workbuddy-contracts.ts';
|
|
22
|
+
/** One pooled WorkBuddy account: the credential plus the facts the card renders. */
|
|
23
|
+
export interface WorkBuddyPoolAccount extends PoolAccountShape<WorkBuddyCredentials> {
|
|
24
|
+
region: WorkBuddyRegion;
|
|
25
|
+
nickname?: string;
|
|
26
|
+
uin?: string;
|
|
27
|
+
/** Which store owns the credential; only managed accounts may be deleted. */
|
|
28
|
+
source: 'desktop' | 'managed';
|
|
29
|
+
/** IDE file a desktop account came from; absent for managed accounts. */
|
|
30
|
+
sourceFile?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Encrypted pool file this line owns. */
|
|
33
|
+
export declare function workBuddyPoolPath(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Error code the adapter routes on when the WHOLE pool is paused.
|
|
36
|
+
*
|
|
37
|
+
* Deliberately not `RATE_LIMIT`: a pause says the pool will not be served at
|
|
38
|
+
* all — the upstream barred accounts, it did not answer 429 for one request —
|
|
39
|
+
* and confusing the two would send the user to wait out a window that has
|
|
40
|
+
* nothing to do with their accounts. The pause lifts by itself and the RESTRICTED
|
|
41
|
+
* accounts do not, so the remedy is also different.
|
|
42
|
+
*/
|
|
43
|
+
export declare const WORKBUDDY_POOL_PAUSED_CODE: "WORKBUDDY_POOL_PAUSED";
|
|
44
|
+
/**
|
|
45
|
+
* Thrown instead of selecting an account while the whole pool is paused.
|
|
46
|
+
*
|
|
47
|
+
* Exported so the protocol worker's caller can tell "upstream barred two
|
|
48
|
+
* accounts" (wait for the pause, then sign the restricted ones in again) from
|
|
49
|
+
* "this request was rate limited". It is never reported as an upstream 429.
|
|
50
|
+
*/
|
|
51
|
+
export declare class WorkBuddyPoolPausedError extends LlmError {
|
|
52
|
+
/** Unix milliseconds the pause lifts on its own; absent when nothing named one. */
|
|
53
|
+
readonly pausedUntil: number | undefined;
|
|
54
|
+
constructor(message: string, pausedUntil?: number);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* How long a second barred account stops the whole pool.
|
|
58
|
+
*
|
|
59
|
+
* Thirty minutes is the confirmed Wave 2A policy: long enough that an upstream
|
|
60
|
+
* refusing every account is not hammered once per turn, short enough that a
|
|
61
|
+
* transient bar does not take the line offline for a working day. When it
|
|
62
|
+
* passes the pool resumes by itself — the restricted accounts do not, because
|
|
63
|
+
* nothing upstream said they may serve again.
|
|
64
|
+
*/
|
|
65
|
+
export declare const WORKBUDDY_POOL_PAUSE_MS: number;
|
|
66
|
+
/**
|
|
67
|
+
* Window in which a second, DIFFERENT barred account stops the whole pool.
|
|
68
|
+
*
|
|
69
|
+
* Measured from each refusal to the next. One barred account is that account's
|
|
70
|
+
* problem and the rest still serve; two different accounts barred inside this
|
|
71
|
+
* window is the pool's problem, because the same thing is about to happen to
|
|
72
|
+
* the third.
|
|
73
|
+
*/
|
|
74
|
+
export declare const WORKBUDDY_RESTRICTION_ESCALATION_WINDOW_MS: number;
|
|
75
|
+
/** One account's `11140` as this pool's own document keeps it. */
|
|
76
|
+
export interface WorkBuddyPoolRestrictionRecord {
|
|
77
|
+
/** Gateway code; {@link WORKBUDDY_RESTRICTED_ACCOUNT_CODE} is the only one recorded. */
|
|
78
|
+
code: number;
|
|
79
|
+
/** Upstream `msg` when one came with the code. Never a credential. */
|
|
80
|
+
message?: string;
|
|
81
|
+
/** Instant the gateway named, when it named one. Reported, never enforced. */
|
|
82
|
+
until?: number;
|
|
83
|
+
/** When this pool observed the refusal; drives the escalation window. */
|
|
84
|
+
observedAt: number;
|
|
85
|
+
}
|
|
86
|
+
/** A pause of the WHOLE pool, as its own document keeps it. */
|
|
87
|
+
export interface WorkBuddyPoolPauseRecord {
|
|
88
|
+
/** Composed sentence for the card; never a token. */
|
|
89
|
+
reason: string;
|
|
90
|
+
pausedSince: number;
|
|
91
|
+
/** Unix milliseconds the pause lifts by itself. */
|
|
92
|
+
pausedUntil: number;
|
|
93
|
+
/** Account ids whose `11140` caused the pause, in observation order. */
|
|
94
|
+
triggeredBy: string[];
|
|
95
|
+
}
|
|
96
|
+
/** Whole-pool state kept inside the pool document. */
|
|
97
|
+
export interface WorkBuddyPoolDocumentState {
|
|
98
|
+
/** Account id → its `11140`. A restricted account is out of rotation. */
|
|
99
|
+
restrictions: Record<string, WorkBuddyPoolRestrictionRecord>;
|
|
100
|
+
pause?: WorkBuddyPoolPauseRecord;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* This line's pool document: the shared shape plus the pool-wide state.
|
|
104
|
+
*
|
|
105
|
+
* The state lives in the SAME document rather than a second store, so one
|
|
106
|
+
* encrypted write keeps "which account may serve" and "may the pool serve at
|
|
107
|
+
* all" in step: two documents could be observed half-updated, and the pool
|
|
108
|
+
* would then select an account its own restriction record bars.
|
|
109
|
+
*/
|
|
110
|
+
export interface WorkBuddyPoolData extends PoolData<WorkBuddyPoolAccount> {
|
|
111
|
+
pool?: WorkBuddyPoolDocumentState;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Read whole-pool state out of a stored document.
|
|
115
|
+
*
|
|
116
|
+
* Absent means "no pool-wide state", which is exactly what a document written
|
|
117
|
+
* before Wave 2A holds — and what an untouched pool still writes, so an install
|
|
118
|
+
* that never met `11140` carries no extra keys at all. A malformed ENTRY is
|
|
119
|
+
* dropped rather than failing the document: losing one memory of a refusal must
|
|
120
|
+
* not make the accounts unreadable, while silently keeping an unparseable pause
|
|
121
|
+
* could take the line offline forever.
|
|
122
|
+
*/
|
|
123
|
+
export declare function parseWorkBuddyPoolState(value: unknown): WorkBuddyPoolDocumentState | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* Validate and normalize one whole pool document.
|
|
126
|
+
*
|
|
127
|
+
* A record whose credential is unusable is dropped rather than repaired: the
|
|
128
|
+
* account can always be adopted again from its file or by signing in again, and
|
|
129
|
+
* keeping a credential-less row would offer the user an account nothing can use.
|
|
130
|
+
*/
|
|
131
|
+
export declare function parseWorkBuddyPoolData(value: unknown): WorkBuddyPoolData;
|
|
132
|
+
/**
|
|
133
|
+
* One cached snapshot as the shared account card renders it.
|
|
134
|
+
*
|
|
135
|
+
* Only what the DTO states is published: every meter that measured a share
|
|
136
|
+
* becomes a window, and a meter that measured none is dropped rather than drawn
|
|
137
|
+
* at 0 — which would claim an unspent allowance no reading supports.
|
|
138
|
+
*
|
|
139
|
+
* Exported for the pool's regression tests; the card only reaches it through
|
|
140
|
+
* the summary hook.
|
|
141
|
+
*/
|
|
142
|
+
export declare function workBuddyPoolQuota(snapshot: WorkBuddyAccountQuota): PoolAccountQuotaDto | undefined;
|
|
143
|
+
export interface WorkBuddyAccountPoolOptions {
|
|
144
|
+
/** Credential store the desktop scan reads through; the pool owns scheduling. */
|
|
145
|
+
store?: FileCredentialStore;
|
|
146
|
+
/** Test seam; production builds the platform backend from the pool path. */
|
|
147
|
+
backend?: CredentialStore<PoolData<WorkBuddyPoolAccount>>;
|
|
148
|
+
maxAccounts?: number;
|
|
149
|
+
/**
|
|
150
|
+
* The settings selection: the account the user pinned and the ones hidden.
|
|
151
|
+
*
|
|
152
|
+
* Read on every pick rather than captured once, because both change from the
|
|
153
|
+
* settings card while the adapter is serving requests.
|
|
154
|
+
*/
|
|
155
|
+
selection?: () => {
|
|
156
|
+
selectedAccountId: string | null;
|
|
157
|
+
hiddenAccountIds: readonly string[];
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* WorkBuddy's account pool.
|
|
162
|
+
*
|
|
163
|
+
* Desktop accounts are adopted into the pool so they can be scheduled and
|
|
164
|
+
* cooled down like any other, but they stay owned by the IDE: the pool refreshes
|
|
165
|
+
* their credential from the IDE's own file on every pick, and deletion is
|
|
166
|
+
* refused for them.
|
|
167
|
+
*/
|
|
168
|
+
export declare class WorkBuddyAccountPool extends AccountPoolCore<WorkBuddyCredentials, WorkBuddyPoolAccount, WorkBuddyAccountSummaryDto> {
|
|
169
|
+
private readonly store;
|
|
170
|
+
private readonly options_selection;
|
|
171
|
+
/**
|
|
172
|
+
* Older settings key → the id the account has now.
|
|
173
|
+
*
|
|
174
|
+
* A pin or a hide written before the identity fix names its account by the
|
|
175
|
+
* old name-derived key. Kept in step by {@link read}, which every routing
|
|
176
|
+
* decision goes through, so the mapping is never stale when it is consulted.
|
|
177
|
+
*/
|
|
178
|
+
private readonly legacyIds;
|
|
179
|
+
/**
|
|
180
|
+
* Per-model parks, in memory only: account id → model → the instant it lifts.
|
|
181
|
+
*
|
|
182
|
+
* The subscription meters an account × MODEL over a 24h window (429 `code
|
|
183
|
+
* 6004` names when it lifts), so cooling the whole ACCOUNT for one exhausted
|
|
184
|
+
* model throws away every other model that account can still serve. Process
|
|
185
|
+
* local on purpose, like the sibling gateway's model cooldowns: the window is
|
|
186
|
+
* short, and a restart re-measures it with the first request rather than
|
|
187
|
+
* trusting a stale timestamp.
|
|
188
|
+
*/
|
|
189
|
+
private readonly modelCooldowns;
|
|
190
|
+
/**
|
|
191
|
+
* Whole-pool state as of the LAST load through {@link loadPoolData}.
|
|
192
|
+
*
|
|
193
|
+
* A cache rather than a read per check: eligibility runs once per account per
|
|
194
|
+
* pick, and asking the encrypted store each time would pay a DPAPI unprotect
|
|
195
|
+
* per candidate. Every read and every mutation loads the document first, so
|
|
196
|
+
* this cannot be stale for longer than one storage round trip.
|
|
197
|
+
*/
|
|
198
|
+
private restrictions;
|
|
199
|
+
private pause;
|
|
200
|
+
constructor(options?: WorkBuddyAccountPoolOptions);
|
|
201
|
+
/**
|
|
202
|
+
* Load the pool, refreshing the legacy-key index on the way.
|
|
203
|
+
*
|
|
204
|
+
* Every routing decision and mutation goes through this method before it
|
|
205
|
+
* consults the settings selection, so building the index here is what keeps
|
|
206
|
+
* a pin written before the identity fix resolvable when
|
|
207
|
+
* {@link resolveSelectionId} is asked for it.
|
|
208
|
+
*/
|
|
209
|
+
protected loadPoolData(): Promise<PoolData<WorkBuddyPoolAccount>>;
|
|
210
|
+
/** Keep the pool-wide cache in step with the document just loaded. */
|
|
211
|
+
private observePoolState;
|
|
212
|
+
/** This account's live `11140`, matched through every key it answers to. */
|
|
213
|
+
private restrictionFor;
|
|
214
|
+
/** The pause that is still running, or undefined when it lifted or never began. */
|
|
215
|
+
private activePause;
|
|
216
|
+
/** The error every selection raises while the pool is paused. */
|
|
217
|
+
private pausedError;
|
|
218
|
+
/**
|
|
219
|
+
* Record an account-scoped refusal reported by the protocol worker.
|
|
220
|
+
*
|
|
221
|
+
* This is the ONE entry point for `11140`, and the policy it implements is
|
|
222
|
+
* the confirmed Wave 2A one:
|
|
223
|
+
*
|
|
224
|
+
* - the first barred account leaves rotation immediately and its restriction
|
|
225
|
+
* is PERSISTED (in the pool document, so a second pool instance over the
|
|
226
|
+
* same store sees it), while every other account keeps serving;
|
|
227
|
+
* - a SECOND, different account barred within
|
|
228
|
+
* {@link WORKBUDDY_RESTRICTION_ESCALATION_WINDOW_MS} pauses the whole pool
|
|
229
|
+
* for {@link WORKBUDDY_POOL_PAUSE_MS} — during which no account is selected
|
|
230
|
+
* at all — and that pause is persisted too;
|
|
231
|
+
* - the pause lifts by itself, the restricted accounts do NOT: only a
|
|
232
|
+
* completed sign-in ({@link addAccount}) puts one back in rotation.
|
|
233
|
+
*
|
|
234
|
+
* Only {@link WORKBUDDY_RESTRICTED_ACCOUNT_CODE} is accepted. `11128` is the
|
|
235
|
+
* channel/request-shape block and `11158` is one model an account has no
|
|
236
|
+
* entitlement for; neither says the ACCOUNT may not serve, so recording either
|
|
237
|
+
* would take a working account out of rotation and — with two inside the
|
|
238
|
+
* window — stop the whole pool over a request-shape mistake. The call is
|
|
239
|
+
* therefore refused loudly, which keeps that misrouting visible in a test or a
|
|
240
|
+
* log instead of silently barring a healthy account.
|
|
241
|
+
*/
|
|
242
|
+
markAccountRestriction(accountId: string, restriction: WorkBuddyAccountRestrictionDto): Promise<void>;
|
|
243
|
+
/** Clear one account's restriction; a completed sign-in is what does this. */
|
|
244
|
+
private clearRestriction;
|
|
245
|
+
/**
|
|
246
|
+
* Whole-pool state for the wire: whether the pool is paused, why, until when,
|
|
247
|
+
* which accounts are barred, and where this document lives.
|
|
248
|
+
*
|
|
249
|
+
* `pausedUntil` is the pause's remaining time in absolute form, which is what
|
|
250
|
+
* a card can count down and a route can answer without a second call. An
|
|
251
|
+
* expired pause is reported as not paused — it never needs a write to lift.
|
|
252
|
+
*/
|
|
253
|
+
poolState(): Promise<WorkBuddyPoolStateDto>;
|
|
254
|
+
/** Map a settings key from before the identity fix onto the account's real id. */
|
|
255
|
+
private resolveSelectionId;
|
|
256
|
+
/**
|
|
257
|
+
* Adopt any desktop credential the pool does not know yet.
|
|
258
|
+
*
|
|
259
|
+
* The IDE's directory is the source of truth for its own accounts, so a
|
|
260
|
+
* credential that appears there joins the pool. Nothing is ever removed: a
|
|
261
|
+
* file that disappears (the IDE signed out, a profile was moved) leaves the
|
|
262
|
+
* account in place, where the user can hide or delete the managed ones.
|
|
263
|
+
*/
|
|
264
|
+
syncDesktopAccounts(): Promise<WorkBuddyAccountSummaryDto[]>;
|
|
265
|
+
/**
|
|
266
|
+
* A stale `authStatus` is cleared once the credential in force has moved on.
|
|
267
|
+
*
|
|
268
|
+
* The marker records that ONE token was refused; it does not record that the
|
|
269
|
+
* sign-in is gone. This line can still produce it from a token-endpoint
|
|
270
|
+
* refusal, and the copy that refusal was about can be replaced afterwards by
|
|
271
|
+
* whoever owns it — the IDE rotates a desktop account's token on its own
|
|
272
|
+
* schedule, and the daily check-in renews a managed one and writes it back to
|
|
273
|
+
* this plugin's store. Nothing else in the system ever revisits an
|
|
274
|
+
* `authStatus`, so without this a row stays out of rotation for good and the
|
|
275
|
+
* card keeps saying "需要重新登录" for an account that is signed in.
|
|
276
|
+
*
|
|
277
|
+
* The verdict is re-checked against what the store holds NOW: a row whose
|
|
278
|
+
* account has a DIFFERENT, unexpired token is routable again and adopts it,
|
|
279
|
+
* while a row still holding the refused token keeps its marker — that one
|
|
280
|
+
* really does need a sign-in.
|
|
281
|
+
*/
|
|
282
|
+
private healStaleAuthFailures;
|
|
283
|
+
/** Account summaries, with a marker the credentials have outlived cleared. */
|
|
284
|
+
listAccounts(): Promise<WorkBuddyAccountSummaryDto[]>;
|
|
285
|
+
/**
|
|
286
|
+
* Pick an account, healing a stale marker first.
|
|
287
|
+
*
|
|
288
|
+
* The healing belongs on the request path, not only on the card: an account
|
|
289
|
+
* marked expired is excluded by the core's eligibility rule, so until the
|
|
290
|
+
* marker is gone the next request is answered with "全部 N 个账号都需要重新登录"
|
|
291
|
+
* for a credential the store has already replaced.
|
|
292
|
+
*/
|
|
293
|
+
getEffectiveAccount(excludeIds?: ReadonlySet<string>, fetchFn?: typeof fetch, forceRefresh?: boolean): Promise<{
|
|
294
|
+
account: WorkBuddyPoolAccount;
|
|
295
|
+
credentials: WorkBuddyCredentials;
|
|
296
|
+
}>;
|
|
297
|
+
/**
|
|
298
|
+
* Pick the account for the next request.
|
|
299
|
+
*
|
|
300
|
+
* A desktop account's credential is re-read from the IDE's file first: the IDE
|
|
301
|
+
* refreshes its own token, so the copy the pool adopted can be older than what
|
|
302
|
+
* is on disk.
|
|
303
|
+
*/
|
|
304
|
+
getEffectiveCredential(excludeIds?: ReadonlySet<string>, fetchFn?: typeof fetch, model?: string): Promise<{
|
|
305
|
+
account: WorkBuddyPoolAccount;
|
|
306
|
+
credentials: WorkBuddyCredentials;
|
|
307
|
+
}>;
|
|
308
|
+
/**
|
|
309
|
+
* Park ONE model on one account; every other model keeps serving.
|
|
310
|
+
*
|
|
311
|
+
* Returns the instant the park lifts, or undefined for a non-positive
|
|
312
|
+
* duration (which clears any existing park rather than extending it).
|
|
313
|
+
*/
|
|
314
|
+
markModelCooldown(accountId: string, model: string, durationMs: number): number | undefined;
|
|
315
|
+
/** When this account's park on this model lifts, or undefined when it may serve. */
|
|
316
|
+
modelCooldownUntil(accountId: string, model: string, now?: number): number | undefined;
|
|
317
|
+
/**
|
|
318
|
+
* The models this account is parked on right now, with the instant each park
|
|
319
|
+
* lifts.
|
|
320
|
+
*
|
|
321
|
+
* Only LIVE parks are reported: a window that has passed is dropped here, so
|
|
322
|
+
* the card never shows a model that may already serve. The lift instant is
|
|
323
|
+
* the one the upstream named, stored verbatim by
|
|
324
|
+
* {@link markModelCooldown}; it is never recomputed from a duration that has
|
|
325
|
+
* since drifted, because a re-derived instant would drift with it.
|
|
326
|
+
*/
|
|
327
|
+
private liveModelCooldowns;
|
|
328
|
+
/**
|
|
329
|
+
* Clear one account's cooldown AND the models it is parked on.
|
|
330
|
+
*
|
|
331
|
+
* The card's "reset cooldown" button promises the account is usable again. A
|
|
332
|
+
* model park is a cooldown too — the account stays eligible, but it still
|
|
333
|
+
* refuses the model the request wants — so leaving the park behind would
|
|
334
|
+
* report a reset that did not happen, and the park would outlive the only
|
|
335
|
+
* control the user has over it.
|
|
336
|
+
*
|
|
337
|
+
* The base write comes first: it is the half that can fail, and a failed
|
|
338
|
+
* write must leave the account's state as it was rather than half-cleared.
|
|
339
|
+
*/
|
|
340
|
+
clearCooldown(accountId: string): Promise<void>;
|
|
341
|
+
/** Accounts currently parked on one model, with lifted entries pruned on the way. */
|
|
342
|
+
private parkedAccountIds;
|
|
343
|
+
/**
|
|
344
|
+
* Whether another account besides `triedAccountIds` can serve THIS model.
|
|
345
|
+
*
|
|
346
|
+
* The plain {@link hasAnotherAvailableAccount} answers for any model, so a
|
|
347
|
+
* rotation loop that consulted it would keep trying while every remaining
|
|
348
|
+
* account is parked on the model it is asking for — turning one exhausted
|
|
349
|
+
* window into a burst of refused requests.
|
|
350
|
+
*/
|
|
351
|
+
hasAnotherAvailableAccountFor(triedAccountIds: ReadonlySet<string>, model: string): Promise<boolean>;
|
|
352
|
+
/**
|
|
353
|
+
* Whether another account may serve right now.
|
|
354
|
+
*
|
|
355
|
+
* Answered from ONE read that also carries the pool-wide state, and false
|
|
356
|
+
* while the pool is paused: the rotation loop consults this before retrying,
|
|
357
|
+
* so a pause has to end the loop there rather than after another selection it
|
|
358
|
+
* would only refuse.
|
|
359
|
+
*/
|
|
360
|
+
hasAnotherAvailableAccount(triedAccountIds: ReadonlySet<string>): Promise<boolean>;
|
|
361
|
+
/**
|
|
362
|
+
* Whether an account may serve a request.
|
|
363
|
+
*
|
|
364
|
+
* A hidden account keeps its place, its alias and its history, but the user
|
|
365
|
+
* has taken it out of this plugin's rotation, so it is not eligible.
|
|
366
|
+
*/
|
|
367
|
+
protected isEligible(account: WorkBuddyPoolAccount, now: number, triedAccountIds?: ReadonlySet<string>): boolean;
|
|
368
|
+
private selection;
|
|
369
|
+
/**
|
|
370
|
+
* Add or re-authorize one account, settling its identity first.
|
|
371
|
+
*
|
|
372
|
+
* A completed browser sign-in states the display name but not always the uid,
|
|
373
|
+
* while the IDE's own file for the same account states the uid. Passing the
|
|
374
|
+
* raw response through would key the login under the name and the file under
|
|
375
|
+
* the uid, so the pool would hold the same account twice — the duplicate this
|
|
376
|
+
* fix exists to remove. Resolving from the credential's own token before the
|
|
377
|
+
* dedupe key is computed is what makes the two paths agree.
|
|
378
|
+
*/
|
|
379
|
+
addAccount(credentials: WorkBuddyCredentials, alias?: string): Promise<WorkBuddyPoolAccount>;
|
|
380
|
+
/**
|
|
381
|
+
* Remove one account inside a transaction.
|
|
382
|
+
*
|
|
383
|
+
* A desktop account is refused: the plugin does not own that credential file,
|
|
384
|
+
* so removing it from the pool would strand the IDE's session while telling
|
|
385
|
+
* the user their account was deleted. Hiding is the supported action there.
|
|
386
|
+
*/
|
|
387
|
+
protected deleteAccountFromPool(data: PoolData<WorkBuddyPoolAccount>, accountId: string): void;
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=account-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-pool.d.ts","sourceRoot":"","sources":["../../../../src/host/workbuddy/account-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { LlmAdapter, LlmError, ReasoningEffortId, type GenerateOptions, type LlmModelInfo, type LlmProviderInfo, type LlmResolvedModelInfo, type PreparedAdapterCall, type ResolvedRetryPolicy, type StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
3
|
+
import { PROVIDER_ID, PROVIDER_NAME } from './types.ts';
|
|
4
|
+
import { FileCredentialStore, FileModelSettingsStore, type WorkBuddyPreferenceStore } from './token-store.ts';
|
|
5
|
+
import { type WorkBuddyModelEntry } from './model-catalog.ts';
|
|
6
|
+
import { type AttachmentImageReader } from './mapper.ts';
|
|
7
|
+
import { type WorkBuddyAccountRestrictionDto } from '../../shared/workbuddy-contracts.ts';
|
|
8
|
+
import type { WorkBuddyCredentials } from './token-store.ts';
|
|
9
|
+
import { type WorkBuddyUsageLedger } from './guardrails.ts';
|
|
10
|
+
/**
|
|
11
|
+
* Effort this route materializes when the caller names none.
|
|
12
|
+
*
|
|
13
|
+
* Preference order: the user's configured level when the model accepts it,
|
|
14
|
+
* otherwise the level the gateway's own catalog declares for that model (the
|
|
15
|
+
* same default the official CLI applies), otherwise nothing — which leaves the
|
|
16
|
+
* provider's own default in charge. A configured level the model does not
|
|
17
|
+
* accept is ignored rather than sent, since the endpoint rejects an unsupported
|
|
18
|
+
* level with `code 11150`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveDefaultReasoningEffort(efforts: readonly string[], configuredEffort?: string | null, modelDefaultEffort?: string | null): ReasoningEffortId | undefined;
|
|
21
|
+
/** Cooldown a 429 imposes when the service names no reset instant. */
|
|
22
|
+
export declare const POOL_COOLDOWN_MS: number;
|
|
23
|
+
/**
|
|
24
|
+
* The account pool this adapter drives, declared STRUCTURALLY.
|
|
25
|
+
*
|
|
26
|
+
* The pool module (`account-pool.ts`) and the settings routes are outside this
|
|
27
|
+
* file's boundary — Wave 3 owns them — so the adapter cannot import the class.
|
|
28
|
+
* Declaring the shape it calls has one property that matters here: this file is
|
|
29
|
+
* typechecked against the CONTRACT, so a method renamed on the pool side fails
|
|
30
|
+
* the build instead of failing at run time in the middle of a rotation loop.
|
|
31
|
+
*
|
|
32
|
+
* `markAccountRestriction` is the one member the pool worker FROZE for Wave 2B:
|
|
33
|
+
* code 11140 is an account verdict (who is asking), not a model verdict, and a
|
|
34
|
+
* `cooldownUntil` on the account or on a model cannot express "this account is
|
|
35
|
+
* barred from everything".
|
|
36
|
+
*/
|
|
37
|
+
export interface WorkBuddyAccountPool {
|
|
38
|
+
listAccounts(): Promise<readonly {
|
|
39
|
+
id: string;
|
|
40
|
+
}[]>;
|
|
41
|
+
getEffectiveCredential(tried: ReadonlySet<string>, fetchFn: typeof fetch, model?: string): Promise<{
|
|
42
|
+
account: {
|
|
43
|
+
id: string;
|
|
44
|
+
};
|
|
45
|
+
credentials: WorkBuddyCredentials;
|
|
46
|
+
}>;
|
|
47
|
+
renewCredential(accountId: string, fetchFn: typeof fetch, current: WorkBuddyCredentials): Promise<WorkBuddyCredentials>;
|
|
48
|
+
hasAnotherAvailableAccount(tried: ReadonlySet<string>): Promise<boolean>;
|
|
49
|
+
hasAnotherAvailableAccountFor(tried: ReadonlySet<string>, model: string): Promise<boolean>;
|
|
50
|
+
markCooldown(accountId: string, ms: number, reason: string): Promise<unknown>;
|
|
51
|
+
markModelCooldown(accountId: string, model: string, until: number): void;
|
|
52
|
+
/** Freeze this account out of every model after code 11140. */
|
|
53
|
+
markAccountRestriction(accountId: string, restriction: WorkBuddyAccountRestrictionDto): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The pool's own "everything is stopped" error.
|
|
57
|
+
*
|
|
58
|
+
* Read structurally (by `name`) rather than by `instanceof`: the class lives in
|
|
59
|
+
* the pool module this file may not import, and a plugin build that loaded the
|
|
60
|
+
* pool and the adapter through two module instances would fail an `instanceof`
|
|
61
|
+
* check that the name comparison passes.
|
|
62
|
+
*/
|
|
63
|
+
export interface WorkBuddyPoolPausedErrorLike extends Error {
|
|
64
|
+
name: 'WorkBuddyPoolPausedError';
|
|
65
|
+
/** Why the whole pool is stopped; composed by the host, never a token. */
|
|
66
|
+
pauseReason?: string;
|
|
67
|
+
/** Unix milliseconds the pause lifts on its own, when it does. */
|
|
68
|
+
pausedUntil?: number;
|
|
69
|
+
}
|
|
70
|
+
/** Whether one thrown value is the pool's whole-pool pause. */
|
|
71
|
+
export declare function isPoolPausedError(error: unknown): error is WorkBuddyPoolPausedErrorLike;
|
|
72
|
+
/**
|
|
73
|
+
* Which of the account's models the picker may offer.
|
|
74
|
+
*
|
|
75
|
+
* The stored list is kept relative to what the ACCOUNT can serve, and the
|
|
76
|
+
* shipped default is not a stored preference: a user who never visited the
|
|
77
|
+
* picker has exactly the shipped defaults stored, and that state has to mean
|
|
78
|
+
* "everything this account can serve" — otherwise a model the catalog gained
|
|
79
|
+
* after the last visit would be hidden from someone who never hid it.
|
|
80
|
+
*/
|
|
81
|
+
export declare function resolveEnabledModelIds(stored: readonly string[], available: readonly string[], enabled?: boolean): string[];
|
|
82
|
+
/** Most system texts this process remembers (FIFO beyond it). */
|
|
83
|
+
export declare const REFUSED_SYSTEM_MEMORY_LIMIT = 256;
|
|
84
|
+
/** Remember one refused system text, evicting the oldest past the limit. */
|
|
85
|
+
export declare function rememberRefusedSystemKey(key: string): void;
|
|
86
|
+
/** Whether this process has already been refused for that system text. */
|
|
87
|
+
export declare function refusedSystemKeyKnown(key: string): boolean;
|
|
88
|
+
/** How many system texts are remembered (test and diagnostics seam). */
|
|
89
|
+
export declare function refusedSystemKeyCount(): number;
|
|
90
|
+
/** Forget every remembered refusal (test seam; never called by the adapter). */
|
|
91
|
+
export declare function clearRefusedSystemKeys(): void;
|
|
92
|
+
export interface WorkBuddyAdapterOptions {
|
|
93
|
+
/**
|
|
94
|
+
* Per-account daily token counters behind the local guardrails.
|
|
95
|
+
*
|
|
96
|
+
* Absent means the guardrails cannot be evaluated, so a deployment without it
|
|
97
|
+
* never refuses a request for a reason nothing is counting.
|
|
98
|
+
*/
|
|
99
|
+
usageLedger?: WorkBuddyUsageLedger;
|
|
100
|
+
fetchFn?: typeof fetch;
|
|
101
|
+
attachments?: AttachmentImageReader;
|
|
102
|
+
/** Live catalog loader seam; defaults to the gateway `/v3/config` call. */
|
|
103
|
+
loadCatalog?: (credentials: WorkBuddyCredentials) => Promise<WorkBuddyModelEntry[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Multi-account pool this adapter rotates through.
|
|
106
|
+
*
|
|
107
|
+
* Absent leaves the line on its single-credential path, which is what the
|
|
108
|
+
* headless tests and any caller that predates the pool use.
|
|
109
|
+
*/
|
|
110
|
+
accountPool?: WorkBuddyAccountPool;
|
|
111
|
+
}
|
|
112
|
+
export declare class WorkBuddyAdapter extends LlmAdapter {
|
|
113
|
+
private readonly store;
|
|
114
|
+
private readonly modelSettings;
|
|
115
|
+
private readonly preferences?;
|
|
116
|
+
private readonly options;
|
|
117
|
+
/** Null keeps the pre-pool single-credential path. */
|
|
118
|
+
private readonly accountPool;
|
|
119
|
+
constructor(store?: FileCredentialStore, modelSettings?: FileModelSettingsStore, preferences?: WorkBuddyPreferenceStore | undefined, options?: WorkBuddyAdapterOptions);
|
|
120
|
+
providerInfo(provider: string): LlmProviderInfo;
|
|
121
|
+
providerRetryPolicy(): ResolvedRetryPolicy;
|
|
122
|
+
imageRequestPricing(): undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Request version the harness should hand this route for one image.
|
|
125
|
+
*
|
|
126
|
+
* This is the other half of the request image budget and it has to come from
|
|
127
|
+
* the same place: the shared kernel decides the target (long edge 1024,
|
|
128
|
+
* 256 KiB per image) and the shared budget decides what still fits, so a
|
|
129
|
+
* mapper cannot ask for a target the harness does not produce, and cannot
|
|
130
|
+
* send an image the kernel already paid to downscale. Answering undefined
|
|
131
|
+
* here used to mean send-as-stored while the mapper applied its own private
|
|
132
|
+
* 12 MB ceiling, which is exactly the drift this pairing removes.
|
|
133
|
+
*/
|
|
134
|
+
imageRequestTarget(_provider: string, _model: string, image: ImageAttachmentRef): {
|
|
135
|
+
width: number;
|
|
136
|
+
height: number;
|
|
137
|
+
maxBytes: number;
|
|
138
|
+
};
|
|
139
|
+
private settings;
|
|
140
|
+
private credentials;
|
|
141
|
+
/**
|
|
142
|
+
* Catalog for the picker: the live gateway listing when reachable, the
|
|
143
|
+
* shipped table otherwise.
|
|
144
|
+
*
|
|
145
|
+
* The gateway is the authority on capabilities, so its answer replaces the
|
|
146
|
+
* fallback rather than merging with it — a model whose context window changed
|
|
147
|
+
* upstream must not keep a stale local value.
|
|
148
|
+
*/
|
|
149
|
+
private catalog;
|
|
150
|
+
/**
|
|
151
|
+
* Models the picker may offer.
|
|
152
|
+
*
|
|
153
|
+
* The catalog is filtered by the account's own region: asking a region for a
|
|
154
|
+
* model it does not serve answers 400 `code 11102`, so offering one would
|
|
155
|
+
* hand the user a model that cannot work.
|
|
156
|
+
*/
|
|
157
|
+
listModels(provider?: string): Promise<readonly LlmModelInfo[]>;
|
|
158
|
+
resolveModel(provider: string, modelId: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
|
|
159
|
+
prepareCall(provider: string, model: string, signal?: AbortSignal): Promise<PreparedAdapterCall>;
|
|
160
|
+
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
161
|
+
/**
|
|
162
|
+
* Effort this request should carry, or `undefined` to send none.
|
|
163
|
+
*
|
|
164
|
+
* Order: the caller's explicit choice, then the user's configured level, then
|
|
165
|
+
* the level the gateway catalog declares for this model. The last step
|
|
166
|
+
* matters because the endpoint returns an **empty `reasoning_content`** when
|
|
167
|
+
* no `reasoning_effort` is present, even for a reasoning-only model: measured
|
|
168
|
+
* on `deepseek-v4.1-flash`, the same prompt yields 0 reasoning characters
|
|
169
|
+
* with no field and 130-215 with one. Omitting it therefore silently drops
|
|
170
|
+
* the model's thinking instead of letting the provider pick, so the catalog's
|
|
171
|
+
* own default (which is what the official CLI sends) is materialized here.
|
|
172
|
+
*
|
|
173
|
+
* A candidate the model does not accept is discarded rather than sent, since
|
|
174
|
+
* the endpoint rejects an unsupported level with `code 11150`.
|
|
175
|
+
*/
|
|
176
|
+
/**
|
|
177
|
+
* Accounts the LOCAL guardrails refuse for this model right now.
|
|
178
|
+
*
|
|
179
|
+
* Reads only numbers this plugin already owns — the billing snapshot's
|
|
180
|
+
* remaining credits and this line's own token counters — so it never becomes a
|
|
181
|
+
* second, disagreeing source of truth about the upstream allowance.
|
|
182
|
+
*/
|
|
183
|
+
private guardrailBlockedAccounts;
|
|
184
|
+
private effortFor;
|
|
185
|
+
private requestStream;
|
|
186
|
+
/**
|
|
187
|
+
* Re-read the stored credential, for a token another process may have written.
|
|
188
|
+
*
|
|
189
|
+
* The desktop app and any sibling plugin share this directory, and a token
|
|
190
|
+
* written there is already the newest one available: refreshing over it would
|
|
191
|
+
* rotate the account's refresh token out from under whoever signed in last.
|
|
192
|
+
* A failed read answers null — it is a fallback, not a verdict.
|
|
193
|
+
*/
|
|
194
|
+
private rereadCredential;
|
|
195
|
+
/**
|
|
196
|
+
* Count this request's billed tokens off its usage frame.
|
|
197
|
+
*
|
|
198
|
+
* Both protocols send exactly one usage frame at the end; the cache counts are
|
|
199
|
+
* added back because the aggregate the surfaces report excludes them, so a
|
|
200
|
+
* cached turn would otherwise be recorded as almost free.
|
|
201
|
+
*/
|
|
202
|
+
private countedChunks;
|
|
203
|
+
/**
|
|
204
|
+
* Read one SSE body into chunks, protocol-agnostically.
|
|
205
|
+
*
|
|
206
|
+
* Bytes on the wire are the liveness signal: a heartbeat or status frame that
|
|
207
|
+
* produces no displayable chunk still proves the connection is alive, so the
|
|
208
|
+
* watchdog timer is reset at the transport layer, not at the parser.
|
|
209
|
+
*/
|
|
210
|
+
private drainStream;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* The failure a 11140 is reported as.
|
|
214
|
+
*
|
|
215
|
+
* Account-scoped, so it is classified apart from every model-scoped refusal: the
|
|
216
|
+
* message says the ACCOUNT is barred (not that a model is unavailable, not that
|
|
217
|
+
* a quota window is full), because the fix is a different account or a release
|
|
218
|
+
* from the service, and no retry can help.
|
|
219
|
+
*/
|
|
220
|
+
export declare function accountRestrictedFailure(detail: string, status: number): LlmError;
|
|
221
|
+
/**
|
|
222
|
+
* Map one failed HTTP response onto a DSH failure.
|
|
223
|
+
*
|
|
224
|
+
* The subscription reports its own conditions inside a JSON `code` while the
|
|
225
|
+
* status line stays generic, so the body is read for the specific cases the
|
|
226
|
+
* status alone cannot express — notably the quota signal, whose message carries
|
|
227
|
+
* the instant the allowance resets.
|
|
228
|
+
*/
|
|
229
|
+
export declare function classifyFailure(status: number, detail: string, headers?: Headers): LlmError;
|
|
230
|
+
/**
|
|
231
|
+
* The reset instant a quota refusal names, as a delay from now.
|
|
232
|
+
*
|
|
233
|
+
* A 24h allowance that is exhausted answers 429 / `code 6004` with the wall
|
|
234
|
+
* clock it lifts — but only in the MESSAGE, never in a header, and in two
|
|
235
|
+
* realm-specific wordings (measured: intl "… resets at 2026-09-20 10:50:48
|
|
236
|
+
* UTC+8", cn "… 将在 2026-10-09 14:44:59 UTC+8 重置"). Reading the status alone
|
|
237
|
+
* therefore loses the only fact that says how long the account is out, and the
|
|
238
|
+
* pool parks a 24-hour limit for five minutes before trying it again.
|
|
239
|
+
*
|
|
240
|
+
* Deliberately tolerant, in the same direction as their gateway: an unparseable
|
|
241
|
+
* body yields `undefined` (callers keep their default cooldown) rather than an
|
|
242
|
+
* error, because this runs on a failure path. An absent `UTC±h` marker means
|
|
243
|
+
* UTC, which is how the sibling implementation reads it too.
|
|
244
|
+
*/
|
|
245
|
+
export declare function readRateLimitReset(detail: string, now?: number): number | undefined;
|
|
246
|
+
/** Read the subscription's own numeric error code out of a response body. */
|
|
247
|
+
export declare function readErrorCode(detail: string): number | null;
|
|
248
|
+
export { PROVIDER_ID, PROVIDER_NAME };
|
|
249
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/host/workbuddy/adapter.ts"],"names":[],"mappings":"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"}
|