@bty/customer-service-cli 0.6.0 → 0.6.4

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.
Files changed (4) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/README.md +49 -9
  3. package/dist/bin.js +1296 -601
  4. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -31,7 +31,24 @@ function formatOutput(response, table) {
31
31
  if (Array.isArray(data)) {
32
32
  renderArrayTable(data);
33
33
  } else if (data !== null && typeof data === "object") {
34
- renderObjectTable(data);
34
+ const obj = data;
35
+ const innerArray = findInnerArray(obj);
36
+ if (innerArray) {
37
+ renderArrayTable(innerArray);
38
+ const total = obj.total ?? obj.count;
39
+ const pageNo = obj.page_no ?? obj.page;
40
+ const pageSize = obj.page_size;
41
+ if (total !== void 0) {
42
+ const paginationParts = [`total: ${total}`];
43
+ if (pageNo !== void 0) paginationParts.push(`page: ${pageNo}`);
44
+ if (pageSize !== void 0) paginationParts.push(`page_size: ${pageSize}`);
45
+ process.stdout.write(`
46
+ ${paginationParts.join(" | ")}
47
+ `);
48
+ }
49
+ } else {
50
+ renderObjectTable(obj);
51
+ }
35
52
  } else {
36
53
  process.stdout.write(JSON.stringify(response, null, 2));
37
54
  return;
@@ -43,6 +60,16 @@ Page ${page} | ${pageSize} per page | ${total} total
43
60
  `);
44
61
  }
45
62
  }
63
+ function findInnerArray(obj) {
64
+ const paginationKeys = /* @__PURE__ */ new Set(["total", "count", "page_no", "page", "page_size"]);
65
+ const arrayKey = Object.keys(obj).find(
66
+ (k) => Array.isArray(obj[k]) && !paginationKeys.has(k)
67
+ );
68
+ if (!arrayKey) return null;
69
+ const arr = obj[arrayKey];
70
+ if (arr.length === 0 || typeof arr[0] !== "object" || arr[0] === null) return null;
71
+ return arr;
72
+ }
46
73
  function renderArrayTable(data) {
47
74
  const first = data[0];
48
75
  if (first == null) {
@@ -52,7 +79,14 @@ function renderArrayTable(data) {
52
79
  const headers = Object.keys(first);
53
80
  const table = new Table({ head: headers });
54
81
  for (const row of data) {
55
- table.push(headers.map((h) => String(row[h] ?? "")));
82
+ table.push(
83
+ headers.map((h) => {
84
+ const val = row[h];
85
+ if (Array.isArray(val)) return val.length === 0 ? "[]" : `[${val.length} items]`;
86
+ if (val !== null && typeof val === "object") return JSON.stringify(val);
87
+ return String(val ?? "");
88
+ })
89
+ );
56
90
  }
57
91
  process.stdout.write(`${table.toString()}
58
92
  `);
@@ -60,7 +94,15 @@ function renderArrayTable(data) {
60
94
  function renderObjectTable(data) {
61
95
  const table = new Table();
62
96
  for (const [key, value] of Object.entries(data)) {
63
- table.push({ [key]: String(value ?? "") });
97
+ let display;
98
+ if (Array.isArray(value)) {
99
+ display = value.length === 0 ? "[]" : `[${value.length} items]`;
100
+ } else if (value !== null && typeof value === "object") {
101
+ display = JSON.stringify(value);
102
+ } else {
103
+ display = String(value ?? "");
104
+ }
105
+ table.push({ [key]: display });
64
106
  }
65
107
  process.stdout.write(`${table.toString()}
66
108
  `);
@@ -436,7 +478,6 @@ function isTokenExpired(expiresAt) {
436
478
  // src/client/helpers.ts
437
479
  var DEFAULT_CS_API_URL = "https://customer-servhub-api.betteryeah.com";
438
480
  var DEFAULT_AI_API_URL = "https://ai-api.betteryeah.com";
439
- var DEFAULT_CUSTOMER_AGENT_API_URL = "https://customer-agent.bantouyan.com";
440
481
  var DEFAULT_CS_ADMIN_URL = "https://customer-service-admin.betteryeah.com";
441
482
  function getCustomerServiceUrl() {
442
483
  const envUrl = process.env.CS_CS_API_URL;
@@ -450,12 +491,6 @@ function getAiApiUrl() {
450
491
  const config = readConfig();
451
492
  return config?.aiApiUrl ?? DEFAULT_AI_API_URL;
452
493
  }
453
- function getCustomerAgentUrl() {
454
- const envUrl = process.env.CS_CUSTOMER_AGENT_URL;
455
- if (envUrl) return envUrl;
456
- const config = readConfig();
457
- return config?.customerAgentApiUrl ?? DEFAULT_CUSTOMER_AGENT_API_URL;
458
- }
459
494
  function getCsAdminUrl() {
460
495
  const envUrl = process.env.CS_CS_ADMIN_URL;
461
496
  if (envUrl) return envUrl;
@@ -477,15 +512,6 @@ function getWorkspaceId(overrideWorkspaceId) {
477
512
  if (globalConfig?.defaultWorkspaceId) return globalConfig.defaultWorkspaceId;
478
513
  throw new APIError(1, "\u672A\u8BBE\u7F6E\u5DE5\u4F5C\u7A7A\u95F4\uFF0C\u8BF7\u8FD0\u884C: cs-cli config set-workspace <id>");
479
514
  }
480
- function buildCookieHeaders() {
481
- const creds = readCredentials();
482
- if (!creds) throw new APIError(2, "\u672A\u767B\u5F55\uFF0C\u8BF7\u8FD0\u884C: cs-cli auth login");
483
- if (isTokenExpired(creds.expiresAt)) {
484
- clearCredentials();
485
- throw new APIError(2, "Token \u5DF2\u8FC7\u671F\uFF0C\u8BF7\u8FD0\u884C: cs-cli auth login");
486
- }
487
- return { Cookie: `auth_token=${creds.accessToken}` };
488
- }
489
515
 
490
516
  // src/client/activity-api.ts
491
517
  var PATH_PREFIX = "/v1/activity";
@@ -1104,6 +1130,17 @@ async function getDailyDeduction(opts) {
1104
1130
  }
1105
1131
  );
1106
1132
  }
1133
+ async function getPointsConsumes(opts) {
1134
+ const request = createRequest();
1135
+ return request(
1136
+ getCustomerServiceUrl(),
1137
+ "/v1/workspace/points_consumes",
1138
+ {
1139
+ method: "POST",
1140
+ body: { page: opts.page, page_size: opts.pageSize, debug: true }
1141
+ }
1142
+ );
1143
+ }
1107
1144
 
1108
1145
  // src/commands/config.ts
1109
1146
  function registerConfigCommand(program2) {
@@ -1187,6 +1224,7 @@ function registerConfigCommand(program2) {
1187
1224
  // src/client/conversation-api.ts
1188
1225
  var MAX_CONTEXT_SEARCH_RANGE_MS = 3 * 24 * 60 * 60 * 1e3;
1189
1226
  var MAX_TRANSFER_HUMAN_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
1227
+ var MAX_TRANSFER_HUMAN_CURSOR_PAGES = 500;
1190
1228
  function parseSearchTime(value, fieldName) {
1191
1229
  const parsed = new Date(value);
1192
1230
  if (Number.isNaN(parsed.getTime())) {
@@ -1259,15 +1297,36 @@ async function listConversations(opts) {
1259
1297
  async function listTransferHumanConversations(opts) {
1260
1298
  validateTransferHumanRange(opts.startDate, opts.endDate);
1261
1299
  const request = createRequest();
1262
- return request(getCustomerServiceUrl(), "/v1/chat/conversations/transfer-human", {
1263
- method: "GET",
1264
- query: {
1265
- customer_agent_config_id: opts.customerAgentConfigId,
1266
- start_date: opts.startDate,
1267
- end_date: opts.endDate,
1268
- page: opts.page ?? 1
1269
- }
1270
- });
1300
+ const items = [];
1301
+ let cursor;
1302
+ let fetchedPages = 0;
1303
+ let pagination = {};
1304
+ while (fetchedPages < MAX_TRANSFER_HUMAN_CURSOR_PAGES) {
1305
+ fetchedPages += 1;
1306
+ const page = await request(
1307
+ getCustomerServiceUrl(),
1308
+ "/v1/chat/conversations/transfer-human",
1309
+ {
1310
+ method: "GET",
1311
+ query: {
1312
+ customer_agent_config_id: opts.customerAgentConfigId,
1313
+ start_date: opts.startDate,
1314
+ end_date: opts.endDate,
1315
+ page: 1,
1316
+ cursor
1317
+ }
1318
+ }
1319
+ );
1320
+ items.push(...page.items ?? []);
1321
+ pagination = page.pagination ?? {};
1322
+ const hasMore = pagination.has_more === true;
1323
+ const nextCursor = typeof pagination.next_cursor === "string" && pagination.next_cursor ? pagination.next_cursor : void 0;
1324
+ if (!hasMore || !nextCursor) {
1325
+ return { ...page, items, pagination: { ...pagination, fetched_pages: fetchedPages } };
1326
+ }
1327
+ cursor = nextCursor;
1328
+ }
1329
+ throw new Error(`\u8F6C\u4EBA\u5DE5\u4F1A\u8BDD\u5206\u9875\u8D85\u8FC7 ${MAX_TRANSFER_HUMAN_CURSOR_PAGES} \u9875\uFF0C\u8BF7\u7F29\u5C0F\u67E5\u8BE2\u65F6\u95F4\u8303\u56F4`);
1271
1330
  }
1272
1331
 
1273
1332
  // src/commands/conversation.ts
@@ -1323,13 +1382,12 @@ function registerConversationCommand(program2) {
1323
1382
  process.exit(toExitCode(err));
1324
1383
  }
1325
1384
  });
1326
- conversation.command("transfer-human").description("\u67E5\u8BE2\u8F6C\u4EBA\u5DE5\u4F1A\u8BDD\u53CA\u5BF9\u5E94\u8F6C\u4EBA\u5DE5\u6D88\u606F\u8BB0\u5F55").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08customer_agent_config_id\uFF09").requiredOption("--start <date>", "\u5F00\u59CB\u65F6\u95F4\uFF08ISO \u683C\u5F0F\uFF0C\u5982 2026-05-20T00:00:00\uFF09").requiredOption("--end <date>", "\u7ED3\u675F\u65F6\u95F4\uFF08ISO \u683C\u5F0F\uFF0C\u5982 2026-05-20T23:59:59\uFF09").option("--page <number>", "\u9875\u7801", "1").action(async (opts) => {
1385
+ conversation.command("transfer-human").description("\u67E5\u8BE2\u8F6C\u4EBA\u5DE5\u4F1A\u8BDD\u53CA\u5BF9\u5E94\u8F6C\u4EBA\u5DE5\u6D88\u606F\u8BB0\u5F55").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08customer_agent_config_id\uFF09").requiredOption("--start <date>", "\u5F00\u59CB\u65F6\u95F4\uFF08ISO \u683C\u5F0F\uFF0C\u5982 2026-05-20T00:00:00\uFF09").requiredOption("--end <date>", "\u7ED3\u675F\u65F6\u95F4\uFF08ISO \u683C\u5F0F\uFF0C\u5982 2026-05-20T23:59:59\uFF09").action(async (opts) => {
1327
1386
  try {
1328
1387
  const data = await listTransferHumanConversations({
1329
1388
  customerAgentConfigId: opts.agent,
1330
1389
  startDate: opts.start,
1331
- endDate: opts.end,
1332
- page: Number(opts.page)
1390
+ endDate: opts.end
1333
1391
  });
1334
1392
  formatOutput({ success: true, data }, program2.opts().table);
1335
1393
  } catch (err) {
@@ -1685,16 +1743,23 @@ async function sendAgentMessage(opts) {
1685
1743
  ];
1686
1744
  }
1687
1745
  const request = createRequest();
1746
+ const body = {
1747
+ msg_list: msgList,
1748
+ is_stream: false,
1749
+ conversation_id: opts.conversationId
1750
+ };
1751
+ if (opts.mock !== void 0) {
1752
+ body.mock = opts.mock;
1753
+ }
1754
+ if (opts.debugDataOverlay !== void 0) {
1755
+ body.debug_data_overlay = opts.debugDataOverlay;
1756
+ }
1688
1757
  return request(
1689
1758
  getCustomerServiceUrl(),
1690
1759
  "/v1/debug/chat/agent_message",
1691
1760
  {
1692
1761
  method: "POST",
1693
- body: {
1694
- msg_list: msgList,
1695
- is_stream: false,
1696
- conversation_id: opts.conversationId
1697
- }
1762
+ body
1698
1763
  }
1699
1764
  );
1700
1765
  }
@@ -1814,218 +1879,677 @@ async function getLangfuseTrace(traceId, env) {
1814
1879
  );
1815
1880
  }
1816
1881
 
1817
- // src/commands/debug.ts
1818
- function registerDebugCommand(program2) {
1819
- const debug = program2.command("debug").description(
1820
- "Agent \u8C03\u8BD5\u6D4B\u8BD5 \u2014\u2014 \u5411 Agent \u53D1\u9001\u6D4B\u8BD5\u6D88\u606F\u5E76\u83B7\u53D6\u56DE\u590D\uFF0C\u662F\u9A8C\u8BC1 Agent \u56DE\u590D\u8D28\u91CF\u7684\u4E3B\u8981\u624B\u6BB5\u3002\u652F\u6301\u5355\u6761\u6D88\u606F\u548C\u591A\u8F6E\u5BF9\u8BDD\u91CD\u653E"
1821
- );
1822
- debug.command("ask").description(
1823
- "\u5411 Agent \u53D1\u9001\u6D88\u606F\u5E76\u7B49\u5F85\u56DE\u590D\u3002\u8FD4\u56DE { conversation_id, reply: [{ record_id, content, ... }] }\u3002record_id \u53EF\u4F20\u7ED9 debug record \u67E5\u770B\u5185\u90E8\u63A8\u7406\u94FE\u8DEF"
1824
- ).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").option("--text <message>", "\u53D1\u9001\u7684\u6D88\u606F\u5185\u5BB9\uFF08\u4E0E --messages \u4E92\u65A5\uFF0C\u4E8C\u9009\u4E00\uFF09").option(
1825
- "--messages <json>",
1826
- '\u5B8C\u6574\u6D88\u606F\u5217\u8868 JSON \u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF0C\u7528\u4E8E\u91CD\u653E\u591A\u8F6E\u5BF9\u8BDD\uFF08\u4E0E --text \u4E92\u65A5\uFF09\u3002\u63A5\u53D7\u4E24\u79CD\u683C\u5F0F\uFF1A(1) JSON \u6570\u7EC4 [{ match_id, content: { text, image_url? }, timestamp, type: "TEXT", role: "user"|"assistant" }, ...] (2) \u542B msg_list \u5B57\u6BB5\u7684\u5BF9\u8C61 { msg_list: [...] }\uFF08conversation records \u7684\u539F\u59CB\u683C\u5F0F\u53EF\u76F4\u63A5\u4F7F\u7528\uFF09'
1827
- ).option("--user <name>", "\u6A21\u62DF\u7684\u7528\u6237\u540D\uFF08\u9ED8\u8BA4\u4F7F\u7528\u767B\u5F55\u7528\u6237\u540D\uFF09").option("--url <image_url>", "\u9644\u5E26\u7684\u56FE\u7247 URL\uFF08\u4EC5 --text \u6A21\u5F0F\u6709\u6548\uFF09").option("--conversation <id>", "\u590D\u7528\u5DF2\u6709\u4F1A\u8BDD ID\uFF0C\u7528\u4E8E\u5728\u540C\u4E00\u4E0A\u4E0B\u6587\u4E2D\u7EE7\u7EED\u5BF9\u8BDD").option("--timeout <seconds>", "\u6700\u5927\u7B49\u5F85\u56DE\u590D\u65F6\u95F4\uFF08\u79D2\uFF09\uFF0C\u590D\u6742 Agent \u5EFA\u8BAE\u8C03\u9AD8", "30").option("--poll-interval <ms>", "\u8F6E\u8BE2\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09", "2000").action(async (opts) => {
1828
- try {
1829
- if (!opts.text && !opts.messages) {
1830
- outputError(1, "\u5FC5\u987B\u6307\u5B9A --text \u6216 --messages \u5176\u4E2D\u4E4B\u4E00");
1831
- process.exit(1);
1832
- }
1833
- const userName = opts.user ?? readCredentials()?.username ?? "cli-user";
1834
- let conversationId;
1835
- if (opts.conversation) {
1836
- conversationId = opts.conversation;
1837
- } else {
1838
- const conv = await createDebugConversation({
1839
- agentConfigId: opts.agent,
1840
- userName
1841
- });
1842
- conversationId = conv.conversation_id;
1843
- }
1844
- let msgList;
1845
- if (opts.messages) {
1846
- const parsed = parseDataOption(opts.messages);
1847
- msgList = Array.isArray(parsed) ? parsed : parsed.msg_list;
1848
- if (!Array.isArray(msgList)) {
1849
- outputError(1, "--messages \u5FC5\u987B\u662F JSON \u6570\u7EC4\u6216\u5305\u542B msg_list \u5B57\u6BB5\u7684\u5BF9\u8C61");
1850
- process.exit(1);
1851
- }
1852
- }
1853
- await sendAgentMessage({
1854
- conversationId,
1855
- text: opts.text,
1856
- imageUrl: opts.url,
1857
- msgList
1858
- });
1859
- const agentRecords = await pollAgentReply(conversationId, {
1860
- timeout: Number(opts.timeout) * 1e3,
1861
- pollInterval: Number(opts.pollInterval)
1862
- });
1863
- formatOutput(
1864
- {
1865
- success: true,
1866
- data: {
1867
- conversation_id: conversationId,
1868
- reply: agentRecords
1869
- }
1870
- },
1871
- program2.opts().table
1872
- );
1873
- } catch (err) {
1874
- reportCaughtError(err);
1875
- process.exit(toExitCode(err));
1876
- }
1877
- });
1878
- debug.command("record").description("\u83B7\u53D6\u67D0\u6761\u56DE\u590D\u7684\u5185\u90E8\u63A8\u7406\u94FE\u8DEF\uFF08flow_info\uFF09\uFF0C\u7528\u4E8E\u8BCA\u65AD Agent \u4E3A\u4F55\u7ED9\u51FA\u7279\u5B9A\u56DE\u590D").argument("<record_id>", "\u56DE\u590D\u8BB0\u5F55 ID\uFF08\u4ECE debug ask \u8FD4\u56DE\u7684 reply[].record_id \u83B7\u53D6\uFF09").option(
1879
- "--deep",
1880
- "\u6DF1\u5EA6\u89E3\u6790\uFF1A\u989D\u5916\u8C03\u7528 ai-api \u7684 flow execute_log \u63A5\u53E3\uFF0C\u62C9\u53D6 flow_info.flow_id + task_id \u5BF9\u5E94\u7684\u5B8C\u6574\u6267\u884C\u65E5\u5FD7\uFF08log_url \u5185\u5BB9\uFF09\uFF0C\u7528\u4E8E\u6392\u67E5\u8282\u70B9\u7EA7\u8F93\u5165\u8F93\u51FA",
1881
- false
1882
- ).option("--flow-workspace <id>", "flow \u6240\u5728 workspace ID\uFF08--deep \u65F6\u4F7F\u7528\uFF0C\u9ED8\u8BA4\u4F7F\u7528\u5185\u7F6E\u56FA\u5B9A\u503C\uFF09").action(async (recordId, opts) => {
1883
- try {
1884
- const data = await getRecordDebugInfo(recordId);
1885
- let deep;
1886
- if (opts.deep) {
1887
- const flowInfo = data.flow_info;
1888
- const flowId = flowInfo?.flow_id;
1889
- const taskId = flowInfo?.task_id;
1890
- if (!flowId || !taskId) {
1891
- deep = { error: "flow_info \u4E2D\u7F3A\u5C11 flow_id \u6216 task_id\uFF0C\u65E0\u6CD5\u6DF1\u5EA6\u89E3\u6790" };
1892
- } else {
1893
- try {
1894
- deep = await getFlowExecuteLog({
1895
- flowId,
1896
- taskId,
1897
- workspaceId: opts.flowWorkspace
1898
- });
1899
- } catch (err) {
1900
- deep = { error: err.message };
1901
- }
1902
- }
1903
- }
1904
- formatOutput(
1905
- { success: true, data: opts.deep ? { ...data, deep } : data },
1906
- program2.opts().table
1907
- );
1908
- } catch (err) {
1909
- reportCaughtError(err);
1910
- process.exit(toExitCode(err));
1911
- }
1912
- });
1913
- debug.command("reproduce").description(
1914
- "\u6839\u636E record_id \u590D\u73B0\u4E00\u6B21 Agent \u56DE\u590D\u3002\u81EA\u52A8\u83B7\u53D6\u5173\u8054\u4F1A\u8BDD\u3001\u622A\u53D6\u4E0A\u4E0B\u6587\u3001\u7528\u539F\u59CB user_name \u521B\u5EFA debug \u4F1A\u8BDD\u5E76\u91CD\u65B0\u53D1\u9001"
1915
- ).argument("<record_id>", "\u8981\u590D\u73B0\u7684\u56DE\u590D\u8BB0\u5F55 ID").option("--agent <config_id>", "\u4F7F\u7528\u6307\u5B9A Agent \u590D\u73B0\uFF08\u9ED8\u8BA4\u4F7F\u7528\u539F\u59CB Agent\uFF09").option("--timeout <seconds>", "\u6700\u5927\u7B49\u5F85\u56DE\u590D\u65F6\u95F4\uFF08\u79D2\uFF09", "60").option("--poll-interval <ms>", "\u8F6E\u8BE2\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09", "2000").option("--dry-run", "\u4EC5\u8F93\u51FA\u622A\u65AD\u540E\u7684\u4E0A\u4E0B\u6587 msg_list\uFF0C\u4E0D\u53D1\u9001", false).action(async (recordId, opts) => {
1916
- try {
1917
- const relations = await getRecordRelations(recordId);
1918
- const { conversation, agent_config: agentConfig } = relations;
1919
- const conversationId = conversation.conversation_id;
1920
- const agentConfigId = opts.agent ?? agentConfig.config_id;
1921
- const userName = conversation.user_name ?? "cli-user";
1922
- const records = await getConversationRecords({
1923
- conversationId,
1924
- pageSize: 200,
1925
- direction: "prev"
1926
- });
1927
- const truncated = truncateBeforeRecord(records, recordId);
1928
- const msgList = recordsToMsgList(truncated);
1929
- if (opts.dryRun) {
1930
- formatOutput(
1931
- {
1932
- success: true,
1933
- data: {
1934
- original_record_id: recordId,
1935
- agent_config_id: agentConfigId,
1936
- agent_config_name: agentConfig.config_name,
1937
- user_name: userName,
1938
- context_messages_count: msgList.length,
1939
- msg_list: msgList
1940
- }
1941
- },
1942
- program2.opts().table
1943
- );
1944
- return;
1945
- }
1946
- const conv = await createDebugConversation({
1947
- agentConfigId,
1948
- userName
1949
- });
1950
- await sendAgentMessage({
1951
- conversationId: conv.conversation_id,
1952
- msgList
1953
- });
1954
- const agentRecords = await pollAgentReply(conv.conversation_id, {
1955
- timeout: Number(opts.timeout) * 1e3,
1956
- pollInterval: Number(opts.pollInterval),
1957
- category: "agent_response"
1958
- });
1959
- let traceId = null;
1960
- try {
1961
- const debugInfo = await getRecordDebugInfo(agentRecords[0].record_id);
1962
- traceId = debugInfo.trace_id ?? null;
1963
- } catch {
1964
- }
1965
- formatOutput(
1966
- {
1967
- success: true,
1968
- data: {
1969
- original_record_id: recordId,
1970
- conversation_id: conv.conversation_id,
1971
- agent_config_id: agentConfigId,
1972
- agent_config_name: agentConfig.config_name,
1973
- user_name: userName,
1974
- context_messages_count: msgList.length,
1975
- trace_id: traceId,
1976
- reply: agentRecords
1977
- }
1978
- },
1979
- program2.opts().table
1980
- );
1981
- } catch (err) {
1982
- reportCaughtError(err);
1983
- process.exit(toExitCode(err));
1984
- }
1985
- });
1986
- debug.command("trace").description(
1987
- "\u6839\u636E Langfuse Trace ID \u83B7\u53D6\u5B8C\u6574\u7684 Trace \u8BE6\u60C5\uFF08\u4ECE debug record \u8FD4\u56DE\u7684 flow_info \u4E2D\u63D0\u53D6 traceId\uFF09"
1988
- ).argument("<trace_id>", "Langfuse Trace ID\uFF08\u4ECE flow_info \u4E2D\u83B7\u53D6\uFF09").option("--env <env>", "langfuse \u73AF\u5883 dev|prod", "prod").action(async (traceId, opts) => {
1989
- try {
1990
- if (opts.env !== "dev" && opts.env !== "prod") {
1991
- outputError(1, "--env \u4EC5\u652F\u6301 dev \u6216 prod");
1992
- process.exit(1);
1993
- }
1994
- const data = await getLangfuseTrace(traceId, opts.env);
1995
- formatOutput({ success: true, data }, program2.opts().table);
1996
- } catch (err) {
1997
- reportCaughtError(err);
1998
- process.exit(toExitCode(err));
1882
+ // src/client/product-api.ts
1883
+ async function listProducts(opts) {
1884
+ const request = createRequest();
1885
+ return request(getCustomerServiceUrl(), "/v1/knowledge/products", {
1886
+ method: "GET",
1887
+ query: {
1888
+ customer_agent_config_id: opts.agentConfigId,
1889
+ search: opts.keyword,
1890
+ status: opts.status?.join(","),
1891
+ tags: opts.tags?.length ? JSON.stringify(opts.tags) : void 0,
1892
+ page: opts.page ?? 1,
1893
+ page_size: opts.pageSize ?? 20
1999
1894
  }
2000
1895
  });
2001
1896
  }
2002
-
2003
- // src/client/faq-api.ts
2004
- async function listFaqFiles(opts) {
1897
+ async function getProductDetail(opts) {
2005
1898
  const request = createRequest();
2006
- return request(getCustomerServiceUrl(), "/v1/knowledge/external", {
1899
+ return request(getCustomerServiceUrl(), "/v1/knowledge/product/detail", {
2007
1900
  method: "GET",
2008
1901
  query: {
2009
1902
  customer_agent_config_id: opts.agentConfigId,
2010
- page: opts.page ?? 1,
2011
- page_size: opts.pageSize ?? 20,
2012
- suffix_type: "_faq"
1903
+ db_id: opts.dbId,
1904
+ product_id: opts.productId
2013
1905
  }
2014
1906
  });
2015
1907
  }
2016
- async function saveFaqContent(opts) {
1908
+ async function updateProduct(opts) {
2017
1909
  const request = createRequest();
2018
- const body = {
2019
- chunks_to_delete: opts.chunksToDelete ?? [],
2020
- contents: opts.contents.map((c) => ({
2021
- content: c.content,
2022
- keywords: c.keywords ?? [],
2023
- enable: c.enable ?? true,
2024
- ...c.chunkId !== void 0 ? { chunk_id: c.chunkId } : {}
2025
- })),
2026
- answers: opts.answers
2027
- };
2028
- if (opts.answerGroupId !== void 0) {
1910
+ return request(getCustomerServiceUrl(), "/v1/knowledge/product/update", {
1911
+ method: "POST",
1912
+ body: {
1913
+ data_id: opts.dataId,
1914
+ knowledge_id: opts.knowledgeId,
1915
+ db_id: opts.dbId,
1916
+ update_dict: opts.updateDict
1917
+ }
1918
+ });
1919
+ }
1920
+ async function uploadProductByUrl(opts) {
1921
+ const request = createRequest();
1922
+ return request(getCustomerServiceUrl(), "/v1/knowledge/products/upload", {
1923
+ method: "POST",
1924
+ body: {
1925
+ customer_agent_config_id: opts.agentConfigId,
1926
+ source_type: opts.sourceType ?? "manual",
1927
+ identify: opts.identify ?? true,
1928
+ product_urls: opts.productUrls
1929
+ }
1930
+ });
1931
+ }
1932
+ async function uploadProductData(opts) {
1933
+ const request = createRequest();
1934
+ return request(getCustomerServiceUrl(), "/v1/knowledge/products/upload", {
1935
+ method: "POST",
1936
+ body: {
1937
+ customer_agent_config_id: opts.agentConfigId,
1938
+ source_type: opts.sourceType ?? "manual",
1939
+ identify: opts.identify ?? true,
1940
+ product_items: opts.productItems
1941
+ }
1942
+ });
1943
+ }
1944
+ async function updateSku(opts) {
1945
+ if (!opts.skuId && !opts.sku) {
1946
+ throw new Error("updateSku \u9700\u8981\u63D0\u4F9B sku \u6216 sku_id \u5176\u4E2D\u4E4B\u4E00");
1947
+ }
1948
+ const identifier = opts.skuId ? { sku_id: opts.skuId } : { sku: opts.sku };
1949
+ const request = createRequest();
1950
+ return request(getCustomerServiceUrl(), "/v1/knowledge/sku/update", {
1951
+ method: "POST",
1952
+ body: {
1953
+ ...identifier,
1954
+ customer_agent_config_id: opts.agentConfigId,
1955
+ update_dict: opts.updateDict
1956
+ }
1957
+ });
1958
+ }
1959
+ async function syncTaobaoProducts(opts) {
1960
+ const request = createRequest();
1961
+ return request(getCustomerServiceUrl(), "/v1/authorized-shop/sync-taobao-products", {
1962
+ method: "POST",
1963
+ body: {
1964
+ customer_agent_config_id: opts.agentConfigId,
1965
+ skip_hash_check: opts.skipHashCheck ?? false,
1966
+ sync_type: opts.syncType ?? "full"
1967
+ }
1968
+ });
1969
+ }
1970
+ async function syncSingleTaobaoProduct(opts) {
1971
+ const request = createRequest();
1972
+ return request(getCustomerServiceUrl(), "/v1/authorized-shop/sync-single-product", {
1973
+ method: "POST",
1974
+ body: {
1975
+ customer_agent_config_id: opts.agentConfigId,
1976
+ product_id: opts.productId
1977
+ }
1978
+ });
1979
+ }
1980
+ async function identifyAllProducts(opts) {
1981
+ const request = createRequest();
1982
+ return request(getCustomerServiceUrl(), "/v1/knowledge/products/identify/all", {
1983
+ method: "POST",
1984
+ body: {
1985
+ customer_agent_config_id: opts.agentConfigId
1986
+ }
1987
+ });
1988
+ }
1989
+
1990
+ // src/client/sa-api.ts
1991
+ async function listSituationActions(opts) {
1992
+ const request = createRequest();
1993
+ return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/list", {
1994
+ method: "GET",
1995
+ query: {
1996
+ customer_agent_config_id: opts.agentConfigId,
1997
+ sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
1998
+ event_first_label: opts.firstLabel ?? "",
1999
+ event_second_label: opts.secondLabel ?? "",
2000
+ page: opts.page ?? 1,
2001
+ page_size: opts.pageSize ?? 500
2002
+ }
2003
+ });
2004
+ }
2005
+ async function searchSituationActions(opts) {
2006
+ const request = createRequest();
2007
+ return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/search", {
2008
+ method: "GET",
2009
+ query: { customer_agent_config_id: opts.agentConfigId, keyword: opts.keyword }
2010
+ });
2011
+ }
2012
+ async function createSituationAction(opts) {
2013
+ const request = createRequest();
2014
+ return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/create", {
2015
+ method: "POST",
2016
+ body: {
2017
+ customer_agent_config_id: opts.agentConfigId,
2018
+ sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
2019
+ event_first_label: opts.firstLabel,
2020
+ event_second_label: opts.secondLabel,
2021
+ situation: opts.situation,
2022
+ action: opts.action,
2023
+ transfer_to_human: opts.transferToHuman ?? false
2024
+ }
2025
+ });
2026
+ }
2027
+ async function updateSituationAction(opts) {
2028
+ const request = createRequest();
2029
+ return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/update", {
2030
+ method: "POST",
2031
+ body: {
2032
+ customer_agent_config_id: opts.agentConfigId,
2033
+ situation_action_id: opts.situationActionId,
2034
+ sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
2035
+ event_first_label: opts.firstLabel,
2036
+ event_second_label: opts.secondLabel,
2037
+ situation: opts.situation,
2038
+ action: opts.action,
2039
+ transfer_to_human: opts.transferToHuman ?? false
2040
+ }
2041
+ });
2042
+ }
2043
+ async function deleteSituationAction(opts) {
2044
+ const request = createRequest();
2045
+ return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/delete", {
2046
+ method: "POST",
2047
+ body: {
2048
+ customer_agent_config_id: opts.agentConfigId,
2049
+ situation_action_id: opts.situationActionId,
2050
+ event_first_label: opts.firstLabel,
2051
+ event_second_label: opts.secondLabel
2052
+ }
2053
+ });
2054
+ }
2055
+ async function listSituationActionVersions(opts) {
2056
+ const request = createRequest();
2057
+ return request(
2058
+ getCustomerServiceUrl(),
2059
+ "/v1/knowledge/situation-actions/list/versions",
2060
+ {
2061
+ method: "GET",
2062
+ query: {
2063
+ customer_agent_config_id: opts.agentConfigId,
2064
+ situation_action_id: opts.situationActionId
2065
+ }
2066
+ }
2067
+ );
2068
+ }
2069
+
2070
+ // src/commands/debug-snapshot.ts
2071
+ var SA_PAGE_SIZE = 500;
2072
+ var ACTIVITY_PAGE_SIZE = 100;
2073
+ var PRODUCT_PAGE_SIZE = 100;
2074
+ var PRODUCT_DETAIL_CONCURRENCY = 4;
2075
+ var PERSONALIZATION_SLOTS = [
2076
+ "intent",
2077
+ "general_qa",
2078
+ "recommend",
2079
+ "takeover_rule",
2080
+ "image_rule",
2081
+ "custom_qa"
2082
+ ];
2083
+ var ACTIVITY_FIELDS = [
2084
+ "activity_name",
2085
+ "activity_rule",
2086
+ "participate_condition",
2087
+ "benefit_content",
2088
+ "redeem_desc",
2089
+ "other_info",
2090
+ "qa"
2091
+ ];
2092
+ var PRODUCT_FIELDS = [
2093
+ "\u5546\u54C1\u6807\u9898",
2094
+ "\u5546\u54C1\u54C1\u7C7B",
2095
+ "\u53C2\u6570",
2096
+ "\u5356\u70B9",
2097
+ "\u8865\u5145\u77E5\u8BC6",
2098
+ "\u8F6E\u64AD\u56FE\u8BC6\u522B\u7ED3\u679C",
2099
+ "\u5546\u54C1\u8BE6\u60C5\u9875\u8BC6\u522B\u7ED3\u679C",
2100
+ "\u5173\u8054\u77E5\u8BC6\u5E93\u547D\u4E2D"
2101
+ ];
2102
+ var SKU_FIELDS = ["\u8865\u5145\u77E5\u8BC6", "sku\u56FE\u8BC6\u522B\u7ED3\u679C"];
2103
+ function asRecord(value) {
2104
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
2105
+ }
2106
+ function asArray(value) {
2107
+ return Array.isArray(value) ? value : [];
2108
+ }
2109
+ function toStringId(value) {
2110
+ if (typeof value === "string" && value.length > 0) return value;
2111
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
2112
+ return void 0;
2113
+ }
2114
+ function hasDefined(record, key) {
2115
+ return Object.prototype.hasOwnProperty.call(record, key) && record[key] !== void 0;
2116
+ }
2117
+ function readPageItems(result) {
2118
+ const record = asRecord(result);
2119
+ return {
2120
+ items: asArray(record.items).map(asRecord),
2121
+ total: typeof record.total === "number" ? record.total : void 0
2122
+ };
2123
+ }
2124
+ function isExhausted(fetchedCount, pageItemsCount, pageSize, total) {
2125
+ if (typeof total === "number") return fetchedCount >= total;
2126
+ return pageItemsCount < pageSize;
2127
+ }
2128
+ async function listAllSituationActions(agentConfigId) {
2129
+ const all = [];
2130
+ for (let page = 1; ; page += 1) {
2131
+ const result = await listSituationActions({
2132
+ agentConfigId,
2133
+ page,
2134
+ pageSize: SA_PAGE_SIZE
2135
+ });
2136
+ const { items, total } = readPageItems(result);
2137
+ all.push(...items);
2138
+ if (isExhausted(all.length, items.length, SA_PAGE_SIZE, total)) return all;
2139
+ }
2140
+ }
2141
+ async function listAllActivities(agentConfigId) {
2142
+ const all = [];
2143
+ for (let page = 1; ; page += 1) {
2144
+ const result = await listActivities({
2145
+ customerAgentConfigId: agentConfigId,
2146
+ page,
2147
+ pageSize: ACTIVITY_PAGE_SIZE
2148
+ });
2149
+ const { items, total } = readPageItems(result);
2150
+ all.push(...items);
2151
+ if (isExhausted(all.length, items.length, ACTIVITY_PAGE_SIZE, total)) return all;
2152
+ }
2153
+ }
2154
+ function readProductId(record) {
2155
+ const productInfo = asRecord(record["\u5546\u54C1\u4FE1\u606F"]);
2156
+ return toStringId(record.product_id) ?? toStringId(record["\u5546\u54C1id"]) ?? toStringId(productInfo["\u5546\u54C1id"]) ?? toStringId(record.id);
2157
+ }
2158
+ async function listAllProductIds(agentConfigId) {
2159
+ const productIds = [];
2160
+ const seen = /* @__PURE__ */ new Set();
2161
+ let fetchedCount = 0;
2162
+ for (let page = 1; ; page += 1) {
2163
+ const result = await listProducts({
2164
+ agentConfigId,
2165
+ page,
2166
+ pageSize: PRODUCT_PAGE_SIZE
2167
+ });
2168
+ const { items, total } = readPageItems(result);
2169
+ fetchedCount += items.length;
2170
+ for (const item of items) {
2171
+ const productId = readProductId(item);
2172
+ if (productId && !seen.has(productId)) {
2173
+ seen.add(productId);
2174
+ productIds.push(productId);
2175
+ }
2176
+ }
2177
+ if (isExhausted(fetchedCount, items.length, PRODUCT_PAGE_SIZE, total)) return productIds;
2178
+ }
2179
+ }
2180
+ function buildPersonalization(agent) {
2181
+ const customerConfig = asRecord(agent.customer_config);
2182
+ const personalization = {};
2183
+ for (const slot of PERSONALIZATION_SLOTS) {
2184
+ const source = asRecord(customerConfig[slot]);
2185
+ if (hasDefined(source, "flow_instruction")) {
2186
+ personalization[slot] = { flow_instruction: source.flow_instruction };
2187
+ }
2188
+ }
2189
+ return personalization;
2190
+ }
2191
+ function buildSituationActions(items) {
2192
+ const groups = /* @__PURE__ */ new Map();
2193
+ for (const item of items) {
2194
+ const eventOne = toStringId(item.event_first_label) ?? "";
2195
+ const eventTwo = toStringId(item.event_second_label) ?? "";
2196
+ const key = `${eventOne}__${eventTwo}`;
2197
+ let group = groups.get(key);
2198
+ if (!group) {
2199
+ group = {
2200
+ sa_key: key,
2201
+ event_one: eventOne,
2202
+ event_two: eventTwo,
2203
+ items: []
2204
+ };
2205
+ groups.set(key, group);
2206
+ }
2207
+ const situation = toStringId(item.situation) ?? "";
2208
+ const patchItem = {
2209
+ match: { situation },
2210
+ situation,
2211
+ scene_summary: hasDefined(item, "scene_summary") ? item.scene_summary : situation
2212
+ };
2213
+ if (hasDefined(item, "action")) patchItem.action = item.action;
2214
+ if (hasDefined(item, "transfer_to_human")) {
2215
+ patchItem.transfer_to_human = item.transfer_to_human;
2216
+ }
2217
+ if (hasDefined(item, "react_loop_count")) {
2218
+ patchItem.react_loop_count = item.react_loop_count;
2219
+ }
2220
+ group.items.push(patchItem);
2221
+ }
2222
+ return [...groups.values()];
2223
+ }
2224
+ function buildActivities(items) {
2225
+ return items.flatMap((item) => {
2226
+ const activityId = toStringId(item.activity_id ?? item.id);
2227
+ if (!activityId) return [];
2228
+ const activity = { activity_id: activityId };
2229
+ for (const field of ACTIVITY_FIELDS) {
2230
+ if (hasDefined(item, field)) activity[field] = item[field];
2231
+ }
2232
+ return [activity];
2233
+ });
2234
+ }
2235
+ function buildSkuItems(detail) {
2236
+ const rawSkuItems = asArray(detail.skus).length > 0 ? asArray(detail.skus) : asArray(detail.sku);
2237
+ return rawSkuItems.flatMap((raw) => {
2238
+ const item = asRecord(raw);
2239
+ const sku = toStringId(item.sku ?? item.sku_id);
2240
+ if (!sku) return [];
2241
+ const skuPatch = {
2242
+ match: { sku },
2243
+ sku
2244
+ };
2245
+ for (const field of SKU_FIELDS) {
2246
+ if (hasDefined(item, field)) skuPatch[field] = item[field];
2247
+ }
2248
+ return [skuPatch];
2249
+ });
2250
+ }
2251
+ function readProductField(detail, productInfo, field) {
2252
+ if (hasDefined(detail, field)) return detail[field];
2253
+ if (hasDefined(productInfo, field)) return productInfo[field];
2254
+ return void 0;
2255
+ }
2256
+ function buildProductKnowledgeItem(detail, fallbackProductId) {
2257
+ const productInfo = asRecord(detail["\u5546\u54C1\u4FE1\u606F"]);
2258
+ const productId = readProductId(detail) ?? fallbackProductId;
2259
+ const product = { product_id: productId };
2260
+ for (const field of PRODUCT_FIELDS) {
2261
+ const value = readProductField(detail, productInfo, field);
2262
+ if (value !== void 0) product[field] = value;
2263
+ }
2264
+ product.sku = buildSkuItems(detail);
2265
+ return product;
2266
+ }
2267
+ async function fetchProductDetails(opts) {
2268
+ const details = [];
2269
+ for (let i = 0; i < opts.productIds.length; i += PRODUCT_DETAIL_CONCURRENCY) {
2270
+ const batch = opts.productIds.slice(i, i + PRODUCT_DETAIL_CONCURRENCY);
2271
+ const batchDetails = await Promise.all(
2272
+ batch.map(async (productId) => {
2273
+ const detail = await getProductDetail({
2274
+ agentConfigId: opts.agentConfigId,
2275
+ dbId: opts.dbId,
2276
+ productId
2277
+ });
2278
+ return buildProductKnowledgeItem(asRecord(detail), productId);
2279
+ })
2280
+ );
2281
+ details.push(...batchDetails);
2282
+ }
2283
+ return details;
2284
+ }
2285
+ async function buildDebugDataOverlaySnapshot(opts) {
2286
+ const agent = asRecord(await getAgent(opts.agentConfigId));
2287
+ const productIds = opts.productIds && opts.productIds.length > 0 ? [...new Set(opts.productIds)] : await listAllProductIds(opts.agentConfigId);
2288
+ const dbId = toStringId(agent.database_id);
2289
+ if (productIds.length > 0 && !dbId) {
2290
+ throw new Error("Agent \u8BE6\u60C5\u4E2D\u672A\u627E\u5230 database_id");
2291
+ }
2292
+ const [saItems, activityItems, productKnowledge] = await Promise.all([
2293
+ listAllSituationActions(opts.agentConfigId),
2294
+ listAllActivities(opts.agentConfigId),
2295
+ dbId ? fetchProductDetails({
2296
+ agentConfigId: opts.agentConfigId,
2297
+ dbId,
2298
+ productIds
2299
+ }) : Promise.resolve([])
2300
+ ]);
2301
+ return {
2302
+ version: 1,
2303
+ servhub: {
2304
+ customer_config: buildPersonalization(agent),
2305
+ forbidden_words: asArray(agent.forbidden_words),
2306
+ platform_config: {}
2307
+ },
2308
+ sop: {
2309
+ node_templates: {},
2310
+ sa: buildSituationActions(saItems),
2311
+ activities: buildActivities(activityItems),
2312
+ product_knowledge: productKnowledge
2313
+ }
2314
+ };
2315
+ }
2316
+
2317
+ // src/commands/debug.ts
2318
+ function registerDebugCommand(program2) {
2319
+ const debug = program2.command("debug").description(
2320
+ "Agent \u8C03\u8BD5\u6D4B\u8BD5 \u2014\u2014 \u5411 Agent \u53D1\u9001\u6D4B\u8BD5\u6D88\u606F\u5E76\u83B7\u53D6\u56DE\u590D\uFF0C\u662F\u9A8C\u8BC1 Agent \u56DE\u590D\u8D28\u91CF\u7684\u4E3B\u8981\u624B\u6BB5\u3002\u652F\u6301\u5355\u6761\u6D88\u606F\u548C\u591A\u8F6E\u5BF9\u8BDD\u91CD\u653E"
2321
+ );
2322
+ debug.command("ask").description(
2323
+ "\u5411 Agent \u53D1\u9001\u6D88\u606F\u5E76\u7B49\u5F85\u56DE\u590D\u3002\u8FD4\u56DE { conversation_id, reply: [{ record_id, content, ... }] }\u3002record_id \u53EF\u4F20\u7ED9 debug record \u67E5\u770B\u5185\u90E8\u63A8\u7406\u94FE\u8DEF"
2324
+ ).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").option("--text <message>", "\u53D1\u9001\u7684\u6D88\u606F\u5185\u5BB9\uFF08\u4E0E --messages \u4E92\u65A5\uFF0C\u4E8C\u9009\u4E00\uFF09").option(
2325
+ "--messages <json>",
2326
+ '\u5B8C\u6574\u6D88\u606F\u5217\u8868 JSON \u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF0C\u7528\u4E8E\u91CD\u653E\u591A\u8F6E\u5BF9\u8BDD\uFF08\u4E0E --text \u4E92\u65A5\uFF09\u3002\u63A5\u53D7\u4E24\u79CD\u683C\u5F0F\uFF1A(1) JSON \u6570\u7EC4 [{ match_id, content: { text, image_url? }, timestamp, type: "TEXT", role: "user"|"assistant" }, ...] (2) \u542B msg_list \u5B57\u6BB5\u7684\u5BF9\u8C61 { msg_list: [...] }\uFF08conversation records \u7684\u539F\u59CB\u683C\u5F0F\u53EF\u76F4\u63A5\u4F7F\u7528\uFF09'
2327
+ ).option("--user <name>", "\u6A21\u62DF\u7684\u7528\u6237\u540D\uFF08\u9ED8\u8BA4\u4F7F\u7528\u767B\u5F55\u7528\u6237\u540D\uFF09").option("--url <image_url>", "\u9644\u5E26\u7684\u56FE\u7247 URL\uFF08\u4EC5 --text \u6A21\u5F0F\u6709\u6548\uFF09").option("--conversation <id>", "\u590D\u7528\u5DF2\u6709\u4F1A\u8BDD ID\uFF0C\u7528\u4E8E\u5728\u540C\u4E00\u4E0A\u4E0B\u6587\u4E2D\u7EE7\u7EED\u5BF9\u8BDD").option("--mock <json>", "\u5DE5\u5177\u7ED3\u679C mock JSON \u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF0C\u5F62\u5982 [{ tool_name, result }]").option("--data-overlay <json>", "debug_data_overlay JSON \u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF0C\u7528\u4E8E\u672C\u8F6E debug \u6570\u636E\u8986\u76D6").option("--timeout <seconds>", "\u6700\u5927\u7B49\u5F85\u56DE\u590D\u65F6\u95F4\uFF08\u79D2\uFF09\uFF0C\u590D\u6742 Agent \u5EFA\u8BAE\u8C03\u9AD8", "30").option("--poll-interval <ms>", "\u8F6E\u8BE2\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09", "2000").action(async (opts) => {
2328
+ try {
2329
+ if (!opts.text && !opts.messages) {
2330
+ outputError(1, "\u5FC5\u987B\u6307\u5B9A --text \u6216 --messages \u5176\u4E2D\u4E4B\u4E00");
2331
+ process.exit(1);
2332
+ }
2333
+ const userName = opts.user ?? readCredentials()?.username ?? "cli-user";
2334
+ let conversationId;
2335
+ if (opts.conversation) {
2336
+ conversationId = opts.conversation;
2337
+ } else {
2338
+ const conv = await createDebugConversation({
2339
+ agentConfigId: opts.agent,
2340
+ userName
2341
+ });
2342
+ conversationId = conv.conversation_id;
2343
+ }
2344
+ let msgList;
2345
+ if (opts.messages) {
2346
+ const parsed = parseDataOption(opts.messages);
2347
+ msgList = Array.isArray(parsed) ? parsed : parsed.msg_list;
2348
+ if (!Array.isArray(msgList)) {
2349
+ outputError(1, "--messages \u5FC5\u987B\u662F JSON \u6570\u7EC4\u6216\u5305\u542B msg_list \u5B57\u6BB5\u7684\u5BF9\u8C61");
2350
+ process.exit(1);
2351
+ }
2352
+ }
2353
+ const mock = opts.mock ? parseDataOption(opts.mock) : void 0;
2354
+ const debugDataOverlay = opts.dataOverlay ? parseDataOption(opts.dataOverlay) : void 0;
2355
+ await sendAgentMessage({
2356
+ conversationId,
2357
+ text: opts.text,
2358
+ imageUrl: opts.url,
2359
+ msgList,
2360
+ mock,
2361
+ debugDataOverlay
2362
+ });
2363
+ const agentRecords = await pollAgentReply(conversationId, {
2364
+ timeout: Number(opts.timeout) * 1e3,
2365
+ pollInterval: Number(opts.pollInterval)
2366
+ });
2367
+ formatOutput(
2368
+ {
2369
+ success: true,
2370
+ data: {
2371
+ conversation_id: conversationId,
2372
+ reply: agentRecords
2373
+ }
2374
+ },
2375
+ program2.opts().table
2376
+ );
2377
+ } catch (err) {
2378
+ reportCaughtError(err);
2379
+ process.exit(toExitCode(err));
2380
+ }
2381
+ });
2382
+ debug.command("record").description("\u83B7\u53D6\u67D0\u6761\u56DE\u590D\u7684\u5185\u90E8\u63A8\u7406\u94FE\u8DEF\uFF08flow_info\uFF09\uFF0C\u7528\u4E8E\u8BCA\u65AD Agent \u4E3A\u4F55\u7ED9\u51FA\u7279\u5B9A\u56DE\u590D").argument("<record_id>", "\u56DE\u590D\u8BB0\u5F55 ID\uFF08\u4ECE debug ask \u8FD4\u56DE\u7684 reply[].record_id \u83B7\u53D6\uFF09").option(
2383
+ "--deep",
2384
+ "\u6DF1\u5EA6\u89E3\u6790\uFF1A\u989D\u5916\u8C03\u7528 ai-api \u7684 flow execute_log \u63A5\u53E3\uFF0C\u62C9\u53D6 flow_info.flow_id + task_id \u5BF9\u5E94\u7684\u5B8C\u6574\u6267\u884C\u65E5\u5FD7\uFF08log_url \u5185\u5BB9\uFF09\uFF0C\u7528\u4E8E\u6392\u67E5\u8282\u70B9\u7EA7\u8F93\u5165\u8F93\u51FA",
2385
+ false
2386
+ ).option("--flow-workspace <id>", "flow \u6240\u5728 workspace ID\uFF08--deep \u65F6\u4F7F\u7528\uFF0C\u9ED8\u8BA4\u4F7F\u7528\u5185\u7F6E\u56FA\u5B9A\u503C\uFF09").action(async (recordId, opts) => {
2387
+ try {
2388
+ const data2 = await getRecordDebugInfo(recordId);
2389
+ let deep;
2390
+ if (opts.deep) {
2391
+ const flowInfo = data2.flow_info;
2392
+ const flowId = flowInfo?.flow_id;
2393
+ const taskId = flowInfo?.task_id;
2394
+ if (!flowId || !taskId) {
2395
+ deep = { error: "flow_info \u4E2D\u7F3A\u5C11 flow_id \u6216 task_id\uFF0C\u65E0\u6CD5\u6DF1\u5EA6\u89E3\u6790" };
2396
+ } else {
2397
+ try {
2398
+ deep = await getFlowExecuteLog({
2399
+ flowId,
2400
+ taskId,
2401
+ workspaceId: opts.flowWorkspace
2402
+ });
2403
+ } catch (err) {
2404
+ deep = { error: err.message };
2405
+ }
2406
+ }
2407
+ }
2408
+ formatOutput(
2409
+ { success: true, data: opts.deep ? { ...data2, deep } : data2 },
2410
+ program2.opts().table
2411
+ );
2412
+ } catch (err) {
2413
+ reportCaughtError(err);
2414
+ process.exit(toExitCode(err));
2415
+ }
2416
+ });
2417
+ debug.command("reproduce").description(
2418
+ "\u6839\u636E record_id \u590D\u73B0\u4E00\u6B21 Agent \u56DE\u590D\u3002\u81EA\u52A8\u83B7\u53D6\u5173\u8054\u4F1A\u8BDD\u3001\u622A\u53D6\u4E0A\u4E0B\u6587\u3001\u7528\u539F\u59CB user_name \u521B\u5EFA debug \u4F1A\u8BDD\u5E76\u91CD\u65B0\u53D1\u9001"
2419
+ ).argument("<record_id>", "\u8981\u590D\u73B0\u7684\u56DE\u590D\u8BB0\u5F55 ID").option("--agent <config_id>", "\u4F7F\u7528\u6307\u5B9A Agent \u590D\u73B0\uFF08\u9ED8\u8BA4\u4F7F\u7528\u539F\u59CB Agent\uFF09").option("--timeout <seconds>", "\u6700\u5927\u7B49\u5F85\u56DE\u590D\u65F6\u95F4\uFF08\u79D2\uFF09", "60").option("--poll-interval <ms>", "\u8F6E\u8BE2\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09", "2000").option("--mock <json>", "\u5DE5\u5177\u7ED3\u679C mock JSON \u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF0C\u5F62\u5982 [{ tool_name, result }]").option("--data-overlay <json>", "debug_data_overlay JSON \u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF0C\u7528\u4E8E\u672C\u8F6E debug \u6570\u636E\u8986\u76D6").option("--dry-run", "\u4EC5\u8F93\u51FA\u622A\u65AD\u540E\u7684\u4E0A\u4E0B\u6587 msg_list\uFF0C\u4E0D\u53D1\u9001", false).action(async (recordId, opts) => {
2420
+ try {
2421
+ const relations = await getRecordRelations(recordId);
2422
+ const { conversation, agent_config: agentConfig } = relations;
2423
+ const conversationId = conversation.conversation_id;
2424
+ const agentConfigId = opts.agent ?? agentConfig.config_id;
2425
+ const userName = conversation.user_name ?? "cli-user";
2426
+ const records = await getConversationRecords({
2427
+ conversationId,
2428
+ pageSize: 200,
2429
+ direction: "prev"
2430
+ });
2431
+ const truncated = truncateBeforeRecord(records, recordId);
2432
+ const msgList = recordsToMsgList(truncated);
2433
+ const mock = opts.mock ? parseDataOption(opts.mock) : void 0;
2434
+ const debugDataOverlay = opts.dataOverlay ? parseDataOption(opts.dataOverlay) : void 0;
2435
+ if (opts.dryRun) {
2436
+ formatOutput(
2437
+ {
2438
+ success: true,
2439
+ data: {
2440
+ original_record_id: recordId,
2441
+ agent_config_id: agentConfigId,
2442
+ agent_config_name: agentConfig.config_name,
2443
+ user_name: userName,
2444
+ context_messages_count: msgList.length,
2445
+ msg_list: msgList,
2446
+ mock,
2447
+ debug_data_overlay: debugDataOverlay
2448
+ }
2449
+ },
2450
+ program2.opts().table
2451
+ );
2452
+ return;
2453
+ }
2454
+ const conv = await createDebugConversation({
2455
+ agentConfigId,
2456
+ userName
2457
+ });
2458
+ await sendAgentMessage({
2459
+ conversationId: conv.conversation_id,
2460
+ msgList,
2461
+ mock,
2462
+ debugDataOverlay
2463
+ });
2464
+ const agentRecords = await pollAgentReply(conv.conversation_id, {
2465
+ timeout: Number(opts.timeout) * 1e3,
2466
+ pollInterval: Number(opts.pollInterval),
2467
+ category: "agent_response"
2468
+ });
2469
+ let traceId = null;
2470
+ try {
2471
+ const debugInfo = await getRecordDebugInfo(agentRecords[0].record_id);
2472
+ traceId = debugInfo.trace_id ?? null;
2473
+ } catch {
2474
+ }
2475
+ formatOutput(
2476
+ {
2477
+ success: true,
2478
+ data: {
2479
+ original_record_id: recordId,
2480
+ conversation_id: conv.conversation_id,
2481
+ agent_config_id: agentConfigId,
2482
+ agent_config_name: agentConfig.config_name,
2483
+ user_name: userName,
2484
+ context_messages_count: msgList.length,
2485
+ trace_id: traceId,
2486
+ reply: agentRecords
2487
+ }
2488
+ },
2489
+ program2.opts().table
2490
+ );
2491
+ } catch (err) {
2492
+ reportCaughtError(err);
2493
+ process.exit(toExitCode(err));
2494
+ }
2495
+ });
2496
+ const data = debug.command("data").description("debug \u6570\u636E\u5DE5\u5177");
2497
+ data.command("snapshot").description("\u751F\u6210\u53EF\u76F4\u63A5\u4F20\u7ED9 --data-overlay @file \u7684 debug_data_overlay v1 JSON").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").option("--product-id <id...>", "\u53EA\u5BFC\u51FA\u6307\u5B9A\u5546\u54C1 ID\uFF1B\u4E0D\u4F20\u5219\u5206\u9875\u5BFC\u51FA\u5168\u91CF\u5546\u54C1").action(async (opts) => {
2498
+ try {
2499
+ const snapshot = await buildDebugDataOverlaySnapshot({
2500
+ agentConfigId: opts.agent,
2501
+ productIds: opts.productId
2502
+ });
2503
+ process.stdout.write(`${JSON.stringify(snapshot, null, 2)}
2504
+ `);
2505
+ } catch (err) {
2506
+ reportCaughtError(err);
2507
+ process.exit(toExitCode(err));
2508
+ }
2509
+ });
2510
+ debug.command("trace").description(
2511
+ "\u6839\u636E Langfuse Trace ID \u83B7\u53D6\u5B8C\u6574\u7684 Trace \u8BE6\u60C5\uFF08\u4ECE debug record \u8FD4\u56DE\u7684 flow_info \u4E2D\u63D0\u53D6 traceId\uFF09"
2512
+ ).argument("<trace_id>", "Langfuse Trace ID\uFF08\u4ECE flow_info \u4E2D\u83B7\u53D6\uFF09").option("--env <env>", "langfuse \u73AF\u5883 dev|prod", "prod").action(async (traceId, opts) => {
2513
+ try {
2514
+ if (opts.env !== "dev" && opts.env !== "prod") {
2515
+ outputError(1, "--env \u4EC5\u652F\u6301 dev \u6216 prod");
2516
+ process.exit(1);
2517
+ }
2518
+ const data2 = await getLangfuseTrace(traceId, opts.env);
2519
+ formatOutput({ success: true, data: data2 }, program2.opts().table);
2520
+ } catch (err) {
2521
+ reportCaughtError(err);
2522
+ process.exit(toExitCode(err));
2523
+ }
2524
+ });
2525
+ }
2526
+
2527
+ // src/client/faq-api.ts
2528
+ async function listFaqFiles(opts) {
2529
+ const request = createRequest();
2530
+ return request(getCustomerServiceUrl(), "/v1/knowledge/external", {
2531
+ method: "GET",
2532
+ query: {
2533
+ customer_agent_config_id: opts.agentConfigId,
2534
+ page: opts.page ?? 1,
2535
+ page_size: opts.pageSize ?? 20,
2536
+ suffix_type: "_faq"
2537
+ }
2538
+ });
2539
+ }
2540
+ async function saveFaqContent(opts) {
2541
+ const request = createRequest();
2542
+ const body = {
2543
+ chunks_to_delete: opts.chunksToDelete ?? [],
2544
+ contents: opts.contents.map((c) => ({
2545
+ content: c.content,
2546
+ keywords: c.keywords ?? [],
2547
+ enable: c.enable ?? true,
2548
+ ...c.chunkId !== void 0 ? { chunk_id: c.chunkId } : {}
2549
+ })),
2550
+ answers: opts.answers
2551
+ };
2552
+ if (opts.answerGroupId !== void 0) {
2029
2553
  body.answer_group_id = opts.answerGroupId;
2030
2554
  }
2031
2555
  return request(
@@ -2035,33 +2559,469 @@ async function saveFaqContent(opts) {
2035
2559
  method: "POST",
2036
2560
  body
2037
2561
  }
2038
- );
2562
+ );
2563
+ }
2564
+ async function listFaqContents(opts) {
2565
+ const request = createRequest();
2566
+ return request(
2567
+ getAiApiUrl(),
2568
+ `/mebsuta/api/v1/dataset/${opts.knowledgeId}/faq_contents`,
2569
+ {
2570
+ method: "GET",
2571
+ query: {
2572
+ page_size: opts.pageSize ?? 20,
2573
+ search_words: opts.searchWords,
2574
+ next_group_id: opts.nextGroupId,
2575
+ need_total: opts.needTotal ?? true
2576
+ }
2577
+ }
2578
+ );
2579
+ }
2580
+ async function deleteFaqGroup(opts) {
2581
+ const request = createRequest();
2582
+ return request(
2583
+ getAiApiUrl(),
2584
+ `/mebsuta/api/v1/dataset/${opts.knowledgeId}/faq_contents/${opts.answerGroupId}`,
2585
+ {
2586
+ method: "DELETE"
2587
+ }
2588
+ );
2589
+ }
2590
+
2591
+ // src/client/knowledge-api.ts
2592
+ async function listExternalKnowledge(opts) {
2593
+ const request = createRequest();
2594
+ return request(getCustomerServiceUrl(), "/v1/knowledge/external", {
2595
+ method: "GET",
2596
+ query: {
2597
+ customer_agent_config_id: opts.agentConfigId,
2598
+ page: opts.page ?? 1,
2599
+ page_size: opts.pageSize ?? 20,
2600
+ suffix_type: "_common"
2601
+ }
2602
+ });
2603
+ }
2604
+ async function listKnowledgeContents(opts) {
2605
+ const request = createRequest();
2606
+ return request(getAiApiUrl(), `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents`, {
2607
+ method: "GET",
2608
+ query: {
2609
+ page_size: opts.pageSize ?? 20,
2610
+ need_total: opts.needTotal ?? true,
2611
+ direction: opts.direction ?? "down"
2612
+ }
2613
+ });
2614
+ }
2615
+ async function addKnowledgeContent(opts) {
2616
+ const request = createRequest();
2617
+ const ts = (opts.now ?? Date.now)();
2618
+ const identifier = `temp_${ts}`;
2619
+ const body = {
2620
+ operations: [
2621
+ {
2622
+ action: "add",
2623
+ original_identifier: opts.afterChunkId ?? "0",
2624
+ identifier
2625
+ }
2626
+ ],
2627
+ content_updates: { [identifier]: opts.content },
2628
+ keywords_updates: { [identifier]: opts.keywords ?? [] },
2629
+ extra_info_updates: { [identifier]: { chunk_status: "done" } }
2630
+ };
2631
+ return request(
2632
+ getAiApiUrl(),
2633
+ `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
2634
+ {
2635
+ method: "POST",
2636
+ body
2637
+ }
2638
+ );
2639
+ }
2640
+ async function updateKnowledgeContent(opts) {
2641
+ const request = createRequest();
2642
+ const operation = {
2643
+ action: "update",
2644
+ identifier: opts.chunkId,
2645
+ enable: opts.enable
2646
+ };
2647
+ const contentUpdates = opts.content !== void 0 ? { [opts.chunkId]: opts.content } : {};
2648
+ const keywordsUpdates = opts.keywords !== void 0 ? { [opts.chunkId]: opts.keywords } : {};
2649
+ const extraInfoUpdates = opts.content !== void 0 || opts.keywords !== void 0 ? { [opts.chunkId]: { chunk_status: "done" } } : {};
2650
+ const body = {
2651
+ operations: [operation],
2652
+ content_updates: contentUpdates,
2653
+ keywords_updates: keywordsUpdates,
2654
+ extra_info_updates: extraInfoUpdates
2655
+ };
2656
+ return request(
2657
+ getAiApiUrl(),
2658
+ `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
2659
+ {
2660
+ method: "POST",
2661
+ body
2662
+ }
2663
+ );
2664
+ }
2665
+ async function findKnowledgeChunk(opts) {
2666
+ const result = await listKnowledgeContents({
2667
+ knowledgeId: opts.knowledgeId,
2668
+ pageSize: opts.pageSize ?? 500,
2669
+ needTotal: true,
2670
+ direction: "down"
2671
+ });
2672
+ return result.contents?.find((c) => c.chunk_id === opts.chunkId);
2673
+ }
2674
+ async function deleteKnowledgeContent(opts) {
2675
+ const request = createRequest();
2676
+ const body = {
2677
+ operations: [{ action: "delete", identifier: opts.chunkId }],
2678
+ content_updates: {},
2679
+ keywords_updates: {},
2680
+ extra_info_updates: {}
2681
+ };
2682
+ return request(
2683
+ getAiApiUrl(),
2684
+ `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
2685
+ {
2686
+ method: "POST",
2687
+ body
2688
+ }
2689
+ );
2690
+ }
2691
+
2692
+ // src/client/product-knowledge-binding-api.ts
2693
+ var PATH_PREFIX2 = "/v1/knowledge/product-bindings";
2694
+ async function listProductKnowledgeBindings(opts) {
2695
+ const request = createRequest();
2696
+ return request(getCustomerServiceUrl(), PATH_PREFIX2, {
2697
+ method: "GET",
2698
+ query: {
2699
+ customer_agent_config_id: opts.agentConfigId,
2700
+ product_id: opts.productId,
2701
+ knowledge_type: opts.knowledgeType,
2702
+ file_id: opts.fileId
2703
+ }
2704
+ });
2705
+ }
2706
+ async function replaceProductKnowledgeBindingsByProduct(opts) {
2707
+ const request = createRequest();
2708
+ return request(getCustomerServiceUrl(), `${PATH_PREFIX2}/by-product`, {
2709
+ method: "PUT",
2710
+ body: {
2711
+ customer_agent_config_id: opts.agentConfigId,
2712
+ product_id: opts.productId,
2713
+ bindings: opts.bindings
2714
+ }
2715
+ });
2039
2716
  }
