dsh-xdpool 2.5.0 → 2.6.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 +158 -0
- package/README.en.md +18 -4
- package/README.md +19 -5
- package/assets/community-qr-qq.jpg +0 -0
- package/assets/community-qr-wechat.jpg +0 -0
- package/cordis.patch.yml +17 -41
- package/lib/bin.js +604 -87
- package/lib/client.js +1227 -891
- package/lib/index.d.ts +430 -143
- package/lib/index.js +2388 -1361
- package/package.json +1 -4
- package/vendor/channel-pack/pack.js +222 -16
package/lib/index.d.ts
CHANGED
|
@@ -398,6 +398,15 @@ interface WorkBuddyTask {
|
|
|
398
398
|
claimed: boolean;
|
|
399
399
|
/** Upstream marked the task locked (not yet reachable). */
|
|
400
400
|
locked: boolean;
|
|
401
|
+
/**
|
|
402
|
+
* The task's own deeplink, verbatim, or '' when it has none.
|
|
403
|
+
*
|
|
404
|
+
* Kept because for the "体验XX专家" family it is the ONLY source of the
|
|
405
|
+
* expert id: those experts are not in the marketplace listing, and the id
|
|
406
|
+
* appears nowhere else (#98). Named after the upstream field so a future
|
|
407
|
+
* reader can find it in a captured JSON body.
|
|
408
|
+
*/
|
|
409
|
+
jumpUrl: string;
|
|
401
410
|
}
|
|
402
411
|
/**
|
|
403
412
|
* Flatten one upstream task entry.
|
|
@@ -1057,6 +1066,16 @@ export declare class WorkBuddyAccountPool {
|
|
|
1057
1066
|
* lives on the pool and is re-applied from settings after each scan.
|
|
1058
1067
|
*/
|
|
1059
1068
|
private disabledIds;
|
|
1069
|
+
/**
|
|
1070
|
+
* The account ids the store held after the last successful write.
|
|
1071
|
+
*
|
|
1072
|
+
* Read back on the next scan to say WHICH accounts left, not just how many.
|
|
1073
|
+
* The list is written wholesale, so a scan that does not find an account
|
|
1074
|
+
* deletes it — and that account's credential is then unrecoverable without a
|
|
1075
|
+
* fresh sign-in (#117). `undefined` until the first write, so the first scan
|
|
1076
|
+
* never reports every account as "leave".
|
|
1077
|
+
*/
|
|
1078
|
+
private lastPersistedIds;
|
|
1060
1079
|
/**
|
|
1061
1080
|
* Account ids the user threw out of the pool for good.
|
|
1062
1081
|
*
|
|
@@ -1134,6 +1153,11 @@ export declare class WorkBuddyAccountPool {
|
|
|
1134
1153
|
* A function rather than a list because that pool is mounted asynchronously
|
|
1135
1154
|
* and can be re-read on demand; `undefined` means "no such source", which is
|
|
1136
1155
|
* the state every test and every pre-mount startup is in.
|
|
1156
|
+
*
|
|
1157
|
+
* The `| undefined` is explicit because `applyExternalSource` CLEARS the field by
|
|
1158
|
+
* assigning `undefined` — under `exactOptionalPropertyTypes` a bare `?:` means
|
|
1159
|
+
* "may be absent, never undefined", which made that documented clearing action
|
|
1160
|
+
* a type error.
|
|
1137
1161
|
*/
|
|
1138
1162
|
private externalSource?;
|
|
1139
1163
|
constructor(options?: AccountPoolOptions);
|
|
@@ -1205,7 +1229,7 @@ export declare class WorkBuddyAccountPool {
|
|
|
1205
1229
|
* Counts are over the region's accounts, since a provider only ever sees its
|
|
1206
1230
|
* own gateway.
|
|
1207
1231
|
*/
|
|
1208
|
-
unavailableReason(modelId?: string, region?: WorkBuddyRegion): {
|
|
1232
|
+
unavailableReason(modelId?: string, region?: WorkBuddyRegion, reserveExempt?: ReadonlySet<string>): {
|
|
1209
1233
|
total: number;
|
|
1210
1234
|
cooling: number;
|
|
1211
1235
|
disabled: number;
|
|
@@ -1295,9 +1319,11 @@ export declare class WorkBuddyAccountPool {
|
|
|
1295
1319
|
* Scans on first use, and rescans when every known account is cooling down: a
|
|
1296
1320
|
* fresh desktop login is the usual way out of an exhausted pool.
|
|
1297
1321
|
*
|
|
1322
|
+
* `reserveExempt` is host-only: account ids whose own credentials freshly
|
|
1323
|
+
* confirmed a zero-credit model. It never bypasses disabled, dead credentials, cooldowns or region.
|
|
1298
1324
|
* `conversationKey` is only consulted under `sticky`; other modes ignore it.
|
|
1299
1325
|
*/
|
|
1300
|
-
acquire(modelId?: string, region?: WorkBuddyRegion, conversationKey?: string): Promise<WorkBuddyAccount | undefined>;
|
|
1326
|
+
acquire(modelId?: string, region?: WorkBuddyRegion, conversationKey?: string, reserveExempt?: ReadonlySet<string>): Promise<WorkBuddyAccount | undefined>;
|
|
1301
1327
|
/** How the pool currently spreads requests. Shown on the card. */
|
|
1302
1328
|
currentDistribution(): AccountDistribution;
|
|
1303
1329
|
/**
|
|
@@ -1403,6 +1429,28 @@ export declare class WorkBuddyAccountPool {
|
|
|
1403
1429
|
clearCredentialDead(accountId: string): void;
|
|
1404
1430
|
/** Accounts currently kept out of rotation because their sign-in was rejected. */
|
|
1405
1431
|
deadCredentials(): readonly WorkBuddyAccount[];
|
|
1432
|
+
/**
|
|
1433
|
+
* Try to bring benched accounts back WITHOUT waiting out the cooldown.
|
|
1434
|
+
*
|
|
1435
|
+
* The cooldown is a guess about how long a problem lasts, and the guess is
|
|
1436
|
+
* usually wrong in one direction or the other: a token revoked by a password
|
|
1437
|
+
* change stays dead for the full window even after the user signs in again in
|
|
1438
|
+
* some other client, and a transient upstream hiccup benches a perfectly good
|
|
1439
|
+
* account for half an hour.
|
|
1440
|
+
*
|
|
1441
|
+
* So instead of only waiting, ask. For each benched account, one cheap
|
|
1442
|
+
* authenticated read: if it answers, the credential works and the account goes
|
|
1443
|
+
* back into rotation immediately. Nothing about the failure is trusted — only a
|
|
1444
|
+
* successful call clears it — and a probe that fails keeps the original
|
|
1445
|
+
* cooldown untouched (probing must never EXTEND a bench, or a broken endpoint
|
|
1446
|
+
* would keep every account locked out for as long as it stayed broken).
|
|
1447
|
+
*
|
|
1448
|
+
* `probe` is injected rather than imported so this class stays free of the
|
|
1449
|
+
* upstream client: the pool knows about accounts, not about HTTP.
|
|
1450
|
+
*
|
|
1451
|
+
* Returns the accounts it revived, for logging and for the run summary.
|
|
1452
|
+
*/
|
|
1453
|
+
reviveBenched(probe: (credential: WorkBuddyCredential) => Promise<unknown>): Promise<readonly WorkBuddyAccount[]>;
|
|
1406
1454
|
/**
|
|
1407
1455
|
* Refresh the account's access token when it is within the margin (or already
|
|
1408
1456
|
* expired), in-flight de-duped per account. A failed refresh keeps the
|
|
@@ -1498,77 +1546,6 @@ interface PoolWebChannelModel {
|
|
|
1498
1546
|
inputModalities?: readonly string[];
|
|
1499
1547
|
description?: string;
|
|
1500
1548
|
}
|
|
1501
|
-
/**
|
|
1502
|
-
* One billion-context session, reduced to what a dashboard may show.
|
|
1503
|
-
*
|
|
1504
|
-
* Counts, sizes and timestamps only. The proxy's own rows carry titles and
|
|
1505
|
-
* first-block hints, which are the user's words; those stay on the machine that
|
|
1506
|
-
* produced them and are not relayed.
|
|
1507
|
-
*/
|
|
1508
|
-
interface PoolWebBillionSession {
|
|
1509
|
-
/** The proxy's session id. Safe to show: it is a generated handle. */
|
|
1510
|
-
id: string;
|
|
1511
|
-
/** Which wire the session speaks; `openai` is what DSH's shim uses. */
|
|
1512
|
-
protocol: string;
|
|
1513
|
-
/** Whether a request hit this session in the last few seconds. */
|
|
1514
|
-
live: boolean;
|
|
1515
|
-
requests: number;
|
|
1516
|
-
/** The compacted context size the proxy is holding, 0 when unknown. */
|
|
1517
|
-
contextTokens: number;
|
|
1518
|
-
/** Which measurement the context size came from; `usage` is the honest one. */
|
|
1519
|
-
contextTokensSource: string;
|
|
1520
|
-
/** Net tokens the proxy says compression saved. */
|
|
1521
|
-
tokensSaved: number;
|
|
1522
|
-
inputTokens: number;
|
|
1523
|
-
cachedTokens: number;
|
|
1524
|
-
outputTokens: number;
|
|
1525
|
-
/** Cache hit rate 0-100, or -1 when no input tokens were ever counted. */
|
|
1526
|
-
cacheHitPct: number;
|
|
1527
|
-
/** How many compressed blocks this session holds. */
|
|
1528
|
-
blocks: number;
|
|
1529
|
-
/** The window the proxy believes the model has, 0 when unknown. */
|
|
1530
|
-
contextWindow: number;
|
|
1531
|
-
/** ISO timestamp of the last request, or '' when the session never had one. */
|
|
1532
|
-
lastSeen: string;
|
|
1533
|
-
/** The last model the session saw, or '' before the first request. */
|
|
1534
|
-
lastModel: string;
|
|
1535
|
-
}
|
|
1536
|
-
/** The document {@link POOL_BILLION_PATH} answers with. */
|
|
1537
|
-
interface PoolWebBillionStatus {
|
|
1538
|
-
/**
|
|
1539
|
-
* Whether a proxy was found and answered.
|
|
1540
|
-
*
|
|
1541
|
-
* `missing` is a normal, expected state, not an error: billion-context is a
|
|
1542
|
-
* separate plugin, and a machine without it must get a page that explains
|
|
1543
|
-
* that rather than a 503 or a blank panel.
|
|
1544
|
-
*/
|
|
1545
|
-
state: 'ready' | 'missing' | 'unreachable';
|
|
1546
|
-
/** Human text for a non-ready state; absent when ready. */
|
|
1547
|
-
reason?: string;
|
|
1548
|
-
/**
|
|
1549
|
-
* The proxy's own loopback origin, absent only when none was recorded.
|
|
1550
|
-
*
|
|
1551
|
-
* The card needs this to hand the user a browser link: billion-context ships
|
|
1552
|
-
* its own dashboard, including a per-session detail view, and duplicating
|
|
1553
|
-
* those screens here would be a second and divergent copy of another
|
|
1554
|
-
* plugin's interface. Linking out keeps one answer.
|
|
1555
|
-
*
|
|
1556
|
-
* This is a service address, not conversation material, and it is safe to
|
|
1557
|
-
* publish for the same reason the route that carries it is loopback-only: a
|
|
1558
|
-
* caller who can read this document can already reach that listener directly.
|
|
1559
|
-
* It is present on `unreachable` too — a proxy that recorded its port and
|
|
1560
|
-
* then went quiet is exactly the case where the URL is the only handle.
|
|
1561
|
-
*/
|
|
1562
|
-
origin?: string;
|
|
1563
|
-
/** The proxy's version, from its own manifest. */
|
|
1564
|
-
version?: string;
|
|
1565
|
-
/** When the proxy process started (epoch ms), 0 when unknown. */
|
|
1566
|
-
startedAt?: number;
|
|
1567
|
-
/** Sessions newest-first, capped by the route. */
|
|
1568
|
-
sessions: readonly PoolWebBillionSession[];
|
|
1569
|
-
/** How many sessions the proxy holds in total, including capped-out ones. */
|
|
1570
|
-
totalSessions: number;
|
|
1571
|
-
}
|
|
1572
1549
|
/**
|
|
1573
1550
|
* Where a registry provider's key goes: `apiKey`, `baseUrl`, or `enabled`.
|
|
1574
1551
|
*/
|
|
@@ -1577,6 +1554,35 @@ type PoolWebAggregatePatch = {
|
|
|
1577
1554
|
providerId: string;
|
|
1578
1555
|
enabled?: boolean;
|
|
1579
1556
|
apiKey?: string;
|
|
1557
|
+
/**
|
|
1558
|
+
* Every key, preferred first — replaces whatever was stored.
|
|
1559
|
+
*
|
|
1560
|
+
* A REPLACEMENT rather than a delta, for the same reason `models` is: the
|
|
1561
|
+
* card sends the whole list it is showing, and a delta would let two open
|
|
1562
|
+
* tabs interleave into a set neither of them chose. An empty array clears
|
|
1563
|
+
* every key.
|
|
1564
|
+
*/
|
|
1565
|
+
apiKeys?: readonly string[];
|
|
1566
|
+
/**
|
|
1567
|
+
* Append ONE key to the stored list.
|
|
1568
|
+
*
|
|
1569
|
+
* The card cannot send `apiKeys`, because the read route never echoes keys
|
|
1570
|
+
* back — it reports only `keyCount`. A replacement list from the browser
|
|
1571
|
+
* would therefore have to be built from placeholders, and would overwrite
|
|
1572
|
+
* every key the user cannot see. This field says "add this one after the
|
|
1573
|
+
* ones already stored", which is the only instruction the card can honestly
|
|
1574
|
+
* give.
|
|
1575
|
+
*
|
|
1576
|
+
* Ignored when it duplicates a stored key.
|
|
1577
|
+
*/
|
|
1578
|
+
appendApiKey?: string;
|
|
1579
|
+
/**
|
|
1580
|
+
* How requests spread across those keys.
|
|
1581
|
+
*
|
|
1582
|
+
* Same vocabulary as the pool lane (`priority`, `round-robin`, `balanced`,
|
|
1583
|
+
* `sticky`, `expiry`); unknown values are rejected rather than stored.
|
|
1584
|
+
*/
|
|
1585
|
+
distribution?: string;
|
|
1580
1586
|
baseUrl?: string;
|
|
1581
1587
|
/**
|
|
1582
1588
|
* The chosen model set, replacing whatever this provider exposed before.
|
|
@@ -1649,6 +1655,23 @@ interface PoolWebAggregateProvider {
|
|
|
1649
1655
|
discovered: boolean;
|
|
1650
1656
|
/** When the provider was first configured. */
|
|
1651
1657
|
addedAt?: string;
|
|
1658
|
+
/**
|
|
1659
|
+
* How many keys this vendor holds.
|
|
1660
|
+
*
|
|
1661
|
+
* `0` for a keyless vendor, `1` for the ordinary case, more when the user
|
|
1662
|
+
* pasted alternates. The card needs the COUNT rather than the keys themselves —
|
|
1663
|
+
* keys never leave the host — because "account usage" only means anything when
|
|
1664
|
+
* there is something to distribute over: with one key it would be a switch with
|
|
1665
|
+
* a single option and no effect, so the card hides it.
|
|
1666
|
+
*/
|
|
1667
|
+
keyCount: number;
|
|
1668
|
+
/**
|
|
1669
|
+
* The usage strategy in force, when the user has chosen one.
|
|
1670
|
+
*
|
|
1671
|
+
* Absent means the documented default (priority). Shares the pool lane's
|
|
1672
|
+
* vocabulary so both kinds of card present one idea one way.
|
|
1673
|
+
*/
|
|
1674
|
+
distribution?: string;
|
|
1652
1675
|
}
|
|
1653
1676
|
/** The document {@link POOL_AGGREGATE_PATH} answers with. */
|
|
1654
1677
|
interface PoolWebAggregateStatus {
|
|
@@ -1747,6 +1770,19 @@ interface PoolWebComboCandidate {
|
|
|
1747
1770
|
usable: boolean;
|
|
1748
1771
|
contextWindow: number;
|
|
1749
1772
|
supportsImages: boolean;
|
|
1773
|
+
/**
|
|
1774
|
+
* Other lanes that serve the SAME model, best-first, excluding this row.
|
|
1775
|
+
*
|
|
1776
|
+
* The "same model, different route" tier: when one provider rate-limits, the
|
|
1777
|
+
* right move is usually to reach the same model through another provider, not
|
|
1778
|
+
* to fall back to a different model — a different model changes the context
|
|
1779
|
+
* window, tool-calling behaviour and writing style.
|
|
1780
|
+
*
|
|
1781
|
+
* Present so the card can offer "also try this model via …" in one click
|
|
1782
|
+
* instead of making the user find the same name under another vendor and add
|
|
1783
|
+
* it three times. Empty when the model has only one route.
|
|
1784
|
+
*/
|
|
1785
|
+
siblings: readonly string[];
|
|
1750
1786
|
}
|
|
1751
1787
|
/** One chain, resolved against the live roster. */
|
|
1752
1788
|
interface PoolWebCombo {
|
|
@@ -1755,6 +1791,21 @@ interface PoolWebCombo {
|
|
|
1755
1791
|
name: string;
|
|
1756
1792
|
/** Members that exist right now, in order. Empty means the chain is dead. */
|
|
1757
1793
|
models: readonly string[];
|
|
1794
|
+
/**
|
|
1795
|
+
* The chain as PLATFORM GROUPS, for the two-level editor.
|
|
1796
|
+
*
|
|
1797
|
+
* Always present — grouping `models` when the chain was saved flat — so the
|
|
1798
|
+
* editor never has to branch on which shape reached it. `models` stays the flat,
|
|
1799
|
+
* authoritative sequence; this is the same content arranged the way the router
|
|
1800
|
+
* walks it (platform order, then model order within each platform).
|
|
1801
|
+
*
|
|
1802
|
+
* Model ids here are BARE (no `provider/` prefix): the owner is the field beside
|
|
1803
|
+
* them, and carrying the prefix in both invites the two to disagree.
|
|
1804
|
+
*/
|
|
1805
|
+
platforms: readonly {
|
|
1806
|
+
owner: string;
|
|
1807
|
+
models: readonly string[];
|
|
1808
|
+
}[];
|
|
1758
1809
|
/** Members the user configured but which the roster no longer serves. */
|
|
1759
1810
|
missing: readonly string[];
|
|
1760
1811
|
strategy: 'fallback' | 'round-robin';
|
|
@@ -2197,9 +2248,40 @@ interface PoolWebAutomationJob {
|
|
|
2197
2248
|
* what turns a row from "it ran" into "it did the things I care about".
|
|
2198
2249
|
*/
|
|
2199
2250
|
detail?: readonly string[];
|
|
2251
|
+
/**
|
|
2252
|
+
* Per-item outcome of the last run, one entry per thing the job looked at.
|
|
2253
|
+
*
|
|
2254
|
+
* `detail` is free text and mixes counters with titles ("签到 +12",
|
|
2255
|
+
* "复活 Account A"), so the card can print it but cannot GROUP it. This is the
|
|
2256
|
+
* same information with a status attached, which is what makes "which tasks
|
|
2257
|
+
* are still unclaimed, and why" answerable:
|
|
2258
|
+
*
|
|
2259
|
+
* claimed — the reward was collected on this run
|
|
2260
|
+
* already — collected earlier today; nothing to do
|
|
2261
|
+
* skipped — the board would not let it be claimed (locked, no energy, …)
|
|
2262
|
+
* failed — the call came back an error
|
|
2263
|
+
*
|
|
2264
|
+
* Without it, "0 claimed" reads the same whether everything was already done,
|
|
2265
|
+
* the account had no energy, or the endpoint is broken — three situations with
|
|
2266
|
+
* three different fixes.
|
|
2267
|
+
*/
|
|
2268
|
+
items?: readonly PoolWebAutomationItem[];
|
|
2200
2269
|
/** A pending milestone worth naming, e.g. the next streak tier countdown. */
|
|
2201
2270
|
progress?: string;
|
|
2202
2271
|
}
|
|
2272
|
+
/** How one item of an automation run ended. */
|
|
2273
|
+
type PoolWebAutomationItemStatus = 'claimed' | 'already' | 'skipped' | 'failed';
|
|
2274
|
+
/** One item an automation job considered, with what happened to it. */
|
|
2275
|
+
interface PoolWebAutomationItem {
|
|
2276
|
+
/** The task board's own title, or a short label for a non-task step. */
|
|
2277
|
+
title: string;
|
|
2278
|
+
status: PoolWebAutomationItemStatus;
|
|
2279
|
+
/** Credits/energy collected, when the upstream reported any. */
|
|
2280
|
+
credit?: number;
|
|
2281
|
+
energy?: number;
|
|
2282
|
+
/** Why it was skipped or how it failed, in the upstream's words. */
|
|
2283
|
+
note?: string;
|
|
2284
|
+
}
|
|
2203
2285
|
/**
|
|
2204
2286
|
* Automation block on the status document.
|
|
2205
2287
|
*
|
|
@@ -2324,8 +2406,23 @@ interface WorkBuddyModelInfo {
|
|
|
2324
2406
|
* (`kimi-k3-1`). A stale fallback is worse than a short one — it looks
|
|
2325
2407
|
* authoritative while being wrong.
|
|
2326
2408
|
*
|
|
2327
|
-
*
|
|
2328
|
-
*
|
|
2409
|
+
* NO PRICES AND NO PROMO BADGES HERE. This table is what the picker shows when
|
|
2410
|
+
* the startup fetch fails, and a multiplier captured months ago is a price the
|
|
2411
|
+
* user will budget against while it is quietly wrong. Two specific harms:
|
|
2412
|
+
*
|
|
2413
|
+
* - `multiplier: 0` renders the "free" badge, so a model that was free at
|
|
2414
|
+
* capture time keeps claiming to be free after the promotion ends;
|
|
2415
|
+
* - a non-zero multiplier renders next to the model, so a stale figure reads
|
|
2416
|
+
* as the current rate.
|
|
2417
|
+
*
|
|
2418
|
+
* `undefined` is the honest state: the card prints no rate and no badge, which
|
|
2419
|
+
* is exactly true — this build does not know the price. The live fetch fills
|
|
2420
|
+
* both in within a second of a working startup, and `catalogSource` already
|
|
2421
|
+
* tells the card to say the list is the built-in one.
|
|
2422
|
+
*
|
|
2423
|
+
* Windows, output ceilings and the `craft` capability tag stay: those are
|
|
2424
|
+
* properties of the model, not of a campaign, and they are what makes the list
|
|
2425
|
+
* usable offline at all.
|
|
2329
2426
|
*/
|
|
2330
2427
|
export declare const FALLBACK_WORKBUDDY_MODELS: readonly WorkBuddyModelInfo[];
|
|
2331
2428
|
/** Which gateway a catalog describes. Mirrors `WorkBuddyRegion` in `upstream.ts`. */
|
|
@@ -2362,11 +2459,24 @@ export declare class WorkBuddyCatalog {
|
|
|
2362
2459
|
current(): readonly WorkBuddyModelInfo[];
|
|
2363
2460
|
/**
|
|
2364
2461
|
* The models DSH should actually offer, after applying the user's selection:
|
|
2365
|
-
* disabled models are dropped, an explicit image list
|
|
2366
|
-
*
|
|
2462
|
+
* disabled models are dropped, an explicit image list decides image support,
|
|
2463
|
+
* and a per-model budget caps the advertised window.
|
|
2367
2464
|
*
|
|
2368
2465
|
* An absent `enabledModelIds` means "everything" — a fresh install with no
|
|
2369
2466
|
* saved selection must not present an empty picker.
|
|
2467
|
+
*
|
|
2468
|
+
* IMAGE SUPPORT IS THE USER'S SET, NOT AN OR. The upstream flag is `true` for
|
|
2469
|
+
* essentially every model of this vendor (measured: 15 of 16 on CN, 23 of 23
|
|
2470
|
+
* on international), so `supportsImages || imageSet.has(id)` could only ever
|
|
2471
|
+
* turn the flag ON — un-ticking the box in the card changed nothing, and the
|
|
2472
|
+
* adapter kept advertising `['text','image']`. The checkbox existed and did
|
|
2473
|
+
* not work, which is worse than not offering it.
|
|
2474
|
+
*
|
|
2475
|
+
* So when the user HAS saved an image selection, that set is the answer, in
|
|
2476
|
+
* both directions. When they have not (undefined — a fresh install, or a
|
|
2477
|
+
* config written before this fix), the upstream capability stands: silently
|
|
2478
|
+
* disabling image input for everyone who never touched the switch would be a
|
|
2479
|
+
* regression, and the absent case is exactly "no opinion".
|
|
2370
2480
|
*/
|
|
2371
2481
|
visible(): readonly WorkBuddyModelInfo[];
|
|
2372
2482
|
/** Replace the catalog and notify the adapter to rebuild its model list. */
|
|
@@ -2433,7 +2543,42 @@ interface ProviderSetting {
|
|
|
2433
2543
|
* one vendor that WAS configured indistinguishable from the rest.
|
|
2434
2544
|
*/
|
|
2435
2545
|
enabled?: boolean;
|
|
2546
|
+
/**
|
|
2547
|
+
* The FIRST usable key, kept as the single-key spelling.
|
|
2548
|
+
*
|
|
2549
|
+
* Almost every provider needs one key, and a user pasting one must not have to
|
|
2550
|
+
* learn an array to do it. This field and {@link apiKeys} are kept in step by
|
|
2551
|
+
* `updateProviderSetting`: writing `apiKey` sets a one-entry list, and writing
|
|
2552
|
+
* `apiKeys` mirrors its first entry back here. Readers therefore do not have to
|
|
2553
|
+
* know which spelling a config file happens to hold.
|
|
2554
|
+
*/
|
|
2436
2555
|
apiKey?: string;
|
|
2556
|
+
/**
|
|
2557
|
+
* Every key this provider may rotate through.
|
|
2558
|
+
*
|
|
2559
|
+
* The pool has always rotated accounts, but a third-party vendor could only
|
|
2560
|
+
* ever hold ONE key, so "account usage" (priority / round-robin / balanced …)
|
|
2561
|
+
* had nothing to distribute over and was not offered on those cards. A vendor
|
|
2562
|
+
* with several keys on one account — which is how most rate limits are actually
|
|
2563
|
+
* dodged — could not express that at all.
|
|
2564
|
+
*
|
|
2565
|
+
* The first entry is the preferred one; the rest are alternates in order.
|
|
2566
|
+
* Absent or empty means "no key configured", which is the same state `apiKey`
|
|
2567
|
+
* has always described.
|
|
2568
|
+
*/
|
|
2569
|
+
apiKeys?: readonly string[];
|
|
2570
|
+
/**
|
|
2571
|
+
* How requests spread across those keys.
|
|
2572
|
+
*
|
|
2573
|
+
* The same five strategies the pool lane offers, and deliberately the same
|
|
2574
|
+
* vocabulary rather than a second set of names for one idea. Absent means
|
|
2575
|
+
* `priority`: use the preferred key until the vendor refuses it, then move on.
|
|
2576
|
+
*
|
|
2577
|
+
* Only meaningful when {@link apiKeys} holds more than one entry — with a single
|
|
2578
|
+
* key there is nothing to distribute over, which is why the card hides the row
|
|
2579
|
+
* in that case.
|
|
2580
|
+
*/
|
|
2581
|
+
distribution?: string;
|
|
2437
2582
|
/** User override for the base URL, for providers whose host is per-deployment. */
|
|
2438
2583
|
baseUrl?: string;
|
|
2439
2584
|
/**
|
|
@@ -2470,13 +2615,45 @@ interface AggregateSettings {
|
|
|
2470
2615
|
/** Chain strategies. Anything else on disk falls back to `fallback`. */
|
|
2471
2616
|
declare const COMBO_STRATEGIES: readonly ['fallback', 'round-robin'];
|
|
2472
2617
|
type ComboStrategy = (typeof COMBO_STRATEGIES)[number];
|
|
2618
|
+
/**
|
|
2619
|
+
* One platform's contribution to a chain: which lane, and which of its models.
|
|
2620
|
+
*
|
|
2621
|
+
* Chains are edited as a TWO-LEVEL list — platform order, then model order inside
|
|
2622
|
+
* each platform — because that is the order the router actually walks and the
|
|
2623
|
+
* order a reader thinks in ("try the bytes one, then Qoder; if both fail, go to
|
|
2624
|
+
* CodeBuddy"). A flat member list expresses the same sequence but cannot show the
|
|
2625
|
+
* grouping, so re-ordering "all of WorkBuddy's models together" meant moving them
|
|
2626
|
+
* one at a time and hoping none was missed.
|
|
2627
|
+
*
|
|
2628
|
+
* `owner` is `workbuddy` for a pool model, or an aggregate provider id. Model ids
|
|
2629
|
+
* are BARE here (no `provider/` prefix): the prefix is derived from the owner when
|
|
2630
|
+
* the chain is flattened, so storing it twice would let the two disagree.
|
|
2631
|
+
*/
|
|
2632
|
+
interface ComboPlatform {
|
|
2633
|
+
owner: string;
|
|
2634
|
+
models: readonly string[];
|
|
2635
|
+
}
|
|
2473
2636
|
/** A chain as the user configured it, before the catalogs are consulted. */
|
|
2474
2637
|
interface ComboSetting {
|
|
2475
2638
|
/** `combo:<slug>`; derived from the name when absent or malformed. */
|
|
2476
2639
|
id?: string;
|
|
2477
2640
|
name: string;
|
|
2478
|
-
/**
|
|
2641
|
+
/**
|
|
2642
|
+
* Member model ids in the order the user put them — the FLATTENED, authoritative
|
|
2643
|
+
* sequence the router walks.
|
|
2644
|
+
*
|
|
2645
|
+
* Kept as the single source of truth so every resolver, the picker row and the
|
|
2646
|
+
* shim keep reading one field. A chain saved with `platforms` also carries this,
|
|
2647
|
+
* derived from them, so an older build and an older config file both keep working.
|
|
2648
|
+
*/
|
|
2479
2649
|
models: readonly string[];
|
|
2650
|
+
/**
|
|
2651
|
+
* The same chain as platform groups, when it was edited that way.
|
|
2652
|
+
*
|
|
2653
|
+
* Absent for a chain written before this existed, or saved flat. The editor
|
|
2654
|
+
* groups such a chain by owner on the fly, so it opens correctly either way.
|
|
2655
|
+
*/
|
|
2656
|
+
platforms?: readonly ComboPlatform[];
|
|
2480
2657
|
/** How the chain advances; `fallback` restarts from the top each turn. */
|
|
2481
2658
|
strategy?: ComboStrategy;
|
|
2482
2659
|
/** Consecutive turns one member serves before `round-robin` advances. */
|
|
@@ -2553,60 +2730,6 @@ interface RelaySetting {
|
|
|
2553
2730
|
models?: string[];
|
|
2554
2731
|
}
|
|
2555
2732
|
//#endregion
|
|
2556
|
-
//#region src/aggregate.d.ts
|
|
2557
|
-
/** Registry `format` → the wire vocabulary this module speaks. */
|
|
2558
|
-
type AggregateWire = 'chat' | 'responses' | 'messages';
|
|
2559
|
-
/** One model the aggregate lane offers. */
|
|
2560
|
-
interface AggregateModelRow {
|
|
2561
|
-
/** Composite id: `providerId/modelId`, which is also the picker id. */
|
|
2562
|
-
id: string;
|
|
2563
|
-
/** Display name: the provider's own name plus the row's label. */
|
|
2564
|
-
name: string;
|
|
2565
|
-
providerId: string;
|
|
2566
|
-
modelId: string;
|
|
2567
|
-
contextWindow: number;
|
|
2568
|
-
maxOutputTokens: number;
|
|
2569
|
-
supportsImages: boolean;
|
|
2570
|
-
wire: AggregateWire;
|
|
2571
|
-
/** `static` from the registry, `discovered` from a live listing. */
|
|
2572
|
-
source: 'static' | 'discovered';
|
|
2573
|
-
}
|
|
2574
|
-
/** One stored aggregate row set, refreshed on change, for the shim and adapter. */
|
|
2575
|
-
declare class AggregateCatalog {
|
|
2576
|
-
private readonly read;
|
|
2577
|
-
private readonly poolRows;
|
|
2578
|
-
private rows;
|
|
2579
|
-
private chainRows;
|
|
2580
|
-
/**
|
|
2581
|
-
* @param read The settings document.
|
|
2582
|
-
* @param poolRows The pool's own rows, needed only to resolve a chain member
|
|
2583
|
-
* that names a WorkBuddy model. A chain may mix pool models with aggregate
|
|
2584
|
-
* ones, so without this a perfectly valid chain would lose its pool half.
|
|
2585
|
-
*/
|
|
2586
|
-
constructor(read: () => AggregateStore | Promise<AggregateStore>, poolRows?: () => readonly WorkBuddyModelInfo[]);
|
|
2587
|
-
/**
|
|
2588
|
-
* Every row this catalog offers: third-party rows first, then chain rows.
|
|
2589
|
-
*
|
|
2590
|
-
* Chains come last so a picker listing stays readable — a chain is a
|
|
2591
|
-
* convenience over models the user already has listed, not a new vendor.
|
|
2592
|
-
*/
|
|
2593
|
-
current(): readonly (AggregateModelRow | ComboModelRow)[];
|
|
2594
|
-
/** Only the third-party rows, which is what the aggregate resolver needs. */
|
|
2595
|
-
providerRows(): readonly AggregateModelRow[];
|
|
2596
|
-
/** Only the chain rows. */
|
|
2597
|
-
comboRows(): readonly ComboModelRow[];
|
|
2598
|
-
/** Re-read the store and notify listeners when the roster actually changed. */
|
|
2599
|
-
refresh(): Promise<readonly (AggregateModelRow | ComboModelRow)[]>;
|
|
2600
|
-
private listeners;
|
|
2601
|
-
onChange(listener: () => void): () => void;
|
|
2602
|
-
/** One third-party row by composite id, or undefined. */
|
|
2603
|
-
find(id: string): AggregateModelRow | undefined;
|
|
2604
|
-
/** One chain row by combo id, or undefined. */
|
|
2605
|
-
findCombo(id: string): ComboModelRow | undefined;
|
|
2606
|
-
/** Whether any provider or chain is serving anything right now. */
|
|
2607
|
-
hasRows(): boolean;
|
|
2608
|
-
}
|
|
2609
|
-
//#endregion
|
|
2610
2733
|
//#region src/stats.d.ts
|
|
2611
2734
|
/**
|
|
2612
2735
|
* Per-call usage accounting for the chat path.
|
|
@@ -2647,7 +2770,18 @@ interface TokenUsage {
|
|
|
2647
2770
|
}
|
|
2648
2771
|
/** One upstream HTTP round trip, successful or not. */
|
|
2649
2772
|
interface UsageCall {
|
|
2650
|
-
/**
|
|
2773
|
+
/**
|
|
2774
|
+
* Which CHANNEL served the call: `workbuddy`, `free`, or a provider id.
|
|
2775
|
+
*
|
|
2776
|
+
* Until this existed the ledger could only say `地区` (domestic /
|
|
2777
|
+
* international), which is a property of the WorkBuddy pool and of nothing
|
|
2778
|
+
* else. Every row therefore read `国内版` even when the call had gone to a
|
|
2779
|
+
* third-party vendor or to the keyless lane, and the only honest reading of the
|
|
2780
|
+
* table was "the other channels are not recorded at all" — which was true:
|
|
2781
|
+
* only the pool and the free lane ever called `record`.
|
|
2782
|
+
*/
|
|
2783
|
+
channel: string;
|
|
2784
|
+
/** Which WorkBuddy gateway served it: `cn` or `global`; empty for other lanes. */
|
|
2651
2785
|
region: string;
|
|
2652
2786
|
/** The model id the request asked for. */
|
|
2653
2787
|
model: string;
|
|
@@ -2681,6 +2815,14 @@ interface UsageCall {
|
|
|
2681
2815
|
}
|
|
2682
2816
|
/** One row of the per-model aggregate. */
|
|
2683
2817
|
interface UsageRow {
|
|
2818
|
+
/**
|
|
2819
|
+
* The channel this row is about: `workbuddy`, `free`, or a provider id.
|
|
2820
|
+
*
|
|
2821
|
+
* Part of the grouping key, not just a label. Two vendors can publish the same
|
|
2822
|
+
* model id, and the pool and the free lane can both serve `glm-5.3` — summing
|
|
2823
|
+
* them into one row would attribute a third-party vendor's tokens to WorkBuddy.
|
|
2824
|
+
*/
|
|
2825
|
+
channel: string;
|
|
2684
2826
|
region: string;
|
|
2685
2827
|
model: string;
|
|
2686
2828
|
/** Physical upstream calls. */
|
|
@@ -2706,6 +2848,14 @@ interface UsageRow {
|
|
|
2706
2848
|
interface UsageAccountRow {
|
|
2707
2849
|
/** Display label of the account, as the pool prints it. */
|
|
2708
2850
|
account: string;
|
|
2851
|
+
/**
|
|
2852
|
+
* The channel this account belongs to.
|
|
2853
|
+
*
|
|
2854
|
+
* Part of the grouping key: a provider's key and a pool account are different
|
|
2855
|
+
* things even when both are labelled, and `free` is not a WorkBuddy account at
|
|
2856
|
+
* all.
|
|
2857
|
+
*/
|
|
2858
|
+
channel: string;
|
|
2709
2859
|
/** Region the account belongs to; an account serves one gateway. */
|
|
2710
2860
|
region: string;
|
|
2711
2861
|
/** Physical calls this account served. */
|
|
@@ -2817,6 +2967,60 @@ declare class UsageRecorder {
|
|
|
2817
2967
|
private days;
|
|
2818
2968
|
}
|
|
2819
2969
|
//#endregion
|
|
2970
|
+
//#region src/aggregate.d.ts
|
|
2971
|
+
/** Registry `format` → the wire vocabulary this module speaks. */
|
|
2972
|
+
type AggregateWire = 'chat' | 'responses' | 'messages';
|
|
2973
|
+
/** One model the aggregate lane offers. */
|
|
2974
|
+
interface AggregateModelRow {
|
|
2975
|
+
/** Composite id: `providerId/modelId`, which is also the picker id. */
|
|
2976
|
+
id: string;
|
|
2977
|
+
/** Display name: the provider's own name plus the row's label. */
|
|
2978
|
+
name: string;
|
|
2979
|
+
providerId: string;
|
|
2980
|
+
modelId: string;
|
|
2981
|
+
contextWindow: number;
|
|
2982
|
+
maxOutputTokens: number;
|
|
2983
|
+
supportsImages: boolean;
|
|
2984
|
+
wire: AggregateWire;
|
|
2985
|
+
/** `static` from the registry, `discovered` from a live listing. */
|
|
2986
|
+
source: 'static' | 'discovered';
|
|
2987
|
+
}
|
|
2988
|
+
/** One stored aggregate row set, refreshed on change, for the shim and adapter. */
|
|
2989
|
+
declare class AggregateCatalog {
|
|
2990
|
+
private readonly read;
|
|
2991
|
+
private readonly poolRows;
|
|
2992
|
+
private rows;
|
|
2993
|
+
private chainRows;
|
|
2994
|
+
/**
|
|
2995
|
+
* @param read The settings document.
|
|
2996
|
+
* @param poolRows The pool's own rows, needed only to resolve a chain member
|
|
2997
|
+
* that names a WorkBuddy model. A chain may mix pool models with aggregate
|
|
2998
|
+
* ones, so without this a perfectly valid chain would lose its pool half.
|
|
2999
|
+
*/
|
|
3000
|
+
constructor(read: () => AggregateStore | Promise<AggregateStore>, poolRows?: () => readonly WorkBuddyModelInfo[]);
|
|
3001
|
+
/**
|
|
3002
|
+
* Every row this catalog offers: third-party rows first, then chain rows.
|
|
3003
|
+
*
|
|
3004
|
+
* Chains come last so a picker listing stays readable — a chain is a
|
|
3005
|
+
* convenience over models the user already has listed, not a new vendor.
|
|
3006
|
+
*/
|
|
3007
|
+
current(): readonly (AggregateModelRow | ComboModelRow)[];
|
|
3008
|
+
/** Only the third-party rows, which is what the aggregate resolver needs. */
|
|
3009
|
+
providerRows(): readonly AggregateModelRow[];
|
|
3010
|
+
/** Only the chain rows. */
|
|
3011
|
+
comboRows(): readonly ComboModelRow[];
|
|
3012
|
+
/** Re-read the store and notify listeners when the roster actually changed. */
|
|
3013
|
+
refresh(): Promise<readonly (AggregateModelRow | ComboModelRow)[]>;
|
|
3014
|
+
private listeners;
|
|
3015
|
+
onChange(listener: () => void): () => void;
|
|
3016
|
+
/** One third-party row by composite id, or undefined. */
|
|
3017
|
+
find(id: string): AggregateModelRow | undefined;
|
|
3018
|
+
/** One chain row by combo id, or undefined. */
|
|
3019
|
+
findCombo(id: string): ComboModelRow | undefined;
|
|
3020
|
+
/** Whether any provider or chain is serving anything right now. */
|
|
3021
|
+
hasRows(): boolean;
|
|
3022
|
+
}
|
|
3023
|
+
//#endregion
|
|
2820
3024
|
//#region src/channel-lane.d.ts
|
|
2821
3025
|
/** One model as the gateway lists and routes it. */
|
|
2822
3026
|
interface ChannelLaneRow {
|
|
@@ -3220,6 +3424,16 @@ interface AutomationJobState {
|
|
|
3220
3424
|
* is the question the panel exists to answer.
|
|
3221
3425
|
*/
|
|
3222
3426
|
detail?: readonly string[];
|
|
3427
|
+
/**
|
|
3428
|
+
* The same work with a status per item.
|
|
3429
|
+
*
|
|
3430
|
+
* `detail` is a flat list of sentences, so the card can print it but cannot
|
|
3431
|
+
* group it. This carries `claimed` / `already` / `skipped` / `failed` per
|
|
3432
|
+
* thing the job looked at, which is what separates "everything was already
|
|
3433
|
+
* done" from "nothing was claimable" from "the endpoint is down" — three
|
|
3434
|
+
* outcomes that all print as "0 claimed".
|
|
3435
|
+
*/
|
|
3436
|
+
items?: readonly PoolWebAutomationItem[];
|
|
3223
3437
|
/**
|
|
3224
3438
|
* A pending milestone worth naming, when there is one.
|
|
3225
3439
|
*
|
|
@@ -3405,6 +3619,16 @@ export declare class WorkBuddyScheduler {
|
|
|
3405
3619
|
/** Host hooks that persist the ledger across restarts. */
|
|
3406
3620
|
private readonly loadEarnings;
|
|
3407
3621
|
private saveEarningsFn;
|
|
3622
|
+
/**
|
|
3623
|
+
* The most recent ledger write that may still be in flight.
|
|
3624
|
+
*
|
|
3625
|
+
* `persistEarnings` is synchronous from its callers' point of view, but the
|
|
3626
|
+
* host's settings write is not: it is an async document update. Keeping the
|
|
3627
|
+
* promise here is what lets {@link flushEarnings} wait for the write that
|
|
3628
|
+
* matters — the last one before a restart — without making every counter
|
|
3629
|
+
* update await disk.
|
|
3630
|
+
*/
|
|
3631
|
+
private pendingEarningsWrite;
|
|
3408
3632
|
constructor(pool: WorkBuddyAccountPool, client: WorkBuddyUpstreamClient, options?: AutomationOptions);
|
|
3409
3633
|
/** Apply a new configuration; safe to call while running. */
|
|
3410
3634
|
/**
|
|
@@ -3415,6 +3639,16 @@ export declare class WorkBuddyScheduler {
|
|
|
3415
3639
|
* would have nowhere to go.
|
|
3416
3640
|
*/
|
|
3417
3641
|
setEarningsPersistence(save: (ledger: AutomationLedger) => void | Promise<void>): void;
|
|
3642
|
+
/**
|
|
3643
|
+
* Wait for the ledger write that is (or was last) in flight.
|
|
3644
|
+
*
|
|
3645
|
+
* Called at the END of a task pass, right after the last claim, so the rewards
|
|
3646
|
+
* that were just collected are on disk before a restart can lose them. It is
|
|
3647
|
+
* deliberately NOT awaited on every counter bump: the settings document write
|
|
3648
|
+
* is the slow part, and paying it per account would slow the pass for no
|
|
3649
|
+
* benefit while the process is still alive.
|
|
3650
|
+
*/
|
|
3651
|
+
flushEarnings(): Promise<void>;
|
|
3418
3652
|
/**
|
|
3419
3653
|
* Fold a previously persisted ledger back in, when it belongs to today.
|
|
3420
3654
|
*
|
|
@@ -3528,6 +3762,14 @@ export declare class WorkBuddyScheduler {
|
|
|
3528
3762
|
* Best effort on purpose: a failed save must never abort a run that has
|
|
3529
3763
|
* already collected rewards, and the in-memory ledger keeps serving the card
|
|
3530
3764
|
* for the rest of the session either way.
|
|
3765
|
+
*
|
|
3766
|
+
* The returned promise settles when the write has landed (or failed). Callers
|
|
3767
|
+
* that are about to END a run await it: reported in #98, a task pass that
|
|
3768
|
+
* claimed 21 tasks had its process restarted before the volatile settings
|
|
3769
|
+
* write reached disk, so `automationEarnings` still read `credit: 0` while
|
|
3770
|
+
* the upstream had really paid out. Fire-and-forget is fine for a counter the
|
|
3771
|
+
* card will re-read in this process; it is not fine for the last write before
|
|
3772
|
+
* exit.
|
|
3531
3773
|
*/
|
|
3532
3774
|
private persistEarnings;
|
|
3533
3775
|
/**
|
|
@@ -3554,6 +3796,10 @@ export declare class WorkBuddyScheduler {
|
|
|
3554
3796
|
*
|
|
3555
3797
|
* Disabled accounts are excluded here rather than filtered by the caller so a
|
|
3556
3798
|
* card switch takes effect on the next pass without any event plumbing.
|
|
3799
|
+
*
|
|
3800
|
+
* `job` narrows the set by region scope: the growth jobs are CN-only while
|
|
3801
|
+
* check-in runs on both gateways, so eligibility cannot be decided without
|
|
3802
|
+
* knowing which job is about to run.
|
|
3557
3803
|
*/
|
|
3558
3804
|
private accountsInOrder;
|
|
3559
3805
|
/**
|
|
@@ -3584,6 +3830,38 @@ export declare class WorkBuddyScheduler {
|
|
|
3584
3830
|
* this is async.
|
|
3585
3831
|
*/
|
|
3586
3832
|
private chainsFor;
|
|
3833
|
+
/**
|
|
3834
|
+
* Summon-and-use one expert NAMED BY THE TASK.
|
|
3835
|
+
*
|
|
3836
|
+
* Structurally `expertChains` minus the marketplace: the expert id is read
|
|
3837
|
+
* from the task's deeplink instead of by browsing `marketExpertList`, because
|
|
3838
|
+
* this family's experts are not listed there at all (#98 measured 500 entries
|
|
3839
|
+
* across both `agent` and `team`, zero hits).
|
|
3840
|
+
*
|
|
3841
|
+
* Returns `[]` — not a throw — when the task carries no usable id: the caller
|
|
3842
|
+
* logs "could not be built" only for exceptions, and a task shape this code
|
|
3843
|
+
* does not understand is information, not a fault.
|
|
3844
|
+
*/
|
|
3845
|
+
/**
|
|
3846
|
+
* Find the expert a task is about, by matching its title against the
|
|
3847
|
+
* marketplace.
|
|
3848
|
+
*
|
|
3849
|
+
* The marketplace listing is ~500 entries across `agent` and `team`, and this
|
|
3850
|
+
* only runs for a task whose deeplink carried no id — at most a handful per
|
|
3851
|
+
* run — so the cost is acceptable. It is not cached because a freshly
|
|
3852
|
+
* published expert must become findable without a restart.
|
|
3853
|
+
*
|
|
3854
|
+
* Matching rules, all of them strict on purpose:
|
|
3855
|
+
* - the task's title must appear IN the expert's name or profession, or the
|
|
3856
|
+
* expert's display name must appear in the title (both directions, since
|
|
3857
|
+
* the board and the marketplace word things differently);
|
|
3858
|
+
* - comparison ignores case, whitespace and the punctuation vendors sprinkle
|
|
3859
|
+
* through names;
|
|
3860
|
+
* - several matches means NO answer. Summoning the wrong agent scores 0, so a
|
|
3861
|
+
* guess costs an upstream call and still fails — worse than declining.
|
|
3862
|
+
*/
|
|
3863
|
+
private expertIdByKeyword;
|
|
3864
|
+
private taskExpertChains;
|
|
3587
3865
|
/**
|
|
3588
3866
|
* The summon-and-use chains for the expert tasks.
|
|
3589
3867
|
*
|
|
@@ -3979,21 +4257,21 @@ interface PoolStatusRouteOptions {
|
|
|
3979
4257
|
* a chain name, and does what it names still exist" — and answering them from
|
|
3980
4258
|
* two snapshots could show a member that the chains no longer resolve.
|
|
3981
4259
|
*/
|
|
3982
|
-
|
|
4260
|
+
/**
|
|
4261
|
+
* The routing document.
|
|
4262
|
+
*
|
|
4263
|
+
* May return a PROMISE: login-channel rows come from the host's
|
|
4264
|
+
* `llm.listModels`, which is asynchronous, and a chain that cannot name TRAE or
|
|
4265
|
+
* Qoder is precisely the defect this document had. A synchronous build keeps
|
|
4266
|
+
* returning the object directly, so both shapes are accepted rather than forcing
|
|
4267
|
+
* every caller to become async.
|
|
4268
|
+
*/
|
|
4269
|
+
combosDocument?: () => PoolWebCombosStatus | Promise<PoolWebCombosStatus>;
|
|
3983
4270
|
/**
|
|
3984
4271
|
* Replace the chain table and refresh the running catalog, then re-answer the
|
|
3985
4272
|
* document. The catalog refresh is what makes a new chain pickable at once.
|
|
3986
4273
|
*/
|
|
3987
4274
|
saveCombos?: (raw: unknown) => Promise<PoolWebCombosStatus>;
|
|
3988
|
-
/**
|
|
3989
|
-
* What the locally running billion-context proxy is doing, read-only.
|
|
3990
|
-
*
|
|
3991
|
-
* Absent when the module could not be wired: the route then answers 503
|
|
3992
|
-
* rather than pretending a third-party proxy reported nothing. It never
|
|
3993
|
-
* rejects — a missing proxy is a normal state with its own `reason`, because
|
|
3994
|
-
* billion-context is a separate optional plugin.
|
|
3995
|
-
*/
|
|
3996
|
-
billionDocument?: () => Promise<PoolWebBillionStatus>;
|
|
3997
4275
|
/**
|
|
3998
4276
|
* The relay's current state, or undefined when this build has no relay.
|
|
3999
4277
|
*
|
|
@@ -4110,6 +4388,15 @@ export interface Config {
|
|
|
4110
4388
|
* does not wipe what the automation already earned.
|
|
4111
4389
|
*/
|
|
4112
4390
|
automationEarnings?: AutomationLedger;
|
|
4391
|
+
/**
|
|
4392
|
+
* Whether the shared 免密 free lane contributes models.
|
|
4393
|
+
*
|
|
4394
|
+
* Absent reads as OFF. It is the only lane that defaults off: it is a shared
|
|
4395
|
+
* third-party endpoint with no credential of the user's own, so leaving it on
|
|
4396
|
+
* dropped a group into the model picker that nothing in the UI could remove
|
|
4397
|
+
* (the aggregate switch does not govern it — it is not an aggregate provider).
|
|
4398
|
+
*/
|
|
4399
|
+
freeLane?: boolean;
|
|
4113
4400
|
}
|
|
4114
4401
|
/** One region's saved model selection. */
|
|
4115
4402
|
export interface ModelSelectionConfig {
|