@reconcrap/boss-recommend-mcp 1.3.20 → 1.3.22
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 +1 -0
- package/package.json +1 -1
- package/skills/boss-chat/README.md +1 -0
- package/skills/boss-chat/SKILL.md +1 -0
- package/src/boss-chat.js +67 -12
- package/src/cli.js +50 -1
- package/src/index.js +18 -3
- package/src/pipeline.js +13 -2
- package/src/test-boss-chat.js +13 -1
- package/src/test-pipeline.js +6 -1
package/README.md
CHANGED
|
@@ -245,6 +245,7 @@ Trae-CN / 长对话防循环建议:
|
|
|
245
245
|
|
|
246
246
|
- 固定流程:`boss_chat_health_check` -> `prepare_boss_chat_run(空参可)` -> 一次性补齐 `job/start_from/target_count/criteria` -> `start_boss_chat_run`。
|
|
247
247
|
- `start_boss_chat_run` 的工具 schema 已把 `job/start_from/target_count/criteria` 标记为必填;不要用它获取岗位列表。
|
|
248
|
+
- 若 `pending_questions` / UI 选项里出现“扫到底(必须传 `target_count="all"`)”,下一次工具调用请直接照抄 `"target_count": "all"`,不要只保留“扫到底”这层自然语言语义。
|
|
248
249
|
- `start_boss_chat_run` 返回 `ACCEPTED` 后直接结束当前回合,不要自动轮询。
|
|
249
250
|
- 缺参或校验失败时,一次性列出全部缺失/错误项,避免重复同一句提示触发宿主“陷入循环”保护。
|
|
250
251
|
- 仅当用户明确要求“查进度”时再调用 `get_boss_chat_run`。
|
package/package.json
CHANGED
|
@@ -34,5 +34,6 @@ target_count mapping:
|
|
|
34
34
|
- `全部候选人` / `所有候选人` must also be treated as unlimited.
|
|
35
35
|
- Always write the argument key as `target_count`.
|
|
36
36
|
- For unlimited mode, prefer `"target_count": "all"` in the tool call; `-1` is accepted for compatibility and used internally by the CLI.
|
|
37
|
+
- If the tool/UI shows `扫到底(必须传 target_count="all")`, copy that literal into the next tool call instead of paraphrasing it.
|
|
37
38
|
- If start_boss_chat_run returns NEED_INPUT for `target_count`, the previous tool call omitted the argument. Retry once using `next_call_example` and include `"target_count": "all"` or a positive integer.
|
|
38
39
|
```
|
|
@@ -55,6 +55,7 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
55
55
|
- 当用户说“全部候选人/所有候选人”时,必须按“扫到底(unlimited)”处理,不要再追问正整数。
|
|
56
56
|
- 参数名必须写 `target_count`(不要写“目标数量”等中文键名)。
|
|
57
57
|
- 当用户选择“扫到底/全部候选人/所有候选人”时,调用参数优先写:`"target_count": "all"`;`-1` 只作为兼容输入和内部 CLI 表示。
|
|
58
|
+
- 若工具或提问选项里出现“扫到底(必须传 `target_count=\"all\"`)”之类字样,下一次工具调用时必须直接照抄这个字面量,不要只保留“扫到底”语义。
|
|
58
59
|
- 禁止 agent 自行补全 `job/start_from/criteria` 并直接执行,必须由用户明确给出或确认。
|
|
59
60
|
- chat-only 启动流程必须先进入聊天页并拉取岗位列表,再让用户从列表中选择 `job`。
|
|
60
61
|
- 必须先用空参调用 `prepare_boss_chat_run` 获取 `job_options`;不要用 `start_boss_chat_run` 做预备调用。
|
package/src/boss-chat.js
CHANGED
|
@@ -14,7 +14,8 @@ const PREPARE_BOSS_CHAT_MAX_ATTEMPTS = 3;
|
|
|
14
14
|
const PREPARE_BOSS_CHAT_RETRY_DELAY_MS = 1200;
|
|
15
15
|
const BOSS_CHAT_TERMINAL_STATES = new Set(["completed", "failed", "canceled"]);
|
|
16
16
|
const CHAT_REQUIRED_FIELDS = ["job", "start_from", "target_count", "criteria"];
|
|
17
|
-
export const
|
|
17
|
+
export const TARGET_COUNT_CANONICAL_ALL = "all";
|
|
18
|
+
export const TARGET_COUNT_ACCEPTED_EXAMPLES = [TARGET_COUNT_CANONICAL_ALL, -1, 20, "全部候选人"];
|
|
18
19
|
const TARGET_COUNT_WRAPPER_KEYS = ["target_count", "targetCount", "value", "count", "limit"];
|
|
19
20
|
const LLM_THINKING_LEVEL_FIELDS = [
|
|
20
21
|
"llmThinkingLevel",
|
|
@@ -128,6 +129,55 @@ function cloneForDiagnostics(value) {
|
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
|
|
132
|
+
export function buildTargetCountCompatibilityHints({
|
|
133
|
+
argumentName = "target_count",
|
|
134
|
+
recommendedArgumentPatch = { target_count: TARGET_COUNT_CANONICAL_ALL },
|
|
135
|
+
includeOptions = true
|
|
136
|
+
} = {}) {
|
|
137
|
+
const normalizedArgumentName = normalizeText(argumentName) || "target_count";
|
|
138
|
+
const clonedRecommendedPatch = cloneForDiagnostics(recommendedArgumentPatch)
|
|
139
|
+
|| { target_count: TARGET_COUNT_CANONICAL_ALL };
|
|
140
|
+
const literal = `${normalizedArgumentName}="${TARGET_COUNT_CANONICAL_ALL}"`;
|
|
141
|
+
const base = {
|
|
142
|
+
argument_name: normalizedArgumentName,
|
|
143
|
+
answer_format: `${normalizedArgumentName} = 正整数 | "${TARGET_COUNT_CANONICAL_ALL}"`,
|
|
144
|
+
canonical_unlimited_value: TARGET_COUNT_CANONICAL_ALL,
|
|
145
|
+
recommended_value: TARGET_COUNT_CANONICAL_ALL,
|
|
146
|
+
recommended_argument_patch: clonedRecommendedPatch,
|
|
147
|
+
accepted_examples: TARGET_COUNT_ACCEPTED_EXAMPLES.slice()
|
|
148
|
+
};
|
|
149
|
+
if (!includeOptions) return base;
|
|
150
|
+
return {
|
|
151
|
+
...base,
|
|
152
|
+
options: [
|
|
153
|
+
{
|
|
154
|
+
label: `扫到底(必须传 ${literal},推荐)`,
|
|
155
|
+
value: TARGET_COUNT_CANONICAL_ALL,
|
|
156
|
+
canonical_value: TARGET_COUNT_CANONICAL_ALL,
|
|
157
|
+
argument_patch: cloneForDiagnostics(clonedRecommendedPatch)
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
label: `不限(等价于 ${literal})`,
|
|
161
|
+
value: "unlimited",
|
|
162
|
+
canonical_value: TARGET_COUNT_CANONICAL_ALL,
|
|
163
|
+
argument_patch: cloneForDiagnostics(clonedRecommendedPatch)
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
label: `全部候选人(等价于 ${literal})`,
|
|
167
|
+
value: "全部候选人",
|
|
168
|
+
canonical_value: TARGET_COUNT_CANONICAL_ALL,
|
|
169
|
+
argument_patch: cloneForDiagnostics(clonedRecommendedPatch)
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
label: `所有候选人(等价于 ${literal})`,
|
|
173
|
+
value: "所有候选人",
|
|
174
|
+
canonical_value: TARGET_COUNT_CANONICAL_ALL,
|
|
175
|
+
argument_patch: cloneForDiagnostics(clonedRecommendedPatch)
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
131
181
|
export function normalizeTargetCountInput(value) {
|
|
132
182
|
if (value === undefined || value === null) {
|
|
133
183
|
return {
|
|
@@ -369,16 +419,16 @@ function getMissingBossChatStartFields(input = {}) {
|
|
|
369
419
|
|
|
370
420
|
function buildTargetCountQuestionHint(item = {}) {
|
|
371
421
|
const next = { ...item };
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
422
|
+
const hints = buildTargetCountCompatibilityHints({
|
|
423
|
+
argumentName: "target_count",
|
|
424
|
+
recommendedArgumentPatch: { target_count: TARGET_COUNT_CANONICAL_ALL }
|
|
425
|
+
});
|
|
426
|
+
return {
|
|
427
|
+
...next,
|
|
428
|
+
...hints,
|
|
429
|
+
question: `请输入 target_count:正整数,或直接填写 "${TARGET_COUNT_CANONICAL_ALL}"(扫到底)。`,
|
|
430
|
+
examples: TARGET_COUNT_ACCEPTED_EXAMPLES.slice()
|
|
431
|
+
};
|
|
382
432
|
}
|
|
383
433
|
|
|
384
434
|
function normalizePendingQuestions(pendingQuestions = []) {
|
|
@@ -406,8 +456,13 @@ function buildNextCallExample(input = {}, missingFields = []) {
|
|
|
406
456
|
function buildTargetCountNeedInputDiagnostics(input = {}, missingFields = []) {
|
|
407
457
|
if (!Array.isArray(missingFields) || !missingFields.includes("target_count")) return {};
|
|
408
458
|
const normalized = normalizeBossChatStartInput(input);
|
|
459
|
+
const hints = buildTargetCountCompatibilityHints({
|
|
460
|
+
argumentName: "target_count",
|
|
461
|
+
recommendedArgumentPatch: { target_count: TARGET_COUNT_CANONICAL_ALL },
|
|
462
|
+
includeOptions: false
|
|
463
|
+
});
|
|
409
464
|
return {
|
|
410
|
-
|
|
465
|
+
...hints,
|
|
411
466
|
...(normalized.targetCountRawValue !== undefined ? { received_target_count: normalized.targetCountRawValue } : {}),
|
|
412
467
|
...(normalized.targetCountParseError ? { target_count_parse_error: normalized.targetCountParseError } : {})
|
|
413
468
|
};
|
package/src/cli.js
CHANGED
|
@@ -45,6 +45,10 @@ const recommendMcpBinaryName = "boss-recommend-mcp";
|
|
|
45
45
|
const autoSyncSkipCommands = new Set(["install", "install-skill", "where", "help", "--help", "-h"]);
|
|
46
46
|
const externalMcpTargetsEnv = "BOSS_RECOMMEND_MCP_CONFIG_TARGETS";
|
|
47
47
|
const externalSkillDirsEnv = "BOSS_RECOMMEND_EXTERNAL_SKILL_DIRS";
|
|
48
|
+
const installConfigDefaults = Object.freeze({
|
|
49
|
+
llmThinkingLevel: "low",
|
|
50
|
+
humanRestEnabled: false
|
|
51
|
+
});
|
|
48
52
|
|
|
49
53
|
function getSkillSourceDir(name = skillName) {
|
|
50
54
|
return path.join(packageRoot, "skills", name);
|
|
@@ -655,6 +659,21 @@ function resolveCliConfigTarget(options = {}) {
|
|
|
655
659
|
};
|
|
656
660
|
}
|
|
657
661
|
|
|
662
|
+
function applyMissingInstallConfigDefaults(config = {}) {
|
|
663
|
+
const nextConfig = { ...config };
|
|
664
|
+
const patchedKeys = [];
|
|
665
|
+
for (const [key, defaultValue] of Object.entries(installConfigDefaults)) {
|
|
666
|
+
if (!Object.prototype.hasOwnProperty.call(nextConfig, key)) {
|
|
667
|
+
nextConfig[key] = defaultValue;
|
|
668
|
+
patchedKeys.push(key);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return {
|
|
672
|
+
nextConfig,
|
|
673
|
+
patchedKeys
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
|
|
658
677
|
function ensureUserConfig(options = {}) {
|
|
659
678
|
const { configPath, workspacePreferred } = resolveCliConfigTarget(options);
|
|
660
679
|
const writeTargets = dedupePaths([configPath, workspacePreferred]).filter(Boolean);
|
|
@@ -671,7 +690,27 @@ function ensureUserConfig(options = {}) {
|
|
|
671
690
|
}
|
|
672
691
|
const stat = fs.statSync(targetPath);
|
|
673
692
|
if (stat.isFile()) {
|
|
674
|
-
|
|
693
|
+
try {
|
|
694
|
+
const existingConfig = readJsonObjectFile(targetPath);
|
|
695
|
+
const patched = applyMissingInstallConfigDefaults(existingConfig);
|
|
696
|
+
if (patched.patchedKeys.length > 0) {
|
|
697
|
+
fs.writeFileSync(targetPath, JSON.stringify(patched.nextConfig, null, 2), "utf8");
|
|
698
|
+
}
|
|
699
|
+
return {
|
|
700
|
+
path: targetPath,
|
|
701
|
+
created: false,
|
|
702
|
+
patched: patched.patchedKeys.length > 0,
|
|
703
|
+
patched_keys: patched.patchedKeys
|
|
704
|
+
};
|
|
705
|
+
} catch (error) {
|
|
706
|
+
return {
|
|
707
|
+
path: targetPath,
|
|
708
|
+
created: false,
|
|
709
|
+
patched: false,
|
|
710
|
+
patched_keys: [],
|
|
711
|
+
patch_error: error?.message || "screening-config.json 解析失败,跳过自动补字段。"
|
|
712
|
+
};
|
|
713
|
+
}
|
|
675
714
|
}
|
|
676
715
|
lastError = new Error(`Config target is a directory and cannot be used as file: ${targetPath}`);
|
|
677
716
|
} catch (error) {
|
|
@@ -1286,6 +1325,11 @@ function installAll(options = {}) {
|
|
|
1286
1325
|
? `screening-config.json created: ${configResult.path}`
|
|
1287
1326
|
: `screening-config.json already exists: ${configResult.path}`
|
|
1288
1327
|
);
|
|
1328
|
+
if (Array.isArray(configResult.patched_keys) && configResult.patched_keys.length > 0) {
|
|
1329
|
+
console.log(`screening-config.json patched missing defaults: ${configResult.patched_keys.join(", ")}`);
|
|
1330
|
+
} else if (configResult.patch_error) {
|
|
1331
|
+
console.warn(`screening-config.json skip default patch: ${configResult.patch_error}`);
|
|
1332
|
+
}
|
|
1289
1333
|
console.log(`请在该目录修改 baseUrl/apiKey/model 并替换占位词后再运行:${path.dirname(configResult.path)}`);
|
|
1290
1334
|
console.log(`MCP config templates exported to: ${mcpTemplateResult.outputDir}`);
|
|
1291
1335
|
for (const item of mcpTemplateResult.files) {
|
|
@@ -1482,6 +1526,11 @@ export async function runCli(argv = process.argv) {
|
|
|
1482
1526
|
case "init-config": {
|
|
1483
1527
|
const result = ensureUserConfig(options);
|
|
1484
1528
|
console.log(result.created ? `Config template created at: ${result.path}` : `Config already exists at: ${result.path}`);
|
|
1529
|
+
if (Array.isArray(result.patched_keys) && result.patched_keys.length > 0) {
|
|
1530
|
+
console.log(`Config patched missing defaults: ${result.patched_keys.join(", ")}`);
|
|
1531
|
+
} else if (result.patch_error) {
|
|
1532
|
+
console.warn(`Config skip default patch: ${result.patch_error}`);
|
|
1533
|
+
}
|
|
1485
1534
|
break;
|
|
1486
1535
|
}
|
|
1487
1536
|
case "set-port": {
|
package/src/index.js
CHANGED
|
@@ -164,7 +164,8 @@ function createTargetCountInputSchema(description) {
|
|
|
164
164
|
additionalProperties: true
|
|
165
165
|
}
|
|
166
166
|
],
|
|
167
|
-
description
|
|
167
|
+
description: `${description} 若用户选择扫到底/不限/全部候选人,优先字面传 "all"。`,
|
|
168
|
+
examples: ["all", 20, { value: "all" }]
|
|
168
169
|
};
|
|
169
170
|
}
|
|
170
171
|
|
|
@@ -486,7 +487,21 @@ function createBossChatStartInputSchema({ requireFullInput = false } = {}) {
|
|
|
486
487
|
safe_pacing: { type: "boolean" },
|
|
487
488
|
batch_rest_enabled: { type: "boolean" }
|
|
488
489
|
},
|
|
489
|
-
additionalProperties: false
|
|
490
|
+
additionalProperties: false,
|
|
491
|
+
examples: [
|
|
492
|
+
{
|
|
493
|
+
job: "530272634",
|
|
494
|
+
start_from: "unread",
|
|
495
|
+
target_count: "all",
|
|
496
|
+
criteria: "请扫到底筛选符合条件的人选"
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
job: "530272634",
|
|
500
|
+
start_from: "unread",
|
|
501
|
+
target_count: 20,
|
|
502
|
+
criteria: "请筛选 20 位符合条件的人选"
|
|
503
|
+
}
|
|
504
|
+
]
|
|
490
505
|
};
|
|
491
506
|
if (requireFullInput) {
|
|
492
507
|
schema.required = ["job", "start_from", "criteria"];
|
|
@@ -653,7 +668,7 @@ function createToolsSchema() {
|
|
|
653
668
|
},
|
|
654
669
|
{
|
|
655
670
|
name: TOOL_BOSS_CHAT_START_RUN,
|
|
656
|
-
description: "异步启动一次 boss-chat 任务。必须一次性提供 job、start_from、target_count、criteria
|
|
671
|
+
description: "异步启动一次 boss-chat 任务。必须一次性提供 job、start_from、target_count、criteria;若用户选择扫到底/不限/全部候选人,必须字面传 target_count=\"all\"。",
|
|
657
672
|
inputSchema: createBossChatStartInputSchema({ requireFullInput: true })
|
|
658
673
|
},
|
|
659
674
|
{
|
package/src/pipeline.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
switchRecommendTab
|
|
15
15
|
} from "./adapters.js";
|
|
16
16
|
import {
|
|
17
|
+
buildTargetCountCompatibilityHints,
|
|
17
18
|
cancelBossChatRun,
|
|
18
19
|
getBossChatRun,
|
|
19
20
|
normalizeTargetCountInput,
|
|
@@ -445,12 +446,22 @@ function normalizeFollowUpChatInput(followUp = null, defaults = null) {
|
|
|
445
446
|
});
|
|
446
447
|
}
|
|
447
448
|
if (!hasExplicitTargetCount) {
|
|
449
|
+
const targetCountHints = buildTargetCountCompatibilityHints({
|
|
450
|
+
argumentName: "follow_up.chat.target_count",
|
|
451
|
+
recommendedArgumentPatch: {
|
|
452
|
+
follow_up: {
|
|
453
|
+
chat: {
|
|
454
|
+
target_count: "all"
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
});
|
|
448
459
|
missing_fields.push("follow_up.chat.target_count");
|
|
449
460
|
pending_questions.push({
|
|
461
|
+
...targetCountHints,
|
|
450
462
|
field: "follow_up.chat.target_count",
|
|
451
|
-
question: "请填写 boss-chat follow-up
|
|
463
|
+
question: "请填写 boss-chat follow-up 本次处理人数上限。若扫到底,请在 follow_up.chat.target_count 里字面填写 \"all\"。",
|
|
452
464
|
value: summary.target_count,
|
|
453
|
-
accepted_examples: ["all", -1, 20, "全部候选人"],
|
|
454
465
|
...(explicitTarget.rawValue !== undefined ? { received_target_count: explicitTarget.rawValue } : {}),
|
|
455
466
|
...(explicitTarget.parseError ? { target_count_parse_error: explicitTarget.parseError } : {})
|
|
456
467
|
});
|
package/src/test-boss-chat.js
CHANGED
|
@@ -226,6 +226,9 @@ async function testBossChatAdapterShouldResolveSharedConfigAndInvokeLocalCli() {
|
|
|
226
226
|
assert.deepEqual(prepared.missing_fields, ["job", "start_from", "target_count", "criteria"]);
|
|
227
227
|
const preparedTargetQuestion = prepared.pending_questions.find((item) => item.field === "target_count");
|
|
228
228
|
assert.equal(preparedTargetQuestion.argument_name, "target_count");
|
|
229
|
+
assert.equal(preparedTargetQuestion.recommended_value, "all");
|
|
230
|
+
assert.equal(preparedTargetQuestion.recommended_argument_patch.target_count, "all");
|
|
231
|
+
assert.equal(preparedTargetQuestion.options.some((item) => item.label.includes('target_count="all"')), true);
|
|
229
232
|
assert.equal(prepared.next_call_example.target_count, "all");
|
|
230
233
|
|
|
231
234
|
const preflight = await startBossChatRun({
|
|
@@ -240,6 +243,7 @@ async function testBossChatAdapterShouldResolveSharedConfigAndInvokeLocalCli() {
|
|
|
240
243
|
const preflightTargetQuestion = preflight.pending_questions.find((item) => item.field === "target_count");
|
|
241
244
|
assert.equal(Boolean(preflightTargetQuestion), true);
|
|
242
245
|
assert.equal(preflightTargetQuestion.argument_name, "target_count");
|
|
246
|
+
assert.equal(preflightTargetQuestion.recommended_argument_patch.target_count, "all");
|
|
243
247
|
assert.equal(Array.isArray(preflightTargetQuestion.options), true);
|
|
244
248
|
|
|
245
249
|
const stateAfterPrepare = readStubState(workspaceRoot);
|
|
@@ -331,6 +335,7 @@ async function testBossChatAdapterShouldResolveSharedConfigAndInvokeLocalCli() {
|
|
|
331
335
|
assert.equal(Boolean(invalidTarget.target_count_parse_error), true);
|
|
332
336
|
assert.equal(invalidTarget.next_call_example.target_count, "all");
|
|
333
337
|
assert.equal(invalidTarget.accepted_examples.includes("all"), true);
|
|
338
|
+
assert.equal(invalidTarget.recommended_argument_patch.target_count, "all");
|
|
334
339
|
|
|
335
340
|
const running = await getBossChatRun({
|
|
336
341
|
workspaceRoot,
|
|
@@ -408,11 +413,15 @@ async function testBossChatMcpToolsShouldValidateAndRoute() {
|
|
|
408
413
|
assert.deepEqual(startToolSchema.required, ["job", "start_from", "criteria"]);
|
|
409
414
|
assert.equal(startToolSchema.anyOf.some((item) => item.required?.includes("target_count")), true);
|
|
410
415
|
assert.equal(startToolSchema.anyOf.some((item) => item.required?.includes("targetCount")), true);
|
|
416
|
+
assert.equal(startToolSchema.properties.target_count.examples.includes("all"), true);
|
|
417
|
+
assert.equal(startToolSchema.examples.some((item) => item.target_count === "all"), true);
|
|
411
418
|
|
|
412
419
|
const prepared = await callTool(workspaceRoot, TOOL_BOSS_CHAT_PREPARE_RUN, {}, 101);
|
|
413
420
|
assert.equal(prepared.status, "NEED_INPUT");
|
|
414
421
|
assert.deepEqual(prepared.missing_fields, ["job", "start_from", "target_count", "criteria"]);
|
|
415
|
-
|
|
422
|
+
const preparedTargetCountQuestion = prepared.pending_questions.find((item) => item.field === "target_count");
|
|
423
|
+
assert.equal(preparedTargetCountQuestion.argument_name, "target_count");
|
|
424
|
+
assert.equal(preparedTargetCountQuestion.recommended_argument_patch.target_count, "all");
|
|
416
425
|
|
|
417
426
|
const needInput = await callTool(workspaceRoot, TOOL_BOSS_CHAT_START_RUN, {}, 11);
|
|
418
427
|
assert.equal(needInput.status, "NEED_INPUT");
|
|
@@ -422,7 +431,9 @@ async function testBossChatMcpToolsShouldValidateAndRoute() {
|
|
|
422
431
|
const targetQuestion = needInput.pending_questions.find((item) => item.field === "target_count");
|
|
423
432
|
assert.equal(Boolean(targetQuestion), true);
|
|
424
433
|
assert.equal(targetQuestion.argument_name, "target_count");
|
|
434
|
+
assert.equal(targetQuestion.recommended_argument_patch.target_count, "all");
|
|
425
435
|
assert.equal(targetQuestion.options.some((item) => item.value === "all"), true);
|
|
436
|
+
assert.equal(targetQuestion.options.some((item) => item.label.includes('target_count="all"')), true);
|
|
426
437
|
|
|
427
438
|
const missingTargetOnly = await callTool(workspaceRoot, TOOL_BOSS_CHAT_START_RUN, {
|
|
428
439
|
job: "算法工程师",
|
|
@@ -445,6 +456,7 @@ async function testBossChatMcpToolsShouldValidateAndRoute() {
|
|
|
445
456
|
assert.equal(invalidTargetOnly.received_target_count, "not a target");
|
|
446
457
|
assert.equal(Boolean(invalidTargetOnly.target_count_parse_error), true);
|
|
447
458
|
assert.equal(invalidTargetOnly.next_call_example.target_count, "all");
|
|
459
|
+
assert.equal(invalidTargetOnly.recommended_argument_patch.target_count, "all");
|
|
448
460
|
|
|
449
461
|
const invalidStartResponse = await handleRequest(
|
|
450
462
|
makeToolCall(11, TOOL_BOSS_CHAT_START_RUN, {
|
package/src/test-pipeline.js
CHANGED
|
@@ -2184,6 +2184,8 @@ async function testFollowUpChatMissingFieldsShouldExposeRecommendDefaults() {
|
|
|
2184
2184
|
assert.equal(criteriaQuestion?.value, "默认沿用 recommend 的筛选条件");
|
|
2185
2185
|
assert.equal(startFromQuestion?.value, "unread");
|
|
2186
2186
|
assert.equal(targetCountQuestion?.value, 18);
|
|
2187
|
+
assert.equal(targetCountQuestion?.recommended_argument_patch?.follow_up?.chat?.target_count, "all");
|
|
2188
|
+
assert.equal(targetCountQuestion?.options?.some((item) => item.label.includes('follow_up.chat.target_count="all"')), true);
|
|
2187
2189
|
}
|
|
2188
2190
|
|
|
2189
2191
|
async function testFollowUpChatMissingStartFromShouldNeedInput() {
|
|
@@ -2221,7 +2223,9 @@ async function testFollowUpChatMissingTargetCountShouldNeedInput() {
|
|
|
2221
2223
|
|
|
2222
2224
|
assert.equal(result.status, "NEED_INPUT");
|
|
2223
2225
|
assert.equal(result.missing_fields.includes("follow_up.chat.target_count"), true);
|
|
2224
|
-
|
|
2226
|
+
const targetQuestion = result.pending_questions.find((item) => item.field === "follow_up.chat.target_count");
|
|
2227
|
+
assert.equal(Boolean(targetQuestion), true);
|
|
2228
|
+
assert.equal(targetQuestion.recommended_argument_patch?.follow_up?.chat?.target_count, "all");
|
|
2225
2229
|
}
|
|
2226
2230
|
|
|
2227
2231
|
async function testFollowUpChatInvalidTargetCountShouldNeedInputWithDiagnostics() {
|
|
@@ -2244,6 +2248,7 @@ async function testFollowUpChatInvalidTargetCountShouldNeedInputWithDiagnostics(
|
|
|
2244
2248
|
assert.equal(targetQuestion?.received_target_count, "not a target");
|
|
2245
2249
|
assert.equal(Boolean(targetQuestion?.target_count_parse_error), true);
|
|
2246
2250
|
assert.equal(targetQuestion?.accepted_examples.includes("all"), true);
|
|
2251
|
+
assert.equal(targetQuestion?.recommended_argument_patch?.follow_up?.chat?.target_count, "all");
|
|
2247
2252
|
}
|
|
2248
2253
|
|
|
2249
2254
|
async function testFollowUpChatAllTargetCountShouldLaunchUnlimited() {
|