@bty/customer-service-cli 0.3.2 → 0.4.1
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/README.md +57 -17
- package/dist/bin.js +247 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -177,9 +177,20 @@ cs-cli --workspace ws-other agent list # ❌ 报错:CS_WORKSPACE_ID 已被
|
|
|
177
177
|
### 工作空间 (`workspace`)
|
|
178
178
|
|
|
179
179
|
|
|
180
|
-
| 命令
|
|
181
|
-
|
|
|
180
|
+
| 命令 | 说明 |
|
|
181
|
+
| --- | --- |
|
|
182
182
|
| `workspace list` | 列出所有工作空间 |
|
|
183
|
+
| `workspace points-consumes-daily [--start <YYYY-MM-DD>] [--end <YYYY-MM-DD>]` | 按天查询工作空间积分消耗(默认最近 30 天) |
|
|
184
|
+
|
|
185
|
+
`workspace points-consumes-daily` 需要可用的工作空间上下文(`--workspace`、本地 `.cs-cli.json` 或全局 `defaultWorkspaceId`)。
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# 查询最近 30 天(默认)
|
|
189
|
+
cs-cli workspace points-consumes-daily
|
|
190
|
+
|
|
191
|
+
# 指定日期范围(含 start/end)
|
|
192
|
+
cs-cli workspace points-consumes-daily --start 2026-04-01 --end 2026-04-23
|
|
193
|
+
```
|
|
183
194
|
|
|
184
195
|
|
|
185
196
|
### Agent 管理 (`agent`)
|
|
@@ -303,33 +314,27 @@ Agent 关联的通用规则知识库(`suffix_type=_common`),与 FAQ / 商
|
|
|
303
314
|
| `debug ask --agent <id> --text <消息> [--user <用户名>] [--url <图片URL>] [--conversation <会话ID>] [--timeout <秒>]` | 向 Agent 发送消息并等待回复 |
|
|
304
315
|
| `debug reproduce <record_id> [--agent <id>] [--timeout <秒>] [--dry-run]` | 根据 record_id 复现 Agent 回复(自动获取上下文) |
|
|
305
316
|
| `debug record <record_id>` | 获取记录的调试信息(flow_info),返回中包含 `trace_id` |
|
|
306
|
-
| `debug trace <trace_id
|
|
317
|
+
| `debug trace <trace_id> [--env <dev\|prod>]` | 根据 Langfuse Trace ID 获取完整 Trace 详情(经服务端代理,默认 `prod`) |
|
|
307
318
|
|
|
308
319
|
|
|
309
320
|
`debug ask` 会自动创建调试会话、发送消息、轮询等待 Agent 回复,默认最大等待 30 秒。支持 `--messages` 传入完整消息列表(JSON 或 @文件)重放 issue 对话。
|
|
310
321
|
|
|
311
322
|
`debug reproduce` 根据一条回复记录自动复现 Agent 回复:通过 recordId 获取关联会话和 Agent 配置,拉取完整会话记录并截取目标 record 之前的上下文,使用原始用户名创建新 debug 会话并发送。`--agent` 可指定另一个 Agent 复现同一段上下文(A/B 对比),`--dry-run` 仅输出上下文不发送。
|
|
312
323
|
|
|
313
|
-
`debug trace
|
|
324
|
+
`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` 字段获取。
|
|
314
325
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
Langfuse 已内置默认连接信息,通常无需配置。如需覆盖,支持环境变量和配置文件两种方式:
|
|
318
|
-
|
|
319
|
-
**环境变量(优先级最高):**
|
|
326
|
+
- `--env <dev|prod>`:指定 Langfuse 环境,默认 `prod`。只接受 `dev` / `prod`,传其它值命令直接报错并以非 0 退出(不发请求)。
|
|
320
327
|
|
|
321
328
|
```bash
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
export LANGFUSE_SECRET_KEY="sk-lf-xxx"
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
**配置文件(`~/.cs-cli/config.json`):**
|
|
329
|
+
# 默认 prod 环境
|
|
330
|
+
cs-cli debug trace <trace_id>
|
|
328
331
|
|
|
329
|
-
|
|
330
|
-
cs-cli
|
|
332
|
+
# 指定 dev 环境
|
|
333
|
+
cs-cli debug trace <trace_id> --env dev
|
|
331
334
|
```
|
|
332
335
|
|
|
336
|
+
> **迁移(v0.4.0 BREAKING)**:`config set --langfuse-host / --langfuse-public-key / --langfuse-secret-key` 及 `CLIConfig.langfuseHost / langfusePublicKey / langfuseSecretKey` 已移除;环境变量 `LANGFUSE_BASE_URL / LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY` 在 CLI 侧不再被读取。`~/.cs-cli/config.json` 中相关字段可直接删除。Langfuse 连接信息(含 dev/prod 双环境凭据)现由 customer-servhub-api 服务端的 `system_config` 表 `langfuse_config` 行统一管理(不再读服务端环境变量 / 内置常量),CLI 侧无需也无法再配置。
|
|
337
|
+
|
|
333
338
|
### 修复记录 (`repair-record`)
|
|
334
339
|
|
|
335
340
|
| 命令 | 说明 |
|
|
@@ -383,6 +388,41 @@ cs-cli config set --langfuse-host <url> --langfuse-public-key <key> --langfuse-s
|
|
|
383
388
|
|
|
384
389
|
创建记录时 `operator_id` 和 `operator_name` 自动从当前登录用户获取,无需手动指定。
|
|
385
390
|
|
|
391
|
+
### 商品变更事件消费 (`change-consumer`)
|
|
392
|
+
|
|
393
|
+
客服运维助手订阅并消费商品变更事件(**pull 模式**)。后端走 `/v1/change-consumers/*`,CLI 标准 Bearer 鉴权。默认 `consumer_key=ops_agent_assistant`。
|
|
394
|
+
|
|
395
|
+
标准工作流:`sub create` 创建订阅 → `delivery list` 轮询待消费项 → `delivery claim` 认领 → 处理 → `delivery complete` 回写。
|
|
396
|
+
|
|
397
|
+
| 命令 | 说明 |
|
|
398
|
+
| --- | --- |
|
|
399
|
+
| `change-consumer sub create --workspace-id <id> [--agent-config <id>] [--events <list>] [--resource-type product] [--consumer-key <key>] [--consumer-name <名称>] [--disabled] [--data <json\|@file>]` | 创建订阅(最简只需 `--workspace-id`;`--agent-config` 缺省表示该工作空间全部商品事件) |
|
|
400
|
+
| `change-consumer sub list [--workspace-id <id>] [--agent-config <id>] [--consumer-key <key>] [--enabled <true\|false>] [--page N] [--page-size N]` | 查询订阅列表 |
|
|
401
|
+
| `change-consumer sub update <subscription_id> --data <json\|@file>` | 更新订阅(`enabled` / `events` / `filters` / `consumer_name`) |
|
|
402
|
+
| `change-consumer delivery list [--workspace-id <id>] [--agent-config <id>] [--consumer-key <key>] [--statuses <list>] [--cursor-created-at <iso>] [--cursor-delivery-id <id>] [--limit N]` | 查询待消费项(不传 `--statuses` 时后端默认返回 pending/claimed/failed;`--cursor-*` 做增量拉取) |
|
|
403
|
+
| `change-consumer delivery claim <delivery_id> --claimed-by <id> [--consumer-key <key>] [--lease-seconds N]` | 认领待消费项(已被其他实例认领且未过期时认领失败) |
|
|
404
|
+
| `change-consumer delivery complete <delivery_id> --status <completed\|ignored\|failed> [--result-action <action>] [--result-note <note>] [--last-error <error>] [--consumer-key <key>] [--data <json\|@file>]` | 回写处理结果 |
|
|
405
|
+
|
|
406
|
+
- `sub create` 默认 `--events product.updated,product.deleted`、`--resource-type product`;`--disabled` 创建为停用态(默认启用)。
|
|
407
|
+
- `delivery complete` 的 `--status` 仅接受 `completed` / `ignored` / `failed`,其它值直接报错退出;不要长时间停留在 `claimed` 不回写。
|
|
408
|
+
- `--result-action` 建议值:`supplemental_knowledge` / `product_association` / `rerun_product_study` / `refresh_recommended_qa` / `ignore_change` / `manual_follow_up`。
|
|
409
|
+
- 各子命令 `--data <json|@file>` 为高级用法,提供时覆盖对应结构化选项。
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
# 1. 创建订阅(该工作空间全部商品 更新/删除 事件)
|
|
413
|
+
cs-cli change-consumer sub create --workspace-id <ws> --events product.updated,product.deleted
|
|
414
|
+
|
|
415
|
+
# 2. 轮询待消费项
|
|
416
|
+
cs-cli change-consumer delivery list --workspace-id <ws> --statuses pending
|
|
417
|
+
|
|
418
|
+
# 3. 认领
|
|
419
|
+
cs-cli change-consumer delivery claim <delivery_id> --claimed-by ops-assistant-1
|
|
420
|
+
|
|
421
|
+
# 4. 处理后回写
|
|
422
|
+
cs-cli change-consumer delivery complete <delivery_id> --status completed \
|
|
423
|
+
--result-action supplemental_knowledge --result-note "已补充商品知识"
|
|
424
|
+
```
|
|
425
|
+
|
|
386
426
|
### 运营监控 (`monitor`)
|
|
387
427
|
|
|
388
428
|
直接调用 `/v1/operation` 底层接口,返回原始数据,由调用方决定如何聚合统计。
|
package/dist/bin.js
CHANGED
|
@@ -437,9 +437,6 @@ function isTokenExpired(expiresAt) {
|
|
|
437
437
|
var DEFAULT_CS_API_URL = "https://customer-servhub-api.betteryeah.com";
|
|
438
438
|
var DEFAULT_AI_API_URL = "https://ai-api.betteryeah.com";
|
|
439
439
|
var DEFAULT_CUSTOMER_AGENT_API_URL = "https://customer-agent.bantouyan.com";
|
|
440
|
-
var DEFAULT_LANGFUSE_HOST = "http://192.168.40.10:3000";
|
|
441
|
-
var DEFAULT_LANGFUSE_PUBLIC_KEY = "pk-lf-1b3aece4-021a-4a81-be4a-abd6334c5929";
|
|
442
|
-
var DEFAULT_LANGFUSE_SECRET_KEY = "sk-lf-edc22ac8-5d0a-4f72-b285-6556adfa8f71";
|
|
443
440
|
function getCustomerServiceUrl() {
|
|
444
441
|
const envUrl = process.env.CS_CS_API_URL;
|
|
445
442
|
if (envUrl) return envUrl;
|
|
@@ -473,14 +470,6 @@ function getWorkspaceId(overrideWorkspaceId) {
|
|
|
473
470
|
if (globalConfig?.defaultWorkspaceId) return globalConfig.defaultWorkspaceId;
|
|
474
471
|
throw new APIError(1, "\u672A\u8BBE\u7F6E\u5DE5\u4F5C\u7A7A\u95F4\uFF0C\u8BF7\u8FD0\u884C: cs-cli config set-workspace <id>");
|
|
475
472
|
}
|
|
476
|
-
function getLangfuseConfig() {
|
|
477
|
-
const config = readConfig();
|
|
478
|
-
return {
|
|
479
|
-
host: process.env.LANGFUSE_BASE_URL ?? config?.langfuseHost ?? DEFAULT_LANGFUSE_HOST,
|
|
480
|
-
publicKey: process.env.LANGFUSE_PUBLIC_KEY ?? config?.langfusePublicKey ?? DEFAULT_LANGFUSE_PUBLIC_KEY,
|
|
481
|
-
secretKey: process.env.LANGFUSE_SECRET_KEY ?? config?.langfuseSecretKey ?? DEFAULT_LANGFUSE_SECRET_KEY
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
473
|
function buildCookieHeaders() {
|
|
485
474
|
const creds = readCredentials();
|
|
486
475
|
if (!creds) throw new APIError(2, "\u672A\u767B\u5F55\uFF0C\u8BF7\u8FD0\u884C: cs-cli auth login");
|
|
@@ -696,6 +685,195 @@ function registerAuthCommand(program2) {
|
|
|
696
685
|
});
|
|
697
686
|
}
|
|
698
687
|
|
|
688
|
+
// src/client/change-consumer-api.ts
|
|
689
|
+
var SUBSCRIPTIONS_PATH = "/v1/change-consumers/subscriptions";
|
|
690
|
+
var DEFAULT_CONSUMER_KEY = "ops_agent_assistant";
|
|
691
|
+
async function createSubscription(body) {
|
|
692
|
+
const request = createRequest();
|
|
693
|
+
return request(getCustomerServiceUrl(), SUBSCRIPTIONS_PATH, {
|
|
694
|
+
method: "POST",
|
|
695
|
+
body
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
async function listSubscriptions(opts) {
|
|
699
|
+
const request = createRequest();
|
|
700
|
+
const query = {};
|
|
701
|
+
if (opts.workspaceId) query.workspace_id = opts.workspaceId;
|
|
702
|
+
if (opts.customerAgentConfigId) query.customer_agent_config_id = opts.customerAgentConfigId;
|
|
703
|
+
if (opts.consumerKey) query.consumer_key = opts.consumerKey;
|
|
704
|
+
if (opts.enabled !== void 0) query.enabled = opts.enabled;
|
|
705
|
+
if (opts.page) query.page = opts.page;
|
|
706
|
+
if (opts.pageSize) query.page_size = opts.pageSize;
|
|
707
|
+
return request(getCustomerServiceUrl(), SUBSCRIPTIONS_PATH, {
|
|
708
|
+
method: "GET",
|
|
709
|
+
query
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
async function updateSubscription(subscriptionId, body) {
|
|
713
|
+
const request = createRequest();
|
|
714
|
+
return request(
|
|
715
|
+
getCustomerServiceUrl(),
|
|
716
|
+
`${SUBSCRIPTIONS_PATH}/${subscriptionId}`,
|
|
717
|
+
{ method: "PUT", body }
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
async function listDeliveries(consumerKey, opts) {
|
|
721
|
+
const request = createRequest();
|
|
722
|
+
const query = {};
|
|
723
|
+
if (opts.workspaceId) query.workspace_id = opts.workspaceId;
|
|
724
|
+
if (opts.customerAgentConfigId) query.customer_agent_config_id = opts.customerAgentConfigId;
|
|
725
|
+
if (opts.statuses) query.statuses = opts.statuses;
|
|
726
|
+
if (opts.cursorCreatedAt) query.cursor_created_at = opts.cursorCreatedAt;
|
|
727
|
+
if (opts.cursorDeliveryId) query.cursor_delivery_id = opts.cursorDeliveryId;
|
|
728
|
+
if (opts.limit) query.limit = opts.limit;
|
|
729
|
+
return request(
|
|
730
|
+
getCustomerServiceUrl(),
|
|
731
|
+
`/v1/change-consumers/${encodeURIComponent(consumerKey)}/deliveries`,
|
|
732
|
+
{ method: "GET", query }
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
async function claimDelivery(deliveryId, body) {
|
|
736
|
+
const request = createRequest();
|
|
737
|
+
return request(
|
|
738
|
+
getCustomerServiceUrl(),
|
|
739
|
+
`/v1/change-consumers/deliveries/${deliveryId}/claim`,
|
|
740
|
+
{ method: "POST", body }
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
async function completeDelivery(deliveryId, body) {
|
|
744
|
+
const request = createRequest();
|
|
745
|
+
return request(
|
|
746
|
+
getCustomerServiceUrl(),
|
|
747
|
+
`/v1/change-consumers/deliveries/${deliveryId}/complete`,
|
|
748
|
+
{ method: "POST", body }
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/commands/change-consumer.ts
|
|
753
|
+
function registerChangeConsumerCommand(program2) {
|
|
754
|
+
const cc = program2.command("change-consumer").description(
|
|
755
|
+
"\u5546\u54C1\u53D8\u66F4\u4E8B\u4EF6\u6D88\u8D39 \u2014\u2014 \u5BA2\u670D\u8FD0\u7EF4\u52A9\u624B\u8BA2\u9605\u5E76\u6D88\u8D39\u5546\u54C1\u53D8\u66F4\uFF08pull \u6A21\u5F0F\uFF09\u3002\u5DE5\u4F5C\u6D41\uFF1Asub create \u521B\u5EFA\u8BA2\u9605 \u2192 delivery list \u8F6E\u8BE2\u5F85\u6D88\u8D39\u9879 \u2192 delivery claim \u8BA4\u9886 \u2192 \u63D0\u793A\u7528\u6237\u5E76\u5904\u7406 \u2192 delivery complete \u56DE\u5199\u3002\u9ED8\u8BA4 consumer_key=" + DEFAULT_CONSUMER_KEY
|
|
756
|
+
);
|
|
757
|
+
const sub = cc.command("sub").description("\u8BA2\u9605\u7BA1\u7406\uFF08subscription\uFF09");
|
|
758
|
+
sub.command("create").description(
|
|
759
|
+
"\u521B\u5EFA\u8BA2\u9605\u3002\u6700\u7B80\u914D\u7F6E\u53EA\u9700 workspace-id + events\uFF1Bcustomer-agent-config-id \u4E0D\u4F20\u8868\u793A\u8BE5 Agent \u5168\u90E8\u5546\u54C1\u4E8B\u4EF6"
|
|
760
|
+
).option("--consumer-key <key>", "consumer_key", DEFAULT_CONSUMER_KEY).option("--consumer-name <name>", "consumer \u663E\u793A\u540D", "\u5BA2\u670D\u8FD0\u7EF4\u52A9\u624B").requiredOption("--workspace-id <workspace_id>", "\u5DE5\u4F5C\u7A7A\u95F4 ID").option("--agent-config <id>", "customer_agent_config_id\uFF08\u53EF\u9009\uFF0C\u7F3A\u7701\u8868\u793A\u5168\u90E8\uFF09").option("--resource-type <type>", "\u8D44\u6E90\u7C7B\u578B", "product").option(
|
|
761
|
+
"--events <list>",
|
|
762
|
+
"\u9017\u53F7\u5206\u9694\u4E8B\u4EF6\u5217\u8868\uFF0C\u5982 product.updated,product.deleted",
|
|
763
|
+
"product.updated,product.deleted"
|
|
764
|
+
).option("--disabled", "\u521B\u5EFA\u4E3A\u505C\u7528\u72B6\u6001\uFF08\u9ED8\u8BA4\u542F\u7528\uFF09", false).option("--data <json>", "\u9AD8\u7EA7\uFF1A\u5B8C\u6574\u8BA2\u9605 JSON \u6216 @\u6587\u4EF6\uFF0C\u63D0\u4F9B\u65F6\u8986\u76D6\u4E0A\u8FF0\u9009\u9879").action(async (opts) => {
|
|
765
|
+
try {
|
|
766
|
+
const body = opts.data ? parseDataOption(opts.data) : {
|
|
767
|
+
consumer_key: opts.consumerKey,
|
|
768
|
+
consumer_name: opts.consumerName,
|
|
769
|
+
mode: "pull",
|
|
770
|
+
workspace_id: opts.workspaceId,
|
|
771
|
+
customer_agent_config_id: opts.agentConfig,
|
|
772
|
+
resource_type: opts.resourceType,
|
|
773
|
+
enabled: !opts.disabled,
|
|
774
|
+
events: String(opts.events).split(",").map((e) => e.trim()).filter(Boolean)
|
|
775
|
+
};
|
|
776
|
+
const data = await createSubscription(body);
|
|
777
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
778
|
+
} catch (err) {
|
|
779
|
+
reportCaughtError(err);
|
|
780
|
+
process.exit(toExitCode(err));
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
sub.command("list").description("\u67E5\u8BE2\u8BA2\u9605\u5217\u8868").option("--workspace-id <workspace_id>", "\u6309\u5DE5\u4F5C\u7A7A\u95F4\u7B5B\u9009").option("--agent-config <id>", "\u6309 customer_agent_config_id \u7B5B\u9009").option("--consumer-key <key>", "\u6309 consumer_key \u7B5B\u9009", DEFAULT_CONSUMER_KEY).option("--enabled <bool>", "\u6309\u542F\u7528\u72B6\u6001\u7B5B\u9009 true/false").option("--page <number>", "\u9875\u7801", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF", "20").action(async (opts) => {
|
|
784
|
+
try {
|
|
785
|
+
const data = await listSubscriptions({
|
|
786
|
+
workspaceId: opts.workspaceId,
|
|
787
|
+
customerAgentConfigId: opts.agentConfig,
|
|
788
|
+
consumerKey: opts.consumerKey,
|
|
789
|
+
enabled: opts.enabled === void 0 ? void 0 : opts.enabled === "true",
|
|
790
|
+
page: Number(opts.page),
|
|
791
|
+
pageSize: Number(opts.pageSize)
|
|
792
|
+
});
|
|
793
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
794
|
+
} catch (err) {
|
|
795
|
+
reportCaughtError(err);
|
|
796
|
+
process.exit(toExitCode(err));
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
sub.command("update").description("\u66F4\u65B0\u8BA2\u9605\u3002\u53EF\u66F4\u65B0 enabled / events / filters / consumer_name").argument("<subscription_id>", "\u8BA2\u9605 ID\uFF08\u4ECE sub list \u83B7\u53D6\uFF09").requiredOption(
|
|
800
|
+
"--data <json>",
|
|
801
|
+
'JSON \u6216 @\u6587\u4EF6\uFF0C\u5982 {"enabled":true,"filters":{"changed_fields_any":["sku"]}}'
|
|
802
|
+
).action(async (subscriptionId, opts) => {
|
|
803
|
+
try {
|
|
804
|
+
const body = parseDataOption(opts.data);
|
|
805
|
+
const data = await updateSubscription(subscriptionId, body);
|
|
806
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
807
|
+
} catch (err) {
|
|
808
|
+
reportCaughtError(err);
|
|
809
|
+
process.exit(toExitCode(err));
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
const delivery = cc.command("delivery").description("\u5F85\u6D88\u8D39\u9879\u7BA1\u7406\uFF08delivery\uFF09");
|
|
813
|
+
delivery.command("list").description(
|
|
814
|
+
"\u67E5\u8BE2\u5F85\u6D88\u8D39\u9879\u3002\u4E0D\u4F20 --statuses \u65F6\u540E\u7AEF\u9ED8\u8BA4\u8FD4\u56DE pending/claimed/failed\uFF1B\u7528 --cursor-* \u505A\u589E\u91CF\u62C9\u53D6"
|
|
815
|
+
).option("--consumer-key <key>", "consumer_key", DEFAULT_CONSUMER_KEY).option("--workspace-id <workspace_id>", "\u6309\u5DE5\u4F5C\u7A7A\u95F4\u7B5B\u9009").option("--agent-config <id>", "\u6309 customer_agent_config_id \u7B5B\u9009").option("--statuses <list>", "\u72B6\u6001\u8FC7\u6EE4\uFF0C\u9017\u53F7\u5206\u9694\uFF0C\u5982 pending,claimed").option("--cursor-created-at <iso>", "\u589E\u91CF\u6E38\u6807\uFF1A\u4E0A\u4E00\u9875 next_cursor.cursor_created_at").option("--cursor-delivery-id <id>", "\u589E\u91CF\u6E38\u6807\uFF1A\u4E0A\u4E00\u9875 next_cursor.cursor_delivery_id").option("--limit <number>", "\u5355\u6B21\u62C9\u53D6\u6761\u6570", "20").action(async (opts) => {
|
|
816
|
+
try {
|
|
817
|
+
const data = await listDeliveries(opts.consumerKey, {
|
|
818
|
+
workspaceId: opts.workspaceId,
|
|
819
|
+
customerAgentConfigId: opts.agentConfig,
|
|
820
|
+
statuses: opts.statuses,
|
|
821
|
+
cursorCreatedAt: opts.cursorCreatedAt,
|
|
822
|
+
cursorDeliveryId: opts.cursorDeliveryId,
|
|
823
|
+
limit: Number(opts.limit)
|
|
824
|
+
});
|
|
825
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
826
|
+
} catch (err) {
|
|
827
|
+
reportCaughtError(err);
|
|
828
|
+
process.exit(toExitCode(err));
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
delivery.command("claim").description("\u8BA4\u9886\u5F85\u6D88\u8D39\u9879\u3002\u5DF2\u88AB\u5176\u4ED6\u5B9E\u4F8B\u8BA4\u9886\u4E14\u672A\u8FC7\u671F\u65F6\u8BA4\u9886\u4F1A\u5931\u8D25").argument("<delivery_id>", "\u5F85\u6D88\u8D39\u9879 ID\uFF08\u4ECE delivery list \u83B7\u53D6\uFF09").option("--consumer-key <key>", "consumer_key", DEFAULT_CONSUMER_KEY).requiredOption("--claimed-by <id>", "\u8BA4\u9886\u8005\u6807\u8BC6\uFF0C\u5EFA\u8BAE\u4F20\u8FD0\u7EF4\u52A9\u624B\u5B9E\u4F8B\u6807\u8BC6").option("--lease-seconds <number>", "\u8BA4\u9886\u6709\u6548\u671F\uFF08\u79D2\uFF09", "300").action(async (deliveryId, opts) => {
|
|
832
|
+
try {
|
|
833
|
+
const data = await claimDelivery(deliveryId, {
|
|
834
|
+
consumer_key: opts.consumerKey,
|
|
835
|
+
claimed_by: opts.claimedBy,
|
|
836
|
+
lease_seconds: Number(opts.leaseSeconds)
|
|
837
|
+
});
|
|
838
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
839
|
+
} catch (err) {
|
|
840
|
+
reportCaughtError(err);
|
|
841
|
+
process.exit(toExitCode(err));
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
delivery.command("complete").description(
|
|
845
|
+
"\u56DE\u5199\u5904\u7406\u7ED3\u679C\u3002status \u53D6 completed/ignored/failed\uFF1B\u4E0D\u8981\u957F\u65F6\u95F4\u505C\u7559\u5728 claimed \u4E0D\u56DE\u5199"
|
|
846
|
+
).argument("<delivery_id>", "\u5F85\u6D88\u8D39\u9879 ID\uFF08\u4ECE delivery list \u83B7\u53D6\uFF09").option("--consumer-key <key>", "consumer_key", DEFAULT_CONSUMER_KEY).requiredOption(
|
|
847
|
+
"--status <status>",
|
|
848
|
+
"completed | ignored | failed"
|
|
849
|
+
).option(
|
|
850
|
+
"--result-action <action>",
|
|
851
|
+
"\u5EFA\u8BAE\u503C: supplemental_knowledge / product_association / rerun_product_study / refresh_recommended_qa / ignore_change / manual_follow_up"
|
|
852
|
+
).option("--result-note <note>", "\u5904\u7406\u8BF4\u660E").option("--last-error <error>", "status=failed \u65F6\u7684\u9519\u8BEF\u63CF\u8FF0").option("--data <json>", "\u9AD8\u7EA7\uFF1A\u5B8C\u6574\u56DE\u5199 JSON \u6216 @\u6587\u4EF6\uFF0C\u63D0\u4F9B\u65F6\u8986\u76D6\u4E0A\u8FF0\u9009\u9879").action(async (deliveryId, opts) => {
|
|
853
|
+
try {
|
|
854
|
+
const status = opts.status;
|
|
855
|
+
if (!["completed", "ignored", "failed"].includes(status)) {
|
|
856
|
+
reportCaughtError(
|
|
857
|
+
new Error("--status \u53EA\u80FD\u662F completed / ignored / failed")
|
|
858
|
+
);
|
|
859
|
+
process.exit(1);
|
|
860
|
+
}
|
|
861
|
+
const body = opts.data ? parseDataOption(opts.data) : {
|
|
862
|
+
consumer_key: opts.consumerKey,
|
|
863
|
+
status,
|
|
864
|
+
result_action: opts.resultAction,
|
|
865
|
+
result_note: opts.resultNote,
|
|
866
|
+
last_error: opts.lastError
|
|
867
|
+
};
|
|
868
|
+
const data = await completeDelivery(deliveryId, body);
|
|
869
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
870
|
+
} catch (err) {
|
|
871
|
+
reportCaughtError(err);
|
|
872
|
+
process.exit(toExitCode(err));
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
|
|
699
877
|
// src/client/chat-history-api.ts
|
|
700
878
|
async function listChatHistory(opts) {
|
|
701
879
|
const request = createRequest();
|
|
@@ -733,20 +911,28 @@ async function listWorkspaces() {
|
|
|
733
911
|
const request = createRequest();
|
|
734
912
|
return request(getCustomerServiceUrl(), "/v1/client/workspaces", { method: "GET" });
|
|
735
913
|
}
|
|
914
|
+
async function getDailyDeduction(opts) {
|
|
915
|
+
const request = createRequest();
|
|
916
|
+
return request(
|
|
917
|
+
getCustomerServiceUrl(),
|
|
918
|
+
"/v1/workspace/points_consumes/daily_deduction",
|
|
919
|
+
{
|
|
920
|
+
method: "POST",
|
|
921
|
+
body: { start_time: opts.startTime, end_time: opts.endTime }
|
|
922
|
+
}
|
|
923
|
+
);
|
|
924
|
+
}
|
|
736
925
|
|
|
737
926
|
// src/commands/config.ts
|
|
738
927
|
function registerConfigCommand(program2) {
|
|
739
928
|
const config = program2.command("config").description(
|
|
740
929
|
"\u914D\u7F6E\u7BA1\u7406 \u2014\u2014 API \u5730\u5740\u3001\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u7B49\u6301\u4E45\u5316\u8BBE\u7F6E\u3002\u652F\u6301\u5168\u5C40\u914D\u7F6E\u548C\u76EE\u5F55\u7EA7\u672C\u5730\u914D\u7F6E\uFF08.cs-cli.json\uFF09"
|
|
741
930
|
);
|
|
742
|
-
config.command("set").description("\u8BBE\u7F6E API \u5730\u5740").option("--cs-api <url>", "\u5BA2\u670D API \u5730\u5740").option("--ai-api <url>", "AI API \u5730\u5740").option("--agent-api <url>", "Customer Agent API \u5730\u5740").
|
|
931
|
+
config.command("set").description("\u8BBE\u7F6E API \u5730\u5740").option("--cs-api <url>", "\u5BA2\u670D API \u5730\u5740").option("--ai-api <url>", "AI API \u5730\u5740").option("--agent-api <url>", "Customer Agent API \u5730\u5740").action((opts) => {
|
|
743
932
|
const updates = {};
|
|
744
933
|
if (opts.csApi) updates.customerServiceApiUrl = opts.csApi;
|
|
745
934
|
if (opts.aiApi) updates.aiApiUrl = opts.aiApi;
|
|
746
935
|
if (opts.agentApi) updates.customerAgentApiUrl = opts.agentApi;
|
|
747
|
-
if (opts.langfuseHost) updates.langfuseHost = opts.langfuseHost;
|
|
748
|
-
if (opts.langfusePublicKey) updates.langfusePublicKey = opts.langfusePublicKey;
|
|
749
|
-
if (opts.langfuseSecretKey) updates.langfuseSecretKey = opts.langfuseSecretKey;
|
|
750
936
|
writeConfig(updates);
|
|
751
937
|
formatOutput({ success: true, data: readConfig() }, program2.opts().table);
|
|
752
938
|
});
|
|
@@ -1092,22 +1278,16 @@ async function getFlowExecuteLog(opts) {
|
|
|
1092
1278
|
const log = await logRes.json();
|
|
1093
1279
|
return { executeLog, log };
|
|
1094
1280
|
}
|
|
1095
|
-
async function getLangfuseTrace(traceId) {
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
"Content-Type": "application/json"
|
|
1281
|
+
async function getLangfuseTrace(traceId, env) {
|
|
1282
|
+
const request = createRequest();
|
|
1283
|
+
return request(
|
|
1284
|
+
getCustomerServiceUrl(),
|
|
1285
|
+
`/v1/debug/langfuse/trace/${encodeURIComponent(traceId)}`,
|
|
1286
|
+
{
|
|
1287
|
+
method: "GET",
|
|
1288
|
+
query: { env }
|
|
1104
1289
|
}
|
|
1105
|
-
|
|
1106
|
-
if (!res.ok) {
|
|
1107
|
-
const text = await res.text().catch(() => "");
|
|
1108
|
-
throw new Error(`Langfuse API error ${res.status}: ${text}`);
|
|
1109
|
-
}
|
|
1110
|
-
return res.json();
|
|
1290
|
+
);
|
|
1111
1291
|
}
|
|
1112
1292
|
|
|
1113
1293
|
// src/commands/debug.ts
|
|
@@ -1281,9 +1461,13 @@ function registerDebugCommand(program2) {
|
|
|
1281
1461
|
});
|
|
1282
1462
|
debug.command("trace").description(
|
|
1283
1463
|
"\u6839\u636E Langfuse Trace ID \u83B7\u53D6\u5B8C\u6574\u7684 Trace \u8BE6\u60C5\uFF08\u4ECE debug record \u8FD4\u56DE\u7684 flow_info \u4E2D\u63D0\u53D6 traceId\uFF09"
|
|
1284
|
-
).argument("<trace_id>", "Langfuse Trace ID\uFF08\u4ECE flow_info \u4E2D\u83B7\u53D6\uFF09").action(async (traceId) => {
|
|
1464
|
+
).argument("<trace_id>", "Langfuse Trace ID\uFF08\u4ECE flow_info \u4E2D\u83B7\u53D6\uFF09").option("--env <env>", "langfuse \u73AF\u5883 dev|prod", "prod").action(async (traceId, opts) => {
|
|
1285
1465
|
try {
|
|
1286
|
-
|
|
1466
|
+
if (opts.env !== "dev" && opts.env !== "prod") {
|
|
1467
|
+
outputError(1, "--env \u4EC5\u652F\u6301 dev \u6216 prod");
|
|
1468
|
+
process.exit(1);
|
|
1469
|
+
}
|
|
1470
|
+
const data = await getLangfuseTrace(traceId, opts.env);
|
|
1287
1471
|
formatOutput({ success: true, data }, program2.opts().table);
|
|
1288
1472
|
} catch (err) {
|
|
1289
1473
|
reportCaughtError(err);
|
|
@@ -3066,6 +3250,13 @@ function registerSACommand(program2) {
|
|
|
3066
3250
|
}
|
|
3067
3251
|
|
|
3068
3252
|
// src/commands/workspace.ts
|
|
3253
|
+
var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
3254
|
+
function toISODate(d) {
|
|
3255
|
+
const yyyy = d.getFullYear();
|
|
3256
|
+
const mm = String(d.getMonth() + 1).padStart(2, "0");
|
|
3257
|
+
const dd = String(d.getDate()).padStart(2, "0");
|
|
3258
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
3259
|
+
}
|
|
3069
3260
|
function registerWorkspaceCommand(program2) {
|
|
3070
3261
|
const workspace = program2.command("workspace").description("\u5DE5\u4F5C\u7A7A\u95F4\u7BA1\u7406 \u2014\u2014 \u4E00\u4E2A\u5DE5\u4F5C\u7A7A\u95F4\u5BF9\u5E94\u4E00\u4E2A\u5BA2\u6237/\u5E97\u94FA\uFF0C\u5305\u542B\u8BE5\u5BA2\u6237\u7684\u6240\u6709 Agent");
|
|
3071
3262
|
workspace.command("list").description("\u5217\u51FA\u5F53\u524D\u8D26\u53F7\u53EF\u8BBF\u95EE\u7684\u6240\u6709\u5DE5\u4F5C\u7A7A\u95F4\u3002\u8FD4\u56DE id \u548C name\uFF0C\u7528\u4E8E config set-workspace").action(async () => {
|
|
@@ -3077,6 +3268,28 @@ function registerWorkspaceCommand(program2) {
|
|
|
3077
3268
|
process.exit(toExitCode(err));
|
|
3078
3269
|
}
|
|
3079
3270
|
});
|
|
3271
|
+
workspace.command("points-consumes-daily").description(
|
|
3272
|
+
"\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"
|
|
3273
|
+
).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) => {
|
|
3274
|
+
try {
|
|
3275
|
+
const now = /* @__PURE__ */ new Date();
|
|
3276
|
+
const defaultEnd = toISODate(now);
|
|
3277
|
+
const defaultStart = toISODate(new Date(now.getTime() - 29 * 24 * 60 * 60 * 1e3));
|
|
3278
|
+
const startTime = opts.start ?? defaultStart;
|
|
3279
|
+
const endTime = opts.end ?? defaultEnd;
|
|
3280
|
+
if (!DATE_RE.test(startTime) || !DATE_RE.test(endTime)) {
|
|
3281
|
+
throw new Error("--start / --end \u9700\u4E3A YYYY-MM-DD \u683C\u5F0F");
|
|
3282
|
+
}
|
|
3283
|
+
if (startTime > endTime) {
|
|
3284
|
+
throw new Error("--start \u4E0D\u80FD\u665A\u4E8E --end");
|
|
3285
|
+
}
|
|
3286
|
+
const data = await getDailyDeduction({ startTime, endTime });
|
|
3287
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
3288
|
+
} catch (err) {
|
|
3289
|
+
reportCaughtError(err);
|
|
3290
|
+
process.exit(toExitCode(err));
|
|
3291
|
+
}
|
|
3292
|
+
});
|
|
3080
3293
|
}
|
|
3081
3294
|
|
|
3082
3295
|
// src/bin.ts
|
|
@@ -3084,7 +3297,7 @@ var require2 = createRequire(import.meta.url);
|
|
|
3084
3297
|
var { version } = require2("../package.json");
|
|
3085
3298
|
var program = new Command();
|
|
3086
3299
|
program.name("cs-cli").description(
|
|
3087
|
-
"BetterYeah AI \u5BA2\u670D\u5E73\u53F0 CLI\u3002\u6838\u5FC3\u6982\u5FF5\uFF1Aworkspace\uFF08\u5DE5\u4F5C\u7A7A\u95F4\uFF09\u2192 agent\uFF08AI \u5BA2\u670D\u673A\u5668\u4EBA\uFF09\u2192 SA/product/FAQ\uFF08\u77E5\u8BC6\u914D\u7F6E\uFF09\u2192 issue\uFF08\u5DE5\u5355\uFF09\u2192 debug\uFF08\u8C03\u8BD5\u9A8C\u8BC1\uFF09\u2192 monitor\uFF08\u8FD0\u8425\u76D1\u63A7\uFF09\u2192 repair-record\uFF08\u4FEE\u590D\u5BA1\u8BA1\uFF09\u3002\u6240\u6709\u547D\u4EE4\u9ED8\u8BA4\u8F93\u51FA JSON\uFF0C\u8FFD\u52A0 --table \u53EF\u5207\u6362\u4E3A\u4EBA\u7C7B\u53EF\u8BFB\u8868\u683C"
|
|
3300
|
+
"BetterYeah AI \u5BA2\u670D\u5E73\u53F0 CLI\u3002\u6838\u5FC3\u6982\u5FF5\uFF1Aworkspace\uFF08\u5DE5\u4F5C\u7A7A\u95F4\uFF09\u2192 agent\uFF08AI \u5BA2\u670D\u673A\u5668\u4EBA\uFF09\u2192 SA/product/FAQ\uFF08\u77E5\u8BC6\u914D\u7F6E\uFF09\u2192 issue\uFF08\u5DE5\u5355\uFF09\u2192 debug\uFF08\u8C03\u8BD5\u9A8C\u8BC1\uFF09\u2192 monitor\uFF08\u8FD0\u8425\u76D1\u63A7\uFF09\u2192 repair-record\uFF08\u4FEE\u590D\u5BA1\u8BA1\uFF09\u2192 change-consumer\uFF08\u5546\u54C1\u53D8\u66F4\u4E8B\u4EF6\u6D88\u8D39\uFF09\u3002\u6240\u6709\u547D\u4EE4\u9ED8\u8BA4\u8F93\u51FA JSON\uFF0C\u8FFD\u52A0 --table \u53EF\u5207\u6362\u4E3A\u4EBA\u7C7B\u53EF\u8BFB\u8868\u683C"
|
|
3088
3301
|
).version(version).option("--table", "\u4EE5\u8868\u683C\u5F62\u5F0F\u8F93\u51FA\uFF08\u9ED8\u8BA4 JSON\uFF09\u3002\u4EBA\u5DE5\u67E5\u770B\u65F6\u4F7F\u7528", false).option("--workspace <id>", "\u4E34\u65F6\u8986\u76D6\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4 ID\uFF0C\u4E0D\u4FEE\u6539\u6301\u4E45\u5316\u914D\u7F6E").option(
|
|
3089
3302
|
"--request-timeout <ms>",
|
|
3090
3303
|
"\u5355\u4E2A HTTP \u8BF7\u6C42\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09\uFF0C\u590D\u6742 Agent \u56DE\u590D\u5EFA\u8BAE\u8C03\u9AD8\u3002\u4E0D\u8981\u5199 --timeout\uFF0C\u90A3\u662F\u5B50\u547D\u4EE4\u7684\u8F6E\u8BE2\u7A97\u53E3\uFF08\u79D2\uFF09",
|
|
@@ -3121,6 +3334,7 @@ registerDebugCommand(program);
|
|
|
3121
3334
|
registerMonitorCommand(program);
|
|
3122
3335
|
registerRepairRecordCommand(program);
|
|
3123
3336
|
registerOperationsRecordCommand(program);
|
|
3337
|
+
registerChangeConsumerCommand(program);
|
|
3124
3338
|
process.on("uncaughtException", (err) => {
|
|
3125
3339
|
outputError(3, err.message);
|
|
3126
3340
|
process.exit(3);
|