@bty/customer-service-cli 0.6.2 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.5 (2026-07-14)
4
+
5
+ - `debug ask` / `debug reproduce` 新增 `--mock <json|@file>`(工具结果 mock,形如 `[{ tool_name, result }]`)与 `--data-overlay <json|@file>`(本轮 `debug_data_overlay` 数据覆盖),发送时透传给 `/v1/debug/chat/agent_message`;`reproduce --dry-run` 输出中同步包含 mock 与 overlay。
6
+ - 新增 `debug data snapshot --agent <id> [--product-id <商品ID...>]`:把当前 Agent 的 SOP / 商品 / 活动等数据导出为 `debug_data_overlay` v1 JSON(写 stdout),配合 `--data-overlay @file` 复跑固定数据集;`--product-id` 可重复传多个只导指定商品,不传则分页导出全量商品。
7
+
8
+ ## 0.6.4 (2026-07-04)
9
+
10
+ - `conversation transfer-human` 适配服务端 cursor 分页:移除 CLI 暴露的 `--page` 参数,CLI 自动沿 `next_cursor` 拉取全部结果并合并返回,避免深翻页请求压垮数据库。
11
+ - `transfer-human` 客户端保留 7 天查询窗口校验,并新增最多 500 个 cursor 页的保护,超出时提示缩小查询时间范围。
12
+
13
+ ## 0.6.3 (2026-06-25)
14
+
15
+ - 修复 `product update` / `product update-sku` 在商品数超过 100 时,对位置靠后的商品报「未找到商品 product_id=xxx」的问题:`findProduct` 由只取第一页(`page:1, pageSize:100`)改为翻页查找,直到命中目标商品或翻完所有页。
16
+
3
17
  ## 0.6.2 (2026-06-15)
4
18
 
5
19
  - `workspace` 新增 `points-consumes` 子命令:分页查询当前工作空间的积分账户消耗流水(`POST /v1/workspace/points_consumes`),支持 `--page` / `--page-size`,CLI 固定传 `debug: true`,返回中包含服务端 `extra` 调试字段。
package/README.md CHANGED
@@ -457,7 +457,7 @@ Agent 关联的通用规则知识库(`suffix_type=_common`),与 FAQ / 商
457
457
  | `conversation list [--agent <id>] [--equipment-id <设备ID>] [--user <用户名>] [--start <日期>] [--end <日期>]` | 搜索会话 |
458
458
  | `conversation records <conversation_id> [--page-size N] [--direction prev|next]` | 获取会话聊天记录 |
459
459
  | `conversation context-search --query <文本> [--start <时间>] [--end <时间>]` | 通过上下文内容模糊搜索对话记录(返回匹配消息详情,时间范围最多 3 天) |
460
- | `conversation transfer-human --agent <customer_agent_config_id> --start <时间> --end <时间> [--page N]` | 查询转人工会话及对应转人工消息记录(时间范围最多 7 天,分页大小固定 100) |
460
+ | `conversation transfer-human --agent <customer_agent_config_id> --start <时间> --end <时间>` | 查询转人工会话及对应转人工消息记录(时间范围最多 7 天,自动 cursor 翻页) |
461
461
 
462
462
 
463
463
  ### Agent 调试 (`debug`)
@@ -465,15 +465,26 @@ Agent 关联的通用规则知识库(`suffix_type=_common`),与 FAQ / 商
465
465
 
466
466
  | 命令 | 说明 |
467
467
  | ----------------------------------------------------------------------------------------------------------- | -------------------- |
468
- | `debug ask --agent <id> --text <消息> [--user <用户名>] [--url <图片URL>] [--conversation <会话ID>] [--timeout <秒>]` | 向 Agent 发送消息并等待回复 |
469
- | `debug reproduce <record_id> [--agent <id>] [--timeout <秒>] [--dry-run]` | 根据 record_id 复现 Agent 回复(自动获取上下文) |
468
+ | `debug ask --agent <id> (--text <消息> \| --messages <json\|@file>) [--user <用户名>] [--url <图片URL>] [--conversation <会话ID>] [--mock <json\|@file>] [--data-overlay <json\|@file>] [--timeout <秒>] [--poll-interval <毫秒>]` | 向 Agent 发送消息并等待回复 |
469
+ | `debug reproduce <record_id> [--agent <id>] [--mock <json\|@file>] [--data-overlay <json\|@file>] [--timeout <秒>] [--poll-interval <毫秒>] [--dry-run]` | 根据 record_id 复现 Agent 回复(自动获取上下文) |
470
+ | `debug data snapshot --agent <id> [--product-id <商品ID...>]` | 生成可传给 `--data-overlay @file` 的 debug 数据覆盖 JSON |
470
471
  | `debug record <record_id>` | 获取记录的调试信息(flow_info),返回中包含 `trace_id` |
