dsh-connect-workbuddy 5.9.0 → 5.10.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 +46 -0
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/lib/bin.js +1 -1
- package/lib/client.js +247 -8
- package/lib/{host-heartbeat-C1tVU2IN.js → host-heartbeat-_EeM2YDF.js} +176 -22
- package/lib/index.d.ts +65 -5
- package/lib/index.js +207 -32
- package/package.json +1 -1
|
@@ -1158,18 +1158,43 @@ function queueNoticeText(report) {
|
|
|
1158
1158
|
* - `gemini-*` :什么都不加
|
|
1159
1159
|
* - 其它 :`response_format: 'b64_json'` + 可选 `n` / `quality` / `style` / `background`
|
|
1160
1160
|
*
|
|
1161
|
-
*
|
|
1162
|
-
*
|
|
1163
|
-
* hunyuan
|
|
1161
|
+
* 两个区的目录各有一条媒体模型,互不重叠(2026-10-25 实测):
|
|
1162
|
+
* - 国内区(61 条模型):`text-to-image` 只有 `hunyuan-image-alpha`,
|
|
1163
|
+
* `image-to-image` 只有 `hunyuan-image-alpha-edit`。走 hunyuan 分支,
|
|
1164
|
+
* 响应是 COS 签名 URL(24h 有效),单张约 5.71 credits。
|
|
1165
|
+
* - 国际区(29 条模型):`hy-image-3.5` 同时带 `text-to-image` 与
|
|
1166
|
+
* `image-to-image`。走「其它」分支(带 `response_format: 'b64_json'`),
|
|
1167
|
+
* 实测单张约 0.03 credits,返回的同样是 ap-singapore 的 COS 签名 URL。
|
|
1168
|
+
*
|
|
1169
|
+
* 两个数不是一个价目表的两个档位:目录条目只有 id/name/tags,**没有价格**,
|
|
1170
|
+
* 价格只在上游结算时以 `data.usage.credit` 返回,所以工具只能回报实扣、
|
|
1171
|
+
* 不能预先报价。
|
|
1164
1172
|
*
|
|
1165
1173
|
* @module dsh-connect-workbuddy/image-gen
|
|
1166
1174
|
*/
|
|
1167
1175
|
/** 产品配置里「文生图」模型的标签。 */
|
|
1168
1176
|
const IMAGE_TAG_TEXT_TO_IMAGE = "text-to-image";
|
|
1177
|
+
/** 产品配置里「图生图 / 改图」模型的标签。 */
|
|
1178
|
+
const IMAGE_TAG_IMAGE_TO_IMAGE = "image-to-image";
|
|
1169
1179
|
/** 官方 CLI 的默认尺寸。 */
|
|
1170
1180
|
const DEFAULT_IMAGE_SIZE = "1024x1024";
|
|
1171
1181
|
/** 生图路由。 */
|
|
1172
1182
|
const IMAGE_GENERATIONS_PATH = "/v2/images/generations";
|
|
1183
|
+
/** 改图路由:官方 CLI 的 `ImageService.editImage` 打的就是这条(2026-10-25 国际区实测 200)。 */
|
|
1184
|
+
const IMAGE_EDITS_PATH = "/v2/images/edits";
|
|
1185
|
+
/**
|
|
1186
|
+
* 本插件认作「媒体模型」的全部标签。
|
|
1187
|
+
*
|
|
1188
|
+
* 目录只读一次就返回全部媒体条目,由调用方按 tag 分组:生图工具只认两个 image
|
|
1189
|
+
* 标签,卡片清单则把视频条目一并列出来。这样 `fetchMediaModels` 不必为每种能力
|
|
1190
|
+
* 各读一遍 `/v3/config`。
|
|
1191
|
+
*/
|
|
1192
|
+
const MEDIA_TAGS = [
|
|
1193
|
+
IMAGE_TAG_TEXT_TO_IMAGE,
|
|
1194
|
+
IMAGE_TAG_IMAGE_TO_IMAGE,
|
|
1195
|
+
"text-to-video",
|
|
1196
|
+
"image-to-video"
|
|
1197
|
+
];
|
|
1173
1198
|
/** 生图链路的错误。带一个稳定的 `code`,避免调用方去匹配文案。 */
|
|
1174
1199
|
var WorkBuddyImageError = class extends Error {
|
|
1175
1200
|
code;
|
|
@@ -1194,10 +1219,14 @@ function stringList(value) {
|
|
|
1194
1219
|
/**
|
|
1195
1220
|
* 从产品配置的 `data.models` 里挑出带指定 tag 的媒体模型。
|
|
1196
1221
|
*
|
|
1222
|
+
* `tag` 可以是一组标签,命中任一即算——目录只读一次就返回全部媒体条目({@link MEDIA_TAGS}),
|
|
1223
|
+
* 调用方再按能力分组过滤,比每种能力各读一遍 `/v3/config` 少一次往返。
|
|
1224
|
+
*
|
|
1197
1225
|
* 去重按 `id`:上游目录里同一个 id 只应出现一次,但目录是外部数据,
|
|
1198
1226
|
* 重复条目不该让卡片或工具参数里出现两个同名选项。
|
|
1199
1227
|
*/
|
|
1200
1228
|
function selectMediaModels(rawModels, tag = IMAGE_TAG_TEXT_TO_IMAGE) {
|
|
1229
|
+
const wanted = typeof tag === "string" ? [tag] : tag;
|
|
1201
1230
|
if (!Array.isArray(rawModels)) return [];
|
|
1202
1231
|
const out = [];
|
|
1203
1232
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1207,7 +1236,7 @@ function selectMediaModels(rawModels, tag = IMAGE_TAG_TEXT_TO_IMAGE) {
|
|
|
1207
1236
|
const id = asString(record["id"]);
|
|
1208
1237
|
if (id === void 0 || seen.has(id)) continue;
|
|
1209
1238
|
const tags = stringList(record["tags"]);
|
|
1210
|
-
if (!tags.includes(
|
|
1239
|
+
if (!wanted.some((one) => tags.includes(one))) continue;
|
|
1211
1240
|
seen.add(id);
|
|
1212
1241
|
out.push({
|
|
1213
1242
|
id,
|
|
@@ -1217,24 +1246,31 @@ function selectMediaModels(rawModels, tag = IMAGE_TAG_TEXT_TO_IMAGE) {
|
|
|
1217
1246
|
}
|
|
1218
1247
|
return out;
|
|
1219
1248
|
}
|
|
1249
|
+
/** tag 的人话名字,只用在错误信息里。 */
|
|
1250
|
+
function tagLabel(tag) {
|
|
1251
|
+
if (tag === "image-to-image") return "图生图";
|
|
1252
|
+
if (tag === "text-to-image") return "文生图";
|
|
1253
|
+
return tag;
|
|
1254
|
+
}
|
|
1220
1255
|
/**
|
|
1221
|
-
*
|
|
1256
|
+
* 按能力标签选一个图像模型:先在该标签组内找调用方点名的那个,否则取组内第一个。
|
|
1222
1257
|
*
|
|
1223
|
-
*
|
|
1224
|
-
*
|
|
1225
|
-
*
|
|
1258
|
+
* 点名的模型必须在**这一组**里——写错名字或拿改图模型来文生图都直接报错,
|
|
1259
|
+
* 而不是把它发上去让上游回一个「route config not found」。这样报错信息能指出
|
|
1260
|
+
* 真正的问题(模型名写错,或该区这一组没有模型),那句话里还会列出本组可用项。
|
|
1226
1261
|
*/
|
|
1227
|
-
function
|
|
1262
|
+
function pickMediaModel(models, requested, tag = IMAGE_TAG_TEXT_TO_IMAGE) {
|
|
1263
|
+
const group = models.filter((model) => model.tags.includes(tag));
|
|
1228
1264
|
if (requested !== void 0 && requested !== "") {
|
|
1229
|
-
const found =
|
|
1265
|
+
const found = group.find((model) => model.id === requested);
|
|
1230
1266
|
if (found === void 0) {
|
|
1231
|
-
const known =
|
|
1232
|
-
throw new WorkBuddyImageError(`workbuddy image:
|
|
1267
|
+
const known = group.map((model) => model.id).join(", ");
|
|
1268
|
+
throw new WorkBuddyImageError(`workbuddy image: 目录里没有${tagLabel(tag)}模型「${requested}」。可用:${known === "" ? "(空)" : known}`, "NO_IMAGE_MODEL");
|
|
1233
1269
|
}
|
|
1234
1270
|
return found;
|
|
1235
1271
|
}
|
|
1236
|
-
const first =
|
|
1237
|
-
if (first === void 0) throw new WorkBuddyImageError(
|
|
1272
|
+
const first = group[0];
|
|
1273
|
+
if (first === void 0) throw new WorkBuddyImageError(`workbuddy image: 该区账号的产品配置里没有任何带 ${tag} 标签的模型(${tagLabel(tag)})。国内区文生图应是 hunyuan-image-alpha、改图是 hunyuan-image-alpha-edit;国际区 hy-image-3.5 同时带这两个标签;一个都没有说明该区目录暂时没有这类模型。`, "NO_IMAGE_MODEL");
|
|
1238
1274
|
return first;
|
|
1239
1275
|
}
|
|
1240
1276
|
/** 按官方 CLI 的 `buildBaseRequestBody` 分支规则拼请求体。 */
|
|
@@ -1255,6 +1291,83 @@ function buildImageBody(request) {
|
|
|
1255
1291
|
return body;
|
|
1256
1292
|
}
|
|
1257
1293
|
/**
|
|
1294
|
+
* 改图请求体:生图那一套字段 + `image`(data URL 数组)+ 可选 `input_fidelity`。
|
|
1295
|
+
*
|
|
1296
|
+
* 顺序照抄官方 CLI 的 `editImage`:先 `buildBaseRequestBody`,再补 `image`,
|
|
1297
|
+
* 再可选补 `input_fidelity`。`image` 上游只认字符串数组,单个字符串会被拒。
|
|
1298
|
+
*/
|
|
1299
|
+
function buildEditBody(request) {
|
|
1300
|
+
const body = buildImageBody(request);
|
|
1301
|
+
body["image"] = [...request.image];
|
|
1302
|
+
if (request.inputFidelity !== void 0 && request.inputFidelity !== "") body["input_fidelity"] = request.inputFidelity;
|
|
1303
|
+
return body;
|
|
1304
|
+
}
|
|
1305
|
+
/** 输入图的大小上限。上游没说,但一张改图输入不该比产物大一个量级,8 MB 足够。 */
|
|
1306
|
+
const MAX_INPUT_IMAGE_BYTES = 8388608;
|
|
1307
|
+
/** 按扩展名猜输入图的 MIME;不认识就返回 undefined(交给嗅探)。 */
|
|
1308
|
+
const IMAGE_MIME_BY_EXTENSION = {
|
|
1309
|
+
".png": "image/png",
|
|
1310
|
+
".jpg": "image/jpeg",
|
|
1311
|
+
".jpeg": "image/jpeg",
|
|
1312
|
+
".gif": "image/gif",
|
|
1313
|
+
".webp": "image/webp",
|
|
1314
|
+
".bmp": "image/bmp",
|
|
1315
|
+
".svg": "image/svg+xml",
|
|
1316
|
+
".ico": "image/x-icon",
|
|
1317
|
+
".tif": "image/tiff",
|
|
1318
|
+
".tiff": "image/tiff"
|
|
1319
|
+
};
|
|
1320
|
+
function imageMimeForPath(path) {
|
|
1321
|
+
const lower = path.toLowerCase();
|
|
1322
|
+
const dot = lower.lastIndexOf(".");
|
|
1323
|
+
if (dot < 0) return void 0;
|
|
1324
|
+
return IMAGE_MIME_BY_EXTENSION[lower.slice(dot)];
|
|
1325
|
+
}
|
|
1326
|
+
/**
|
|
1327
|
+
* 按魔数嗅探图片 MIME,照抄官方 CLI 的 `detectMimeTypeFromBase64`。
|
|
1328
|
+
*
|
|
1329
|
+
* 认不出来时兜底 `image/png`(CLI 也是这么兜的):宁可让上游按 png 试一次,
|
|
1330
|
+
* 也不要因为一个我们没见过的头就拒掉用户给的图。
|
|
1331
|
+
*/
|
|
1332
|
+
function sniffImageMime(bytes) {
|
|
1333
|
+
const at = (index) => bytes[index] ?? -1;
|
|
1334
|
+
if (at(0) === 137 && at(1) === 80 && at(2) === 78 && at(3) === 71) return "image/png";
|
|
1335
|
+
if (at(0) === 255 && at(1) === 216 && at(2) === 255) return "image/jpeg";
|
|
1336
|
+
if (at(0) === 71 && at(1) === 73 && at(2) === 70 && at(3) === 56) return "image/gif";
|
|
1337
|
+
if (at(0) === 82 && at(1) === 73 && at(2) === 70 && at(3) === 70 && at(8) === 87 && at(9) === 69 && at(10) === 66 && at(11) === 80) return "image/webp";
|
|
1338
|
+
if (at(0) === 66 && at(1) === 77) return "image/bmp";
|
|
1339
|
+
return "image/png";
|
|
1340
|
+
}
|
|
1341
|
+
/** 拼出上游唯一接受的输入形态:`data:<mime>;base64,<base64>`。 */
|
|
1342
|
+
function imageDataUrl(mime, base64) {
|
|
1343
|
+
return `data:${mime};base64,${base64}`;
|
|
1344
|
+
}
|
|
1345
|
+
/** 解析一个 data URL 形式的输入图;不是 `data:image/*;base64,` 就返回 undefined。 */
|
|
1346
|
+
function parseImageDataUrl(value) {
|
|
1347
|
+
const match = /^data:([^;,]+);base64,(.+)$/s.exec(value.trim());
|
|
1348
|
+
if (match === null) return void 0;
|
|
1349
|
+
const mime = match[1] ?? "";
|
|
1350
|
+
const base64 = match[2] ?? "";
|
|
1351
|
+
if (!mime.startsWith("image/") || base64 === "") return void 0;
|
|
1352
|
+
return {
|
|
1353
|
+
mime,
|
|
1354
|
+
base64
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
const BARE_BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
1358
|
+
/**
|
|
1359
|
+
* 看起来像「裸 base64」而不是路径吗?
|
|
1360
|
+
*
|
|
1361
|
+
* 判据照抄 CLI 的 `processImageInput`:不含路径分隔符、足够长、字符集是 base64。
|
|
1362
|
+
* 长度门槛是必要的——`a.png` 这种文件名同样不含分隔符,短到不足以是图片数据。
|
|
1363
|
+
*/
|
|
1364
|
+
function isBareBase64Image(value) {
|
|
1365
|
+
const text = value.trim();
|
|
1366
|
+
if (text.length < 100) return false;
|
|
1367
|
+
if (text.includes("/") || text.includes("\\")) return false;
|
|
1368
|
+
return BARE_BASE64.test(text);
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1258
1371
|
* 解析生图响应。
|
|
1259
1372
|
*
|
|
1260
1373
|
* 信封是 `{code, msg, request_id, data}`;`code !== 0` 是业务失败(与 HTTP 状态
|
|
@@ -1308,7 +1421,7 @@ function describeImageFailure(status, bodyText) {
|
|
|
1308
1421
|
} catch {}
|
|
1309
1422
|
if (status === 401 || status === 403) return new WorkBuddyImageError(`workbuddy image: 凭据被上游拒绝(HTTP ${status}),请在插件设置里重新登录 WorkBuddy。${detail === "" ? "" : ` ${detail}`}`, "AUTH");
|
|
1310
1423
|
if (status === 429) return new WorkBuddyImageError(`workbuddy image: 触发上游限流(HTTP 429),稍后再试。${detail === "" ? "" : ` ${detail}`}`, "RATE_LIMIT");
|
|
1311
|
-
if (status === 404) return new WorkBuddyImageError(`workbuddy image: 上游没有这条生图路由(HTTP 404
|
|
1424
|
+
if (status === 404) return new WorkBuddyImageError(`workbuddy image: 上游没有这条生图路由(HTTP 404)——该区网关没有开放生图接口。${detail === "" ? "" : ` ${detail}`}`, "NO_ROUTE");
|
|
1312
1425
|
return new WorkBuddyImageError(`workbuddy image: 上游失败(HTTP ${status})${detail === "" ? "" : `: ${detail}`}`, "UPSTREAM");
|
|
1313
1426
|
}
|
|
1314
1427
|
//#endregion
|
|
@@ -4368,12 +4481,22 @@ var WorkBuddyUpstreamClient = class {
|
|
|
4368
4481
|
return levels;
|
|
4369
4482
|
}
|
|
4370
4483
|
/**
|
|
4371
|
-
*
|
|
4484
|
+
* 读该账号所属区的产品配置,返回**全部**媒体模型(图 + 视频,按 tag 区分)。
|
|
4372
4485
|
*
|
|
4373
4486
|
* 走的是和 {@link fetchModels} 同一条 `/v3/config`(国内区与国际区都答),
|
|
4374
4487
|
* 区别只在这里保留 `data.models` 的媒体条目、而不是投影成 CLI 聊天目录。
|
|
4375
|
-
*
|
|
4376
|
-
*
|
|
4488
|
+
* 两区实测(2026-10-25,同日各跑一次只读探针):
|
|
4489
|
+
* - 国内区 61 条模型 / 17 条带 tag:`hunyuan-image-alpha`(`text-to-image`)、
|
|
4490
|
+
* `hunyuan-image-alpha-edit`(`image-to-image`)、`kling-video-v3` 与
|
|
4491
|
+
* `minimax-video-h3`(`text-to-video` + `image-to-video`)。
|
|
4492
|
+
* - 国际区 29 条 / 7 条带 tag:`hy-image-3.5`(`text-to-image` +
|
|
4493
|
+
* `image-to-image`)、`kling-video-v3`(两种视频 tag)。
|
|
4494
|
+
* 两边目录完全不重叠,所以「国际区一条都没有」是 2026-10-21 的旧观测,
|
|
4495
|
+
* 已经过期 —— 目录真的没标时才返回空数组(而不是编一个模型出来)。
|
|
4496
|
+
*
|
|
4497
|
+
* 返回的是**未分组**的全集:谁要 `text-to-image` 就自己按 tag 过滤
|
|
4498
|
+
* ({@link selectMediaModels} / `pickMediaModel`)。生图工具、改图路径、卡片清单
|
|
4499
|
+
* 因此共用这一次读取,而不是各读一遍目录。
|
|
4377
4500
|
*
|
|
4378
4501
|
* 这是一次 EXTRA 读取,不是「复用目录那一次」:`fetchModels` 的结果被投影成
|
|
4379
4502
|
* 聊天目录就丢掉了媒体标签,所以这里必须再读一遍同一份文档。它是只读 GET、
|
|
@@ -4395,7 +4518,7 @@ var WorkBuddyUpstreamClient = class {
|
|
|
4395
4518
|
});
|
|
4396
4519
|
const envelope = await readEnvelope(response);
|
|
4397
4520
|
if (!response.ok || envelope.code !== 0) throw envelopeError(response.status, envelope);
|
|
4398
|
-
return selectMediaModels((typeof envelope.data === "object" && envelope.data !== null ? envelope.data : {})["models"],
|
|
4521
|
+
return selectMediaModels((typeof envelope.data === "object" && envelope.data !== null ? envelope.data : {})["models"], MEDIA_TAGS);
|
|
4399
4522
|
};
|
|
4400
4523
|
try {
|
|
4401
4524
|
return await readMedia(GLOBAL_CONFIG_PATH);
|
|
@@ -4409,7 +4532,9 @@ var WorkBuddyUpstreamClient = class {
|
|
|
4409
4532
|
* 发一次文生图请求。
|
|
4410
4533
|
*
|
|
4411
4534
|
* 端点、请求体、响应解析全部照抄官方 CLI 的 ImageService(见 `image-gen.ts`
|
|
4412
|
-
*
|
|
4535
|
+
* 的模块注释)。产物是 24 小时有效的 COS 签名 URL;实扣积分随区与模型不同
|
|
4536
|
+
* (国内区 `hunyuan-image-alpha` 5.71、国际区 `hy-image-3.5` 0.03),
|
|
4537
|
+
* 只在响应的 `data.usage.credit` 里给出,调用方按实际值回报。
|
|
4413
4538
|
*
|
|
4414
4539
|
* 失败分两层:HTTP 非 2xx 交给 {@link describeImageFailure} 翻成带 code 的
|
|
4415
4540
|
* 错误(401/403 提示重新登录、404 提示该区没有生图路由、429 提示限流);
|
|
@@ -4432,6 +4557,35 @@ var WorkBuddyUpstreamClient = class {
|
|
|
4432
4557
|
}
|
|
4433
4558
|
return parseImageResponse(payload);
|
|
4434
4559
|
}
|
|
4560
|
+
/**
|
|
4561
|
+
* 发一次改图请求(`image-to-image`)。
|
|
4562
|
+
*
|
|
4563
|
+
* 端点换成官方 CLI `ImageService.editImage` 用的 `/v2/images/edits`,请求体是
|
|
4564
|
+
* 生图那一套 + `image`(**必须是 data URL 字符串数组**)+ 可选 `input_fidelity`。
|
|
4565
|
+
* 2026-10-25 国际区实测:`hy-image-3.5` + 一张 712×962 的截图 → 200、code 0、
|
|
4566
|
+
* 一张 COS 签名 URL、`credit 0.03`。
|
|
4567
|
+
*
|
|
4568
|
+
* `image` 的形态由调用方(工具层)负责规整成 data URL——这一层只发请求、
|
|
4569
|
+
* 不碰文件系统,和 {@link generateImage} 的分工保持一致。
|
|
4570
|
+
*/
|
|
4571
|
+
async editImage(credential, request, signal) {
|
|
4572
|
+
if (request.image.length === 0) throw new WorkBuddyImageError("workbuddy image: 改图请求缺少输入图(image 数组为空)。", "INVALID_ARGS");
|
|
4573
|
+
const response = await fetch(`${chatBase(credential)}${IMAGE_EDITS_PATH}`, {
|
|
4574
|
+
method: "POST",
|
|
4575
|
+
headers: imageHeaders(credential),
|
|
4576
|
+
body: JSON.stringify(buildEditBody(request)),
|
|
4577
|
+
signal: signal ?? AbortSignal.timeout(IMAGE_TIMEOUT_MS)
|
|
4578
|
+
});
|
|
4579
|
+
const text = await response.text();
|
|
4580
|
+
if (!response.ok) throw describeImageFailure(response.status, text);
|
|
4581
|
+
let payload;
|
|
4582
|
+
try {
|
|
4583
|
+
payload = JSON.parse(text);
|
|
4584
|
+
} catch {
|
|
4585
|
+
throw new WorkBuddyImageError(`workbuddy image: 上游返回的不是 JSON(HTTP ${response.status}): ${text.slice(0, 200)}`, "UPSTREAM");
|
|
4586
|
+
}
|
|
4587
|
+
return parseImageResponse(payload);
|
|
4588
|
+
}
|
|
4435
4589
|
/** Query today's check-in status without changing account state. */
|
|
4436
4590
|
async fetchCheckinStatus(credential) {
|
|
4437
4591
|
const response = await fetch(`${billingBase(credential)}/v2/billing/meter/checkin-activity-status`, {
|
|
@@ -6983,7 +7137,7 @@ function describeRosterSeenPayload(raw) {
|
|
|
6983
7137
|
//#endregion
|
|
6984
7138
|
//#region src/version.ts
|
|
6985
7139
|
/** The npm package version this build was produced from. */
|
|
6986
|
-
const WORKBUDDY_CONNECT_VERSION = "5.
|
|
7140
|
+
const WORKBUDDY_CONNECT_VERSION = "5.10.0";
|
|
6987
7141
|
//#endregion
|
|
6988
7142
|
//#region src/host-heartbeat.ts
|
|
6989
7143
|
/**
|
|
@@ -7141,4 +7295,4 @@ async function clearHostHeartbeat() {
|
|
|
7141
7295
|
await rm(workbuddyHostHeartbeatPath(), { force: true });
|
|
7142
7296
|
}
|
|
7143
7297
|
//#endregion
|
|
7144
|
-
export { parseCreditMultiplier as $, isEncryptedCredentialError as A,
|
|
7298
|
+
export { parseCreditMultiplier as $, isEncryptedCredentialError as A, nativeModalityOf as At, WorkBuddyCredentialRejectedError as B, macosBundleExecutable as Bt, WorkBuddyCredentialStore as C, parseImageDataUrl as Ct, defaultDesktopAuthDirs as D, queueNoticeText as Dt, defaultDesktopAuthCandidates as E, parseQueueAnswer as Et, workbuddyAccountId as F, fetchAtRestKeyPayload as Ft, forceNeutralHead as G, hostPeersInfo as Gt, channelGateMemberOf as H, openEncryptedField as Ht, workbuddyOwnAuthPath as I, findWorkbuddyAppExecutable as It, isCredentialRejectedError as J, writeFileAtomic as Jt, isContextTooLongBody as K, resolveDshHome as Kt, CONTEXT_OVERFLOW_MARKER as L, findWorkbuddyAppExecutableWithSource as Lt, legacyWorkbuddyOwnAuthPath as M, clearAtRestKeyCache as Mt, parseWorkBuddyAuth as N, deriveAtRestKey as Nt, defaultDesktopAuthPath as O, NATIVE_MODALITY_BY_MODEL_ID as Ot, preferredAccountName as P, deriveAtRestKeyId as Pt, openingEvidenceOfBody as Q, CREDENTIAL_REJECTED_CODE as R, isEncryptedFieldWrapper as Rt, WORKBUDDY_AUTH_FILE_ENV as S, isBareBase64Image as St, authFileName as T, sniffImageMime as Tt, classifyUpstreamError as U, readAtRestKey as Ut, WorkBuddyUpstreamClient as V, macosNestedAppBundles as Vt, declaredTools as W, workbuddyAppExecutableCandidates as Wt, knownRegionOf as X, isFirstMessageGateBody as Y, modelIdOfBody as Z, deriveCatalog as _, IMAGE_TAG_TEXT_TO_IMAGE as _t, readHostHeartbeat as a, requestEvidenceOf as at, ENCRYPTED_CREDENTIAL_CODE as b, imageDataUrl as bt, WORKBUDDY_CONNECT_VERSION as c, REFUSES_OFF_MODEL_IDS as ct, rosterSeenPath as d, offDefaultFor as dt, parseReasoning as et, piAiRuntimeInfo as f, offRefused as ft, applyContextBudgets as g, IMAGE_TAG_IMAGE_TO_IMAGE as gt, WorkBuddyCatalog as h, DEFAULT_IMAGE_SIZE as ht, processStartTimeMs as i, regionOf as it, isVaultAccountId as j, WORKBUDDY_APP_EXECUTABLE_ENV as jt, hasEncryptedCredentialFields as k, imageDefaultFor as kt, createFileRosterSeenStore as l, defaultOffModelIds as lt, FALLBACK_WORKBUDDY_MODELS_GLOBAL as m, withEffectiveOff as mt, clearHostHeartbeat as n, perturbChannelFingerprints as nt, workbuddyHostHeartbeatPath as o, rewriteSessionTitleModel as ot, FALLBACK_WORKBUDDY_MODELS as p, recordRefusal as pt, isConversationIdGateBody as q, withFileLock as qt, isHeartbeatProcessAlive as r, prepareChatBody as rt, writeHostHeartbeat as s, attachBusyLevels as st, WORKBUDDY_HOST_HEARTBEAT_FILENAME as t, parseUpstreamModel as tt, describeRosterSeenPayload as u, lastRefusalFor as ut, fallbackModelsFor as v, MAX_INPUT_IMAGE_BYTES as vt, WorkBuddyEncryptedCredentialError as w, pickMediaModel as wt, WORKBUDDY_AUTH_FILENAME as x, imageMimeForPath as xt, withoutRouters as y, WorkBuddyImageError as yt, WORKBUDDY_FALLBACK_SYSTEM_PROMPT as z, isWorkbuddyBundle as zt };
|
package/lib/index.d.ts
CHANGED
|
@@ -1564,12 +1564,22 @@ declare class WorkBuddyUpstreamClient {
|
|
|
1564
1564
|
*/
|
|
1565
1565
|
fetchModelBusy(credential: WorkBuddyCredential, modelIds: readonly string[], signal?: AbortSignal): Promise<Map<string, WorkBuddyBusyLevel>>;
|
|
1566
1566
|
/**
|
|
1567
|
-
*
|
|
1567
|
+
* 读该账号所属区的产品配置,返回**全部**媒体模型(图 + 视频,按 tag 区分)。
|
|
1568
1568
|
*
|
|
1569
1569
|
* 走的是和 {@link fetchModels} 同一条 `/v3/config`(国内区与国际区都答),
|
|
1570
1570
|
* 区别只在这里保留 `data.models` 的媒体条目、而不是投影成 CLI 聊天目录。
|
|
1571
|
-
*
|
|
1572
|
-
*
|
|
1571
|
+
* 两区实测(2026-10-25,同日各跑一次只读探针):
|
|
1572
|
+
* - 国内区 61 条模型 / 17 条带 tag:`hunyuan-image-alpha`(`text-to-image`)、
|
|
1573
|
+
* `hunyuan-image-alpha-edit`(`image-to-image`)、`kling-video-v3` 与
|
|
1574
|
+
* `minimax-video-h3`(`text-to-video` + `image-to-video`)。
|
|
1575
|
+
* - 国际区 29 条 / 7 条带 tag:`hy-image-3.5`(`text-to-image` +
|
|
1576
|
+
* `image-to-image`)、`kling-video-v3`(两种视频 tag)。
|
|
1577
|
+
* 两边目录完全不重叠,所以「国际区一条都没有」是 2026-10-21 的旧观测,
|
|
1578
|
+
* 已经过期 —— 目录真的没标时才返回空数组(而不是编一个模型出来)。
|
|
1579
|
+
*
|
|
1580
|
+
* 返回的是**未分组**的全集:谁要 `text-to-image` 就自己按 tag 过滤
|
|
1581
|
+
* ({@link selectMediaModels} / `pickMediaModel`)。生图工具、改图路径、卡片清单
|
|
1582
|
+
* 因此共用这一次读取,而不是各读一遍目录。
|
|
1573
1583
|
*
|
|
1574
1584
|
* 这是一次 EXTRA 读取,不是「复用目录那一次」:`fetchModels` 的结果被投影成
|
|
1575
1585
|
* 聊天目录就丢掉了媒体标签,所以这里必须再读一遍同一份文档。它是只读 GET、
|
|
@@ -1582,7 +1592,9 @@ declare class WorkBuddyUpstreamClient {
|
|
|
1582
1592
|
* 发一次文生图请求。
|
|
1583
1593
|
*
|
|
1584
1594
|
* 端点、请求体、响应解析全部照抄官方 CLI 的 ImageService(见 `image-gen.ts`
|
|
1585
|
-
*
|
|
1595
|
+
* 的模块注释)。产物是 24 小时有效的 COS 签名 URL;实扣积分随区与模型不同
|
|
1596
|
+
* (国内区 `hunyuan-image-alpha` 5.71、国际区 `hy-image-3.5` 0.03),
|
|
1597
|
+
* 只在响应的 `data.usage.credit` 里给出,调用方按实际值回报。
|
|
1586
1598
|
*
|
|
1587
1599
|
* 失败分两层:HTTP 非 2xx 交给 {@link describeImageFailure} 翻成带 code 的
|
|
1588
1600
|
* 错误(401/403 提示重新登录、404 提示该区没有生图路由、429 提示限流);
|
|
@@ -1593,6 +1605,24 @@ declare class WorkBuddyUpstreamClient {
|
|
|
1593
1605
|
readonly prompt: string;
|
|
1594
1606
|
readonly size?: string;
|
|
1595
1607
|
}, signal?: AbortSignal): Promise<WorkBuddyImageOutcome>;
|
|
1608
|
+
/**
|
|
1609
|
+
* 发一次改图请求(`image-to-image`)。
|
|
1610
|
+
*
|
|
1611
|
+
* 端点换成官方 CLI `ImageService.editImage` 用的 `/v2/images/edits`,请求体是
|
|
1612
|
+
* 生图那一套 + `image`(**必须是 data URL 字符串数组**)+ 可选 `input_fidelity`。
|
|
1613
|
+
* 2026-10-25 国际区实测:`hy-image-3.5` + 一张 712×962 的截图 → 200、code 0、
|
|
1614
|
+
* 一张 COS 签名 URL、`credit 0.03`。
|
|
1615
|
+
*
|
|
1616
|
+
* `image` 的形态由调用方(工具层)负责规整成 data URL——这一层只发请求、
|
|
1617
|
+
* 不碰文件系统,和 {@link generateImage} 的分工保持一致。
|
|
1618
|
+
*/
|
|
1619
|
+
editImage(credential: WorkBuddyCredential, request: {
|
|
1620
|
+
readonly model: string;
|
|
1621
|
+
readonly prompt: string;
|
|
1622
|
+
readonly size?: string;
|
|
1623
|
+
readonly image: readonly string[];
|
|
1624
|
+
readonly inputFidelity?: string;
|
|
1625
|
+
}, signal?: AbortSignal): Promise<WorkBuddyImageOutcome>;
|
|
1596
1626
|
/** Query today's check-in status without changing account state. */
|
|
1597
1627
|
fetchCheckinStatus(credential: WorkBuddyCredential): Promise<WorkBuddyCheckinStatus>;
|
|
1598
1628
|
/**
|
|
@@ -4143,6 +4173,19 @@ interface WorkBuddyStatusRouteOptions {
|
|
|
4143
4173
|
* renders no segment at all rather than a made-up "0 新模型".
|
|
4144
4174
|
*/
|
|
4145
4175
|
rosterSeen?(region: WorkBuddyRegion): Promise<RosterSeenReadout>;
|
|
4176
|
+
/**
|
|
4177
|
+
* Read the region's MEDIA models (image + video) for the card's read-only
|
|
4178
|
+
* roster block.
|
|
4179
|
+
*
|
|
4180
|
+
* Optional: a Host that mounts these routes without the upstream client
|
|
4181
|
+
* simply answers 503, and the card hides the block. Returns the same rows the
|
|
4182
|
+
* image tool consumes, so the card's list and the tool's model validation
|
|
4183
|
+
* cannot disagree about what exists in a region.
|
|
4184
|
+
*/
|
|
4185
|
+
mediaModels?(region: WorkBuddyRegion, options?: {
|
|
4186
|
+
readonly signal?: AbortSignal;
|
|
4187
|
+
readonly refresh?: boolean;
|
|
4188
|
+
}): Promise<readonly WorkBuddyMediaModel[]>;
|
|
4146
4189
|
/**
|
|
4147
4190
|
* Whether the requested region's provider is currently offered to DSH. The
|
|
4148
4191
|
* card renders this as the tab's on/off checkbox, so the switch reflects the
|
|
@@ -4922,6 +4965,23 @@ declare function regionStateOf(config: Config, region: WorkBuddyRegion): WorkBud
|
|
|
4922
4965
|
* about a region's state.
|
|
4923
4966
|
*/
|
|
4924
4967
|
declare function regionEnabled(config: Config, region: WorkBuddyRegion): boolean;
|
|
4968
|
+
/**
|
|
4969
|
+
* The region that owns the image tool right now, or `undefined` when no region
|
|
4970
|
+
* has it switched on.
|
|
4971
|
+
*
|
|
4972
|
+
* BOTH gates are required, and both are read live: the region's provider switch
|
|
4973
|
+
* must be ON (`regionEnabled`, opt-OUT) and the user must have opted IN to the
|
|
4974
|
+
* model spending credits there (`imageToolEnabled`, opt-IN). Absence of
|
|
4975
|
+
* `imageToolEnabled` is never consent.
|
|
4976
|
+
*
|
|
4977
|
+
* CN wins when both regions qualify, and that order is the only backward
|
|
4978
|
+
* compatible one: before the international gateway carried a `text-to-image`
|
|
4979
|
+
* model (measured 2026-10-25: `hy-image-3.5`) CN was the only region that could
|
|
4980
|
+
* ever be opted in, so a profile that opted in there keeps using CN even after
|
|
4981
|
+
* the global tab is switched on as well. That is exactly `REGION_KEYS`' order;
|
|
4982
|
+
* it is not incidental.
|
|
4983
|
+
*/
|
|
4984
|
+
declare function imageToolRegionOf(config: Config): WorkBuddyRegion | undefined;
|
|
4925
4985
|
/**
|
|
4926
4986
|
* The account id a region should select, or `undefined` for the documented
|
|
4927
4987
|
* default: follow whatever the WorkBuddy app is currently signed in as.
|
|
@@ -4972,4 +5032,4 @@ declare function legacyAttributionRegion(value: Config, accountsFor: (region: Wo
|
|
|
4972
5032
|
*/
|
|
4973
5033
|
declare function apply(ctx: Context, config: Config): void;
|
|
4974
5034
|
//#endregion
|
|
4975
|
-
export { CREDENTIAL_REJECTED_CODE, Config, DEFAULT_PROBE_INPUT_TOKENS, ENCRYPTED_CREDENTIAL_CODE, FALLBACK_WORKBUDDY_MODELS, FALLBACK_WORKBUDDY_MODELS_GLOBAL, NATIVE_MODALITY_BY_MODEL_ID, PROBE_INPUT_TOKEN_CHOICES, PROBE_MAX_TOKENS, PROBE_SYSTEM_PROMPT, REFUSES_OFF_MODEL_IDS, type UpstreamErrorKind, WORKBUDDY_ACCOUNTS_REFRESH_PATH, WORKBUDDY_APP_EXECUTABLE_ENV, WORKBUDDY_AUTH_FILENAME, WORKBUDDY_AUTH_FILE_ENV, WORKBUDDY_CHECKIN_PATH, WORKBUDDY_CONNECT_VERSION, WORKBUDDY_GLOBAL_PROVIDER, WORKBUDDY_HOST_HEARTBEAT_FILENAME, WORKBUDDY_MODELS_REFRESH_PATH, WORKBUDDY_PROBE_PATH, WORKBUDDY_PROVIDER, WORKBUDDY_PROVIDERS, WORKBUDDY_PROVIDER_DISPLAY_NAMES, WORKBUDDY_REGIONS, WORKBUDDY_REGION_PARAM, WORKBUDDY_SETTINGS_NS, WORKBUDDY_STREAM_IDLE_TIMEOUT_MS, WORKBUDDY_TPS_PATH, WORKBUDDY_USAGE_PATH, type WorkBuddyAccountChoice, type WorkBuddyAdapter, type WorkBuddyAuthStatus, type WorkBuddyCandidateFailure, WorkBuddyCatalog, type WorkBuddyChatResult, type WorkBuddyCredential, type WorkBuddyCredentialRecovery, WorkBuddyCredentialRejectedError, WorkBuddyCredentialStore, type WorkBuddyCreditPackage, type WorkBuddyCredits, WorkBuddyEncryptedCredentialError, type WorkBuddyEncryptedField, type WorkBuddyHostHeartbeat, type WorkBuddyModelInfo, type WorkBuddyNativeModality, WorkBuddyPoolPreferences, type WorkBuddyProbeClient, type WorkBuddyProbeOutcome, type WorkBuddyProbeResult, type WorkBuddyProbeStore, type WorkBuddyReasoning, type WorkBuddyRecoveryCandidate, type WorkBuddyRefreshOutcome, WorkBuddyRegionState, type WorkBuddyShim, type WorkBuddyStatusRouteOptions, type WorkBuddyStoreOptions, WorkBuddyUpstreamClient, type WorkBuddyUpstreamModel, type WorkBuddyUsabilityProbeOptions, apply, asVolatile, authFileName, classifyUpstreamError, clearAtRestKeyCache, clearHostHeartbeat, cooldownOf, createAccountUsabilityProbe, createWorkBuddyAdapter, createWorkBuddyShim, creditOfStream, defaultDesktopAuthCandidates, defaultDesktopAuthDirs, defaultDesktopAuthPath, defaultOffModelIds, deriveAtRestKey, deriveAtRestKeyId, deriveCatalog, fallbackModelsFor, fetchAtRestKeyPayload, findWorkbuddyAppExecutable, hasEncryptedCredentialFields, imageDefaultFor, inject, isCredentialRejectedError, isEncryptedCredentialError, isEncryptedFieldWrapper, isHeartbeatProcessAlive, isWorkbuddyBundle, knownRegionOf, legacyAttributionRegion, legacyWorkbuddyOwnAuthPath, macosBundleExecutable, macosNestedAppBundles, modelIdOfBody, name, nativeModalityOf, nextRegionEnabled, nextRegionSlots, offDefaultFor, openEncryptedField, outcomeOfFailure, parseCreditMultiplier, parseReasoning, parseRetryAfter, parseUpstreamModel, parseWorkBuddyAuth, prepareChatBody, probeModel, probeRequestBody, probeSucceeded, processStartTimeMs, readAtRestKey, readHostHeartbeat, regionCleared, regionEnabled, regionEnabledOf, regionOf, regionOfProvider, regionOfStatusUrl, regionStateOf, regionsFieldIsCorrupt, regionsMapOf, registerWorkBuddyStatusRoute, resolveCredentialRecovery, selectAccountFor, settingsNamespaceOf, toPersistedWorkBuddyModel, unwrapVolatileDeep, withEffectiveOff, withWorkBuddyRegion, workBuddyDisplayName, workBuddyModelInput, workBuddyThinkingLevelMap, workBuddyWebStatus, workbuddyAccountId, workbuddyAppExecutableCandidates, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, writeHostHeartbeat };
|
|
5035
|
+
export { CREDENTIAL_REJECTED_CODE, Config, DEFAULT_PROBE_INPUT_TOKENS, ENCRYPTED_CREDENTIAL_CODE, FALLBACK_WORKBUDDY_MODELS, FALLBACK_WORKBUDDY_MODELS_GLOBAL, NATIVE_MODALITY_BY_MODEL_ID, PROBE_INPUT_TOKEN_CHOICES, PROBE_MAX_TOKENS, PROBE_SYSTEM_PROMPT, REFUSES_OFF_MODEL_IDS, type UpstreamErrorKind, WORKBUDDY_ACCOUNTS_REFRESH_PATH, WORKBUDDY_APP_EXECUTABLE_ENV, WORKBUDDY_AUTH_FILENAME, WORKBUDDY_AUTH_FILE_ENV, WORKBUDDY_CHECKIN_PATH, WORKBUDDY_CONNECT_VERSION, WORKBUDDY_GLOBAL_PROVIDER, WORKBUDDY_HOST_HEARTBEAT_FILENAME, WORKBUDDY_MODELS_REFRESH_PATH, WORKBUDDY_PROBE_PATH, WORKBUDDY_PROVIDER, WORKBUDDY_PROVIDERS, WORKBUDDY_PROVIDER_DISPLAY_NAMES, WORKBUDDY_REGIONS, WORKBUDDY_REGION_PARAM, WORKBUDDY_SETTINGS_NS, WORKBUDDY_STREAM_IDLE_TIMEOUT_MS, WORKBUDDY_TPS_PATH, WORKBUDDY_USAGE_PATH, type WorkBuddyAccountChoice, type WorkBuddyAdapter, type WorkBuddyAuthStatus, type WorkBuddyCandidateFailure, WorkBuddyCatalog, type WorkBuddyChatResult, type WorkBuddyCredential, type WorkBuddyCredentialRecovery, WorkBuddyCredentialRejectedError, WorkBuddyCredentialStore, type WorkBuddyCreditPackage, type WorkBuddyCredits, WorkBuddyEncryptedCredentialError, type WorkBuddyEncryptedField, type WorkBuddyHostHeartbeat, type WorkBuddyModelInfo, type WorkBuddyNativeModality, WorkBuddyPoolPreferences, type WorkBuddyProbeClient, type WorkBuddyProbeOutcome, type WorkBuddyProbeResult, type WorkBuddyProbeStore, type WorkBuddyReasoning, type WorkBuddyRecoveryCandidate, type WorkBuddyRefreshOutcome, WorkBuddyRegionState, type WorkBuddyShim, type WorkBuddyStatusRouteOptions, type WorkBuddyStoreOptions, WorkBuddyUpstreamClient, type WorkBuddyUpstreamModel, type WorkBuddyUsabilityProbeOptions, apply, asVolatile, authFileName, classifyUpstreamError, clearAtRestKeyCache, clearHostHeartbeat, cooldownOf, createAccountUsabilityProbe, createWorkBuddyAdapter, createWorkBuddyShim, creditOfStream, defaultDesktopAuthCandidates, defaultDesktopAuthDirs, defaultDesktopAuthPath, defaultOffModelIds, deriveAtRestKey, deriveAtRestKeyId, deriveCatalog, fallbackModelsFor, fetchAtRestKeyPayload, findWorkbuddyAppExecutable, hasEncryptedCredentialFields, imageDefaultFor, imageToolRegionOf, inject, isCredentialRejectedError, isEncryptedCredentialError, isEncryptedFieldWrapper, isHeartbeatProcessAlive, isWorkbuddyBundle, knownRegionOf, legacyAttributionRegion, legacyWorkbuddyOwnAuthPath, macosBundleExecutable, macosNestedAppBundles, modelIdOfBody, name, nativeModalityOf, nextRegionEnabled, nextRegionSlots, offDefaultFor, openEncryptedField, outcomeOfFailure, parseCreditMultiplier, parseReasoning, parseRetryAfter, parseUpstreamModel, parseWorkBuddyAuth, prepareChatBody, probeModel, probeRequestBody, probeSucceeded, processStartTimeMs, readAtRestKey, readHostHeartbeat, regionCleared, regionEnabled, regionEnabledOf, regionOf, regionOfProvider, regionOfStatusUrl, regionStateOf, regionsFieldIsCorrupt, regionsMapOf, registerWorkBuddyStatusRoute, resolveCredentialRecovery, selectAccountFor, settingsNamespaceOf, toPersistedWorkBuddyModel, unwrapVolatileDeep, withEffectiveOff, withWorkBuddyRegion, workBuddyDisplayName, workBuddyModelInput, workBuddyThinkingLevelMap, workBuddyWebStatus, workbuddyAccountId, workbuddyAppExecutableCandidates, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, writeHostHeartbeat };
|