2040
- async function listFaqContents(opts) {
2717
+ async function replaceProductKnowledgeBindingsByFile(opts) {
2041
2718
  const request = createRequest();
2042
- return request(
2043
- getAiApiUrl(),
2044
- `/mebsuta/api/v1/dataset/${opts.knowledgeId}/faq_contents`,
2045
- {
2046
- method: "GET",
2047
- query: {
2048
- page_size: opts.pageSize ?? 20,
2049
- search_words: opts.searchWords,
2050
- next_group_id: opts.nextGroupId,
2051
- need_total: opts.needTotal ?? true
2052
- }
2719
+ return request(getCustomerServiceUrl(), `${PATH_PREFIX2}/by-file`, {
2720
+ method: "PUT",
2721
+ body: {
2722
+ customer_agent_config_id: opts.agentConfigId,
2723
+ knowledge_type: opts.knowledgeType,
2724
+ file_id: opts.fileId,
2725
+ file_name: opts.fileName,
2726
+ partition_id: opts.partitionId,
2727
+ partition_name: opts.partitionName,
2728
+ products: opts.productIds.map((product_id) => ({ product_id }))
2053
2729
  }
2054
- );
2730
+ });
2055
2731
  }
2056
- async function deleteFaqGroup(opts) {
2057
- const request = createRequest();
2058
- return request(
2059
- getAiApiUrl(),
2060
- `/mebsuta/api/v1/dataset/${opts.knowledgeId}/faq_contents/${opts.answerGroupId}`,
2061
- {
2062
- method: "DELETE"
2732
+
2733
+ // src/commands/product-knowledge-binding.ts
2734
+ function parsePositiveInt(value, fieldName) {
2735
+ const n = Number(value);
2736
+ if (!Number.isInteger(n) || n <= 0) {
2737
+ throw new Error(`${fieldName} \u5FC5\u987B\u4E3A\u6B63\u6574\u6570`);
2738
+ }
2739
+ return n;
2740
+ }
2741
+ function parseKnowledgeType(value) {
2742
+ if (value === "qa" || value === "common") return value;
2743
+ throw new Error("--type \u4EC5\u63A5\u53D7 qa | common");
2744
+ }
2745
+ function dedupeStrings(values) {
2746
+ const seen = /* @__PURE__ */ new Set();
2747
+ const result = [];
2748
+ for (const value of values) {
2749
+ const trimmed = String(value || "").trim();
2750
+ if (!trimmed || seen.has(trimmed)) continue;
2751
+ seen.add(trimmed);
2752
+ result.push(trimmed);
2753
+ }
2754
+ return result;
2755
+ }
2756
+ function bindingKey(item) {
2757
+ return `${item.knowledge_type}:${item.file_id}`;
2758
+ }
2759
+ function toBindingInput(item) {
2760
+ return {
2761
+ knowledge_type: item.knowledge_type,
2762
+ file_id: parsePositiveInt(item.file_id, "file_id"),
2763
+ file_name: item.file_name ?? null,
2764
+ partition_id: parsePositiveInt(item.partition_id, "partition_id"),
2765
+ partition_name: item.partition_name ?? null
2766
+ };
2767
+ }
2768
+ function normalizeBindingInput(value) {
2769
+ if (!value || typeof value !== "object") {
2770
+ throw new Error("bindings \u6BCF\u9879\u5FC5\u987B\u662F\u5BF9\u8C61");
2771
+ }
2772
+ const item = value;
2773
+ return {
2774
+ knowledge_type: parseKnowledgeType(String(item.knowledge_type ?? "")),
2775
+ file_id: parsePositiveInt(item.file_id, "file_id"),
2776
+ file_name: item.file_name ?? null,
2777
+ partition_id: parsePositiveInt(item.partition_id, "partition_id"),
2778
+ partition_name: item.partition_name ?? null
2779
+ };
2780
+ }
2781
+ function parseBindingsOption(raw) {
2782
+ const parsed = parseDataOption(raw);
2783
+ if (!Array.isArray(parsed)) {
2784
+ throw new Error("--bindings \u5FC5\u987B\u662F\u6570\u7EC4");
2785
+ }
2786
+ return parsed.map(normalizeBindingInput);
2787
+ }
2788
+ function fileIdOf(item) {
2789
+ return parsePositiveInt(item.knowledge_id ?? item.file_id, "file_id");
2790
+ }
2791
+ function partitionIdOf(item) {
2792
+ return parsePositiveInt(item.partition_id, "partition_id");
2793
+ }
2794
+ function failWithMessage(message) {
2795
+ outputError(1, message);
2796
+ process.exit(1);
2797
+ }
2798
+ async function listFilesByType(knowledgeType, agentConfigId) {
2799
+ const result = knowledgeType === "qa" ? await listFaqFiles({ agentConfigId, page: 1, pageSize: 100 }) : await listExternalKnowledge({ agentConfigId, page: 1, pageSize: 100 });
2800
+ return result.items ?? [];
2801
+ }
2802
+ async function resolveFile(opts) {
2803
+ if (opts.file && (opts.fileId || opts.partitionId)) {
2804
+ throw new Error("--file \u4E0E --file-id/--partition-id \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
2805
+ }
2806
+ if (opts.file) {
2807
+ const files = await listFilesByType(opts.knowledgeType, opts.agentConfigId);
2808
+ const matched = files.filter((item2) => item2.file_name === opts.file);
2809
+ if (matched.length === 0) {
2810
+ failWithMessage(`\u672A\u627E\u5230\u77E5\u8BC6\u5E93\u6587\u4EF6: ${opts.file}`);
2063
2811
  }
2064
- );
2812
+ if (matched.length > 1) {
2813
+ failWithMessage(`\u77E5\u8BC6\u5E93\u6587\u4EF6\u540D\u4E0D\u552F\u4E00: ${opts.file}\uFF0C\u8BF7\u6539\u7528 --file-id/--partition-id`);
2814
+ }
2815
+ const item = matched[0];
2816
+ return {
2817
+ fileId: fileIdOf(item),
2818
+ fileName: item.file_name ?? opts.file,
2819
+ partitionId: partitionIdOf(item),
2820
+ partitionName: item.partition_name ?? null
2821
+ };
2822
+ }
2823
+ if (!opts.fileId || !opts.partitionId) {
2824
+ throw new Error("\u8BF7\u63D0\u4F9B --file \u6216\u540C\u65F6\u63D0\u4F9B --file-id \u4E0E --partition-id");
2825
+ }
2826
+ return {
2827
+ fileId: parsePositiveInt(opts.fileId, "file_id"),
2828
+ fileName: opts.fileName,
2829
+ partitionId: parsePositiveInt(opts.partitionId, "partition_id"),
2830
+ partitionName: opts.partitionName
2831
+ };
2832
+ }
2833
+ async function replaceProductBindings(opts) {
2834
+ return replaceProductKnowledgeBindingsByProduct({
2835
+ agentConfigId: opts.agentConfigId,
2836
+ productId: opts.productId,
2837
+ bindings: opts.bindings
2838
+ });
2839
+ }
2840
+ async function getProductBindingInputs(opts) {
2841
+ const current = await listProductKnowledgeBindings({
2842
+ agentConfigId: opts.agentConfigId,
2843
+ productId: opts.productId
2844
+ });
2845
+ return (current.items ?? []).map(toBindingInput);
2846
+ }
2847
+ async function replaceFileBindings(opts) {
2848
+ return replaceProductKnowledgeBindingsByFile({
2849
+ agentConfigId: opts.agentConfigId,
2850
+ knowledgeType: opts.knowledgeType,
2851
+ fileId: opts.file.fileId,
2852
+ fileName: opts.file.fileName,
2853
+ partitionId: opts.file.partitionId,
2854
+ partitionName: opts.file.partitionName,
2855
+ productIds: opts.productIds
2856
+ });
2857
+ }
2858
+ async function getFileProductIds(opts) {
2859
+ const current = await listProductKnowledgeBindings({
2860
+ agentConfigId: opts.agentConfigId,
2861
+ knowledgeType: opts.knowledgeType,
2862
+ fileId: opts.fileId
2863
+ });
2864
+ return dedupeStrings((current.items ?? []).map((item) => item.product_id));
2865
+ }
2866
+ function handleError(err) {
2867
+ reportCaughtError(err);
2868
+ process.exit(toExitCode(err));
2869
+ }
2870
+ function registerProductRelatedKnowledgeCommand(product, program2) {
2871
+ const related = product.command("related-knowledge").description("\u5546\u54C1\u8BE6\u60C5\u5173\u8054\u77E5\u8BC6\u5E93\u6587\u4EF6\u7BA1\u7406\uFF1Alist / add / remove / set");
2872
+ related.command("list").description("\u5217\u51FA\u6307\u5B9A\u5546\u54C1\u7ED1\u5B9A\u7684 QA / \u6269\u5C55\u77E5\u8BC6\u5E93\u6587\u4EF6").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID").requiredOption("--product-id <product_id>", "\u5546\u54C1 ID").action(async (opts) => {
2873
+ try {
2874
+ const data = await listProductKnowledgeBindings({
2875
+ agentConfigId: opts.agent,
2876
+ productId: opts.productId
2877
+ });
2878
+ formatOutput({ success: true, data }, program2.opts().table);
2879
+ } catch (err) {
2880
+ handleError(err);
2881
+ }
2882
+ });
2883
+ related.command("add").description(
2884
+ "\u7ED9\u5546\u54C1\u8FFD\u52A0\u4E00\u4E2A\u5173\u8054\u77E5\u8BC6\u5E93\u6587\u4EF6\u3002\u652F\u6301 --file \u7CBE\u786E\u5339\u914D\uFF0C\u6216\u663E\u5F0F\u4F20 --file-id + --partition-id"
2885
+ ).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID").requiredOption("--product-id <product_id>", "\u5546\u54C1 ID").requiredOption("--type <qa|common>", "\u77E5\u8BC6\u5E93\u7C7B\u578B\uFF1Aqa \u6216 common").option("--file <exact_name>", "\u77E5\u8BC6\u5E93\u6587\u4EF6\u540D\uFF0C\u7CBE\u786E\u5339\u914D").option("--file-id <id>", "\u77E5\u8BC6\u5E93\u6587\u4EF6 ID").option("--file-name <name>", "\u77E5\u8BC6\u5E93\u6587\u4EF6\u540D\u5FEB\u7167").option("--partition-id <id>", "\u77E5\u8BC6\u5E93\u5206\u533A ID").option("--partition-name <name>", "\u77E5\u8BC6\u5E93\u5206\u533A\u540D\u5FEB\u7167").action(async (opts) => {
2886
+ try {
2887
+ const knowledgeType = parseKnowledgeType(opts.type);
2888
+ const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
2889
+ const current = await getProductBindingInputs({
2890
+ agentConfigId: opts.agent,
2891
+ productId: opts.productId
2892
+ });
2893
+ const byKey = new Map(current.map((item) => [bindingKey(item), item]));
2894
+ byKey.set(bindingKey({ knowledge_type: knowledgeType, file_id: file.fileId }), {
2895
+ knowledge_type: knowledgeType,
2896
+ file_id: file.fileId,
2897
+ file_name: file.fileName ?? null,
2898
+ partition_id: file.partitionId,
2899
+ partition_name: file.partitionName ?? null
2900
+ });
2901
+ const data = await replaceProductBindings({
2902
+ agentConfigId: opts.agent,
2903
+ productId: opts.productId,
2904
+ bindings: Array.from(byKey.values())
2905
+ });
2906
+ formatOutput({ success: true, data }, program2.opts().table);
2907
+ } catch (err) {
2908
+ handleError(err);
2909
+ }
2910
+ });
2911
+ related.command("remove").description("\u79FB\u9664\u5546\u54C1\u7ED1\u5B9A\u7684\u4E00\u4E2A\u77E5\u8BC6\u5E93\u6587\u4EF6\uFF1B\u76EE\u6807\u4E0D\u5B58\u5728\u65F6\u4FDD\u6301\u5E42\u7B49\u6210\u529F").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID").requiredOption("--product-id <product_id>", "\u5546\u54C1 ID").requiredOption("--type <qa|common>", "\u77E5\u8BC6\u5E93\u7C7B\u578B\uFF1Aqa \u6216 common").requiredOption("--file-id <id>", "\u77E5\u8BC6\u5E93\u6587\u4EF6 ID").action(async (opts) => {
2912
+ try {
2913
+ const knowledgeType = parseKnowledgeType(opts.type);
2914
+ const fileId = parsePositiveInt(opts.fileId, "file_id");
2915
+ const current = await getProductBindingInputs({
2916
+ agentConfigId: opts.agent,
2917
+ productId: opts.productId
2918
+ });
2919
+ const next = current.filter(
2920
+ (item) => !(item.knowledge_type === knowledgeType && item.file_id === fileId)
2921
+ );
2922
+ const data = await replaceProductBindings({
2923
+ agentConfigId: opts.agent,
2924
+ productId: opts.productId,
2925
+ bindings: next
2926
+ });
2927
+ formatOutput({ success: true, data }, program2.opts().table);
2928
+ } catch (err) {
2929
+ handleError(err);
2930
+ }
2931
+ });
2932
+ related.command("set").description("\u8986\u76D6\u6307\u5B9A\u5546\u54C1\u7684\u5168\u90E8\u5173\u8054\u77E5\u8BC6\u5E93\u6587\u4EF6\u3002--bindings \u652F\u6301 JSON \u6216 @file").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID").requiredOption("--product-id <product_id>", "\u5546\u54C1 ID").requiredOption("--bindings <json>", "\u7ED1\u5B9A\u6570\u7EC4 JSON \u6216 @\u6587\u4EF6\u8DEF\u5F84").action(async (opts) => {
2933
+ try {
2934
+ const bindings = parseBindingsOption(opts.bindings);
2935
+ const data = await replaceProductBindings({
2936
+ agentConfigId: opts.agent,
2937
+ productId: opts.productId,
2938
+ bindings
2939
+ });
2940
+ formatOutput({ success: true, data }, program2.opts().table);
2941
+ } catch (err) {
2942
+ handleError(err);
2943
+ }
2944
+ });
2945
+ }
2946
+ function registerKnowledgeFileBindProductsCommand(parent, program2, kind) {
2947
+ const knowledgeType = kind === "faq" ? "qa" : "common";
2948
+ const bind = parent.command("bind-products").description("\u77E5\u8BC6\u5E93\u6587\u4EF6\u7ED1\u5B9A\u5546\u54C1\u7BA1\u7406\uFF1Alist / add / remove / set");
2949
+ function addFileOptions(command) {
2950
+ return command.requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID").option("--file <exact_name>", "\u77E5\u8BC6\u5E93\u6587\u4EF6\u540D\uFF0C\u7CBE\u786E\u5339\u914D").option("--file-id <id>", "\u77E5\u8BC6\u5E93\u6587\u4EF6 ID").option("--file-name <name>", "\u77E5\u8BC6\u5E93\u6587\u4EF6\u540D\u5FEB\u7167").option("--partition-id <id>", "\u77E5\u8BC6\u5E93\u5206\u533A ID").option("--partition-name <name>", "\u77E5\u8BC6\u5E93\u5206\u533A\u540D\u5FEB\u7167");
2951
+ }
2952
+ bind.command("list").description("\u5217\u51FA\u6307\u5B9A\u77E5\u8BC6\u5E93\u6587\u4EF6\u7ED1\u5B9A\u7684\u5546\u54C1").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID").option("--file <exact_name>", "\u77E5\u8BC6\u5E93\u6587\u4EF6\u540D\uFF0C\u7CBE\u786E\u5339\u914D").option("--file-id <id>", "\u77E5\u8BC6\u5E93\u6587\u4EF6 ID").option("--file-name <name>", "\u77E5\u8BC6\u5E93\u6587\u4EF6\u540D\u5FEB\u7167").option("--partition-id <id>", "\u77E5\u8BC6\u5E93\u5206\u533A ID").option("--partition-name <name>", "\u77E5\u8BC6\u5E93\u5206\u533A\u540D\u5FEB\u7167").action(async (opts) => {
2953
+ try {
2954
+ const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
2955
+ const data = await listProductKnowledgeBindings({
2956
+ agentConfigId: opts.agent,
2957
+ knowledgeType,
2958
+ fileId: file.fileId
2959
+ });
2960
+ formatOutput({ success: true, data }, program2.opts().table);
2961
+ } catch (err) {
2962
+ handleError(err);
2963
+ }
2964
+ });
2965
+ addFileOptions(
2966
+ bind.command("add").description("\u7ED9\u77E5\u8BC6\u5E93\u6587\u4EF6\u8FFD\u52A0\u7ED1\u5B9A\u5546\u54C1\uFF1B\u5DF2\u7ED1\u5B9A\u5546\u54C1\u4F1A\u81EA\u52A8\u53BB\u91CD").requiredOption("--product-id <id...>", "\u5546\u54C1 ID\uFF0C\u53EF\u4F20\u591A\u4E2A")
2967
+ ).action(async (opts) => {
2968
+ try {
2969
+ const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
2970
+ const currentIds = await getFileProductIds({
2971
+ agentConfigId: opts.agent,
2972
+ knowledgeType,
2973
+ fileId: file.fileId
2974
+ });
2975
+ const productIds = dedupeStrings([...currentIds, ...opts.productId ?? []]);
2976
+ const data = await replaceFileBindings({
2977
+ agentConfigId: opts.agent,
2978
+ knowledgeType,
2979
+ file,
2980
+ productIds
2981
+ });
2982
+ formatOutput({ success: true, data }, program2.opts().table);
2983
+ } catch (err) {
2984
+ handleError(err);
2985
+ }
2986
+ });
2987
+ addFileOptions(
2988
+ bind.command("remove").description("\u4ECE\u77E5\u8BC6\u5E93\u6587\u4EF6\u79FB\u9664\u7ED1\u5B9A\u5546\u54C1\uFF1B\u76EE\u6807\u4E0D\u5B58\u5728\u65F6\u4FDD\u6301\u5E42\u7B49\u6210\u529F").requiredOption("--product-id <id...>", "\u5546\u54C1 ID\uFF0C\u53EF\u4F20\u591A\u4E2A")
2989
+ ).action(async (opts) => {
2990
+ try {
2991
+ const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
2992
+ const removing = new Set(dedupeStrings(opts.productId ?? []));
2993
+ const currentIds = await getFileProductIds({
2994
+ agentConfigId: opts.agent,
2995
+ knowledgeType,
2996
+ fileId: file.fileId
2997
+ });
2998
+ const data = await replaceFileBindings({
2999
+ agentConfigId: opts.agent,
3000
+ knowledgeType,
3001
+ file,
3002
+ productIds: currentIds.filter((productId) => !removing.has(productId))
3003
+ });
3004
+ formatOutput({ success: true, data }, program2.opts().table);
3005
+ } catch (err) {
3006
+ handleError(err);
3007
+ }
3008
+ });
3009
+ addFileOptions(
3010
+ bind.command("set").description("\u8986\u76D6\u77E5\u8BC6\u5E93\u6587\u4EF6\u7ED1\u5B9A\u7684\u5168\u90E8\u5546\u54C1").requiredOption("--product-id <id...>", "\u5546\u54C1 ID\uFF0C\u53EF\u4F20\u591A\u4E2A")
3011
+ ).action(async (opts) => {
3012
+ try {
3013
+ const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
3014
+ const data = await replaceFileBindings({
3015
+ agentConfigId: opts.agent,
3016
+ knowledgeType,
3017
+ file,
3018
+ productIds: dedupeStrings(opts.productId ?? [])
3019
+ });
3020
+ formatOutput({ success: true, data }, program2.opts().table);
3021
+ } catch (err) {
3022
+ handleError(err);
3023
+ }
3024
+ });
2065
3025
  }
