dsh-workbuddy-xdpool 1.7.1 → 1.7.3
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 +146 -169
- package/lib/bin.js +286 -54
- package/lib/client.js +90 -16
- package/lib/index.d.ts +726 -550
- package/lib/index.js +384 -69
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -288,6 +288,13 @@ interface UpstreamClientOptions {
|
|
|
288
288
|
fetchImpl?: typeof fetch;
|
|
289
289
|
/** Client version string sent to the upstream. */
|
|
290
290
|
clientVersion?: string;
|
|
291
|
+
/**
|
|
292
|
+
* Override the catalog-fetch backoff, in milliseconds.
|
|
293
|
+
*
|
|
294
|
+
* Tests set this to `[]` (or tiny values) so a retry case does not spend real
|
|
295
|
+
* seconds sleeping. Production uses {@link CATALOG_RETRY_BACKOFF_MS}.
|
|
296
|
+
*/
|
|
297
|
+
catalogRetryBackoffMs?: readonly number[];
|
|
291
298
|
}
|
|
292
299
|
/** Region for a login domain; an empty domain means CN (matching upstream tooling). */
|
|
293
300
|
/** The two gateways WorkBuddy serves: the domestic one and the international one. */
|
|
@@ -421,6 +428,19 @@ export declare function buddyAppEvents(buddyId: string, buddyName: string): Reco
|
|
|
421
428
|
export declare class WorkBuddyUpstreamClient {
|
|
422
429
|
private readonly fetchImpl;
|
|
423
430
|
private readonly clientVersion;
|
|
431
|
+
/** Backoff ladder for `fetchModels`; empty means a single attempt. */
|
|
432
|
+
private readonly catalogRetryBackoffMs;
|
|
433
|
+
/**
|
|
434
|
+
* Optional logger for retry notices.
|
|
435
|
+
*
|
|
436
|
+
* Set by the host so a retry is visible in the log with its attempt count —
|
|
437
|
+
* without it, a retry that eventually succeeds is invisible, and an operator
|
|
438
|
+
* debugging "why was the catalog slow" has nothing to look at.
|
|
439
|
+
*/
|
|
440
|
+
logger: {
|
|
441
|
+
warn?(...args: unknown[]): void;
|
|
442
|
+
info?(...args: unknown[]): void;
|
|
443
|
+
} | undefined;
|
|
424
444
|
constructor(options?: UpstreamClientOptions);
|
|
425
445
|
/**
|
|
426
446
|
* Normalize an OpenAI chat-completions body for the WorkBuddy upstream:
|
|
@@ -467,6 +487,16 @@ export declare class WorkBuddyUpstreamClient {
|
|
|
467
487
|
* below is common to the two branches.
|
|
468
488
|
*/
|
|
469
489
|
fetchModels(credential: WorkBuddyCredential, signal?: AbortSignal): Promise<readonly WorkBuddyUpstreamModel[]>;
|
|
490
|
+
/**
|
|
491
|
+
* One catalog attempt, without retries.
|
|
492
|
+
*
|
|
493
|
+
* Split out so {@link fetchModels} can retry it: the failure this guards
|
|
494
|
+
* against is a startup network hiccup, where several independent components
|
|
495
|
+
* see `fetch failed` inside the same second and the very next request
|
|
496
|
+
* succeeds — exactly the case a single attempt turns into "the user's model
|
|
497
|
+
* list is missing half its entries for the rest of the session".
|
|
498
|
+
*/
|
|
499
|
+
private fetchModelsOnce;
|
|
470
500
|
/** Read-only credits query, aggregated by package. Does not consume credits. */
|
|
471
501
|
fetchCredits(credential: WorkBuddyCredential): Promise<WorkBuddyCredits>;
|
|
472
502
|
/** Query today's check-in status without changing account state. */
|
|
@@ -1063,92 +1093,520 @@ export declare class WorkBuddyAccountPool {
|
|
|
1063
1093
|
};
|
|
1064
1094
|
}
|
|
1065
1095
|
//#endregion
|
|
1066
|
-
//#region src/
|
|
1067
|
-
/**
|
|
1068
|
-
|
|
1096
|
+
//#region src/status-paths.d.ts
|
|
1097
|
+
/**
|
|
1098
|
+
* Node-free constants and types shared by the Host and browser halves of the
|
|
1099
|
+
* WorkBuddy XD Pool settings card.
|
|
1100
|
+
*
|
|
1101
|
+
* Pool's runtime state already lives in `src/status.ts` (`buildStatus` /
|
|
1102
|
+
* `WorkBuddyStatus`); this module only carves the cross-domain (Host→browser)
|
|
1103
|
+
* JSON document into a shape that stays token-free and matches what the
|
|
1104
|
+
* browser card renders. Route paths are plugin-owned and mounted on the Host's
|
|
1105
|
+
* same-origin web server (see `src/web-status.ts`).
|
|
1106
|
+
*
|
|
1107
|
+
* @module dsh-workbuddy-xdpool/status-paths
|
|
1108
|
+
*/
|
|
1109
|
+
/** Plugin-owned read-only pool status endpoint (account rows + models + shim). */
|
|
1110
|
+
export declare const POOL_STATUS_PATH = "/plugins/dsh-workbuddy-xdpool/status";
|
|
1111
|
+
/** Plugin-owned local account rescan endpoint (re-read desktop snapshots). */
|
|
1112
|
+
export declare const POOL_RESCAN_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/rescan";
|
|
1113
|
+
/** Plugin-owned cooldown reset endpoint (clear all 429 cooldowns). */
|
|
1114
|
+
export declare const POOL_RESET_COOLDOWN_PATH = "/plugins/dsh-workbuddy-xdpool/cooldowns/reset";
|
|
1115
|
+
/** Plugin-owned daily check-in action endpoint (claim today's reward). */
|
|
1116
|
+
export declare const POOL_CHECKIN_PATH = "/plugins/dsh-workbuddy-xdpool/checkin";
|
|
1117
|
+
/** Plugin-owned model-selection save endpoint (writes the settings section). */
|
|
1118
|
+
export declare const POOL_MODELS_SAVE_PATH = "/plugins/dsh-workbuddy-xdpool/models/save";
|
|
1119
|
+
/**
|
|
1120
|
+
* Throw one account out of the pool for good, or take it back.
|
|
1121
|
+
*
|
|
1122
|
+
* Separate from the disable route because the semantics differ: disabling is a
|
|
1123
|
+
* rotation preference the account survives, ignoring survives the account.
|
|
1124
|
+
*/
|
|
1125
|
+
export declare const POOL_ACCOUNT_IGNORE_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/ignored";
|
|
1126
|
+
/** Run one automation job immediately, so the card can verify it on demand. */
|
|
1127
|
+
export declare const POOL_AUTOMATION_RUN_PATH = "/plugins/dsh-workbuddy-xdpool/automation/run";
|
|
1128
|
+
/** Set or clear one account's reserved-credit floor. */
|
|
1129
|
+
export declare const POOL_CREDIT_RESERVE_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/credit-reserve";
|
|
1130
|
+
/** One account's row, token-free. */
|
|
1131
|
+
interface PoolWebAccount {
|
|
1132
|
+
id: string;
|
|
1133
|
+
label: string;
|
|
1134
|
+
nickname?: string;
|
|
1135
|
+
domain: string;
|
|
1136
|
+
/** ISO timestamp; absent when the credential carries no expiry. */
|
|
1137
|
+
expiresAt?: string;
|
|
1138
|
+
/** Account-wide cooldown (every model blocked); only after a no-model penalize. */
|
|
1139
|
+
cooling: boolean;
|
|
1140
|
+
/** ISO timestamp when the account-wide 429 cooldown lifts; only while cooling. */
|
|
1141
|
+
cooldownUntil?: string;
|
|
1142
|
+
/**
|
|
1143
|
+
* Per-model cooldowns currently active. The account is NOT `cooling` while a
|
|
1144
|
+
* model is limited — its other models still serve — but each entry tells the
|
|
1145
|
+
* card which model is out until when (e.g. `hy4-preview` cooling to 10:14,
|
|
1146
|
+
* `hy3` normal).
|
|
1147
|
+
*/
|
|
1148
|
+
modelCooldowns?: ReadonlyArray<{
|
|
1149
|
+
modelId: string;
|
|
1150
|
+
until: string;
|
|
1151
|
+
}>;
|
|
1152
|
+
/**
|
|
1153
|
+
* Whether the user switched this account off. A disabled account never
|
|
1154
|
+
* serves a request, but it stays listed so the card can switch it back on.
|
|
1155
|
+
*/
|
|
1156
|
+
disabled: boolean;
|
|
1157
|
+
rateLimitHits: number;
|
|
1158
|
+
/**
|
|
1159
|
+
* Credits the user asked to keep for this account. The pool stops picking the
|
|
1160
|
+
* account once its balance reaches the reserve, so this many credits survive.
|
|
1161
|
+
* 0 means the account may be spent down as before.
|
|
1162
|
+
*/
|
|
1163
|
+
creditReserve: number;
|
|
1164
|
+
/**
|
|
1165
|
+
* Whether the account is held back purely by its reserve right now. Kept
|
|
1166
|
+
* distinct from `cooling`: a reserved account is healthy and simply
|
|
1167
|
+
* protected, which is a different thing to tell the user than rate-limited.
|
|
1168
|
+
*/
|
|
1169
|
+
reserved: boolean;
|
|
1170
|
+
/**
|
|
1171
|
+
* What the automation earned for this account today. Absent when it earned
|
|
1172
|
+
* nothing (or the automation never ran for it), so the card can stay quiet
|
|
1173
|
+
* instead of printing a row of zeroes.
|
|
1174
|
+
*/
|
|
1175
|
+
automationToday?: PoolWebAutomationEarnings;
|
|
1176
|
+
/** ISO timestamp of the last successful use (best-effort pool bookkeeping). */
|
|
1177
|
+
lastUsedAt?: string;
|
|
1178
|
+
/** Aggregated credit summary for the account, read-only. */
|
|
1179
|
+
credits?: PoolWebCredits;
|
|
1180
|
+
creditsError?: string;
|
|
1181
|
+
/**
|
|
1182
|
+
* Today's check-in state for this account, read-only. Present only when the
|
|
1183
|
+
* per-account check-in probe succeeded and the program is active. The card
|
|
1184
|
+
* renders one claim button per account, so a multi-account pool can collect
|
|
1185
|
+
* every account's daily reward without switching accounts by hand.
|
|
1186
|
+
*/
|
|
1187
|
+
checkin?: PoolWebCheckin;
|
|
1188
|
+
checkinError?: string;
|
|
1189
|
+
}
|
|
1190
|
+
/** One credit package (as surfaced by the pool's upstream client), node-free. */
|
|
1191
|
+
interface PoolWebCreditPackage {
|
|
1192
|
+
packageName: string;
|
|
1193
|
+
remain?: number;
|
|
1194
|
+
size?: number;
|
|
1195
|
+
/** CapacityType 4 — refreshed each cycle and never expires. */
|
|
1196
|
+
monthly?: boolean;
|
|
1197
|
+
/** Next cycle refresh point, ms. */
|
|
1198
|
+
cycleRefreshMs?: number;
|
|
1199
|
+
/** One-off expiry, ms. */
|
|
1200
|
+
expiresAtMs?: number;
|
|
1201
|
+
}
|
|
1202
|
+
/** Aggregated credit answer the card renders under one account. */
|
|
1203
|
+
interface PoolWebCredits {
|
|
1204
|
+
total?: number;
|
|
1205
|
+
packages: readonly PoolWebCreditPackage[];
|
|
1206
|
+
/** Credits expiring within 3 days. */
|
|
1207
|
+
expiringSoon?: number;
|
|
1208
|
+
/** When the nearest package expires, ms. */
|
|
1209
|
+
nearestExpiryMs?: number;
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Daily check-in state the card renders under one account's credits. Mirrors
|
|
1213
|
+
* the upstream activity endpoint, minus anything the browser does not need.
|
|
1214
|
+
*/
|
|
1215
|
+
interface PoolWebCheckin {
|
|
1216
|
+
/** The activity is running; a claim button is offered only while true. */
|
|
1217
|
+
active: boolean;
|
|
1218
|
+
/** Already collected today — the button renders as a done state. */
|
|
1219
|
+
todayCheckedIn: boolean;
|
|
1220
|
+
/** Consecutive days checked in. */
|
|
1221
|
+
streakDays: number;
|
|
1222
|
+
/** Credits a single day grants. */
|
|
1223
|
+
dailyCredit: number;
|
|
1224
|
+
/** Credits collected today (0 before claiming). */
|
|
1225
|
+
todayCredit: number;
|
|
1226
|
+
/** Today is a streak milestone day. */
|
|
1227
|
+
isStreakDay: boolean;
|
|
1228
|
+
/** The day count the next milestone lands on. */
|
|
1229
|
+
nextStreakDay: number;
|
|
1230
|
+
/** Bonus credits granted on a milestone day. */
|
|
1231
|
+
streakBonusCredit: number;
|
|
1232
|
+
}
|
|
1233
|
+
/** Result of one claim, so the card can confirm what was collected. */
|
|
1234
|
+
interface PoolWebCheckinClaim {
|
|
1235
|
+
credit: number;
|
|
1236
|
+
streakDays: number;
|
|
1237
|
+
isStreakDay: boolean;
|
|
1238
|
+
}
|
|
1239
|
+
/** One model the pool exposes to DSH, with cost / free tags. */
|
|
1240
|
+
interface PoolWebModel {
|
|
1069
1241
|
id: string;
|
|
1070
|
-
/** Display name; the multiplier is appended for the picker. */
|
|
1071
1242
|
name: string;
|
|
1072
|
-
|
|
1073
|
-
maxOutputTokens: number;
|
|
1074
|
-
/** Relative credit cost, e.g. 0.79 for `x0.79`. */
|
|
1243
|
+
/** Relative credit cost, e.g. 0.79 for x0.79. */
|
|
1075
1244
|
multiplier?: number;
|
|
1076
|
-
/** Upstream-declared thinking levels. */
|
|
1077
|
-
supportedEfforts?: readonly string[];
|
|
1078
|
-
supportsImages: boolean;
|
|
1079
1245
|
/** Upstream tags: free / limited-free / night-discount. */
|
|
1080
1246
|
tags?: readonly string[];
|
|
1247
|
+
/** Effective image support after the user's per-model toggle. */
|
|
1248
|
+
supportsImages: boolean;
|
|
1249
|
+
/** Effective context window after the user's budget cap. */
|
|
1250
|
+
contextWindow: number;
|
|
1251
|
+
/** The window the upstream advertises, before any cap. */
|
|
1252
|
+
nativeContextWindow: number;
|
|
1253
|
+
/** Upstream output ceiling, so the card can show both limits. */
|
|
1254
|
+
maxOutputTokens: number;
|
|
1255
|
+
/** Thinking levels the upstream declares, when it declares any. */
|
|
1256
|
+
supportedEfforts?: readonly string[];
|
|
1257
|
+
/** Whether this model is currently enabled in the picker. */
|
|
1258
|
+
enabled: boolean;
|
|
1081
1259
|
}
|
|
1082
1260
|
/**
|
|
1083
|
-
*
|
|
1084
|
-
* upstream cannot be reached.
|
|
1261
|
+
* Body of the account ignore/unignore route: exactly one account per request.
|
|
1085
1262
|
*
|
|
1086
|
-
*
|
|
1087
|
-
*
|
|
1088
|
-
*
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1263
|
+
* `ignored: true` throws the account out of the pool for good (its credential is
|
|
1264
|
+
* not even read on the next scan, and a fresh desktop sign-in will not bring it
|
|
1265
|
+
* back). `false` restores it, at which point the next scan discovers it again.
|
|
1266
|
+
*/
|
|
1267
|
+
interface PoolWebAccountIgnore {
|
|
1268
|
+
/** Pool account id, as reported in `PoolWebAccount.id`. */
|
|
1269
|
+
accountId: string;
|
|
1270
|
+
/** `true` ignores the account permanently; `false` takes it back. */
|
|
1271
|
+
ignored: boolean;
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* One account the user has thrown out of the pool.
|
|
1092
1275
|
*
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1276
|
+
* Kept on the status document so the card can list what was ignored and offer a
|
|
1277
|
+
* way back: without that, "ignored" is a one-way door the user cannot inspect or
|
|
1278
|
+
* undo from the UI, which is how a hidden list becomes a support burden.
|
|
1095
1279
|
*/
|
|
1096
|
-
|
|
1097
|
-
/**
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
/**
|
|
1102
|
-
|
|
1103
|
-
current(): readonly WorkBuddyModelInfo[];
|
|
1104
|
-
/**
|
|
1105
|
-
* The models DSH should actually offer, after applying the user's selection:
|
|
1106
|
-
* disabled models are dropped, an explicit image list overrides the upstream
|
|
1107
|
-
* capability flag, and a per-model budget caps the advertised window.
|
|
1108
|
-
*
|
|
1109
|
-
* An absent `enabledModelIds` means "everything" — a fresh install with no
|
|
1110
|
-
* saved selection must not present an empty picker.
|
|
1111
|
-
*/
|
|
1112
|
-
visible(): readonly WorkBuddyModelInfo[];
|
|
1113
|
-
/** Replace the catalog and notify the adapter to rebuild its model list. */
|
|
1114
|
-
update(models: readonly WorkBuddyModelInfo[]): void;
|
|
1115
|
-
/** Restore the static fallback, e.g. when the upstream stops answering. */
|
|
1116
|
-
reset(): void;
|
|
1117
|
-
/** Replace the user's selection; the adapter rebuilds from `visible()`. */
|
|
1118
|
-
applySelection(selection: ModelSelection): void;
|
|
1119
|
-
/** The selection currently in force, for the card's save round-trip. */
|
|
1120
|
-
currentSelection(): ModelSelection;
|
|
1121
|
-
onChange(listener: () => void): () => void;
|
|
1122
|
-
find(id: string): WorkBuddyModelInfo | undefined;
|
|
1123
|
-
/** Replace the catalog from the live upstream list; keeps the fallback if empty. */
|
|
1124
|
-
updateFromUpstream(models: readonly WorkBuddyUpstreamModel[]): void;
|
|
1125
|
-
private notify;
|
|
1280
|
+
interface PoolWebIgnoredAccount {
|
|
1281
|
+
/** Pool account id, the same key `PoolWebAccount.id` uses. */
|
|
1282
|
+
id: string;
|
|
1283
|
+
/** Human label captured at ignore time, so the row reads without a rescan. */
|
|
1284
|
+
label: string;
|
|
1285
|
+
/** ISO timestamp of when it was ignored. */
|
|
1286
|
+
ignoredAt: string;
|
|
1126
1287
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
/** Absent = every model in the catalog is offered. */
|
|
1288
|
+
interface PoolWebModelSelection {
|
|
1289
|
+
/** Absent = every model is enabled. */
|
|
1130
1290
|
enabledModelIds?: readonly string[];
|
|
1131
1291
|
/** Absent = each model follows its upstream image capability. */
|
|
1132
1292
|
imageModelIds?: readonly string[];
|
|
1133
1293
|
/** Per-model context-window cap, keyed by model id. */
|
|
1134
1294
|
contextBudgets?: Readonly<Record<string, number | undefined>>;
|
|
1135
1295
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1296
|
+
/** The JSON document the pool card renders. */
|
|
1297
|
+
interface PoolWebStatus {
|
|
1298
|
+
ok: boolean;
|
|
1299
|
+
accounts: readonly PoolWebAccount[];
|
|
1300
|
+
/** The next account the pool would use (rotation cursor). */
|
|
1301
|
+
activeAccountId?: string;
|
|
1302
|
+
cooling: number;
|
|
1303
|
+
models: readonly PoolWebModel[];
|
|
1304
|
+
/** The saved selection the card diffs its draft against. */
|
|
1305
|
+
selection: PoolWebModelSelection;
|
|
1306
|
+
/**
|
|
1307
|
+
* How the pool spreads requests: `priority` drains one account before
|
|
1308
|
+
* moving on, `round-robin` splits the spend evenly.
|
|
1309
|
+
*/
|
|
1310
|
+
distribution: PoolDistribution;
|
|
1311
|
+
/** Which region this document describes. */
|
|
1312
|
+
region: PoolRegion;
|
|
1313
|
+
/** Every region holding at least one account, in display order. */
|
|
1314
|
+
regions: readonly PoolRegion[];
|
|
1315
|
+
shim: {
|
|
1316
|
+
running: boolean;
|
|
1317
|
+
baseUrl?: string;
|
|
1318
|
+
};
|
|
1319
|
+
/** Daily-points automation state, so the card can show what ran and when. */
|
|
1320
|
+
automation: PoolWebAutomation;
|
|
1321
|
+
/** Per-account credit floors currently in force, keyed by account id. */
|
|
1322
|
+
creditReserves: Readonly<Record<string, number>>;
|
|
1323
|
+
/**
|
|
1324
|
+
* Accounts thrown out of the pool, in the order they were ignored.
|
|
1325
|
+
*
|
|
1326
|
+
* Reported so the card can show the list and offer a way back. These accounts
|
|
1327
|
+
* are NOT in `accounts`: they are filtered out before their credentials are
|
|
1328
|
+
* read, which is the whole point of the feature.
|
|
1329
|
+
*/
|
|
1330
|
+
ignored: readonly PoolWebIgnoredAccount[];
|
|
1331
|
+
/**
|
|
1332
|
+
* Where THIS region's model list came from.
|
|
1333
|
+
*
|
|
1334
|
+
* `live` = fetched from the gateway (or a cached fetch survived a restart).
|
|
1335
|
+
* `fallback` = the built-in static table, which means the startup fetch
|
|
1336
|
+
* failed and the user is looking at a SHORTER, possibly stale roster — models
|
|
1337
|
+
* they had enabled can be missing from it entirely.
|
|
1338
|
+
*
|
|
1339
|
+
* Surfaced because the failure used to be log-only: the picker quietly lost
|
|
1340
|
+
* half its entries and nothing on screen said why, so it read as "the plugin
|
|
1341
|
+
* deleted my models".
|
|
1342
|
+
*/
|
|
1343
|
+
catalogSource?: PoolWebCatalogSource;
|
|
1344
|
+
/** When the live catalog was last successfully fetched, ISO. */
|
|
1345
|
+
catalogUpdatedAt?: string;
|
|
1346
|
+
/** Why the last fetch failed, when it did. Redacted and length-capped. */
|
|
1347
|
+
catalogError?: string;
|
|
1348
|
+
}
|
|
1349
|
+
/** How a region's model list was obtained. */
|
|
1350
|
+
type PoolWebCatalogSource = 'live' | 'fallback';
|
|
1351
|
+
/** One automation job's last run, as shown on the card. */
|
|
1352
|
+
interface PoolWebAutomationJob {
|
|
1353
|
+
/** `YYYY-MM-DD` of the last run in this process, if it has run. */
|
|
1354
|
+
lastRunDate?: string;
|
|
1355
|
+
/**
|
|
1356
|
+
* Epoch ms of the last run, so the card can show the TIME.
|
|
1357
|
+
*
|
|
1358
|
+
* Carried because a date-only stamp cannot tell one run from eight: every
|
|
1359
|
+
* repeat inside the same day rendered as the identical `2026-09-28 · 2`,
|
|
1360
|
+
* which is what kept a "re-runs every hour" defect invisible on the card.
|
|
1361
|
+
*/
|
|
1362
|
+
lastRunAtMs?: number;
|
|
1363
|
+
/**
|
|
1364
|
+
* Configured slots consumed today, as `YYYY-MM-DDTHH`.
|
|
1365
|
+
*
|
|
1366
|
+
* Shown so "which of today's hours already ran" is answerable at a glance
|
|
1367
|
+
* rather than inferred from a counter.
|
|
1368
|
+
*/
|
|
1369
|
+
firedSlots?: readonly string[];
|
|
1370
|
+
/** Accounts that finished without error on the last run. */
|
|
1371
|
+
ok: number;
|
|
1372
|
+
/** Accounts that failed on the last run (each one skipped, the run continued). */
|
|
1373
|
+
failed: number;
|
|
1374
|
+
/** Credits claimed by the task job on the last run. */
|
|
1375
|
+
credit: number;
|
|
1376
|
+
/** Energy claimed by the task job on the last run. */
|
|
1377
|
+
energy: number;
|
|
1378
|
+
/** Tasks claimed by the task job on the last run. */
|
|
1379
|
+
claimed: number;
|
|
1380
|
+
/** One-line summary of the last run. */
|
|
1381
|
+
message?: string;
|
|
1382
|
+
/**
|
|
1383
|
+
* What the last run actually did, in the words of the task board.
|
|
1384
|
+
*
|
|
1385
|
+
* `message` is a count; this is the list a person can check off, which is
|
|
1386
|
+
* what turns a row from "it ran" into "it did the things I care about".
|
|
1387
|
+
*/
|
|
1388
|
+
detail?: readonly string[];
|
|
1389
|
+
/** A pending milestone worth naming, e.g. the next streak tier countdown. */
|
|
1390
|
+
progress?: string;
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Automation block on the status document.
|
|
1394
|
+
*
|
|
1395
|
+
* Carries the schedule and each job's last outcome so the card can answer
|
|
1396
|
+
* "is it on, when does it run, and what did it last do" without reaching into
|
|
1397
|
+
* the scheduler itself.
|
|
1398
|
+
*/
|
|
1399
|
+
interface PoolWebAutomation {
|
|
1400
|
+
/** Master switch, mirrored from the saved config. */
|
|
1401
|
+
enabled: boolean;
|
|
1402
|
+
/** Whether the loop is currently running. */
|
|
1403
|
+
running: boolean;
|
|
1404
|
+
/** Configured hours per job, so the card can show the schedule. */
|
|
1405
|
+
checkinHours: readonly number[];
|
|
1406
|
+
reportHours: readonly number[];
|
|
1407
|
+
taskHours: readonly number[];
|
|
1408
|
+
streakHours: readonly number[];
|
|
1409
|
+
travelHours: readonly number[];
|
|
1410
|
+
jobs: {
|
|
1411
|
+
checkin: PoolWebAutomationJob;
|
|
1412
|
+
report: PoolWebAutomationJob;
|
|
1413
|
+
tasks: PoolWebAutomationJob;
|
|
1414
|
+
streak: PoolWebAutomationJob;
|
|
1415
|
+
travel: PoolWebAutomationJob;
|
|
1416
|
+
};
|
|
1417
|
+
/** Claimable tasks seen on the most recent task pass, across accounts. */
|
|
1418
|
+
claimableSeen: number;
|
|
1419
|
+
/**
|
|
1420
|
+
* Whether a manual run is in flight. The card polls this to know when to
|
|
1421
|
+
* stop showing progress and report the result.
|
|
1422
|
+
*/
|
|
1423
|
+
runInProgress: boolean;
|
|
1424
|
+
/**
|
|
1425
|
+
* Per-account credits/energy/tasks the automation earned TODAY, keyed by
|
|
1426
|
+
* account id. An account that earned nothing is simply absent, so the card
|
|
1427
|
+
* can say "nothing yet" instead of showing a bare zero.
|
|
1428
|
+
*/
|
|
1429
|
+
earningsToday: Readonly<Record<string, PoolWebAutomationEarnings>>;
|
|
1430
|
+
}
|
|
1431
|
+
/** Today's automation take for one account. */
|
|
1432
|
+
interface PoolWebAutomationEarnings {
|
|
1433
|
+
/** Credits claimed from the task centre today. */
|
|
1434
|
+
credit: number;
|
|
1435
|
+
/** Energy claimed from the task centre today. */
|
|
1436
|
+
energy: number;
|
|
1437
|
+
/** Tasks claimed today. */
|
|
1438
|
+
claimed: number;
|
|
1439
|
+
/** Credits collected from check-in today. */
|
|
1440
|
+
checkinCredit: number;
|
|
1441
|
+
/** Credits from streak redemption and the lottery today. */
|
|
1442
|
+
bonusCredit: number;
|
|
1443
|
+
/** Credits from buddy adoption and the travel loop today. */
|
|
1444
|
+
travelCredit: number;
|
|
1445
|
+
/** Local date the counters belong to (YYYY-MM-DD). */
|
|
1446
|
+
date: string;
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* The two gateways, matching the provider ids the host registers. `cn` is the
|
|
1450
|
+
* domestic gateway (`copilot.tencent.com` / `codebuddy.cn`); `global` is the
|
|
1451
|
+
* international one (`workbuddy.ai`).
|
|
1452
|
+
*/
|
|
1453
|
+
type PoolRegion = 'cn' | 'global';
|
|
1454
|
+
/** How the pool spreads requests across its accounts. */
|
|
1455
|
+
type PoolDistribution = 'priority' | 'round-robin' | 'balanced';
|
|
1456
|
+
/**
|
|
1457
|
+
* The schedule every automation job falls back to.
|
|
1458
|
+
*
|
|
1459
|
+
* Shared by both halves on purpose. The host uses it when a configured hour
|
|
1460
|
+
* list arrives empty (the settings schema materializes "never configured" into
|
|
1461
|
+
* `[]`), and the card uses it when it writes the `automation` block back, so a
|
|
1462
|
+
* document that already holds an empty list is healed instead of being saved
|
|
1463
|
+
* back as an unrunnable schedule.
|
|
1464
|
+
*
|
|
1465
|
+
* This lives here rather than in `scheduler.ts` because the browser half cannot
|
|
1466
|
+
* import the host module: `scheduler.ts` pulls in `node:crypto` and the whole
|
|
1467
|
+
* upstream client, none of which exists in the browser bundle. Two hand-written
|
|
1468
|
+
* copies would drift, and the drift is invisible — the card would write a
|
|
1469
|
+
* schedule the scheduler does not run.
|
|
1470
|
+
*/
|
|
1471
|
+
export declare const DEFAULT_AUTOMATION_HOURS: {
|
|
1472
|
+
readonly checkin: readonly [9];
|
|
1473
|
+
readonly report: readonly [10];
|
|
1474
|
+
readonly tasks: readonly [11];
|
|
1475
|
+
readonly streak: readonly [12];
|
|
1476
|
+
readonly travel: readonly [9, 21];
|
|
1477
|
+
};
|
|
1478
|
+
//#endregion
|
|
1479
|
+
//#region src/catalog.d.ts
|
|
1480
|
+
/** One model the provider exposes. */
|
|
1481
|
+
interface WorkBuddyModelInfo {
|
|
1482
|
+
id: string;
|
|
1483
|
+
/** Display name; the multiplier is appended for the picker. */
|
|
1484
|
+
name: string;
|
|
1485
|
+
contextWindow: number;
|
|
1486
|
+
maxOutputTokens: number;
|
|
1487
|
+
/** Relative credit cost, e.g. 0.79 for `x0.79`. */
|
|
1488
|
+
multiplier?: number;
|
|
1489
|
+
/** Upstream-declared thinking levels. */
|
|
1490
|
+
supportedEfforts?: readonly string[];
|
|
1491
|
+
supportsImages: boolean;
|
|
1492
|
+
/** Upstream tags: free / limited-free / night-discount. */
|
|
1493
|
+
tags?: readonly string[];
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Static fallback used before the first live catalog fetch, and whenever the
|
|
1497
|
+
* upstream cannot be reached.
|
|
1498
|
+
*
|
|
1499
|
+
* This table is the DOMESTIC (CN) roster, and it is kept in step with what
|
|
1500
|
+
* `copilot.tencent.com` actually advertises. It matters more than a "just in
|
|
1501
|
+
* case" list usually would: a failed startup fetch falls back to it, and the
|
|
1502
|
+
* user sees that as "half my models were deleted" — `deepseek-v4.1-flash`
|
|
1503
|
+
* and friends simply vanishing from the picker, with no visible explanation.
|
|
1504
|
+
*
|
|
1505
|
+
* Every row below was captured from the live endpoint, INCLUDING the window
|
|
1506
|
+
* sizes: the previous version carried a 32K window for `hy3` when the gateway
|
|
1507
|
+
* says 192K, and listed `kimi-k3` under an id the gateway no longer uses
|
|
1508
|
+
* (`kimi-k3-1`). A stale fallback is worse than a short one — it looks
|
|
1509
|
+
* authoritative while being wrong.
|
|
1510
|
+
*
|
|
1511
|
+
* `multiplier: 0` is the gateways' own spelling of "free" (`credits: "x0.00"`),
|
|
1512
|
+
* which is what turns on the free badge.
|
|
1513
|
+
*/
|
|
1514
|
+
export declare const FALLBACK_WORKBUDDY_MODELS: readonly WorkBuddyModelInfo[];
|
|
1515
|
+
/** Live catalog with a static fallback behind it. */
|
|
1516
|
+
export declare class WorkBuddyCatalog {
|
|
1517
|
+
private models;
|
|
1518
|
+
private listeners;
|
|
1519
|
+
/** User's model selection. Empty object = follow the catalog unfiltered. */
|
|
1520
|
+
private selection;
|
|
1521
|
+
/**
|
|
1522
|
+
* Whether `models` came from the gateway or from the static table.
|
|
1523
|
+
*
|
|
1524
|
+
* Tracked so the card can SAY which it is showing. A failed fetch used to be
|
|
1525
|
+
* invisible on screen: the picker simply held fewer models than before, which
|
|
1526
|
+
* the user reasonably read as "the plugin deleted my models" rather than "the
|
|
1527
|
+
* network hiccuped at startup".
|
|
1528
|
+
*/
|
|
1529
|
+
private source;
|
|
1530
|
+
/** When the live list last landed. */
|
|
1531
|
+
private lastUpdatedAt;
|
|
1532
|
+
/** Why the last fetch failed, for display. */
|
|
1533
|
+
private lastError;
|
|
1534
|
+
current(): readonly WorkBuddyModelInfo[];
|
|
1535
|
+
/**
|
|
1536
|
+
* The models DSH should actually offer, after applying the user's selection:
|
|
1537
|
+
* disabled models are dropped, an explicit image list overrides the upstream
|
|
1538
|
+
* capability flag, and a per-model budget caps the advertised window.
|
|
1539
|
+
*
|
|
1540
|
+
* An absent `enabledModelIds` means "everything" — a fresh install with no
|
|
1541
|
+
* saved selection must not present an empty picker.
|
|
1542
|
+
*/
|
|
1543
|
+
visible(): readonly WorkBuddyModelInfo[];
|
|
1544
|
+
/** Replace the catalog and notify the adapter to rebuild its model list. */
|
|
1545
|
+
update(models: readonly WorkBuddyModelInfo[]): void;
|
|
1546
|
+
/** Restore the static fallback, e.g. when the upstream stops answering. */
|
|
1547
|
+
reset(): void;
|
|
1548
|
+
/** Replace the user's selection; the adapter rebuilds from `visible()`. */
|
|
1549
|
+
applySelection(selection: ModelSelection): void;
|
|
1550
|
+
/** The selection currently in force, for the card's save round-trip. */
|
|
1551
|
+
currentSelection(): ModelSelection;
|
|
1552
|
+
/**
|
|
1553
|
+
* Whether this catalog is serving live data or the built-in table.
|
|
1554
|
+
*
|
|
1555
|
+
* `fallback` is not an error state, but it IS a degraded one: the user is
|
|
1556
|
+
* looking at a shorter roster than the gateway offers, so the card says so
|
|
1557
|
+
* and offers a retry instead of letting them wonder where the models went.
|
|
1558
|
+
*/
|
|
1559
|
+
currentSource(): PoolWebCatalogSource;
|
|
1560
|
+
/**
|
|
1561
|
+
* When the live list last landed, if it ever did.
|
|
1562
|
+
*
|
|
1563
|
+
* Named `catalogUpdatedAt()` rather than `updatedAt()` because the class
|
|
1564
|
+
* already had an `updatedAt` member; two members of the same name is a
|
|
1565
|
+
* compile error, and the awkwardness is a useful signal that the concept is
|
|
1566
|
+
* "when THIS catalog was refreshed", not a generic timestamp.
|
|
1567
|
+
*/
|
|
1568
|
+
catalogUpdatedAt(): string | undefined;
|
|
1569
|
+
/** Why the last fetch failed, if it did. */
|
|
1570
|
+
lastFetchError(): string | undefined;
|
|
1571
|
+
onChange(listener: () => void): () => void;
|
|
1572
|
+
find(id: string): WorkBuddyModelInfo | undefined;
|
|
1573
|
+
/** Replace the catalog from the live upstream list; keeps the fallback if empty. */
|
|
1574
|
+
updateFromUpstream(models: readonly WorkBuddyUpstreamModel[]): void;
|
|
1575
|
+
/**
|
|
1576
|
+
* Record that a fetch attempt failed, leaving the current list in place.
|
|
1577
|
+
*
|
|
1578
|
+
* The list is deliberately NOT reset here: a refresh that fails should keep
|
|
1579
|
+
* whatever working catalog is already loaded, rather than demoting a healthy
|
|
1580
|
+
* session to the static table because one retry ran out.
|
|
1581
|
+
*/
|
|
1582
|
+
noteFetchFailure(message: string): void;
|
|
1583
|
+
private notify;
|
|
1584
|
+
}
|
|
1585
|
+
/** The user's model selection, as stored in the settings section. */
|
|
1586
|
+
interface ModelSelection {
|
|
1587
|
+
/** Absent = every model in the catalog is offered. */
|
|
1588
|
+
enabledModelIds?: readonly string[];
|
|
1589
|
+
/** Absent = each model follows its upstream image capability. */
|
|
1590
|
+
imageModelIds?: readonly string[];
|
|
1591
|
+
/** Per-model context-window cap, keyed by model id. */
|
|
1592
|
+
contextBudgets?: Readonly<Record<string, number | undefined>>;
|
|
1593
|
+
}
|
|
1594
|
+
//#endregion
|
|
1595
|
+
//#region src/shim.d.ts
|
|
1596
|
+
interface ShimLogger {
|
|
1597
|
+
info?(...args: unknown[]): void;
|
|
1598
|
+
warn(...args: unknown[]): void;
|
|
1599
|
+
error(...args: unknown[]): void;
|
|
1600
|
+
}
|
|
1601
|
+
interface WorkBuddyShim {
|
|
1602
|
+
ready: Promise<void>;
|
|
1603
|
+
baseUrl(): string;
|
|
1604
|
+
token(): string;
|
|
1605
|
+
close(): Promise<void>;
|
|
1606
|
+
}
|
|
1607
|
+
interface WorkBuddyShimOptions {
|
|
1608
|
+
pool: WorkBuddyAccountPool;
|
|
1609
|
+
client: WorkBuddyUpstreamClient;
|
|
1152
1610
|
catalog: WorkBuddyCatalog;
|
|
1153
1611
|
logger?: ShimLogger;
|
|
1154
1612
|
/**
|
|
@@ -1265,9 +1723,37 @@ interface AutomationJobState {
|
|
|
1265
1723
|
* repeat tick inside the same hour is still refused.
|
|
1266
1724
|
*/
|
|
1267
1725
|
lastRunSlot?: string;
|
|
1268
|
-
/**
|
|
1269
|
-
|
|
1270
|
-
|
|
1726
|
+
/**
|
|
1727
|
+
* Every configured slot consumed TODAY, as `YYYY-MM-DDTHH`.
|
|
1728
|
+
*
|
|
1729
|
+
* This is what actually gates a re-run, and it is a SET rather than a single
|
|
1730
|
+
* slot because one field could not express the contract: a job configured for
|
|
1731
|
+
* `[9, 21]` runs twice, and a single "last slot" value can only remember one
|
|
1732
|
+
* of them — the second run erased the first, so the 9 o'clock candidate looked
|
|
1733
|
+
* unconsumed again and the job re-fired every hour after 21:00.
|
|
1734
|
+
*
|
|
1735
|
+
* The values are the CONFIGURED hours that were spent, never the clock time
|
|
1736
|
+
* the run happened to finish at. Storing the finish time was the original
|
|
1737
|
+
* defect: the reader compared it against a configured candidate, so the two
|
|
1738
|
+
* almost never matched and the gate stayed open all day.
|
|
1739
|
+
*
|
|
1740
|
+
* In-memory like the rest of `states`: this is a per-process record, and the
|
|
1741
|
+
* catch-up design deliberately re-runs an hour that passed while DSH was
|
|
1742
|
+
* closed. See `automationEarnings` for the ledger that DOES persist.
|
|
1743
|
+
*/
|
|
1744
|
+
firedSlots?: readonly string[];
|
|
1745
|
+
/**
|
|
1746
|
+
* The clock slot the last run STARTED in (`YYYY-MM-DDTHH`).
|
|
1747
|
+
*
|
|
1748
|
+
* Separate from {@link firedSlots} on purpose: this is a throttle ("do not
|
|
1749
|
+
* start twice inside the same hour"), while `firedSlots` is the schedule
|
|
1750
|
+
* ledger. Conflating the two is what let a catch-up run at 13:00 erase the
|
|
1751
|
+
* record of the 9 o'clock slot.
|
|
1752
|
+
*/
|
|
1753
|
+
lastFiredHour?: string;
|
|
1754
|
+
/** Epoch ms of the last completed run. */
|
|
1755
|
+
lastRunAtMs?: number;
|
|
1756
|
+
/** Accounts that completed without throwing. */
|
|
1271
1757
|
ok: number;
|
|
1272
1758
|
/** Accounts that threw (each one skipped, the run continued). */
|
|
1273
1759
|
failed: number;
|
|
@@ -1535,7 +2021,27 @@ export declare class WorkBuddyScheduler {
|
|
|
1535
2021
|
* two hours still runs twice a day — but a job whose hour passed while DSH was
|
|
1536
2022
|
* closed runs immediately on the next tick instead of waiting for tomorrow.
|
|
1537
2023
|
*/
|
|
1538
|
-
|
|
2024
|
+
/**
|
|
2025
|
+
* The configured slot `kind` should consume at `now`, or undefined when none.
|
|
2026
|
+
*
|
|
2027
|
+
* Returns the SLOT STRING (not a boolean) because the caller must record the
|
|
2028
|
+
* same value it acted on. Returning a boolean was the original bug's enabler:
|
|
2029
|
+
* the tick asked "is it due", then `runJob` independently wrote "what time is
|
|
2030
|
+
* it now" — and those two answers were almost never equal.
|
|
2031
|
+
*
|
|
2032
|
+
* CATCH-UP semantics are deliberate: a candidate fires once its hour has
|
|
2033
|
+
* PASSED and its slot is still unconsumed, so a laptop that slept through
|
|
2034
|
+
* 10:00 still runs the job when it wakes, on the same day.
|
|
2035
|
+
*
|
|
2036
|
+
* The EARLIEST unconsumed candidate wins, which is what keeps a two-hour job
|
|
2037
|
+
* (`travelHours: [9, 21]`) whole: consuming the earliest due slot leaves the
|
|
2038
|
+
* later one for its own hour.
|
|
2039
|
+
*/
|
|
2040
|
+
private dueSlot;
|
|
2041
|
+
/** Today's consumed slots for one job, as a set. */
|
|
2042
|
+
private firedSlotsOf;
|
|
2043
|
+
/** Record one consumed slot on a job's state. */
|
|
2044
|
+
private consumeSlot;
|
|
1539
2045
|
private tick;
|
|
1540
2046
|
/** Run one job against every eligible account and record the outcome. */
|
|
1541
2047
|
/**
|
|
@@ -1568,6 +2074,12 @@ export declare class WorkBuddyScheduler {
|
|
|
1568
2074
|
/**
|
|
1569
2075
|
* Run one job against every eligible account and record the outcome.
|
|
1570
2076
|
*
|
|
2077
|
+
* `consumedSlot` is the configured slot this run spends (`dueSlot`'s answer).
|
|
2078
|
+
* It is passed IN rather than recomputed here so the value recorded is exactly
|
|
2079
|
+
* the value the schedule decided on — the defect this replaces wrote
|
|
2080
|
+
* `slotKey(now)` instead, i.e. the clock time the run finished at, which
|
|
2081
|
+
* almost never equals the configured candidate the gate had compared against.
|
|
2082
|
+
*
|
|
1571
2083
|
* The task job runs in TWO passes. The first sends the event chains that light
|
|
1572
2084
|
* up client-scored tasks; the second collects rewards. They are separate
|
|
1573
2085
|
* because scoring lands asynchronously — a chain sent and claimed within the
|
|
@@ -1582,497 +2094,148 @@ export declare class WorkBuddyScheduler {
|
|
|
1582
2094
|
* Accounts to run against, in pool order.
|
|
1583
2095
|
*
|
|
1584
2096
|
* Disabled accounts are excluded here rather than filtered by the caller so a
|
|
1585
|
-
* card switch takes effect on the next pass without any event plumbing.
|
|
1586
|
-
*/
|
|
1587
|
-
private accountsInOrder;
|
|
1588
|
-
/**
|
|
1589
|
-
* Send one activity report, then verify it landed.
|
|
1590
|
-
*
|
|
1591
|
-
* The upstream answers 200 even when it drops the event, so the streak is
|
|
1592
|
-
* read back as the oracle: `days > 0` means it counted. A failed read-back is
|
|
1593
|
-
* logged and treated as a suspicious result, never as a retry — the report is
|
|
1594
|
-
* idempotent per day, and hammering it is exactly what the one-a-day quota
|
|
1595
|
-
* exists to avoid.
|
|
1596
|
-
*/
|
|
1597
|
-
private reportOne;
|
|
1598
|
-
private sendEventChains;
|
|
1599
|
-
/**
|
|
1600
|
-
* Send one chain on the channel it was built for.
|
|
1601
|
-
*
|
|
1602
|
-
* The transport is not a detail of the sender: the scorer keys different
|
|
1603
|
-
* tasks to different fingerprint families, so a web-scored event posted as a
|
|
1604
|
-
* desktop event is accepted and then ignored.
|
|
1605
|
-
*/
|
|
1606
|
-
private sendChain;
|
|
1607
|
-
/**
|
|
1608
|
-
* Build every chain that scores one task.
|
|
1609
|
-
*
|
|
1610
|
-
* Most tasks need a single chain; `template_5` needs five, because the scorer
|
|
1611
|
-
* counts distinct `template_used` events rather than a boolean. The two tasks
|
|
1612
|
-
* that join a conversation (skill, expert) open a real one first, which is why
|
|
1613
|
-
* this is async.
|
|
1614
|
-
*/
|
|
1615
|
-
private chainsFor;
|
|
1616
|
-
/**
|
|
1617
|
-
* The summon-and-use chains for the expert tasks.
|
|
1618
|
-
*
|
|
1619
|
-
* Two steps per expert, and both are load-bearing: the summon events alone are
|
|
1620
|
-
* impressions, and a use event on its own scores nothing because the scorer
|
|
1621
|
-
* looks the conversation up. Only a real chat with `X-Expert-Id` produces an
|
|
1622
|
-
* id it will accept.
|
|
1623
|
-
*/
|
|
1624
|
-
private expertChains;
|
|
1625
|
-
/**
|
|
1626
|
-
* The 腾讯轻量云 expert chain.
|
|
1627
|
-
*
|
|
1628
|
-
* Structurally the same as the expert task, with two differences the scorer
|
|
1629
|
-
* checks: `agent_task_created` has to name the expert, and the use event has
|
|
1630
|
-
* to report `mode: 'LOCAL'` with an empty type and zero cost — that is what
|
|
1631
|
-
* the lighthouse criterion looks for.
|
|
1632
|
-
*/
|
|
1633
|
-
private lighthouseChains;
|
|
1634
|
-
/**
|
|
1635
|
-
* The task-centre pass for one account.
|
|
1636
|
-
*
|
|
1637
|
-
* Order matters: enrich first (enrol in everything open), then claim. Both
|
|
1638
|
-
* halves are idempotent — accepting an already-accepted task succeeds, and a
|
|
1639
|
-
* repeat claim answers `already_claimed` — so a pass that dies halfway is
|
|
1640
|
-
* safe to replay on the next tick.
|
|
1641
|
-
*/
|
|
1642
|
-
private runTasks;
|
|
1643
|
-
/**
|
|
1644
|
-
* Streak redemption plus the lottery it unlocks.
|
|
1645
|
-
*
|
|
1646
|
-
* Tiers unlock on consecutive active days (7/14/28). Redeeming one pays
|
|
1647
|
-
* credits, energy, a makeup card and — the part nothing else grants — lottery
|
|
1648
|
-
* draws, so the draw runs straight after and only for the chances in hand.
|
|
1649
|
-
*
|
|
1650
|
-
* Everything here is idempotent: a tier already claimed is skipped by its
|
|
1651
|
-
* status, and a draw consumes one chance, so a replay cannot double-spend.
|
|
1652
|
-
*/
|
|
1653
|
-
private redeemStreak;
|
|
1654
|
-
/**
|
|
1655
|
-
* One trip through the buddy travel loop for an account.
|
|
1656
|
-
*
|
|
1657
|
-
* A single pass advances the state machine by at most one step: a trip
|
|
1658
|
-
* that has arrived is collected, and an idle buddy is sent out. A buddy
|
|
1659
|
-
* already travelling is left alone — there is nothing to do until it lands.
|
|
1660
|
-
*
|
|
1661
|
-
* Measured against the live upstream: the departed trip reports
|
|
1662
|
-
* `dailyLimitReached` immediately, so the once-a-day limit needs no local
|
|
1663
|
-
* bookkeeping.
|
|
1664
|
-
*/
|
|
1665
|
-
private runTravel;
|
|
1666
|
-
}
|
|
1667
|
-
//#endregion
|
|
1668
|
-
//#region src/status.d.ts
|
|
1669
|
-
/** One account's status row. */
|
|
1670
|
-
interface AccountStatus {
|
|
1671
|
-
id: string;
|
|
1672
|
-
label: string;
|
|
1673
|
-
nickname?: string;
|
|
1674
|
-
domain: string;
|
|
1675
|
-
/** ISO timestamp when the access token expires. */
|
|
1676
|
-
expiresAt?: string;
|
|
1677
|
-
/** Account-wide cooldown (every model blocked). */
|
|
1678
|
-
cooling: boolean;
|
|
1679
|
-
cooldownUntil?: string;
|
|
1680
|
-
/** Per-model cooldowns active right now (modelId → ISO until); the account
|
|
1681
|
-
* itself is not `cooling` while only some models are limited. */
|
|
1682
|
-
modelCooldowns?: readonly {
|
|
1683
|
-
modelId: string;
|
|
1684
|
-
until: string;
|
|
1685
|
-
}[];
|
|
1686
|
-
rateLimitHits: number;
|
|
1687
|
-
/** Read-only aggregated credit summary for the account. */
|
|
1688
|
-
credits?: WorkBuddyCredits;
|
|
1689
|
-
creditsError?: string;
|
|
1690
|
-
sourcePath: string;
|
|
1691
|
-
}
|
|
1692
|
-
/** Whole-plugin status document. */
|
|
1693
|
-
interface WorkBuddyStatus {
|
|
1694
|
-
ok: boolean;
|
|
1695
|
-
accounts: AccountStatus[];
|
|
1696
|
-
activeAccountId?: string;
|
|
1697
|
-
cooling: number;
|
|
1698
|
-
models: {
|
|
1699
|
-
id: string;
|
|
1700
|
-
name: string;
|
|
1701
|
-
multiplier?: number;
|
|
1702
|
-
tags?: readonly string[];
|
|
1703
|
-
}[];
|
|
1704
|
-
shim: {
|
|
1705
|
-
running: boolean;
|
|
1706
|
-
baseUrl?: string;
|
|
1707
|
-
};
|
|
1708
|
-
}
|
|
1709
|
-
interface StatusOptions {
|
|
1710
|
-
pool: WorkBuddyAccountPool;
|
|
1711
|
-
/** The catalog to report. Regional callers pass their own region's. */
|
|
1712
|
-
catalog: WorkBuddyCatalog;
|
|
1713
|
-
client: WorkBuddyUpstreamClient;
|
|
1714
|
-
shim?: {
|
|
1715
|
-
running: boolean;
|
|
1716
|
-
baseUrl?: string;
|
|
1717
|
-
};
|
|
1718
|
-
/** Query credits per account. Off for cheap diagnostics runs. */
|
|
1719
|
-
includeCredits?: boolean;
|
|
1720
|
-
}
|
|
1721
|
-
/** Build the status document. Never throws. */
|
|
1722
|
-
export declare function buildStatus(options: StatusOptions): Promise<WorkBuddyStatus>;
|
|
1723
|
-
/** Format the status document for a terminal. */
|
|
1724
|
-
export declare function formatStatus(status: WorkBuddyStatus): string;
|
|
1725
|
-
/** Format the per-model credit multipliers. */
|
|
1726
|
-
export declare function formatRates(status: WorkBuddyStatus): string;
|
|
1727
|
-
//#endregion
|
|
1728
|
-
//#region src/status-paths.d.ts
|
|
1729
|
-
/**
|
|
1730
|
-
* Node-free constants and types shared by the Host and browser halves of the
|
|
1731
|
-
* WorkBuddy XD Pool settings card.
|
|
1732
|
-
*
|
|
1733
|
-
* Pool's runtime state already lives in `src/status.ts` (`buildStatus` /
|
|
1734
|
-
* `WorkBuddyStatus`); this module only carves the cross-domain (Host→browser)
|
|
1735
|
-
* JSON document into a shape that stays token-free and matches what the
|
|
1736
|
-
* browser card renders. Route paths are plugin-owned and mounted on the Host's
|
|
1737
|
-
* same-origin web server (see `src/web-status.ts`).
|
|
1738
|
-
*
|
|
1739
|
-
* @module dsh-workbuddy-xdpool/status-paths
|
|
1740
|
-
*/
|
|
1741
|
-
/** Plugin-owned read-only pool status endpoint (account rows + models + shim). */
|
|
1742
|
-
export declare const POOL_STATUS_PATH = "/plugins/dsh-workbuddy-xdpool/status";
|
|
1743
|
-
/** Plugin-owned local account rescan endpoint (re-read desktop snapshots). */
|
|
1744
|
-
export declare const POOL_RESCAN_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/rescan";
|
|
1745
|
-
/** Plugin-owned cooldown reset endpoint (clear all 429 cooldowns). */
|
|
1746
|
-
export declare const POOL_RESET_COOLDOWN_PATH = "/plugins/dsh-workbuddy-xdpool/cooldowns/reset";
|
|
1747
|
-
/** Plugin-owned daily check-in action endpoint (claim today's reward). */
|
|
1748
|
-
export declare const POOL_CHECKIN_PATH = "/plugins/dsh-workbuddy-xdpool/checkin";
|
|
1749
|
-
/** Plugin-owned model-selection save endpoint (writes the settings section). */
|
|
1750
|
-
export declare const POOL_MODELS_SAVE_PATH = "/plugins/dsh-workbuddy-xdpool/models/save";
|
|
1751
|
-
/**
|
|
1752
|
-
* Throw one account out of the pool for good, or take it back.
|
|
1753
|
-
*
|
|
1754
|
-
* Separate from the disable route because the semantics differ: disabling is a
|
|
1755
|
-
* rotation preference the account survives, ignoring survives the account.
|
|
1756
|
-
*/
|
|
1757
|
-
export declare const POOL_ACCOUNT_IGNORE_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/ignored";
|
|
1758
|
-
/** Run one automation job immediately, so the card can verify it on demand. */
|
|
1759
|
-
export declare const POOL_AUTOMATION_RUN_PATH = "/plugins/dsh-workbuddy-xdpool/automation/run";
|
|
1760
|
-
/** Set or clear one account's reserved-credit floor. */
|
|
1761
|
-
export declare const POOL_CREDIT_RESERVE_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/credit-reserve";
|
|
1762
|
-
/** One account's row, token-free. */
|
|
1763
|
-
interface PoolWebAccount {
|
|
1764
|
-
id: string;
|
|
1765
|
-
label: string;
|
|
1766
|
-
nickname?: string;
|
|
1767
|
-
domain: string;
|
|
1768
|
-
/** ISO timestamp; absent when the credential carries no expiry. */
|
|
1769
|
-
expiresAt?: string;
|
|
1770
|
-
/** Account-wide cooldown (every model blocked); only after a no-model penalize. */
|
|
1771
|
-
cooling: boolean;
|
|
1772
|
-
/** ISO timestamp when the account-wide 429 cooldown lifts; only while cooling. */
|
|
1773
|
-
cooldownUntil?: string;
|
|
1774
|
-
/**
|
|
1775
|
-
* Per-model cooldowns currently active. The account is NOT `cooling` while a
|
|
1776
|
-
* model is limited — its other models still serve — but each entry tells the
|
|
1777
|
-
* card which model is out until when (e.g. `hy4-preview` cooling to 10:14,
|
|
1778
|
-
* `hy3` normal).
|
|
1779
|
-
*/
|
|
1780
|
-
modelCooldowns?: ReadonlyArray<{
|
|
1781
|
-
modelId: string;
|
|
1782
|
-
until: string;
|
|
1783
|
-
}>;
|
|
1784
|
-
/**
|
|
1785
|
-
* Whether the user switched this account off. A disabled account never
|
|
1786
|
-
* serves a request, but it stays listed so the card can switch it back on.
|
|
1787
|
-
*/
|
|
1788
|
-
disabled: boolean;
|
|
1789
|
-
rateLimitHits: number;
|
|
1790
|
-
/**
|
|
1791
|
-
* Credits the user asked to keep for this account. The pool stops picking the
|
|
1792
|
-
* account once its balance reaches the reserve, so this many credits survive.
|
|
1793
|
-
* 0 means the account may be spent down as before.
|
|
1794
|
-
*/
|
|
1795
|
-
creditReserve: number;
|
|
1796
|
-
/**
|
|
1797
|
-
* Whether the account is held back purely by its reserve right now. Kept
|
|
1798
|
-
* distinct from `cooling`: a reserved account is healthy and simply
|
|
1799
|
-
* protected, which is a different thing to tell the user than rate-limited.
|
|
1800
|
-
*/
|
|
1801
|
-
reserved: boolean;
|
|
1802
|
-
/**
|
|
1803
|
-
* What the automation earned for this account today. Absent when it earned
|
|
1804
|
-
* nothing (or the automation never ran for it), so the card can stay quiet
|
|
1805
|
-
* instead of printing a row of zeroes.
|
|
1806
|
-
*/
|
|
1807
|
-
automationToday?: PoolWebAutomationEarnings;
|
|
1808
|
-
/** ISO timestamp of the last successful use (best-effort pool bookkeeping). */
|
|
1809
|
-
lastUsedAt?: string;
|
|
1810
|
-
/** Aggregated credit summary for the account, read-only. */
|
|
1811
|
-
credits?: PoolWebCredits;
|
|
1812
|
-
creditsError?: string;
|
|
1813
|
-
/**
|
|
1814
|
-
* Today's check-in state for this account, read-only. Present only when the
|
|
1815
|
-
* per-account check-in probe succeeded and the program is active. The card
|
|
1816
|
-
* renders one claim button per account, so a multi-account pool can collect
|
|
1817
|
-
* every account's daily reward without switching accounts by hand.
|
|
1818
|
-
*/
|
|
1819
|
-
checkin?: PoolWebCheckin;
|
|
1820
|
-
checkinError?: string;
|
|
1821
|
-
}
|
|
1822
|
-
/** One credit package (as surfaced by the pool's upstream client), node-free. */
|
|
1823
|
-
interface PoolWebCreditPackage {
|
|
1824
|
-
packageName: string;
|
|
1825
|
-
remain?: number;
|
|
1826
|
-
size?: number;
|
|
1827
|
-
/** CapacityType 4 — refreshed each cycle and never expires. */
|
|
1828
|
-
monthly?: boolean;
|
|
1829
|
-
/** Next cycle refresh point, ms. */
|
|
1830
|
-
cycleRefreshMs?: number;
|
|
1831
|
-
/** One-off expiry, ms. */
|
|
1832
|
-
expiresAtMs?: number;
|
|
1833
|
-
}
|
|
1834
|
-
/** Aggregated credit answer the card renders under one account. */
|
|
1835
|
-
interface PoolWebCredits {
|
|
1836
|
-
total?: number;
|
|
1837
|
-
packages: readonly PoolWebCreditPackage[];
|
|
1838
|
-
/** Credits expiring within 3 days. */
|
|
1839
|
-
expiringSoon?: number;
|
|
1840
|
-
/** When the nearest package expires, ms. */
|
|
1841
|
-
nearestExpiryMs?: number;
|
|
1842
|
-
}
|
|
1843
|
-
/**
|
|
1844
|
-
* Daily check-in state the card renders under one account's credits. Mirrors
|
|
1845
|
-
* the upstream activity endpoint, minus anything the browser does not need.
|
|
1846
|
-
*/
|
|
1847
|
-
interface PoolWebCheckin {
|
|
1848
|
-
/** The activity is running; a claim button is offered only while true. */
|
|
1849
|
-
active: boolean;
|
|
1850
|
-
/** Already collected today — the button renders as a done state. */
|
|
1851
|
-
todayCheckedIn: boolean;
|
|
1852
|
-
/** Consecutive days checked in. */
|
|
1853
|
-
streakDays: number;
|
|
1854
|
-
/** Credits a single day grants. */
|
|
1855
|
-
dailyCredit: number;
|
|
1856
|
-
/** Credits collected today (0 before claiming). */
|
|
1857
|
-
todayCredit: number;
|
|
1858
|
-
/** Today is a streak milestone day. */
|
|
1859
|
-
isStreakDay: boolean;
|
|
1860
|
-
/** The day count the next milestone lands on. */
|
|
1861
|
-
nextStreakDay: number;
|
|
1862
|
-
/** Bonus credits granted on a milestone day. */
|
|
1863
|
-
streakBonusCredit: number;
|
|
1864
|
-
}
|
|
1865
|
-
/** Result of one claim, so the card can confirm what was collected. */
|
|
1866
|
-
interface PoolWebCheckinClaim {
|
|
1867
|
-
credit: number;
|
|
1868
|
-
streakDays: number;
|
|
1869
|
-
isStreakDay: boolean;
|
|
1870
|
-
}
|
|
1871
|
-
/** One model the pool exposes to DSH, with cost / free tags. */
|
|
1872
|
-
interface PoolWebModel {
|
|
1873
|
-
id: string;
|
|
1874
|
-
name: string;
|
|
1875
|
-
/** Relative credit cost, e.g. 0.79 for x0.79. */
|
|
1876
|
-
multiplier?: number;
|
|
1877
|
-
/** Upstream tags: free / limited-free / night-discount. */
|
|
1878
|
-
tags?: readonly string[];
|
|
1879
|
-
/** Effective image support after the user's per-model toggle. */
|
|
1880
|
-
supportsImages: boolean;
|
|
1881
|
-
/** Effective context window after the user's budget cap. */
|
|
1882
|
-
contextWindow: number;
|
|
1883
|
-
/** The window the upstream advertises, before any cap. */
|
|
1884
|
-
nativeContextWindow: number;
|
|
1885
|
-
/** Upstream output ceiling, so the card can show both limits. */
|
|
1886
|
-
maxOutputTokens: number;
|
|
1887
|
-
/** Thinking levels the upstream declares, when it declares any. */
|
|
1888
|
-
supportedEfforts?: readonly string[];
|
|
1889
|
-
/** Whether this model is currently enabled in the picker. */
|
|
1890
|
-
enabled: boolean;
|
|
1891
|
-
}
|
|
1892
|
-
/**
|
|
1893
|
-
* Body of the account ignore/unignore route: exactly one account per request.
|
|
1894
|
-
*
|
|
1895
|
-
* `ignored: true` throws the account out of the pool for good (its credential is
|
|
1896
|
-
* not even read on the next scan, and a fresh desktop sign-in will not bring it
|
|
1897
|
-
* back). `false` restores it, at which point the next scan discovers it again.
|
|
1898
|
-
*/
|
|
1899
|
-
interface PoolWebAccountIgnore {
|
|
1900
|
-
/** Pool account id, as reported in `PoolWebAccount.id`. */
|
|
1901
|
-
accountId: string;
|
|
1902
|
-
/** `true` ignores the account permanently; `false` takes it back. */
|
|
1903
|
-
ignored: boolean;
|
|
1904
|
-
}
|
|
1905
|
-
/**
|
|
1906
|
-
* One account the user has thrown out of the pool.
|
|
1907
|
-
*
|
|
1908
|
-
* Kept on the status document so the card can list what was ignored and offer a
|
|
1909
|
-
* way back: without that, "ignored" is a one-way door the user cannot inspect or
|
|
1910
|
-
* undo from the UI, which is how a hidden list becomes a support burden.
|
|
1911
|
-
*/
|
|
1912
|
-
interface PoolWebIgnoredAccount {
|
|
1913
|
-
/** Pool account id, the same key `PoolWebAccount.id` uses. */
|
|
1914
|
-
id: string;
|
|
1915
|
-
/** Human label captured at ignore time, so the row reads without a rescan. */
|
|
1916
|
-
label: string;
|
|
1917
|
-
/** ISO timestamp of when it was ignored. */
|
|
1918
|
-
ignoredAt: string;
|
|
1919
|
-
}
|
|
1920
|
-
interface PoolWebModelSelection {
|
|
1921
|
-
/** Absent = every model is enabled. */
|
|
1922
|
-
enabledModelIds?: readonly string[];
|
|
1923
|
-
/** Absent = each model follows its upstream image capability. */
|
|
1924
|
-
imageModelIds?: readonly string[];
|
|
1925
|
-
/** Per-model context-window cap, keyed by model id. */
|
|
1926
|
-
contextBudgets?: Readonly<Record<string, number | undefined>>;
|
|
1927
|
-
}
|
|
1928
|
-
/** The JSON document the pool card renders. */
|
|
1929
|
-
interface PoolWebStatus {
|
|
1930
|
-
ok: boolean;
|
|
1931
|
-
accounts: readonly PoolWebAccount[];
|
|
1932
|
-
/** The next account the pool would use (rotation cursor). */
|
|
1933
|
-
activeAccountId?: string;
|
|
1934
|
-
cooling: number;
|
|
1935
|
-
models: readonly PoolWebModel[];
|
|
1936
|
-
/** The saved selection the card diffs its draft against. */
|
|
1937
|
-
selection: PoolWebModelSelection;
|
|
2097
|
+
* card switch takes effect on the next pass without any event plumbing.
|
|
2098
|
+
*/
|
|
2099
|
+
private accountsInOrder;
|
|
1938
2100
|
/**
|
|
1939
|
-
*
|
|
1940
|
-
*
|
|
2101
|
+
* Send one activity report, then verify it landed.
|
|
2102
|
+
*
|
|
2103
|
+
* The upstream answers 200 even when it drops the event, so the streak is
|
|
2104
|
+
* read back as the oracle: `days > 0` means it counted. A failed read-back is
|
|
2105
|
+
* logged and treated as a suspicious result, never as a retry — the report is
|
|
2106
|
+
* idempotent per day, and hammering it is exactly what the one-a-day quota
|
|
2107
|
+
* exists to avoid.
|
|
1941
2108
|
*/
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
region: PoolRegion;
|
|
1945
|
-
/** Every region holding at least one account, in display order. */
|
|
1946
|
-
regions: readonly PoolRegion[];
|
|
1947
|
-
shim: {
|
|
1948
|
-
running: boolean;
|
|
1949
|
-
baseUrl?: string;
|
|
1950
|
-
};
|
|
1951
|
-
/** Daily-points automation state, so the card can show what ran and when. */
|
|
1952
|
-
automation: PoolWebAutomation;
|
|
1953
|
-
/** Per-account credit floors currently in force, keyed by account id. */
|
|
1954
|
-
creditReserves: Readonly<Record<string, number>>;
|
|
2109
|
+
private reportOne;
|
|
2110
|
+
private sendEventChains;
|
|
1955
2111
|
/**
|
|
1956
|
-
*
|
|
2112
|
+
* Send one chain on the channel it was built for.
|
|
1957
2113
|
*
|
|
1958
|
-
*
|
|
1959
|
-
*
|
|
1960
|
-
*
|
|
2114
|
+
* The transport is not a detail of the sender: the scorer keys different
|
|
2115
|
+
* tasks to different fingerprint families, so a web-scored event posted as a
|
|
2116
|
+
* desktop event is accepted and then ignored.
|
|
1961
2117
|
*/
|
|
1962
|
-
|
|
1963
|
-
}
|
|
1964
|
-
/** One automation job's last run, as shown on the card. */
|
|
1965
|
-
interface PoolWebAutomationJob {
|
|
1966
|
-
/** `YYYY-MM-DD` of the last run in this process, if it has run. */
|
|
1967
|
-
lastRunDate?: string;
|
|
1968
|
-
/** Accounts that finished without error on the last run. */
|
|
1969
|
-
ok: number;
|
|
1970
|
-
/** Accounts that failed on the last run (each one skipped, the run continued). */
|
|
1971
|
-
failed: number;
|
|
1972
|
-
/** Credits claimed by the task job on the last run. */
|
|
1973
|
-
credit: number;
|
|
1974
|
-
/** Energy claimed by the task job on the last run. */
|
|
1975
|
-
energy: number;
|
|
1976
|
-
/** Tasks claimed by the task job on the last run. */
|
|
1977
|
-
claimed: number;
|
|
1978
|
-
/** One-line summary of the last run. */
|
|
1979
|
-
message?: string;
|
|
2118
|
+
private sendChain;
|
|
1980
2119
|
/**
|
|
1981
|
-
*
|
|
2120
|
+
* Build every chain that scores one task.
|
|
1982
2121
|
*
|
|
1983
|
-
*
|
|
1984
|
-
*
|
|
2122
|
+
* Most tasks need a single chain; `template_5` needs five, because the scorer
|
|
2123
|
+
* counts distinct `template_used` events rather than a boolean. The two tasks
|
|
2124
|
+
* that join a conversation (skill, expert) open a real one first, which is why
|
|
2125
|
+
* this is async.
|
|
1985
2126
|
*/
|
|
1986
|
-
|
|
1987
|
-
/** A pending milestone worth naming, e.g. the next streak tier countdown. */
|
|
1988
|
-
progress?: string;
|
|
1989
|
-
}
|
|
1990
|
-
/**
|
|
1991
|
-
* Automation block on the status document.
|
|
1992
|
-
*
|
|
1993
|
-
* Carries the schedule and each job's last outcome so the card can answer
|
|
1994
|
-
* "is it on, when does it run, and what did it last do" without reaching into
|
|
1995
|
-
* the scheduler itself.
|
|
1996
|
-
*/
|
|
1997
|
-
interface PoolWebAutomation {
|
|
1998
|
-
/** Master switch, mirrored from the saved config. */
|
|
1999
|
-
enabled: boolean;
|
|
2000
|
-
/** Whether the loop is currently running. */
|
|
2001
|
-
running: boolean;
|
|
2002
|
-
/** Configured hours per job, so the card can show the schedule. */
|
|
2003
|
-
checkinHours: readonly number[];
|
|
2004
|
-
reportHours: readonly number[];
|
|
2005
|
-
taskHours: readonly number[];
|
|
2006
|
-
streakHours: readonly number[];
|
|
2007
|
-
travelHours: readonly number[];
|
|
2008
|
-
jobs: {
|
|
2009
|
-
checkin: PoolWebAutomationJob;
|
|
2010
|
-
report: PoolWebAutomationJob;
|
|
2011
|
-
tasks: PoolWebAutomationJob;
|
|
2012
|
-
streak: PoolWebAutomationJob;
|
|
2013
|
-
travel: PoolWebAutomationJob;
|
|
2014
|
-
};
|
|
2015
|
-
/** Claimable tasks seen on the most recent task pass, across accounts. */
|
|
2016
|
-
claimableSeen: number;
|
|
2127
|
+
private chainsFor;
|
|
2017
2128
|
/**
|
|
2018
|
-
*
|
|
2019
|
-
*
|
|
2129
|
+
* The summon-and-use chains for the expert tasks.
|
|
2130
|
+
*
|
|
2131
|
+
* Two steps per expert, and both are load-bearing: the summon events alone are
|
|
2132
|
+
* impressions, and a use event on its own scores nothing because the scorer
|
|
2133
|
+
* looks the conversation up. Only a real chat with `X-Expert-Id` produces an
|
|
2134
|
+
* id it will accept.
|
|
2020
2135
|
*/
|
|
2021
|
-
|
|
2136
|
+
private expertChains;
|
|
2022
2137
|
/**
|
|
2023
|
-
*
|
|
2024
|
-
*
|
|
2025
|
-
*
|
|
2138
|
+
* The 腾讯轻量云 expert chain.
|
|
2139
|
+
*
|
|
2140
|
+
* Structurally the same as the expert task, with two differences the scorer
|
|
2141
|
+
* checks: `agent_task_created` has to name the expert, and the use event has
|
|
2142
|
+
* to report `mode: 'LOCAL'` with an empty type and zero cost — that is what
|
|
2143
|
+
* the lighthouse criterion looks for.
|
|
2026
2144
|
*/
|
|
2027
|
-
|
|
2145
|
+
private lighthouseChains;
|
|
2146
|
+
/**
|
|
2147
|
+
* The task-centre pass for one account.
|
|
2148
|
+
*
|
|
2149
|
+
* Order matters: enrich first (enrol in everything open), then claim. Both
|
|
2150
|
+
* halves are idempotent — accepting an already-accepted task succeeds, and a
|
|
2151
|
+
* repeat claim answers `already_claimed` — so a pass that dies halfway is
|
|
2152
|
+
* safe to replay on the next tick.
|
|
2153
|
+
*/
|
|
2154
|
+
private runTasks;
|
|
2155
|
+
/**
|
|
2156
|
+
* Streak redemption plus the lottery it unlocks.
|
|
2157
|
+
*
|
|
2158
|
+
* Tiers unlock on consecutive active days (7/14/28). Redeeming one pays
|
|
2159
|
+
* credits, energy, a makeup card and — the part nothing else grants — lottery
|
|
2160
|
+
* draws, so the draw runs straight after and only for the chances in hand.
|
|
2161
|
+
*
|
|
2162
|
+
* Everything here is idempotent: a tier already claimed is skipped by its
|
|
2163
|
+
* status, and a draw consumes one chance, so a replay cannot double-spend.
|
|
2164
|
+
*/
|
|
2165
|
+
private redeemStreak;
|
|
2166
|
+
/**
|
|
2167
|
+
* One trip through the buddy travel loop for an account.
|
|
2168
|
+
*
|
|
2169
|
+
* A single pass advances the state machine by at most one step: a trip
|
|
2170
|
+
* that has arrived is collected, and an idle buddy is sent out. A buddy
|
|
2171
|
+
* already travelling is left alone — there is nothing to do until it lands.
|
|
2172
|
+
*
|
|
2173
|
+
* Measured against the live upstream: the departed trip reports
|
|
2174
|
+
* `dailyLimitReached` immediately, so the once-a-day limit needs no local
|
|
2175
|
+
* bookkeeping.
|
|
2176
|
+
*/
|
|
2177
|
+
private runTravel;
|
|
2028
2178
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
/**
|
|
2038
|
-
|
|
2039
|
-
/**
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2179
|
+
//#endregion
|
|
2180
|
+
//#region src/status.d.ts
|
|
2181
|
+
/** One account's status row. */
|
|
2182
|
+
interface AccountStatus {
|
|
2183
|
+
id: string;
|
|
2184
|
+
label: string;
|
|
2185
|
+
nickname?: string;
|
|
2186
|
+
domain: string;
|
|
2187
|
+
/** ISO timestamp when the access token expires. */
|
|
2188
|
+
expiresAt?: string;
|
|
2189
|
+
/** Account-wide cooldown (every model blocked). */
|
|
2190
|
+
cooling: boolean;
|
|
2191
|
+
cooldownUntil?: string;
|
|
2192
|
+
/** Per-model cooldowns active right now (modelId → ISO until); the account
|
|
2193
|
+
* itself is not `cooling` while only some models are limited. */
|
|
2194
|
+
modelCooldowns?: readonly {
|
|
2195
|
+
modelId: string;
|
|
2196
|
+
until: string;
|
|
2197
|
+
}[];
|
|
2198
|
+
rateLimitHits: number;
|
|
2199
|
+
/** Read-only aggregated credit summary for the account. */
|
|
2200
|
+
credits?: WorkBuddyCredits;
|
|
2201
|
+
creditsError?: string;
|
|
2202
|
+
sourcePath: string;
|
|
2045
2203
|
}
|
|
2046
|
-
/**
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2204
|
+
/** Whole-plugin status document. */
|
|
2205
|
+
interface WorkBuddyStatus {
|
|
2206
|
+
ok: boolean;
|
|
2207
|
+
accounts: AccountStatus[];
|
|
2208
|
+
activeAccountId?: string;
|
|
2209
|
+
cooling: number;
|
|
2210
|
+
models: {
|
|
2211
|
+
id: string;
|
|
2212
|
+
name: string;
|
|
2213
|
+
multiplier?: number;
|
|
2214
|
+
tags?: readonly string[];
|
|
2215
|
+
}[];
|
|
2216
|
+
shim: {
|
|
2217
|
+
running: boolean;
|
|
2218
|
+
baseUrl?: string;
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
interface StatusOptions {
|
|
2222
|
+
pool: WorkBuddyAccountPool;
|
|
2223
|
+
/** The catalog to report. Regional callers pass their own region's. */
|
|
2224
|
+
catalog: WorkBuddyCatalog;
|
|
2225
|
+
client: WorkBuddyUpstreamClient;
|
|
2226
|
+
shim?: {
|
|
2227
|
+
running: boolean;
|
|
2228
|
+
baseUrl?: string;
|
|
2229
|
+
};
|
|
2230
|
+
/** Query credits per account. Off for cheap diagnostics runs. */
|
|
2231
|
+
includeCredits?: boolean;
|
|
2232
|
+
}
|
|
2233
|
+
/** Build the status document. Never throws. */
|
|
2234
|
+
export declare function buildStatus(options: StatusOptions): Promise<WorkBuddyStatus>;
|
|
2235
|
+
/** Format the status document for a terminal. */
|
|
2236
|
+
export declare function formatStatus(status: WorkBuddyStatus): string;
|
|
2237
|
+
/** Format the per-model credit multipliers. */
|
|
2238
|
+
export declare function formatRates(status: WorkBuddyStatus): string;
|
|
2076
2239
|
//#endregion
|
|
2077
2240
|
//#region src/ignored.d.ts
|
|
2078
2241
|
/** Directory holding this plugin's own state (imported snapshots, ignore list). */
|
|
@@ -2202,6 +2365,19 @@ interface PoolStatusRouteOptions {
|
|
|
2202
2365
|
* disk, including edits made by the CLI while the card is open.
|
|
2203
2366
|
*/
|
|
2204
2367
|
ignoredAccounts?: () => readonly PoolWebIgnoredAccount[];
|
|
2368
|
+
/**
|
|
2369
|
+
* Re-fetch the model catalog for BOTH regions and report what landed.
|
|
2370
|
+
*
|
|
2371
|
+
* Absent when the host did not wire it: the route then answers 503 rather
|
|
2372
|
+
* than pretending the refresh happened.
|
|
2373
|
+
*/
|
|
2374
|
+
refreshCatalog?: () => Promise<{
|
|
2375
|
+
regions: Readonly<Record<PoolRegion, {
|
|
2376
|
+
source: PoolWebCatalogSource;
|
|
2377
|
+
models: number;
|
|
2378
|
+
error?: string;
|
|
2379
|
+
}>>;
|
|
2380
|
+
}>;
|
|
2205
2381
|
}
|
|
2206
2382
|
/**
|
|
2207
2383
|
* Assemble the card's status document. Per-account credits and check-in state
|