@bty/customer-service-cli 0.6.5 → 0.6.7

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/dist/bin.js CHANGED
@@ -318,7 +318,7 @@ function toExitCode(err) {
318
318
  return 1;
319
319
  }
320
320
  function createRequest(globalTimeout) {
321
- return async function request(baseUrl, path6, options) {
321
+ return async function request(baseUrl, path7, options) {
322
322
  const headers = {
323
323
  "Content-Type": "application/json",
324
324
  ...options.headers
@@ -346,7 +346,7 @@ function createRequest(globalTimeout) {
346
346
  if (workspaceId) {
347
347
  headers["workspace-id"] = workspaceId;
348
348
  }
349
- let url = `${baseUrl}${path6}`;
349
+ let url = `${baseUrl}${path7}`;
350
350
  if (options.query) {
351
351
  const params = new URLSearchParams();
352
352
  for (const [key, value] of Object.entries(options.query)) {
@@ -485,6 +485,9 @@ function getCustomerServiceUrl() {
485
485
  const config = readConfig();
486
486
  return config?.customerServiceApiUrl ?? DEFAULT_CS_API_URL;
487
487
  }
488
+ function getObservabilityUrl() {
489
+ return `${getCustomerServiceUrl().replace(/\/+$/, "")}/observability`;
490
+ }
488
491
  function getAiApiUrl() {
489
492
  const envUrl = process.env.CS_AI_API_URL;
490
493
  if (envUrl) return envUrl;
@@ -1401,22 +1404,22 @@ function registerConversationCommand(program2) {
1401
1404
  var DASHBOARD_PREFIX = "/v1/dashboard";
1402
1405
  async function getDashboardSummary(opts) {
1403
1406
  const request = createRequest();
1404
- const path6 = opts.configId ? `${DASHBOARD_PREFIX}/${opts.configId}/summary` : `${DASHBOARD_PREFIX}/summary`;
1407
+ const path7 = opts.configId ? `${DASHBOARD_PREFIX}/${opts.configId}/summary` : `${DASHBOARD_PREFIX}/summary`;
1405
1408
  const query = {};
1406
1409
  if (opts.startDate) query.start_date = opts.startDate;
1407
1410
  if (opts.endDate) query.end_date = opts.endDate;
1408
1411
  if (opts.channel) query.channel = opts.channel;
1409
- return request(getCustomerServiceUrl(), path6, { method: "GET", query });
1412
+ return request(getObservabilityUrl(), path7, { method: "GET", query });
1410
1413
  }
1411
1414
  async function getDashboardTrend(opts) {
1412
1415
  const request = createRequest();
1413
- const path6 = opts.configId ? `${DASHBOARD_PREFIX}/${opts.configId}/trend` : `${DASHBOARD_PREFIX}/trend`;
1416
+ const path7 = opts.configId ? `${DASHBOARD_PREFIX}/${opts.configId}/trend` : `${DASHBOARD_PREFIX}/trend`;
1414
1417
  const query = {};
1415
1418
  if (opts.startDate) query.start_date = opts.startDate;
1416
1419
  if (opts.endDate) query.end_date = opts.endDate;
1417
1420
  if (opts.granularity) query.granularity = opts.granularity;
1418
1421
  if (opts.channel) query.channel = opts.channel;
1419
- return request(getCustomerServiceUrl(), path6, { method: "GET", query });
1422
+ return request(getObservabilityUrl(), path7, { method: "GET", query });
1420
1423
  }
1421
1424
  async function listShopStatistics(opts) {
1422
1425
  const request = createRequest();
@@ -1424,7 +1427,7 @@ async function listShopStatistics(opts) {
1424
1427
  if (opts.startDate) query.start_date = opts.startDate;
1425
1428
  if (opts.endDate) query.end_date = opts.endDate;
1426
1429
  if (opts.channel) query.channel = opts.channel;
1427
- return request(getCustomerServiceUrl(), `${DASHBOARD_PREFIX}/shop-statistics`, {
1430
+ return request(getObservabilityUrl(), `${DASHBOARD_PREFIX}/shop-statistics`, {
1428
1431
  method: "GET",
1429
1432
  query
1430
1433
  });
@@ -1435,7 +1438,7 @@ async function getIntentStatistics(opts) {
1435
1438
  if (opts.startDate) query.start_date = opts.startDate;
1436
1439
  if (opts.endDate) query.end_date = opts.endDate;
1437
1440
  return request(
1438
- getCustomerServiceUrl(),
1441
+ getObservabilityUrl(),
1439
1442
  `${DASHBOARD_PREFIX}/${opts.configId}/intent-statistics`,
1440
1443
  { method: "GET", query }
1441
1444
  );
@@ -1451,7 +1454,7 @@ async function listIntentConversations(opts) {
1451
1454
  if (opts.page) query.page = opts.page;
1452
1455
  if (opts.pageSize) query.page_size = opts.pageSize;
1453
1456
  return request(
1454
- getCustomerServiceUrl(),
1457
+ getObservabilityUrl(),
1455
1458
  `${DASHBOARD_PREFIX}/${opts.configId}/intent-conversations`,
1456
1459
  { method: "GET", query }
1457
1460
  );
@@ -1539,7 +1542,7 @@ async function exportShopData(opts) {
1539
1542
  if (opts.configIds && opts.configIds.length > 0) body.config_ids = opts.configIds;
1540
1543
  if (opts.channel) body.channel = opts.channel;
1541
1544
  const data = await request(
1542
- getCustomerServiceUrl(),
1545
+ getObservabilityUrl(),
1543
1546
  `${DASHBOARD_PREFIX}/export`,
1544
1547
  { method: "POST", body }
1545
1548
  );
@@ -1636,12 +1639,12 @@ function registerDashboardCommand(program2) {
1636
1639
  channel: opts.channel
1637
1640
  });
1638
1641
  if (opts.out) {
1639
- const { path: path6, bytes } = await writeBinaryToFile(
1642
+ const { path: path7, bytes } = await writeBinaryToFile(
1640
1643
  opts.out,
1641
1644
  Buffer.from(result.csv, "utf-8")
1642
1645
  );
1643
1646
  formatOutput(
1644
- { success: true, data: { path: path6, bytes, count: result.rows.length } },
1647
+ { success: true, data: { path: path7, bytes, count: result.rows.length } },
1645
1648
  program2.opts().table
1646
1649
  );
1647
1650
  } else {
@@ -4062,6 +4065,252 @@ function registerKnowledgeCommand(program2) {
4062
4065
  registerKnowledgeFileBindProductsCommand(knowledge, program2, "common");
4063
4066
  }
4064
4067
 
4068
+ // src/lib/media-upload.ts
4069
+ import fs9 from "fs";
4070
+ import path5 from "path";
4071
+ import OSS from "ali-oss";
4072
+
4073
+ // src/client/oss-api.ts
4074
+ import CryptoJS2 from "crypto-js";
4075
+ var STS_SECRET_KEY = "asdb2l0jskjft1q314f3ffjy71k9shj6";
4076
+ var IV_BYTES_LEN = 16;
4077
+ function decryptStsPayload(ciphertext) {
4078
+ const ciphertextBytes = CryptoJS2.enc.Base64.parse(
4079
+ ciphertext.replaceAll("-", "+").replaceAll("_", "/")
4080
+ );
4081
+ const iv = ciphertextBytes.clone();
4082
+ iv.sigBytes = IV_BYTES_LEN;
4083
+ iv.clamp();
4084
+ const encryptedContent = ciphertextBytes.clone();
4085
+ encryptedContent.words.splice(0, IV_BYTES_LEN / 4);
4086
+ encryptedContent.sigBytes -= IV_BYTES_LEN;
4087
+ const decrypted = CryptoJS2.AES.decrypt(
4088
+ // biome-ignore lint/suspicious/noExplicitAny: CryptoJS CipherParams 结构,仅需 ciphertext 字段
4089
+ { ciphertext: encryptedContent },
4090
+ CryptoJS2.enc.Utf8.parse(STS_SECRET_KEY),
4091
+ {
4092
+ iv,
4093
+ mode: CryptoJS2.mode.CBC,
4094
+ padding: CryptoJS2.pad.Pkcs7
4095
+ }
4096
+ );
4097
+ return decrypted.toString(CryptoJS2.enc.Utf8);
4098
+ }
4099
+ async function getUploadStsToken() {
4100
+ const request = createRequest();
4101
+ const encrypted = await request(getAiApiUrl(), "/v1/upload_sts", {
4102
+ method: "GET"
4103
+ });
4104
+ if (typeof encrypted !== "string" || encrypted.length === 0) {
4105
+ throw new Error("\u83B7\u53D6 OSS \u4E0A\u4F20\u51ED\u8BC1\u5931\u8D25\uFF1A\u63A5\u53E3\u672A\u8FD4\u56DE\u52A0\u5BC6\u6570\u636E");
4106
+ }
4107
+ let decoded;
4108
+ try {
4109
+ decoded = decryptStsPayload(encrypted);
4110
+ } catch (err) {
4111
+ throw new Error(`OSS \u4E0A\u4F20\u51ED\u8BC1\u89E3\u5BC6\u5931\u8D25\uFF1A${err.message}`);
4112
+ }
4113
+ let token;
4114
+ try {
4115
+ token = JSON.parse(decoded);
4116
+ } catch {
4117
+ throw new Error("OSS \u4E0A\u4F20\u51ED\u8BC1\u89E3\u6790\u5931\u8D25\uFF1A\u89E3\u5BC6\u7ED3\u679C\u4E0D\u662F\u5408\u6CD5 JSON");
4118
+ }
4119
+ if (!token.access_key_id || !token.access_key_secret) {
4120
+ throw new Error("OSS \u4E0A\u4F20\u51ED\u8BC1\u7F3A\u5C11 access_key_id / access_key_secret");
4121
+ }
4122
+ return token;
4123
+ }
4124
+
4125
+ // src/lib/media-upload.ts
4126
+ var IMAGE_MAX_BYTES = 10 * 1024 * 1024;
4127
+ var VIDEO_MAX_BYTES = 200 * 1024 * 1024;
4128
+ var DEFAULT_PATH_PREFIX = "/ai/knowledge/supplement";
4129
+ var IMAGE_EXTS = /* @__PURE__ */ new Set([
4130
+ ".jpg",
4131
+ ".jpeg",
4132
+ ".png",
4133
+ ".gif",
4134
+ ".webp",
4135
+ ".bmp",
4136
+ ".svg",
4137
+ ".tiff",
4138
+ ".tif",
4139
+ ".ico",
4140
+ ".heic",
4141
+ ".heif",
4142
+ ".avif"
4143
+ ]);
4144
+ var VIDEO_EXTS = /* @__PURE__ */ new Set([
4145
+ ".mp4",
4146
+ ".mov",
4147
+ ".avi",
4148
+ ".mkv",
4149
+ ".webm",
4150
+ ".flv",
4151
+ ".wmv",
4152
+ ".m4v",
4153
+ ".mpeg",
4154
+ ".mpg",
4155
+ ".3gp"
4156
+ ]);
4157
+ function isRemoteUrl(value) {
4158
+ return /^https?:\/\//i.test(value.trim());
4159
+ }
4160
+ function inferMediaType(filePath) {
4161
+ const ext = path5.extname(filePath).toLowerCase();
4162
+ if (IMAGE_EXTS.has(ext)) return "image";
4163
+ if (VIDEO_EXTS.has(ext)) return "video";
4164
+ return void 0;
4165
+ }
4166
+ function extMatchesType(filePath, type) {
4167
+ const ext = path5.extname(filePath).toLowerCase();
4168
+ if (type === "image") return !VIDEO_EXTS.has(ext);
4169
+ return !IMAGE_EXTS.has(ext);
4170
+ }
4171
+ function validateLocalFile(opts) {
4172
+ const { filePath } = opts;
4173
+ const absPath = path5.resolve(filePath);
4174
+ let stat;
4175
+ try {
4176
+ stat = fs9.statSync(absPath);
4177
+ } catch {
4178
+ throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4179
+ }
4180
+ if (!stat.isFile()) {
4181
+ throw new Error(`\u8DEF\u5F84\u4E0D\u662F\u6587\u4EF6: ${filePath}`);
4182
+ }
4183
+ const type = opts.type ?? inferMediaType(absPath);
4184
+ if (!type) {
4185
+ throw new Error(`\u65E0\u6CD5\u6839\u636E\u6269\u5C55\u540D\u5224\u65AD\u5A92\u4F53\u7C7B\u578B\uFF0C\u8BF7\u663E\u5F0F\u6307\u5B9A --type image|video: ${filePath}`);
4186
+ }
4187
+ if (type !== "image" && type !== "video") {
4188
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u5A92\u4F53\u7C7B\u578B: ${type}\uFF08\u4EC5\u652F\u6301 image / video\uFF09`);
4189
+ }
4190
+ if (!extMatchesType(absPath, type)) {
4191
+ throw new Error(`\u6587\u4EF6\u6269\u5C55\u540D\u4E0E\u58F0\u660E\u7684\u7C7B\u578B ${type} \u4E0D\u5339\u914D: ${filePath}`);
4192
+ }
4193
+ const limit = type === "image" ? IMAGE_MAX_BYTES : VIDEO_MAX_BYTES;
4194
+ if (stat.size > limit) {
4195
+ const limitMb = Math.round(limit / (1024 * 1024));
4196
+ const sizeMb = (stat.size / (1024 * 1024)).toFixed(2);
4197
+ throw new Error(
4198
+ `${type === "image" ? "\u56FE\u7247" : "\u89C6\u9891"}\u5927\u5C0F ${sizeMb}MB \u8D85\u8FC7\u4E0A\u9650 ${limitMb}MB: ${filePath}`
4199
+ );
4200
+ }
4201
+ return {
4202
+ absPath,
4203
+ filename: path5.basename(absPath),
4204
+ type,
4205
+ sizeBytes: stat.size
4206
+ };
4207
+ }
4208
+ function buildObjectKey(opts) {
4209
+ const ts = opts.timestamp ?? Date.now();
4210
+ const prefix = opts.pathPrefix.replace(/\/+$/, "").replace(/^\/+/, "");
4211
+ return `${prefix}/${ts}_${opts.filename}`;
4212
+ }
4213
+ var defaultOssPut = async ({ token, bucket, key, bytes }) => {
4214
+ const client = new OSS({
4215
+ region: token.region || "oss-cn-hangzhou",
4216
+ accessKeyId: token.access_key_id,
4217
+ accessKeySecret: token.access_key_secret,
4218
+ stsToken: token.security_token,
4219
+ bucket,
4220
+ secure: true,
4221
+ ...token.endpoint ? { endpoint: token.endpoint } : {}
4222
+ });
4223
+ const normalizedKey = key.replace(/^\/+/, "");
4224
+ const result = await client.put(normalizedKey, bytes);
4225
+ const rawUrl = result?.url ?? result?.res?.requestUrls?.[0];
4226
+ if (!rawUrl) {
4227
+ throw new Error("\u4E0A\u4F20\u6210\u529F\u4F46\u672A\u80FD\u89E3\u6790\u8FD4\u56DE URL");
4228
+ }
4229
+ return rawUrl.split("?")[0];
4230
+ };
4231
+ var ossPutImpl = defaultOssPut;
4232
+ async function uploadLocalFile(opts) {
4233
+ const token = await getUploadStsToken();
4234
+ const bucket = token.resource_bucket;
4235
+ if (!bucket) {
4236
+ throw new Error("OSS \u4E0A\u4F20\u51ED\u8BC1\u7F3A\u5C11 resource_bucket\uFF08\u516C\u5F00\u6876\uFF09\uFF0C\u65E0\u6CD5\u4E0A\u4F20\u516C\u5F00\u5A92\u4F53");
4237
+ }
4238
+ const key = buildObjectKey({
4239
+ pathPrefix: opts.pathPrefix ?? DEFAULT_PATH_PREFIX,
4240
+ filename: opts.file.filename,
4241
+ timestamp: opts.timestamp
4242
+ });
4243
+ const bytes = fs9.readFileSync(opts.file.absPath);
4244
+ try {
4245
+ return await ossPutImpl({ token, bucket, key, bytes });
4246
+ } catch (err) {
4247
+ throw new Error(`OSS \u4E0A\u4F20\u5931\u8D25: ${err.message}`);
4248
+ }
4249
+ }
4250
+ async function resolveMediaInput(opts) {
4251
+ const value = opts.value.trim();
4252
+ if (isRemoteUrl(value)) {
4253
+ return value;
4254
+ }
4255
+ const file = validateLocalFile({ filePath: value, type: opts.type });
4256
+ if (opts.dryRun) {
4257
+ return `<dry-run:will-upload:${file.filename}>`;
4258
+ }
4259
+ return uploadLocalFile({ file, pathPrefix: opts.pathPrefix });
4260
+ }
4261
+
4262
+ // src/commands/media.ts
4263
+ function registerMediaCommand(program2) {
4264
+ const media = program2.command("media").description(
4265
+ "\u5A92\u4F53\u4E0A\u4F20 \u2014\u2014 \u5C06\u672C\u5730\u56FE\u7247/\u89C6\u9891\u4E0A\u4F20\u5230\u516C\u5F00 OSS \u5E76\u8FD4\u56DE\u516C\u7F51 URL\u3002\u7528\u4E8E\u7EF4\u62A4\u5546\u54C1\u8865\u5145\u77E5\u8BC6\u4E2D\u7684 images / videos\uFF08\u8DEF\u5F84\u524D\u7F00\u4E0E\u524D\u7AEF\u4E00\u81F4\uFF09"
4266
+ );
4267
+ media.command("upload").description(
4268
+ "\u4E0A\u4F20\u5355\u4E2A\u672C\u5730\u56FE\u7247/\u89C6\u9891\u5230\u516C\u5F00 OSS\uFF0C\u8FD4\u56DE\u53EF\u8BBF\u95EE URL\u3002\u56FE\u7247\u9650 10MB\u3001\u89C6\u9891\u9650 200MB\uFF1B\u8D85\u9650\u76F4\u63A5\u62D2\u7EDD\uFF0C\u4E0D\u53D1\u4E0A\u4F20\u8BF7\u6C42"
4269
+ ).requiredOption("--file <path>", "\u672C\u5730\u6587\u4EF6\u8DEF\u5F84").option("--type <type>", "\u5A92\u4F53\u7C7B\u578B: image | video\uFF08\u7F3A\u7701\u6309\u6269\u5C55\u540D\u63A8\u65AD\uFF09").option(
4270
+ "--path-prefix <prefix>",
4271
+ "OSS \u8DEF\u5F84\u524D\u7F00\uFF0C\u6700\u7EC8 key \u4E3A <prefix>/<timestamp>_<filename>",
4272
+ DEFAULT_PATH_PREFIX
4273
+ ).option("--dry-run", "\u4EC5\u6821\u9A8C\u5E76\u8F93\u51FA\u5C06\u8981\u4E0A\u4F20\u7684\u4FE1\u606F\uFF0C\u4E0D\u5B9E\u9645\u4E0A\u4F20").action(async (opts) => {
4274
+ try {
4275
+ if (isRemoteUrl(opts.file)) {
4276
+ throw new Error("--file \u9700\u4E3A\u672C\u5730\u8DEF\u5F84\uFF1B\u5DF2\u662F URL \u7684\u5A92\u4F53\u65E0\u9700\u4E0A\u4F20");
4277
+ }
4278
+ const type = opts.type;
4279
+ if (type && type !== "image" && type !== "video") {
4280
+ throw new Error(`--type \u4EC5\u652F\u6301 image | video\uFF0C\u6536\u5230: ${type}`);
4281
+ }
4282
+ const file = validateLocalFile({ filePath: opts.file, type });
4283
+ if (opts.dryRun) {
4284
+ formatOutput(
4285
+ {
4286
+ success: true,
4287
+ data: {
4288
+ dryRun: true,
4289
+ file: file.absPath,
4290
+ type: file.type,
4291
+ sizeBytes: file.sizeBytes,
4292
+ pathPrefix: opts.pathPrefix
4293
+ }
4294
+ },
4295
+ program2.opts().table
4296
+ );
4297
+ return;
4298
+ }
4299
+ const url = await uploadLocalFile({ file, pathPrefix: opts.pathPrefix });
4300
+ formatOutput(
4301
+ {
4302
+ success: true,
4303
+ data: { url, type: file.type, sizeBytes: file.sizeBytes }
4304
+ },
4305
+ program2.opts().table
4306
+ );
4307
+ } catch (err) {
4308
+ reportCaughtError(err);
4309
+ process.exit(toExitCode(err));
4310
+ }
4311
+ });
4312
+ }
4313
+
4065
4314
  // src/client/monitor-api.ts
4066
4315
  var MONITOR_PATH_PREFIX = "/v1/operation";
4067
4316
  async function listAgentLifecycle(opts) {
@@ -4954,44 +5203,6 @@ function registerNodeTemplateCommand(program2) {
4954
5203
  });
4955
5204
  }
4956
5205
 
4957
- // src/client/ops-agent-api.ts
4958
- async function listOpsAgentConversations(opts) {
4959
- const workspaceId = getWorkspaceId(opts.workspaceId);
4960
- const request = createRequest();
4961
- const query = {
4962
- page: opts.page ?? 1,
4963
- page_size: opts.pageSize ?? 20
4964
- };
4965
- if (opts.customerId) query.customer_id = opts.customerId;
4966
- if (opts.agentId) query.agent_id = opts.agentId;
4967
- return request(getCustomerServiceUrl(), "/v1/ops-agent/conversations", {
4968
- method: "GET",
4969
- query,
4970
- headers: { "workspace-id": workspaceId }
4971
- });
4972
- }
4973
-
4974
- // src/commands/ops-agent.ts
4975
- function registerOpsAgentCommand(program2) {
4976
- const opsAgent = program2.command("ops-agent").description("Ops Agent\uFF08\u5BA2\u670D\u52A9\u624B\uFF09\u67E5\u8BE2\u547D\u4EE4");
4977
- opsAgent.command("conversations").description(
4978
- "\u67E5\u8BE2\u5BA2\u670D\u52A9\u624B\u4F1A\u8BDD\u5217\u8868\u3002\u8FD4\u56DE workspace_id\u3001customer_id\u3001title\u3001agent_id\u3001created_at\u3001updated_at"
4979
- ).option("--customer-id <id>", "\u6309 customer_id \u7B5B\u9009").option("--agent-id <id>", "\u6309 Ops Agent \u914D\u7F6E ID\uFF08customer_agent_config_id\uFF09\u7B5B\u9009").option("--page <number>", "\u9875\u7801", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF", "20").action(async (opts) => {
4980
- try {
4981
- const data = await listOpsAgentConversations({
4982
- customerId: opts.customerId,
4983
- agentId: opts.agentId,
4984
- page: Number(opts.page),
4985
- pageSize: Number(opts.pageSize)
4986
- });
4987
- formatOutput({ success: true, data }, program2.opts().table);
4988
- } catch (err) {
4989
- reportCaughtError(err);
4990
- process.exit(toExitCode(err));
4991
- }
4992
- });
4993
- }
4994
-
4995
5206
  // src/client/operations-record-api.ts
4996
5207
  var PATH_PREFIX3 = "/v1/agent_operations_records";
4997
5208
  async function listOperationsRecords(opts) {
@@ -5106,6 +5317,112 @@ function registerOperationsRecordCommand(program2) {
5106
5317
  });
5107
5318
  }
5108
5319
 
5320
+ // src/client/ops-agent-api.ts
5321
+ async function listOpsAgentConversations(opts) {
5322
+ const workspaceId = getWorkspaceId(opts.workspaceId);
5323
+ const request = createRequest();
5324
+ const query = {
5325
+ page: opts.page ?? 1,
5326
+ page_size: opts.pageSize ?? 20
5327
+ };
5328
+ if (opts.customerId) query.customer_id = opts.customerId;
5329
+ if (opts.agentId) query.agent_id = opts.agentId;
5330
+ return request(getCustomerServiceUrl(), "/v1/ops-agent/conversations", {
5331
+ method: "GET",
5332
+ query,
5333
+ headers: { "workspace-id": workspaceId }
5334
+ });
5335
+ }
5336
+
5337
+ // src/commands/ops-agent.ts
5338
+ function registerOpsAgentCommand(program2) {
5339
+ const opsAgent = program2.command("ops-agent").description("Ops Agent\uFF08\u5BA2\u670D\u52A9\u624B\uFF09\u67E5\u8BE2\u547D\u4EE4");
5340
+ opsAgent.command("conversations").description(
5341
+ "\u67E5\u8BE2\u5BA2\u670D\u52A9\u624B\u4F1A\u8BDD\u5217\u8868\u3002\u8FD4\u56DE workspace_id\u3001customer_id\u3001title\u3001agent_id\u3001created_at\u3001updated_at"
5342
+ ).option("--customer-id <id>", "\u6309 customer_id \u7B5B\u9009").option("--agent-id <id>", "\u6309 Ops Agent \u914D\u7F6E ID\uFF08customer_agent_config_id\uFF09\u7B5B\u9009").option("--page <number>", "\u9875\u7801", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF", "20").action(async (opts) => {
5343
+ try {
5344
+ const data = await listOpsAgentConversations({
5345
+ customerId: opts.customerId,
5346
+ agentId: opts.agentId,
5347
+ page: Number(opts.page),
5348
+ pageSize: Number(opts.pageSize)
5349
+ });
5350
+ formatOutput({ success: true, data }, program2.opts().table);
5351
+ } catch (err) {
5352
+ reportCaughtError(err);
5353
+ process.exit(toExitCode(err));
5354
+ }
5355
+ });
5356
+ }
5357
+
5358
+ // src/commands/product.ts
5359
+ import fs10 from "fs";
5360
+
5361
+ // src/lib/supplement.ts
5362
+ function parseSupplementField(value) {
5363
+ let current = value;
5364
+ for (let i = 0; i < 3; i++) {
5365
+ if (Array.isArray(current)) {
5366
+ return current.filter((it) => it != null && typeof it === "object");
5367
+ }
5368
+ if (typeof current !== "string") return [];
5369
+ const trimmed = current.trim();
5370
+ if (trimmed === "") return [];
5371
+ try {
5372
+ current = JSON.parse(trimmed);
5373
+ } catch {
5374
+ throw new Error(`\u8865\u5145\u77E5\u8BC6 JSON \u89E3\u6790\u5931\u8D25: ${truncate(trimmed)}`);
5375
+ }
5376
+ }
5377
+ return Array.isArray(current) ? current.filter((it) => it != null && typeof it === "object") : [];
5378
+ }
5379
+ function truncate(s, max = 120) {
5380
+ return s.length > max ? `${s.slice(0, max)}\u2026` : s;
5381
+ }
5382
+ function mergeUnique(existing, incoming) {
5383
+ const seen = /* @__PURE__ */ new Set();
5384
+ const result = [];
5385
+ for (const v of [...existing ?? [], ...incoming]) {
5386
+ const t = (v ?? "").trim();
5387
+ if (t === "" || seen.has(t)) continue;
5388
+ seen.add(t);
5389
+ result.push(t);
5390
+ }
5391
+ return result;
5392
+ }
5393
+ function addSupplementItem(existing, item) {
5394
+ const next = {
5395
+ question: item.question,
5396
+ answer: item.answer
5397
+ };
5398
+ if (item.images && item.images.length > 0) next.images = mergeUnique([], item.images);
5399
+ if (item.videos && item.videos.length > 0) next.videos = mergeUnique([], item.videos);
5400
+ return [...existing, next];
5401
+ }
5402
+ function appendMediaToItem(existing, opts) {
5403
+ if (!Number.isInteger(opts.index) || opts.index < 0 || opts.index >= existing.length) {
5404
+ throw new Error(`\u8865\u5145\u77E5\u8BC6\u6761\u76EE\u4E0B\u6807\u8D8A\u754C: index=${opts.index}\uFF08\u5F53\u524D\u5171 ${existing.length} \u6761\uFF09`);
5405
+ }
5406
+ return existing.map((it, i) => {
5407
+ if (i !== opts.index) return it;
5408
+ const updated = { ...it };
5409
+ if (opts.images && opts.images.length > 0) {
5410
+ updated.images = mergeUnique(asStringArray(it.images), opts.images);
5411
+ }
5412
+ if (opts.videos && opts.videos.length > 0) {
5413
+ updated.videos = mergeUnique(asStringArray(it.videos), opts.videos);
5414
+ }
5415
+ return updated;
5416
+ });
5417
+ }
5418
+ function asStringArray(value) {
5419
+ if (!Array.isArray(value)) return [];
5420
+ return value.filter((v) => typeof v === "string");
5421
+ }
5422
+ function serializeSupplement(items) {
5423
+ return JSON.stringify(items);
5424
+ }
5425
+
5109
5426
  // src/commands/product.ts
5110
5427
  async function getDbId(agentConfigId) {
5111
5428
  const agent = await getAgent(agentConfigId);
@@ -5130,6 +5447,41 @@ async function findProduct(agentConfigId, productId) {
5130
5447
  }
5131
5448
  }
5132
5449
  }
5450
+ async function loadProductSupplement(agentConfigId, productId) {
5451
+ const [dbId, matched] = await Promise.all([
5452
+ getDbId(agentConfigId),
5453
+ findProduct(agentConfigId, productId)
5454
+ ]);
5455
+ const detail = await getProductDetail({
5456
+ agentConfigId,
5457
+ dbId,
5458
+ productId
5459
+ });
5460
+ const items = parseSupplementField(detail.\u8865\u5145\u77E5\u8BC6);
5461
+ return {
5462
+ dbId,
5463
+ dataId: detail.id,
5464
+ knowledgeId: matched.knowledge_id,
5465
+ items,
5466
+ raw: detail.\u8865\u5145\u77E5\u8BC6
5467
+ };
5468
+ }
5469
+ async function writeProductSupplement(ctx, items) {
5470
+ return updateProduct({
5471
+ dataId: ctx.dataId,
5472
+ knowledgeId: ctx.knowledgeId,
5473
+ dbId: ctx.dbId,
5474
+ updateDict: { \u8865\u5145\u77E5\u8BC6: serializeSupplement(items) }
5475
+ });
5476
+ }
5477
+ async function resolveMediaList(values, type, dryRun) {
5478
+ if (!values || values.length === 0) return [];
5479
+ const urls = [];
5480
+ for (const value of values) {
5481
+ urls.push(await resolveMediaInput({ value, type, dryRun }));
5482
+ }
5483
+ return urls;
5484
+ }
5133
5485
  function registerProductCommand(program2) {
5134
5486
  const product = program2.command("product").description(
5135
5487
  "\u5546\u54C1\u77E5\u8BC6\u5E93\u7BA1\u7406 \u2014\u2014 Agent \u5173\u8054\u7684\u5546\u54C1\u6570\u636E\uFF08\u5356\u70B9\u3001\u8865\u5145\u77E5\u8BC6\u3001SKU\u3001\u53C2\u6570\u3001\u56FE\u7247\u8BC6\u522B\u7ED3\u679C\u7B49\uFF09\u3002Agent \u56DE\u7B54\u5546\u54C1\u76F8\u5173\u95EE\u9898\u65F6\u4F9D\u8D56\u6B64\u6570\u636E\u6E90"
@@ -5315,8 +5667,117 @@ function registerProductCommand(program2) {
5315
5667
  process.exit(toExitCode(err));
5316
5668
  }
5317
5669
  });
5670
+ registerProductSupplementCommand(product, program2);
5318
5671
  registerProductRelatedKnowledgeCommand(product, program2);
5319
5672
  }
5673
+ function registerProductSupplementCommand(product, program2) {
5674
+ const supplement = product.command("supplement").description(
5675
+ "\u5546\u54C1\u8865\u5145\u77E5\u8BC6\uFF08\u95EE\u7B54 + \u56FE\u7247/\u89C6\u9891\uFF09\u7EF4\u62A4\u3002\u5199\u5165\u91C7\u7528 read-modify-write\uFF0C\u53EA\u5408\u5E76\u76EE\u6807\u6761\u76EE\uFF0C\u4E0D\u8986\u76D6\u5176\u5B83\u8865\u5145\u77E5\u8BC6"
5676
+ );
5677
+ supplement.command("list").description("\u5217\u51FA\u5546\u54C1\u5F53\u524D\u8865\u5145\u77E5\u8BC6\u6761\u76EE\uFF08\u542B\u6BCF\u6761\u7684 question / answer / images / videos\uFF09").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption("--product-id <product_id>", "\u5546\u54C1 ID\uFF08\u4ECE product list \u83B7\u53D6\uFF09").action(async (opts) => {
5678
+ try {
5679
+ const ctx = await loadProductSupplement(opts.agent, opts.productId);
5680
+ formatOutput(
5681
+ {
5682
+ success: true,
5683
+ data: {
5684
+ product_id: opts.productId,
5685
+ count: ctx.items.length,
5686
+ \u8865\u5145\u77E5\u8BC6: ctx.items
5687
+ }
5688
+ },
5689
+ program2.opts().table
5690
+ );
5691
+ } catch (err) {
5692
+ reportCaughtError(err);
5693
+ process.exit(toExitCode(err));
5694
+ }
5695
+ });
5696
+ supplement.command("add").description(
5697
+ "\u65B0\u589E\u4E00\u6761\u8865\u5145\u77E5\u8BC6\uFF08Q/A + \u53EF\u9009\u56FE\u7247/\u89C6\u9891\uFF09\u3002--image / --video \u652F\u6301\u672C\u5730\u6587\u4EF6\uFF08\u81EA\u52A8\u4E0A\u4F20\u516C\u5F00 OSS\uFF09\u6216\u5DF2\u6709 URL\uFF08\u76F4\u5199\uFF09\u3002read-modify-write\uFF1A\u4FDD\u7559\u5168\u90E8\u65E2\u6709\u6761\u76EE\uFF0C\u4EC5\u8FFD\u52A0\u65B0\u6761\u76EE"
5698
+ ).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption("--product-id <product_id>", "\u5546\u54C1 ID\uFF08\u4ECE product list \u83B7\u53D6\uFF09").requiredOption("--question <text>", "\u5E38\u95EE\u95EE\u9898").requiredOption("--answer <text>", "\u56DE\u7B54\u5185\u5BB9").option("--image <path-or-url...>", "\u56FE\u7247\u672C\u5730\u8DEF\u5F84\u6216 URL\uFF08\u53EF\u591A\u4E2A\uFF09").option("--video <path-or-url...>", "\u89C6\u9891\u672C\u5730\u8DEF\u5F84\u6216 URL\uFF08\u53EF\u591A\u4E2A\uFF09").option("--dry-run", "\u53EA\u8F93\u51FA\u6700\u7EC8\u5C06\u5199\u5165\u7684 JSON\uFF0C\u4E0D\u5B9E\u9645\u4E0A\u4F20/\u66F4\u65B0").option("--backup <path>", "\u5199\u5165\u524D\u5C06\u66F4\u65B0\u524D\u8865\u5145\u77E5\u8BC6\u5FEB\u7167\u4FDD\u5B58\u5230\u6307\u5B9A\u6587\u4EF6").action(async (opts) => {
5699
+ try {
5700
+ const ctx = await loadProductSupplement(opts.agent, opts.productId);
5701
+ maybeWriteBackup(opts.backup, ctx.items);
5702
+ const images = await resolveMediaList(opts.image, "image", Boolean(opts.dryRun));
5703
+ const videos = await resolveMediaList(opts.video, "video", Boolean(opts.dryRun));
5704
+ const nextItems = addSupplementItem(ctx.items, {
5705
+ question: opts.question,
5706
+ answer: opts.answer,
5707
+ images,
5708
+ videos
5709
+ });
5710
+ if (opts.dryRun) {
5711
+ formatOutput(
5712
+ {
5713
+ success: true,
5714
+ data: {
5715
+ dryRun: true,
5716
+ before: ctx.items,
5717
+ after: nextItems,
5718
+ update_dict: { \u8865\u5145\u77E5\u8BC6: serializeSupplement(nextItems) }
5719
+ }
5720
+ },
5721
+ program2.opts().table
5722
+ );
5723
+ return;
5724
+ }
5725
+ const data = await writeProductSupplement(ctx, nextItems);
5726
+ formatOutput(
5727
+ { success: true, data: { updated: true, count: nextItems.length, result: data } },
5728
+ program2.opts().table
5729
+ );
5730
+ } catch (err) {
5731
+ reportCaughtError(err);
5732
+ process.exit(toExitCode(err));
5733
+ }
5734
+ });
5735
+ supplement.command("append-media").description(
5736
+ "\u5411\u6307\u5B9A\u4E0B\u6807\u7684\u5DF2\u6709\u8865\u5145\u77E5\u8BC6\u6761\u76EE\u8FFD\u52A0\u56FE\u7247/\u89C6\u9891\u3002\u539F\u6709 question / answer / images / videos \u53CA\u5176\u5B83\u6761\u76EE\u5747\u4E0D\u4E22\u5931"
5737
+ ).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption("--product-id <product_id>", "\u5546\u54C1 ID\uFF08\u4ECE product list \u83B7\u53D6\uFF09").requiredOption("--index <number>", "\u76EE\u6807\u8865\u5145\u77E5\u8BC6\u6761\u76EE\u4E0B\u6807\uFF08\u4ECE 0 \u5F00\u59CB\uFF0C\u89C1 supplement list\uFF09").option("--image <path-or-url...>", "\u56FE\u7247\u672C\u5730\u8DEF\u5F84\u6216 URL\uFF08\u53EF\u591A\u4E2A\uFF09").option("--video <path-or-url...>", "\u89C6\u9891\u672C\u5730\u8DEF\u5F84\u6216 URL\uFF08\u53EF\u591A\u4E2A\uFF09").option("--dry-run", "\u53EA\u8F93\u51FA\u6700\u7EC8\u5C06\u5199\u5165\u7684 JSON\uFF0C\u4E0D\u5B9E\u9645\u4E0A\u4F20/\u66F4\u65B0").option("--backup <path>", "\u5199\u5165\u524D\u5C06\u66F4\u65B0\u524D\u8865\u5145\u77E5\u8BC6\u5FEB\u7167\u4FDD\u5B58\u5230\u6307\u5B9A\u6587\u4EF6").action(async (opts) => {
5738
+ try {
5739
+ const index = Number(opts.index);
5740
+ if (!Number.isInteger(index) || index < 0) {
5741
+ throw new Error(`--index \u5FC5\u987B\u4E3A\u975E\u8D1F\u6574\u6570\uFF0C\u6536\u5230: ${opts.index}`);
5742
+ }
5743
+ if ((!opts.image || opts.image.length === 0) && (!opts.video || opts.video.length === 0)) {
5744
+ throw new Error("\u8BF7\u81F3\u5C11\u63D0\u4F9B\u4E00\u4E2A --image \u6216 --video");
5745
+ }
5746
+ const ctx = await loadProductSupplement(opts.agent, opts.productId);
5747
+ maybeWriteBackup(opts.backup, ctx.items);
5748
+ const images = await resolveMediaList(opts.image, "image", Boolean(opts.dryRun));
5749
+ const videos = await resolveMediaList(opts.video, "video", Boolean(opts.dryRun));
5750
+ const nextItems = appendMediaToItem(ctx.items, { index, images, videos });
5751
+ if (opts.dryRun) {
5752
+ formatOutput(
5753
+ {
5754
+ success: true,
5755
+ data: {
5756
+ dryRun: true,
5757
+ before: ctx.items,
5758
+ after: nextItems,
5759
+ update_dict: { \u8865\u5145\u77E5\u8BC6: serializeSupplement(nextItems) }
5760
+ }
5761
+ },
5762
+ program2.opts().table
5763
+ );
5764
+ return;
5765
+ }
5766
+ const data = await writeProductSupplement(ctx, nextItems);
5767
+ formatOutput(
5768
+ { success: true, data: { updated: true, index, result: data } },
5769
+ program2.opts().table
5770
+ );
5771
+ } catch (err) {
5772
+ reportCaughtError(err);
5773
+ process.exit(toExitCode(err));
5774
+ }
5775
+ });
5776
+ }
5777
+ function maybeWriteBackup(backupPath, items) {
5778
+ if (!backupPath) return;
5779
+ fs10.writeFileSync(backupPath, JSON.stringify(items, null, 2), "utf-8");
5780
+ }
5320
5781
 
5321
5782
  // src/client/repair-record-api.ts
5322
5783
  var PATH_PREFIX4 = "/api/repair-records";
@@ -5534,7 +5995,7 @@ function registerSACommand(program2) {
5534
5995
  }
5535
5996
 
5536
5997
  // src/commands/special-project.ts
5537
- import fs9 from "fs";
5998
+ import fs11 from "fs";
5538
5999
 
5539
6000
  // src/client/special-project-api.ts
5540
6001
  async function createSpecialProject(input) {
@@ -5577,7 +6038,7 @@ async function upsertSpecialProjects(items, apply) {
5577
6038
  // src/commands/special-project.ts
5578
6039
  function readJsonArg(value) {
5579
6040
  if (value.startsWith("@")) {
5580
- return fs9.readFileSync(value.slice(1), "utf-8");
6041
+ return fs11.readFileSync(value.slice(1), "utf-8");
5581
6042
  }
5582
6043
  return value;
5583
6044
  }
@@ -5654,11 +6115,11 @@ function registerSpecialProjectCommand(program2) {
5654
6115
  }
5655
6116
 
5656
6117
  // src/commands/testset.ts
5657
- import fs11 from "fs";
6118
+ import fs13 from "fs";
5658
6119
 
5659
6120
  // src/client/testset-api.ts
5660
- import fs10 from "fs";
5661
- import path5 from "path";
6121
+ import fs12 from "fs";
6122
+ import path6 from "path";
5662
6123
  function unwrapPaginated(raw, fallbackPageSize) {
5663
6124
  return {
5664
6125
  items: Array.isArray(raw?.data) ? raw?.data : [],
@@ -5686,14 +6147,14 @@ async function listTestSets(query) {
5686
6147
  }
5687
6148
  async function createTestSetFromFile(input) {
5688
6149
  const request = createRequest();
5689
- const fileBytes = fs10.readFileSync(input.filePath);
6150
+ const fileBytes = fs12.readFileSync(input.filePath);
5690
6151
  const formData = new FormData();
5691
6152
  formData.append(
5692
6153
  "file",
5693
6154
  new Blob([fileBytes], {
5694
6155
  type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
5695
6156
  }),
5696
- path5.basename(input.filePath)
6157
+ path6.basename(input.filePath)
5697
6158
  );
5698
6159
  return request(getCustomerServiceUrl(), "/v1/test_sets/file/upload", {
5699
6160
  method: "POST",
@@ -6190,7 +6651,7 @@ function readPromptInput(value) {
6190
6651
  if (!filePath) {
6191
6652
  throw new Error("File path cannot be empty after @");
6192
6653
  }
6193
- return fs11.readFileSync(filePath, "utf-8");
6654
+ return fs13.readFileSync(filePath, "utf-8");
6194
6655
  }
6195
6656
  return value;
6196
6657
  }
@@ -6225,7 +6686,7 @@ function registerTestsetCommand(program2) {
6225
6686
  });
6226
6687
  testset.command("create").description("\u901A\u8FC7 xlsx \u6587\u4EF6\u521B\u5EFA\u6D4B\u8BD5\u96C6").requiredOption("--customer-agent-config-id <id>", "Agent \u914D\u7F6E ID\uFF08\u5FC5\u586B\uFF0C\u4E0E\u540E\u7AEF\u5951\u7EA6\u5BF9\u9F50\uFF09").requiredOption("--file <path>", "\u6D4B\u8BD5\u96C6 xlsx \u6587\u4EF6\u8DEF\u5F84").option("--name <text>", "\u6D4B\u8BD5\u96C6\u540D\u79F0\uFF1B\u4E0D\u4F20\u5219\u540E\u7AEF\u53D6\u6587\u4EF6\u540D").option("--description <text>", "\u6D4B\u8BD5\u96C6\u63CF\u8FF0").option("--use-type <text>", "\u6587\u4EF6\u7528\u9014\u6807\u8BC6").action(async (opts) => {
6227
6688
  try {
6228
- if (!fs11.existsSync(opts.file)) {
6689
+ if (!fs13.existsSync(opts.file)) {
6229
6690
  outputError(1, `\u6587\u4EF6\u4E0D\u5B58\u5728: ${opts.file}`);
6230
6691
  process.exit(1);
6231
6692
  }
@@ -6320,6 +6781,563 @@ function registerTestsetCommand(program2) {
6320
6781
  registerExportCommand(program2, testset);
6321
6782
  }
6322
6783
 
6784
+ // src/commands/tool.ts
6785
+ import fs14 from "fs";
6786
+
6787
+ // src/client/flow-api.ts
6788
+ import { randomUUID as randomUUID2 } from "crypto";
6789
+
6790
+ // src/client/flow-skeleton.ts
6791
+ import { randomUUID } from "crypto";
6792
+ var DEFAULT_FORM_CONFIG = [
6793
+ {
6794
+ type: "json",
6795
+ label: "\u4E0A\u4E0B\u6587",
6796
+ required: true,
6797
+ placeholder: "\u8BF7\u8F93\u5165",
6798
+ variableName: "dialogue",
6799
+ cascadeFields: [],
6800
+ isCascadeField: false
6801
+ }
6802
+ ];
6803
+ function buildEdge(source, target) {
6804
+ return {
6805
+ id: `${source}-${target}`,
6806
+ type: "insert",
6807
+ source,
6808
+ target,
6809
+ interactionWidth: 80,
6810
+ style: {
6811
+ stroke: "#C0C3D1",
6812
+ strokeWidth: 2,
6813
+ strokeLinecap: "round",
6814
+ strokeLinejoin: "round"
6815
+ }
6816
+ };
6817
+ }
6818
+ function buildFlowSkeleton(opts) {
6819
+ const startId = randomUUID();
6820
+ const codeId = randomUUID();
6821
+ const endId = randomUUID();
6822
+ const codeName = opts.codeNodeName ?? "javascript_1";
6823
+ const startNode = {
6824
+ id: startId,
6825
+ type: "START",
6826
+ actionType: "TRIGGER",
6827
+ name: "start",
6828
+ relation: null,
6829
+ isEnable: true,
6830
+ layout: { width: 420, height: 311, position: { x: 0, y: 0 } },
6831
+ data: {
6832
+ name: "start",
6833
+ type: "form",
6834
+ actionType: "TRIGGER",
6835
+ inputs: {},
6836
+ isEnable: true,
6837
+ relation: null,
6838
+ conditions: [],
6839
+ packageName: "",
6840
+ sortCopyIndex: -1,
6841
+ formConfig: opts.inputVars ?? DEFAULT_FORM_CONFIG
6842
+ }
6843
+ };
6844
+ const codeNode = {
6845
+ id: codeId,
6846
+ type: "CODE",
6847
+ actionType: "CODE",
6848
+ name: codeName,
6849
+ relation: null,
6850
+ isEnable: true,
6851
+ layout: { width: 420, height: 435, position: { x: 544, y: 0 } },
6852
+ data: {
6853
+ name: codeName,
6854
+ type: null,
6855
+ actionType: "CODE",
6856
+ inputs: {
6857
+ code: opts.code,
6858
+ desc: opts.description ?? "",
6859
+ version: 1,
6860
+ language: "javascript"
6861
+ },
6862
+ isEnable: true,
6863
+ relation: null,
6864
+ conditions: [],
6865
+ packageName: "",
6866
+ formConfig: null,
6867
+ sortCopyIndex: 1
6868
+ }
6869
+ };
6870
+ const endNode = {
6871
+ id: endId,
6872
+ type: "END",
6873
+ actionType: "END",
6874
+ name: "output",
6875
+ relation: null,
6876
+ isEnable: true,
6877
+ layout: { width: 420, height: 98, position: { x: 1088, y: 0 } },
6878
+ data: {
6879
+ name: "output",
6880
+ type: null,
6881
+ actionType: "END",
6882
+ inputs: {},
6883
+ isEnable: true,
6884
+ relation: null,
6885
+ conditions: [],
6886
+ packageName: "",
6887
+ formConfig: null,
6888
+ sortCopyIndex: -1
6889
+ }
6890
+ };
6891
+ return {
6892
+ nodes: [startNode, codeNode, endNode],
6893
+ edges: [buildEdge(startId, codeId), buildEdge(codeId, endId)]
6894
+ };
6895
+ }
6896
+
6897
+ // src/client/flow-api.ts
6898
+ var CODE_NODE_GUIDE = `# CODE \u8282\u70B9\u7F16\u5199\u6307\u5357\uFF08JavaScript\uFF09
6899
+
6900
+ \u81EA\u5B9A\u4E49\u5DE5\u5177 = \u4E00\u4E2A flow\uFF0C\u6838\u5FC3\u662F\u5176\u4E2D\u7684 CODE \u8282\u70B9\u3002\u672C CLI \u521B\u5EFA/\u66F4\u65B0\u7684 CODE \u8282\u70B9\u53EA\u652F\u6301 JavaScript\u3002
6901
+ \u5B98\u65B9\u6587\u6863\uFF1Ahttps://ai-docs.betteryeah.com/Flow/\u8282\u70B9\u4ECB\u7ECD\u4E0E\u914D\u7F6E/JavaScript&Python\u8282\u70B9.html
6902
+
6903
+ ## 1. \u5165\u53E3\uFF1Aasync function main()
6904
+
6905
+ \u5FC5\u987B\u7F16\u5199\u540D\u4E3A main \u7684\u5F02\u6B65\u5165\u53E3\u51FD\u6570\uFF08\u9876\u5C42 async function main()\uFF09\u3002
6906
+ main() \u7684\u8FD4\u56DE\u503C\u5373\u5DE5\u5177\u4EA7\u51FA\uFF08\u4E1A\u52A1\u7ED3\u679C\uFF09\uFF0C\u4F1A\u88AB\u5E73\u53F0\u56DE\u586B\u7ED9 Agent \u4F5C\u4E3A\u8BE5\u5DE5\u5177\u7684\u8F93\u51FA\uFF1B
6907
+ \u6CA1\u6709 return \u5219\u8F93\u51FA\u4E3A null\u3002
6908
+
6909
+ ## 2. \u5165\u53C2\u4E0E\u53D8\u91CF\u6CE8\u5165
6910
+
6911
+ \u524D\u7F6E\u8282\u70B9\u7684\u53D8\u91CF\u5DF2\u5185\u7F6E\u5728\u4EE3\u7801\u6267\u884C\u73AF\u5883\u4E2D\uFF0C\u76F4\u63A5\u4EE5\u540C\u540D\u5168\u5C40\u53D8\u91CF\u4F7F\u7528\u3001\u65E0\u9700\u58F0\u660E\uFF1A
6912
+ - START \u8282\u70B9 formConfig \u58F0\u660E\u7684\u6BCF\u4E2A variableName \u90FD\u4F1A\u6CE8\u5165\u4E3A\u540C\u540D\u5168\u5C40\u53D8\u91CF\u3002
6913
+ \u9ED8\u8BA4\u53EA\u58F0\u660E\u4E00\u4E2A dialogue\uFF08\u4E0A\u4E0B\u6587\uFF0C\u7C7B\u578B json\uFF09\u2014\u2014\u5373\u6574\u6BB5\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u76F4\u63A5\u5F15\u7528 dialogue \u5373\u53EF\u3002
6914
+ \u8981\u52A0\u5165\u53C2\u5C31\u6539 formConfig\uFF08\u521B\u5EFA\u65F6\u7528 --input-vars \u8986\u76D6\uFF09\u3002
6915
+ - \u4E0A\u6E38\u5176\u5B83\u8282\u70B9\u7684\u8F93\u51FA\u540C\u6837\u6309\u8282\u70B9\u540D\u6CE8\u5165\uFF08\u5982 llm_1\uFF09\u3002\u672C CLI \u751F\u6210\u7684\u9AA8\u67B6\u53EA\u6709 START\u2192CODE\u2192END\uFF0C
6916
+ \u6240\u4EE5\u901A\u5E38\u53EA\u7528\u5F97\u5230 formConfig \u91CC\u7684\u53D8\u91CF\u3002
6917
+
6918
+ ## 3. \u8FD4\u56DE\u503C
6919
+
6920
+ \u8FD4\u56DE**\u88F8\u7684** object / list \u5373\u53EF\uFF0C**\u4E0D\u8981\u518D\u5957\u4E00\u5C42 {data:{...}} \u6216 {data:{run_result:[...]}} \u4FE1\u5C01**\u3002
6921
+ \u5E73\u53F0\u6309\u88F8\u8FD4\u56DE\u503C\u6D88\u8D39\uFF1B\u591A\u5957\u7684\u4FE1\u5C01\u4F1A\u8BA9\u4E0B\u6E38\u5BCC\u5316/\u89E3\u6790\u6309\u5B57\u9762 key \u53D6\u503C\u800C\u9759\u9ED8\u5931\u8D25\uFF08\u5DF2\u53D1\u751F\u8FC7\u7EBF\u4E0A\u4E8B\u6545\uFF09\u3002
6922
+ \u8FD4\u56DE\u503C\u5FC5\u987B\u53EF\u5E8F\u5217\u5316\u2014\u2014\u4E0D\u80FD\u662F\u6B63\u5219\u3001\u51FD\u6570\u7B49\u4E0D\u53EF\u5E8F\u5217\u5316\u5BF9\u8C61\u3002
6923
+
6924
+ ## 4. \u5185\u7F6E\u5305\uFF08CommonJS\uFF09
6925
+
6926
+ \u73AF\u5883\u5185\u7F6E\u5E38\u7528\u5305\uFF0C\u7528 require \u5BFC\u5165\uFF08\u4E0D\u652F\u6301 ES Module \u7684 import\uFF09\uFF1A
6927
+
6928
+ const axios = require('axios'); // HTTP \u8BF7\u6C42
6929
+ const dayjs = require('dayjs'); // \u65E5\u671F\u5904\u7406
6930
+ const crypto = require('crypto'); // \u52A0\u5BC6/\u6458\u8981
6931
+
6932
+ ## 5. BetterYeah SDK
6933
+
6934
+ const Betteryeah = require('betteryeah').default;
6935
+ const betteryeah = new Betteryeah();
6936
+
6937
+ \u6838\u5FC3\u6A21\u5757\uFF08\u5168\u90E8 await \u8C03\u7528\uFF09\uFF1A
6938
+ - betteryeah.llm.chat({ systemPrompt, model, jsonMode, temperature, messages })\uFF1A\u8C03\u5927\u6A21\u578B
6939
+ - betteryeah.knowledge.searchKnowledge / insertKnowledge\uFF1A\u77E5\u8BC6\u5E93\u67E5\u8BE2/\u63D2\u5165
6940
+ - betteryeah.database.executeDatabase({ databaseId, executableSql })\uFF1A\u6267\u884C SQL
6941
+ - betteryeah.plugin.*\uFF1A\u641C\u7D22\uFF08search.googleSearch/bingSearch/aiSearch\uFF09\u3001\u89E3\u6790\uFF08parsing.web/excel/pdf/...\uFF09\u3001
6942
+ \u8BC6\u56FE\u751F\u56FE\uFF08image.vision/generate/ocr\uFF09\u7B49
6943
+ - betteryeah.subFlow.execute(flowId, parameter)\uFF1A\u8C03\u7528\u5176\u5B83\u5DF2\u53D1\u5E03\u5DE5\u4F5C\u6D41
6944
+
6945
+ SDK \u7EDF\u4E00\u54CD\u5E94\u5F62\u72B6 { code, success, message, data, usage }\uFF0C\u52A1\u5FC5\u68C0\u67E5 success\uFF1A
6946
+
6947
+ if (!result.success) throw new Error(result.message ?? '\u6267\u884C\u51FA\u9519');
6948
+
6949
+ ## 6. betterAI \u8FD0\u884C\u65F6\u5BF9\u8C61
6950
+
6951
+ - betterAI.store.set(key, value) / betterAI.store.get(key)\uFF1Aflow \u751F\u547D\u5468\u671F\u5185\u5171\u4EAB\u6570\u636E
6952
+ - betterAI.session.*\uFF1A\u4F1A\u8BDD\u5143\u4FE1\u606F\u4E0E\u6301\u4E45\u5316\u8BB0\u5FC6\uFF08sessionId / conversationId / metaData / \u804A\u5929\u8BB0\u5F55\uFF09
6953
+ - betterAI.agent.chat.*\uFF1A\u5411 Agent \u4F1A\u8BDD\u63A8\u9001\u6D88\u606F/\u901A\u77E5
6954
+
6955
+ ## 7. \u5B8C\u6574\u793A\u4F8B
6956
+
6957
+ async function main() {
6958
+ const ctx = dialogue; // \u6765\u81EA START formConfig \u7684\u5168\u5C40\u53D8\u91CF
6959
+ // ...\u4F60\u7684\u4E1A\u52A1\u903B\u8F91...
6960
+ return { ok: true }; // main \u7684\u8FD4\u56DE\u503C\u5373\u5DE5\u5177\u4EA7\u51FA\uFF08\u88F8\u5BF9\u8C61\uFF0C\u52FF\u5957\u4FE1\u5C01\uFF09
6961
+ }
6962
+
6963
+ ## 8. \u6CE8\u610F\u4E8B\u9879
6964
+
6965
+ - \u77E5\u8BC6\u5E93 ID / \u6587\u4EF6 ID / \u6570\u636E\u5E93 ID \u7B49\u5728\u5E73\u53F0\u5DE6\u4FA7\u8D44\u6E90\u6811\u7528\u590D\u5236\u6309\u94AE\u83B7\u53D6\u3002
6966
+ - SDK \u5404\u6A21\u5757\u5B8C\u6574\u53C2\u6570\u4E0E\u66F4\u591A\u793A\u4F8B\u4EE5\u4E0A\u65B9\u5B98\u65B9\u6587\u6863\u4E3A\u51C6\u3002
6967
+ `;
6968
+ async function createFlow(opts) {
6969
+ const { nodes, edges } = buildFlowSkeleton({
6970
+ code: opts.code,
6971
+ description: opts.description,
6972
+ inputVars: opts.inputVars,
6973
+ codeNodeName: opts.codeNodeName
6974
+ });
6975
+ const request = createRequest();
6976
+ const res = await request(
6977
+ getAiApiUrl(),
6978
+ "/v1/applications",
6979
+ {
6980
+ method: "POST",
6981
+ query: { workspaceId: getWorkspaceId() },
6982
+ headers: {
6983
+ accept: "application/json",
6984
+ "application-id": randomUUID2().replace(/-/g, "")
6985
+ },
6986
+ body: {
6987
+ icon: "\u{1F33C}",
6988
+ color: "#ADE9CE",
6989
+ description: opts.description ?? "\u6682\u65E0\u63CF\u8FF0",
6990
+ name: opts.name,
6991
+ applicationType: "AI",
6992
+ config: JSON.stringify({ nodes, edges }),
6993
+ channel_type: "flow"
6994
+ }
6995
+ }
6996
+ );
6997
+ const flowId = res.flowId;
6998
+ const versionId = res.versionId;
6999
+ const publish = opts.publish !== false;
7000
+ if (publish) {
7001
+ await request(getAiApiUrl(), "/v1/flow/publish", {
7002
+ method: "POST",
7003
+ body: {
7004
+ draftVersionId: versionId,
7005
+ ...opts.versionDesc ? { version_desc: opts.versionDesc } : {}
7006
+ }
7007
+ });
7008
+ }
7009
+ return { flow_id: flowId, version_id: versionId, published: publish };
7010
+ }
7011
+ async function getFlowConfig(opts) {
7012
+ const request = createRequest();
7013
+ return request(getAiApiUrl(), `/v1/applications/${encodeURIComponent(opts.flowId)}`, {
7014
+ method: "GET"
7015
+ });
7016
+ }
7017
+ async function updateFlowCode(opts) {
7018
+ const data = await getFlowConfig({ flowId: opts.flowId });
7019
+ const config = data.config;
7020
+ if (!config || typeof config !== "object" || !Array.isArray(config.nodes)) {
7021
+ throw new APIError(1, "flow config \u5F62\u72B6\u5F02\u5E38\uFF1A\u7F3A nodes \u6570\u7EC4\uFF0C\u65E0\u6CD5\u5B9A\u4F4D CODE \u8282\u70B9");
7022
+ }
7023
+ const codeNodes = config.nodes.filter(
7024
+ // biome-ignore lint/suspicious/noExplicitAny: 同上
7025
+ (n) => n.type === "CODE"
7026
+ );
7027
+ if (codeNodes.length !== 1) {
7028
+ throw new APIError(1, `\u672A\u627E\u5230\u552F\u4E00 CODE \u8282\u70B9\uFF08\u627E\u5230 ${codeNodes.length} \u4E2A\uFF09`);
7029
+ }
7030
+ codeNodes[0].data.inputs.code = opts.code;
7031
+ const request = createRequest();
7032
+ await request(getAiApiUrl(), "/v1/flow/update", {
7033
+ method: "POST",
7034
+ body: { appId: opts.flowId, config, flowId: opts.flowId }
7035
+ });
7036
+ const publish = opts.publish !== false;
7037
+ if (publish) {
7038
+ const draft = await request(
7039
+ getAiApiUrl(),
7040
+ `/v1/flow/draft/${encodeURIComponent(opts.flowId)}`,
7041
+ { method: "GET" }
7042
+ );
7043
+ await request(getAiApiUrl(), "/v1/flow/publish", {
7044
+ method: "POST",
7045
+ body: {
7046
+ draftVersionId: draft.version_id,
7047
+ ...opts.versionDesc ? { version_desc: opts.versionDesc } : {}
7048
+ }
7049
+ });
7050
+ }
7051
+ return { flow_id: opts.flowId, published: publish };
7052
+ }
7053
+ async function getWorkspaceAccessKey() {
7054
+ const request = createRequest();
7055
+ const workspaceId = getWorkspaceId();
7056
+ return request(
7057
+ getAiApiUrl(),
7058
+ `/v1/workspaces/getKey/${encodeURIComponent(workspaceId)}`,
7059
+ { method: "GET" }
7060
+ );
7061
+ }
7062
+ async function runFlow(opts) {
7063
+ const accessKey = await getWorkspaceAccessKey();
7064
+ const request = createRequest();
7065
+ return request(
7066
+ getAiApiUrl(),
7067
+ `/v1/public_api/rest_api/${encodeURIComponent(opts.flowId)}/execute_flow`,
7068
+ {
7069
+ method: "POST",
7070
+ headers: { "Access-Key": accessKey },
7071
+ body: { inputs: opts.inputs ?? {}, async_execute: false }
7072
+ }
7073
+ );
7074
+ }
7075
+ async function deleteFlow(opts) {
7076
+ const request = createRequest();
7077
+ await request(getAiApiUrl(), `/v1/applications/${encodeURIComponent(opts.flowId)}`, {
7078
+ method: "DELETE"
7079
+ });
7080
+ return { flow_id: opts.flowId };
7081
+ }
7082
+
7083
+ // src/client/tool-api.ts
7084
+ var VALID_INVOCATION_MODES = ["must_invoke", "on_demand", "on_demand_async"];
7085
+ function assertInvocationMode(mode) {
7086
+ if (!VALID_INVOCATION_MODES.includes(mode)) {
7087
+ throw new APIError(
7088
+ 1,
7089
+ "invocation_mode \u975E\u6CD5\uFF0C\u53EF\u9009\u503C\uFF1Amust_invoke / on_demand / on_demand_async"
7090
+ );
7091
+ }
7092
+ }
7093
+ async function listToolsByConfig(opts) {
7094
+ const request = createRequest();
7095
+ return request(getCustomerServiceUrl(), "/v1/tool/by-config", {
7096
+ method: "GET",
7097
+ query: { customer_agent_config_id: opts.agentConfigId }
7098
+ });
7099
+ }
7100
+ async function createCustomTool(opts) {
7101
+ if (opts.invocationMode !== void 0) {
7102
+ assertInvocationMode(opts.invocationMode);
7103
+ }
7104
+ const request = createRequest();
7105
+ return request(getCustomerServiceUrl(), "/v1/tool/custom", {
7106
+ method: "POST",
7107
+ body: {
7108
+ name: opts.name,
7109
+ key: opts.key,
7110
+ workspace_id: getWorkspaceId(),
7111
+ customer_agent_config_id: opts.agentConfigId,
7112
+ source_id: opts.sourceId,
7113
+ source_type: opts.sourceType ?? "flow",
7114
+ description: opts.description ?? "",
7115
+ invocation_mode: opts.invocationMode ?? "on_demand",
7116
+ input_var_descriptions: opts.inputVarDescriptions ?? {}
7117
+ }
7118
+ });
7119
+ }
7120
+ async function updateTool(opts) {
7121
+ if (opts.invocationMode !== void 0) {
7122
+ assertInvocationMode(opts.invocationMode);
7123
+ }
7124
+ const body = {};
7125
+ if (opts.name !== void 0) body.name = opts.name;
7126
+ if (opts.key !== void 0) body.key = opts.key;
7127
+ if (opts.description !== void 0) body.description = opts.description;
7128
+ if (opts.sourceId !== void 0) body.source_id = opts.sourceId;
7129
+ if (opts.invocationMode !== void 0) body.invocation_mode = opts.invocationMode;
7130
+ if (opts.inputVarDescriptions !== void 0) {
7131
+ body.input_var_descriptions = opts.inputVarDescriptions;
7132
+ }
7133
+ const request = createRequest();
7134
+ return request(getCustomerServiceUrl(), `/v1/tool/${opts.toolId}`, {
7135
+ method: "PUT",
7136
+ body
7137
+ });
7138
+ }
7139
+ async function deleteTool(opts) {
7140
+ const request = createRequest();
7141
+ return request(getCustomerServiceUrl(), `/v1/tool/${opts.toolId}`, {
7142
+ method: "DELETE"
7143
+ });
7144
+ }
7145
+ async function listWorkflows(opts) {
7146
+ const request = createRequest();
7147
+ return request(getCustomerServiceUrl(), "/v1/tool/workflow/list", {
7148
+ method: "GET",
7149
+ query: { workspace_id: getWorkspaceId(), keyword: opts.keyword ?? "" }
7150
+ });
7151
+ }
7152
+ async function getWorkflowDetail(opts) {
7153
+ const request = createRequest();
7154
+ return request(
7155
+ getCustomerServiceUrl(),
7156
+ `/v1/tool/workflow/${encodeURIComponent(opts.flowId)}/detail`,
7157
+ {
7158
+ method: "GET",
7159
+ query: { workspace_id: getWorkspaceId() }
7160
+ }
7161
+ );
7162
+ }
7163
+
7164
+ // src/commands/tool.ts
7165
+ function readArgMaybeFile(value) {
7166
+ if (value.startsWith("@")) {
7167
+ const filePath = value.slice(1);
7168
+ try {
7169
+ return fs14.readFileSync(filePath, "utf8");
7170
+ } catch {
7171
+ throw new APIError(
7172
+ 1,
7173
+ `\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A${filePath}\uFF08@ \u524D\u7F00\u8868\u793A\u6587\u4EF6\u8DEF\u5F84\uFF1B\u8981\u4F20\u5B57\u9762\u5185\u5BB9\u8BF7\u53BB\u6389 @\uFF09`
7174
+ );
7175
+ }
7176
+ }
7177
+ return value;
7178
+ }
7179
+ function registerToolCommand(program2) {
7180
+ const tool = program2.command("tool").description(
7181
+ "\u81EA\u5B9A\u4E49/\u8986\u76D6\u5DE5\u5177\uFF08agent tool\uFF09\u7BA1\u7406 \u2014\u2014 \u5BF9\u67D0\u4E2A Agent \u914D\u7F6E\u7ED1\u5B9A\u7684\u81EA\u5B9A\u4E49\u5DE5\u5177\u505A\u589E\u5220\u6539\u67E5\uFF0C\u5E76\u53D1\u73B0\u53EF\u7ED1\u5B9A\u7684\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\u3002\u5305\u88C5 servhub /v1/tool API"
7182
+ );
7183
+ tool.command("list").description("\u5217\u51FA\u8BE5 Agent \u914D\u7F6E\u5DF2\u7ED1\u5B9A\u7684\u5DE5\u5177\uFF08custom + system\uFF09").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").action(async (opts) => {
7184
+ try {
7185
+ const data = await listToolsByConfig({ agentConfigId: opts.agent });
7186
+ formatOutput({ success: true, data }, program2.opts().table);
7187
+ } catch (err) {
7188
+ reportCaughtError(err);
7189
+ process.exit(toExitCode(err));
7190
+ }
7191
+ });
7192
+ tool.command("create").description("\u521B\u5EFA\u81EA\u5B9A\u4E49\u5DE5\u5177\uFF0C\u7ED1\u5B9A\u4E00\u4E2A\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\u4F5C\u4E3A\u5DE5\u5177\u5B9E\u73B0").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption("--name <name>", "\u5DE5\u5177\u663E\u793A\u540D\u79F0").requiredOption("--key <key>", "\u5DE5\u5177 key\uFF08\u552F\u4E00\u6807\u8BC6\uFF09").requiredOption("--source-id <flow_id>", "\u7ED1\u5B9A\u7684\u5DE5\u4F5C\u6D41 ID\uFF08\u4ECE tool workflow list \u83B7\u53D6\uFF09").option("--description <text>", "\u5DE5\u5177\u63CF\u8FF0").option("--source-type <type>", "\u5DE5\u5177\u6765\u6E90\u7C7B\u578B\uFF08\u9ED8\u8BA4 flow\uFF09").option(
7193
+ "--invocation-mode <mode>",
7194
+ "\u8C03\u7528\u6A21\u5F0F\uFF1Amust_invoke / on_demand / on_demand_async\uFF08\u9ED8\u8BA4 on_demand\uFF09"
7195
+ ).option("--input-vars <json>", "\u5165\u53C2\u63CF\u8FF0\uFF08JSON \u5B57\u7B26\u4E32\uFF09\uFF0C\u89E3\u6790\u4E3A input_var_descriptions").action(async (opts) => {
7196
+ try {
7197
+ const inputVarDescriptions = opts.inputVars !== void 0 ? JSON.parse(opts.inputVars) : void 0;
7198
+ const data = await createCustomTool({
7199
+ agentConfigId: opts.agent,
7200
+ name: opts.name,
7201
+ key: opts.key,
7202
+ sourceId: opts.sourceId,
7203
+ description: opts.description,
7204
+ sourceType: opts.sourceType,
7205
+ invocationMode: opts.invocationMode,
7206
+ inputVarDescriptions
7207
+ });
7208
+ formatOutput({ success: true, data }, program2.opts().table);
7209
+ } catch (err) {
7210
+ reportCaughtError(err);
7211
+ process.exit(toExitCode(err));
7212
+ }
7213
+ });
7214
+ tool.command("update <tool_id>").description("\u66F4\u65B0\u5DE5\u5177\u7684\u4EFB\u610F\u5B50\u96C6\u5B57\u6BB5\uFF08\u4EC5\u900F\u4F20\u5B9E\u9645\u63D0\u4F9B\u7684 flag\uFF09").option("--name <name>", "\u5DE5\u5177\u663E\u793A\u540D\u79F0").option("--key <key>", "\u5DE5\u5177 key\uFF08\u552F\u4E00\u6807\u8BC6\uFF09").option("--description <text>", "\u5DE5\u5177\u63CF\u8FF0").option("--source-id <flow_id>", "\u7ED1\u5B9A\u7684\u5DE5\u4F5C\u6D41 ID").option("--invocation-mode <mode>", "\u8C03\u7528\u6A21\u5F0F\uFF1Amust_invoke / on_demand / on_demand_async").option("--input-vars <json>", "\u5165\u53C2\u63CF\u8FF0\uFF08JSON \u5B57\u7B26\u4E32\uFF09\uFF0C\u89E3\u6790\u4E3A input_var_descriptions").action(async (toolId, opts) => {
7215
+ try {
7216
+ const inputVarDescriptions = opts.inputVars !== void 0 ? JSON.parse(opts.inputVars) : void 0;
7217
+ const data = await updateTool({
7218
+ toolId,
7219
+ name: opts.name,
7220
+ key: opts.key,
7221
+ description: opts.description,
7222
+ sourceId: opts.sourceId,
7223
+ invocationMode: opts.invocationMode,
7224
+ inputVarDescriptions
7225
+ });
7226
+ formatOutput({ success: true, data }, program2.opts().table);
7227
+ } catch (err) {
7228
+ reportCaughtError(err);
7229
+ process.exit(toExitCode(err));
7230
+ }
7231
+ });
7232
+ tool.command("delete <tool_id>").description("\u5220\u9664\uFF08\u8F6F\u5220\u9664\uFF09\u6307\u5B9A\u5DE5\u5177").action(async (toolId) => {
7233
+ try {
7234
+ const data = await deleteTool({ toolId });
7235
+ formatOutput({ success: true, data }, program2.opts().table);
7236
+ } catch (err) {
7237
+ reportCaughtError(err);
7238
+ process.exit(toExitCode(err));
7239
+ }
7240
+ });
7241
+ const workflow = tool.command("workflow").description(
7242
+ "\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\u7BA1\u7406\uFF1Alist / detail\uFF08\u53D1\u73B0\uFF09+ create / update / run / delete / describe\uFF08\u589E\u6539\u8DD1\u5220 + \u8BF4\u660E\uFF09"
7243
+ );
7244
+ workflow.command("list").description("\u5217\u51FA\u5F53\u524D\u5DE5\u4F5C\u7A7A\u95F4\u53EF\u7ED1\u5B9A\u7684\u5DE5\u4F5C\u6D41\uFF08flow\uFF09").option("--keyword <kw>", "\u6309\u5173\u952E\u8BCD\u6A21\u7CCA\u7B5B\u9009").action(async (opts) => {
7245
+ try {
7246
+ const data = await listWorkflows({ keyword: opts.keyword });
7247
+ formatOutput({ success: true, data }, program2.opts().table);
7248
+ } catch (err) {
7249
+ reportCaughtError(err);
7250
+ process.exit(toExitCode(err));
7251
+ }
7252
+ });
7253
+ workflow.command("detail <flow_id>").description("\u67E5\u770B\u6307\u5B9A\u5DE5\u4F5C\u6D41\u7684\u5165\u53C2\u5217\u8868\uFF08\u7528\u4E8E\u6784\u9020 input_var_descriptions\uFF09").action(async (flowId) => {
7254
+ try {
7255
+ const data = await getWorkflowDetail({ flowId });
7256
+ formatOutput({ success: true, data }, program2.opts().table);
7257
+ } catch (err) {
7258
+ reportCaughtError(err);
7259
+ process.exit(toExitCode(err));
7260
+ }
7261
+ });
7262
+ workflow.command("create").description(
7263
+ "\u521B\u5EFA\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\uFF1ASTART \u2192 CODE \u2192 END \u9AA8\u67B6\uFF0CCODE \u8282\u70B9\u627F\u8F7D\u5DE5\u5177\u4EE3\u7801\uFF08\u4EC5\u652F\u6301 JavaScript\uFF09\u3002\u975E\u5E42\u7B49\u2014\u2014\u91CD\u8BD5\u4F1A\u5EFA\u51FA\u91CD\u590D flow\uFF0C\u91CD\u8BD5\u524D\u5148 tool workflow list --keyword <name> \u6838\u5BF9"
7264
+ ).requiredOption("--name <name>", "\u5DE5\u4F5C\u6D41\u540D\u79F0").requiredOption(
7265
+ "--code <code|@file>",
7266
+ "CODE \u8282\u70B9 JavaScript \u4EE3\u7801\uFF1B\u503C\u4EE5 @ \u5F00\u5934\u5219\u8BFB\u53D6\u8BE5\u6587\u4EF6\u8DEF\u5F84\uFF08\u5982 @./tool.js\uFF09\uFF0C\u5426\u5219\u6309\u5B57\u9762\u4EE3\u7801"
7267
+ ).option("--description <text>", "\u5DE5\u4F5C\u6D41\u63CF\u8FF0").option(
7268
+ "--input-vars <json|@file>",
7269
+ "\u8986\u76D6 START formConfig\uFF08@file \u540C --code\uFF09\uFF1B\u5F62\u6001\u662F formConfig \u6570\u7EC4 [{type,label,required,placeholder,variableName,...}]\uFF0C\u9ED8\u8BA4\u4EC5 dialogue\u3002\u6CE8\u610F\uFF1A\u4E0E tool create \u7684 --input-vars\uFF08input_var_descriptions\uFF09\u662F\u4E0D\u540C\u5B57\u6BB5"
7270
+ ).option("--no-publish", "\u53EA\u5EFA\u8349\u7A3F\u4E0D\u53D1\u5E03").option("--code-node-name <name>", "CODE \u8282\u70B9\u540D\uFF08\u9ED8\u8BA4 javascript_1\uFF09").option("--version-desc <text>", "\u53D1\u5E03\u7248\u672C\u63CF\u8FF0\uFF08\u5E73\u53F0\u7248\u672C\u5386\u53F2\u91CC\u53EF\u89C1\uFF1B--no-publish \u65F6\u5FFD\u7565\uFF09").action(async (opts) => {
7271
+ try {
7272
+ const code = readArgMaybeFile(opts.code);
7273
+ const inputVars = opts.inputVars !== void 0 ? JSON.parse(readArgMaybeFile(opts.inputVars)) : void 0;
7274
+ const data = await createFlow({
7275
+ name: opts.name,
7276
+ code,
7277
+ description: opts.description,
7278
+ inputVars,
7279
+ codeNodeName: opts.codeNodeName,
7280
+ publish: opts.publish,
7281
+ versionDesc: opts.versionDesc
7282
+ });
7283
+ formatOutput({ success: true, data }, program2.opts().table);
7284
+ } catch (err) {
7285
+ reportCaughtError(err);
7286
+ process.exit(toExitCode(err));
7287
+ }
7288
+ });
7289
+ workflow.command("update <flow_id>").description("\u66F4\u65B0\u5DE5\u4F5C\u6D41\u552F\u4E00 CODE \u8282\u70B9\u7684\u4EE3\u7801\uFF08\u5176\u5B83\u8282\u70B9\u539F\u6837\u4FDD\u7559\uFF09").requiredOption(
7290
+ "--code <code|@file>",
7291
+ "CODE \u8282\u70B9\u65B0\u4EE3\u7801\uFF08JavaScript\uFF09\uFF1B\u503C\u4EE5 @ \u5F00\u5934\u5219\u8BFB\u53D6\u8BE5\u6587\u4EF6\u8DEF\u5F84\uFF0C\u5426\u5219\u6309\u5B57\u9762\u4EE3\u7801"
7292
+ ).option("--no-publish", "\u53EA\u66F4\u65B0\u8349\u7A3F\u4E0D\u53D1\u5E03").option("--version-desc <text>", "\u53D1\u5E03\u7248\u672C\u63CF\u8FF0\uFF08\u5E73\u53F0\u7248\u672C\u5386\u53F2\u91CC\u53EF\u89C1\uFF1B--no-publish \u65F6\u5FFD\u7565\uFF09").action(async (flowId, opts) => {
7293
+ try {
7294
+ const code = readArgMaybeFile(opts.code);
7295
+ const data = await updateFlowCode({
7296
+ flowId,
7297
+ code,
7298
+ publish: opts.publish,
7299
+ versionDesc: opts.versionDesc
7300
+ });
7301
+ formatOutput({ success: true, data }, program2.opts().table);
7302
+ } catch (err) {
7303
+ reportCaughtError(err);
7304
+ process.exit(toExitCode(err));
7305
+ }
7306
+ });
7307
+ workflow.command("run <flow_id>").description(
7308
+ "\u8FD0\u884C\u5DF2\u53D1\u5E03\u7684\u5DE5\u4F5C\u6D41\uFF08HTTP \u540C\u6B65\u6267\u884C\uFF09\uFF1A\u81EA\u52A8\u53D6\u5F53\u524D\u7A7A\u95F4\u5E94\u7528\u6001 access key\uFF0C\u8FD4\u56DE run_result"
7309
+ ).option(
7310
+ "--input <json|@file>",
7311
+ `flow \u5165\u53C2 JSON \u5BF9\u8C61\uFF08\u9ED8\u8BA4 {}\uFF09\uFF0C\u952E\u5BF9\u5E94 START formConfig \u7684 variableName\uFF0C\u5982 '{"dialogue":...}'\uFF1B@file \u540C --code`
7312
+ ).action(async (flowId, opts) => {
7313
+ try {
7314
+ const inputs = opts.input !== void 0 ? JSON.parse(readArgMaybeFile(opts.input)) : void 0;
7315
+ const data = await runFlow({ flowId, inputs });
7316
+ formatOutput({ success: true, data }, program2.opts().table);
7317
+ } catch (err) {
7318
+ reportCaughtError(err);
7319
+ process.exit(toExitCode(err));
7320
+ }
7321
+ });
7322
+ workflow.command("delete <flow_id>").description("\u786C\u5220\u9664\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\u2014\u2014\u4E0D\u53EF\u6062\u590D\uFF08\u533A\u522B\u4E8E tool delete \u7684\u8F6F\u5220\u9664\uFF09").option("--yes", "\u786E\u8BA4\u5220\u9664\uFF08\u5FC5\u987B\u663E\u5F0F\u52A0\uFF0C\u5426\u5219\u62D2\u7EDD\uFF09").action(async (flowId, opts) => {
7323
+ try {
7324
+ if (!opts.yes) {
7325
+ throw new APIError(1, "\u5220\u9664\u4F1A\u8BA9\u6307\u5411\u6B64 flow \u7684\u81EA\u5B9A\u4E49\u5DE5\u5177\u5931\u6548\uFF0C\u786E\u8BA4\u8BF7\u52A0 --yes");
7326
+ }
7327
+ const data = await deleteFlow({ flowId });
7328
+ formatOutput({ success: true, data }, program2.opts().table);
7329
+ } catch (err) {
7330
+ reportCaughtError(err);
7331
+ process.exit(toExitCode(err));
7332
+ }
7333
+ });
7334
+ workflow.command("describe").description(
7335
+ "\u8F93\u51FA CODE \u8282\u70B9\uFF08JavaScript\uFF09\u4F7F\u7528\u6587\u6863\uFF1A\u5165\u53E3/\u53D8\u91CF\u6CE8\u5165/\u8FD4\u56DE\u503C/\u5185\u7F6E\u5305/SDK\uFF0C\u4F9D\u636E\u5B98\u65B9\u6587\u6863\u6574\u7406"
7336
+ ).action(() => {
7337
+ formatOutput({ success: true, data: { guide: CODE_NODE_GUIDE } }, program2.opts().table);
7338
+ });
7339
+ }
7340
+
6323
7341
  // src/commands/workspace.ts
6324
7342
  var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
6325
7343
  function toISODate(d) {
@@ -6413,7 +7431,9 @@ registerWorkspaceCommand(program);
6413
7431
  registerAgentCommand(program);
6414
7432
  registerOpsAgentCommand(program);
6415
7433
  registerSACommand(program);
7434
+ registerToolCommand(program);
6416
7435
  registerProductCommand(program);
7436
+ registerMediaCommand(program);
6417
7437
  registerKnowledgeCommand(program);
6418
7438
  registerActivityCommand(program);
6419
7439
  registerIssueCommand(program);