@reconcrap/boss-recommend-mcp 1.3.7 → 1.3.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/README.md +6 -3
- package/package.json +1 -1
- package/skills/boss-chat/README.md +3 -1
- package/skills/boss-chat/SKILL.md +5 -3
- package/src/boss-chat.js +17 -1
- package/src/cli.js +9 -0
- package/src/index.js +22 -5
- package/src/test-boss-chat.js +38 -0
- package/vendor/boss-chat-cli/src/cli.js +5 -0
package/README.md
CHANGED
|
@@ -201,10 +201,12 @@ node src/cli.js chat run --job "算法工程师" --start-from unread --criteria
|
|
|
201
201
|
|
|
202
202
|
- CLI:
|
|
203
203
|
- `boss-recommend-mcp chat health-check`
|
|
204
|
+
- `boss-recommend-mcp chat prepare-run`
|
|
204
205
|
- `boss-recommend-mcp chat run --job "算法工程师" --start-from unread --targetCount 20 --criteria "有 AI Agent 经验"`(后台启动,不自动轮询)
|
|
205
206
|
- `boss-recommend-mcp chat start-run|get-run|pause-run|resume-run|cancel-run`
|
|
206
207
|
- MCP:
|
|
207
208
|
- `boss_chat_health_check`
|
|
209
|
+
- `prepare_boss_chat_run`
|
|
208
210
|
- `start_boss_chat_run`
|
|
209
211
|
- `get_boss_chat_run`
|
|
210
212
|
- `pause_boss_chat_run`
|
|
@@ -213,13 +215,14 @@ node src/cli.js chat run --job "算法工程师" --start-from unread --criteria
|
|
|
213
215
|
|
|
214
216
|
chat-only 交互建议:
|
|
215
217
|
|
|
216
|
-
- 先调用一次 `
|
|
217
|
-
- 然后基于 `job_options` 让用户选择 `job`,并补齐 `start_from`、`target_count`、`criteria`
|
|
218
|
+
- 先调用一次 `prepare_boss_chat_run`(可不带参数),服务会先导航到 `https://www.zhipin.com/web/chat/index` 并返回 `NEED_INPUT`,其中包含岗位 `job_options` 与待补字段。
|
|
219
|
+
- 然后基于 `job_options` 让用户选择 `job`,并补齐 `start_from`、`target_count`、`criteria` 后调用 `start_boss_chat_run` 启动任务。
|
|
218
220
|
- `target_count` 支持正整数;若用户给出 `全部候选人` / `所有候选人`,会自动按不限(扫到底)处理。
|
|
219
221
|
|
|
220
222
|
Trae-CN / 长对话防循环建议:
|
|
221
223
|
|
|
222
|
-
- 固定流程:`boss_chat_health_check` -> `
|
|
224
|
+
- 固定流程:`boss_chat_health_check` -> `prepare_boss_chat_run(空参可)` -> 一次性补齐 `job/start_from/target_count/criteria` -> `start_boss_chat_run`。
|
|
225
|
+
- `start_boss_chat_run` 的工具 schema 已把 `job/start_from/target_count/criteria` 标记为必填;不要用它获取岗位列表。
|
|
223
226
|
- `start_boss_chat_run` 返回 `ACCEPTED` 后直接结束当前回合,不要自动轮询。
|
|
224
227
|
- 缺参或校验失败时,一次性列出全部缺失/错误项,避免重复同一句提示触发宿主“陷入循环”保护。
|
|
225
228
|
- 仅当用户明确要求“查进度”时再调用 `get_boss_chat_run`。
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@ Please run a Boss chat-only task (do not switch to recommend flow).
|
|
|
13
13
|
|
|
14
14
|
Execution order:
|
|
15
15
|
1) Call boss_chat_health_check.
|
|
16
|
-
2) Call
|
|
16
|
+
2) Call prepare_boss_chat_run once (empty params allowed) to fetch job_options and missing fields.
|
|
17
17
|
3) Ask for these required fields in one shot: job, start_from (unread/all), target_count, criteria.
|
|
18
18
|
4) After user reply, call start_boss_chat_run exactly once to start the run.
|
|
19
19
|
5) If ACCEPTED, reply only with run_id and "task started"; no auto polling.
|
|
@@ -21,6 +21,7 @@ Execution order:
|
|
|
21
21
|
Anti-loop rules:
|
|
22
22
|
- Do not repeat the same sentence across turns.
|
|
23
23
|
- On validation errors, list all missing/invalid fields once.
|
|
24
|
+
- Do not use start_boss_chat_run for preflight. It is only for the final start call and must include job/start_from/target_count/criteria.
|
|
24
25
|
- Do not call start_boss_chat_run repeatedly in one turn.
|
|
25
26
|
- Do not call get_boss_chat_run unless user explicitly asks for progress.
|
|
26
27
|
|
|
@@ -30,4 +31,5 @@ target_count mapping:
|
|
|
30
31
|
- `全部候选人` / `所有候选人` must also be treated as unlimited.
|
|
31
32
|
- Always write the argument key as `target_count`.
|
|
32
33
|
- For unlimited mode, send `"target_count": "all"` in the tool call.
|
|
34
|
+
- 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.
|
|
33
35
|
```
|
|
@@ -14,6 +14,7 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
14
14
|
## Tool Routing
|
|
15
15
|
|
|
16
16
|
- 健康检查:`boss_chat_health_check`
|
|
17
|
+
- 预备并获取岗位列表:`prepare_boss_chat_run`
|
|
17
18
|
- 启动异步任务:`start_boss_chat_run`
|
|
18
19
|
- 查询进度:`get_boss_chat_run`
|
|
19
20
|
- 暂停:`pause_boss_chat_run`
|
|
@@ -29,7 +30,6 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
29
30
|
|
|
30
31
|
可选:
|
|
31
32
|
|
|
32
|
-
- `target_count`
|
|
33
33
|
- `profile`(默认 `default`)
|
|
34
34
|
- `port`
|
|
35
35
|
- `dry_run`
|
|
@@ -57,7 +57,9 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
57
57
|
- 当用户选择“扫到底/全部候选人/所有候选人”时,调用参数统一写:`"target_count": "all"`。
|
|
58
58
|
- 禁止 agent 自行补全 `job/start_from/criteria` 并直接执行,必须由用户明确给出或确认。
|
|
59
59
|
- chat-only 启动流程必须先进入聊天页并拉取岗位列表,再让用户从列表中选择 `job`。
|
|
60
|
-
-
|
|
60
|
+
- 必须先用空参调用 `prepare_boss_chat_run` 获取 `job_options`;不要用 `start_boss_chat_run` 做预备调用。
|
|
61
|
+
- `start_boss_chat_run` 只能用于真正启动,必须一次性传齐 `job` / `start_from` / `target_count` / `criteria`。
|
|
62
|
+
- 若 `start_boss_chat_run` 返回 `NEED_INPUT` 且 `missing_fields` 包含 `target_count`,说明你没有把用户选择写入工具参数;下一次调用必须照 `next_call_example` 原样补上 `"target_count": "all"` 或正整数,不要重复空调用。
|
|
61
63
|
- 默认不自动轮询;只有用户要求查进度时才调用 `get_boss_chat_run`。
|
|
62
64
|
- `start_boss_chat_run` 返回 `ACCEPTED` 后,默认立即结束当前回合,不得主动连续调用 `get_boss_chat_run`。
|
|
63
65
|
- 只有当用户明确给出“轮询频率/间隔”(例如“每30分钟查一次”)时,才允许按该频率查询进度。
|
|
@@ -73,6 +75,6 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
73
75
|
## Response Style
|
|
74
76
|
|
|
75
77
|
- 用结构化中文。
|
|
76
|
-
- 首轮建议先调用一次 `
|
|
78
|
+
- 首轮建议先调用一次 `prepare_boss_chat_run`(可空参)获取 `job_options` 与 `pending_questions`。
|
|
77
79
|
- 缺参时必须逐项确认:`job`(来自岗位列表)、`start_from`(`unread|all`)、`target_count`、`criteria`。
|
|
78
80
|
- 若健康检查失败,明确提示共享配置文件 `screening-config.json` 不可用。
|
package/src/boss-chat.js
CHANGED
|
@@ -508,7 +508,23 @@ export async function startBossChatRun({ workspaceRoot, input = {} }) {
|
|
|
508
508
|
}
|
|
509
509
|
|
|
510
510
|
export async function prepareBossChatRun({ workspaceRoot, input = {} }) {
|
|
511
|
-
|
|
511
|
+
const payload = (await spawnBossChatCli({ workspaceRoot, command: "prepare-run", input })).payload;
|
|
512
|
+
if (payload?.status !== "NEED_INPUT") return payload;
|
|
513
|
+
|
|
514
|
+
const missingFields = getMissingBossChatStartFields(input);
|
|
515
|
+
const pendingQuestions = Array.isArray(payload?.pending_questions)
|
|
516
|
+
? payload.pending_questions.filter((item) => (
|
|
517
|
+
missingFields.length === 0 || missingFields.includes(String(item?.field || ""))
|
|
518
|
+
))
|
|
519
|
+
: [];
|
|
520
|
+
const nextCallExample = buildNextCallExample(input, missingFields);
|
|
521
|
+
return {
|
|
522
|
+
...payload,
|
|
523
|
+
required_fields: CHAT_REQUIRED_FIELDS.slice(),
|
|
524
|
+
missing_fields: missingFields,
|
|
525
|
+
pending_questions: normalizePendingQuestions(pendingQuestions),
|
|
526
|
+
...(nextCallExample ? { next_call_example: nextCallExample } : {})
|
|
527
|
+
};
|
|
512
528
|
}
|
|
513
529
|
|
|
514
530
|
export async function getBossChatRun({ workspaceRoot, input = {} }) {
|
package/src/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getBossChatHealthCheck,
|
|
22
22
|
getBossChatRun,
|
|
23
23
|
pauseBossChatRun,
|
|
24
|
+
prepareBossChatRun,
|
|
24
25
|
resumeBossChatRun,
|
|
25
26
|
startBossChatRun
|
|
26
27
|
} from "./boss-chat.js";
|
|
@@ -1360,6 +1361,14 @@ async function runBossChatCliCommand(subcommand, options = {}) {
|
|
|
1360
1361
|
return;
|
|
1361
1362
|
}
|
|
1362
1363
|
|
|
1364
|
+
if (subcommand === "prepare-run") {
|
|
1365
|
+
printJson(await prepareBossChatRun({
|
|
1366
|
+
workspaceRoot,
|
|
1367
|
+
input: buildBossChatCliInput(options)
|
|
1368
|
+
}));
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1363
1372
|
if (subcommand === "run") {
|
|
1364
1373
|
printJson(await startBossChatRun({
|
|
1365
1374
|
workspaceRoot,
|
package/src/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
getBossChatHealthCheck,
|
|
14
14
|
getBossChatRun,
|
|
15
15
|
pauseBossChatRun,
|
|
16
|
+
prepareBossChatRun,
|
|
16
17
|
resumeBossChatRun,
|
|
17
18
|
startBossChatRun
|
|
18
19
|
} from "./boss-chat.js";
|
|
@@ -51,6 +52,7 @@ const TOOL_RUN_FEATURED_CALIBRATION = "run_featured_calibration";
|
|
|
51
52
|
const TOOL_GET_FEATURED_CALIBRATION_STATUS = "get_featured_calibration_status";
|
|
52
53
|
const TOOL_RUN_RECOMMEND_SELF_HEAL = "run_recommend_self_heal";
|
|
53
54
|
const TOOL_BOSS_CHAT_HEALTH_CHECK = "boss_chat_health_check";
|
|
55
|
+
const TOOL_BOSS_CHAT_PREPARE_RUN = "prepare_boss_chat_run";
|
|
54
56
|
const TOOL_BOSS_CHAT_START_RUN = "start_boss_chat_run";
|
|
55
57
|
const TOOL_BOSS_CHAT_GET_RUN = "get_boss_chat_run";
|
|
56
58
|
const TOOL_BOSS_CHAT_PAUSE_RUN = "pause_boss_chat_run";
|
|
@@ -413,8 +415,8 @@ function createRunInputSchema() {
|
|
|
413
415
|
};
|
|
414
416
|
}
|
|
415
417
|
|
|
416
|
-
function createBossChatStartInputSchema() {
|
|
417
|
-
|
|
418
|
+
function createBossChatStartInputSchema({ requireFullInput = false } = {}) {
|
|
419
|
+
const schema = {
|
|
418
420
|
type: "object",
|
|
419
421
|
properties: {
|
|
420
422
|
profile: {
|
|
@@ -459,6 +461,10 @@ function createBossChatStartInputSchema() {
|
|
|
459
461
|
},
|
|
460
462
|
additionalProperties: false
|
|
461
463
|
};
|
|
464
|
+
if (requireFullInput) {
|
|
465
|
+
schema.required = ["job", "start_from", "target_count", "criteria"];
|
|
466
|
+
}
|
|
467
|
+
return schema;
|
|
462
468
|
}
|
|
463
469
|
|
|
464
470
|
function createRunFeaturedCalibrationInputSchema() {
|
|
@@ -610,10 +616,15 @@ function createToolsSchema() {
|
|
|
610
616
|
}
|
|
611
617
|
},
|
|
612
618
|
{
|
|
613
|
-
name:
|
|
614
|
-
description: "
|
|
619
|
+
name: TOOL_BOSS_CHAT_PREPARE_RUN,
|
|
620
|
+
description: "预备一次 boss-chat 任务:只导航聊天页并返回岗位列表与待补字段,不会启动任务。用它先获取 job_options。",
|
|
615
621
|
inputSchema: createBossChatStartInputSchema()
|
|
616
622
|
},
|
|
623
|
+
{
|
|
624
|
+
name: TOOL_BOSS_CHAT_START_RUN,
|
|
625
|
+
description: "异步启动一次 boss-chat 任务。必须一次性提供 job、start_from、target_count、criteria;扫到底请传 target_count=\"all\"。",
|
|
626
|
+
inputSchema: createBossChatStartInputSchema({ requireFullInput: true })
|
|
627
|
+
},
|
|
617
628
|
{
|
|
618
629
|
name: TOOL_BOSS_CHAT_GET_RUN,
|
|
619
630
|
description: "查询 boss-chat run_id 的当前状态。",
|
|
@@ -1776,6 +1787,10 @@ function handleBossChatHealthCheckTool(workspaceRoot, args) {
|
|
|
1776
1787
|
return getBossChatHealthCheck(workspaceRoot, args);
|
|
1777
1788
|
}
|
|
1778
1789
|
|
|
1790
|
+
async function handleBossChatPrepareRunTool({ workspaceRoot, args }) {
|
|
1791
|
+
return prepareBossChatRun({ workspaceRoot, input: args });
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1779
1794
|
async function handleBossChatStartRunTool({ workspaceRoot, args }) {
|
|
1780
1795
|
return startBossChatRun({ workspaceRoot, input: args });
|
|
1781
1796
|
}
|
|
@@ -1859,7 +1874,7 @@ async function handleRequest(message, workspaceRoot) {
|
|
|
1859
1874
|
}
|
|
1860
1875
|
}
|
|
1861
1876
|
|
|
1862
|
-
if (
|
|
1877
|
+
if ([TOOL_BOSS_CHAT_PREPARE_RUN, TOOL_BOSS_CHAT_START_RUN].includes(toolName)) {
|
|
1863
1878
|
const inputError = validateBossChatStartArgs(args);
|
|
1864
1879
|
if (inputError) {
|
|
1865
1880
|
return createJsonRpcError(id, -32602, inputError);
|
|
@@ -1901,6 +1916,8 @@ async function handleRequest(message, workspaceRoot) {
|
|
|
1901
1916
|
payload = await handleRunRecommendSelfHealTool({ workspaceRoot, args });
|
|
1902
1917
|
} else if (toolName === TOOL_BOSS_CHAT_HEALTH_CHECK) {
|
|
1903
1918
|
payload = handleBossChatHealthCheckTool(workspaceRoot, args);
|
|
1919
|
+
} else if (toolName === TOOL_BOSS_CHAT_PREPARE_RUN) {
|
|
1920
|
+
payload = await handleBossChatPrepareRunTool({ workspaceRoot, args });
|
|
1904
1921
|
} else if (toolName === TOOL_BOSS_CHAT_START_RUN) {
|
|
1905
1922
|
payload = await handleBossChatStartRunTool({ workspaceRoot, args });
|
|
1906
1923
|
} else if (toolName === TOOL_BOSS_CHAT_GET_RUN) {
|
package/src/test-boss-chat.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
getBossChatHealthCheck,
|
|
9
9
|
getBossChatRun,
|
|
10
10
|
pauseBossChatRun,
|
|
11
|
+
prepareBossChatRun,
|
|
11
12
|
resumeBossChatRun,
|
|
12
13
|
startBossChatRun
|
|
13
14
|
} from "./boss-chat.js";
|
|
@@ -17,6 +18,7 @@ import { __testables as indexTestables } from "./index.js";
|
|
|
17
18
|
const { handleRequest } = indexTestables;
|
|
18
19
|
|
|
19
20
|
const TOOL_BOSS_CHAT_HEALTH_CHECK = "boss_chat_health_check";
|
|
21
|
+
const TOOL_BOSS_CHAT_PREPARE_RUN = "prepare_boss_chat_run";
|
|
20
22
|
const TOOL_BOSS_CHAT_START_RUN = "start_boss_chat_run";
|
|
21
23
|
const TOOL_BOSS_CHAT_GET_RUN = "get_boss_chat_run";
|
|
22
24
|
const TOOL_BOSS_CHAT_PAUSE_RUN = "pause_boss_chat_run";
|
|
@@ -202,6 +204,16 @@ async function testBossChatAdapterShouldResolveSharedConfigAndInvokeLocalCli() {
|
|
|
202
204
|
assert.equal(health.shared_llm_config, true);
|
|
203
205
|
assert.equal(health.debug_port, 9666);
|
|
204
206
|
|
|
207
|
+
const prepared = await prepareBossChatRun({
|
|
208
|
+
workspaceRoot,
|
|
209
|
+
input: {}
|
|
210
|
+
});
|
|
211
|
+
assert.equal(prepared.status, "NEED_INPUT");
|
|
212
|
+
assert.deepEqual(prepared.missing_fields, ["job", "start_from", "target_count", "criteria"]);
|
|
213
|
+
const preparedTargetQuestion = prepared.pending_questions.find((item) => item.field === "target_count");
|
|
214
|
+
assert.equal(preparedTargetQuestion.argument_name, "target_count");
|
|
215
|
+
assert.equal(prepared.next_call_example.target_count, "all");
|
|
216
|
+
|
|
205
217
|
const preflight = await startBossChatRun({
|
|
206
218
|
workspaceRoot,
|
|
207
219
|
input: {}
|
|
@@ -301,6 +313,23 @@ async function testBossChatAdapterShouldResolveSharedConfigAndInvokeLocalCli() {
|
|
|
301
313
|
|
|
302
314
|
async function testBossChatMcpToolsShouldValidateAndRoute() {
|
|
303
315
|
await withBossChatWorkspace(async (workspaceRoot) => {
|
|
316
|
+
const toolsResponse = await handleRequest({
|
|
317
|
+
jsonrpc: "2.0",
|
|
318
|
+
id: 10,
|
|
319
|
+
method: "tools/list",
|
|
320
|
+
params: {}
|
|
321
|
+
}, workspaceRoot);
|
|
322
|
+
const tools = toolsResponse.result.tools;
|
|
323
|
+
const prepareToolSchema = tools.find((item) => item.name === TOOL_BOSS_CHAT_PREPARE_RUN).inputSchema;
|
|
324
|
+
const startToolSchema = tools.find((item) => item.name === TOOL_BOSS_CHAT_START_RUN).inputSchema;
|
|
325
|
+
assert.equal(prepareToolSchema.required, undefined);
|
|
326
|
+
assert.deepEqual(startToolSchema.required, ["job", "start_from", "target_count", "criteria"]);
|
|
327
|
+
|
|
328
|
+
const prepared = await callTool(workspaceRoot, TOOL_BOSS_CHAT_PREPARE_RUN, {}, 101);
|
|
329
|
+
assert.equal(prepared.status, "NEED_INPUT");
|
|
330
|
+
assert.deepEqual(prepared.missing_fields, ["job", "start_from", "target_count", "criteria"]);
|
|
331
|
+
assert.equal(prepared.pending_questions.find((item) => item.field === "target_count").argument_name, "target_count");
|
|
332
|
+
|
|
304
333
|
const needInput = await callTool(workspaceRoot, TOOL_BOSS_CHAT_START_RUN, {}, 11);
|
|
305
334
|
assert.equal(needInput.status, "NEED_INPUT");
|
|
306
335
|
assert.deepEqual(needInput.required_fields, ["job", "start_from", "target_count", "criteria"]);
|
|
@@ -413,6 +442,15 @@ async function testBossChatCliShouldSupportRunAndFollowUpParsing() {
|
|
|
413
442
|
}
|
|
414
443
|
|
|
415
444
|
await withBossChatWorkspace(async (workspaceRoot) => {
|
|
445
|
+
const prepareLogs = await captureConsoleLogs(async () => {
|
|
446
|
+
await cliTestables.runBossChatCliCommand("prepare-run", {
|
|
447
|
+
"workspace-root": workspaceRoot
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
const prepared = JSON.parse(prepareLogs[0]);
|
|
451
|
+
assert.equal(prepared.status, "NEED_INPUT");
|
|
452
|
+
assert.equal(prepared.pending_questions.find((item) => item.field === "target_count").argument_name, "target_count");
|
|
453
|
+
|
|
416
454
|
const logs = await captureConsoleLogs(async () => {
|
|
417
455
|
await cliTestables.runBossChatCliCommand("run", {
|
|
418
456
|
"workspace-root": workspaceRoot,
|
|
@@ -141,10 +141,15 @@ function isUnlimitedTargetCountToken(value) {
|
|
|
141
141
|
'inf',
|
|
142
142
|
'max',
|
|
143
143
|
'full',
|
|
144
|
+
'allcandidates',
|
|
144
145
|
'全部',
|
|
145
146
|
'全量',
|
|
146
147
|
'不限',
|
|
147
148
|
'扫到底',
|
|
149
|
+
'全部候选人',
|
|
150
|
+
'所有候选人',
|
|
151
|
+
'全部人选',
|
|
152
|
+
'所有人选',
|
|
148
153
|
'直到完成所有人选',
|
|
149
154
|
].includes(token);
|
|
150
155
|
}
|