dsh-connect-workbuddy 4.14.1 → 5.0.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 +183 -0
- package/README.en.md +22 -4
- package/README.md +22 -4
- package/lib/bin.js +1 -1
- package/lib/client.js +463 -109
- package/lib/{host-heartbeat-D1WnqQY2.js → host-heartbeat-D313ENPV.js} +952 -53
- package/lib/index.d.ts +182 -1
- package/lib/index.js +434 -10
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +3 -1
package/lib/index.d.ts
CHANGED
|
@@ -574,6 +574,27 @@ declare class WorkBuddyCredentialStore {
|
|
|
574
574
|
}>;
|
|
575
575
|
}
|
|
576
576
|
//#endregion
|
|
577
|
+
//#region src/image-gen.d.ts
|
|
578
|
+
/**
|
|
579
|
+
* 产品配置 `data.models` 里的一个媒体模型条目。
|
|
580
|
+
*
|
|
581
|
+
* 实测上游只给三个字段(`{"id":"hunyuan-image-alpha","name":"Hunyuan Image Alpha",
|
|
582
|
+
* "tags":["text-to-image"]}`),没有 credits、没有上下文长度。不要在这里补
|
|
583
|
+
* 上游没有的字段——那正是「不猜」红线的反面。
|
|
584
|
+
*/
|
|
585
|
+
interface WorkBuddyMediaModel {
|
|
586
|
+
readonly id: string;
|
|
587
|
+
readonly name: string;
|
|
588
|
+
readonly tags: readonly string[];
|
|
589
|
+
}
|
|
590
|
+
/** 上游成功响应的归一化结果。`url` 与 `b64` 至少有一个。 */
|
|
591
|
+
interface WorkBuddyImageOutcome {
|
|
592
|
+
readonly url?: string;
|
|
593
|
+
readonly b64?: string;
|
|
594
|
+
readonly created?: number;
|
|
595
|
+
readonly credit?: number;
|
|
596
|
+
}
|
|
597
|
+
//#endregion
|
|
577
598
|
//#region src/promo.d.ts
|
|
578
599
|
/**
|
|
579
600
|
* WorkBuddy promotion & tier badges — the upstream's own "this model is on
|
|
@@ -747,6 +768,59 @@ interface WorkBuddyPromo {
|
|
|
747
768
|
priority: number;
|
|
748
769
|
}
|
|
749
770
|
//#endregion
|
|
771
|
+
//#region src/busy.d.ts
|
|
772
|
+
/**
|
|
773
|
+
* WorkBuddy model load — the "繁忙程度" line the WorkBuddy client draws under a
|
|
774
|
+
* model, read from the upstream's own probe and rendered next to the model name.
|
|
775
|
+
*
|
|
776
|
+
* WHY A SEPARATE REQUEST, AND WHY IT COSTS ALMOST NOTHING. Load is NOT part of
|
|
777
|
+
* the model directory: `/v3/config` lists models and prices, and says nothing
|
|
778
|
+
* about how busy each one is right now. The app asks a dedicated probe —
|
|
779
|
+
* `POST /v2/chat/busy { models: [...] }` — and so does this plugin, exactly once
|
|
780
|
+
* per model-picker refresh, batched at the upstream's own limit of 50 ids per
|
|
781
|
+
* call. The probe is read-only and free (no credits, no account mutation):
|
|
782
|
+
* measured 2026-10-21 on the CN gateway, HTTP 200 with
|
|
783
|
+
*
|
|
784
|
+
* {"code":0,"msg":"OK","requestId":"…","data":[
|
|
785
|
+
* {"model":"hy3","busy_level":"busy"},
|
|
786
|
+
* {"model":"deepseek-v4.1-flash","busy_level":"congested"}]}
|
|
787
|
+
*
|
|
788
|
+
* IDENTICAL ON EVERY CN HOST AND UNDER EITHER CLIENT IDENTITY. `copilot.tencent.com`,
|
|
789
|
+
* `www.workbuddy.cn` and `www.codebuddy.cn` answer byte-for-byte the same list,
|
|
790
|
+
* and so do the CLI user agent (`CLI/2.63.2 CodeBuddy/2.63.2`) and the app's
|
|
791
|
+
* product identity (`WorkBuddy/5.8.3 WorkBuddy/5.8.3 CLI/2.161.0`). Unlike
|
|
792
|
+
* `/v3/config`, this endpoint is not channel-sensitive, so the plugin asks it as
|
|
793
|
+
* the CLI agent it already is on the chat path — no product identity needed.
|
|
794
|
+
*
|
|
795
|
+
* THE LEVELS ARE THE APP'S OWN ENUM, and anything outside it is `unknown`:
|
|
796
|
+
* `idle` / `normal` / `busy` / `congested` / `unavailable`. The app's own words
|
|
797
|
+
* (from its `im-channels` bundle, `chatInput.modelSelector.busy.*`) are
|
|
798
|
+
* 空闲 / 轻微拥堵 / 极度拥堵 / 不可用; English reads Idle / Slightly congested /
|
|
799
|
+
* Extremely congested / Unavailable.
|
|
800
|
+
*
|
|
801
|
+
* WHY THE LABELS LIVE HERE AND NOT IN THE UPSTREAM CLIENT. The probe returns a
|
|
802
|
+
* machine level, never text: the same response is drawn differently by the app
|
|
803
|
+
* (an icon for `congested`, a word for the rest), so the rendering decision
|
|
804
|
+
* belongs with the renderer. This module keeps the words, the tone, and the
|
|
805
|
+
* "which levels are worth drawing at all" rule in one place.
|
|
806
|
+
*
|
|
807
|
+
* NOTHING HERE IS PERSISTED. Load is a fact about THIS MINUTE: a cached level
|
|
808
|
+
* that survives a restart is a lie, and the model directory is saved to disk
|
|
809
|
+
* while a level must not be. So the level is attached to the catalog entry at
|
|
810
|
+
* refresh time and nowhere else — see `attachBusyLevels` and `src/index.ts`.
|
|
811
|
+
*
|
|
812
|
+
* @module dsh-connect-workbuddy/busy
|
|
813
|
+
*/
|
|
814
|
+
/**
|
|
815
|
+
* One model's load, in the upstream's vocabulary.
|
|
816
|
+
*
|
|
817
|
+
* `unknown` is the plugin's own value, not the upstream's: it is what an
|
|
818
|
+
* unusable entry becomes (a missing level, a level outside the enum, a model the
|
|
819
|
+
* probe did not answer for). It is deliberately distinct from `normal` — "we
|
|
820
|
+
* were told nothing" must not be drawn as "all good".
|
|
821
|
+
*/
|
|
822
|
+
type WorkBuddyBusyLevel = 'idle' | 'normal' | 'busy' | 'congested' | 'unavailable' | 'unknown';
|
|
823
|
+
//#endregion
|
|
750
824
|
//#region src/upstream.d.ts
|
|
751
825
|
/** WorkBuddy region selected by the credential's login domain. */
|
|
752
826
|
type WorkBuddyRegion = 'cn' | 'global';
|
|
@@ -802,7 +876,27 @@ type UpstreamErrorKind = 'hard_credit' |
|
|
|
802
876
|
* later and each attempt teaches the pool a false fact about a credential
|
|
803
877
|
* that was never the problem.
|
|
804
878
|
*/
|
|
805
|
-
'channel_reject' |
|
|
879
|
+
'channel_reject' |
|
|
880
|
+
/**
|
|
881
|
+
* The upstream put this request in a queue instead of running it: business
|
|
882
|
+
* codes `6020` (waiting, with a position), `6021` (queue full), `6022` (this
|
|
883
|
+
* user already holds the maximum). See `src/queue.ts`.
|
|
884
|
+
*
|
|
885
|
+
* Its own kind because it is the ONE failure where the credential was fine,
|
|
886
|
+
* the request was fine, and the server already accepted the work — telling the
|
|
887
|
+
* user "请求失败" or rotating accounts is wrong on both counts. A queued
|
|
888
|
+
* request follows the MODEL and the shared queue, not the account, so another
|
|
889
|
+
* account is handed the same position: NOT failover-worthy (see
|
|
890
|
+
* `isFailoverWorthy` in the shim).
|
|
891
|
+
*
|
|
892
|
+
* Classified BEFORE the plain status branches: the queue condition arrives as
|
|
893
|
+
* a business code and the HTTP status it rides on is incidental (observed on
|
|
894
|
+
* 200-shaped envelopes and on 429/500). Without this member it fell through to
|
|
895
|
+
* `server`/`soft_rate`, both of which DO fail over — so hitting a queue walked
|
|
896
|
+
* the whole account pool, burning a real request per account, before saying
|
|
897
|
+
* "you are #8777 in line".
|
|
898
|
+
*/
|
|
899
|
+
'model_queue' | 'not_found' | 'server' | 'client';
|
|
806
900
|
/** Reasoning capability as the upstream catalog declares it. */
|
|
807
901
|
interface WorkBuddyReasoning {
|
|
808
902
|
supportedEfforts?: readonly string[];
|
|
@@ -864,6 +958,16 @@ interface WorkBuddyUpstreamModel {
|
|
|
864
958
|
* not where the document was read. See `src/promo.ts`.
|
|
865
959
|
*/
|
|
866
960
|
promos?: readonly WorkBuddyPromo[];
|
|
961
|
+
/**
|
|
962
|
+
* How busy this model is RIGHT NOW, from the upstream's own probe
|
|
963
|
+
* (`POST /v2/chat/busy`, see `src/busy.ts`).
|
|
964
|
+
*
|
|
965
|
+
* Deliberately NOT part of the catalog document, and deliberately not
|
|
966
|
+
* persisted: the directory is a fact that survives a restart, a load level is
|
|
967
|
+
* a fact about the minute it was measured. It is stamped onto the in-memory
|
|
968
|
+
* catalog entry at refresh time and disappears with the process.
|
|
969
|
+
*/
|
|
970
|
+
busyLevel?: WorkBuddyBusyLevel;
|
|
867
971
|
}
|
|
868
972
|
/** One billing package as the upstream returns it, dates already parsed. */
|
|
869
973
|
interface WorkBuddyCreditPackage {
|
|
@@ -1231,6 +1335,48 @@ declare class WorkBuddyUpstreamClient {
|
|
|
1231
1335
|
* one step upstream of it).
|
|
1232
1336
|
*/
|
|
1233
1337
|
fetchModels(credential: WorkBuddyCredential, signal?: AbortSignal, keepModelIds?: readonly string[]): Promise<readonly WorkBuddyUpstreamModel[]>;
|
|
1338
|
+
/**
|
|
1339
|
+
* Read how busy each model is right now, from the upstream's own probe.
|
|
1340
|
+
*
|
|
1341
|
+
* Batched at the upstream's ceiling (`WORKBUDDY_BUSY_BATCH_SIZE`), because the
|
|
1342
|
+
* probe takes a list of ids and answers only about the ids it was given.
|
|
1343
|
+
*
|
|
1344
|
+
* Throws on anything that is not a clean `code: 0`, like every other reader in
|
|
1345
|
+
* this class — the CALLER decides that a failed load probe is survivable and
|
|
1346
|
+
* catches it. Nothing here is persisted: the level belongs to the refresh that
|
|
1347
|
+
* asked for it.
|
|
1348
|
+
*/
|
|
1349
|
+
fetchModelBusy(credential: WorkBuddyCredential, modelIds: readonly string[], signal?: AbortSignal): Promise<Map<string, WorkBuddyBusyLevel>>;
|
|
1350
|
+
/**
|
|
1351
|
+
* 读该账号所属区的产品配置,挑出带 `text-to-image` 标签的媒体模型。
|
|
1352
|
+
*
|
|
1353
|
+
* 走的是和 {@link fetchModels} 同一条 `/v3/config`(国内区与国际区都答),
|
|
1354
|
+
* 区别只在这里保留 `data.models` 的媒体条目、而不是投影成 CLI 聊天目录。
|
|
1355
|
+
* 国内区实测 62 条模型里只有 `hunyuan-image-alpha` 带 `text-to-image`;
|
|
1356
|
+
* 国际区一条都没有 —— 所以本方法对国际区返回空数组,而不是编一个模型出来。
|
|
1357
|
+
*
|
|
1358
|
+
* 这是一次 EXTRA 读取,不是「复用目录那一次」:`fetchModels` 的结果被投影成
|
|
1359
|
+
* 聊天目录就丢掉了媒体标签,所以这里必须再读一遍同一份文档。它是只读 GET、
|
|
1360
|
+
* 不花积分,且工具侧有 5 分钟缓存,但「零新增请求」的说法不成立,别那么写。
|
|
1361
|
+
* 国内区与 {@link fetchModels} 一样走 `/v3` → `/v2` 降级:上游一旦不答
|
|
1362
|
+
* `/v3`,聊天目录会降级而这里不能变成一个原始异常。
|
|
1363
|
+
*/
|
|
1364
|
+
fetchMediaModels(credential: WorkBuddyCredential, signal?: AbortSignal): Promise<readonly WorkBuddyMediaModel[]>;
|
|
1365
|
+
/**
|
|
1366
|
+
* 发一次文生图请求。
|
|
1367
|
+
*
|
|
1368
|
+
* 端点、请求体、响应解析全部照抄官方 CLI 的 ImageService(见 `image-gen.ts`
|
|
1369
|
+
* 的模块注释)。实测单张 5.71 credits,产物是 24 小时有效的 COS 签名 URL。
|
|
1370
|
+
*
|
|
1371
|
+
* 失败分两层:HTTP 非 2xx 交给 {@link describeImageFailure} 翻成带 code 的
|
|
1372
|
+
* 错误(401/403 提示重新登录、404 提示该区没有生图路由、429 提示限流);
|
|
1373
|
+
* HTTP 200 但信封 `code !== 0` 由 {@link parseImageResponse} 处理。
|
|
1374
|
+
*/
|
|
1375
|
+
generateImage(credential: WorkBuddyCredential, request: {
|
|
1376
|
+
readonly model: string;
|
|
1377
|
+
readonly prompt: string;
|
|
1378
|
+
readonly size?: string;
|
|
1379
|
+
}, signal?: AbortSignal): Promise<WorkBuddyImageOutcome>;
|
|
1234
1380
|
/** Query today's check-in status without changing account state. */
|
|
1235
1381
|
fetchCheckinStatus(credential: WorkBuddyCredential): Promise<WorkBuddyCheckinStatus>;
|
|
1236
1382
|
/**
|
|
@@ -2938,6 +3084,15 @@ type WorkBuddyWebUsage =
|
|
|
2938
3084
|
* "关闭不了" report.
|
|
2939
3085
|
*/
|
|
2940
3086
|
showCreditsInMainUi?: boolean;
|
|
3087
|
+
/**
|
|
3088
|
+
* Whether the model may call the image-generation tool here (opt-in).
|
|
3089
|
+
*
|
|
3090
|
+
* Travels on the Host's answer for the same reason as the fields around it,
|
|
3091
|
+
* and matters more: a checkbox rendering a stale value would let the user
|
|
3092
|
+
* believe the spending capability was ON when it is off, or leave it on
|
|
3093
|
+
* after a switch-off that never landed.
|
|
3094
|
+
*/
|
|
3095
|
+
imageToolEnabled?: boolean;
|
|
2941
3096
|
/** WHERE this region's readout sits (issue #62); absent means `composer`. */
|
|
2942
3097
|
creditPosition?: WorkBuddyCreditPosition;
|
|
2943
3098
|
message?: string;
|
|
@@ -2974,6 +3129,15 @@ type WorkBuddyWebUsage =
|
|
|
2974
3129
|
* settings mirror.
|
|
2975
3130
|
*/
|
|
2976
3131
|
showCreditsInMainUi?: boolean;
|
|
3132
|
+
/**
|
|
3133
|
+
* Whether the model may call the image-generation tool here (opt-in).
|
|
3134
|
+
*
|
|
3135
|
+
* Travels on the Host's answer for the same reason as the fields around it,
|
|
3136
|
+
* and matters more: a checkbox rendering a stale value would let the user
|
|
3137
|
+
* believe the spending capability was ON when it is off, or leave it on
|
|
3138
|
+
* after a switch-off that never landed.
|
|
3139
|
+
*/
|
|
3140
|
+
imageToolEnabled?: boolean;
|
|
2977
3141
|
/** WHERE this region's readout sits (issue #62); absent means `composer`. */
|
|
2978
3142
|
creditPosition?: WorkBuddyCreditPosition;
|
|
2979
3143
|
source?: 'desktop' | 'dsh';
|
|
@@ -3419,6 +3583,14 @@ interface WorkBuddyStatusRouteOptions {
|
|
|
3419
3583
|
* existed, so a Host that predates it renders exactly as it used to.
|
|
3420
3584
|
*/
|
|
3421
3585
|
creditPosition?(region: WorkBuddyRegion): WorkBuddyCreditPosition;
|
|
3586
|
+
/**
|
|
3587
|
+
* Whether the model may call the image-generation tool in this region.
|
|
3588
|
+
*
|
|
3589
|
+
* Optional, and absent reads as OFF — the opposite of the fields above. This
|
|
3590
|
+
* one authorizes the MODEL to spend credits on its own, so an older Host that
|
|
3591
|
+
* cannot answer must not be read as consent.
|
|
3592
|
+
*/
|
|
3593
|
+
imageToolEnabled?(region: WorkBuddyRegion): boolean;
|
|
3422
3594
|
/**
|
|
3423
3595
|
* Send one real-volume request to each named model of a region and report what
|
|
3424
3596
|
* came back.
|
|
@@ -3824,6 +3996,15 @@ interface WorkBuddyRegionState {
|
|
|
3824
3996
|
* written before this switch existed keeps whatever the default was.
|
|
3825
3997
|
*/
|
|
3826
3998
|
showCreditsInMainUi?: boolean;
|
|
3999
|
+
/**
|
|
4000
|
+
* Whether the model may call the image-generation tool here (opt-IN).
|
|
4001
|
+
*
|
|
4002
|
+
* The only switch in this interface where an ABSENT value means OFF. Every
|
|
4003
|
+
* other flag here governs something the user can undo by clicking again;
|
|
4004
|
+
* this one authorizes the model to spend real credits on its own, so an
|
|
4005
|
+
* upgrade — or a config whose value could not be read — must leave it off.
|
|
4006
|
+
*/
|
|
4007
|
+
imageToolEnabled?: boolean;
|
|
3827
4008
|
/**
|
|
3828
4009
|
* WHERE this region's credit readout sits (issue #62).
|
|
3829
4010
|
*
|