2066
3026
 
2067
3027
  // src/commands/faq.ts
@@ -2196,6 +3156,7 @@ function registerFaqCommand(program2) {
2196
3156
  process.exit(toExitCode(err));
2197
3157
  }
2198
3158
  });
3159
+ registerKnowledgeFileBindProductsCommand(faq, program2, "faq");
2199
3160
  }
2200
3161
 
2201
3162
  // src/client/issue-api.ts
@@ -2261,11 +3222,9 @@ async function getIssueStats(opts) {
2261
3222
  const query = {};
2262
3223
  if (opts.dateStart) query.date_start = opts.dateStart;
2263
3224
  if (opts.dateEnd) query.date_end = opts.dateEnd;
2264
- const result = await request(getCustomerAgentUrl(), "/api/issues/stats", {
3225
+ const result = await request(getCsAdminUrl(), "/api/issues/stats", {
2265
3226
  method: "GET",
2266
- query,
2267
- headers: buildCookieHeaders(),
2268
- skipAuth: true
3227
+ query
2269
3228
  });
2270
3229
  return result.data ?? result;
2271
3230
  }
@@ -2926,148 +3885,45 @@ function registerIssueCommand(program2) {
2926
3885
  try {
2927
3886
  const data = await listIssueComments(issueId);
2928
3887
  formatOutput({ success: true, data }, program2.opts().table);
2929
- } catch (err) {
2930
- reportCaughtError(err);
2931
- process.exit(toExitCode(err));
2932
- }
2933
- });
2934
- comment.command("add").description("\u6DFB\u52A0\u8BC4\u8BBA").argument("<issue_id>", "\u5DE5\u5355 ID").requiredOption("--content <text>", "\u8BC4\u8BBA\u5185\u5BB9").action(async (issueId, opts) => {
2935
- try {
2936
- const data = await addIssueComment(issueId, opts.content);
2937
- formatOutput({ success: true, data }, program2.opts().table);
2938
- } catch (err) {
2939
- reportCaughtError(err);
2940
- process.exit(toExitCode(err));
2941
- }
2942
- });
2943
- }
2944
- async function resolveSessionsForIssues(issues, workspaceId) {
2945
- const out = [];
2946
- for (let i = 0; i < issues.length; i++) {
2947
- const it = issues[i];
2948
- let conversationId;
2949
- if (it.conversation_id) {
2950
- conversationId = it.conversation_id;
2951
- } else if (it.user_name) {
2952
- try {
2953
- conversationId = await resolveSession({ userName: it.user_name, workspaceId });
2954
- } catch (err) {
2955
- const msg = err instanceof Error ? err.message : String(err);
2956
- throw new Error(`issues[${i}] \u53CD\u67E5\u4F1A\u8BDD\u5931\u8D25\uFF1A${msg}`);
2957
- }
2958
- } else {
2959
- throw new Error(`issues[${i}] \u65E2\u65E0 conversation_id \u4E5F\u65E0 user_name`);
2960
- }
2961
- out.push({ issue: it, conversationId });
2962
- }
2963
- return out;
2964
- }
2965
-
2966
- // src/commands/knowledge.ts
2967
- import fs8 from "fs";
2968
-
2969
- // src/client/knowledge-api.ts
2970
- async function listExternalKnowledge(opts) {
2971
- const request = createRequest();
2972
- return request(getCustomerServiceUrl(), "/v1/knowledge/external", {
2973
- method: "GET",
2974
- query: {
2975
- customer_agent_config_id: opts.agentConfigId,
2976
- page: opts.page ?? 1,
2977
- page_size: opts.pageSize ?? 20,
2978
- suffix_type: "_common"
2979
- }
2980
- });
2981
- }
2982
- async function listKnowledgeContents(opts) {
2983
- const request = createRequest();
2984
- return request(getAiApiUrl(), `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents`, {
2985
- method: "GET",
2986
- query: {
2987
- page_size: opts.pageSize ?? 20,
2988
- need_total: opts.needTotal ?? true,
2989
- direction: opts.direction ?? "down"
2990
- }
2991
- });
2992
- }
2993
- async function addKnowledgeContent(opts) {
2994
- const request = createRequest();
2995
- const ts = (opts.now ?? Date.now)();
2996
- const identifier = `temp_${ts}`;
2997
- const body = {
2998
- operations: [
2999
- {
3000
- action: "add",
3001
- original_identifier: opts.afterChunkId ?? "0",
3002
- identifier
3003
- }
3004
- ],
3005
- content_updates: { [identifier]: opts.content },
3006
- keywords_updates: { [identifier]: opts.keywords ?? [] },
3007
- extra_info_updates: { [identifier]: { chunk_status: "done" } }
3008
- };
3009
- return request(
3010
- getAiApiUrl(),
3011
- `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
3012
- {
3013
- method: "POST",
3014
- body
3015
- }
3016
- );
3017
- }
3018
- async function updateKnowledgeContent(opts) {
3019
- const request = createRequest();
3020
- const operation = {
3021
- action: "update",
3022
- identifier: opts.chunkId,
3023
- enable: opts.enable
3024
- };
3025
- const contentUpdates = opts.content !== void 0 ? { [opts.chunkId]: opts.content } : {};
3026
- const keywordsUpdates = opts.keywords !== void 0 ? { [opts.chunkId]: opts.keywords } : {};
3027
- const extraInfoUpdates = opts.content !== void 0 || opts.keywords !== void 0 ? { [opts.chunkId]: { chunk_status: "done" } } : {};
3028
- const body = {
3029
- operations: [operation],
3030
- content_updates: contentUpdates,
3031
- keywords_updates: keywordsUpdates,
3032
- extra_info_updates: extraInfoUpdates
3033
- };
3034
- return request(
3035
- getAiApiUrl(),
3036
- `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
3037
- {
3038
- method: "POST",
3039
- body
3888
+ } catch (err) {
3889
+ reportCaughtError(err);
3890
+ process.exit(toExitCode(err));
3891
+ }
3892
+ });
3893
+ comment.command("add").description("\u6DFB\u52A0\u8BC4\u8BBA").argument("<issue_id>", "\u5DE5\u5355 ID").requiredOption("--content <text>", "\u8BC4\u8BBA\u5185\u5BB9").action(async (issueId, opts) => {
3894
+ try {
3895
+ const data = await addIssueComment(issueId, opts.content);
3896
+ formatOutput({ success: true, data }, program2.opts().table);
3897
+ } catch (err) {
3898
+ reportCaughtError(err);
3899
+ process.exit(toExitCode(err));
3040
3900
  }
3041
- );
3042
- }
3043
- async function findKnowledgeChunk(opts) {
3044
- const result = await listKnowledgeContents({
3045
- knowledgeId: opts.knowledgeId,
3046
- pageSize: opts.pageSize ?? 500,
3047
- needTotal: true,
3048
- direction: "down"
3049
3901
  });
3050
- return result.contents?.find((c) => c.chunk_id === opts.chunkId);
3051
3902
  }
