@reconcrap/boss-recommend-mcp 1.3.19 → 1.3.20
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 +2 -1
- package/config/screening-config.example.json +2 -1
- package/package.json +1 -1
- package/src/adapters.js +25 -0
- package/src/boss-chat.js +28 -1
- package/src/test-boss-chat.js +3 -3
- package/vendor/boss-chat-cli/src/runtime/interaction.js +1 -1
- package/vendor/boss-chat-cli/src/services/llm.js +3 -3
- package/vendor/boss-recommend-screen-cli/boss-recommend-screen-cli.cjs +11 -4
- package/vendor/boss-recommend-screen-cli/test-recoverable-resume-failures.cjs +5 -5
package/README.md
CHANGED
|
@@ -167,7 +167,8 @@ config/screening-config.example.json
|
|
|
167
167
|
- `openaiProject`
|
|
168
168
|
- `debugPort`
|
|
169
169
|
- `outputDir`
|
|
170
|
-
- `llmThinkingLevel`:默认 `
|
|
170
|
+
- `llmThinkingLevel`:默认 `low`。可设为 `off/minimal/low/medium/high/auto/current`,用于控制 OpenAI-compatible LLM 的 thinking/reasoning 强度。
|
|
171
|
+
- `humanRestEnabled`:默认 `false`。`false` 时 recommend-screen 随机休息/批次休息与 boss-chat 批次休息均为 `0ms`;`true` 时恢复随机休息节奏。
|
|
171
172
|
|
|
172
173
|
## 常用命令
|
|
173
174
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
"baseUrl": "https://api.openai.com/v1",
|
|
3
3
|
"apiKey": "replace-with-openai-api-key",
|
|
4
4
|
"model": "gpt-4.1-mini",
|
|
5
|
-
"llmThinkingLevel": "
|
|
5
|
+
"llmThinkingLevel": "low",
|
|
6
|
+
"humanRestEnabled": false,
|
|
6
7
|
"openaiOrganization": "optional-org-id",
|
|
7
8
|
"openaiProject": "optional-project-id"
|
|
8
9
|
}
|
package/package.json
CHANGED
package/src/adapters.js
CHANGED
|
@@ -121,6 +121,30 @@ function normalizeText(value) {
|
|
|
121
121
|
return String(value || "").replace(/\s+/g, " ").trim();
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
function parseBooleanValue(value) {
|
|
125
|
+
if (typeof value === "boolean") return value;
|
|
126
|
+
const normalized = normalizeText(value).toLowerCase();
|
|
127
|
+
if (!normalized) return null;
|
|
128
|
+
if (["1", "true", "yes", "y", "on", "是"].includes(normalized)) return true;
|
|
129
|
+
if (["0", "false", "no", "n", "off", "否"].includes(normalized)) return false;
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function resolveHumanRestEnabled(config = {}) {
|
|
134
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) return false;
|
|
135
|
+
const candidates = [
|
|
136
|
+
config.humanRestEnabled,
|
|
137
|
+
config.human_rest_enabled,
|
|
138
|
+
config.humanLikeRestEnabled,
|
|
139
|
+
config.human_like_rest_enabled
|
|
140
|
+
];
|
|
141
|
+
for (const candidate of candidates) {
|
|
142
|
+
const parsed = parseBooleanValue(candidate);
|
|
143
|
+
if (typeof parsed === "boolean") return parsed;
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
124
148
|
function serializeInputSummary(value) {
|
|
125
149
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
126
150
|
try {
|
|
@@ -2937,6 +2961,7 @@ export async function runRecommendScreenCli({
|
|
|
2937
2961
|
if (llmThinkingLevel) {
|
|
2938
2962
|
args.push("--thinking-level", llmThinkingLevel);
|
|
2939
2963
|
}
|
|
2964
|
+
args.push("--human-rest", String(resolveHumanRestEnabled(loaded.config)));
|
|
2940
2965
|
if (Number.isInteger(screenParams.target_count) && screenParams.target_count > 0) {
|
|
2941
2966
|
args.push("--targetCount", String(screenParams.target_count));
|
|
2942
2967
|
}
|
package/src/boss-chat.js
CHANGED
|
@@ -40,6 +40,30 @@ function parsePositiveInteger(value, fallback = null) {
|
|
|
40
40
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
function parseBooleanValue(value) {
|
|
44
|
+
if (typeof value === "boolean") return value;
|
|
45
|
+
const normalized = normalizeText(value).toLowerCase();
|
|
46
|
+
if (!normalized) return null;
|
|
47
|
+
if (["1", "true", "yes", "y", "on", "是"].includes(normalized)) return true;
|
|
48
|
+
if (["0", "false", "no", "n", "off", "否"].includes(normalized)) return false;
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function resolveHumanRestEnabled(config = {}) {
|
|
53
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) return false;
|
|
54
|
+
const candidates = [
|
|
55
|
+
config.humanRestEnabled,
|
|
56
|
+
config.human_rest_enabled,
|
|
57
|
+
config.humanLikeRestEnabled,
|
|
58
|
+
config.human_like_rest_enabled
|
|
59
|
+
];
|
|
60
|
+
for (const candidate of candidates) {
|
|
61
|
+
const parsed = parseBooleanValue(candidate);
|
|
62
|
+
if (typeof parsed === "boolean") return parsed;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
43
67
|
function isUnlimitedTargetCountToken(value) {
|
|
44
68
|
const token = normalizeText(value).toLowerCase();
|
|
45
69
|
if (!token) return false;
|
|
@@ -290,7 +314,8 @@ function resolveBossChatScreenConfig(workspaceRoot) {
|
|
|
290
314
|
apiKey: normalizeText(parsed.apiKey),
|
|
291
315
|
model: normalizeText(parsed.model),
|
|
292
316
|
llmThinkingLevel: resolveLlmThinkingLevel(parsed),
|
|
293
|
-
debugPort: parsePositiveInteger(parsed.debugPort, 9222)
|
|
317
|
+
debugPort: parsePositiveInteger(parsed.debugPort, 9222),
|
|
318
|
+
humanRestEnabled: resolveHumanRestEnabled(parsed)
|
|
294
319
|
},
|
|
295
320
|
config_path: configPath,
|
|
296
321
|
config_dir: path.dirname(configPath)
|
|
@@ -430,6 +455,8 @@ function buildBossChatCliArgs(command, input, resolvedConfig) {
|
|
|
430
455
|
}
|
|
431
456
|
if (typeof normalized.batchRestEnabled === "boolean") {
|
|
432
457
|
args.push("--batch-rest", String(normalized.batchRestEnabled));
|
|
458
|
+
} else if (typeof resolvedConfig?.humanRestEnabled === "boolean") {
|
|
459
|
+
args.push("--batch-rest", String(resolvedConfig.humanRestEnabled));
|
|
433
460
|
}
|
|
434
461
|
return args;
|
|
435
462
|
}
|
package/src/test-boss-chat.js
CHANGED
|
@@ -755,8 +755,8 @@ async function testBossChatLlmShouldApplyThinkingDefaultsAndOverrides() {
|
|
|
755
755
|
},
|
|
756
756
|
});
|
|
757
757
|
await volcClient.requestCompletions({ prompt: "prompt", evidenceCorpus: "resume" });
|
|
758
|
-
assert.deepEqual(volcCompletionPayload.thinking, { type: "
|
|
759
|
-
assert.equal(volcCompletionPayload.reasoning_effort, "
|
|
758
|
+
assert.deepEqual(volcCompletionPayload.thinking, { type: "enabled" });
|
|
759
|
+
assert.equal(volcCompletionPayload.reasoning_effort, "low");
|
|
760
760
|
|
|
761
761
|
let lowCompletionPayload = null;
|
|
762
762
|
const lowClient = new LlmClient({
|
|
@@ -787,7 +787,7 @@ async function testBossChatLlmShouldApplyThinkingDefaultsAndOverrides() {
|
|
|
787
787
|
});
|
|
788
788
|
await openaiClient.requestCompletions({ prompt: "prompt", evidenceCorpus: "resume" });
|
|
789
789
|
assert.equal(openaiCompletionPayload.thinking, undefined);
|
|
790
|
-
assert.equal(openaiCompletionPayload.reasoning_effort, "
|
|
790
|
+
assert.equal(openaiCompletionPayload.reasoning_effort, "low");
|
|
791
791
|
|
|
792
792
|
let responsesPayload = null;
|
|
793
793
|
const responsesClient = new LlmClient({
|
|
@@ -47,7 +47,7 @@ export class InteractionController {
|
|
|
47
47
|
return 0;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
const restMs =
|
|
50
|
+
const restMs = 4000 + Math.floor(Math.random() * 4000);
|
|
51
51
|
logger.log(`短暂休息 ${restMs}ms,保持处理节奏稳定...`);
|
|
52
52
|
await this.wait(restMs);
|
|
53
53
|
this.nextRestAt = processedCount + this.randomRestThreshold();
|
|
@@ -104,7 +104,7 @@ function resolveLlmThinkingLevel(config = {}, options = {}) {
|
|
|
104
104
|
normalizeLlmThinkingLevel(config.reasoningEffort) ||
|
|
105
105
|
normalizeLlmThinkingLevel(config.reasoning_effort) ||
|
|
106
106
|
getEnvLlmThinkingLevel() ||
|
|
107
|
-
'
|
|
107
|
+
'low'
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -118,7 +118,7 @@ function isVolcengineModel(baseUrl, model) {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
function applyChatCompletionThinking(payload, { baseUrl = '', model = '', thinkingLevel = '' } = {}) {
|
|
121
|
-
const level = normalizeLlmThinkingLevel(thinkingLevel) || '
|
|
121
|
+
const level = normalizeLlmThinkingLevel(thinkingLevel) || 'low';
|
|
122
122
|
if (isProviderDefaultThinkingLevel(level)) return payload;
|
|
123
123
|
const isVolc = isVolcengineModel(baseUrl, model);
|
|
124
124
|
if (isVolc) {
|
|
@@ -142,7 +142,7 @@ function applyChatCompletionThinking(payload, { baseUrl = '', model = '', thinki
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
function applyResponsesThinking(payload, { thinkingLevel = '' } = {}) {
|
|
145
|
-
const level = normalizeLlmThinkingLevel(thinkingLevel) || '
|
|
145
|
+
const level = normalizeLlmThinkingLevel(thinkingLevel) || 'low';
|
|
146
146
|
if (isProviderDefaultThinkingLevel(level) || level === 'auto') return payload;
|
|
147
147
|
payload.reasoning = {
|
|
148
148
|
...(payload.reasoning || {}),
|
|
@@ -1288,7 +1288,7 @@ function getEnvLlmThinkingLevel() {
|
|
|
1288
1288
|
}
|
|
1289
1289
|
|
|
1290
1290
|
function resolveLlmThinkingLevel(value) {
|
|
1291
|
-
return normalizeLlmThinkingLevel(value) || getEnvLlmThinkingLevel() || "
|
|
1291
|
+
return normalizeLlmThinkingLevel(value) || getEnvLlmThinkingLevel() || "low";
|
|
1292
1292
|
}
|
|
1293
1293
|
|
|
1294
1294
|
function isVolcengineModel(baseUrl, model) {
|
|
@@ -1339,6 +1339,7 @@ function parseArgs(argv) {
|
|
|
1339
1339
|
checkpointPath: null,
|
|
1340
1340
|
pauseControlPath: null,
|
|
1341
1341
|
resume: false,
|
|
1342
|
+
humanRestEnabled: false,
|
|
1342
1343
|
postAction: null,
|
|
1343
1344
|
postActionConfirmed: null,
|
|
1344
1345
|
help: false,
|
|
@@ -1353,6 +1354,7 @@ function parseArgs(argv) {
|
|
|
1353
1354
|
pageScope: false,
|
|
1354
1355
|
calibrationPath: false,
|
|
1355
1356
|
port: false,
|
|
1357
|
+
humanRest: false,
|
|
1356
1358
|
postAction: false,
|
|
1357
1359
|
postActionConfirmed: false
|
|
1358
1360
|
}
|
|
@@ -1421,6 +1423,11 @@ function parseArgs(argv) {
|
|
|
1421
1423
|
} else if (token === "--pause-control-path" && (inlineValue || next)) {
|
|
1422
1424
|
parsed.pauseControlPath = path.resolve(inlineValue || next);
|
|
1423
1425
|
if (!inlineValue) index += 1;
|
|
1426
|
+
} else if ((token === "--human-rest" || token === "--humanRest" || token === "--human_rest") && (inlineValue || next)) {
|
|
1427
|
+
const parsedBoolean = parseBoolean(inlineValue || next);
|
|
1428
|
+
parsed.humanRestEnabled = parsedBoolean === true;
|
|
1429
|
+
parsed.__provided.humanRest = parsedBoolean !== null;
|
|
1430
|
+
if (!inlineValue) index += 1;
|
|
1424
1431
|
} else if (token === "--resume") {
|
|
1425
1432
|
parsed.resume = true;
|
|
1426
1433
|
} else if ((token === "--post-action" || token === "--postAction") && (inlineValue || next)) {
|
|
@@ -5743,12 +5750,12 @@ class RecommendScreenCli {
|
|
|
5743
5750
|
async takeBreakIfNeeded() {
|
|
5744
5751
|
this.restCounter += 1;
|
|
5745
5752
|
if (Math.random() < 0.08) {
|
|
5746
|
-
const pauseMs = 0;
|
|
5753
|
+
const pauseMs = this.args.humanRestEnabled ? 3000 + Math.floor(Math.random() * 4000) : 0;
|
|
5747
5754
|
log(`[随机休息] 暂停 ${Math.round(pauseMs / 1000)} 秒`);
|
|
5748
5755
|
await sleep(pauseMs);
|
|
5749
5756
|
}
|
|
5750
5757
|
if (this.restCounter >= this.restThreshold) {
|
|
5751
|
-
const pauseMs = 0;
|
|
5758
|
+
const pauseMs = this.args.humanRestEnabled ? 15000 + Math.floor(Math.random() * 15000) : 0;
|
|
5752
5759
|
log(`[批次休息] 已连续处理 ${this.restCounter} 人,暂停 ${Math.round(pauseMs / 1000)} 秒`);
|
|
5753
5760
|
await sleep(pauseMs);
|
|
5754
5761
|
this.restCounter = 0;
|
|
@@ -6469,7 +6476,7 @@ async function main() {
|
|
|
6469
6476
|
console.log(JSON.stringify({
|
|
6470
6477
|
status: "COMPLETED",
|
|
6471
6478
|
result: {
|
|
6472
|
-
usage: "node boss-recommend-screen-cli.cjs --criteria \"有 MCP 开发经验\" --post-action <favorite|greet|none> --max-greet-count 10 --post-action-confirmed true --baseurl <url> --apikey <key> --model <model> --thinking-level off|low|medium|high|current --page-scope recommend|latest|featured --calibration <favorite-calibration.json> --port 9222 --output <csv-path> [--input-summary-json <json>] --checkpoint-path <checkpoint.json> --pause-control-path <pause-control.json> [--resume]"
|
|
6479
|
+
usage: "node boss-recommend-screen-cli.cjs --criteria \"有 MCP 开发经验\" --post-action <favorite|greet|none> --max-greet-count 10 --post-action-confirmed true --baseurl <url> --apikey <key> --model <model> --thinking-level off|low|medium|high|current --page-scope recommend|latest|featured --calibration <favorite-calibration.json> --port 9222 --human-rest <true|false> --output <csv-path> [--input-summary-json <json>] --checkpoint-path <checkpoint.json> --pause-control-path <pause-control.json> [--resume]"
|
|
6473
6480
|
}
|
|
6474
6481
|
}));
|
|
6475
6482
|
return;
|
|
@@ -1525,8 +1525,8 @@ async function testCallTextModelShouldFallbackToChunkModeOnContextLimit() {
|
|
|
1525
1525
|
}
|
|
1526
1526
|
}
|
|
1527
1527
|
|
|
1528
|
-
async function
|
|
1529
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-thinking-
|
|
1528
|
+
async function testTextModelShouldDefaultThinkingLowForVolcengine() {
|
|
1529
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-thinking-low-default-"));
|
|
1530
1530
|
const cli = new RecommendScreenCli(createArgs(tempDir));
|
|
1531
1531
|
cli.args.baseUrl = "https://ark.cn-beijing.volces.com/api/v3";
|
|
1532
1532
|
cli.args.model = "doubao-seed-2-0-mini-260215";
|
|
@@ -1552,8 +1552,8 @@ async function testTextModelShouldDefaultThinkingOffForVolcengine() {
|
|
|
1552
1552
|
};
|
|
1553
1553
|
try {
|
|
1554
1554
|
await cli.callTextModel("resume");
|
|
1555
|
-
assert.deepEqual(capturedPayload?.thinking, { type: "
|
|
1556
|
-
assert.equal(capturedPayload?.reasoning_effort, "
|
|
1555
|
+
assert.deepEqual(capturedPayload?.thinking, { type: "enabled" });
|
|
1556
|
+
assert.equal(capturedPayload?.reasoning_effort, "low");
|
|
1557
1557
|
} finally {
|
|
1558
1558
|
global.fetch = originalFetch;
|
|
1559
1559
|
}
|
|
@@ -1812,7 +1812,7 @@ async function main() {
|
|
|
1812
1812
|
testParseArgsShouldSupportInputSummaryJson();
|
|
1813
1813
|
await testCallTextModelShouldNotTruncateLongResume();
|
|
1814
1814
|
await testCallTextModelShouldFallbackToChunkModeOnContextLimit();
|
|
1815
|
-
await
|
|
1815
|
+
await testTextModelShouldDefaultThinkingLowForVolcengine();
|
|
1816
1816
|
await testTextModelShouldSupportLowThinkingForVolcengine();
|
|
1817
1817
|
await testPrepareVisionImageSegmentsShouldSplitLongImage();
|
|
1818
1818
|
await testVisionEvidenceGateShouldDemoteImageFallbackWithoutEvidence();
|