@reconcrap/boss-recommend-mcp 1.3.16 → 1.3.17
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 +1 -0
- package/package.json +1 -1
- package/src/adapters.js +28 -9
- package/src/boss-chat.js +22 -0
- package/src/cli.js +6 -1
- package/src/test-boss-chat.js +89 -0
- package/vendor/boss-chat-cli/src/cli.js +10 -0
- package/vendor/boss-chat-cli/src/mcp/server.js +1 -1
- package/vendor/boss-chat-cli/src/mcp/tool-runtime.js +1 -1
- package/vendor/boss-chat-cli/src/services/llm.js +119 -24
- package/vendor/boss-chat-cli/src/services/profile-store.js +5 -0
- package/vendor/boss-recommend-screen-cli/boss-recommend-screen-cli.cjs +400 -69
- package/vendor/boss-recommend-screen-cli/scripts/capture-full-resume-canvas.cjs +109 -41
- package/vendor/boss-recommend-screen-cli/test-recoverable-resume-failures.cjs +204 -0
|
@@ -26,7 +26,21 @@ const CSV_HEADER = [
|
|
|
26
26
|
"证据门控降级",
|
|
27
27
|
"错误码",
|
|
28
28
|
"错误信息",
|
|
29
|
-
"候选人ID"
|
|
29
|
+
"候选人ID",
|
|
30
|
+
"总耗时ms",
|
|
31
|
+
"候选卡片读取ms",
|
|
32
|
+
"点击候选人ms",
|
|
33
|
+
"详情打开ms",
|
|
34
|
+
"network简历等待ms",
|
|
35
|
+
"文本模型ms",
|
|
36
|
+
"截图获取ms",
|
|
37
|
+
"视觉模型ms",
|
|
38
|
+
"late network retry ms",
|
|
39
|
+
"DOM fallback ms",
|
|
40
|
+
"通过后动作ms",
|
|
41
|
+
"关闭详情ms",
|
|
42
|
+
"休息ms",
|
|
43
|
+
"checkpoint保存ms"
|
|
30
44
|
].join(",");
|
|
31
45
|
const INPUT_SUMMARY_HEADER = ["运行输入字段", "运行输入值"].join(",");
|
|
32
46
|
const RESUME_CAPTURE_WAIT_MS = 60000;
|
|
@@ -34,6 +48,8 @@ const RESUME_CAPTURE_MAX_ATTEMPTS = 4;
|
|
|
34
48
|
const RESUME_CAPTURE_RETRY_DELAY_MS = 1200;
|
|
35
49
|
const NETWORK_RESUME_WAIT_MS = 4200;
|
|
36
50
|
const NETWORK_RESUME_RETRY_WAIT_MS = 2000;
|
|
51
|
+
const NETWORK_RESUME_IMAGE_MODE_GRACE_MS = 1000;
|
|
52
|
+
const NETWORK_RESUME_LATE_RETRY_MS = 3000;
|
|
37
53
|
const MAX_CONSECUTIVE_RESUME_CAPTURE_FAILURES = 10;
|
|
38
54
|
const DEFAULT_VISION_MAX_IMAGE_PIXELS = 36000000;
|
|
39
55
|
const DEFAULT_VISION_RETRY_MAX_IMAGE_PIXELS = 30000000;
|
|
@@ -962,12 +978,69 @@ function shouldBringChromeToFront() {
|
|
|
962
978
|
}
|
|
963
979
|
|
|
964
980
|
const SHOULD_BRING_TO_FRONT = shouldBringChromeToFront();
|
|
981
|
+
const LLM_THINKING_ENV_KEYS = [
|
|
982
|
+
"BOSS_RECOMMEND_LLM_THINKING_LEVEL",
|
|
983
|
+
"BOSS_LLM_THINKING_LEVEL",
|
|
984
|
+
"LLM_THINKING_LEVEL"
|
|
985
|
+
];
|
|
986
|
+
|
|
987
|
+
function normalizeLlmThinkingLevel(value) {
|
|
988
|
+
const normalized = normalizeText(value).toLowerCase().replace(/[_\s]+/g, "-");
|
|
989
|
+
if (!normalized) return "";
|
|
990
|
+
if (["off", "disabled", "disable", "minimal", "none", "false", "0"].includes(normalized)) return "off";
|
|
991
|
+
if (["low", "medium", "high", "auto", "current", "default", "provider-default", "unchanged", "inherit"].includes(normalized)) {
|
|
992
|
+
return normalized;
|
|
993
|
+
}
|
|
994
|
+
return "";
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function getEnvLlmThinkingLevel() {
|
|
998
|
+
for (const key of LLM_THINKING_ENV_KEYS) {
|
|
999
|
+
const normalized = normalizeLlmThinkingLevel(process.env[key]);
|
|
1000
|
+
if (normalized) return normalized;
|
|
1001
|
+
}
|
|
1002
|
+
return "";
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
function resolveLlmThinkingLevel(value) {
|
|
1006
|
+
return normalizeLlmThinkingLevel(value) || getEnvLlmThinkingLevel() || "off";
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
function isVolcengineModel(baseUrl, model) {
|
|
1010
|
+
const combined = `${baseUrl || ""} ${model || ""}`;
|
|
1011
|
+
return /volces\.com|volcengine|ark\.cn-|doubao|seed/i.test(combined);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
function applyChatCompletionThinking(payload, { baseUrl = "", model = "", thinkingLevel = "" } = {}) {
|
|
1015
|
+
const level = resolveLlmThinkingLevel(thinkingLevel);
|
|
1016
|
+
if (["current", "default", "provider-default", "unchanged", "inherit"].includes(level)) return payload;
|
|
1017
|
+
const isVolc = isVolcengineModel(baseUrl, model);
|
|
1018
|
+
if (isVolc) {
|
|
1019
|
+
if (level === "auto") {
|
|
1020
|
+
payload.thinking = { type: "auto" };
|
|
1021
|
+
return payload;
|
|
1022
|
+
}
|
|
1023
|
+
if (level === "off") {
|
|
1024
|
+
payload.thinking = { type: "disabled" };
|
|
1025
|
+
payload.reasoning_effort = "minimal";
|
|
1026
|
+
return payload;
|
|
1027
|
+
}
|
|
1028
|
+
payload.thinking = { type: "enabled" };
|
|
1029
|
+
payload.reasoning_effort = level;
|
|
1030
|
+
return payload;
|
|
1031
|
+
}
|
|
1032
|
+
if (level !== "auto") {
|
|
1033
|
+
payload.reasoning_effort = level === "off" ? "minimal" : level;
|
|
1034
|
+
}
|
|
1035
|
+
return payload;
|
|
1036
|
+
}
|
|
965
1037
|
|
|
966
1038
|
function parseArgs(argv) {
|
|
967
1039
|
const parsed = {
|
|
968
1040
|
baseUrl: null,
|
|
969
1041
|
apiKey: null,
|
|
970
1042
|
model: null,
|
|
1043
|
+
thinkingLevel: null,
|
|
971
1044
|
openaiOrganization: null,
|
|
972
1045
|
openaiProject: null,
|
|
973
1046
|
criteria: null,
|
|
@@ -988,6 +1061,7 @@ function parseArgs(argv) {
|
|
|
988
1061
|
baseUrl: false,
|
|
989
1062
|
apiKey: false,
|
|
990
1063
|
model: false,
|
|
1064
|
+
thinkingLevel: false,
|
|
991
1065
|
criteria: false,
|
|
992
1066
|
targetCount: false,
|
|
993
1067
|
maxGreetCount: false,
|
|
@@ -1016,6 +1090,10 @@ function parseArgs(argv) {
|
|
|
1016
1090
|
parsed.model = inlineValue || next;
|
|
1017
1091
|
parsed.__provided.model = true;
|
|
1018
1092
|
if (!inlineValue) index += 1;
|
|
1093
|
+
} else if ((token === "--thinking-level" || token === "--thinkingLevel" || token === "--llm-thinking-level" || token === "--reasoning-effort") && (inlineValue || next)) {
|
|
1094
|
+
parsed.thinkingLevel = inlineValue || next;
|
|
1095
|
+
parsed.__provided.thinkingLevel = true;
|
|
1096
|
+
if (!inlineValue) index += 1;
|
|
1019
1097
|
} else if (token === "--openai-organization" && (inlineValue || next)) {
|
|
1020
1098
|
parsed.openaiOrganization = inlineValue || next;
|
|
1021
1099
|
if (!inlineValue) index += 1;
|
|
@@ -1208,6 +1286,30 @@ function csvEscape(value) {
|
|
|
1208
1286
|
return `"${String(value || "").replace(/"/g, '""')}"`;
|
|
1209
1287
|
}
|
|
1210
1288
|
|
|
1289
|
+
function normalizeTimingMs(value) {
|
|
1290
|
+
const parsed = Number(value);
|
|
1291
|
+
if (!Number.isFinite(parsed) || parsed < 0) return null;
|
|
1292
|
+
return Math.round(parsed);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
function sanitizeTimingBreakdown(value) {
|
|
1296
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1297
|
+
const result = {};
|
|
1298
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
1299
|
+
const normalizedKey = normalizeText(key);
|
|
1300
|
+
if (!normalizedKey) continue;
|
|
1301
|
+
const normalizedValue = normalizeTimingMs(raw);
|
|
1302
|
+
if (normalizedValue === null) continue;
|
|
1303
|
+
result[normalizedKey] = normalizedValue;
|
|
1304
|
+
}
|
|
1305
|
+
return result;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
function getTimingMs(timing, key) {
|
|
1309
|
+
const normalized = normalizeTimingMs(timing?.[key]);
|
|
1310
|
+
return normalized === null ? "" : normalized;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1211
1313
|
function stringifyInputSummaryValue(value) {
|
|
1212
1314
|
if (value === null) return "null";
|
|
1213
1315
|
if (value === undefined) return "";
|
|
@@ -2844,6 +2946,8 @@ class RecommendScreenCli {
|
|
|
2844
2946
|
dom_fallback: 0,
|
|
2845
2947
|
image_fallback: 0
|
|
2846
2948
|
};
|
|
2949
|
+
this.resumeAcquisitionMode = "unknown";
|
|
2950
|
+
this.resumeAcquisitionModeReason = "";
|
|
2847
2951
|
this.lastActiveTabStatus = PAGE_SCOPE_TAB_STATUS[this.args.pageScope] || null;
|
|
2848
2952
|
this.featuredCalibration = this.args.pageScope === "featured"
|
|
2849
2953
|
? loadCalibrationPosition(this.args.calibrationPath)
|
|
@@ -2890,6 +2994,8 @@ class RecommendScreenCli {
|
|
|
2890
2994
|
skipped_count: this.skippedCount,
|
|
2891
2995
|
greet_count: this.greetCount,
|
|
2892
2996
|
greet_limit_fallback_count: this.greetLimitFallbackCount,
|
|
2997
|
+
resume_acquisition_mode: this.resumeAcquisitionMode,
|
|
2998
|
+
resume_acquisition_mode_reason: this.resumeAcquisitionModeReason,
|
|
2893
2999
|
processed_keys: Array.from(this.processedKeys),
|
|
2894
3000
|
passed_candidates: this.passedCandidates.map((item) => ({
|
|
2895
3001
|
name: item?.name || "",
|
|
@@ -2926,7 +3032,8 @@ class RecommendScreenCli {
|
|
|
2926
3032
|
error_code: item?.error_code || "",
|
|
2927
3033
|
error_message: item?.error_message || "",
|
|
2928
3034
|
chunk_index: Number.isFinite(Number(item?.chunk_index)) ? Number(item.chunk_index) : null,
|
|
2929
|
-
chunk_total: Number.isFinite(Number(item?.chunk_total)) ? Number(item.chunk_total) : null
|
|
3035
|
+
chunk_total: Number.isFinite(Number(item?.chunk_total)) ? Number(item.chunk_total) : null,
|
|
3036
|
+
timing_ms: sanitizeTimingBreakdown(item?.timing_ms)
|
|
2930
3037
|
})),
|
|
2931
3038
|
input_summary: sanitizeInputSummary(this.inputSummary)
|
|
2932
3039
|
};
|
|
@@ -2942,6 +3049,7 @@ class RecommendScreenCli {
|
|
|
2942
3049
|
checkpoint_path: this.checkpointPath,
|
|
2943
3050
|
selected_page: this.args.pageScope || "recommend",
|
|
2944
3051
|
active_tab_status: this.lastActiveTabStatus || PAGE_SCOPE_TAB_STATUS[this.args.pageScope] || null,
|
|
3052
|
+
resume_acquisition_mode: this.resumeAcquisitionMode,
|
|
2945
3053
|
resume_source: this.resumeSourceStats.image_fallback > 0
|
|
2946
3054
|
? "image_fallback"
|
|
2947
3055
|
: this.resumeSourceStats.dom_fallback > 0
|
|
@@ -3092,7 +3200,8 @@ class RecommendScreenCli {
|
|
|
3092
3200
|
error_code: normalizeText(entry?.error_code || "") || "",
|
|
3093
3201
|
error_message: normalizeText(entry?.error_message || "") || "",
|
|
3094
3202
|
chunk_index: Number.isFinite(Number(entry?.chunk_index)) ? Number(entry.chunk_index) : null,
|
|
3095
|
-
chunk_total: Number.isFinite(Number(entry?.chunk_total)) ? Number(entry.chunk_total) : null
|
|
3203
|
+
chunk_total: Number.isFinite(Number(entry?.chunk_total)) ? Number(entry.chunk_total) : null,
|
|
3204
|
+
timing_ms: sanitizeTimingBreakdown(entry?.timing_ms)
|
|
3096
3205
|
};
|
|
3097
3206
|
this.candidateAudits.push(normalized);
|
|
3098
3207
|
const maxItems = parsePositiveInteger(process.env.BOSS_RECOMMEND_MAX_CANDIDATE_AUDITS);
|
|
@@ -3101,6 +3210,22 @@ class RecommendScreenCli {
|
|
|
3101
3210
|
}
|
|
3102
3211
|
}
|
|
3103
3212
|
|
|
3213
|
+
updateCandidateAuditTiming(candidateKey, timing = {}) {
|
|
3214
|
+
const normalizedKey = normalizeText(candidateKey || "");
|
|
3215
|
+
if (!normalizedKey) return;
|
|
3216
|
+
const timingMs = sanitizeTimingBreakdown(timing);
|
|
3217
|
+
for (let index = this.candidateAudits.length - 1; index >= 0; index -= 1) {
|
|
3218
|
+
const audit = this.candidateAudits[index];
|
|
3219
|
+
if (
|
|
3220
|
+
normalizeText(audit?.candidate_key || "") === normalizedKey
|
|
3221
|
+
|| normalizeText(audit?.geek_id || "") === normalizedKey
|
|
3222
|
+
) {
|
|
3223
|
+
audit.timing_ms = timingMs;
|
|
3224
|
+
return;
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
|
|
3104
3229
|
logResumeNetworkMissDiagnostics(candidate, options = {}) {
|
|
3105
3230
|
const candidateKey = normalizeText(candidate?.key || candidate?.geek_id || "");
|
|
3106
3231
|
const candidateName = normalizeText(candidate?.name || "");
|
|
@@ -3240,6 +3365,60 @@ class RecommendScreenCli {
|
|
|
3240
3365
|
return null;
|
|
3241
3366
|
}
|
|
3242
3367
|
|
|
3368
|
+
setResumeAcquisitionMode(mode, reason = "") {
|
|
3369
|
+
if (!["unknown", "network", "image"].includes(mode)) return;
|
|
3370
|
+
if (this.resumeAcquisitionMode === mode) return;
|
|
3371
|
+
this.resumeAcquisitionMode = mode;
|
|
3372
|
+
this.resumeAcquisitionModeReason = normalizeText(reason || "");
|
|
3373
|
+
log(`[简历获取模式] mode=${mode}${this.resumeAcquisitionModeReason ? ` reason=${this.resumeAcquisitionModeReason}` : ""}`);
|
|
3374
|
+
}
|
|
3375
|
+
|
|
3376
|
+
async waitForResumeNetworkByMode(candidate, options = {}) {
|
|
3377
|
+
const minTs = Number.isFinite(Number(options?.minTs)) ? Number(options.minTs) : 0;
|
|
3378
|
+
const mode = this.resumeAcquisitionMode || "unknown";
|
|
3379
|
+
const firstWaitMs = mode === "image" ? NETWORK_RESUME_IMAGE_MODE_GRACE_MS : NETWORK_RESUME_WAIT_MS;
|
|
3380
|
+
const waitStartedAt = Date.now();
|
|
3381
|
+
let networkCandidateInfo = await this.waitForNetworkResumeCandidateInfo(candidate, firstWaitMs, { minTs });
|
|
3382
|
+
if (normalizeText(networkCandidateInfo?.resumeText)) {
|
|
3383
|
+
this.setResumeAcquisitionMode("network", "network_resume_hit");
|
|
3384
|
+
return networkCandidateInfo;
|
|
3385
|
+
}
|
|
3386
|
+
if (typeof this.logResumeNetworkMissDiagnostics === "function") {
|
|
3387
|
+
this.logResumeNetworkMissDiagnostics(candidate, {
|
|
3388
|
+
timeoutMs: firstWaitMs,
|
|
3389
|
+
waitStartedAt
|
|
3390
|
+
});
|
|
3391
|
+
}
|
|
3392
|
+
if (mode === "image") {
|
|
3393
|
+
return null;
|
|
3394
|
+
}
|
|
3395
|
+
await sleep(NETWORK_RESUME_RETRY_WAIT_MS);
|
|
3396
|
+
networkCandidateInfo = await this.waitForNetworkResumeCandidateInfo(
|
|
3397
|
+
candidate,
|
|
3398
|
+
NETWORK_RESUME_RETRY_WAIT_MS,
|
|
3399
|
+
{ minTs }
|
|
3400
|
+
);
|
|
3401
|
+
if (normalizeText(networkCandidateInfo?.resumeText)) {
|
|
3402
|
+
this.setResumeAcquisitionMode("network", "network_resume_retry_hit");
|
|
3403
|
+
return networkCandidateInfo;
|
|
3404
|
+
}
|
|
3405
|
+
return null;
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3408
|
+
async waitForLateNetworkResumeCandidateInfo(candidate, options = {}) {
|
|
3409
|
+
const minTs = Number.isFinite(Number(options?.minTs)) ? Number(options.minTs) : 0;
|
|
3410
|
+
const networkCandidateInfo = await this.waitForNetworkResumeCandidateInfo(
|
|
3411
|
+
candidate,
|
|
3412
|
+
NETWORK_RESUME_LATE_RETRY_MS,
|
|
3413
|
+
{ minTs }
|
|
3414
|
+
);
|
|
3415
|
+
if (normalizeText(networkCandidateInfo?.resumeText)) {
|
|
3416
|
+
this.setResumeAcquisitionMode("network", "late_network_resume_hit");
|
|
3417
|
+
return networkCandidateInfo;
|
|
3418
|
+
}
|
|
3419
|
+
return null;
|
|
3420
|
+
}
|
|
3421
|
+
|
|
3243
3422
|
async extractResumeTextFromDom(candidate) {
|
|
3244
3423
|
const candidateKey = normalizeText(candidate?.key || candidate?.geek_id || "");
|
|
3245
3424
|
const candidateLabel = normalizeText(candidate?.name || candidateKey || "unknown");
|
|
@@ -3637,7 +3816,8 @@ class RecommendScreenCli {
|
|
|
3637
3816
|
error_code: normalizeText(item?.error_code || "") || "",
|
|
3638
3817
|
error_message: normalizeText(item?.error_message || "") || "",
|
|
3639
3818
|
chunk_index: Number.isFinite(Number(item?.chunk_index)) ? Number(item.chunk_index) : null,
|
|
3640
|
-
chunk_total: Number.isFinite(Number(item?.chunk_total)) ? Number(item.chunk_total) : null
|
|
3819
|
+
chunk_total: Number.isFinite(Number(item?.chunk_total)) ? Number(item.chunk_total) : null,
|
|
3820
|
+
timing_ms: sanitizeTimingBreakdown(item?.timing_ms)
|
|
3641
3821
|
}))
|
|
3642
3822
|
: [];
|
|
3643
3823
|
if (!this.inputSummary) {
|
|
@@ -3665,6 +3845,17 @@ class RecommendScreenCli {
|
|
|
3665
3845
|
this.resumeSourceStats.image_fallback = 1;
|
|
3666
3846
|
}
|
|
3667
3847
|
}
|
|
3848
|
+
const checkpointMode = normalizeText(parsed.resume_acquisition_mode || "").toLowerCase();
|
|
3849
|
+
if (["network", "image"].includes(checkpointMode)) {
|
|
3850
|
+
this.resumeAcquisitionMode = checkpointMode;
|
|
3851
|
+
this.resumeAcquisitionModeReason = normalizeText(parsed.resume_acquisition_mode_reason || "checkpoint");
|
|
3852
|
+
} else if (this.resumeSourceStats.network > 0) {
|
|
3853
|
+
this.resumeAcquisitionMode = "network";
|
|
3854
|
+
this.resumeAcquisitionModeReason = "checkpoint_source_stats";
|
|
3855
|
+
} else if (this.resumeSourceStats.image_fallback > 0) {
|
|
3856
|
+
this.resumeAcquisitionMode = "image";
|
|
3857
|
+
this.resumeAcquisitionModeReason = "checkpoint_source_stats";
|
|
3858
|
+
}
|
|
3668
3859
|
|
|
3669
3860
|
return true;
|
|
3670
3861
|
}
|
|
@@ -4191,7 +4382,8 @@ class RecommendScreenCli {
|
|
|
4191
4382
|
outPrefix,
|
|
4192
4383
|
targetPattern: RECOMMEND_URL_FRAGMENT,
|
|
4193
4384
|
waitResumeMs: RESUME_CAPTURE_WAIT_MS,
|
|
4194
|
-
scrollSettleMs: 500
|
|
4385
|
+
scrollSettleMs: 500,
|
|
4386
|
+
stitchFullImage: false
|
|
4195
4387
|
});
|
|
4196
4388
|
} catch (error) {
|
|
4197
4389
|
lastError = error;
|
|
@@ -4218,7 +4410,7 @@ class RecommendScreenCli {
|
|
|
4218
4410
|
DEFAULT_VISION_MAX_IMAGE_PIXELS
|
|
4219
4411
|
);
|
|
4220
4412
|
const retryLimit = resolveVisionRetryPixelLimit(primaryLimit);
|
|
4221
|
-
const preparedPrimary = await this.
|
|
4413
|
+
const preparedPrimary = await this.prepareVisionInputsForModel(imagePath, primaryLimit, "primary");
|
|
4222
4414
|
try {
|
|
4223
4415
|
const primaryResult = await this.requestVisionModel(preparedPrimary.imagePaths);
|
|
4224
4416
|
return this.applyVisionEvidenceGate(primaryResult);
|
|
@@ -4233,7 +4425,7 @@ class RecommendScreenCli {
|
|
|
4233
4425
|
`segments=${preparedPrimary.imagePaths?.length || 1}`
|
|
4234
4426
|
);
|
|
4235
4427
|
}
|
|
4236
|
-
const preparedRetry = await this.
|
|
4428
|
+
const preparedRetry = await this.prepareVisionInputsForModel(imagePath, retryLimit, "retry");
|
|
4237
4429
|
try {
|
|
4238
4430
|
const retryResult = await this.requestVisionModel(preparedRetry.imagePaths);
|
|
4239
4431
|
return this.applyVisionEvidenceGate(retryResult);
|
|
@@ -4253,6 +4445,37 @@ class RecommendScreenCli {
|
|
|
4253
4445
|
}
|
|
4254
4446
|
}
|
|
4255
4447
|
|
|
4448
|
+
async prepareVisionInputsForModel(imageInput, maxPixels, attemptTag = "primary") {
|
|
4449
|
+
const sourcePaths = Array.isArray(imageInput) ? imageInput.filter(Boolean) : [imageInput].filter(Boolean);
|
|
4450
|
+
if (sourcePaths.length <= 0) {
|
|
4451
|
+
return {
|
|
4452
|
+
imagePaths: [],
|
|
4453
|
+
source: "empty",
|
|
4454
|
+
sourcePixels: null,
|
|
4455
|
+
currentPixels: null
|
|
4456
|
+
};
|
|
4457
|
+
}
|
|
4458
|
+
const preparedItems = [];
|
|
4459
|
+
for (let index = 0; index < sourcePaths.length; index += 1) {
|
|
4460
|
+
const prepared = await this.prepareVisionImageSegmentsForModel(
|
|
4461
|
+
sourcePaths[index],
|
|
4462
|
+
maxPixels,
|
|
4463
|
+
`${attemptTag}.input${String(index + 1).padStart(3, "0")}`
|
|
4464
|
+
);
|
|
4465
|
+
preparedItems.push(prepared);
|
|
4466
|
+
}
|
|
4467
|
+
return {
|
|
4468
|
+
imagePaths: preparedItems.flatMap((item) => item.imagePaths || []),
|
|
4469
|
+
source: sourcePaths.length > 1 ? "ordered_chunks" : (preparedItems[0]?.source || "single"),
|
|
4470
|
+
sourcePixels: preparedItems.reduce((acc, item) => (
|
|
4471
|
+
Number.isFinite(Number(item?.sourcePixels)) ? acc + Number(item.sourcePixels) : acc
|
|
4472
|
+
), 0) || null,
|
|
4473
|
+
currentPixels: preparedItems.reduce((acc, item) => (
|
|
4474
|
+
Number.isFinite(Number(item?.currentPixels)) ? acc + Number(item.currentPixels) : acc
|
|
4475
|
+
), 0) || null
|
|
4476
|
+
};
|
|
4477
|
+
}
|
|
4478
|
+
|
|
4256
4479
|
applyVisionEvidenceGate(result) {
|
|
4257
4480
|
const parsed = result && typeof result === "object" ? result : {};
|
|
4258
4481
|
const rawPassed = parsed?.rawPassed === true || parsed?.passed === true;
|
|
@@ -4474,6 +4697,7 @@ class RecommendScreenCli {
|
|
|
4474
4697
|
"请根据以下标准判断候选人是否通过筛选。\n\n" +
|
|
4475
4698
|
`筛选标准:\n${this.args.criteria}\n\n` +
|
|
4476
4699
|
"你将收到候选人完整简历的一个或多个顺序分段图片。必须完整阅读全部分段后再判断," +
|
|
4700
|
+
"不能只根据前几段下结论;后续分段中的教育、项目、经历或否定信息必须纳入最终判断。" +
|
|
4477
4701
|
"严禁编造任何不存在的经历、项目、学校、公司或时间线;证据不足时必须判定为不通过。\n\n" +
|
|
4478
4702
|
"要求:\n" +
|
|
4479
4703
|
"1) reason 必须写出可审计的判定依据,至少包含 2 条与筛选标准直接相关的事实。\n" +
|
|
@@ -4518,6 +4742,11 @@ class RecommendScreenCli {
|
|
|
4518
4742
|
}
|
|
4519
4743
|
]
|
|
4520
4744
|
};
|
|
4745
|
+
applyChatCompletionThinking(payload, {
|
|
4746
|
+
baseUrl,
|
|
4747
|
+
model: this.args.model,
|
|
4748
|
+
thinkingLevel: this.args.thinkingLevel
|
|
4749
|
+
});
|
|
4521
4750
|
const headers = {
|
|
4522
4751
|
"Content-Type": "application/json",
|
|
4523
4752
|
Authorization: `Bearer ${this.args.apiKey}`
|
|
@@ -4665,6 +4894,11 @@ class RecommendScreenCli {
|
|
|
4665
4894
|
}
|
|
4666
4895
|
]
|
|
4667
4896
|
};
|
|
4897
|
+
applyChatCompletionThinking(payload, {
|
|
4898
|
+
baseUrl,
|
|
4899
|
+
model: this.args.model,
|
|
4900
|
+
thinkingLevel: this.args.thinkingLevel
|
|
4901
|
+
});
|
|
4668
4902
|
const headers = {
|
|
4669
4903
|
"Content-Type": "application/json",
|
|
4670
4904
|
Authorization: `Bearer ${this.args.apiKey}`
|
|
@@ -5044,6 +5278,7 @@ class RecommendScreenCli {
|
|
|
5044
5278
|
const finalPassed = audit?.final_passed === true || normalizeText(audit?.outcome || "") === "passed";
|
|
5045
5279
|
const screeningReason = normalizeText(audit?.screening_reason || passedItem?.reason || "");
|
|
5046
5280
|
const passReason = finalPassed ? screeningReason : "";
|
|
5281
|
+
const timing = sanitizeTimingBreakdown(audit?.timing_ms);
|
|
5047
5282
|
lines.push([
|
|
5048
5283
|
csvEscape(audit?.candidate_name || passedItem?.name || ""),
|
|
5049
5284
|
csvEscape(audit?.school || passedItem?.school || ""),
|
|
@@ -5062,7 +5297,21 @@ class RecommendScreenCli {
|
|
|
5062
5297
|
csvEscape(audit?.evidence_gate_demoted === true ? "true" : "false"),
|
|
5063
5298
|
csvEscape(audit?.error_code || ""),
|
|
5064
5299
|
csvEscape(audit?.error_message || ""),
|
|
5065
|
-
csvEscape(auditGeekId || passedItem?.geekId || "")
|
|
5300
|
+
csvEscape(auditGeekId || passedItem?.geekId || ""),
|
|
5301
|
+
csvEscape(getTimingMs(timing, "total_ms")),
|
|
5302
|
+
csvEscape(getTimingMs(timing, "card_profile_ms")),
|
|
5303
|
+
csvEscape(getTimingMs(timing, "click_candidate_ms")),
|
|
5304
|
+
csvEscape(getTimingMs(timing, "detail_open_ms")),
|
|
5305
|
+
csvEscape(getTimingMs(timing, "network_resume_wait_ms")),
|
|
5306
|
+
csvEscape(getTimingMs(timing, "text_model_ms")),
|
|
5307
|
+
csvEscape(getTimingMs(timing, "image_capture_ms")),
|
|
5308
|
+
csvEscape(getTimingMs(timing, "vision_model_ms")),
|
|
5309
|
+
csvEscape(getTimingMs(timing, "late_network_retry_ms")),
|
|
5310
|
+
csvEscape(getTimingMs(timing, "dom_fallback_ms")),
|
|
5311
|
+
csvEscape(getTimingMs(timing, "post_action_ms")),
|
|
5312
|
+
csvEscape(getTimingMs(timing, "close_detail_ms")),
|
|
5313
|
+
csvEscape(getTimingMs(timing, "rest_ms")),
|
|
5314
|
+
csvEscape(getTimingMs(timing, "checkpoint_save_ms"))
|
|
5066
5315
|
].join(","));
|
|
5067
5316
|
}
|
|
5068
5317
|
fs.mkdirSync(path.dirname(this.args.output), { recursive: true });
|
|
@@ -5218,6 +5467,29 @@ class RecommendScreenCli {
|
|
|
5218
5467
|
this.scrollRetryCount = 0;
|
|
5219
5468
|
this.processedCount += 1;
|
|
5220
5469
|
log(`处理第 ${this.processedCount} 位候选人: ${nextCandidate.name || nextCandidate.geek_id}`);
|
|
5470
|
+
const candidateStartedAt = Date.now();
|
|
5471
|
+
const candidateTiming = {};
|
|
5472
|
+
const candidateKeyForTiming = nextCandidate.key || nextCandidate.geek_id || "";
|
|
5473
|
+
const addCandidateTiming = (key, startedAt) => {
|
|
5474
|
+
const elapsed = Math.max(0, Date.now() - startedAt);
|
|
5475
|
+
candidateTiming[key] = Math.round((Number(candidateTiming[key]) || 0) + elapsed);
|
|
5476
|
+
};
|
|
5477
|
+
const timeCandidateStage = async (key, fn) => {
|
|
5478
|
+
const startedAt = Date.now();
|
|
5479
|
+
try {
|
|
5480
|
+
return await fn();
|
|
5481
|
+
} finally {
|
|
5482
|
+
addCandidateTiming(key, startedAt);
|
|
5483
|
+
}
|
|
5484
|
+
};
|
|
5485
|
+
const timeCandidateStageSync = (key, fn) => {
|
|
5486
|
+
const startedAt = Date.now();
|
|
5487
|
+
try {
|
|
5488
|
+
return fn();
|
|
5489
|
+
} finally {
|
|
5490
|
+
addCandidateTiming(key, startedAt);
|
|
5491
|
+
}
|
|
5492
|
+
};
|
|
5221
5493
|
let shouldMarkProcessed = true;
|
|
5222
5494
|
let resumeSource = "";
|
|
5223
5495
|
let resumeTextLength = null;
|
|
@@ -5235,7 +5507,10 @@ class RecommendScreenCli {
|
|
|
5235
5507
|
|
|
5236
5508
|
try {
|
|
5237
5509
|
this.currentCandidateKey = nextCandidate.key || nextCandidate.geek_id || null;
|
|
5238
|
-
const cardProfile = await
|
|
5510
|
+
const cardProfile = await timeCandidateStage(
|
|
5511
|
+
"card_profile_ms",
|
|
5512
|
+
() => this.extractCandidateProfileFromCard(nextCandidate)
|
|
5513
|
+
);
|
|
5239
5514
|
candidateProfile = mergeCandidateProfiles(
|
|
5240
5515
|
cardProfile || null,
|
|
5241
5516
|
{
|
|
@@ -5247,38 +5522,26 @@ class RecommendScreenCli {
|
|
|
5247
5522
|
}
|
|
5248
5523
|
);
|
|
5249
5524
|
const candidateCaptureStartedAt = Date.now();
|
|
5250
|
-
await this.clickCandidate(nextCandidate);
|
|
5251
|
-
const detailOpen = await this.ensureDetailOpen();
|
|
5525
|
+
await timeCandidateStage("click_candidate_ms", () => this.clickCandidate(nextCandidate));
|
|
5526
|
+
const detailOpen = await timeCandidateStage("detail_open_ms", () => this.ensureDetailOpen());
|
|
5252
5527
|
if (!detailOpen) {
|
|
5253
5528
|
throw this.buildError("DETAIL_OPEN_FAILED", "详情页打开超时");
|
|
5254
5529
|
}
|
|
5255
5530
|
|
|
5256
5531
|
let capture = null;
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5532
|
+
let networkCandidateInfo = await timeCandidateStage(
|
|
5533
|
+
"network_resume_wait_ms",
|
|
5534
|
+
() => this.waitForResumeNetworkByMode(nextCandidate, {
|
|
5535
|
+
minTs: candidateCaptureStartedAt
|
|
5536
|
+
})
|
|
5537
|
+
);
|
|
5262
5538
|
let domCandidateInfo = null;
|
|
5263
|
-
if (!normalizeText(networkCandidateInfo?.resumeText)) {
|
|
5264
|
-
if (typeof this.logResumeNetworkMissDiagnostics === "function") {
|
|
5265
|
-
this.logResumeNetworkMissDiagnostics(nextCandidate, {
|
|
5266
|
-
timeoutMs: networkWaitMs,
|
|
5267
|
-
waitStartedAt: networkWaitStartedAt
|
|
5268
|
-
});
|
|
5269
|
-
}
|
|
5270
|
-
await sleep(NETWORK_RESUME_RETRY_WAIT_MS);
|
|
5271
|
-
networkCandidateInfo = await this.waitForNetworkResumeCandidateInfo(
|
|
5272
|
-
nextCandidate,
|
|
5273
|
-
NETWORK_RESUME_RETRY_WAIT_MS,
|
|
5274
|
-
{
|
|
5275
|
-
minTs: candidateCaptureStartedAt
|
|
5276
|
-
}
|
|
5277
|
-
);
|
|
5278
|
-
}
|
|
5279
5539
|
|
|
5280
5540
|
if (networkCandidateInfo?.resumeText) {
|
|
5281
|
-
screening = await
|
|
5541
|
+
screening = await timeCandidateStage(
|
|
5542
|
+
"text_model_ms",
|
|
5543
|
+
() => this.callTextModel(networkCandidateInfo.resumeText)
|
|
5544
|
+
);
|
|
5282
5545
|
resumeSource = "network";
|
|
5283
5546
|
resumeTextLength = normalizeText(networkCandidateInfo.resumeText).length;
|
|
5284
5547
|
this.resumeSourceStats.network += 1;
|
|
@@ -5296,14 +5559,29 @@ class RecommendScreenCli {
|
|
|
5296
5559
|
} else {
|
|
5297
5560
|
try {
|
|
5298
5561
|
resumeSource = "image_fallback";
|
|
5299
|
-
capture = await
|
|
5300
|
-
|
|
5562
|
+
capture = await timeCandidateStage(
|
|
5563
|
+
"image_capture_ms",
|
|
5564
|
+
() => this.captureResumeImage(nextCandidate)
|
|
5565
|
+
);
|
|
5566
|
+
this.setResumeAcquisitionMode("image", "image_capture_success");
|
|
5567
|
+
screening = await timeCandidateStage(
|
|
5568
|
+
"vision_model_ms",
|
|
5569
|
+
() => this.callVisionModel(capture.modelImagePaths || capture.stitchedImage)
|
|
5570
|
+
);
|
|
5301
5571
|
this.resumeSourceStats.image_fallback += 1;
|
|
5302
5572
|
} catch (imageFallbackError) {
|
|
5303
|
-
const
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5573
|
+
const lateNetworkCandidateInfo = await timeCandidateStage(
|
|
5574
|
+
"late_network_retry_ms",
|
|
5575
|
+
() => this.waitForLateNetworkResumeCandidateInfo(nextCandidate, {
|
|
5576
|
+
minTs: candidateCaptureStartedAt
|
|
5577
|
+
})
|
|
5578
|
+
);
|
|
5579
|
+
if (lateNetworkCandidateInfo?.resumeText) {
|
|
5580
|
+
networkCandidateInfo = lateNetworkCandidateInfo;
|
|
5581
|
+
screening = await timeCandidateStage(
|
|
5582
|
+
"text_model_ms",
|
|
5583
|
+
() => this.callTextModel(networkCandidateInfo.resumeText)
|
|
5584
|
+
);
|
|
5307
5585
|
resumeSource = "network";
|
|
5308
5586
|
resumeTextLength = normalizeText(networkCandidateInfo.resumeText).length;
|
|
5309
5587
|
this.resumeSourceStats.network += 1;
|
|
@@ -5318,25 +5596,54 @@ class RecommendScreenCli {
|
|
|
5318
5596
|
position: nextCandidate.last_position || ""
|
|
5319
5597
|
}
|
|
5320
5598
|
);
|
|
5321
|
-
} else if (domFallback?.domCandidateInfo?.resumeText) {
|
|
5322
|
-
domCandidateInfo = domFallback.domCandidateInfo;
|
|
5323
|
-
screening = await this.callTextModel(domCandidateInfo.resumeText);
|
|
5324
|
-
resumeSource = "dom_fallback";
|
|
5325
|
-
resumeTextLength = normalizeText(domCandidateInfo.resumeText).length;
|
|
5326
|
-
this.resumeSourceStats.dom_fallback += 1;
|
|
5327
|
-
candidateProfile = mergeCandidateProfiles(
|
|
5328
|
-
domCandidateInfo || null,
|
|
5329
|
-
cardProfile || null,
|
|
5330
|
-
{
|
|
5331
|
-
name: nextCandidate.name || "",
|
|
5332
|
-
school: nextCandidate.school || "",
|
|
5333
|
-
major: nextCandidate.major || "",
|
|
5334
|
-
company: nextCandidate.last_company || "",
|
|
5335
|
-
position: nextCandidate.last_position || ""
|
|
5336
|
-
}
|
|
5337
|
-
);
|
|
5338
5599
|
} else {
|
|
5339
|
-
|
|
5600
|
+
const domFallback = await timeCandidateStage(
|
|
5601
|
+
"dom_fallback_ms",
|
|
5602
|
+
() => this.resolveDomResumeFallback(nextCandidate, cardProfile || null)
|
|
5603
|
+
);
|
|
5604
|
+
if (domFallback?.networkCandidateInfo?.resumeText) {
|
|
5605
|
+
networkCandidateInfo = domFallback.networkCandidateInfo;
|
|
5606
|
+
screening = await timeCandidateStage(
|
|
5607
|
+
"text_model_ms",
|
|
5608
|
+
() => this.callTextModel(networkCandidateInfo.resumeText)
|
|
5609
|
+
);
|
|
5610
|
+
resumeSource = "network";
|
|
5611
|
+
resumeTextLength = normalizeText(networkCandidateInfo.resumeText).length;
|
|
5612
|
+
this.resumeSourceStats.network += 1;
|
|
5613
|
+
candidateProfile = mergeCandidateProfiles(
|
|
5614
|
+
networkCandidateInfo || null,
|
|
5615
|
+
cardProfile || null,
|
|
5616
|
+
{
|
|
5617
|
+
name: nextCandidate.name || "",
|
|
5618
|
+
school: nextCandidate.school || "",
|
|
5619
|
+
major: nextCandidate.major || "",
|
|
5620
|
+
company: nextCandidate.last_company || "",
|
|
5621
|
+
position: nextCandidate.last_position || ""
|
|
5622
|
+
}
|
|
5623
|
+
);
|
|
5624
|
+
} else if (domFallback?.domCandidateInfo?.resumeText) {
|
|
5625
|
+
domCandidateInfo = domFallback.domCandidateInfo;
|
|
5626
|
+
screening = await timeCandidateStage(
|
|
5627
|
+
"text_model_ms",
|
|
5628
|
+
() => this.callTextModel(domCandidateInfo.resumeText)
|
|
5629
|
+
);
|
|
5630
|
+
resumeSource = "dom_fallback";
|
|
5631
|
+
resumeTextLength = normalizeText(domCandidateInfo.resumeText).length;
|
|
5632
|
+
this.resumeSourceStats.dom_fallback += 1;
|
|
5633
|
+
candidateProfile = mergeCandidateProfiles(
|
|
5634
|
+
domCandidateInfo || null,
|
|
5635
|
+
cardProfile || null,
|
|
5636
|
+
{
|
|
5637
|
+
name: nextCandidate.name || "",
|
|
5638
|
+
school: nextCandidate.school || "",
|
|
5639
|
+
major: nextCandidate.major || "",
|
|
5640
|
+
company: nextCandidate.last_company || "",
|
|
5641
|
+
position: nextCandidate.last_position || ""
|
|
5642
|
+
}
|
|
5643
|
+
);
|
|
5644
|
+
} else {
|
|
5645
|
+
throw imageFallbackError;
|
|
5646
|
+
}
|
|
5340
5647
|
}
|
|
5341
5648
|
}
|
|
5342
5649
|
}
|
|
@@ -5356,13 +5663,16 @@ class RecommendScreenCli {
|
|
|
5356
5663
|
}
|
|
5357
5664
|
let actionResult = { actionTaken: "none" };
|
|
5358
5665
|
try {
|
|
5359
|
-
actionResult =
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
:
|
|
5666
|
+
actionResult = await timeCandidateStage(
|
|
5667
|
+
"post_action_ms",
|
|
5668
|
+
() => effectiveAction === "favorite"
|
|
5669
|
+
? this.favoriteCandidate({
|
|
5670
|
+
alreadyInterested: networkCandidateInfo?.alreadyInterested === true
|
|
5671
|
+
})
|
|
5672
|
+
: effectiveAction === "greet"
|
|
5673
|
+
? this.greetCandidate()
|
|
5674
|
+
: Promise.resolve({ actionTaken: "none" })
|
|
5675
|
+
);
|
|
5366
5676
|
} catch (postActionError) {
|
|
5367
5677
|
if (!isRecoverablePostActionError(postActionError, effectiveAction)) {
|
|
5368
5678
|
throw postActionError;
|
|
@@ -5395,7 +5705,7 @@ class RecommendScreenCli {
|
|
|
5395
5705
|
action: actionResult.actionTaken,
|
|
5396
5706
|
geekId: nextCandidate.geek_id,
|
|
5397
5707
|
summary: screening.summary,
|
|
5398
|
-
imagePath: capture?.stitchedImage || "",
|
|
5708
|
+
imagePath: capture?.stitchedImage || capture?.modelImagePaths?.[0] || capture?.chunkFiles?.[0] || "",
|
|
5399
5709
|
resumeSource
|
|
5400
5710
|
});
|
|
5401
5711
|
this.recordCandidateAudit({
|
|
@@ -5527,7 +5837,7 @@ class RecommendScreenCli {
|
|
|
5527
5837
|
);
|
|
5528
5838
|
}
|
|
5529
5839
|
} finally {
|
|
5530
|
-
const closed = await this.closeDetailPage();
|
|
5840
|
+
const closed = await timeCandidateStage("close_detail_ms", () => this.closeDetailPage());
|
|
5531
5841
|
if (!closed) {
|
|
5532
5842
|
if (allowDetailCloseFailure) {
|
|
5533
5843
|
log("[详情关闭兜底] 本候选人 post_action 失败后详情页关闭未确认,已记录错误并继续下一位候选人。");
|
|
@@ -5540,12 +5850,31 @@ class RecommendScreenCli {
|
|
|
5540
5850
|
}
|
|
5541
5851
|
}
|
|
5542
5852
|
|
|
5543
|
-
await this.takeBreakIfNeeded();
|
|
5853
|
+
await timeCandidateStage("rest_ms", () => this.takeBreakIfNeeded());
|
|
5854
|
+
candidateTiming.total_ms = Math.max(0, Date.now() - candidateStartedAt);
|
|
5855
|
+
this.updateCandidateAuditTiming(candidateKeyForTiming, candidateTiming);
|
|
5544
5856
|
try {
|
|
5545
|
-
this.saveCheckpoint();
|
|
5857
|
+
timeCandidateStageSync("checkpoint_save_ms", () => this.saveCheckpoint());
|
|
5858
|
+
candidateTiming.total_ms = Math.max(0, Date.now() - candidateStartedAt);
|
|
5859
|
+
this.updateCandidateAuditTiming(candidateKeyForTiming, candidateTiming);
|
|
5546
5860
|
} catch (checkpointError) {
|
|
5547
5861
|
log(`[保存checkpoint失败] ${checkpointError.message || checkpointError}`);
|
|
5548
5862
|
}
|
|
5863
|
+
try {
|
|
5864
|
+
this.saveCsv();
|
|
5865
|
+
} catch (csvError) {
|
|
5866
|
+
log(`[增量保存CSV失败] ${csvError.message || csvError}`);
|
|
5867
|
+
}
|
|
5868
|
+
log(
|
|
5869
|
+
`[TIMING] candidate=${candidateKeyForTiming || nextCandidate.name || "unknown"} ` +
|
|
5870
|
+
`total_ms=${candidateTiming.total_ms ?? ""} ` +
|
|
5871
|
+
`network_ms=${candidateTiming.network_resume_wait_ms ?? 0} ` +
|
|
5872
|
+
`text_model_ms=${candidateTiming.text_model_ms ?? 0} ` +
|
|
5873
|
+
`image_capture_ms=${candidateTiming.image_capture_ms ?? 0} ` +
|
|
5874
|
+
`vision_model_ms=${candidateTiming.vision_model_ms ?? 0} ` +
|
|
5875
|
+
`post_action_ms=${candidateTiming.post_action_ms ?? 0} ` +
|
|
5876
|
+
`close_ms=${candidateTiming.close_detail_ms ?? 0}`
|
|
5877
|
+
);
|
|
5549
5878
|
}
|
|
5550
5879
|
|
|
5551
5880
|
if (this.args.targetCount && this.passedCandidates.length < this.args.targetCount) {
|
|
@@ -5606,7 +5935,7 @@ async function main() {
|
|
|
5606
5935
|
console.log(JSON.stringify({
|
|
5607
5936
|
status: "COMPLETED",
|
|
5608
5937
|
result: {
|
|
5609
|
-
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> --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]"
|
|
5938
|
+
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]"
|
|
5610
5939
|
}
|
|
5611
5940
|
}));
|
|
5612
5941
|
return;
|
|
@@ -5646,6 +5975,8 @@ if (require.main === module) {
|
|
|
5646
5975
|
MAX_CONSECUTIVE_RESUME_CAPTURE_FAILURES,
|
|
5647
5976
|
RESUME_CAPTURE_MAX_ATTEMPTS,
|
|
5648
5977
|
RESUME_CAPTURE_WAIT_MS,
|
|
5978
|
+
NETWORK_RESUME_IMAGE_MODE_GRACE_MS,
|
|
5979
|
+
NETWORK_RESUME_LATE_RETRY_MS,
|
|
5649
5980
|
parseFavoriteActionFromPostData,
|
|
5650
5981
|
parseFavoriteActionFromRequest,
|
|
5651
5982
|
parseFavoriteActionFromKnownRequest,
|