3052
- async function deleteKnowledgeContent(opts) {
3053
- const request = createRequest();
3054
- const body = {
3055
- operations: [{ action: "delete", identifier: opts.chunkId }],
3056
- content_updates: {},
3057
- keywords_updates: {},
3058
- extra_info_updates: {}
3059
- };
3060
- return request(
3061
- getAiApiUrl(),
3062
- `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
3063
- {
3064
- method: "POST",
3065
- body
3903
+ async function resolveSessionsForIssues(issues, workspaceId) {
3904
+ const out = [];
3905
+ for (let i = 0; i < issues.length; i++) {
3906
+ const it = issues[i];
3907
+ let conversationId;
3908
+ if (it.conversation_id) {
3909
+ conversationId = it.conversation_id;
3910
+ } else if (it.user_name) {
3911
+ try {
3912
+ conversationId = await resolveSession({ userName: it.user_name, workspaceId });
3913
+ } catch (err) {
3914
+ const msg = err instanceof Error ? err.message : String(err);
3915
+ throw new Error(`issues[${i}] \u53CD\u67E5\u4F1A\u8BDD\u5931\u8D25\uFF1A${msg}`);
3916
+ }
3917
+ } else {
3918
+ throw new Error(`issues[${i}] \u65E2\u65E0 conversation_id \u4E5F\u65E0 user_name`);
3066
3919
  }
3067
- );
3920
+ out.push({ issue: it, conversationId });
3921
+ }
3922
+ return out;
3068
3923
  }
3069
3924
 
3070
3925
  // src/commands/knowledge.ts
3926
+ import fs8 from "fs";
3071
3927
  function readContentArg(value) {
3072
3928
  if (value.startsWith("@")) {
3073
3929
  return fs8.readFileSync(value.slice(1), "utf-8");
@@ -3203,6 +4059,7 @@ function registerKnowledgeCommand(program2) {
3203
4059
  process.exit(toExitCode(err));
3204
4060
  }
3205
4061
  });
4062
+ registerKnowledgeFileBindProductsCommand(knowledge, program2, "common");
3206
4063
  }
3207
4064
 
3208
4065
  // src/client/monitor-api.ts
@@ -4136,7 +4993,7 @@ function registerOpsAgentCommand(program2) {
4136
4993
  }
4137
4994
 
4138
4995
  // src/client/operations-record-api.ts
4139
- var PATH_PREFIX2 = "/v1/agent_operations_records";
4996
+ var PATH_PREFIX3 = "/v1/agent_operations_records";
4140
4997
  async function listOperationsRecords(opts) {
4141
4998
  const request = createRequest();
4142
4999
  const query = {};
@@ -4144,34 +5001,34 @@ async function listOperationsRecords(opts) {
4144
5001
  if (opts.agentId) query.agent_id = opts.agentId;
4145
5002
  if (opts.page) query.page = opts.page;
4146
5003
  if (opts.pageSize) query.page_size = opts.pageSize;
4147
- return request(getCustomerServiceUrl(), PATH_PREFIX2, {
5004
+ return request(getCustomerServiceUrl(), PATH_PREFIX3, {
4148
5005
  method: "GET",
4149
5006
  query
4150
5007
  });
4151
5008
  }
4152
5009
  async function getOperationsRecord(recordId) {
4153
5010
  const request = createRequest();
4154
- return request(getCustomerServiceUrl(), `${PATH_PREFIX2}/${recordId}`, {
5011
+ return request(getCustomerServiceUrl(), `${PATH_PREFIX3}/${recordId}`, {
4155
5012
  method: "GET"
4156
5013
  });
4157
5014
  }
4158
5015
  async function createOperationsRecord(data) {
4159
5016
  const request = createRequest();
4160
- return request(getCustomerServiceUrl(), PATH_PREFIX2, {
5017
+ return request(getCustomerServiceUrl(), PATH_PREFIX3, {
4161
5018
  method: "POST",
4162
5019
  body: data
4163
5020
  });
4164
5021
  }
4165
5022
  async function updateOperationsRecord(recordId, data) {
4166
5023
  const request = createRequest();
4167
- return request(getCustomerServiceUrl(), `${PATH_PREFIX2}/${recordId}`, {
5024
+ return request(getCustomerServiceUrl(), `${PATH_PREFIX3}/${recordId}`, {
4168
5025
  method: "PUT",
4169
5026
  body: data
4170
5027
  });
4171
5028
  }
4172
5029
  async function deleteOperationsRecord(recordId) {
4173
5030
  const request = createRequest();
4174
- return request(getCustomerServiceUrl(), `${PATH_PREFIX2}/${recordId}`, {
5031
+ return request(getCustomerServiceUrl(), `${PATH_PREFIX3}/${recordId}`, {
4175
5032
  method: "DELETE"
4176
5033
  });
4177
5034
  }
@@ -4249,114 +5106,6 @@ function registerOperationsRecordCommand(program2) {
4249
5106
  });
4250
5107
  }
4251
5108
 
4252
- // src/client/product-api.ts
4253
- async function listProducts(opts) {
4254
- const request = createRequest();
4255
- return request(getCustomerServiceUrl(), "/v1/knowledge/products", {
4256
- method: "GET",
4257
- query: {
4258
- customer_agent_config_id: opts.agentConfigId,
4259
- search: opts.keyword,
4260
- status: opts.status?.join(","),
4261
- tags: opts.tags?.length ? JSON.stringify(opts.tags) : void 0,
4262
- page: opts.page ?? 1,
4263
- page_size: opts.pageSize ?? 20
4264
- }
4265
- });
4266
- }
4267
- async function getProductDetail(opts) {
4268
- const request = createRequest();
4269
- return request(getCustomerServiceUrl(), "/v1/knowledge/product/detail", {
4270
- method: "GET",
4271
- query: {
4272
- customer_agent_config_id: opts.agentConfigId,
4273
- db_id: opts.dbId,
4274
- product_id: opts.productId
4275
- }
4276
- });
4277
- }
4278
- async function updateProduct(opts) {
4279
- const request = createRequest();
4280
- return request(getCustomerServiceUrl(), "/v1/knowledge/product/update", {
4281
- method: "POST",
4282
- body: {
4283
- data_id: opts.dataId,
4284
- knowledge_id: opts.knowledgeId,
4285
- db_id: opts.dbId,
4286
- update_dict: opts.updateDict
4287
- }
4288
- });
4289
- }
4290
- async function uploadProductByUrl(opts) {
4291
- const request = createRequest();
4292
- return request(getCustomerServiceUrl(), "/v1/knowledge/products/upload", {
4293
- method: "POST",
4294
- body: {
4295
- customer_agent_config_id: opts.agentConfigId,
4296
- source_type: opts.sourceType ?? "manual",
4297
- identify: opts.identify ?? true,
4298
- product_urls: opts.productUrls
4299
- }
4300
- });
4301
- }
4302
- async function uploadProductData(opts) {
4303
- const request = createRequest();
4304
- return request(getCustomerServiceUrl(), "/v1/knowledge/products/upload", {
4305
- method: "POST",
4306
- body: {
4307
- customer_agent_config_id: opts.agentConfigId,
4308
- source_type: opts.sourceType ?? "manual",
4309
- identify: opts.identify ?? true,
4310
- product_items: opts.productItems
4311
- }
4312
- });
4313
- }
4314
- async function updateSku(opts) {
4315
- if (!opts.skuId && !opts.sku) {
4316
- throw new Error("updateSku \u9700\u8981\u63D0\u4F9B sku \u6216 sku_id \u5176\u4E2D\u4E4B\u4E00");
4317
- }
4318
- const identifier = opts.skuId ? { sku_id: opts.skuId } : { sku: opts.sku };
4319
- const request = createRequest();
4320
- return request(getCustomerServiceUrl(), "/v1/knowledge/sku/update", {
4321
- method: "POST",
4322
- body: {
4323
- ...identifier,
4324
- customer_agent_config_id: opts.agentConfigId,
4325
- update_dict: opts.updateDict
4326
- }
4327
- });
4328
- }
4329
- async function syncTaobaoProducts(opts) {
4330
- const request = createRequest();
4331
- return request(getCustomerServiceUrl(), "/v1/authorized-shop/sync-taobao-products", {
4332
- method: "POST",
4333
- body: {
4334
- customer_agent_config_id: opts.agentConfigId,
4335
- skip_hash_check: opts.skipHashCheck ?? false,
4336
- sync_type: opts.syncType ?? "full"
4337
- }
4338
- });
4339
- }
4340
- async function syncSingleTaobaoProduct(opts) {
4341
- const request = createRequest();
4342
- return request(getCustomerServiceUrl(), "/v1/authorized-shop/sync-single-product", {
4343
- method: "POST",
4344
- body: {
4345
- customer_agent_config_id: opts.agentConfigId,
4346
- product_id: opts.productId
4347
- }
4348
- });
4349
- }
4350
- async function identifyAllProducts(opts) {
4351
- const request = createRequest();
4352
- return request(getCustomerServiceUrl(), "/v1/knowledge/products/identify/all", {
4353
- method: "POST",
4354
- body: {
4355
- customer_agent_config_id: opts.agentConfigId
4356
- }
4357
- });
4358
- }
4359
-
4360
5109
  // src/commands/product.ts
4361
5110
  async function getDbId(agentConfigId) {
4362
5111
  const agent = await getAgent(agentConfigId);
@@ -4366,12 +5115,20 @@ async function getDbId(agentConfigId) {
4366
5115
  return agent.database_id;
4367
5116
  }
4368
5117
  async function findProduct(agentConfigId, productId) {
4369
- const result = await listProducts({ agentConfigId, page: 1, pageSize: 100 });
4370
- const matched = result.items?.find((p) => p.product_id === productId);
4371
- if (!matched) {
4372
- throw new Error(`\u672A\u627E\u5230\u5546\u54C1 product_id=${productId}`);
5118
+ const pageSize = 100;
5119
+ for (let page = 1; ; page += 1) {
5120
+ const result = await listProducts({ agentConfigId, page, pageSize });
5121
+ const items = result.items ?? [];
5122
+ const matched = items.find((p) => p.product_id === productId);
5123
+ if (matched) {
5124
+ return matched;
5125
+ }
5126
+ const fetched = page * pageSize;
5127
+ const exhausted = items.length < pageSize || typeof result.total === "number" && fetched >= result.total;
5128
+ if (exhausted) {
5129
+ throw new Error(`\u672A\u627E\u5230\u5546\u54C1 product_id=${productId}`);
5130
+ }
4373
5131
  }
4374
- return matched;
4375
5132
  }
4376
5133
  function registerProductCommand(program2) {
4377
5134
  const product = program2.command("product").description(
@@ -4558,10 +5315,11 @@ function registerProductCommand(program2) {
4558
5315
  process.exit(toExitCode(err));
4559
5316
  }
4560
5317
  });
5318
+ registerProductRelatedKnowledgeCommand(product, program2);
4561
5319
  }
4562
5320
 
4563
5321
  // src/client/repair-record-api.ts
4564
- var PATH_PREFIX3 = "/api/repair-records";
5322
+ var PATH_PREFIX4 = "/api/repair-records";
4565
5323
  async function listRepairRecords(opts) {
4566
5324
  const request = createRequest();
4567
5325
  const query = {};
@@ -4570,21 +5328,21 @@ async function listRepairRecords(opts) {
4570
5328
  if (opts.workspaceId) query.workspace_id = opts.workspaceId;
4571
5329
  if (opts.page) query.page = opts.page;
4572
5330
  if (opts.pageSize) query.page_size = opts.pageSize;
4573
- return request(getCsAdminUrl(), PATH_PREFIX3, {
5331
+ return request(getCsAdminUrl(), PATH_PREFIX4, {
4574
5332
  method: "GET",
4575
5333
  query
4576
5334
  });
4577
5335
  }
4578
5336
  async function createRepairRecord(data) {
4579
5337
  const request = createRequest();
4580
- return request(getCsAdminUrl(), PATH_PREFIX3, {
5338
+ return request(getCsAdminUrl(), PATH_PREFIX4, {
4581
5339
  method: "POST",
4582
5340
  body: data
4583
5341
  });
4584
5342
  }
4585
5343
  async function updateRepairRecord(recordId, data) {
4586
5344
  const request = createRequest();
4587
- return request(getCsAdminUrl(), `${PATH_PREFIX3}/${recordId}`, {
5345
+ return request(getCsAdminUrl(), `${PATH_PREFIX4}/${recordId}`, {
4588
5346
  method: "PUT",
4589
5347
  body: data
4590
5348
  });
@@ -4660,86 +5418,6 @@ function registerRepairRecordCommand(program2) {
4660
5418
  });
4661
5419
  }
4662
5420
 
4663
- // src/client/sa-api.ts
4664
- async function listSituationActions(opts) {
4665
- const request = createRequest();
4666
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/list", {
4667
- method: "GET",
4668
- query: {
4669
- customer_agent_config_id: opts.agentConfigId,
4670
- sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
4671
- event_first_label: opts.firstLabel ?? "",
4672
- event_second_label: opts.secondLabel ?? "",
4673
- page: opts.page ?? 1,
4674
- page_size: opts.pageSize ?? 500
4675
- }
4676
- });
4677
- }
4678
- async function searchSituationActions(opts) {
4679
- const request = createRequest();
4680
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/search", {
4681
- method: "GET",
4682
- query: { customer_agent_config_id: opts.agentConfigId, keyword: opts.keyword }
4683
- });
4684
- }
4685
- async function createSituationAction(opts) {
4686
- const request = createRequest();
4687
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/create", {
4688
- method: "POST",
4689
- body: {
4690
- customer_agent_config_id: opts.agentConfigId,
4691
- sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
4692
- event_first_label: opts.firstLabel,
4693
- event_second_label: opts.secondLabel,
4694
- situation: opts.situation,
4695
- action: opts.action,
4696
- transfer_to_human: opts.transferToHuman ?? false
4697
- }
4698
- });
4699
- }
4700
- async function updateSituationAction(opts) {
4701
- const request = createRequest();
4702
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/update", {
4703
- method: "POST",
4704
- body: {
4705
- customer_agent_config_id: opts.agentConfigId,
4706
- situation_action_id: opts.situationActionId,
4707
- sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
4708
- event_first_label: opts.firstLabel,
4709
- event_second_label: opts.secondLabel,
4710
- situation: opts.situation,
4711
- action: opts.action,
4712
- transfer_to_human: opts.transferToHuman ?? false
4713
- }
4714
- });
4715
- }
4716
- async function deleteSituationAction(opts) {
4717
- const request = createRequest();
4718
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/delete", {
4719
- method: "POST",
4720
- body: {
4721
- customer_agent_config_id: opts.agentConfigId,
4722
- situation_action_id: opts.situationActionId,
4723
- event_first_label: opts.firstLabel,
4724
- event_second_label: opts.secondLabel
4725
- }
4726
- });
4727
- }
4728
- async function listSituationActionVersions(opts) {
4729
- const request = createRequest();
4730
- return request(
4731
- getCustomerServiceUrl(),
4732
- "/v1/knowledge/situation-actions/list/versions",
4733
- {
4734
- method: "GET",
4735
- query: {
4736
- customer_agent_config_id: opts.agentConfigId,
4737
- situation_action_id: opts.situationActionId
4738
- }
4739
- }
4740
- );
4741
- }
4742
-
4743
5421
  // src/commands/sa.ts
4744
5422
  function registerSACommand(program2) {
4745
5423
  const sa = program2.command("sa").description(
@@ -5661,6 +6339,23 @@ function registerWorkspaceCommand(program2) {
5661
6339
  process.exit(toExitCode(err));
5662
6340
  }
5663
6341
  });
6342
+ workspace.command("points-consumes").description("\u5206\u9875\u67E5\u8BE2\u5F53\u524D\u5DE5\u4F5C\u7A7A\u95F4\u7684\u79EF\u5206\u8D26\u6237\u6D88\u8017\u6D41\u6C34\uFF0C\u56FA\u5B9A\u8FD4\u56DE extra \u8C03\u8BD5\u5B57\u6BB5").option("--page <number>", "\u9875\u7801\uFF0C\u9ED8\u8BA4 1", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF\uFF0C\u9ED8\u8BA4 20", "20").action(async (opts) => {
6343
+ try {
6344
+ const page = Number(opts.page);
6345
+ const pageSize = Number(opts.pageSize);
6346
+ if (!Number.isInteger(page) || page <= 0) {
6347
+ throw new Error("--page \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
6348
+ }
6349
+ if (!Number.isInteger(pageSize) || pageSize <= 0) {
6350
+ throw new Error("--page-size \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
6351
+ }
6352
+ const data = await getPointsConsumes({ page, pageSize });
6353
+ formatOutput({ success: true, data }, program2.opts().table);
6354
+ } catch (err) {
6355
+ reportCaughtError(err);
6356
+ process.exit(toExitCode(err));
6357
+ }
6358
+ });
5664
6359
  workspace.command("points-consumes-daily").description(
5665
6360
  "\u6309\u5929\u67E5\u8BE2\u5F53\u524D\u5DE5\u4F5C\u7A7A\u95F4\u7684\u79EF\u5206\u6D88\u8017\u3002\u9ED8\u8BA4\u6700\u8FD1 30 \u5929\uFF08end=\u4ECA\u5929\uFF0Cstart=\u4ECA\u5929-29d\uFF09\uFF0C\u8FD4\u56DE consume_date / total_consume_points \u5217\u8868"
5666
6361
  ).option("--start <YYYY-MM-DD>", "\u8D77\u59CB\u65E5\u671F\uFF08\u542B\uFF09\uFF0C\u9ED8\u8BA4\u4ECA\u5929-29d").option("--end <YYYY-MM-DD>", "\u7ED3\u675F\u65E5\u671F\uFF08\u542B\uFF09\uFF0C\u9ED8\u8BA4\u4ECA\u5929").action(async (opts) => {