471
472
  | `debug trace <trace_id> [--env <dev\|prod>]` | 根据 Langfuse Trace ID 获取完整 Trace 详情(经服务端代理,默认 `prod`) |
472
473
 
473
474
 
474
- `debug ask` 会自动创建调试会话、发送消息、轮询等待 Agent 回复,默认最大等待 30 秒。支持 `--messages` 传入完整消息列表(JSON 或 @文件)重放 issue 对话。
475
+ `debug ask` 会自动创建调试会话、发送消息、轮询等待 Agent 回复,默认最大等待 30 秒,默认轮询间隔 2000ms。`--text` 与 `--messages` 二选一:`--text` 发送单条消息,`--url` 只在 `--text` 模式下作为附图 URL;`--messages` 传入完整消息列表(JSON 或 @文件)重放多轮对话,既接受 JSON 数组,也接受 `conversation records` 原始 `{ "msg_list": [...] }` 对象。`--conversation` 可复用已有 debug 会话继续对话;`--mock` 可传工具结果 mock;`--data-overlay` 可传 `debug_data_overlay` JSON 或 @文件。
475
476
 
476
- `debug reproduce` 根据一条回复记录自动复现 Agent 回复:通过 recordId 获取关联会话和 Agent 配置,拉取完整会话记录并截取目标 record 之前的上下文,使用原始用户名创建新 debug 会话并发送。`--agent` 可指定另一个 Agent 复现同一段上下文(A/B 对比),`--dry-run` 仅输出上下文不发送。
477
+ `debug reproduce` 根据一条回复记录自动复现 Agent 回复:通过 recordId 获取关联会话和 Agent 配置,拉取完整会话记录并截取目标 record 之前的上下文,使用原始用户名创建新 debug 会话并发送。默认最大等待 60 秒,默认轮询间隔 2000ms。`--agent` 可指定另一个 Agent 复现同一段上下文(A/B 对比);`--mock` 和 `--data-overlay` 会在复现发送时透传;`--dry-run` 仅输出截断后的 `msg_list`、mock 和 overlay,不发送。
478
+
479
+ `debug data snapshot` 生成 `debug_data_overlay` v1 JSON,适合把当前 Agent 的 SOP / 商品 / 活动等数据固定成一次 debug 覆盖输入,再通过 `debug ask --data-overlay @file` 或 `debug reproduce --data-overlay @file` 复跑。`--agent <id>` 必填;`--product-id <商品ID...>` 可重复传多个商品 ID,只导出指定商品,不传则分页导出全量商品。命令输出写到 stdout,通常重定向到文件保存。
480
+
481
+ ```bash
482
+ # 只导出指定商品相关 overlay
483
+ cs-cli debug data snapshot --agent <id> --product-id 586812046546 > overlay.json
484
+
485
+ # 使用 overlay 跑一次 ask
486
+ cs-cli debug ask --agent <id> --text "https://item.taobao.com/item.htm?id=586812046546 这个商品名称是啥" --data-overlay @overlay.json
487
+ ```
477
488
 
478
489
  `debug trace`(v0.4.0 起,**行为变更**)不再由 CLI 直连 Langfuse REST API,改为请求 customer-servhub-api 的 `GET /v1/debug/langfuse/trace/{trace_id}?env=<env>`,走 CLI 标准 Bearer 鉴权,由服务端按 env 选择 Langfuse 凭据并代理拉取 Trace。Trace ID 从 `debug record` 返回的 `trace_id` 字段获取。
479
490
 
@@ -842,12 +853,9 @@ cs-cli product add --agent <id> --data @products.json --source batch --no-identi
842
853
  # 通过上下文内容模糊搜索对话记录(自动使用当前工作空间,查询窗口最多 3 天)
843
854
  cs-cli conversation context-search --query "退款问题" --start 2026-03-22T00:00:00 --end 2026-03-22T23:59:59
844
855
 
