@reconcrap/boss-recommend-mcp 1.3.30 → 1.3.32

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.
@@ -3,6 +3,8 @@
3
3
  "apiKey": "replace-with-openai-api-key",
4
4
  "model": "gpt-4.1-mini",
5
5
  "llmThinkingLevel": "low",
6
+ "llmTimeoutMs": 60000,
7
+ "llmMaxRetries": 3,
6
8
  "humanRestEnabled": false,
7
9
  "openaiOrganization": "optional-org-id",
8
10
  "openaiProject": "optional-project-id"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reconcrap/boss-recommend-mcp",
3
- "version": "1.3.30",
3
+ "version": "1.3.32",
4
4
  "description": "Unified MCP pipeline for recommend-page filtering and screening on Boss Zhipin",
5
5
  "keywords": [
6
6
  "boss",
package/src/adapters.js CHANGED
@@ -27,6 +27,8 @@ const LLM_THINKING_LEVEL_FIELDS = [
27
27
  "reasoningEffort",
28
28
  "reasoning_effort"
29
29
  ];
30
+ const DEFAULT_SHARED_LLM_TIMEOUT_MS = 60000;
31
+ const DEFAULT_SHARED_LLM_MAX_RETRIES = 3;
30
32
  const DEFAULT_RECOMMEND_SCREEN_TIMEOUT_MS = 24 * 60 * 60 * 1000;
31
33
  const PAGE_SCOPE_TO_TAB_STATUS = {
32
34
  recommend: "0",
@@ -405,6 +407,19 @@ function resolveLlmThinkingLevel(config = {}) {
405
407
  }
406
408
  return "";
407
409
  }
410
+
411
+ export function resolveSharedLlmTransportConfig(config = {}) {
412
+ const timeoutMs = parsePositiveInteger(config?.llmTimeoutMs)
413
+ || parsePositiveInteger(config?.llm_timeout_ms)
414
+ || DEFAULT_SHARED_LLM_TIMEOUT_MS;
415
+ const maxRetries = parsePositiveInteger(config?.llmMaxRetries)
416
+ || parsePositiveInteger(config?.llm_max_retries)
417
+ || DEFAULT_SHARED_LLM_MAX_RETRIES;
418
+ return {
419
+ llmTimeoutMs: timeoutMs,
420
+ llmMaxRetries: maxRetries
421
+ };
422
+ }
408
423
 
409
424
  function resolveWorkspaceDebugPort(workspaceRoot) {
410
425
  const fromEnv = parsePositiveInteger(process.env.BOSS_RECOMMEND_CHROME_PORT);
@@ -2961,6 +2976,13 @@ export async function runRecommendScreenCli({
2961
2976
  if (llmThinkingLevel) {
2962
2977
  args.push("--thinking-level", llmThinkingLevel);
2963
2978
  }
2979
+ const sharedLlmTransport = resolveSharedLlmTransportConfig(loaded.config);
2980
+ if (sharedLlmTransport.llmTimeoutMs) {
2981
+ args.push("--llm-timeout-ms", String(sharedLlmTransport.llmTimeoutMs));
2982
+ }
2983
+ if (sharedLlmTransport.llmMaxRetries) {
2984
+ args.push("--llm-max-retries", String(sharedLlmTransport.llmMaxRetries));
2985
+ }
2964
2986
  args.push("--human-rest", String(resolveHumanRestEnabled(loaded.config)));
2965
2987
  if (Number.isInteger(screenParams.target_count) && screenParams.target_count > 0) {
2966
2988
  args.push("--targetCount", String(screenParams.target_count));
package/src/boss-chat.js CHANGED
@@ -4,7 +4,7 @@ import process from "node:process";
4
4
  import { spawn } from "node:child_process";
5
5
  import { fileURLToPath } from "node:url";
6
6
 
7
- import { getScreenConfigResolution } from "./adapters.js";
7
+ import { getScreenConfigResolution, resolveSharedLlmTransportConfig } from "./adapters.js";
8
8
 
9
9
  const currentFilePath = fileURLToPath(import.meta.url);
10
10
  const packageRoot = path.resolve(path.dirname(currentFilePath), "..");
@@ -364,6 +364,7 @@ function resolveBossChatScreenConfig(workspaceRoot) {
364
364
  apiKey: normalizeText(parsed.apiKey),
365
365
  model: normalizeText(parsed.model),
366
366
  llmThinkingLevel: resolveLlmThinkingLevel(parsed),
367
+ ...resolveSharedLlmTransportConfig(parsed),
367
368
  debugPort: parsePositiveInteger(parsed.debugPort, 9222),
368
369
  humanRestEnabled: resolveHumanRestEnabled(parsed)
369
370
  },
@@ -484,6 +485,12 @@ function buildBossChatCliArgs(command, input, resolvedConfig) {
484
485
  if (resolvedConfig.llmThinkingLevel) {
485
486
  args.push("--thinking-level", resolvedConfig.llmThinkingLevel);
486
487
  }
488
+ if (resolvedConfig.llmTimeoutMs) {
489
+ args.push("--llm-timeout-ms", String(resolvedConfig.llmTimeoutMs));
490
+ }
491
+ if (resolvedConfig.llmMaxRetries) {
492
+ args.push("--llm-max-retries", String(resolvedConfig.llmMaxRetries));
493
+ }
487
494
  return args;
488
495
  }
489
496
 
@@ -504,6 +511,12 @@ function buildBossChatCliArgs(command, input, resolvedConfig) {
504
511
  if (resolvedConfig.llmThinkingLevel) {
505
512
  args.push("--thinking-level", resolvedConfig.llmThinkingLevel);
506
513
  }
514
+ if (resolvedConfig.llmTimeoutMs) {
515
+ args.push("--llm-timeout-ms", String(resolvedConfig.llmTimeoutMs));
516
+ }
517
+ if (resolvedConfig.llmMaxRetries) {
518
+ args.push("--llm-max-retries", String(resolvedConfig.llmMaxRetries));
519
+ }
507
520
  args.push("--port", String(normalized.port || resolvedConfig.debugPort || 9222));
508
521
  if (typeof normalized.safePacing === "boolean") {
509
522
  args.push("--safe-pacing", String(normalized.safePacing));
@@ -7,6 +7,7 @@ import {
7
7
  runPipelinePreflight,
8
8
  runRecommendSearchCli,
9
9
  runRecommendScreenCli,
10
+ resolveSharedLlmTransportConfig,
10
11
  __testables as adapterTestables
11
12
  } from "./adapters.js";
12
13
 
@@ -107,6 +108,23 @@ function testResolveScreenTimeoutDefaultsTo24Hours() {
107
108
  }
108
109
  }
109
110
 
111
+ function testResolveSharedLlmTransportConfigShouldUseDefaultsAndOverrides() {
112
+ assert.deepEqual(resolveSharedLlmTransportConfig({}), {
113
+ llmTimeoutMs: 60000,
114
+ llmMaxRetries: 3,
115
+ });
116
+ assert.deepEqual(
117
+ resolveSharedLlmTransportConfig({
118
+ llmTimeoutMs: 90000,
119
+ llmMaxRetries: 5,
120
+ }),
121
+ {
122
+ llmTimeoutMs: 90000,
123
+ llmMaxRetries: 5,
124
+ },
125
+ );
126
+ }
127
+
110
128
  function testBuildRecommendScreenProcessErrorMapsTimeout() {
111
129
  const error = buildRecommendScreenProcessError({ code: -1, error_code: "TIMEOUT" }, 86400000);
112
130
  assert.equal(error?.code, "TIMEOUT");
@@ -155,6 +173,76 @@ async function testResumeRequiresCheckpointFile() {
155
173
  }
156
174
  }
157
175
 
176
+ async function testRecommendScreenCliShouldPassSharedLlmTransportArgs() {
177
+ const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-stub-"));
178
+ const screenDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
179
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-home-"));
180
+ const previousHome = process.env.BOSS_RECOMMEND_HOME;
181
+ fs.mkdirSync(screenDir, { recursive: true });
182
+ fs.writeFileSync(
183
+ path.join(screenDir, "boss-recommend-screen-cli.cjs"),
184
+ [
185
+ "#!/usr/bin/env node",
186
+ "const fs = require('node:fs');",
187
+ "const path = require('node:path');",
188
+ "const argv = process.argv.slice(2);",
189
+ "const parsed = {};",
190
+ "for (let i = 0; i < argv.length; i += 1) {",
191
+ " const token = argv[i];",
192
+ " if (!token.startsWith('--')) continue;",
193
+ " const next = argv[i + 1];",
194
+ " parsed[token.slice(2)] = next && !next.startsWith('--') ? next : true;",
195
+ " if (next && !next.startsWith('--')) i += 1;",
196
+ "}",
197
+ "const output = path.join(process.env.BOSS_RECOMMEND_HOME, 'screen-cli-args.json');",
198
+ "fs.writeFileSync(output, JSON.stringify(parsed, null, 2));",
199
+ "console.log(JSON.stringify({ status: 'COMPLETED', result: { processed_count: 0, output_csv: parsed.output || '' } }));",
200
+ ].join("\n"),
201
+ "utf8",
202
+ );
203
+
204
+ process.env.BOSS_RECOMMEND_HOME = tempHome;
205
+ fs.writeFileSync(
206
+ path.join(tempHome, "screening-config.json"),
207
+ JSON.stringify(
208
+ {
209
+ baseUrl: "https://api.openai.com/v1",
210
+ apiKey: "sk-valid-test",
211
+ model: "gpt-4.1-mini",
212
+ llmTimeoutMs: 75000,
213
+ llmMaxRetries: 6,
214
+ },
215
+ null,
216
+ 2,
217
+ ),
218
+ );
219
+
220
+ try {
221
+ const result = await runRecommendScreenCli({
222
+ workspaceRoot,
223
+ screenParams: {
224
+ criteria: "有 MCP 经验",
225
+ target_count: null,
226
+ post_action: "none",
227
+ max_greet_count: null,
228
+ },
229
+ pageScope: "recommend",
230
+ });
231
+ assert.equal(result.ok, true);
232
+ const parsed = JSON.parse(fs.readFileSync(path.join(tempHome, "screen-cli-args.json"), "utf8"));
233
+ assert.equal(parsed["llm-timeout-ms"], "75000");
234
+ assert.equal(parsed["llm-max-retries"], "6");
235
+ } finally {
236
+ if (previousHome === undefined) {
237
+ delete process.env.BOSS_RECOMMEND_HOME;
238
+ } else {
239
+ process.env.BOSS_RECOMMEND_HOME = previousHome;
240
+ }
241
+ fs.rmSync(workspaceRoot, { recursive: true, force: true });
242
+ fs.rmSync(tempHome, { recursive: true, force: true });
243
+ }
244
+ }
245
+
158
246
  function testPreflightShouldCheckSharpInsteadOfPython() {
159
247
  const preflight = runPipelinePreflight(process.cwd());
160
248
  const keys = new Set((preflight.checks || []).map((item) => item?.key));
@@ -520,8 +608,10 @@ async function main() {
520
608
  testParsePausedStructuredOutput();
521
609
  testParseScreenProgressLineShouldCountFavoriteFailureAsSkipped();
522
610
  testResolveScreenTimeoutDefaultsTo24Hours();
611
+ testResolveSharedLlmTransportConfigShouldUseDefaultsAndOverrides();
523
612
  testBuildRecommendScreenProcessErrorMapsTimeout();
524
613
  await testResumeRequiresCheckpointFile();
614
+ await testRecommendScreenCliShouldPassSharedLlmTransportArgs();
525
615
  testPreflightShouldCheckSharpInsteadOfPython();
526
616
  testPreflightFeaturedShouldRequireFavoriteCalibration();
527
617
  testPreflightRecommendShouldKeepFavoriteCalibrationOptional();