@reconcrap/boss-recommend-mcp 1.3.36 → 1.3.38
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 +6 -2
- package/package.json +1 -1
- package/skills/boss-chat/SKILL.md +8 -0
- package/skills/boss-recommend-pipeline/SKILL.md +2 -0
- package/src/boss-chat.js +32 -27
- package/src/cli.js +8 -1
- package/src/index.js +28 -0
- package/src/pipeline.js +139 -14
- package/src/test-boss-chat.js +191 -75
- package/src/test-pipeline.js +123 -4
- package/vendor/boss-chat-cli/src/app.js +21 -16
- package/vendor/boss-chat-cli/src/cli.js +68 -50
- package/vendor/boss-chat-cli/src/services/profile-store.js +26 -21
package/README.md
CHANGED
|
@@ -188,7 +188,7 @@ node src/cli.js launch-chrome --port 9222
|
|
|
188
188
|
node src/cli.js run --instruction-file request.txt --confirmation-file confirmation.json --overrides-file overrides.json
|
|
189
189
|
node src/cli.js run --instruction-file request.txt --confirmation-file confirmation.json --overrides-file overrides.json --follow-up-file follow-up.json
|
|
190
190
|
node src/cli.js chat health-check
|
|
191
|
-
node src/cli.js chat run --job "算法工程师" --start-from unread --criteria "有 AI Agent 经验" --targetCount 20
|
|
191
|
+
node src/cli.js chat run --job "算法工程师" --start-from unread --criteria "有 AI Agent 经验" --targetCount 20 --greeting-text "您好,方便发下简历吗?"
|
|
192
192
|
```
|
|
193
193
|
|
|
194
194
|
## Recommend + Chat Follow-up
|
|
@@ -201,6 +201,7 @@ node src/cli.js chat run --job "算法工程师" --start-from unread --criteria
|
|
|
201
201
|
"chat": {
|
|
202
202
|
"criteria": "候选人需要继续在聊天页过滤有 AI Agent 经验的人选",
|
|
203
203
|
"start_from": "unread",
|
|
204
|
+
"greeting_text": "您好,方便发下简历吗?",
|
|
204
205
|
"target_count": 20,
|
|
205
206
|
"profile": "default",
|
|
206
207
|
"dry_run": false,
|
|
@@ -215,9 +216,11 @@ node src/cli.js chat run --job "算法工程师" --start-from unread --criteria
|
|
|
215
216
|
说明:
|
|
216
217
|
|
|
217
218
|
- `criteria` / `start_from` / `target_count` 为必填
|
|
219
|
+
- `greeting_text` 可选(兼容 `greetingText`)
|
|
218
220
|
- `profile` 可选,默认 `default`
|
|
219
221
|
- `job` 与 `port` 继承 recommend run 已选岗位和调试端口
|
|
220
222
|
- `baseUrl` / `apiKey` / `model` 不再单独传入,固定复用 recommend 的 `screening-config.json`
|
|
223
|
+
- `greeting_text` 默认优先级:本次显式值 > profile 历史值 > 内置默认招呼语(`Hi同学,能麻烦发下简历吗?`)
|
|
221
224
|
- 若缺少 `follow_up.chat` 必填项,pipeline 会返回 `NEED_INPUT`
|
|
222
225
|
- recommend 成功后,父 run 继续存活并进入 `chat_followup`;chat 结束后父 run 才会进入最终终态
|
|
223
226
|
- `boss-chat` 子任务状态统一写入 `~/.boss-recommend-mcp/boss-chat`(或 `BOSS_CHAT_HOME` 指定目录),不再依赖工作区 `cwd`
|
|
@@ -229,7 +232,7 @@ node src/cli.js chat run --job "算法工程师" --start-from unread --criteria
|
|
|
229
232
|
- CLI:
|
|
230
233
|
- `boss-recommend-mcp chat health-check`
|
|
231
234
|
- `boss-recommend-mcp chat prepare-run`
|
|
232
|
-
- `boss-recommend-mcp chat run --job "算法工程师" --start-from unread --targetCount 20 --criteria "有 AI Agent 经验"`(后台启动,不自动轮询)
|
|
235
|
+
- `boss-recommend-mcp chat run --job "算法工程师" --start-from unread --targetCount 20 --criteria "有 AI Agent 经验" [--greeting-text "您好,方便发下简历吗?"]`(后台启动,不自动轮询)
|
|
233
236
|
- `boss-recommend-mcp chat start-run|get-run|pause-run|resume-run|cancel-run`
|
|
234
237
|
- MCP:
|
|
235
238
|
- `boss_chat_health_check`
|
|
@@ -247,6 +250,7 @@ chat-only 交互建议:
|
|
|
247
250
|
|
|
248
251
|
- 先调用一次 `prepare_boss_chat_run`(可不带参数),服务会先导航到 `https://www.zhipin.com/web/chat/index` 并返回 `NEED_INPUT`,其中包含岗位 `job_options` 与待补字段。
|
|
249
252
|
- 然后基于 `job_options` 让用户选择 `job`,并补齐 `start_from`、`target_count`、`criteria` 后调用 `start_boss_chat_run` 启动任务。
|
|
253
|
+
- `greeting_text` 可选;未传时会自动沿用 profile 上次输入,若无历史值则使用默认招呼语(`Hi同学,能麻烦发下简历吗?`)。
|
|
250
254
|
- `target_count` 支持正整数、`all`、`-1`;若用户给出 `全部候选人` / `所有候选人`,会自动按不限(扫到底)处理。
|
|
251
255
|
|
|
252
256
|
Trae-CN / 长对话防循环建议:
|
package/package.json
CHANGED
|
@@ -31,12 +31,19 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
31
31
|
可选:
|
|
32
32
|
|
|
33
33
|
- `profile`(默认 `default`)
|
|
34
|
+
- `greeting_text`(兼容 `greetingText`,可选自定义首条打招呼消息)
|
|
34
35
|
- `port`
|
|
35
36
|
- `dry_run`
|
|
36
37
|
- `no_state`
|
|
37
38
|
- `safe_pacing`
|
|
38
39
|
- `batch_rest_enabled`
|
|
39
40
|
|
|
41
|
+
`greeting_text` 默认规则:
|
|
42
|
+
|
|
43
|
+
- 本次显式传入 `greeting_text`:使用本次值
|
|
44
|
+
- 本次未传,但当前 `profile` 有历史输入:使用历史值
|
|
45
|
+
- 两者都没有:使用内置默认招呼语(`Hi同学,能麻烦发下简历吗?`)
|
|
46
|
+
|
|
40
47
|
`target_count` 填写规则(关键):
|
|
41
48
|
|
|
42
49
|
- 正整数:如 `20`
|
|
@@ -55,6 +62,7 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
55
62
|
- 当用户说“全部候选人/所有候选人”时,必须按“扫到底(unlimited)”处理,不要再追问正整数。
|
|
56
63
|
- 参数名必须写 `target_count`(不要写“目标数量”等中文键名)。
|
|
57
64
|
- 当用户选择“扫到底/全部候选人/所有候选人”时,调用参数优先写:`"target_count": "all"`;`-1` 只作为兼容输入和内部 CLI 表示。
|
|
65
|
+
- `greeting_text` 是可选项,不能因为缺少它阻塞启动或追加必填追问。
|
|
58
66
|
- 若工具或提问选项里出现“扫到底(必须传 `target_count=\"all\"`)”之类字样,下一次工具调用时必须直接照抄这个字面量,不要只保留“扫到底”语义。
|
|
59
67
|
- 禁止 agent 自行补全 `job/start_from/criteria` 并直接执行,必须由用户明确给出或确认。
|
|
60
68
|
- chat-only 启动流程必须先进入聊天页并拉取岗位列表,再让用户从列表中选择 `job`。
|
|
@@ -72,8 +72,10 @@ description: "Use when users want Boss recommend-page filtering/screening via bo
|
|
|
72
72
|
- `start_from`: `unread|all`
|
|
73
73
|
- `target_count`
|
|
74
74
|
- `follow_up.chat` 可选:
|
|
75
|
+
- `greeting_text`(兼容 `greetingText`,自定义首条打招呼消息)
|
|
75
76
|
- `profile`(默认 `default`)
|
|
76
77
|
- `dry_run/no_state/safe_pacing/batch_rest_enabled`
|
|
78
|
+
- `greeting_text` 未传时,boss-chat 会自动按默认优先级回退:本次显式值 > profile 历史值 > 内置默认招呼语
|
|
77
79
|
- `job` / `port` 继承 recommend run 上下文;不要单独向用户再要一份
|
|
78
80
|
- LLM 配置固定复用 recommend 的 `screening-config.json`;不要单独向用户再要 `baseUrl/apiKey/model`
|
|
79
81
|
- 缺少 `follow_up.chat` 必填项时,按 `pending_questions` 补缺口;不要额外发起一轮独立的 chat 确认流程
|
package/src/boss-chat.js
CHANGED
|
@@ -573,20 +573,22 @@ function resolveBossChatScreenConfig(workspaceRoot) {
|
|
|
573
573
|
};
|
|
574
574
|
}
|
|
575
575
|
|
|
576
|
-
function normalizeBossChatStartInput(input = {}) {
|
|
577
|
-
const profile = normalizeText(input.profile) || "default";
|
|
578
|
-
const job = normalizeText(input.job);
|
|
579
|
-
const startFromRaw = normalizeText(input.startFrom || input.start_from).toLowerCase();
|
|
580
|
-
const startFrom = startFromRaw === "all" ? "all" : startFromRaw === "unread" ? "unread" : "";
|
|
581
|
-
const criteria = normalizeText(input.criteria);
|
|
582
|
-
const
|
|
583
|
-
const
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
576
|
+
function normalizeBossChatStartInput(input = {}) {
|
|
577
|
+
const profile = normalizeText(input.profile) || "default";
|
|
578
|
+
const job = normalizeText(input.job);
|
|
579
|
+
const startFromRaw = normalizeText(input.startFrom || input.start_from).toLowerCase();
|
|
580
|
+
const startFrom = startFromRaw === "all" ? "all" : startFromRaw === "unread" ? "unread" : "";
|
|
581
|
+
const criteria = normalizeText(input.criteria);
|
|
582
|
+
const greetingText = normalizeText(input.greeting_text || input.greetingText || input.greeting);
|
|
583
|
+
const parsedTarget = normalizeTargetCountInput(getBossChatTargetCountValue(input));
|
|
584
|
+
const port = parsePositiveInteger(input.port);
|
|
585
|
+
return {
|
|
586
|
+
profile,
|
|
587
|
+
job,
|
|
588
|
+
startFrom,
|
|
589
|
+
criteria,
|
|
590
|
+
greetingText,
|
|
591
|
+
targetCount: parsedTarget.targetCount,
|
|
590
592
|
targetCountArg: parsedTarget.cliArg,
|
|
591
593
|
targetCountProvided: parsedTarget.provided,
|
|
592
594
|
targetCountPublicValue: parsedTarget.publicValue,
|
|
@@ -645,10 +647,11 @@ function buildNextCallExample(input = {}, missingFields = []) {
|
|
|
645
647
|
const sample = {};
|
|
646
648
|
if (normalized.job) sample.job = normalized.job;
|
|
647
649
|
if (normalized.startFrom) sample.start_from = normalized.startFrom;
|
|
648
|
-
if (normalized.criteria) sample.criteria = normalized.criteria;
|
|
649
|
-
if (normalized.
|
|
650
|
-
|
|
651
|
-
|
|
650
|
+
if (normalized.criteria) sample.criteria = normalized.criteria;
|
|
651
|
+
if (normalized.greetingText) sample.greeting_text = normalized.greetingText;
|
|
652
|
+
if (normalized.targetCountProvided) {
|
|
653
|
+
sample.target_count = normalized.targetCountPublicValue || (normalized.targetCountArg === "-1" ? "all" : normalized.targetCount);
|
|
654
|
+
} else if (missingFields.includes("target_count")) {
|
|
652
655
|
sample.target_count = "all";
|
|
653
656
|
}
|
|
654
657
|
return Object.keys(sample).length > 0 ? sample : null;
|
|
@@ -678,9 +681,10 @@ function buildBossChatCliArgs(command, input, resolvedConfig, runtimeLayout = nu
|
|
|
678
681
|
const normalized = normalizeBossChatStartInput(input);
|
|
679
682
|
args.push("--profile", normalized.profile);
|
|
680
683
|
if (normalized.job) args.push("--job", normalized.job);
|
|
681
|
-
if (normalized.startFrom) args.push("--start-from", normalized.startFrom);
|
|
682
|
-
if (normalized.criteria) args.push("--criteria", normalized.criteria);
|
|
683
|
-
if (normalized.
|
|
684
|
+
if (normalized.startFrom) args.push("--start-from", normalized.startFrom);
|
|
685
|
+
if (normalized.criteria) args.push("--criteria", normalized.criteria);
|
|
686
|
+
if (normalized.greetingText) args.push("--greeting", normalized.greetingText);
|
|
687
|
+
if (normalized.targetCountArg) args.push("--targetCount", normalized.targetCountArg);
|
|
684
688
|
args.push("--port", String(normalized.port || resolvedConfig.debugPort || 9222));
|
|
685
689
|
args.push("--baseurl", resolvedConfig.baseUrl);
|
|
686
690
|
args.push("--apikey", resolvedConfig.apiKey);
|
|
@@ -702,12 +706,13 @@ function buildBossChatCliArgs(command, input, resolvedConfig, runtimeLayout = nu
|
|
|
702
706
|
args.push("--profile", normalized.profile);
|
|
703
707
|
if (normalized.dryRun) args.push("--dry-run");
|
|
704
708
|
if (normalized.noState) args.push("--no-state");
|
|
705
|
-
args.push("--job", normalized.job);
|
|
706
|
-
args.push("--start-from", normalized.startFrom);
|
|
707
|
-
args.push("--criteria", normalized.criteria);
|
|
708
|
-
if (normalized.
|
|
709
|
-
|
|
710
|
-
|
|
709
|
+
args.push("--job", normalized.job);
|
|
710
|
+
args.push("--start-from", normalized.startFrom);
|
|
711
|
+
args.push("--criteria", normalized.criteria);
|
|
712
|
+
if (normalized.greetingText) args.push("--greeting", normalized.greetingText);
|
|
713
|
+
if (normalized.targetCountArg) {
|
|
714
|
+
args.push("--targetCount", normalized.targetCountArg);
|
|
715
|
+
}
|
|
711
716
|
args.push("--baseurl", resolvedConfig.baseUrl);
|
|
712
717
|
args.push("--apikey", resolvedConfig.apiKey);
|
|
713
718
|
args.push("--model", resolvedConfig.model);
|
package/src/cli.js
CHANGED
|
@@ -1377,7 +1377,7 @@ function printHelp() {
|
|
|
1377
1377
|
console.log("");
|
|
1378
1378
|
console.log("Run command:");
|
|
1379
1379
|
console.log(" boss-recommend-mcp run --instruction \"推荐页上筛选211男生,近14天没有,有大模型平台经验\" [--confirmation-json '{...}'] [--overrides-json '{...}'] [--follow-up-json '{...}']");
|
|
1380
|
-
console.log(" boss-recommend-mcp chat run --job \"算法工程师\" --start-from unread --criteria \"有 AI Agent 经验\" --targetCount 20 # 后台启动,不自动轮询");
|
|
1380
|
+
console.log(" boss-recommend-mcp chat run --job \"算法工程师\" --start-from unread --criteria \"有 AI Agent 经验\" --targetCount 20 [--greeting-text \"你好,方便发下简历吗?\"] # 后台启动,不自动轮询");
|
|
1381
1381
|
console.log(" boss-recommend-mcp config set --base-url <url> --api-key <key> --model <model> [--thinking-level off|low|medium|high|current] [--openai-organization <id>] [--openai-project <id>]");
|
|
1382
1382
|
console.log(" boss-recommend-mcp install --agent trae-cn");
|
|
1383
1383
|
console.log(" boss-recommend-mcp doctor --agent trae-cn --page-scope featured");
|
|
@@ -1481,11 +1481,18 @@ async function runPipelineOnce(options) {
|
|
|
1481
1481
|
}
|
|
1482
1482
|
|
|
1483
1483
|
function buildBossChatCliInput(options = {}) {
|
|
1484
|
+
const greetingTextRaw =
|
|
1485
|
+
options["greeting-text"]
|
|
1486
|
+
?? options.greeting_text
|
|
1487
|
+
?? options.greetingText
|
|
1488
|
+
?? options.greeting;
|
|
1489
|
+
const greetingText = typeof greetingTextRaw === "string" ? greetingTextRaw.trim() : undefined;
|
|
1484
1490
|
return {
|
|
1485
1491
|
profile: typeof options.profile === "string" ? options.profile.trim() : undefined,
|
|
1486
1492
|
job: typeof options.job === "string" ? options.job.trim() : undefined,
|
|
1487
1493
|
start_from: String(options["start-from"] || options.start_from || "").trim().toLowerCase() || undefined,
|
|
1488
1494
|
criteria: typeof options.criteria === "string" ? options.criteria.trim() : undefined,
|
|
1495
|
+
greeting_text: greetingText || undefined,
|
|
1489
1496
|
target_count: parseBossChatTargetCountOption(options.targetCount || options["target-count"] || options.target_count),
|
|
1490
1497
|
port: parsePositivePort(options.port),
|
|
1491
1498
|
dry_run: options["dry-run"] === true || options.dryRun === true,
|
package/src/index.js
CHANGED
|
@@ -437,6 +437,14 @@ function createRunInputSchema() {
|
|
|
437
437
|
type: "string",
|
|
438
438
|
enum: ["unread", "all"]
|
|
439
439
|
},
|
|
440
|
+
greeting_text: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: "可选,首条打招呼消息;未传时按 profile 历史值/默认值自动回退"
|
|
443
|
+
},
|
|
444
|
+
greetingText: {
|
|
445
|
+
type: "string",
|
|
446
|
+
description: "兼容字段;优先使用 greeting_text。可选首条打招呼消息"
|
|
447
|
+
},
|
|
440
448
|
target_count: createTargetCountInputSchema("boss-chat follow-up 本次处理人数上限;支持正整数、all 或 -1(扫到底)"),
|
|
441
449
|
dry_run: { type: "boolean" },
|
|
442
450
|
no_state: { type: "boolean" },
|
|
@@ -475,6 +483,14 @@ function createBossChatStartInputSchema({ requireFullInput = false } = {}) {
|
|
|
475
483
|
type: "string",
|
|
476
484
|
description: "boss-chat 的筛选 criteria"
|
|
477
485
|
},
|
|
486
|
+
greeting_text: {
|
|
487
|
+
type: "string",
|
|
488
|
+
description: "可选,首条打招呼消息;未传时按 profile 历史值/默认值自动回退"
|
|
489
|
+
},
|
|
490
|
+
greetingText: {
|
|
491
|
+
type: "string",
|
|
492
|
+
description: "兼容字段;优先使用 greeting_text。可选首条打招呼消息"
|
|
493
|
+
},
|
|
478
494
|
target_count: createTargetCountInputSchema("本次处理人数上限;支持正整数、all 或 -1(扫到底),也兼容 { value: \"all\" } 等包装对象"),
|
|
479
495
|
targetCount: createTargetCountInputSchema("兼容字段;优先使用 target_count。本次处理人数上限,支持正整数、all 或 -1(扫到底)"),
|
|
480
496
|
port: {
|
|
@@ -773,6 +789,18 @@ function validateBossChatStartArgs(args) {
|
|
|
773
789
|
return "criteria must be a non-empty string when provided";
|
|
774
790
|
}
|
|
775
791
|
}
|
|
792
|
+
if (
|
|
793
|
+
Object.prototype.hasOwnProperty.call(args, "greeting_text")
|
|
794
|
+
&& typeof args.greeting_text !== "string"
|
|
795
|
+
) {
|
|
796
|
+
return "greeting_text must be a string when provided";
|
|
797
|
+
}
|
|
798
|
+
if (
|
|
799
|
+
Object.prototype.hasOwnProperty.call(args, "greetingText")
|
|
800
|
+
&& typeof args.greetingText !== "string"
|
|
801
|
+
) {
|
|
802
|
+
return "greetingText must be a string when provided";
|
|
803
|
+
}
|
|
776
804
|
if (
|
|
777
805
|
Object.prototype.hasOwnProperty.call(args, "target_count")
|
|
778
806
|
|| Object.prototype.hasOwnProperty.call(args, "targetCount")
|
package/src/pipeline.js
CHANGED
|
@@ -30,6 +30,15 @@ const SEARCH_NO_IFRAME_RETRY_DELAY_MS = 1200;
|
|
|
30
30
|
const MAX_SEARCH_FILTER_AUTO_RETRY_ATTEMPTS = 2;
|
|
31
31
|
const SEARCH_FILTER_AUTO_RETRY_DELAY_MS = 1200;
|
|
32
32
|
const BOSS_CHAT_FOLLOW_UP_POLL_MS = 1500;
|
|
33
|
+
const FOLLOW_UP_TARGET_COUNT_PASSED_TOKEN = "passed_count";
|
|
34
|
+
const FOLLOW_UP_TARGET_COUNT_PASSED_LABEL = "通过筛选数";
|
|
35
|
+
const FOLLOW_UP_TARGET_COUNT_PASSED_ALIASES = new Set([
|
|
36
|
+
FOLLOW_UP_TARGET_COUNT_PASSED_TOKEN,
|
|
37
|
+
"passed",
|
|
38
|
+
"通过筛选数",
|
|
39
|
+
"筛选通过数",
|
|
40
|
+
"通过数"
|
|
41
|
+
]);
|
|
33
42
|
const SEARCH_FILTER_RETRY_TOKENS = [
|
|
34
43
|
"FILTER_CONFIRM_FAILED",
|
|
35
44
|
"FILTER_DOM_CLASS_VERIFY_FAILED",
|
|
@@ -72,6 +81,75 @@ function normalizePipelineTargetCountValue(value) {
|
|
|
72
81
|
return normalizeTargetCountInput(value).publicValue;
|
|
73
82
|
}
|
|
74
83
|
|
|
84
|
+
function isFollowUpPassedTargetCountToken(value) {
|
|
85
|
+
const normalized = normalizeText(value).toLowerCase().replace(/\s+/g, "");
|
|
86
|
+
if (!normalized) return false;
|
|
87
|
+
return FOLLOW_UP_TARGET_COUNT_PASSED_ALIASES.has(normalized);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function normalizeFollowUpTargetCountInput(value) {
|
|
91
|
+
const normalized = normalizeTargetCountInput(value);
|
|
92
|
+
if (normalized.provided) {
|
|
93
|
+
return {
|
|
94
|
+
...normalized,
|
|
95
|
+
launchValue: normalized.publicValue,
|
|
96
|
+
passedCountMode: false
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (isFollowUpPassedTargetCountToken(value)) {
|
|
100
|
+
return {
|
|
101
|
+
provided: true,
|
|
102
|
+
targetCount: null,
|
|
103
|
+
cliArg: null,
|
|
104
|
+
publicValue: FOLLOW_UP_TARGET_COUNT_PASSED_LABEL,
|
|
105
|
+
rawValue: value,
|
|
106
|
+
parseError: null,
|
|
107
|
+
launchValue: FOLLOW_UP_TARGET_COUNT_PASSED_TOKEN,
|
|
108
|
+
passedCountMode: true
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
...normalized,
|
|
113
|
+
launchValue: null,
|
|
114
|
+
passedCountMode: false
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function resolveFollowUpChatTargetCountForLaunch(targetCount, recommendSummary = null) {
|
|
119
|
+
if (isFollowUpPassedTargetCountToken(targetCount)) {
|
|
120
|
+
const passedCount = parsePositiveIntegerValue(recommendSummary?.passed_count);
|
|
121
|
+
if (passedCount) {
|
|
122
|
+
return {
|
|
123
|
+
ok: true,
|
|
124
|
+
target_count: passedCount,
|
|
125
|
+
resolved_from: FOLLOW_UP_TARGET_COUNT_PASSED_TOKEN,
|
|
126
|
+
passed_count: recommendSummary?.passed_count ?? null
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
code: "FOLLOW_UP_TARGET_COUNT_PASSED_UNAVAILABLE",
|
|
132
|
+
message: "boss-chat follow-up 选择了“通过筛选数”,但本次通过人数为空或 0。请改为正整数,或填写 all(扫到底)。",
|
|
133
|
+
passed_count: recommendSummary?.passed_count ?? null
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const normalized = normalizeTargetCountInput(targetCount);
|
|
137
|
+
if (normalized.provided) {
|
|
138
|
+
return {
|
|
139
|
+
ok: true,
|
|
140
|
+
target_count: normalized.publicValue,
|
|
141
|
+
resolved_from: "explicit",
|
|
142
|
+
passed_count: recommendSummary?.passed_count ?? null
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
ok: false,
|
|
147
|
+
code: "FOLLOW_UP_TARGET_COUNT_INVALID",
|
|
148
|
+
message: normalized.parseError || "boss-chat follow-up target_count 无效。",
|
|
149
|
+
passed_count: recommendSummary?.passed_count ?? null
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
75
153
|
function sleep(ms) {
|
|
76
154
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
77
155
|
}
|
|
@@ -394,13 +472,13 @@ function normalizeFollowUpChatInput(followUp = null, defaults = null) {
|
|
|
394
472
|
const defaultCriteria = normalizeText(defaults?.criteria || "");
|
|
395
473
|
const defaultStartFromRaw = normalizeText(defaults?.start_from || "").toLowerCase();
|
|
396
474
|
const defaultStartFrom = defaultStartFromRaw === "all" ? "all" : "unread";
|
|
397
|
-
const defaultTargetCount = normalizePipelineTargetCountValue(defaults?.target_count);
|
|
398
475
|
|
|
399
476
|
const explicitCriteria = normalizeText(raw.criteria);
|
|
400
477
|
const explicitStartFromRaw = normalizeText(raw.start_from).toLowerCase();
|
|
401
478
|
const explicitStartFrom = explicitStartFromRaw === "all" ? "all" : explicitStartFromRaw === "unread" ? "unread" : "";
|
|
402
|
-
const
|
|
403
|
-
const
|
|
479
|
+
const explicitGreetingText = normalizeText(raw.greeting_text || raw.greetingText);
|
|
480
|
+
const explicitTarget = normalizeFollowUpTargetCountInput(raw.target_count);
|
|
481
|
+
const explicitTargetCount = explicitTarget.launchValue;
|
|
404
482
|
|
|
405
483
|
const hasExplicitCriteria = Boolean(explicitCriteria);
|
|
406
484
|
const hasExplicitStartFrom = Boolean(explicitStartFrom);
|
|
@@ -408,14 +486,16 @@ function normalizeFollowUpChatInput(followUp = null, defaults = null) {
|
|
|
408
486
|
|
|
409
487
|
const criteria = explicitCriteria || defaultCriteria;
|
|
410
488
|
const startFrom = explicitStartFrom || defaultStartFrom;
|
|
411
|
-
const targetCount = explicitTargetCount ||
|
|
489
|
+
const targetCount = explicitTargetCount || FOLLOW_UP_TARGET_COUNT_PASSED_TOKEN;
|
|
490
|
+
const targetCountSummaryValue = explicitTarget.publicValue || FOLLOW_UP_TARGET_COUNT_PASSED_LABEL;
|
|
412
491
|
|
|
413
492
|
const profile = normalizeText(raw.profile) || "default";
|
|
414
493
|
const summary = {
|
|
415
494
|
profile,
|
|
416
495
|
criteria: criteria || null,
|
|
417
496
|
start_from: startFrom || null,
|
|
418
|
-
|
|
497
|
+
greeting_text: explicitGreetingText || null,
|
|
498
|
+
target_count: targetCountSummaryValue,
|
|
419
499
|
dry_run: raw.dry_run === true,
|
|
420
500
|
no_state: raw.no_state === true,
|
|
421
501
|
safe_pacing: typeof raw.safe_pacing === "boolean" ? raw.safe_pacing : null,
|
|
@@ -446,21 +526,39 @@ function normalizeFollowUpChatInput(followUp = null, defaults = null) {
|
|
|
446
526
|
});
|
|
447
527
|
}
|
|
448
528
|
if (!hasExplicitTargetCount) {
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
chat: {
|
|
454
|
-
target_count: "all"
|
|
455
|
-
}
|
|
529
|
+
const recommendedTargetCountPatch = {
|
|
530
|
+
follow_up: {
|
|
531
|
+
chat: {
|
|
532
|
+
target_count: FOLLOW_UP_TARGET_COUNT_PASSED_LABEL
|
|
456
533
|
}
|
|
457
534
|
}
|
|
535
|
+
};
|
|
536
|
+
const targetCountHints = buildTargetCountCompatibilityHints({
|
|
537
|
+
argumentName: "follow_up.chat.target_count",
|
|
538
|
+
recommendedArgumentPatch: recommendedTargetCountPatch
|
|
458
539
|
});
|
|
459
540
|
missing_fields.push("follow_up.chat.target_count");
|
|
460
541
|
pending_questions.push({
|
|
461
542
|
...targetCountHints,
|
|
543
|
+
answer_format: `follow_up.chat.target_count = "${FOLLOW_UP_TARGET_COUNT_PASSED_LABEL}" | 正整数 | "all"`,
|
|
544
|
+
recommended_value: FOLLOW_UP_TARGET_COUNT_PASSED_LABEL,
|
|
545
|
+
recommended_argument_patch: recommendedTargetCountPatch,
|
|
546
|
+
canonical_passed_count_value: FOLLOW_UP_TARGET_COUNT_PASSED_TOKEN,
|
|
547
|
+
accepted_examples: [
|
|
548
|
+
FOLLOW_UP_TARGET_COUNT_PASSED_LABEL,
|
|
549
|
+
...targetCountHints.accepted_examples
|
|
550
|
+
],
|
|
551
|
+
options: [
|
|
552
|
+
{
|
|
553
|
+
label: `通过筛选数(推荐)`,
|
|
554
|
+
value: FOLLOW_UP_TARGET_COUNT_PASSED_LABEL,
|
|
555
|
+
canonical_value: FOLLOW_UP_TARGET_COUNT_PASSED_TOKEN,
|
|
556
|
+
argument_patch: recommendedTargetCountPatch
|
|
557
|
+
},
|
|
558
|
+
...(Array.isArray(targetCountHints.options) ? targetCountHints.options : [])
|
|
559
|
+
],
|
|
462
560
|
field: "follow_up.chat.target_count",
|
|
463
|
-
question: "请填写 boss-chat follow-up
|
|
561
|
+
question: "请填写 boss-chat follow-up 目标人数。默认建议填写“通过筛选数”;若要扫到底,请在 follow_up.chat.target_count 里字面填写 \"all\"。",
|
|
464
562
|
value: summary.target_count,
|
|
465
563
|
...(explicitTarget.rawValue !== undefined ? { received_target_count: explicitTarget.rawValue } : {}),
|
|
466
564
|
...(explicitTarget.parseError ? { target_count_parse_error: explicitTarget.parseError } : {})
|
|
@@ -476,6 +574,7 @@ function normalizeFollowUpChatInput(followUp = null, defaults = null) {
|
|
|
476
574
|
profile,
|
|
477
575
|
criteria: criteria || null,
|
|
478
576
|
start_from: startFrom || null,
|
|
577
|
+
greeting_text: explicitGreetingText || undefined,
|
|
479
578
|
target_count: targetCount,
|
|
480
579
|
dry_run: raw.dry_run === true,
|
|
481
580
|
no_state: raw.no_state === true,
|
|
@@ -523,6 +622,7 @@ function buildResolvedFollowUpChatInput(followUpChat, { selectedJob, debugPort }
|
|
|
523
622
|
job: selectedJob?.title || selectedJob?.label || selectedJob?.value || null,
|
|
524
623
|
start_from: followUpChat?.input?.start_from || null,
|
|
525
624
|
criteria: followUpChat?.input?.criteria || null,
|
|
625
|
+
greeting_text: followUpChat?.input?.greeting_text || null,
|
|
526
626
|
target_count: followUpChat?.input?.target_count || null,
|
|
527
627
|
port: Number.isFinite(debugPort) ? debugPort : null,
|
|
528
628
|
dry_run: followUpChat?.input?.dry_run === true,
|
|
@@ -543,6 +643,7 @@ function buildBossChatFollowUpStatus({ payload, runId, fallbackInput = null, sta
|
|
|
543
643
|
job: normalizeText(fallbackInput?.job) || null,
|
|
544
644
|
start_from: normalizeText(fallbackInput?.start_from) || null,
|
|
545
645
|
criteria: normalizeText(fallbackInput?.criteria) || null,
|
|
646
|
+
greeting_text: normalizeText(fallbackInput?.greeting_text) || null,
|
|
546
647
|
target_count: normalizePipelineTargetCountValue(fallbackInput?.target_count),
|
|
547
648
|
port: parsePositiveIntegerValue(fallbackInput?.port),
|
|
548
649
|
progress: {
|
|
@@ -857,10 +958,32 @@ async function runBossChatFollowUpPhase({
|
|
|
857
958
|
cancelChatRun
|
|
858
959
|
}) {
|
|
859
960
|
const recommendSummary = recommendResult?.result || null;
|
|
860
|
-
const
|
|
961
|
+
const requestedChatInput = buildResolvedFollowUpChatInput(followUpChat, {
|
|
861
962
|
selectedJob,
|
|
862
963
|
debugPort
|
|
863
964
|
});
|
|
965
|
+
const targetCountResolution = resolveFollowUpChatTargetCountForLaunch(
|
|
966
|
+
requestedChatInput.target_count,
|
|
967
|
+
recommendSummary
|
|
968
|
+
);
|
|
969
|
+
if (!targetCountResolution.ok) {
|
|
970
|
+
return buildFollowUpFailedResponse(
|
|
971
|
+
targetCountResolution.code || "BOSS_CHAT_FOLLOW_UP_TARGET_COUNT_INVALID",
|
|
972
|
+
targetCountResolution.message || "boss-chat follow-up target_count 无法解析。",
|
|
973
|
+
recommendResult,
|
|
974
|
+
{
|
|
975
|
+
enabled: true,
|
|
976
|
+
input: requestedChatInput,
|
|
977
|
+
target_count_resolution: targetCountResolution
|
|
978
|
+
}
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
const resolvedChatInput = {
|
|
982
|
+
...requestedChatInput,
|
|
983
|
+
target_count: targetCountResolution.target_count,
|
|
984
|
+
target_count_source: targetCountResolution.resolved_from,
|
|
985
|
+
target_count_requested: requestedChatInput.target_count
|
|
986
|
+
};
|
|
864
987
|
let chatRunId = normalizeText(resume?.chat_run_id || "");
|
|
865
988
|
const resumeFromChatPhase = resume?.resume === true && normalizeText(resume?.follow_up_phase) === "chat_followup";
|
|
866
989
|
let pauseRequested = false;
|
|
@@ -877,6 +1000,7 @@ async function runBossChatFollowUpPhase({
|
|
|
877
1000
|
profile: resolvedChatInput.profile,
|
|
878
1001
|
job: resolvedChatInput.job,
|
|
879
1002
|
start_from: resolvedChatInput.start_from,
|
|
1003
|
+
greeting_text: resolvedChatInput.greeting_text,
|
|
880
1004
|
target_count: resolvedChatInput.target_count
|
|
881
1005
|
});
|
|
882
1006
|
|
|
@@ -888,6 +1012,7 @@ async function runBossChatFollowUpPhase({
|
|
|
888
1012
|
job: resolvedChatInput.job,
|
|
889
1013
|
start_from: resolvedChatInput.start_from,
|
|
890
1014
|
criteria: resolvedChatInput.criteria,
|
|
1015
|
+
greeting_text: resolvedChatInput.greeting_text,
|
|
891
1016
|
target_count: resolvedChatInput.target_count,
|
|
892
1017
|
port: resolvedChatInput.port,
|
|
893
1018
|
dry_run: resolvedChatInput.dry_run,
|