@reconcrap/boss-recommend-mcp 1.3.6 → 1.3.7
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/package.json +1 -1
- package/skills/boss-chat/README.md +2 -0
- package/skills/boss-chat/SKILL.md +2 -0
- package/src/boss-chat.js +40 -1
- package/src/test-boss-chat.js +18 -0
package/package.json
CHANGED
|
@@ -28,4 +28,6 @@ target_count mapping:
|
|
|
28
28
|
- Positive integer means explicit cap (for example 20).
|
|
29
29
|
- `all` / `unlimited` / `全部` / `不限` / `扫到底` / `全量` means unlimited.
|
|
30
30
|
- `全部候选人` / `所有候选人` must also be treated as unlimited.
|
|
31
|
+
- Always write the argument key as `target_count`.
|
|
32
|
+
- For unlimited mode, send `"target_count": "all"` in the tool call.
|
|
31
33
|
```
|
|
@@ -53,6 +53,8 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
53
53
|
- `job` / `start_from` / `criteria` 缺一不可;缺参时只补缺口。
|
|
54
54
|
- `target_count` 在 chat-only 启动前也是必填项,不能默认省略。
|
|
55
55
|
- 当用户说“全部候选人/所有候选人”时,必须按“扫到底(unlimited)”处理,不要再追问正整数。
|
|
56
|
+
- 参数名必须写 `target_count`(不要写“目标数量”等中文键名)。
|
|
57
|
+
- 当用户选择“扫到底/全部候选人/所有候选人”时,调用参数统一写:`"target_count": "all"`。
|
|
56
58
|
- 禁止 agent 自行补全 `job/start_from/criteria` 并直接执行,必须由用户明确给出或确认。
|
|
57
59
|
- chat-only 启动流程必须先进入聊天页并拉取岗位列表,再让用户从列表中选择 `job`。
|
|
58
60
|
- 允许先用空参调用 `start_boss_chat_run` 触发 `NEED_INPUT`;若返回了 `job_options`,必须完整展示所有岗位选项给用户确认。
|
package/src/boss-chat.js
CHANGED
|
@@ -261,6 +261,42 @@ function getMissingBossChatStartFields(input = {}) {
|
|
|
261
261
|
return missing;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
function buildTargetCountQuestionHint(item = {}) {
|
|
265
|
+
const next = { ...item };
|
|
266
|
+
next.question = "请输入 target_count:正整数,或 all(扫到底)。";
|
|
267
|
+
next.options = [
|
|
268
|
+
{ label: "扫到底(推荐)", value: "all" },
|
|
269
|
+
{ label: "不限", value: "unlimited" },
|
|
270
|
+
{ label: "全部候选人", value: "全部候选人" },
|
|
271
|
+
{ label: "所有候选人", value: "所有候选人" }
|
|
272
|
+
];
|
|
273
|
+
next.examples = ["all", 20];
|
|
274
|
+
next.argument_name = "target_count";
|
|
275
|
+
return next;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function normalizePendingQuestions(pendingQuestions = []) {
|
|
279
|
+
return pendingQuestions.map((item) => {
|
|
280
|
+
if (String(item?.field || "") !== "target_count") return item;
|
|
281
|
+
return buildTargetCountQuestionHint(item);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function buildNextCallExample(input = {}, missingFields = []) {
|
|
286
|
+
if (!Array.isArray(missingFields) || missingFields.length === 0) return null;
|
|
287
|
+
const normalized = normalizeBossChatStartInput(input);
|
|
288
|
+
const sample = {};
|
|
289
|
+
if (normalized.job) sample.job = normalized.job;
|
|
290
|
+
if (normalized.startFrom) sample.start_from = normalized.startFrom;
|
|
291
|
+
if (normalized.criteria) sample.criteria = normalized.criteria;
|
|
292
|
+
if (normalized.targetCountProvided) {
|
|
293
|
+
sample.target_count = normalized.targetCountArg === "-1" ? "all" : normalized.targetCount;
|
|
294
|
+
} else if (missingFields.includes("target_count")) {
|
|
295
|
+
sample.target_count = "all";
|
|
296
|
+
}
|
|
297
|
+
return Object.keys(sample).length > 0 ? sample : null;
|
|
298
|
+
}
|
|
299
|
+
|
|
264
300
|
function buildBossChatCliArgs(command, input, resolvedConfig) {
|
|
265
301
|
const args = [command, "--json"];
|
|
266
302
|
if (command === "prepare-run") {
|
|
@@ -455,12 +491,15 @@ export async function startBossChatRun({ workspaceRoot, input = {} }) {
|
|
|
455
491
|
const pendingQuestions = Array.isArray(prepared?.pending_questions)
|
|
456
492
|
? prepared.pending_questions.filter((item) => missingFields.includes(String(item?.field || "")))
|
|
457
493
|
: [];
|
|
494
|
+
const normalizedPendingQuestions = normalizePendingQuestions(pendingQuestions);
|
|
495
|
+
const nextCallExample = buildNextCallExample(input, missingFields);
|
|
458
496
|
return {
|
|
459
497
|
...prepared,
|
|
460
498
|
status: "NEED_INPUT",
|
|
461
499
|
required_fields: CHAT_REQUIRED_FIELDS.slice(),
|
|
462
500
|
missing_fields: missingFields,
|
|
463
|
-
pending_questions:
|
|
501
|
+
pending_questions: normalizedPendingQuestions,
|
|
502
|
+
...(nextCallExample ? { next_call_example: nextCallExample } : {}),
|
|
464
503
|
message: prepared?.message
|
|
465
504
|
|| "已获取 Boss 聊天页岗位列表,请先补齐 job / start_from / target_count / criteria。"
|
|
466
505
|
};
|
package/src/test-boss-chat.js
CHANGED
|
@@ -210,6 +210,11 @@ async function testBossChatAdapterShouldResolveSharedConfigAndInvokeLocalCli() {
|
|
|
210
210
|
assert.deepEqual(preflight.required_fields, ["job", "start_from", "target_count", "criteria"]);
|
|
211
211
|
assert.equal(Array.isArray(preflight.job_options), true);
|
|
212
212
|
assert.equal(preflight.job_options.length, 2);
|
|
213
|
+
assert.equal(Array.isArray(preflight.pending_questions), true);
|
|
214
|
+
const preflightTargetQuestion = preflight.pending_questions.find((item) => item.field === "target_count");
|
|
215
|
+
assert.equal(Boolean(preflightTargetQuestion), true);
|
|
216
|
+
assert.equal(preflightTargetQuestion.argument_name, "target_count");
|
|
217
|
+
assert.equal(Array.isArray(preflightTargetQuestion.options), true);
|
|
213
218
|
|
|
214
219
|
const stateAfterPrepare = readStubState(workspaceRoot);
|
|
215
220
|
assert.equal(stateAfterPrepare.last_prepare_args.profile, "default");
|
|
@@ -301,6 +306,19 @@ async function testBossChatMcpToolsShouldValidateAndRoute() {
|
|
|
301
306
|
assert.deepEqual(needInput.required_fields, ["job", "start_from", "target_count", "criteria"]);
|
|
302
307
|
assert.equal(Array.isArray(needInput.job_options), true);
|
|
303
308
|
assert.equal(needInput.job_options.length, 2);
|
|
309
|
+
const targetQuestion = needInput.pending_questions.find((item) => item.field === "target_count");
|
|
310
|
+
assert.equal(Boolean(targetQuestion), true);
|
|
311
|
+
assert.equal(targetQuestion.argument_name, "target_count");
|
|
312
|
+
assert.equal(targetQuestion.options.some((item) => item.value === "all"), true);
|
|
313
|
+
|
|
314
|
+
const missingTargetOnly = await callTool(workspaceRoot, TOOL_BOSS_CHAT_START_RUN, {
|
|
315
|
+
job: "算法工程师",
|
|
316
|
+
start_from: "all",
|
|
317
|
+
criteria: "全部候选人都过一遍"
|
|
318
|
+
}, 111);
|
|
319
|
+
assert.equal(missingTargetOnly.status, "NEED_INPUT");
|
|
320
|
+
assert.deepEqual(missingTargetOnly.missing_fields, ["target_count"]);
|
|
321
|
+
assert.equal(missingTargetOnly.next_call_example.target_count, "all");
|
|
304
322
|
|
|
305
323
|
const invalidStartResponse = await handleRequest(
|
|
306
324
|
makeToolCall(11, TOOL_BOSS_CHAT_START_RUN, {
|