@bty/customer-service-cli 0.6.0 → 0.6.2
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 +17 -1
- package/README.md +32 -0
- package/dist/bin.js +524 -136
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.6.
|
|
3
|
+
## 0.6.2 (2026-06-15)
|
|
4
|
+
|
|
5
|
+
- `workspace` 新增 `points-consumes` 子命令:分页查询当前工作空间的积分账户消耗流水(`POST /v1/workspace/points_consumes`),支持 `--page` / `--page-size`,CLI 固定传 `debug: true`,返回中包含服务端 `extra` 调试字段。
|
|
6
|
+
- `customer-servhub-api` 的 `POST /v1/workspace/points_consumes` 新增 `debug` 请求参数:默认 `false` 不返回 `extra`,传 `true` 时返回 `extra` 方便调试。
|
|
7
|
+
|
|
8
|
+
## 0.6.1 (2026-06-11)
|
|
9
|
+
|
|
10
|
+
- `product` 新增 `related-knowledge` 子命令组,支持按商品维护“关联知识库”文件级绑定:
|
|
11
|
+
- `product related-knowledge list --agent <id> --product-id <id>`:列出商品绑定的 QA / 扩展知识库文件。
|
|
12
|
+
- `product related-knowledge add --agent <id> --product-id <id> --type qa|common (--file <name> | --file-id <id> --partition-id <id>)`:给商品追加绑定文件,重复文件幂等去重。
|
|
13
|
+
- `product related-knowledge remove --agent <id> --product-id <id> --type qa|common --file-id <id>`:移除指定绑定,目标不存在时保持幂等。
|
|
14
|
+
- `product related-knowledge set --agent <id> --product-id <id> --bindings <json|@file>`:覆盖商品的全部关联知识库文件。
|
|
15
|
+
- `faq` / `knowledge` 新增文件侧 `bind-products` 子命令组,分别固定写入 `knowledge_type=qa` / `knowledge_type=common`:
|
|
16
|
+
- `list`:按知识库文件反查绑定商品。
|
|
17
|
+
- `add` / `remove`:read-modify-replace 维护绑定商品,重复添加或移除不存在的商品保持幂等。
|
|
18
|
+
- `set`:覆盖该文件绑定的全部商品。
|
|
19
|
+
- 新增 `product-knowledge-binding-api` 客户端封装,对接 customer-servhub-api `/v1/knowledge/product-bindings*` 现有接口;CLI 不改变服务端绑定表或 sop-engine 命中逻辑。
|
|
4
20
|
|
|
5
21
|
- 新增 `node-template describe [--stage <s>]`:节点编写说明书命令(AI 编写前必读)——输出每个节点的职责/可编辑面/输出契约/平台锁定段,以及该节点可 `@引用` 的变量目录。纯静态、与具体 agent 无关,无需 `--agent`。
|
|
6
22
|
- `node-template` 节点 stage 新增 `image_understanding` 伪 stage(图片理解方法论可配置化,spec 2026-06-08):`describe` / `get` / `set-draft` / `publish` / `versions` / `version` / `restore` 均纳入;发布前 `{{}}` 合法性校验白名单同步放行。
|
package/README.md
CHANGED
|
@@ -227,6 +227,10 @@ cs-cli workspace points-consumes-daily --start 2026-04-01 --end 2026-04-23
|
|
|
227
227
|
| `product identify-all --agent <id>` | 一键增强学习当前 Agent 下所有待增强商品 |
|
|
228
228
|
| `product sync-taobao --agent <id> [--skip-hash-check] [--sync-type <full\|incremental>]` | 触发淘宝店铺商品同步 |
|
|
229
229
|
| `product sync-taobao-item --agent <id> --product-id <商品ID>` | 触发单个淘宝商品同步 |
|
|
230
|
+
| `product related-knowledge list --agent <id> --product-id <商品ID>` | 列出商品详情绑定的 QA / 扩展知识库文件 |
|
|
231
|
+
| `product related-knowledge add --agent <id> --product-id <商品ID> --type <qa\|common> (--file <文件名> \| --file-id <id> --partition-id <id>)` | 给商品追加关联知识库文件 |
|
|
232
|
+
| `product related-knowledge remove --agent <id> --product-id <商品ID> --type <qa\|common> --file-id <id>` | 移除商品绑定的指定知识库文件 |
|
|
233
|
+
| `product related-knowledge set --agent <id> --product-id <商品ID> --bindings <json\|@file>` | 覆盖商品绑定的全部知识库文件 |
|
|
230
234
|
|
|
231
235
|
`product update` 支持更新的字段包括:`卖点`、`补充知识`、`tag`、`参数`、`轮播图识别结果`、`商品详情页识别结果` 等。`--update` 接受 JSON 字符串或 `@文件路径`。
|
|
232
236
|
|
|
@@ -240,6 +244,8 @@ cs-cli workspace points-consumes-daily --start 2026-04-01 --end 2026-04-23
|
|
|
240
244
|
|
|
241
245
|
注意:这两个命令仅对已开通“高级工具”的店铺 Agent 生效。未开通高级工具时,即使 `--agent` 已绑定淘宝授权店铺,请求也可能在服务端失败。
|
|
242
246
|
|
|
247
|
+
`product related-knowledge` 管理商品详情的“关联知识库”文件级绑定。`--type qa` 对应 FAQ 知识库,`--type common` 对应扩展知识库。`add` / `remove` 会先读取当前绑定,再通过服务端全量替换接口写回;重复添加或移除不存在的文件保持幂等。`--file <文件名>` 会按当前 Agent 的知识库文件列表做精确匹配;文件名不存在或不唯一时,改用 `--file-id` + `--partition-id` 显式模式。
|
|
248
|
+
|
|
243
249
|
```bash
|
|
244
250
|
# 更新卖点
|
|
245
251
|
cs-cli product update --agent <id> --product-id <商品ID> --update '{"卖点":"新卖点内容"}'
|
|
@@ -255,6 +261,12 @@ cs-cli product update-sku --agent <id> --sku "颜色分类:粉红" --update '{"
|
|
|
255
261
|
|
|
256
262
|
# 更新 SKU 补充知识(按 sku_id 定位,推荐)
|
|
257
263
|
cs-cli product update-sku --agent <id> --sku-id 6072595054179 --update '{"补充知识":"说明内容"}'
|
|
264
|
+
|
|
265
|
+
# 给商品绑定一个 FAQ 文件
|
|
266
|
+
cs-cli product related-knowledge add --agent <id> --product-id <商品ID> --type qa --file "常见问题.xlsx"
|
|
267
|
+
|
|
268
|
+
# 显式 ID 模式绑定扩展知识文件
|
|
269
|
+
cs-cli product related-knowledge add --agent <id> --product-id <商品ID> --type common --file-id 622474 --partition-id 12345 --file-name "售后规则.md"
|
|
258
270
|
```
|
|
259
271
|
|
|
260
272
|
|
|
@@ -405,11 +417,17 @@ CLI 把 `description` + `expected` 拼成 `content`:
|
|
|
405
417
|
| `faq add --agent <id> --file <文件名> --questions <问题1,问题2> --answers <答案=xxx>` | 添加 FAQ 内容 |
|
|
406
418
|
| `faq update --agent <id> --file <文件名> --group-id <id> [--questions <...>] [--answers <...>] [--delete-chunks <id1,id2>]` | 更新已有 FAQ 答案组(`--questions` / `--answers` / `--delete-chunks` 至少一个) |
|
|
407
419
|
| `faq delete --agent <id> --file <文件名> --group-id <id>` | 删除 FAQ 答案组 |
|
|
420
|
+
| `faq bind-products list --agent <id> (--file <文件名> \| --file-id <id> --partition-id <id>)` | 列出 FAQ 文件绑定的商品 |
|
|
421
|
+
| `faq bind-products add --agent <id> (--file <文件名> \| --file-id <id> --partition-id <id>) --product-id <商品ID...>` | 给 FAQ 文件追加绑定商品 |
|
|
422
|
+
| `faq bind-products remove --agent <id> (--file <文件名> \| --file-id <id> --partition-id <id>) --product-id <商品ID...>` | 从 FAQ 文件移除绑定商品 |
|
|
423
|
+
| `faq bind-products set --agent <id> (--file <文件名> \| --file-id <id> --partition-id <id>) --product-id <商品ID...>` | 覆盖 FAQ 文件绑定的全部商品 |
|
|
408
424
|
|
|
409
425
|
`faq content` 走 `GET /mebsuta/api/v1/dataset/{knowledge_id}/faq_contents`,列出文件内的答案组及其 `answer_group_id`,是 `faq update` / `faq delete` 拿 `--group-id` 的来源(`faq list` 只给文件,文件内的 group-id 要靠这条命令查)。支持 `--keyword` 搜索、`--page-size` 分页、`--next-group-id` 游标续翻。
|
|
410
426
|
|
|
411
427
|
`faq update` 按 `answer_group_id` 定位目标组,POST 同一个 `faq_contents/save` 接口完成字段替换、问题替换与 chunk 级删除。`faq delete` 走 `DELETE /faq_contents/{group_id}` 整组删除。
|
|
412
428
|
|
|
429
|
+
`faq bind-products` 固定写入 `knowledge_type=qa` 的商品绑定关系,适合从 FAQ 文件视角批量维护关联商品。`--file` 为精确文件名匹配;文件名不唯一时请传 `--file-id` 和 `--partition-id`。
|
|
430
|
+
|
|
413
431
|
### 扩展知识库 (`knowledge`)
|
|
414
432
|
|
|
415
433
|
Agent 关联的通用规则知识库(`suffix_type=_common`),与 FAQ / 商品知识并列的第三类知识源,支持段落(chunk)级 CRUD,统一走 `/mebsuta/api/v1/dataset/{id}/contents/perform-operations`。
|
|
@@ -421,9 +439,15 @@ Agent 关联的通用规则知识库(`suffix_type=_common`),与 FAQ / 商
|
|
|
421
439
|
| `knowledge content add --knowledge-id <id> --content <text\|@file> [--keyword <k...>] [--after <chunk_id>]` | 新增段落 |
|
|
422
440
|
| `knowledge content update --knowledge-id <id> --chunk-id <id> [--content <text\|@file>] [--keyword <k...>] [--enable \| --disable]` | 更新段落(四个变更字段至少一个;未指定 `--enable` / `--disable` 时自动保留当前启停状态,避免后端 enable 必填校验失败) |
|
|
423
441
|
| `knowledge content delete --knowledge-id <id> --chunk-id <id>` | 删除段落 |
|
|
442
|
+
| `knowledge bind-products list --agent <id> (--file <文件名> \| --file-id <id> --partition-id <id>)` | 列出扩展知识文件绑定的商品 |
|
|
443
|
+
| `knowledge bind-products add --agent <id> (--file <文件名> \| --file-id <id> --partition-id <id>) --product-id <商品ID...>` | 给扩展知识文件追加绑定商品 |
|
|
444
|
+
| `knowledge bind-products remove --agent <id> (--file <文件名> \| --file-id <id> --partition-id <id>) --product-id <商品ID...>` | 从扩展知识文件移除绑定商品 |
|
|
445
|
+
| `knowledge bind-products set --agent <id> (--file <文件名> \| --file-id <id> --partition-id <id>) --product-id <商品ID...>` | 覆盖扩展知识文件绑定的全部商品 |
|
|
424
446
|
|
|
425
447
|
`knowledge content add` / `update` 的 `--content` 支持 `@路径` 前缀从文件读取**纯文本**(不是 JSON)。`--keyword` 为 variadic 选项,空格分隔多个关键词。
|
|
426
448
|
|
|
449
|
+
`knowledge bind-products` 固定写入 `knowledge_type=common` 的商品绑定关系,适合从扩展知识文件视角批量维护关联商品。`add` / `remove` 会 read-modify-replace,重复添加或移除不存在的商品保持幂等。
|
|
450
|
+
|
|
427
451
|
|
|
428
452
|
### 会话管理 (`conversation`)
|
|
429
453
|
|
|
@@ -453,6 +477,14 @@ Agent 关联的通用规则知识库(`suffix_type=_common`),与 FAQ / 商
|
|
|
453
477
|
|
|
454
478
|
`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` 字段获取。
|
|
455
479
|
|
|
480
|
+
### 工作空间 (`workspace`)
|
|
481
|
+
|
|
482
|
+
| 命令 | 说明 |
|
|
483
|
+
| --- | --- |
|
|
484
|
+
| `workspace list` | 列出当前账号可访问的工作空间 |
|
|
485
|
+
| `workspace points-consumes [--page <n>] [--page-size <n>]` | 分页查询积分账户消耗流水,固定返回 `extra` 调试字段 |
|
|
486
|
+
| `workspace points-consumes-daily [--start <YYYY-MM-DD>] [--end <YYYY-MM-DD>]` | 按天查询积分消耗趋势 |
|
|
487
|
+
|
|
456
488
|
- `--env <dev|prod>`:指定 Langfuse 环境,默认 `prod`。只接受 `dev` / `prod`,传其它值命令直接报错并以非 0 退出(不发请求)。
|
|
457
489
|
|
|
458
490
|
```bash
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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) {
|
|
@@ -2064,6 +2101,442 @@ async function deleteFaqGroup(opts) {
|
|
|
2064
2101
|
);
|
|
2065
2102
|
}
|
|
2066
2103
|
|
|
2104
|
+
// src/client/knowledge-api.ts
|
|
2105
|
+
async function listExternalKnowledge(opts) {
|
|
2106
|
+
const request = createRequest();
|
|
2107
|
+
return request(getCustomerServiceUrl(), "/v1/knowledge/external", {
|
|
2108
|
+
method: "GET",
|
|
2109
|
+
query: {
|
|
2110
|
+
customer_agent_config_id: opts.agentConfigId,
|
|
2111
|
+
page: opts.page ?? 1,
|
|
2112
|
+
page_size: opts.pageSize ?? 20,
|
|
2113
|
+
suffix_type: "_common"
|
|
2114
|
+
}
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2117
|
+
async function listKnowledgeContents(opts) {
|
|
2118
|
+
const request = createRequest();
|
|
2119
|
+
return request(getAiApiUrl(), `/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents`, {
|
|
2120
|
+
method: "GET",
|
|
2121
|
+
query: {
|
|
2122
|
+
page_size: opts.pageSize ?? 20,
|
|
2123
|
+
need_total: opts.needTotal ?? true,
|
|
2124
|
+
direction: opts.direction ?? "down"
|
|
2125
|
+
}
|
|
2126
|
+
});
|
|
2127
|
+
}
|
|
2128
|
+
async function addKnowledgeContent(opts) {
|
|
2129
|
+
const request = createRequest();
|
|
2130
|
+
const ts = (opts.now ?? Date.now)();
|
|
2131
|
+
const identifier = `temp_${ts}`;
|
|
2132
|
+
const body = {
|
|
2133
|
+
operations: [
|
|
2134
|
+
{
|
|
2135
|
+
action: "add",
|
|
2136
|
+
original_identifier: opts.afterChunkId ?? "0",
|
|
2137
|
+
identifier
|
|
2138
|
+
}
|
|
2139
|
+
],
|
|
2140
|
+
content_updates: { [identifier]: opts.content },
|
|
2141
|
+
keywords_updates: { [identifier]: opts.keywords ?? [] },
|
|
2142
|
+
extra_info_updates: { [identifier]: { chunk_status: "done" } }
|
|
2143
|
+
};
|
|
2144
|
+
return request(
|
|
2145
|
+
getAiApiUrl(),
|
|
2146
|
+
`/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
|
|
2147
|
+
{
|
|
2148
|
+
method: "POST",
|
|
2149
|
+
body
|
|
2150
|
+
}
|
|
2151
|
+
);
|
|
2152
|
+
}
|
|
2153
|
+
async function updateKnowledgeContent(opts) {
|
|
2154
|
+
const request = createRequest();
|
|
2155
|
+
const operation = {
|
|
2156
|
+
action: "update",
|
|
2157
|
+
identifier: opts.chunkId,
|
|
2158
|
+
enable: opts.enable
|
|
2159
|
+
};
|
|
2160
|
+
const contentUpdates = opts.content !== void 0 ? { [opts.chunkId]: opts.content } : {};
|
|
2161
|
+
const keywordsUpdates = opts.keywords !== void 0 ? { [opts.chunkId]: opts.keywords } : {};
|
|
2162
|
+
const extraInfoUpdates = opts.content !== void 0 || opts.keywords !== void 0 ? { [opts.chunkId]: { chunk_status: "done" } } : {};
|
|
2163
|
+
const body = {
|
|
2164
|
+
operations: [operation],
|
|
2165
|
+
content_updates: contentUpdates,
|
|
2166
|
+
keywords_updates: keywordsUpdates,
|
|
2167
|
+
extra_info_updates: extraInfoUpdates
|
|
2168
|
+
};
|
|
2169
|
+
return request(
|
|
2170
|
+
getAiApiUrl(),
|
|
2171
|
+
`/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
|
|
2172
|
+
{
|
|
2173
|
+
method: "POST",
|
|
2174
|
+
body
|
|
2175
|
+
}
|
|
2176
|
+
);
|
|
2177
|
+
}
|
|
2178
|
+
async function findKnowledgeChunk(opts) {
|
|
2179
|
+
const result = await listKnowledgeContents({
|
|
2180
|
+
knowledgeId: opts.knowledgeId,
|
|
2181
|
+
pageSize: opts.pageSize ?? 500,
|
|
2182
|
+
needTotal: true,
|
|
2183
|
+
direction: "down"
|
|
2184
|
+
});
|
|
2185
|
+
return result.contents?.find((c) => c.chunk_id === opts.chunkId);
|
|
2186
|
+
}
|
|
2187
|
+
async function deleteKnowledgeContent(opts) {
|
|
2188
|
+
const request = createRequest();
|
|
2189
|
+
const body = {
|
|
2190
|
+
operations: [{ action: "delete", identifier: opts.chunkId }],
|
|
2191
|
+
content_updates: {},
|
|
2192
|
+
keywords_updates: {},
|
|
2193
|
+
extra_info_updates: {}
|
|
2194
|
+
};
|
|
2195
|
+
return request(
|
|
2196
|
+
getAiApiUrl(),
|
|
2197
|
+
`/mebsuta/api/v1/dataset/${opts.knowledgeId}/contents/perform-operations`,
|
|
2198
|
+
{
|
|
2199
|
+
method: "POST",
|
|
2200
|
+
body
|
|
2201
|
+
}
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
// src/client/product-knowledge-binding-api.ts
|
|
2206
|
+
var PATH_PREFIX2 = "/v1/knowledge/product-bindings";
|
|
2207
|
+
async function listProductKnowledgeBindings(opts) {
|
|
2208
|
+
const request = createRequest();
|
|
2209
|
+
return request(getCustomerServiceUrl(), PATH_PREFIX2, {
|
|
2210
|
+
method: "GET",
|
|
2211
|
+
query: {
|
|
2212
|
+
customer_agent_config_id: opts.agentConfigId,
|
|
2213
|
+
product_id: opts.productId,
|
|
2214
|
+
knowledge_type: opts.knowledgeType,
|
|
2215
|
+
file_id: opts.fileId
|
|
2216
|
+
}
|
|
2217
|
+
});
|
|
2218
|
+
}
|
|
2219
|
+
async function replaceProductKnowledgeBindingsByProduct(opts) {
|
|
2220
|
+
const request = createRequest();
|
|
2221
|
+
return request(getCustomerServiceUrl(), `${PATH_PREFIX2}/by-product`, {
|
|
2222
|
+
method: "PUT",
|
|
2223
|
+
body: {
|
|
2224
|
+
customer_agent_config_id: opts.agentConfigId,
|
|
2225
|
+
product_id: opts.productId,
|
|
2226
|
+
bindings: opts.bindings
|
|
2227
|
+
}
|
|
2228
|
+
});
|
|
2229
|
+
}
|
|
2230
|
+
async function replaceProductKnowledgeBindingsByFile(opts) {
|
|
2231
|
+
const request = createRequest();
|
|
2232
|
+
return request(getCustomerServiceUrl(), `${PATH_PREFIX2}/by-file`, {
|
|
2233
|
+
method: "PUT",
|
|
2234
|
+
body: {
|
|
2235
|
+
customer_agent_config_id: opts.agentConfigId,
|
|
2236
|
+
knowledge_type: opts.knowledgeType,
|
|
2237
|
+
file_id: opts.fileId,
|
|
2238
|
+
file_name: opts.fileName,
|
|
2239
|
+
partition_id: opts.partitionId,
|
|
2240
|
+
partition_name: opts.partitionName,
|
|
2241
|
+
products: opts.productIds.map((product_id) => ({ product_id }))
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
// src/commands/product-knowledge-binding.ts
|
|
2247
|
+
function parsePositiveInt(value, fieldName) {
|
|
2248
|
+
const n = Number(value);
|
|
2249
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
2250
|
+
throw new Error(`${fieldName} \u5FC5\u987B\u4E3A\u6B63\u6574\u6570`);
|
|
2251
|
+
}
|
|
2252
|
+
return n;
|
|
2253
|
+
}
|
|
2254
|
+
function parseKnowledgeType(value) {
|
|
2255
|
+
if (value === "qa" || value === "common") return value;
|
|
2256
|
+
throw new Error("--type \u4EC5\u63A5\u53D7 qa | common");
|
|
2257
|
+
}
|
|
2258
|
+
function dedupeStrings(values) {
|
|
2259
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2260
|
+
const result = [];
|
|
2261
|
+
for (const value of values) {
|
|
2262
|
+
const trimmed = String(value || "").trim();
|
|
2263
|
+
if (!trimmed || seen.has(trimmed)) continue;
|
|
2264
|
+
seen.add(trimmed);
|
|
2265
|
+
result.push(trimmed);
|
|
2266
|
+
}
|
|
2267
|
+
return result;
|
|
2268
|
+
}
|
|
2269
|
+
function bindingKey(item) {
|
|
2270
|
+
return `${item.knowledge_type}:${item.file_id}`;
|
|
2271
|
+
}
|
|
2272
|
+
function toBindingInput(item) {
|
|
2273
|
+
return {
|
|
2274
|
+
knowledge_type: item.knowledge_type,
|
|
2275
|
+
file_id: parsePositiveInt(item.file_id, "file_id"),
|
|
2276
|
+
file_name: item.file_name ?? null,
|
|
2277
|
+
partition_id: parsePositiveInt(item.partition_id, "partition_id"),
|
|
2278
|
+
partition_name: item.partition_name ?? null
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
function normalizeBindingInput(value) {
|
|
2282
|
+
if (!value || typeof value !== "object") {
|
|
2283
|
+
throw new Error("bindings \u6BCF\u9879\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
2284
|
+
}
|
|
2285
|
+
const item = value;
|
|
2286
|
+
return {
|
|
2287
|
+
knowledge_type: parseKnowledgeType(String(item.knowledge_type ?? "")),
|
|
2288
|
+
file_id: parsePositiveInt(item.file_id, "file_id"),
|
|
2289
|
+
file_name: item.file_name ?? null,
|
|
2290
|
+
partition_id: parsePositiveInt(item.partition_id, "partition_id"),
|
|
2291
|
+
partition_name: item.partition_name ?? null
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
function parseBindingsOption(raw) {
|
|
2295
|
+
const parsed = parseDataOption(raw);
|
|
2296
|
+
if (!Array.isArray(parsed)) {
|
|
2297
|
+
throw new Error("--bindings \u5FC5\u987B\u662F\u6570\u7EC4");
|
|
2298
|
+
}
|
|
2299
|
+
return parsed.map(normalizeBindingInput);
|
|
2300
|
+
}
|
|
2301
|
+
function fileIdOf(item) {
|
|
2302
|
+
return parsePositiveInt(item.knowledge_id ?? item.file_id, "file_id");
|
|
2303
|
+
}
|
|
2304
|
+
function partitionIdOf(item) {
|
|
2305
|
+
return parsePositiveInt(item.partition_id, "partition_id");
|
|
2306
|
+
}
|
|
2307
|
+
function failWithMessage(message) {
|
|
2308
|
+
outputError(1, message);
|
|
2309
|
+
process.exit(1);
|
|
2310
|
+
}
|
|
2311
|
+
async function listFilesByType(knowledgeType, agentConfigId) {
|
|
2312
|
+
const result = knowledgeType === "qa" ? await listFaqFiles({ agentConfigId, page: 1, pageSize: 100 }) : await listExternalKnowledge({ agentConfigId, page: 1, pageSize: 100 });
|
|
2313
|
+
return result.items ?? [];
|
|
2314
|
+
}
|
|
2315
|
+
async function resolveFile(opts) {
|
|
2316
|
+
if (opts.file && (opts.fileId || opts.partitionId)) {
|
|
2317
|
+
throw new Error("--file \u4E0E --file-id/--partition-id \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
2318
|
+
}
|
|
2319
|
+
if (opts.file) {
|
|
2320
|
+
const files = await listFilesByType(opts.knowledgeType, opts.agentConfigId);
|
|
2321
|
+
const matched = files.filter((item2) => item2.file_name === opts.file);
|
|
2322
|
+
if (matched.length === 0) {
|
|
2323
|
+
failWithMessage(`\u672A\u627E\u5230\u77E5\u8BC6\u5E93\u6587\u4EF6: ${opts.file}`);
|
|
2324
|
+
}
|
|
2325
|
+
if (matched.length > 1) {
|
|
2326
|
+
failWithMessage(`\u77E5\u8BC6\u5E93\u6587\u4EF6\u540D\u4E0D\u552F\u4E00: ${opts.file}\uFF0C\u8BF7\u6539\u7528 --file-id/--partition-id`);
|
|
2327
|
+
}
|
|
2328
|
+
const item = matched[0];
|
|
2329
|
+
return {
|
|
2330
|
+
fileId: fileIdOf(item),
|
|
2331
|
+
fileName: item.file_name ?? opts.file,
|
|
2332
|
+
partitionId: partitionIdOf(item),
|
|
2333
|
+
partitionName: item.partition_name ?? null
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
if (!opts.fileId || !opts.partitionId) {
|
|
2337
|
+
throw new Error("\u8BF7\u63D0\u4F9B --file \u6216\u540C\u65F6\u63D0\u4F9B --file-id \u4E0E --partition-id");
|
|
2338
|
+
}
|
|
2339
|
+
return {
|
|
2340
|
+
fileId: parsePositiveInt(opts.fileId, "file_id"),
|
|
2341
|
+
fileName: opts.fileName,
|
|
2342
|
+
partitionId: parsePositiveInt(opts.partitionId, "partition_id"),
|
|
2343
|
+
partitionName: opts.partitionName
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
async function replaceProductBindings(opts) {
|
|
2347
|
+
return replaceProductKnowledgeBindingsByProduct({
|
|
2348
|
+
agentConfigId: opts.agentConfigId,
|
|
2349
|
+
productId: opts.productId,
|
|
2350
|
+
bindings: opts.bindings
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
async function getProductBindingInputs(opts) {
|
|
2354
|
+
const current = await listProductKnowledgeBindings({
|
|
2355
|
+
agentConfigId: opts.agentConfigId,
|
|
2356
|
+
productId: opts.productId
|
|
2357
|
+
});
|
|
2358
|
+
return (current.items ?? []).map(toBindingInput);
|
|
2359
|
+
}
|
|
2360
|
+
async function replaceFileBindings(opts) {
|
|
2361
|
+
return replaceProductKnowledgeBindingsByFile({
|
|
2362
|
+
agentConfigId: opts.agentConfigId,
|
|
2363
|
+
knowledgeType: opts.knowledgeType,
|
|
2364
|
+
fileId: opts.file.fileId,
|
|
2365
|
+
fileName: opts.file.fileName,
|
|
2366
|
+
partitionId: opts.file.partitionId,
|
|
2367
|
+
partitionName: opts.file.partitionName,
|
|
2368
|
+
productIds: opts.productIds
|
|
2369
|
+
});
|
|
2370
|
+
}
|
|
2371
|
+
async function getFileProductIds(opts) {
|
|
2372
|
+
const current = await listProductKnowledgeBindings({
|
|
2373
|
+
agentConfigId: opts.agentConfigId,
|
|
2374
|
+
knowledgeType: opts.knowledgeType,
|
|
2375
|
+
fileId: opts.fileId
|
|
2376
|
+
});
|
|
2377
|
+
return dedupeStrings((current.items ?? []).map((item) => item.product_id));
|
|
2378
|
+
}
|
|
2379
|
+
function handleError(err) {
|
|
2380
|
+
reportCaughtError(err);
|
|
2381
|
+
process.exit(toExitCode(err));
|
|
2382
|
+
}
|
|
2383
|
+
function registerProductRelatedKnowledgeCommand(product, program2) {
|
|
2384
|
+
const related = product.command("related-knowledge").description("\u5546\u54C1\u8BE6\u60C5\u5173\u8054\u77E5\u8BC6\u5E93\u6587\u4EF6\u7BA1\u7406\uFF1Alist / add / remove / set");
|
|
2385
|
+
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) => {
|
|
2386
|
+
try {
|
|
2387
|
+
const data = await listProductKnowledgeBindings({
|
|
2388
|
+
agentConfigId: opts.agent,
|
|
2389
|
+
productId: opts.productId
|
|
2390
|
+
});
|
|
2391
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
2392
|
+
} catch (err) {
|
|
2393
|
+
handleError(err);
|
|
2394
|
+
}
|
|
2395
|
+
});
|
|
2396
|
+
related.command("add").description(
|
|
2397
|
+
"\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"
|
|
2398
|
+
).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) => {
|
|
2399
|
+
try {
|
|
2400
|
+
const knowledgeType = parseKnowledgeType(opts.type);
|
|
2401
|
+
const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
|
|
2402
|
+
const current = await getProductBindingInputs({
|
|
2403
|
+
agentConfigId: opts.agent,
|
|
2404
|
+
productId: opts.productId
|
|
2405
|
+
});
|
|
2406
|
+
const byKey = new Map(current.map((item) => [bindingKey(item), item]));
|
|
2407
|
+
byKey.set(bindingKey({ knowledge_type: knowledgeType, file_id: file.fileId }), {
|
|
2408
|
+
knowledge_type: knowledgeType,
|
|
2409
|
+
file_id: file.fileId,
|
|
2410
|
+
file_name: file.fileName ?? null,
|
|
2411
|
+
partition_id: file.partitionId,
|
|
2412
|
+
partition_name: file.partitionName ?? null
|
|
2413
|
+
});
|
|
2414
|
+
const data = await replaceProductBindings({
|
|
2415
|
+
agentConfigId: opts.agent,
|
|
2416
|
+
productId: opts.productId,
|
|
2417
|
+
bindings: Array.from(byKey.values())
|
|
2418
|
+
});
|
|
2419
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
2420
|
+
} catch (err) {
|
|
2421
|
+
handleError(err);
|
|
2422
|
+
}
|
|
2423
|
+
});
|
|
2424
|
+
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) => {
|
|
2425
|
+
try {
|
|
2426
|
+
const knowledgeType = parseKnowledgeType(opts.type);
|
|
2427
|
+
const fileId = parsePositiveInt(opts.fileId, "file_id");
|
|
2428
|
+
const current = await getProductBindingInputs({
|
|
2429
|
+
agentConfigId: opts.agent,
|
|
2430
|
+
productId: opts.productId
|
|
2431
|
+
});
|
|
2432
|
+
const next = current.filter(
|
|
2433
|
+
(item) => !(item.knowledge_type === knowledgeType && item.file_id === fileId)
|
|
2434
|
+
);
|
|
2435
|
+
const data = await replaceProductBindings({
|
|
2436
|
+
agentConfigId: opts.agent,
|
|
2437
|
+
productId: opts.productId,
|
|
2438
|
+
bindings: next
|
|
2439
|
+
});
|
|
2440
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
2441
|
+
} catch (err) {
|
|
2442
|
+
handleError(err);
|
|
2443
|
+
}
|
|
2444
|
+
});
|
|
2445
|
+
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) => {
|
|
2446
|
+
try {
|
|
2447
|
+
const bindings = parseBindingsOption(opts.bindings);
|
|
2448
|
+
const data = await replaceProductBindings({
|
|
2449
|
+
agentConfigId: opts.agent,
|
|
2450
|
+
productId: opts.productId,
|
|
2451
|
+
bindings
|
|
2452
|
+
});
|
|
2453
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
2454
|
+
} catch (err) {
|
|
2455
|
+
handleError(err);
|
|
2456
|
+
}
|
|
2457
|
+
});
|
|
2458
|
+
}
|
|
2459
|
+
function registerKnowledgeFileBindProductsCommand(parent, program2, kind) {
|
|
2460
|
+
const knowledgeType = kind === "faq" ? "qa" : "common";
|
|
2461
|
+
const bind = parent.command("bind-products").description("\u77E5\u8BC6\u5E93\u6587\u4EF6\u7ED1\u5B9A\u5546\u54C1\u7BA1\u7406\uFF1Alist / add / remove / set");
|
|
2462
|
+
function addFileOptions(command) {
|
|
2463
|
+
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");
|
|
2464
|
+
}
|
|
2465
|
+
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) => {
|
|
2466
|
+
try {
|
|
2467
|
+
const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
|
|
2468
|
+
const data = await listProductKnowledgeBindings({
|
|
2469
|
+
agentConfigId: opts.agent,
|
|
2470
|
+
knowledgeType,
|
|
2471
|
+
fileId: file.fileId
|
|
2472
|
+
});
|
|
2473
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
2474
|
+
} catch (err) {
|
|
2475
|
+
handleError(err);
|
|
2476
|
+
}
|
|
2477
|
+
});
|
|
2478
|
+
addFileOptions(
|
|
2479
|
+
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")
|
|
2480
|
+
).action(async (opts) => {
|
|
2481
|
+
try {
|
|
2482
|
+
const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
|
|
2483
|
+
const currentIds = await getFileProductIds({
|
|
2484
|
+
agentConfigId: opts.agent,
|
|
2485
|
+
knowledgeType,
|
|
2486
|
+
fileId: file.fileId
|
|
2487
|
+
});
|
|
2488
|
+
const productIds = dedupeStrings([...currentIds, ...opts.productId ?? []]);
|
|
2489
|
+
const data = await replaceFileBindings({
|
|
2490
|
+
agentConfigId: opts.agent,
|
|
2491
|
+
knowledgeType,
|
|
2492
|
+
file,
|
|
2493
|
+
productIds
|
|
2494
|
+
});
|
|
2495
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
2496
|
+
} catch (err) {
|
|
2497
|
+
handleError(err);
|
|
2498
|
+
}
|
|
2499
|
+
});
|
|
2500
|
+
addFileOptions(
|
|
2501
|
+
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")
|
|
2502
|
+
).action(async (opts) => {
|
|
2503
|
+
try {
|
|
2504
|
+
const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
|
|
2505
|
+
const removing = new Set(dedupeStrings(opts.productId ?? []));
|
|
2506
|
+
const currentIds = await getFileProductIds({
|
|
2507
|
+
agentConfigId: opts.agent,
|
|
2508
|
+
knowledgeType,
|
|
2509
|
+
fileId: file.fileId
|
|
2510
|
+
});
|
|
2511
|
+
const data = await replaceFileBindings({
|
|
2512
|
+
agentConfigId: opts.agent,
|
|
2513
|
+
knowledgeType,
|
|
2514
|
+
file,
|
|
2515
|
+
productIds: currentIds.filter((productId) => !removing.has(productId))
|
|
2516
|
+
});
|
|
2517
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
2518
|
+
} catch (err) {
|
|
2519
|
+
handleError(err);
|
|
2520
|
+
}
|
|
2521
|
+
});
|
|
2522
|
+
addFileOptions(
|
|
2523
|
+
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")
|
|
2524
|
+
).action(async (opts) => {
|
|
2525
|
+
try {
|
|
2526
|
+
const file = await resolveFile({ ...opts, agentConfigId: opts.agent, knowledgeType });
|
|
2527
|
+
const data = await replaceFileBindings({
|
|
2528
|
+
agentConfigId: opts.agent,
|
|
2529
|
+
knowledgeType,
|
|
2530
|
+
file,
|
|
2531
|
+
productIds: dedupeStrings(opts.productId ?? [])
|
|
2532
|
+
});
|
|
2533
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
2534
|
+
} catch (err) {
|
|
2535
|
+
handleError(err);
|
|
2536
|
+
}
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2067
2540
|
// src/commands/faq.ts
|
|
2068
2541
|
function parseQuestions(input) {
|
|
2069
2542
|
return input.split(",").map((q) => q.trim()).filter((q) => q.length > 0).map((q) => ({ content: q, keywords: [], enable: true }));
|
|
@@ -2196,6 +2669,7 @@ function registerFaqCommand(program2) {
|
|
|
2196
2669
|
process.exit(toExitCode(err));
|
|
2197
2670
|
}
|
|
2198
2671
|
});
|
|
2672
|
+
registerKnowledgeFileBindProductsCommand(faq, program2, "faq");
|
|
2199
2673
|
}
|
|
2200
2674
|
|
|
2201
2675
|
// src/client/issue-api.ts
|
|
@@ -2261,11 +2735,9 @@ async function getIssueStats(opts) {
|
|
|
2261
2735
|
const query = {};
|
|
2262
2736
|
if (opts.dateStart) query.date_start = opts.dateStart;
|
|
2263
2737
|
if (opts.dateEnd) query.date_end = opts.dateEnd;
|
|
2264
|
-
const result = await request(
|
|
2738
|
+
const result = await request(getCsAdminUrl(), "/api/issues/stats", {
|
|
2265
2739
|
method: "GET",
|
|
2266
|
-
query
|
|
2267
|
-
headers: buildCookieHeaders(),
|
|
2268
|
-
skipAuth: true
|
|
2740
|
+
query
|
|
2269
2741
|
});
|
|
2270
2742
|
return result.data ?? result;
|
|
2271
2743
|
}
|
|
@@ -2965,109 +3437,6 @@ async function resolveSessionsForIssues(issues, workspaceId) {
|
|
|
2965
3437
|
|
|
2966
3438
|
// src/commands/knowledge.ts
|
|
2967
3439
|
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
|
|
3040
|
-
}
|
|
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
|
-
});
|
|
3050
|
-
return result.contents?.find((c) => c.chunk_id === opts.chunkId);
|
|
3051
|
-
}
|
|
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
|
|
3066
|
-
}
|
|
3067
|
-
);
|
|
3068
|
-
}
|
|
3069
|
-
|
|
3070
|
-
// src/commands/knowledge.ts
|
|
3071
3440
|
function readContentArg(value) {
|
|
3072
3441
|
if (value.startsWith("@")) {
|
|
3073
3442
|
return fs8.readFileSync(value.slice(1), "utf-8");
|
|
@@ -3203,6 +3572,7 @@ function registerKnowledgeCommand(program2) {
|
|
|
3203
3572
|
process.exit(toExitCode(err));
|
|
3204
3573
|
}
|
|
3205
3574
|
});
|
|
3575
|
+
registerKnowledgeFileBindProductsCommand(knowledge, program2, "common");
|
|
3206
3576
|
}
|
|
3207
3577
|
|
|
3208
3578
|
// src/client/monitor-api.ts
|
|
@@ -4136,7 +4506,7 @@ function registerOpsAgentCommand(program2) {
|
|
|
4136
4506
|
}
|
|
4137
4507
|
|
|
4138
4508
|
// src/client/operations-record-api.ts
|
|
4139
|
-
var
|
|
4509
|
+
var PATH_PREFIX3 = "/v1/agent_operations_records";
|
|
4140
4510
|
async function listOperationsRecords(opts) {
|
|
4141
4511
|
const request = createRequest();
|
|
4142
4512
|
const query = {};
|
|
@@ -4144,34 +4514,34 @@ async function listOperationsRecords(opts) {
|
|
|
4144
4514
|
if (opts.agentId) query.agent_id = opts.agentId;
|
|
4145
4515
|
if (opts.page) query.page = opts.page;
|
|
4146
4516
|
if (opts.pageSize) query.page_size = opts.pageSize;
|
|
4147
|
-
return request(getCustomerServiceUrl(),
|
|
4517
|
+
return request(getCustomerServiceUrl(), PATH_PREFIX3, {
|
|
4148
4518
|
method: "GET",
|
|
4149
4519
|
query
|
|
4150
4520
|
});
|
|
4151
4521
|
}
|
|
4152
4522
|
async function getOperationsRecord(recordId) {
|
|
4153
4523
|
const request = createRequest();
|
|
4154
|
-
return request(getCustomerServiceUrl(), `${
|
|
4524
|
+
return request(getCustomerServiceUrl(), `${PATH_PREFIX3}/${recordId}`, {
|
|
4155
4525
|
method: "GET"
|
|
4156
4526
|
});
|
|
4157
4527
|
}
|
|
4158
4528
|
async function createOperationsRecord(data) {
|
|
4159
4529
|
const request = createRequest();
|
|
4160
|
-
return request(getCustomerServiceUrl(),
|
|
4530
|
+
return request(getCustomerServiceUrl(), PATH_PREFIX3, {
|
|
4161
4531
|
method: "POST",
|
|
4162
4532
|
body: data
|
|
4163
4533
|
});
|
|
4164
4534
|
}
|
|
4165
4535
|
async function updateOperationsRecord(recordId, data) {
|
|
4166
4536
|
const request = createRequest();
|
|
4167
|
-
return request(getCustomerServiceUrl(), `${
|
|
4537
|
+
return request(getCustomerServiceUrl(), `${PATH_PREFIX3}/${recordId}`, {
|
|
4168
4538
|
method: "PUT",
|
|
4169
4539
|
body: data
|
|
4170
4540
|
});
|
|
4171
4541
|
}
|
|
4172
4542
|
async function deleteOperationsRecord(recordId) {
|
|
4173
4543
|
const request = createRequest();
|
|
4174
|
-
return request(getCustomerServiceUrl(), `${
|
|
4544
|
+
return request(getCustomerServiceUrl(), `${PATH_PREFIX3}/${recordId}`, {
|
|
4175
4545
|
method: "DELETE"
|
|
4176
4546
|
});
|
|
4177
4547
|
}
|
|
@@ -4558,10 +4928,11 @@ function registerProductCommand(program2) {
|
|
|
4558
4928
|
process.exit(toExitCode(err));
|
|
4559
4929
|
}
|
|
4560
4930
|
});
|
|
4931
|
+
registerProductRelatedKnowledgeCommand(product, program2);
|
|
4561
4932
|
}
|
|
4562
4933
|
|
|
4563
4934
|
// src/client/repair-record-api.ts
|
|
4564
|
-
var
|
|
4935
|
+
var PATH_PREFIX4 = "/api/repair-records";
|
|
4565
4936
|
async function listRepairRecords(opts) {
|
|
4566
4937
|
const request = createRequest();
|
|
4567
4938
|
const query = {};
|
|
@@ -4570,21 +4941,21 @@ async function listRepairRecords(opts) {
|
|
|
4570
4941
|
if (opts.workspaceId) query.workspace_id = opts.workspaceId;
|
|
4571
4942
|
if (opts.page) query.page = opts.page;
|
|
4572
4943
|
if (opts.pageSize) query.page_size = opts.pageSize;
|
|
4573
|
-
return request(getCsAdminUrl(),
|
|
4944
|
+
return request(getCsAdminUrl(), PATH_PREFIX4, {
|
|
4574
4945
|
method: "GET",
|
|
4575
4946
|
query
|
|
4576
4947
|
});
|
|
4577
4948
|
}
|
|
4578
4949
|
async function createRepairRecord(data) {
|
|
4579
4950
|
const request = createRequest();
|
|
4580
|
-
return request(getCsAdminUrl(),
|
|
4951
|
+
return request(getCsAdminUrl(), PATH_PREFIX4, {
|
|
4581
4952
|
method: "POST",
|
|
4582
4953
|
body: data
|
|
4583
4954
|
});
|
|
4584
4955
|
}
|
|
4585
4956
|
async function updateRepairRecord(recordId, data) {
|
|
4586
4957
|
const request = createRequest();
|
|
4587
|
-
return request(getCsAdminUrl(), `${
|
|
4958
|
+
return request(getCsAdminUrl(), `${PATH_PREFIX4}/${recordId}`, {
|
|
4588
4959
|
method: "PUT",
|
|
4589
4960
|
body: data
|
|
4590
4961
|
});
|
|
@@ -5661,6 +6032,23 @@ function registerWorkspaceCommand(program2) {
|
|
|
5661
6032
|
process.exit(toExitCode(err));
|
|
5662
6033
|
}
|
|
5663
6034
|
});
|
|
6035
|
+
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) => {
|
|
6036
|
+
try {
|
|
6037
|
+
const page = Number(opts.page);
|
|
6038
|
+
const pageSize = Number(opts.pageSize);
|
|
6039
|
+
if (!Number.isInteger(page) || page <= 0) {
|
|
6040
|
+
throw new Error("--page \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
|
|
6041
|
+
}
|
|
6042
|
+
if (!Number.isInteger(pageSize) || pageSize <= 0) {
|
|
6043
|
+
throw new Error("--page-size \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
|
|
6044
|
+
}
|
|
6045
|
+
const data = await getPointsConsumes({ page, pageSize });
|
|
6046
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
6047
|
+
} catch (err) {
|
|
6048
|
+
reportCaughtError(err);
|
|
6049
|
+
process.exit(toExitCode(err));
|
|
6050
|
+
}
|
|
6051
|
+
});
|
|
5664
6052
|
workspace.command("points-consumes-daily").description(
|
|
5665
6053
|
"\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
6054
|
).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) => {
|