845
- # 查询转人工会话及对应转人工消息记录(按 MANUAL_TAKEOVER_REQUIRED 事件时间过滤,查询窗口最多 7 天)
856
+ # 查询转人工会话及对应转人工消息记录(按 MANUAL_TAKEOVER_REQUIRED 事件时间过滤,查询窗口最多 7 天,自动 cursor 翻页)
846
857
  cs-cli conversation transfer-human --agent <customer_agent_config_id> --start 2026-05-24T00:00:00 --end 2026-05-24T23:59:59
847
858
 
848
- # 查询第 2 页转人工会话
849
- cs-cli conversation transfer-human --agent <customer_agent_config_id> --start 2026-05-24T00:00:00 --end 2026-05-24T23:59:59 --page 2
850
-
851
859
  # 复现某条回复(自动获取上下文、原始用户名、Agent 配置)
852
860
  cs-cli debug reproduce <record_id>
853
861
 
package/dist/bin.js CHANGED
@@ -1224,6 +1224,7 @@ function registerConfigCommand(program2) {
1224
1224
  // src/client/conversation-api.ts
1225
1225
  var MAX_CONTEXT_SEARCH_RANGE_MS = 3 * 24 * 60 * 60 * 1e3;
1226
1226
  var MAX_TRANSFER_HUMAN_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
1227
+ var MAX_TRANSFER_HUMAN_CURSOR_PAGES = 500;
1227
1228
  function parseSearchTime(value, fieldName) {
1228
1229
  const parsed = new Date(value);
1229
1230
  if (Number.isNaN(parsed.getTime())) {
@@ -1296,15 +1297,36 @@ async function listConversations(opts) {
1296
1297
  async function listTransferHumanConversations(opts) {
1297
1298
  validateTransferHumanRange(opts.startDate, opts.endDate);
1298
1299
  const request = createRequest();
1299
- return request(getCustomerServiceUrl(), "/v1/chat/conversations/transfer-human", {
1300
- method: "GET",
1301
- query: {
1302
- customer_agent_config_id: opts.customerAgentConfigId,
1303
- start_date: opts.startDate,
1304
- end_date: opts.endDate,
1305
- page: opts.page ?? 1
1306
- }
1307
- });
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`);
1308
1330
  }
1309
1331
 
1310
1332
  // src/commands/conversation.ts
@@ -1360,13 +1382,12 @@ function registerConversationCommand(program2) {
1360
1382
  process.exit(toExitCode(err));
1361
1383
  }
1362
1384
  });
1363
- 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) => {
1364
1386
  try {
1365
1387
  const data = await listTransferHumanConversations({
1366
1388
  customerAgentConfigId: opts.agent,
1367
1389
  startDate: opts.start,
1368
- endDate: opts.end,
1369
- page: Number(opts.page)
1390
+ endDate: opts.end
1370
1391
  });
1371
1392
  formatOutput({ success: true, data }, program2.opts().table);
1372
1393
  } catch (err) {
@@ -1722,16 +1743,23 @@ async function sendAgentMessage(opts) {
1722
1743
  ];
1723
1744
  }
1724
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
+ }
1725
1757
  return request(
1726
1758
  getCustomerServiceUrl(),
1727
1759
  "/v1/debug/chat/agent_message",
1728
1760
  {
1729
1761
  method: "POST",
1730
- body: {
1731
- msg_list: msgList,
1732
- is_stream: false,
1733
- conversation_id: opts.conversationId
1734
- }
1762
+ body
1735
1763
  }
1736
1764
  );
1737
1765
  }
@@ -1851,6 +1879,441 @@ async function getLangfuseTrace(traceId, env) {
1851
1879
  );
1852
1880
  }
1853
1881
 
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
1894
+ }
1895
+ });
1896
+ }
1897
+ async function getProductDetail(opts) {
1898
+ const request = createRequest();
1899
+ return request(getCustomerServiceUrl(), "/v1/knowledge/product/detail", {
1900
+ method: "GET",
1901
+ query: {
1902
+ customer_agent_config_id: opts.agentConfigId,
1903
+ db_id: opts.dbId,
1904
+ product_id: opts.productId
1905
+ }
1906
+ });
1907
+ }
1908
+ async function updateProduct(opts) {
1909
+ const request = createRequest();
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
+
1854
2317
  // src/commands/debug.ts
1855
2318
  function registerDebugCommand(program2) {
1856
2319
  const debug = program2.command("debug").description(
@@ -1861,7 +2324,7 @@ function registerDebugCommand(program2) {
1861
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(
1862
2325
  "--messages <json>",
1863
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'
1864
- ).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) => {
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) => {
1865
2328
  try {
1866
2329
  if (!opts.text && !opts.messages) {
1867
2330
  outputError(1, "\u5FC5\u987B\u6307\u5B9A --text \u6216 --messages \u5176\u4E2D\u4E4B\u4E00");
@@ -1887,11 +2350,15 @@ function registerDebugCommand(program2) {
1887
2350
  process.exit(1);
1888
2351
  }
1889
2352
  }
2353
+ const mock = opts.mock ? parseDataOption(opts.mock) : void 0;
2354
+ const debugDataOverlay = opts.dataOverlay ? parseDataOption(opts.dataOverlay) : void 0;
1890
2355
  await sendAgentMessage({
1891
2356
  conversationId,
1892
2357
  text: opts.text,
1893
2358
  imageUrl: opts.url,
1894
- msgList
2359
+ msgList,
2360
+ mock,
2361
+ debugDataOverlay
1895
2362
  });
1896
2363
  const agentRecords = await pollAgentReply(conversationId, {
1897
2364
  timeout: Number(opts.timeout) * 1e3,
@@ -1918,10 +2385,10 @@ function registerDebugCommand(program2) {
1918
2385
  false
1919
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) => {
1920
2387
  try {
1921
- const data = await getRecordDebugInfo(recordId);
2388
+ const data2 = await getRecordDebugInfo(recordId);
1922
2389
  let deep;
1923
2390
  if (opts.deep) {
1924
- const flowInfo = data.flow_info;
2391
+ const flowInfo = data2.flow_info;
1925
2392
  const flowId = flowInfo?.flow_id;
1926
2393
  const taskId = flowInfo?.task_id;
1927
2394
  if (!flowId || !taskId) {
@@ -1939,7 +2406,7 @@ function registerDebugCommand(program2) {
1939
2406
  }
1940
2407
  }
1941
2408
  formatOutput(
1942
- { success: true, data: opts.deep ? { ...data, deep } : data },
2409
+ { success: true, data: opts.deep ? { ...data2, deep } : data2 },
1943
2410
  program2.opts().table
1944
2411
  );
1945
2412
  } catch (err) {
@@ -1949,7 +2416,7 @@ function registerDebugCommand(program2) {
1949
2416
  });
1950
2417
  debug.command("reproduce").description(
1951
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"
1952
- ).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) => {
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) => {
1953
2420
  try {
1954
2421
  const relations = await getRecordRelations(recordId);
1955
2422
  const { conversation, agent_config: agentConfig } = relations;
@@ -1963,6 +2430,8 @@ function registerDebugCommand(program2) {
1963
2430
  });
1964
2431
  const truncated = truncateBeforeRecord(records, recordId);
1965
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;
1966
2435
  if (opts.dryRun) {
1967
2436
  formatOutput(
1968
2437
  {
@@ -1973,7 +2442,9 @@ function registerDebugCommand(program2) {
1973
2442
  agent_config_name: agentConfig.config_name,
1974
2443
  user_name: userName,
1975
2444
  context_messages_count: msgList.length,
1976
- msg_list: msgList
2445
+ msg_list: msgList,
2446
+ mock,
2447
+ debug_data_overlay: debugDataOverlay
1977
2448
  }
1978
2449
  },
1979
2450
  program2.opts().table
@@ -1986,7 +2457,9 @@ function registerDebugCommand(program2) {
1986
2457
  });
1987
2458
  await sendAgentMessage({
1988
2459
  conversationId: conv.conversation_id,
1989
- msgList
2460
+ msgList,
2461
+ mock,
2462
+ debugDataOverlay
1990
2463
  });
1991
2464
  const agentRecords = await pollAgentReply(conv.conversation_id, {
1992
2465
  timeout: Number(opts.timeout) * 1e3,
@@ -2020,6 +2493,20 @@ function registerDebugCommand(program2) {
2020
2493
  process.exit(toExitCode(err));
2021
2494
  }
2022
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
+ });
2023
2510
  debug.command("trace").description(
2024
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"
2025
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) => {
@@ -2028,8 +2515,8 @@ function registerDebugCommand(program2) {
2028
2515
  outputError(1, "--env \u4EC5\u652F\u6301 dev \u6216 prod");
2029
2516
  process.exit(1);
2030
2517
  }
2031
- const data = await getLangfuseTrace(traceId, opts.env);
2032
- formatOutput({ success: true, data }, program2.opts().table);
2518
+ const data2 = await getLangfuseTrace(traceId, opts.env);
2519
+ formatOutput({ success: true, data: data2 }, program2.opts().table);
2033
2520
  } catch (err) {
2034
2521
  reportCaughtError(err);
2035
2522
  process.exit(toExitCode(err));
@@ -4619,114 +5106,6 @@ function registerOperationsRecordCommand(program2) {
4619
5106
  });
4620
5107
  }
4621
5108
 
4622
- // src/client/product-api.ts
4623
- async function listProducts(opts) {
4624
- const request = createRequest();
4625
- return request(getCustomerServiceUrl(), "/v1/knowledge/products", {
4626
- method: "GET",
4627
- query: {
4628
- customer_agent_config_id: opts.agentConfigId,
4629
- search: opts.keyword,
4630
- status: opts.status?.join(","),
4631
- tags: opts.tags?.length ? JSON.stringify(opts.tags) : void 0,
4632
- page: opts.page ?? 1,
4633
- page_size: opts.pageSize ?? 20
4634
- }
4635
- });
4636
- }
4637
- async function getProductDetail(opts) {
4638
- const request = createRequest();
4639
- return request(getCustomerServiceUrl(), "/v1/knowledge/product/detail", {
4640
- method: "GET",
4641
- query: {
4642
- customer_agent_config_id: opts.agentConfigId,
4643
- db_id: opts.dbId,
4644
- product_id: opts.productId
4645
- }
4646
- });
4647
- }
4648
- async function updateProduct(opts) {
4649
- const request = createRequest();
4650
- return request(getCustomerServiceUrl(), "/v1/knowledge/product/update", {
4651
- method: "POST",
4652
- body: {
4653
- data_id: opts.dataId,
4654
- knowledge_id: opts.knowledgeId,
4655
- db_id: opts.dbId,
4656
- update_dict: opts.updateDict
4657
- }
4658
- });
4659
- }
4660
- async function uploadProductByUrl(opts) {
4661
- const request = createRequest();
4662
- return request(getCustomerServiceUrl(), "/v1/knowledge/products/upload", {
4663
- method: "POST",
4664
- body: {
4665
- customer_agent_config_id: opts.agentConfigId,
4666
- source_type: opts.sourceType ?? "manual",
4667
- identify: opts.identify ?? true,
4668
- product_urls: opts.productUrls
4669
- }
4670
- });
4671
- }
4672
- async function uploadProductData(opts) {
4673
- const request = createRequest();
4674
- return request(getCustomerServiceUrl(), "/v1/knowledge/products/upload", {
4675
- method: "POST",
4676
- body: {
4677
- customer_agent_config_id: opts.agentConfigId,
4678
- source_type: opts.sourceType ?? "manual",
4679
- identify: opts.identify ?? true,
4680
- product_items: opts.productItems
4681
- }
4682
- });
4683
- }
4684
- async function updateSku(opts) {
4685
- if (!opts.skuId && !opts.sku) {
4686
- throw new Error("updateSku \u9700\u8981\u63D0\u4F9B sku \u6216 sku_id \u5176\u4E2D\u4E4B\u4E00");
4687
- }
4688
- const identifier = opts.skuId ? { sku_id: opts.skuId } : { sku: opts.sku };
4689
- const request = createRequest();
4690
- return request(getCustomerServiceUrl(), "/v1/knowledge/sku/update", {
4691
- method: "POST",
4692
- body: {
4693
- ...identifier,
4694
- customer_agent_config_id: opts.agentConfigId,
4695
- update_dict: opts.updateDict
4696
- }
4697
- });
4698
- }
4699
- async function syncTaobaoProducts(opts) {
4700
- const request = createRequest();
4701
- return request(getCustomerServiceUrl(), "/v1/authorized-shop/sync-taobao-products", {
4702
- method: "POST",
4703
- body: {
4704
- customer_agent_config_id: opts.agentConfigId,
4705
- skip_hash_check: opts.skipHashCheck ?? false,
4706
- sync_type: opts.syncType ?? "full"
4707
- }
4708
- });
4709
- }
4710
- async function syncSingleTaobaoProduct(opts) {
4711
- const request = createRequest();
4712
- return request(getCustomerServiceUrl(), "/v1/authorized-shop/sync-single-product", {
4713
- method: "POST",
4714
- body: {
4715
- customer_agent_config_id: opts.agentConfigId,
4716
- product_id: opts.productId
4717
- }
4718
- });
4719
- }
4720
- async function identifyAllProducts(opts) {
4721
- const request = createRequest();
4722
- return request(getCustomerServiceUrl(), "/v1/knowledge/products/identify/all", {
4723
- method: "POST",
4724
- body: {
4725
- customer_agent_config_id: opts.agentConfigId
4726
- }
4727
- });
4728
- }
4729
-
4730
5109
  // src/commands/product.ts
4731
5110
  async function getDbId(agentConfigId) {
4732
5111
  const agent = await getAgent(agentConfigId);
@@ -4736,12 +5115,20 @@ async function getDbId(agentConfigId) {
4736
5115
  return agent.database_id;
4737
5116
  }
4738
5117
  async function findProduct(agentConfigId, productId) {
4739
- const result = await listProducts({ agentConfigId, page: 1, pageSize: 100 });
4740
- const matched = result.items?.find((p) => p.product_id === productId);
4741
- if (!matched) {
4742
- 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
+ }
4743
5131
  }
4744
- return matched;
4745
5132
  }
4746
5133
  function registerProductCommand(program2) {
4747
5134
  const product = program2.command("product").description(
@@ -5031,86 +5418,6 @@ function registerRepairRecordCommand(program2) {
5031
5418
  });
5032
5419
  }
5033
5420
 
5034
- // src/client/sa-api.ts
5035
- async function listSituationActions(opts) {
5036
- const request = createRequest();
5037
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/list", {
5038
- method: "GET",
5039
- query: {
5040
- customer_agent_config_id: opts.agentConfigId,
5041
- sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
5042
- event_first_label: opts.firstLabel ?? "",
5043
- event_second_label: opts.secondLabel ?? "",
5044
- page: opts.page ?? 1,
5045
- page_size: opts.pageSize ?? 500
5046
- }
5047
- });
5048
- }
5049
- async function searchSituationActions(opts) {
5050
- const request = createRequest();
5051
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/search", {
5052
- method: "GET",
5053
- query: { customer_agent_config_id: opts.agentConfigId, keyword: opts.keyword }
5054
- });
5055
- }
5056
- async function createSituationAction(opts) {
5057
- const request = createRequest();
5058
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/create", {
5059
- method: "POST",
5060
- body: {
5061
- customer_agent_config_id: opts.agentConfigId,
5062
- sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
5063
- event_first_label: opts.firstLabel,
5064
- event_second_label: opts.secondLabel,
5065
- situation: opts.situation,
5066
- action: opts.action,
5067
- transfer_to_human: opts.transferToHuman ?? false
5068
- }
5069
- });
5070
- }
5071
- async function updateSituationAction(opts) {
5072
- const request = createRequest();
5073
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/update", {
5074
- method: "POST",
5075
- body: {
5076
- customer_agent_config_id: opts.agentConfigId,
5077
- situation_action_id: opts.situationActionId,
5078
- sub_agent_intent: opts.subAgentIntent ?? "GENERAL_QA",
5079
- event_first_label: opts.firstLabel,
5080
- event_second_label: opts.secondLabel,
5081
- situation: opts.situation,
5082
- action: opts.action,
5083
- transfer_to_human: opts.transferToHuman ?? false
5084
- }
5085
- });
5086
- }
5087
- async function deleteSituationAction(opts) {
5088
- const request = createRequest();
5089
- return request(getCustomerServiceUrl(), "/v1/knowledge/situation-actions/delete", {
5090
- method: "POST",
5091
- body: {
5092
- customer_agent_config_id: opts.agentConfigId,
5093
- situation_action_id: opts.situationActionId,
5094
- event_first_label: opts.firstLabel,
5095
- event_second_label: opts.secondLabel
5096
- }
5097
- });
5098
- }
5099
- async function listSituationActionVersions(opts) {
5100
- const request = createRequest();
5101
- return request(
5102
- getCustomerServiceUrl(),
5103
- "/v1/knowledge/situation-actions/list/versions",
5104
- {
5105
- method: "GET",
5106
- query: {
5107
- customer_agent_config_id: opts.agentConfigId,
5108
- situation_action_id: opts.situationActionId
5109
- }
5110
- }
5111
- );
5112
- }
5113
-
5114
5421
  // src/commands/sa.ts
5115
5422
  function registerSACommand(program2) {
5116
5423
  const sa = program2.command("sa").description(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bty/customer-service-cli",
3
- "version": "0.6.2",
3
+ "version": "0.6.5",
4
4
  "description": "AI Customer Service CLI - Agent friendly",
5
5
  "type": "module",
6
6
  "main": "./dist/bin.js",