@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reconcrap/boss-recommend-mcp",
3
- "version": "1.3.6",
3
+ "version": "1.3.7",
4
4
  "description": "Unified MCP pipeline for recommend-page filtering and screening on Boss Zhipin",
5
5
  "keywords": [
6
6
  "boss",
@@ -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: pendingQuestions,
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
  };
@@ -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, {