@bty/customer-service-cli 0.6.6 → 0.6.8
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 +30 -1
- package/README.md +21 -1
- package/dist/bin.js +597 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Unreleased
|
|
4
4
|
|
|
5
5
|
- 新增 `media upload` 命令与 `product supplement` 子命令组,支持商品「补充知识」图片/视频维护,与前端上传行为一致:
|
|
6
6
|
- `media upload --file <path> --type image|video [--path-prefix /ai/knowledge/supplement] [--dry-run]`:本地图片/视频先经 `/v1/upload_sts` 取 STS 凭证上传到公开 OSS(`resource_bucket`),返回公网 URL;已是 http(s) URL 直接拒绝(无需上传)。上传 key 与前端一致:`${prefix}/${timestamp}_${filename}`。图片上限 10MB、视频上限 200MB,超限/类型不符在发起上传请求前直接失败。
|
|
@@ -9,6 +9,24 @@
|
|
|
9
9
|
- `product supplement append-media --agent <id> --product-id <id> --index <n> [--image ...] [--video ...] [--dry-run] [--backup <path>]`:仅向目标下标条目追加媒体,其它条目原样保留;去重合并,未提供任何媒体时报错。
|
|
10
10
|
- Dashboard 命令使用客服 API 原域名下的 `/observability` 网关前缀,无需新增地址配置。
|
|
11
11
|
|
|
12
|
+
## 0.6.8 (2026-08-10)
|
|
13
|
+
|
|
14
|
+
- `conversation transfer-human` 新增 `--only-abnormal`:默认仍返回全部转人工会话;开启后仅保留异常会话,排除正常 SOP 转人工、`专家agent无法回答`、`存在无法处理的消息类型:...` 三类正常情况。
|
|
15
|
+
|
|
16
|
+
## 0.6.7 (2026-07-30)
|
|
17
|
+
|
|
18
|
+
> 版本号说明:registry 实际发布序列 0.6.2 → 0.6.4 → 0.6.5 → 0.6.6(0.6.3 从未发布,0.6.4–0.6.6 由其它分支占用),故本条目落 0.6.7。
|
|
19
|
+
|
|
20
|
+
- `tool workflow` 子组新增 `create` / `update` / `delete` / `describe`,直连 BetterYeah 平台(`ai-api`)程序化管理工作流(flow)本体(既有 `list` / `detail` 走 servhub 代理不变)。CODE 节点只支持 JavaScript:
|
|
21
|
+
- `tool workflow create --name <名称> --code <code|@file> [--description] [--input-vars <json|@file>] [--no-publish] [--code-node-name]`:程序生成固定 START→CODE→END 三节点骨架(`POST /v1/applications`,`config` 以 JSON 字符串提交),把 JavaScript 代码写进 CODE 节点,默认自动发布;返回 `flow_id` / `version_id` 供 `tool create --source-id` 绑定。骨架结构以真实生产 flow 实测为准(dashed-UUID 节点 id、CODE 节点默认名 `javascript_1`)。
|
|
22
|
+
- `tool workflow update <flow_id> --code <code|@file> [--no-publish]`:先 `GET /v1/applications/{id}` 取 config,定位唯一 CODE 节点替换其代码(`config` 以对象提交,与 create 的字符串相反),默认取草稿后发布;非唯一 CODE 节点 / config 形状异常在发更新前报清晰错误,不发请求。
|
|
23
|
+
- `tool workflow run <flow_id> [--input <json|@file>]`:HTTP 同步运行已发布 flow——自动 `GET /v1/workspaces/getKey/{ws}`(登录态)换应用态 Access-Key,再 `POST /v1/public_api/rest_api/{flow_id}/execute_flow`,返回 `task_id` / `status` / `run_result`;替代平台画布的 wss 执行通道(`ws_execute_flow`),实测两通道 `run_result` 一致。
|
|
24
|
+
- `tool workflow delete <flow_id> --yes`:硬删除(`DELETE /v1/applications/{id}`),缺 `--yes` 拒绝并提示。
|
|
25
|
+
- `tool workflow describe`:输出 CODE 节点(JavaScript)使用文档,依据官方「JavaScript&Python 节点」文档整理——入口 `async main()`、变量注入(START formConfig 的 `dialogue` 等)、返回值约定(裸对象、可序列化、勿套 `{data:{...}}` 信封)、内置包(CommonJS `require`:axios/dayjs/crypto)、`betteryeah` SDK(llm/knowledge/database/plugin/subFlow)与 `betterAI` 运行时对象。
|
|
26
|
+
- `tool workflow create/update` 新增 `--version-desc <text>`:发布时透传平台 `version_desc`(版本历史可见,便于区分 CLI 改动);不传则不带该键,`--no-publish` 时忽略。
|
|
27
|
+
- `--code` / `--input-vars` 的值支持 `@文件路径` 读取;文件不存在时给出指向 `@` 前缀语义的可操作报错,不发请求。
|
|
28
|
+
- 新增 `flow-skeleton`(纯函数骨架生成器)+ `flow-api` 客户端封装;URL path 段的 `flow_id` 统一 `encodeURIComponent`(对齐本仓既有防注入约定)。CLI 不改任何后端,不复刻 servhub 受保护模板名单——受保护 flow 由平台在 update/delete 时拒绝,CLI 如实透传。
|
|
29
|
+
|
|
12
30
|
## 0.6.5 (2026-07-14)
|
|
13
31
|
|
|
14
32
|
- `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。
|
|
@@ -23,6 +41,17 @@
|
|
|
23
41
|
|
|
24
42
|
- 修复 `product update` / `product update-sku` 在商品数超过 100 时,对位置靠后的商品报「未找到商品 product_id=xxx」的问题:`findProduct` 由只取第一页(`page:1, pageSize:100`)改为翻页查找,直到命中目标商品或翻完所有页。
|
|
25
43
|
|
|
44
|
+
## 0.6.3 (2026-06-24 · 未发布,tool 命令组实际随 0.6.7 发布)
|
|
45
|
+
|
|
46
|
+
- 新增 `tool` 命令组,包装 customer-servhub-api 现有 `/v1/tool` 接口管理 Agent 的自定义/覆盖工具(增删改查):
|
|
47
|
+
- `tool list --agent <id>`:列出该 Agent 配置已绑定的工具(custom + system)。
|
|
48
|
+
- `tool create --agent <id> --name <名称> --key <标识> --source-id <flow_id> [--description] [--source-type] [--invocation-mode] [--input-vars <json>]`:创建绑定工作流(flow)的自定义工具;`source_type` 默认 `flow`、`invocation_mode` 默认 `on_demand`、`workspace_id` 由当前工作空间回填。
|
|
49
|
+
- `tool update <tool_id> [...]`:局部更新,仅透传实际提供的字段(蛇形键名映射,未提供字段不进请求体)。
|
|
50
|
+
- `tool delete <tool_id>`:软删除工具。
|
|
51
|
+
- `tool workflow list [--keyword]` / `tool workflow detail <flow_id>`:发现可绑定工作流及其入参,辅助 `create` 取 `source_id` / 填 `--input-vars`。
|
|
52
|
+
- 非法 `--invocation-mode` 在发请求前本地报错(可选值 `must_invoke` / `on_demand` / `on_demand_async`)。
|
|
53
|
+
- 新增 `tool-api` 客户端封装,仅消费现有接口;CLI 不改变服务端工具表或 sop-engine 的工具执行逻辑。
|
|
54
|
+
|
|
26
55
|
## 0.6.2 (2026-06-15)
|
|
27
56
|
|
|
28
57
|
- `workspace` 新增 `points-consumes` 子命令:分页查询当前工作空间的积分账户消耗流水(`POST /v1/workspace/points_consumes`),支持 `--page` / `--page-size`,CLI 固定传 `debug: true`,返回中包含服务端 `extra` 调试字段。
|
package/README.md
CHANGED
|
@@ -217,6 +217,26 @@ cs-cli workspace points-consumes-daily --start 2026-04-01 --end 2026-04-23
|
|
|
217
217
|
| `sa delete --agent <id> --id <SA_ID> --first-label <一级标签> --second-label <二级标签>` | 删除场景动作 |
|
|
218
218
|
| `sa versions --agent <id> --id <SA_ID>` | 查看修改记录 |
|
|
219
219
|
|
|
220
|
+
### 工具 (`tool`)
|
|
221
|
+
|
|
222
|
+
| 命令 | 说明 |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| `tool list --agent <id>` | 列出该 Agent 配置已绑定的工具(custom + system) |
|
|
225
|
+
| `tool create --agent <id> --name <名称> --key <标识> --source-id <flow_id> [--description <描述>] [--source-type <类型>] [--invocation-mode <模式>] [--input-vars <json>]` | 创建绑定工作流(flow)的自定义工具 |
|
|
226
|
+
| `tool update <tool_id> [--name <名称>] [--key <标识>] [--description <描述>] [--source-id <flow_id>] [--invocation-mode <模式>] [--input-vars <json>]` | 更新工具(仅透传实际提供的字段) |
|
|
227
|
+
| `tool delete <tool_id>` | 删除(软删除)指定工具 |
|
|
228
|
+
| `tool workflow list [--keyword <关键词>]` | 搜索可绑定的工作流(flow),取 `source_id` |
|
|
229
|
+
| `tool workflow detail <flow_id>` | 查看工作流入参,辅助填 `--input-vars` |
|
|
230
|
+
| `tool workflow create --name <名称> --code <code\|@file> [--description <描述>] [--input-vars <json\|@file>] [--no-publish] [--code-node-name <名称>] [--version-desc <描述>]` | 创建 START→CODE→END 骨架工作流,CODE 节点承载工具代码(仅 JavaScript),默认自动发布 |
|
|
231
|
+
| `tool workflow update <flow_id> --code <code\|@file> [--no-publish] [--version-desc <描述>]` | 只更新工作流唯一 CODE 节点的代码(其它节点原样保留),默认自动发布 |
|
|
232
|
+
| `tool workflow run <flow_id> [--input <json\|@file>]` | 运行已发布的工作流(HTTP 同步执行),返回 `task_id` / `status` / `run_result` |
|
|
233
|
+
| `tool workflow delete <flow_id> --yes` | 硬删除工作流(不可恢复);缺 `--yes` 拒绝执行 |
|
|
234
|
+
| `tool workflow describe` | 输出 CODE 节点(JavaScript)使用文档:入口/变量注入/返回值/内置包/SDK,依据官方文档整理 |
|
|
235
|
+
|
|
236
|
+
`tool` 命令组包装 customer-servhub-api 现有 `/v1/tool` 接口,管理 Agent 的自定义/覆盖工具;CLI 不改变服务端工具表或 sop-engine 的工具执行逻辑。`--invocation-mode` 取值 `must_invoke` / `on_demand`(默认)/ `on_demand_async`,非法值在发请求前本地报错;`tool create --input-vars` 接受 JSON 字符串,形如 `{"order_id":{"description":"订单号","type":"string","required":true}}`,对应工作流入参描述;`workspace_id` 由当前工作空间自动回填。
|
|
237
|
+
|
|
238
|
+
`tool workflow create/update/run/delete` 直连 BetterYeah 平台(`ai-api`)程序化管理工作流本体:`create` 生成固定 START→CODE→END 三节点骨架并把代码写进 CODE 节点、默认发布,返回 `flow_id` 供 `tool create --source-id` 绑定;`update` 只暴露 CODE 节点代码的修改;`run` 是 HTTP 同步执行(自动经 `GET /v1/workspaces/getKey/{ws}` 用登录态换应用态 Access-Key 再调 `execute_flow`,替代平台画布的 wss 通道),`--input` 的键对应 START `formConfig` 的 `variableName`(默认 `{}`);`delete` 是硬删除、必须显式 `--yes`。create/update 发布时可用 `--version-desc` 附版本描述(平台版本历史里可见,便于区分 CLI 改动;`--no-publish` 时忽略)。CODE 节点只支持 JavaScript(CommonJS `require`,不支持 ES Module)。`--code` / `--input-vars` 的值以 `@` 开头时按文件路径读取(如 `@./tool.js`)。注意 `tool workflow create --input-vars` 覆盖的是 START 节点的 `formConfig` 入参声明,与 `tool create --input-vars`(工具记录的 `input_var_descriptions`)是不同字段。`tool workflow describe` 输出依据[官方 JavaScript&Python 节点文档](https://ai-docs.betteryeah.com/Flow/节点介绍与配置/JavaScript&Python节点.html)整理的 CODE 节点使用文档(入口 `main()`、变量注入、返回值约定、内置包、BetterYeah SDK),AI 编写工具代码前应先读。
|
|
239
|
+
|
|
220
240
|
### 商品管理 (`product`)
|
|
221
241
|
|
|
222
242
|
| 命令 | 说明 |
|
|
@@ -500,7 +520,7 @@ Agent 关联的通用规则知识库(`suffix_type=_common`),与 FAQ / 商
|
|
|
500
520
|
| `conversation list [--agent <id>] [--equipment-id <设备ID>] [--user <用户名>] [--start <日期>] [--end <日期>]` | 搜索会话 |
|
|
501
521
|
| `conversation records <conversation_id> [--page-size N] [--direction prev|next]` | 获取会话聊天记录 |
|
|
502
522
|
| `conversation context-search --query <文本> [--start <时间>] [--end <时间>]` | 通过上下文内容模糊搜索对话记录(返回匹配消息详情,时间范围最多 3 天) |
|
|
503
|
-
| `conversation transfer-human --agent <customer_agent_config_id> --start <时间> --end
|
|
523
|
+
| `conversation transfer-human --agent <customer_agent_config_id> --start <时间> --end <时间> [--only-abnormal]` | 查询转人工会话及对应转人工消息记录(时间范围最多 7 天,自动 cursor 翻页;`--only-abnormal` 仅保留异常会话) |
|
|
504
524
|
|
|
505
525
|
|
|
506
526
|
### Agent 调试 (`debug`)
|
package/dist/bin.js
CHANGED
|
@@ -526,6 +526,7 @@ async function listActivities(opts) {
|
|
|
526
526
|
page_size: opts.pageSize ?? 20
|
|
527
527
|
};
|
|
528
528
|
if (opts.search) query.search = opts.search;
|
|
529
|
+
if (opts.state) query.state = opts.state;
|
|
529
530
|
return request(getCustomerServiceUrl(), `${PATH_PREFIX}/list`, {
|
|
530
531
|
method: "GET",
|
|
531
532
|
query
|
|
@@ -615,6 +616,11 @@ function parseEnabledFlag(raw) {
|
|
|
615
616
|
if (raw === "false") return false;
|
|
616
617
|
throw new Error("--enabled \u4EC5\u63A5\u53D7 true | false");
|
|
617
618
|
}
|
|
619
|
+
var VALID_LIST_STATES = ["all", "pending", "ongoing", "ended"];
|
|
620
|
+
function parseStateFlag(raw) {
|
|
621
|
+
if (VALID_LIST_STATES.includes(raw)) return raw;
|
|
622
|
+
throw new Error(`--state \u4EC5\u63A5\u53D7 ${VALID_LIST_STATES.join(" | ")}`);
|
|
623
|
+
}
|
|
618
624
|
function parseActivityId(raw) {
|
|
619
625
|
const n = Number(raw);
|
|
620
626
|
if (!Number.isInteger(n) || n <= 0) {
|
|
@@ -627,14 +633,18 @@ function registerActivityCommand(program2) {
|
|
|
627
633
|
"\u6D3B\u52A8 V2 \u7BA1\u7406 \u2014\u2014 \u589E\u5220\u6539\u67E5\u6D3B\u52A8\u3001\u6309\u5546\u54C1\u53CD\u67E5\u3001\u5355\u6761\u542F\u7528 toggle\u3001per-tenant V2 \u603B\u5F00\u5173\u3002\u670D\u52A1\u7AEF\uFF1Acustomer-servhub-api /v1/activity*\uFF1B\u5951\u7EA6\u53C2\u8003 docs/devkit/specs/2026-05-28-activity-v2-api-reference.md"
|
|
628
634
|
);
|
|
629
635
|
activity.command("list").description(
|
|
630
|
-
"\u5217\u51FA\u6D3B\u52A8\uFF08\u5206\u9875 + \u540D\u79F0\u641C\u7D22\uFF09\u3002\u8FD4\u56DE total / v2_activity_enabled / items[]\uFF0Citems \u542B id\u3001activity_name\u3001effective_type\u3001enabled\u3001product_scope\u3001products \u7B49"
|
|
631
|
-
).requiredOption("--agent <id>", "customer_agent_config_id\uFF08agent \u914D\u7F6E ID\uFF0C\u4ECE agent list \u83B7\u53D6\uFF09").option("--page <number>", "\u9875\u7801\uFF08\u22651\uFF09", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF\uFF081-100\uFF09", "20").option("--search <text>", "\u6309\u6D3B\u52A8\u540D\u6A21\u7CCA\u5339\u914D").
|
|
636
|
+
"\u5217\u51FA\u6D3B\u52A8\uFF08\u5206\u9875 + \u540D\u79F0\u641C\u7D22 + \u72B6\u6001\u8FC7\u6EE4\uFF09\u3002\u8FD4\u56DE total / v2_activity_enabled / items[]\uFF0Citems \u542B id\u3001activity_name\u3001effective_type\u3001enabled\u3001product_scope\u3001products \u7B49\uFF1Btotal \u4E0E state/search \u8FC7\u6EE4\u540C\u53E3\u5F84"
|
|
637
|
+
).requiredOption("--agent <id>", "customer_agent_config_id\uFF08agent \u914D\u7F6E ID\uFF0C\u4ECE agent list \u83B7\u53D6\uFF09").option("--page <number>", "\u9875\u7801\uFF08\u22651\uFF09", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF\uFF081-100\uFF09", "20").option("--search <text>", "\u6309\u6D3B\u52A8\u540D\u6A21\u7CCA\u5339\u914D").option(
|
|
638
|
+
"--state <state>",
|
|
639
|
+
"\u5C55\u793A\u72B6\u6001\u8FC7\u6EE4\uFF1Aall | pending | ongoing | ended\uFF08\u7F3A\u7701=all\uFF0C\u542B\u65F6\u95F4\u5F02\u5E38\u6761\u76EE\uFF1Blong_term \u6052 ongoing\uFF09"
|
|
640
|
+
).action(async (opts) => {
|
|
632
641
|
try {
|
|
633
642
|
const data = await listActivities({
|
|
634
643
|
customerAgentConfigId: opts.agent,
|
|
635
644
|
page: Number(opts.page),
|
|
636
645
|
pageSize: Number(opts.pageSize),
|
|
637
|
-
search: opts.search
|
|
646
|
+
search: opts.search,
|
|
647
|
+
state: opts.state === void 0 ? void 0 : parseStateFlag(opts.state)
|
|
638
648
|
});
|
|
639
649
|
formatOutput({ success: true, data }, program2.opts().table);
|
|
640
650
|
} catch (err) {
|
|
@@ -1228,6 +1238,11 @@ function registerConfigCommand(program2) {
|
|
|
1228
1238
|
var MAX_CONTEXT_SEARCH_RANGE_MS = 3 * 24 * 60 * 60 * 1e3;
|
|
1229
1239
|
var MAX_TRANSFER_HUMAN_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
1230
1240
|
var MAX_TRANSFER_HUMAN_CURSOR_PAGES = 500;
|
|
1241
|
+
var NORMAL_TRANSFER_EVENTS = /* @__PURE__ */ new Set([
|
|
1242
|
+
"\u9700\u8981\u4EBA\u5DE5\u63A5\u7BA1, SOP\u5F15\u64CE\u8BF7\u6C42\u8F6C\u4EBA\u5DE5\u5904\u7406",
|
|
1243
|
+
"\u9700\u8981\u4EBA\u5DE5\u63A5\u7BA1, \u4E13\u5BB6agent\u65E0\u6CD5\u56DE\u7B54"
|
|
1244
|
+
]);
|
|
1245
|
+
var NORMAL_TRANSFER_EVENT_PREFIXES = ["\u9700\u8981\u4EBA\u5DE5\u63A5\u7BA1, \u5B58\u5728\u65E0\u6CD5\u5904\u7406\u7684\u6D88\u606F\u7C7B\u578B\uFF1A"];
|
|
1231
1246
|
function parseSearchTime(value, fieldName) {
|
|
1232
1247
|
const parsed = new Date(value);
|
|
1233
1248
|
if (Number.isNaN(parsed.getTime())) {
|
|
@@ -1256,6 +1271,22 @@ function validateTransferHumanRange(startTime, endTime) {
|
|
|
1256
1271
|
throw new Error("\u67E5\u8BE2\u65F6\u95F4\u8303\u56F4\u4E0D\u80FD\u8D85\u8FC77\u5929");
|
|
1257
1272
|
}
|
|
1258
1273
|
}
|
|
1274
|
+
function shouldKeepTransferHumanConversation(item, onlyAbnormal) {
|
|
1275
|
+
if (!onlyAbnormal) return true;
|
|
1276
|
+
if (!item || typeof item !== "object") return true;
|
|
1277
|
+
const takeoverEvents = item.takeover_event_record;
|
|
1278
|
+
if (!Array.isArray(takeoverEvents) || takeoverEvents.length === 0) return true;
|
|
1279
|
+
const eventNames = takeoverEvents.map((event) => {
|
|
1280
|
+
if (!event || typeof event !== "object") return void 0;
|
|
1281
|
+
const eventName = event.event_name;
|
|
1282
|
+
return typeof eventName === "string" ? eventName : void 0;
|
|
1283
|
+
}).filter((eventName) => typeof eventName === "string");
|
|
1284
|
+
if (eventNames.length === 0) return true;
|
|
1285
|
+
return eventNames.some((eventName) => {
|
|
1286
|
+
if (NORMAL_TRANSFER_EVENTS.has(eventName)) return false;
|
|
1287
|
+
return !NORMAL_TRANSFER_EVENT_PREFIXES.some((prefix) => eventName.startsWith(prefix));
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1259
1290
|
async function contextSearchRecords(opts) {
|
|
1260
1291
|
validateContextSearchRange(opts.startTime, opts.endTime);
|
|
1261
1292
|
const wsId = getWorkspaceId(opts.workspaceId);
|
|
@@ -1320,7 +1351,8 @@ async function listTransferHumanConversations(opts) {
|
|
|
1320
1351
|
}
|
|
1321
1352
|
}
|
|
1322
1353
|
);
|
|
1323
|
-
|
|
1354
|
+
const pageItems = page.items ?? [];
|
|
1355
|
+
items.push(...pageItems.filter((item) => shouldKeepTransferHumanConversation(item, opts.onlyAbnormal ?? false)));
|
|
1324
1356
|
pagination = page.pagination ?? {};
|
|
1325
1357
|
const hasMore = pagination.has_more === true;
|
|
1326
1358
|
const nextCursor = typeof pagination.next_cursor === "string" && pagination.next_cursor ? pagination.next_cursor : void 0;
|
|
@@ -1385,12 +1417,13 @@ function registerConversationCommand(program2) {
|
|
|
1385
1417
|
process.exit(toExitCode(err));
|
|
1386
1418
|
}
|
|
1387
1419
|
});
|
|
1388
|
-
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) => {
|
|
1420
|
+
conversation.command("transfer-human").description("\u67E5\u8BE2\u8F6C\u4EBA\u5DE5\u4F1A\u8BDD\u53CA\u5BF9\u5E94\u8F6C\u4EBA\u5DE5\u6D88\u606F\u8BB0\u5F55\uFF08\u53EF\u9009\u4EC5\u4FDD\u7559\u5F02\u5E38\u4F1A\u8BDD\uFF09").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("--only-abnormal", "\u4EC5\u4FDD\u7559\u5F02\u5E38\u4F1A\u8BDD\uFF08\u6392\u9664\u6B63\u5E38 SOP \u8F6C\u4EBA\u5DE5\u3001agent \u65E0\u6CD5\u56DE\u7B54\u3001\u8F93\u5165/\u6D88\u606F\u7C7B\u578B\u5F02\u5E38\uFF09", false).action(async (opts) => {
|
|
1389
1421
|
try {
|
|
1390
1422
|
const data = await listTransferHumanConversations({
|
|
1391
1423
|
customerAgentConfigId: opts.agent,
|
|
1392
1424
|
startDate: opts.start,
|
|
1393
|
-
endDate: opts.end
|
|
1425
|
+
endDate: opts.end,
|
|
1426
|
+
onlyAbnormal: opts.onlyAbnormal
|
|
1394
1427
|
});
|
|
1395
1428
|
formatOutput({ success: true, data }, program2.opts().table);
|
|
1396
1429
|
} catch (err) {
|
|
@@ -6781,6 +6814,563 @@ function registerTestsetCommand(program2) {
|
|
|
6781
6814
|
registerExportCommand(program2, testset);
|
|
6782
6815
|
}
|
|
6783
6816
|
|
|
6817
|
+
// src/commands/tool.ts
|
|
6818
|
+
import fs14 from "fs";
|
|
6819
|
+
|
|
6820
|
+
// src/client/flow-api.ts
|
|
6821
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
6822
|
+
|
|
6823
|
+
// src/client/flow-skeleton.ts
|
|
6824
|
+
import { randomUUID } from "crypto";
|
|
6825
|
+
var DEFAULT_FORM_CONFIG = [
|
|
6826
|
+
{
|
|
6827
|
+
type: "json",
|
|
6828
|
+
label: "\u4E0A\u4E0B\u6587",
|
|
6829
|
+
required: true,
|
|
6830
|
+
placeholder: "\u8BF7\u8F93\u5165",
|
|
6831
|
+
variableName: "dialogue",
|
|
6832
|
+
cascadeFields: [],
|
|
6833
|
+
isCascadeField: false
|
|
6834
|
+
}
|
|
6835
|
+
];
|
|
6836
|
+
function buildEdge(source, target) {
|
|
6837
|
+
return {
|
|
6838
|
+
id: `${source}-${target}`,
|
|
6839
|
+
type: "insert",
|
|
6840
|
+
source,
|
|
6841
|
+
target,
|
|
6842
|
+
interactionWidth: 80,
|
|
6843
|
+
style: {
|
|
6844
|
+
stroke: "#C0C3D1",
|
|
6845
|
+
strokeWidth: 2,
|
|
6846
|
+
strokeLinecap: "round",
|
|
6847
|
+
strokeLinejoin: "round"
|
|
6848
|
+
}
|
|
6849
|
+
};
|
|
6850
|
+
}
|
|
6851
|
+
function buildFlowSkeleton(opts) {
|
|
6852
|
+
const startId = randomUUID();
|
|
6853
|
+
const codeId = randomUUID();
|
|
6854
|
+
const endId = randomUUID();
|
|
6855
|
+
const codeName = opts.codeNodeName ?? "javascript_1";
|
|
6856
|
+
const startNode = {
|
|
6857
|
+
id: startId,
|
|
6858
|
+
type: "START",
|
|
6859
|
+
actionType: "TRIGGER",
|
|
6860
|
+
name: "start",
|
|
6861
|
+
relation: null,
|
|
6862
|
+
isEnable: true,
|
|
6863
|
+
layout: { width: 420, height: 311, position: { x: 0, y: 0 } },
|
|
6864
|
+
data: {
|
|
6865
|
+
name: "start",
|
|
6866
|
+
type: "form",
|
|
6867
|
+
actionType: "TRIGGER",
|
|
6868
|
+
inputs: {},
|
|
6869
|
+
isEnable: true,
|
|
6870
|
+
relation: null,
|
|
6871
|
+
conditions: [],
|
|
6872
|
+
packageName: "",
|
|
6873
|
+
sortCopyIndex: -1,
|
|
6874
|
+
formConfig: opts.inputVars ?? DEFAULT_FORM_CONFIG
|
|
6875
|
+
}
|
|
6876
|
+
};
|
|
6877
|
+
const codeNode = {
|
|
6878
|
+
id: codeId,
|
|
6879
|
+
type: "CODE",
|
|
6880
|
+
actionType: "CODE",
|
|
6881
|
+
name: codeName,
|
|
6882
|
+
relation: null,
|
|
6883
|
+
isEnable: true,
|
|
6884
|
+
layout: { width: 420, height: 435, position: { x: 544, y: 0 } },
|
|
6885
|
+
data: {
|
|
6886
|
+
name: codeName,
|
|
6887
|
+
type: null,
|
|
6888
|
+
actionType: "CODE",
|
|
6889
|
+
inputs: {
|
|
6890
|
+
code: opts.code,
|
|
6891
|
+
desc: opts.description ?? "",
|
|
6892
|
+
version: 1,
|
|
6893
|
+
language: "javascript"
|
|
6894
|
+
},
|
|
6895
|
+
isEnable: true,
|
|
6896
|
+
relation: null,
|
|
6897
|
+
conditions: [],
|
|
6898
|
+
packageName: "",
|
|
6899
|
+
formConfig: null,
|
|
6900
|
+
sortCopyIndex: 1
|
|
6901
|
+
}
|
|
6902
|
+
};
|
|
6903
|
+
const endNode = {
|
|
6904
|
+
id: endId,
|
|
6905
|
+
type: "END",
|
|
6906
|
+
actionType: "END",
|
|
6907
|
+
name: "output",
|
|
6908
|
+
relation: null,
|
|
6909
|
+
isEnable: true,
|
|
6910
|
+
layout: { width: 420, height: 98, position: { x: 1088, y: 0 } },
|
|
6911
|
+
data: {
|
|
6912
|
+
name: "output",
|
|
6913
|
+
type: null,
|
|
6914
|
+
actionType: "END",
|
|
6915
|
+
inputs: {},
|
|
6916
|
+
isEnable: true,
|
|
6917
|
+
relation: null,
|
|
6918
|
+
conditions: [],
|
|
6919
|
+
packageName: "",
|
|
6920
|
+
formConfig: null,
|
|
6921
|
+
sortCopyIndex: -1
|
|
6922
|
+
}
|
|
6923
|
+
};
|
|
6924
|
+
return {
|
|
6925
|
+
nodes: [startNode, codeNode, endNode],
|
|
6926
|
+
edges: [buildEdge(startId, codeId), buildEdge(codeId, endId)]
|
|
6927
|
+
};
|
|
6928
|
+
}
|
|
6929
|
+
|
|
6930
|
+
// src/client/flow-api.ts
|
|
6931
|
+
var CODE_NODE_GUIDE = `# CODE \u8282\u70B9\u7F16\u5199\u6307\u5357\uFF08JavaScript\uFF09
|
|
6932
|
+
|
|
6933
|
+
\u81EA\u5B9A\u4E49\u5DE5\u5177 = \u4E00\u4E2A flow\uFF0C\u6838\u5FC3\u662F\u5176\u4E2D\u7684 CODE \u8282\u70B9\u3002\u672C CLI \u521B\u5EFA/\u66F4\u65B0\u7684 CODE \u8282\u70B9\u53EA\u652F\u6301 JavaScript\u3002
|
|
6934
|
+
\u5B98\u65B9\u6587\u6863\uFF1Ahttps://ai-docs.betteryeah.com/Flow/\u8282\u70B9\u4ECB\u7ECD\u4E0E\u914D\u7F6E/JavaScript&Python\u8282\u70B9.html
|
|
6935
|
+
|
|
6936
|
+
## 1. \u5165\u53E3\uFF1Aasync function main()
|
|
6937
|
+
|
|
6938
|
+
\u5FC5\u987B\u7F16\u5199\u540D\u4E3A main \u7684\u5F02\u6B65\u5165\u53E3\u51FD\u6570\uFF08\u9876\u5C42 async function main()\uFF09\u3002
|
|
6939
|
+
main() \u7684\u8FD4\u56DE\u503C\u5373\u5DE5\u5177\u4EA7\u51FA\uFF08\u4E1A\u52A1\u7ED3\u679C\uFF09\uFF0C\u4F1A\u88AB\u5E73\u53F0\u56DE\u586B\u7ED9 Agent \u4F5C\u4E3A\u8BE5\u5DE5\u5177\u7684\u8F93\u51FA\uFF1B
|
|
6940
|
+
\u6CA1\u6709 return \u5219\u8F93\u51FA\u4E3A null\u3002
|
|
6941
|
+
|
|
6942
|
+
## 2. \u5165\u53C2\u4E0E\u53D8\u91CF\u6CE8\u5165
|
|
6943
|
+
|
|
6944
|
+
\u524D\u7F6E\u8282\u70B9\u7684\u53D8\u91CF\u5DF2\u5185\u7F6E\u5728\u4EE3\u7801\u6267\u884C\u73AF\u5883\u4E2D\uFF0C\u76F4\u63A5\u4EE5\u540C\u540D\u5168\u5C40\u53D8\u91CF\u4F7F\u7528\u3001\u65E0\u9700\u58F0\u660E\uFF1A
|
|
6945
|
+
- START \u8282\u70B9 formConfig \u58F0\u660E\u7684\u6BCF\u4E2A variableName \u90FD\u4F1A\u6CE8\u5165\u4E3A\u540C\u540D\u5168\u5C40\u53D8\u91CF\u3002
|
|
6946
|
+
\u9ED8\u8BA4\u53EA\u58F0\u660E\u4E00\u4E2A dialogue\uFF08\u4E0A\u4E0B\u6587\uFF0C\u7C7B\u578B json\uFF09\u2014\u2014\u5373\u6574\u6BB5\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u76F4\u63A5\u5F15\u7528 dialogue \u5373\u53EF\u3002
|
|
6947
|
+
\u8981\u52A0\u5165\u53C2\u5C31\u6539 formConfig\uFF08\u521B\u5EFA\u65F6\u7528 --input-vars \u8986\u76D6\uFF09\u3002
|
|
6948
|
+
- \u4E0A\u6E38\u5176\u5B83\u8282\u70B9\u7684\u8F93\u51FA\u540C\u6837\u6309\u8282\u70B9\u540D\u6CE8\u5165\uFF08\u5982 llm_1\uFF09\u3002\u672C CLI \u751F\u6210\u7684\u9AA8\u67B6\u53EA\u6709 START\u2192CODE\u2192END\uFF0C
|
|
6949
|
+
\u6240\u4EE5\u901A\u5E38\u53EA\u7528\u5F97\u5230 formConfig \u91CC\u7684\u53D8\u91CF\u3002
|
|
6950
|
+
|
|
6951
|
+
## 3. \u8FD4\u56DE\u503C
|
|
6952
|
+
|
|
6953
|
+
\u8FD4\u56DE**\u88F8\u7684** object / list \u5373\u53EF\uFF0C**\u4E0D\u8981\u518D\u5957\u4E00\u5C42 {data:{...}} \u6216 {data:{run_result:[...]}} \u4FE1\u5C01**\u3002
|
|
6954
|
+
\u5E73\u53F0\u6309\u88F8\u8FD4\u56DE\u503C\u6D88\u8D39\uFF1B\u591A\u5957\u7684\u4FE1\u5C01\u4F1A\u8BA9\u4E0B\u6E38\u5BCC\u5316/\u89E3\u6790\u6309\u5B57\u9762 key \u53D6\u503C\u800C\u9759\u9ED8\u5931\u8D25\uFF08\u5DF2\u53D1\u751F\u8FC7\u7EBF\u4E0A\u4E8B\u6545\uFF09\u3002
|
|
6955
|
+
\u8FD4\u56DE\u503C\u5FC5\u987B\u53EF\u5E8F\u5217\u5316\u2014\u2014\u4E0D\u80FD\u662F\u6B63\u5219\u3001\u51FD\u6570\u7B49\u4E0D\u53EF\u5E8F\u5217\u5316\u5BF9\u8C61\u3002
|
|
6956
|
+
|
|
6957
|
+
## 4. \u5185\u7F6E\u5305\uFF08CommonJS\uFF09
|
|
6958
|
+
|
|
6959
|
+
\u73AF\u5883\u5185\u7F6E\u5E38\u7528\u5305\uFF0C\u7528 require \u5BFC\u5165\uFF08\u4E0D\u652F\u6301 ES Module \u7684 import\uFF09\uFF1A
|
|
6960
|
+
|
|
6961
|
+
const axios = require('axios'); // HTTP \u8BF7\u6C42
|
|
6962
|
+
const dayjs = require('dayjs'); // \u65E5\u671F\u5904\u7406
|
|
6963
|
+
const crypto = require('crypto'); // \u52A0\u5BC6/\u6458\u8981
|
|
6964
|
+
|
|
6965
|
+
## 5. BetterYeah SDK
|
|
6966
|
+
|
|
6967
|
+
const Betteryeah = require('betteryeah').default;
|
|
6968
|
+
const betteryeah = new Betteryeah();
|
|
6969
|
+
|
|
6970
|
+
\u6838\u5FC3\u6A21\u5757\uFF08\u5168\u90E8 await \u8C03\u7528\uFF09\uFF1A
|
|
6971
|
+
- betteryeah.llm.chat({ systemPrompt, model, jsonMode, temperature, messages })\uFF1A\u8C03\u5927\u6A21\u578B
|
|
6972
|
+
- betteryeah.knowledge.searchKnowledge / insertKnowledge\uFF1A\u77E5\u8BC6\u5E93\u67E5\u8BE2/\u63D2\u5165
|
|
6973
|
+
- betteryeah.database.executeDatabase({ databaseId, executableSql })\uFF1A\u6267\u884C SQL
|
|
6974
|
+
- betteryeah.plugin.*\uFF1A\u641C\u7D22\uFF08search.googleSearch/bingSearch/aiSearch\uFF09\u3001\u89E3\u6790\uFF08parsing.web/excel/pdf/...\uFF09\u3001
|
|
6975
|
+
\u8BC6\u56FE\u751F\u56FE\uFF08image.vision/generate/ocr\uFF09\u7B49
|
|
6976
|
+
- betteryeah.subFlow.execute(flowId, parameter)\uFF1A\u8C03\u7528\u5176\u5B83\u5DF2\u53D1\u5E03\u5DE5\u4F5C\u6D41
|
|
6977
|
+
|
|
6978
|
+
SDK \u7EDF\u4E00\u54CD\u5E94\u5F62\u72B6 { code, success, message, data, usage }\uFF0C\u52A1\u5FC5\u68C0\u67E5 success\uFF1A
|
|
6979
|
+
|
|
6980
|
+
if (!result.success) throw new Error(result.message ?? '\u6267\u884C\u51FA\u9519');
|
|
6981
|
+
|
|
6982
|
+
## 6. betterAI \u8FD0\u884C\u65F6\u5BF9\u8C61
|
|
6983
|
+
|
|
6984
|
+
- betterAI.store.set(key, value) / betterAI.store.get(key)\uFF1Aflow \u751F\u547D\u5468\u671F\u5185\u5171\u4EAB\u6570\u636E
|
|
6985
|
+
- betterAI.session.*\uFF1A\u4F1A\u8BDD\u5143\u4FE1\u606F\u4E0E\u6301\u4E45\u5316\u8BB0\u5FC6\uFF08sessionId / conversationId / metaData / \u804A\u5929\u8BB0\u5F55\uFF09
|
|
6986
|
+
- betterAI.agent.chat.*\uFF1A\u5411 Agent \u4F1A\u8BDD\u63A8\u9001\u6D88\u606F/\u901A\u77E5
|
|
6987
|
+
|
|
6988
|
+
## 7. \u5B8C\u6574\u793A\u4F8B
|
|
6989
|
+
|
|
6990
|
+
async function main() {
|
|
6991
|
+
const ctx = dialogue; // \u6765\u81EA START formConfig \u7684\u5168\u5C40\u53D8\u91CF
|
|
6992
|
+
// ...\u4F60\u7684\u4E1A\u52A1\u903B\u8F91...
|
|
6993
|
+
return { ok: true }; // main \u7684\u8FD4\u56DE\u503C\u5373\u5DE5\u5177\u4EA7\u51FA\uFF08\u88F8\u5BF9\u8C61\uFF0C\u52FF\u5957\u4FE1\u5C01\uFF09
|
|
6994
|
+
}
|
|
6995
|
+
|
|
6996
|
+
## 8. \u6CE8\u610F\u4E8B\u9879
|
|
6997
|
+
|
|
6998
|
+
- \u77E5\u8BC6\u5E93 ID / \u6587\u4EF6 ID / \u6570\u636E\u5E93 ID \u7B49\u5728\u5E73\u53F0\u5DE6\u4FA7\u8D44\u6E90\u6811\u7528\u590D\u5236\u6309\u94AE\u83B7\u53D6\u3002
|
|
6999
|
+
- SDK \u5404\u6A21\u5757\u5B8C\u6574\u53C2\u6570\u4E0E\u66F4\u591A\u793A\u4F8B\u4EE5\u4E0A\u65B9\u5B98\u65B9\u6587\u6863\u4E3A\u51C6\u3002
|
|
7000
|
+
`;
|
|
7001
|
+
async function createFlow(opts) {
|
|
7002
|
+
const { nodes, edges } = buildFlowSkeleton({
|
|
7003
|
+
code: opts.code,
|
|
7004
|
+
description: opts.description,
|
|
7005
|
+
inputVars: opts.inputVars,
|
|
7006
|
+
codeNodeName: opts.codeNodeName
|
|
7007
|
+
});
|
|
7008
|
+
const request = createRequest();
|
|
7009
|
+
const res = await request(
|
|
7010
|
+
getAiApiUrl(),
|
|
7011
|
+
"/v1/applications",
|
|
7012
|
+
{
|
|
7013
|
+
method: "POST",
|
|
7014
|
+
query: { workspaceId: getWorkspaceId() },
|
|
7015
|
+
headers: {
|
|
7016
|
+
accept: "application/json",
|
|
7017
|
+
"application-id": randomUUID2().replace(/-/g, "")
|
|
7018
|
+
},
|
|
7019
|
+
body: {
|
|
7020
|
+
icon: "\u{1F33C}",
|
|
7021
|
+
color: "#ADE9CE",
|
|
7022
|
+
description: opts.description ?? "\u6682\u65E0\u63CF\u8FF0",
|
|
7023
|
+
name: opts.name,
|
|
7024
|
+
applicationType: "AI",
|
|
7025
|
+
config: JSON.stringify({ nodes, edges }),
|
|
7026
|
+
channel_type: "flow"
|
|
7027
|
+
}
|
|
7028
|
+
}
|
|
7029
|
+
);
|
|
7030
|
+
const flowId = res.flowId;
|
|
7031
|
+
const versionId = res.versionId;
|
|
7032
|
+
const publish = opts.publish !== false;
|
|
7033
|
+
if (publish) {
|
|
7034
|
+
await request(getAiApiUrl(), "/v1/flow/publish", {
|
|
7035
|
+
method: "POST",
|
|
7036
|
+
body: {
|
|
7037
|
+
draftVersionId: versionId,
|
|
7038
|
+
...opts.versionDesc ? { version_desc: opts.versionDesc } : {}
|
|
7039
|
+
}
|
|
7040
|
+
});
|
|
7041
|
+
}
|
|
7042
|
+
return { flow_id: flowId, version_id: versionId, published: publish };
|
|
7043
|
+
}
|
|
7044
|
+
async function getFlowConfig(opts) {
|
|
7045
|
+
const request = createRequest();
|
|
7046
|
+
return request(getAiApiUrl(), `/v1/applications/${encodeURIComponent(opts.flowId)}`, {
|
|
7047
|
+
method: "GET"
|
|
7048
|
+
});
|
|
7049
|
+
}
|
|
7050
|
+
async function updateFlowCode(opts) {
|
|
7051
|
+
const data = await getFlowConfig({ flowId: opts.flowId });
|
|
7052
|
+
const config = data.config;
|
|
7053
|
+
if (!config || typeof config !== "object" || !Array.isArray(config.nodes)) {
|
|
7054
|
+
throw new APIError(1, "flow config \u5F62\u72B6\u5F02\u5E38\uFF1A\u7F3A nodes \u6570\u7EC4\uFF0C\u65E0\u6CD5\u5B9A\u4F4D CODE \u8282\u70B9");
|
|
7055
|
+
}
|
|
7056
|
+
const codeNodes = config.nodes.filter(
|
|
7057
|
+
// biome-ignore lint/suspicious/noExplicitAny: 同上
|
|
7058
|
+
(n) => n.type === "CODE"
|
|
7059
|
+
);
|
|
7060
|
+
if (codeNodes.length !== 1) {
|
|
7061
|
+
throw new APIError(1, `\u672A\u627E\u5230\u552F\u4E00 CODE \u8282\u70B9\uFF08\u627E\u5230 ${codeNodes.length} \u4E2A\uFF09`);
|
|
7062
|
+
}
|
|
7063
|
+
codeNodes[0].data.inputs.code = opts.code;
|
|
7064
|
+
const request = createRequest();
|
|
7065
|
+
await request(getAiApiUrl(), "/v1/flow/update", {
|
|
7066
|
+
method: "POST",
|
|
7067
|
+
body: { appId: opts.flowId, config, flowId: opts.flowId }
|
|
7068
|
+
});
|
|
7069
|
+
const publish = opts.publish !== false;
|
|
7070
|
+
if (publish) {
|
|
7071
|
+
const draft = await request(
|
|
7072
|
+
getAiApiUrl(),
|
|
7073
|
+
`/v1/flow/draft/${encodeURIComponent(opts.flowId)}`,
|
|
7074
|
+
{ method: "GET" }
|
|
7075
|
+
);
|
|
7076
|
+
await request(getAiApiUrl(), "/v1/flow/publish", {
|
|
7077
|
+
method: "POST",
|
|
7078
|
+
body: {
|
|
7079
|
+
draftVersionId: draft.version_id,
|
|
7080
|
+
...opts.versionDesc ? { version_desc: opts.versionDesc } : {}
|
|
7081
|
+
}
|
|
7082
|
+
});
|
|
7083
|
+
}
|
|
7084
|
+
return { flow_id: opts.flowId, published: publish };
|
|
7085
|
+
}
|
|
7086
|
+
async function getWorkspaceAccessKey() {
|
|
7087
|
+
const request = createRequest();
|
|
7088
|
+
const workspaceId = getWorkspaceId();
|
|
7089
|
+
return request(
|
|
7090
|
+
getAiApiUrl(),
|
|
7091
|
+
`/v1/workspaces/getKey/${encodeURIComponent(workspaceId)}`,
|
|
7092
|
+
{ method: "GET" }
|
|
7093
|
+
);
|
|
7094
|
+
}
|
|
7095
|
+
async function runFlow(opts) {
|
|
7096
|
+
const accessKey = await getWorkspaceAccessKey();
|
|
7097
|
+
const request = createRequest();
|
|
7098
|
+
return request(
|
|
7099
|
+
getAiApiUrl(),
|
|
7100
|
+
`/v1/public_api/rest_api/${encodeURIComponent(opts.flowId)}/execute_flow`,
|
|
7101
|
+
{
|
|
7102
|
+
method: "POST",
|
|
7103
|
+
headers: { "Access-Key": accessKey },
|
|
7104
|
+
body: { inputs: opts.inputs ?? {}, async_execute: false }
|
|
7105
|
+
}
|
|
7106
|
+
);
|
|
7107
|
+
}
|
|
7108
|
+
async function deleteFlow(opts) {
|
|
7109
|
+
const request = createRequest();
|
|
7110
|
+
await request(getAiApiUrl(), `/v1/applications/${encodeURIComponent(opts.flowId)}`, {
|
|
7111
|
+
method: "DELETE"
|
|
7112
|
+
});
|
|
7113
|
+
return { flow_id: opts.flowId };
|
|
7114
|
+
}
|
|
7115
|
+
|
|
7116
|
+
// src/client/tool-api.ts
|
|
7117
|
+
var VALID_INVOCATION_MODES = ["must_invoke", "on_demand", "on_demand_async"];
|
|
7118
|
+
function assertInvocationMode(mode) {
|
|
7119
|
+
if (!VALID_INVOCATION_MODES.includes(mode)) {
|
|
7120
|
+
throw new APIError(
|
|
7121
|
+
1,
|
|
7122
|
+
"invocation_mode \u975E\u6CD5\uFF0C\u53EF\u9009\u503C\uFF1Amust_invoke / on_demand / on_demand_async"
|
|
7123
|
+
);
|
|
7124
|
+
}
|
|
7125
|
+
}
|
|
7126
|
+
async function listToolsByConfig(opts) {
|
|
7127
|
+
const request = createRequest();
|
|
7128
|
+
return request(getCustomerServiceUrl(), "/v1/tool/by-config", {
|
|
7129
|
+
method: "GET",
|
|
7130
|
+
query: { customer_agent_config_id: opts.agentConfigId }
|
|
7131
|
+
});
|
|
7132
|
+
}
|
|
7133
|
+
async function createCustomTool(opts) {
|
|
7134
|
+
if (opts.invocationMode !== void 0) {
|
|
7135
|
+
assertInvocationMode(opts.invocationMode);
|
|
7136
|
+
}
|
|
7137
|
+
const request = createRequest();
|
|
7138
|
+
return request(getCustomerServiceUrl(), "/v1/tool/custom", {
|
|
7139
|
+
method: "POST",
|
|
7140
|
+
body: {
|
|
7141
|
+
name: opts.name,
|
|
7142
|
+
key: opts.key,
|
|
7143
|
+
workspace_id: getWorkspaceId(),
|
|
7144
|
+
customer_agent_config_id: opts.agentConfigId,
|
|
7145
|
+
source_id: opts.sourceId,
|
|
7146
|
+
source_type: opts.sourceType ?? "flow",
|
|
7147
|
+
description: opts.description ?? "",
|
|
7148
|
+
invocation_mode: opts.invocationMode ?? "on_demand",
|
|
7149
|
+
input_var_descriptions: opts.inputVarDescriptions ?? {}
|
|
7150
|
+
}
|
|
7151
|
+
});
|
|
7152
|
+
}
|
|
7153
|
+
async function updateTool(opts) {
|
|
7154
|
+
if (opts.invocationMode !== void 0) {
|
|
7155
|
+
assertInvocationMode(opts.invocationMode);
|
|
7156
|
+
}
|
|
7157
|
+
const body = {};
|
|
7158
|
+
if (opts.name !== void 0) body.name = opts.name;
|
|
7159
|
+
if (opts.key !== void 0) body.key = opts.key;
|
|
7160
|
+
if (opts.description !== void 0) body.description = opts.description;
|
|
7161
|
+
if (opts.sourceId !== void 0) body.source_id = opts.sourceId;
|
|
7162
|
+
if (opts.invocationMode !== void 0) body.invocation_mode = opts.invocationMode;
|
|
7163
|
+
if (opts.inputVarDescriptions !== void 0) {
|
|
7164
|
+
body.input_var_descriptions = opts.inputVarDescriptions;
|
|
7165
|
+
}
|
|
7166
|
+
const request = createRequest();
|
|
7167
|
+
return request(getCustomerServiceUrl(), `/v1/tool/${opts.toolId}`, {
|
|
7168
|
+
method: "PUT",
|
|
7169
|
+
body
|
|
7170
|
+
});
|
|
7171
|
+
}
|
|
7172
|
+
async function deleteTool(opts) {
|
|
7173
|
+
const request = createRequest();
|
|
7174
|
+
return request(getCustomerServiceUrl(), `/v1/tool/${opts.toolId}`, {
|
|
7175
|
+
method: "DELETE"
|
|
7176
|
+
});
|
|
7177
|
+
}
|
|
7178
|
+
async function listWorkflows(opts) {
|
|
7179
|
+
const request = createRequest();
|
|
7180
|
+
return request(getCustomerServiceUrl(), "/v1/tool/workflow/list", {
|
|
7181
|
+
method: "GET",
|
|
7182
|
+
query: { workspace_id: getWorkspaceId(), keyword: opts.keyword ?? "" }
|
|
7183
|
+
});
|
|
7184
|
+
}
|
|
7185
|
+
async function getWorkflowDetail(opts) {
|
|
7186
|
+
const request = createRequest();
|
|
7187
|
+
return request(
|
|
7188
|
+
getCustomerServiceUrl(),
|
|
7189
|
+
`/v1/tool/workflow/${encodeURIComponent(opts.flowId)}/detail`,
|
|
7190
|
+
{
|
|
7191
|
+
method: "GET",
|
|
7192
|
+
query: { workspace_id: getWorkspaceId() }
|
|
7193
|
+
}
|
|
7194
|
+
);
|
|
7195
|
+
}
|
|
7196
|
+
|
|
7197
|
+
// src/commands/tool.ts
|
|
7198
|
+
function readArgMaybeFile(value) {
|
|
7199
|
+
if (value.startsWith("@")) {
|
|
7200
|
+
const filePath = value.slice(1);
|
|
7201
|
+
try {
|
|
7202
|
+
return fs14.readFileSync(filePath, "utf8");
|
|
7203
|
+
} catch {
|
|
7204
|
+
throw new APIError(
|
|
7205
|
+
1,
|
|
7206
|
+
`\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A${filePath}\uFF08@ \u524D\u7F00\u8868\u793A\u6587\u4EF6\u8DEF\u5F84\uFF1B\u8981\u4F20\u5B57\u9762\u5185\u5BB9\u8BF7\u53BB\u6389 @\uFF09`
|
|
7207
|
+
);
|
|
7208
|
+
}
|
|
7209
|
+
}
|
|
7210
|
+
return value;
|
|
7211
|
+
}
|
|
7212
|
+
function registerToolCommand(program2) {
|
|
7213
|
+
const tool = program2.command("tool").description(
|
|
7214
|
+
"\u81EA\u5B9A\u4E49/\u8986\u76D6\u5DE5\u5177\uFF08agent tool\uFF09\u7BA1\u7406 \u2014\u2014 \u5BF9\u67D0\u4E2A Agent \u914D\u7F6E\u7ED1\u5B9A\u7684\u81EA\u5B9A\u4E49\u5DE5\u5177\u505A\u589E\u5220\u6539\u67E5\uFF0C\u5E76\u53D1\u73B0\u53EF\u7ED1\u5B9A\u7684\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\u3002\u5305\u88C5 servhub /v1/tool API"
|
|
7215
|
+
);
|
|
7216
|
+
tool.command("list").description("\u5217\u51FA\u8BE5 Agent \u914D\u7F6E\u5DF2\u7ED1\u5B9A\u7684\u5DE5\u5177\uFF08custom + system\uFF09").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").action(async (opts) => {
|
|
7217
|
+
try {
|
|
7218
|
+
const data = await listToolsByConfig({ agentConfigId: opts.agent });
|
|
7219
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7220
|
+
} catch (err) {
|
|
7221
|
+
reportCaughtError(err);
|
|
7222
|
+
process.exit(toExitCode(err));
|
|
7223
|
+
}
|
|
7224
|
+
});
|
|
7225
|
+
tool.command("create").description("\u521B\u5EFA\u81EA\u5B9A\u4E49\u5DE5\u5177\uFF0C\u7ED1\u5B9A\u4E00\u4E2A\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\u4F5C\u4E3A\u5DE5\u5177\u5B9E\u73B0").requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption("--name <name>", "\u5DE5\u5177\u663E\u793A\u540D\u79F0").requiredOption("--key <key>", "\u5DE5\u5177 key\uFF08\u552F\u4E00\u6807\u8BC6\uFF09").requiredOption("--source-id <flow_id>", "\u7ED1\u5B9A\u7684\u5DE5\u4F5C\u6D41 ID\uFF08\u4ECE tool workflow list \u83B7\u53D6\uFF09").option("--description <text>", "\u5DE5\u5177\u63CF\u8FF0").option("--source-type <type>", "\u5DE5\u5177\u6765\u6E90\u7C7B\u578B\uFF08\u9ED8\u8BA4 flow\uFF09").option(
|
|
7226
|
+
"--invocation-mode <mode>",
|
|
7227
|
+
"\u8C03\u7528\u6A21\u5F0F\uFF1Amust_invoke / on_demand / on_demand_async\uFF08\u9ED8\u8BA4 on_demand\uFF09"
|
|
7228
|
+
).option("--input-vars <json>", "\u5165\u53C2\u63CF\u8FF0\uFF08JSON \u5B57\u7B26\u4E32\uFF09\uFF0C\u89E3\u6790\u4E3A input_var_descriptions").action(async (opts) => {
|
|
7229
|
+
try {
|
|
7230
|
+
const inputVarDescriptions = opts.inputVars !== void 0 ? JSON.parse(opts.inputVars) : void 0;
|
|
7231
|
+
const data = await createCustomTool({
|
|
7232
|
+
agentConfigId: opts.agent,
|
|
7233
|
+
name: opts.name,
|
|
7234
|
+
key: opts.key,
|
|
7235
|
+
sourceId: opts.sourceId,
|
|
7236
|
+
description: opts.description,
|
|
7237
|
+
sourceType: opts.sourceType,
|
|
7238
|
+
invocationMode: opts.invocationMode,
|
|
7239
|
+
inputVarDescriptions
|
|
7240
|
+
});
|
|
7241
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7242
|
+
} catch (err) {
|
|
7243
|
+
reportCaughtError(err);
|
|
7244
|
+
process.exit(toExitCode(err));
|
|
7245
|
+
}
|
|
7246
|
+
});
|
|
7247
|
+
tool.command("update <tool_id>").description("\u66F4\u65B0\u5DE5\u5177\u7684\u4EFB\u610F\u5B50\u96C6\u5B57\u6BB5\uFF08\u4EC5\u900F\u4F20\u5B9E\u9645\u63D0\u4F9B\u7684 flag\uFF09").option("--name <name>", "\u5DE5\u5177\u663E\u793A\u540D\u79F0").option("--key <key>", "\u5DE5\u5177 key\uFF08\u552F\u4E00\u6807\u8BC6\uFF09").option("--description <text>", "\u5DE5\u5177\u63CF\u8FF0").option("--source-id <flow_id>", "\u7ED1\u5B9A\u7684\u5DE5\u4F5C\u6D41 ID").option("--invocation-mode <mode>", "\u8C03\u7528\u6A21\u5F0F\uFF1Amust_invoke / on_demand / on_demand_async").option("--input-vars <json>", "\u5165\u53C2\u63CF\u8FF0\uFF08JSON \u5B57\u7B26\u4E32\uFF09\uFF0C\u89E3\u6790\u4E3A input_var_descriptions").action(async (toolId, opts) => {
|
|
7248
|
+
try {
|
|
7249
|
+
const inputVarDescriptions = opts.inputVars !== void 0 ? JSON.parse(opts.inputVars) : void 0;
|
|
7250
|
+
const data = await updateTool({
|
|
7251
|
+
toolId,
|
|
7252
|
+
name: opts.name,
|
|
7253
|
+
key: opts.key,
|
|
7254
|
+
description: opts.description,
|
|
7255
|
+
sourceId: opts.sourceId,
|
|
7256
|
+
invocationMode: opts.invocationMode,
|
|
7257
|
+
inputVarDescriptions
|
|
7258
|
+
});
|
|
7259
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7260
|
+
} catch (err) {
|
|
7261
|
+
reportCaughtError(err);
|
|
7262
|
+
process.exit(toExitCode(err));
|
|
7263
|
+
}
|
|
7264
|
+
});
|
|
7265
|
+
tool.command("delete <tool_id>").description("\u5220\u9664\uFF08\u8F6F\u5220\u9664\uFF09\u6307\u5B9A\u5DE5\u5177").action(async (toolId) => {
|
|
7266
|
+
try {
|
|
7267
|
+
const data = await deleteTool({ toolId });
|
|
7268
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7269
|
+
} catch (err) {
|
|
7270
|
+
reportCaughtError(err);
|
|
7271
|
+
process.exit(toExitCode(err));
|
|
7272
|
+
}
|
|
7273
|
+
});
|
|
7274
|
+
const workflow = tool.command("workflow").description(
|
|
7275
|
+
"\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\u7BA1\u7406\uFF1Alist / detail\uFF08\u53D1\u73B0\uFF09+ create / update / run / delete / describe\uFF08\u589E\u6539\u8DD1\u5220 + \u8BF4\u660E\uFF09"
|
|
7276
|
+
);
|
|
7277
|
+
workflow.command("list").description("\u5217\u51FA\u5F53\u524D\u5DE5\u4F5C\u7A7A\u95F4\u53EF\u7ED1\u5B9A\u7684\u5DE5\u4F5C\u6D41\uFF08flow\uFF09").option("--keyword <kw>", "\u6309\u5173\u952E\u8BCD\u6A21\u7CCA\u7B5B\u9009").action(async (opts) => {
|
|
7278
|
+
try {
|
|
7279
|
+
const data = await listWorkflows({ keyword: opts.keyword });
|
|
7280
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7281
|
+
} catch (err) {
|
|
7282
|
+
reportCaughtError(err);
|
|
7283
|
+
process.exit(toExitCode(err));
|
|
7284
|
+
}
|
|
7285
|
+
});
|
|
7286
|
+
workflow.command("detail <flow_id>").description("\u67E5\u770B\u6307\u5B9A\u5DE5\u4F5C\u6D41\u7684\u5165\u53C2\u5217\u8868\uFF08\u7528\u4E8E\u6784\u9020 input_var_descriptions\uFF09").action(async (flowId) => {
|
|
7287
|
+
try {
|
|
7288
|
+
const data = await getWorkflowDetail({ flowId });
|
|
7289
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7290
|
+
} catch (err) {
|
|
7291
|
+
reportCaughtError(err);
|
|
7292
|
+
process.exit(toExitCode(err));
|
|
7293
|
+
}
|
|
7294
|
+
});
|
|
7295
|
+
workflow.command("create").description(
|
|
7296
|
+
"\u521B\u5EFA\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\uFF1ASTART \u2192 CODE \u2192 END \u9AA8\u67B6\uFF0CCODE \u8282\u70B9\u627F\u8F7D\u5DE5\u5177\u4EE3\u7801\uFF08\u4EC5\u652F\u6301 JavaScript\uFF09\u3002\u975E\u5E42\u7B49\u2014\u2014\u91CD\u8BD5\u4F1A\u5EFA\u51FA\u91CD\u590D flow\uFF0C\u91CD\u8BD5\u524D\u5148 tool workflow list --keyword <name> \u6838\u5BF9"
|
|
7297
|
+
).requiredOption("--name <name>", "\u5DE5\u4F5C\u6D41\u540D\u79F0").requiredOption(
|
|
7298
|
+
"--code <code|@file>",
|
|
7299
|
+
"CODE \u8282\u70B9 JavaScript \u4EE3\u7801\uFF1B\u503C\u4EE5 @ \u5F00\u5934\u5219\u8BFB\u53D6\u8BE5\u6587\u4EF6\u8DEF\u5F84\uFF08\u5982 @./tool.js\uFF09\uFF0C\u5426\u5219\u6309\u5B57\u9762\u4EE3\u7801"
|
|
7300
|
+
).option("--description <text>", "\u5DE5\u4F5C\u6D41\u63CF\u8FF0").option(
|
|
7301
|
+
"--input-vars <json|@file>",
|
|
7302
|
+
"\u8986\u76D6 START formConfig\uFF08@file \u540C --code\uFF09\uFF1B\u5F62\u6001\u662F formConfig \u6570\u7EC4 [{type,label,required,placeholder,variableName,...}]\uFF0C\u9ED8\u8BA4\u4EC5 dialogue\u3002\u6CE8\u610F\uFF1A\u4E0E tool create \u7684 --input-vars\uFF08input_var_descriptions\uFF09\u662F\u4E0D\u540C\u5B57\u6BB5"
|
|
7303
|
+
).option("--no-publish", "\u53EA\u5EFA\u8349\u7A3F\u4E0D\u53D1\u5E03").option("--code-node-name <name>", "CODE \u8282\u70B9\u540D\uFF08\u9ED8\u8BA4 javascript_1\uFF09").option("--version-desc <text>", "\u53D1\u5E03\u7248\u672C\u63CF\u8FF0\uFF08\u5E73\u53F0\u7248\u672C\u5386\u53F2\u91CC\u53EF\u89C1\uFF1B--no-publish \u65F6\u5FFD\u7565\uFF09").action(async (opts) => {
|
|
7304
|
+
try {
|
|
7305
|
+
const code = readArgMaybeFile(opts.code);
|
|
7306
|
+
const inputVars = opts.inputVars !== void 0 ? JSON.parse(readArgMaybeFile(opts.inputVars)) : void 0;
|
|
7307
|
+
const data = await createFlow({
|
|
7308
|
+
name: opts.name,
|
|
7309
|
+
code,
|
|
7310
|
+
description: opts.description,
|
|
7311
|
+
inputVars,
|
|
7312
|
+
codeNodeName: opts.codeNodeName,
|
|
7313
|
+
publish: opts.publish,
|
|
7314
|
+
versionDesc: opts.versionDesc
|
|
7315
|
+
});
|
|
7316
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7317
|
+
} catch (err) {
|
|
7318
|
+
reportCaughtError(err);
|
|
7319
|
+
process.exit(toExitCode(err));
|
|
7320
|
+
}
|
|
7321
|
+
});
|
|
7322
|
+
workflow.command("update <flow_id>").description("\u66F4\u65B0\u5DE5\u4F5C\u6D41\u552F\u4E00 CODE \u8282\u70B9\u7684\u4EE3\u7801\uFF08\u5176\u5B83\u8282\u70B9\u539F\u6837\u4FDD\u7559\uFF09").requiredOption(
|
|
7323
|
+
"--code <code|@file>",
|
|
7324
|
+
"CODE \u8282\u70B9\u65B0\u4EE3\u7801\uFF08JavaScript\uFF09\uFF1B\u503C\u4EE5 @ \u5F00\u5934\u5219\u8BFB\u53D6\u8BE5\u6587\u4EF6\u8DEF\u5F84\uFF0C\u5426\u5219\u6309\u5B57\u9762\u4EE3\u7801"
|
|
7325
|
+
).option("--no-publish", "\u53EA\u66F4\u65B0\u8349\u7A3F\u4E0D\u53D1\u5E03").option("--version-desc <text>", "\u53D1\u5E03\u7248\u672C\u63CF\u8FF0\uFF08\u5E73\u53F0\u7248\u672C\u5386\u53F2\u91CC\u53EF\u89C1\uFF1B--no-publish \u65F6\u5FFD\u7565\uFF09").action(async (flowId, opts) => {
|
|
7326
|
+
try {
|
|
7327
|
+
const code = readArgMaybeFile(opts.code);
|
|
7328
|
+
const data = await updateFlowCode({
|
|
7329
|
+
flowId,
|
|
7330
|
+
code,
|
|
7331
|
+
publish: opts.publish,
|
|
7332
|
+
versionDesc: opts.versionDesc
|
|
7333
|
+
});
|
|
7334
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7335
|
+
} catch (err) {
|
|
7336
|
+
reportCaughtError(err);
|
|
7337
|
+
process.exit(toExitCode(err));
|
|
7338
|
+
}
|
|
7339
|
+
});
|
|
7340
|
+
workflow.command("run <flow_id>").description(
|
|
7341
|
+
"\u8FD0\u884C\u5DF2\u53D1\u5E03\u7684\u5DE5\u4F5C\u6D41\uFF08HTTP \u540C\u6B65\u6267\u884C\uFF09\uFF1A\u81EA\u52A8\u53D6\u5F53\u524D\u7A7A\u95F4\u5E94\u7528\u6001 access key\uFF0C\u8FD4\u56DE run_result"
|
|
7342
|
+
).option(
|
|
7343
|
+
"--input <json|@file>",
|
|
7344
|
+
`flow \u5165\u53C2 JSON \u5BF9\u8C61\uFF08\u9ED8\u8BA4 {}\uFF09\uFF0C\u952E\u5BF9\u5E94 START formConfig \u7684 variableName\uFF0C\u5982 '{"dialogue":...}'\uFF1B@file \u540C --code`
|
|
7345
|
+
).action(async (flowId, opts) => {
|
|
7346
|
+
try {
|
|
7347
|
+
const inputs = opts.input !== void 0 ? JSON.parse(readArgMaybeFile(opts.input)) : void 0;
|
|
7348
|
+
const data = await runFlow({ flowId, inputs });
|
|
7349
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7350
|
+
} catch (err) {
|
|
7351
|
+
reportCaughtError(err);
|
|
7352
|
+
process.exit(toExitCode(err));
|
|
7353
|
+
}
|
|
7354
|
+
});
|
|
7355
|
+
workflow.command("delete <flow_id>").description("\u786C\u5220\u9664\u5DE5\u4F5C\u6D41\uFF08flow\uFF09\u2014\u2014\u4E0D\u53EF\u6062\u590D\uFF08\u533A\u522B\u4E8E tool delete \u7684\u8F6F\u5220\u9664\uFF09").option("--yes", "\u786E\u8BA4\u5220\u9664\uFF08\u5FC5\u987B\u663E\u5F0F\u52A0\uFF0C\u5426\u5219\u62D2\u7EDD\uFF09").action(async (flowId, opts) => {
|
|
7356
|
+
try {
|
|
7357
|
+
if (!opts.yes) {
|
|
7358
|
+
throw new APIError(1, "\u5220\u9664\u4F1A\u8BA9\u6307\u5411\u6B64 flow \u7684\u81EA\u5B9A\u4E49\u5DE5\u5177\u5931\u6548\uFF0C\u786E\u8BA4\u8BF7\u52A0 --yes");
|
|
7359
|
+
}
|
|
7360
|
+
const data = await deleteFlow({ flowId });
|
|
7361
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
7362
|
+
} catch (err) {
|
|
7363
|
+
reportCaughtError(err);
|
|
7364
|
+
process.exit(toExitCode(err));
|
|
7365
|
+
}
|
|
7366
|
+
});
|
|
7367
|
+
workflow.command("describe").description(
|
|
7368
|
+
"\u8F93\u51FA CODE \u8282\u70B9\uFF08JavaScript\uFF09\u4F7F\u7528\u6587\u6863\uFF1A\u5165\u53E3/\u53D8\u91CF\u6CE8\u5165/\u8FD4\u56DE\u503C/\u5185\u7F6E\u5305/SDK\uFF0C\u4F9D\u636E\u5B98\u65B9\u6587\u6863\u6574\u7406"
|
|
7369
|
+
).action(() => {
|
|
7370
|
+
formatOutput({ success: true, data: { guide: CODE_NODE_GUIDE } }, program2.opts().table);
|
|
7371
|
+
});
|
|
7372
|
+
}
|
|
7373
|
+
|
|
6784
7374
|
// src/commands/workspace.ts
|
|
6785
7375
|
var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
6786
7376
|
function toISODate(d) {
|
|
@@ -6874,6 +7464,7 @@ registerWorkspaceCommand(program);
|
|
|
6874
7464
|
registerAgentCommand(program);
|
|
6875
7465
|
registerOpsAgentCommand(program);
|
|
6876
7466
|
registerSACommand(program);
|
|
7467
|
+
registerToolCommand(program);
|
|
6877
7468
|
registerProductCommand(program);
|
|
6878
7469
|
registerMediaCommand(program);
|
|
6879
7470
|
registerKnowledgeCommand(program);
|