@reconcrap/boss-recommend-mcp 1.3.15 → 1.3.16
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
|
@@ -3305,6 +3305,60 @@ class RecommendScreenCli {
|
|
|
3305
3305
|
return info;
|
|
3306
3306
|
}
|
|
3307
3307
|
|
|
3308
|
+
async resolveDomResumeFallback(candidate, cardProfile) {
|
|
3309
|
+
let domCandidateInfo = await this.extractResumeTextFromDom(candidate);
|
|
3310
|
+
let networkCandidateInfo = null;
|
|
3311
|
+
if (domCandidateInfo && !isDomProfileConsistentWithCard(cardProfile, domCandidateInfo)) {
|
|
3312
|
+
this.recordResumeNetworkDiagnostic({
|
|
3313
|
+
kind: "dom_profile_mismatch",
|
|
3314
|
+
candidate_key: normalizeText(candidate?.key || candidate?.geek_id || ""),
|
|
3315
|
+
card_name: normalizeText(cardProfile?.name || ""),
|
|
3316
|
+
dom_name: normalizeText(domCandidateInfo?.name || ""),
|
|
3317
|
+
card_school: normalizeText(cardProfile?.school || ""),
|
|
3318
|
+
dom_school: normalizeText(domCandidateInfo?.school || "")
|
|
3319
|
+
});
|
|
3320
|
+
log(
|
|
3321
|
+
`[DOM简历疑似错位] candidate=${candidate?.key || candidate?.geek_id || "unknown"} ` +
|
|
3322
|
+
`card=${normalizeText(cardProfile?.name || "-")} dom=${normalizeText(domCandidateInfo?.name || "-")},尝试重试一次点击+监听。`
|
|
3323
|
+
);
|
|
3324
|
+
try {
|
|
3325
|
+
const retryCaptureStartedAt = Date.now();
|
|
3326
|
+
await this.clickCandidate(candidate);
|
|
3327
|
+
const retryDetailOpen = await this.ensureDetailOpen();
|
|
3328
|
+
if (retryDetailOpen) {
|
|
3329
|
+
networkCandidateInfo = await this.waitForNetworkResumeCandidateInfo(
|
|
3330
|
+
candidate,
|
|
3331
|
+
NETWORK_RESUME_RETRY_WAIT_MS,
|
|
3332
|
+
{ minTs: retryCaptureStartedAt }
|
|
3333
|
+
);
|
|
3334
|
+
if (!normalizeText(networkCandidateInfo?.resumeText)) {
|
|
3335
|
+
const retryDomCandidateInfo = await this.extractResumeTextFromDom(candidate);
|
|
3336
|
+
if (retryDomCandidateInfo && isDomProfileConsistentWithCard(cardProfile, retryDomCandidateInfo)) {
|
|
3337
|
+
domCandidateInfo = retryDomCandidateInfo;
|
|
3338
|
+
} else {
|
|
3339
|
+
domCandidateInfo = null;
|
|
3340
|
+
}
|
|
3341
|
+
} else {
|
|
3342
|
+
domCandidateInfo = null;
|
|
3343
|
+
}
|
|
3344
|
+
} else {
|
|
3345
|
+
domCandidateInfo = null;
|
|
3346
|
+
}
|
|
3347
|
+
} catch (retryError) {
|
|
3348
|
+
domCandidateInfo = null;
|
|
3349
|
+
this.recordResumeNetworkDiagnostic({
|
|
3350
|
+
kind: "dom_profile_mismatch_retry_failed",
|
|
3351
|
+
candidate_key: normalizeText(candidate?.key || candidate?.geek_id || ""),
|
|
3352
|
+
error: normalizeText(retryError?.message || retryError)
|
|
3353
|
+
});
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
return {
|
|
3357
|
+
domCandidateInfo,
|
|
3358
|
+
networkCandidateInfo
|
|
3359
|
+
};
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3308
3362
|
handleNetworkRequestWillBeSent(params) {
|
|
3309
3363
|
const url = normalizeText(params?.request?.url || "");
|
|
3310
3364
|
const postData = params?.request?.postData || "";
|
|
@@ -5222,82 +5276,69 @@ class RecommendScreenCli {
|
|
|
5222
5276
|
}
|
|
5223
5277
|
);
|
|
5224
5278
|
}
|
|
5225
|
-
if (!normalizeText(networkCandidateInfo?.resumeText)) {
|
|
5226
|
-
domCandidateInfo = await this.extractResumeTextFromDom(nextCandidate);
|
|
5227
|
-
if (domCandidateInfo && !isDomProfileConsistentWithCard(cardProfile, domCandidateInfo)) {
|
|
5228
|
-
this.recordResumeNetworkDiagnostic({
|
|
5229
|
-
kind: "dom_profile_mismatch",
|
|
5230
|
-
candidate_key: normalizeText(nextCandidate?.key || nextCandidate?.geek_id || ""),
|
|
5231
|
-
card_name: normalizeText(cardProfile?.name || ""),
|
|
5232
|
-
dom_name: normalizeText(domCandidateInfo?.name || ""),
|
|
5233
|
-
card_school: normalizeText(cardProfile?.school || ""),
|
|
5234
|
-
dom_school: normalizeText(domCandidateInfo?.school || "")
|
|
5235
|
-
});
|
|
5236
|
-
log(
|
|
5237
|
-
`[DOM简历疑似错位] candidate=${nextCandidate?.key || nextCandidate?.geek_id || "unknown"} ` +
|
|
5238
|
-
`card=${normalizeText(cardProfile?.name || "-")} dom=${normalizeText(domCandidateInfo?.name || "-")},尝试重试一次点击+监听。`
|
|
5239
|
-
);
|
|
5240
|
-
try {
|
|
5241
|
-
const retryCaptureStartedAt = Date.now();
|
|
5242
|
-
await this.clickCandidate(nextCandidate);
|
|
5243
|
-
const retryDetailOpen = await this.ensureDetailOpen();
|
|
5244
|
-
if (retryDetailOpen) {
|
|
5245
|
-
networkCandidateInfo = await this.waitForNetworkResumeCandidateInfo(
|
|
5246
|
-
nextCandidate,
|
|
5247
|
-
NETWORK_RESUME_RETRY_WAIT_MS,
|
|
5248
|
-
{ minTs: retryCaptureStartedAt }
|
|
5249
|
-
);
|
|
5250
|
-
if (!normalizeText(networkCandidateInfo?.resumeText)) {
|
|
5251
|
-
const retryDomCandidateInfo = await this.extractResumeTextFromDom(nextCandidate);
|
|
5252
|
-
if (retryDomCandidateInfo && isDomProfileConsistentWithCard(cardProfile, retryDomCandidateInfo)) {
|
|
5253
|
-
domCandidateInfo = retryDomCandidateInfo;
|
|
5254
|
-
} else {
|
|
5255
|
-
domCandidateInfo = null;
|
|
5256
|
-
}
|
|
5257
|
-
} else {
|
|
5258
|
-
domCandidateInfo = null;
|
|
5259
|
-
}
|
|
5260
|
-
} else {
|
|
5261
|
-
domCandidateInfo = null;
|
|
5262
|
-
}
|
|
5263
|
-
} catch (retryError) {
|
|
5264
|
-
domCandidateInfo = null;
|
|
5265
|
-
this.recordResumeNetworkDiagnostic({
|
|
5266
|
-
kind: "dom_profile_mismatch_retry_failed",
|
|
5267
|
-
candidate_key: normalizeText(nextCandidate?.key || nextCandidate?.geek_id || ""),
|
|
5268
|
-
error: normalizeText(retryError?.message || retryError)
|
|
5269
|
-
});
|
|
5270
|
-
}
|
|
5271
|
-
}
|
|
5272
|
-
}
|
|
5273
|
-
const resumeCandidateInfo = networkCandidateInfo?.resumeText ? networkCandidateInfo : domCandidateInfo;
|
|
5274
|
-
candidateProfile = mergeCandidateProfiles(
|
|
5275
|
-
resumeCandidateInfo || null,
|
|
5276
|
-
cardProfile || null,
|
|
5277
|
-
{
|
|
5278
|
-
name: nextCandidate.name || "",
|
|
5279
|
-
school: nextCandidate.school || "",
|
|
5280
|
-
major: nextCandidate.major || "",
|
|
5281
|
-
company: nextCandidate.last_company || "",
|
|
5282
|
-
position: nextCandidate.last_position || ""
|
|
5283
|
-
}
|
|
5284
|
-
);
|
|
5285
5279
|
|
|
5286
5280
|
if (networkCandidateInfo?.resumeText) {
|
|
5287
5281
|
screening = await this.callTextModel(networkCandidateInfo.resumeText);
|
|
5288
5282
|
resumeSource = "network";
|
|
5289
5283
|
resumeTextLength = normalizeText(networkCandidateInfo.resumeText).length;
|
|
5290
5284
|
this.resumeSourceStats.network += 1;
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5285
|
+
candidateProfile = mergeCandidateProfiles(
|
|
5286
|
+
networkCandidateInfo || null,
|
|
5287
|
+
cardProfile || null,
|
|
5288
|
+
{
|
|
5289
|
+
name: nextCandidate.name || "",
|
|
5290
|
+
school: nextCandidate.school || "",
|
|
5291
|
+
major: nextCandidate.major || "",
|
|
5292
|
+
company: nextCandidate.last_company || "",
|
|
5293
|
+
position: nextCandidate.last_position || ""
|
|
5294
|
+
}
|
|
5295
|
+
);
|
|
5296
5296
|
} else {
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5297
|
+
try {
|
|
5298
|
+
resumeSource = "image_fallback";
|
|
5299
|
+
capture = await this.captureResumeImage(nextCandidate);
|
|
5300
|
+
screening = await this.callVisionModel(capture.stitchedImage);
|
|
5301
|
+
this.resumeSourceStats.image_fallback += 1;
|
|
5302
|
+
} catch (imageFallbackError) {
|
|
5303
|
+
const domFallback = await this.resolveDomResumeFallback(nextCandidate, cardProfile || null);
|
|
5304
|
+
if (domFallback?.networkCandidateInfo?.resumeText) {
|
|
5305
|
+
networkCandidateInfo = domFallback.networkCandidateInfo;
|
|
5306
|
+
screening = await this.callTextModel(networkCandidateInfo.resumeText);
|
|
5307
|
+
resumeSource = "network";
|
|
5308
|
+
resumeTextLength = normalizeText(networkCandidateInfo.resumeText).length;
|
|
5309
|
+
this.resumeSourceStats.network += 1;
|
|
5310
|
+
candidateProfile = mergeCandidateProfiles(
|
|
5311
|
+
networkCandidateInfo || null,
|
|
5312
|
+
cardProfile || null,
|
|
5313
|
+
{
|
|
5314
|
+
name: nextCandidate.name || "",
|
|
5315
|
+
school: nextCandidate.school || "",
|
|
5316
|
+
major: nextCandidate.major || "",
|
|
5317
|
+
company: nextCandidate.last_company || "",
|
|
5318
|
+
position: nextCandidate.last_position || ""
|
|
5319
|
+
}
|
|
5320
|
+
);
|
|
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
|
+
} else {
|
|
5339
|
+
throw imageFallbackError;
|
|
5340
|
+
}
|
|
5341
|
+
}
|
|
5301
5342
|
}
|
|
5302
5343
|
this.resetResumeCaptureFailureStreak();
|
|
5303
5344
|
log(`筛选结果: ${screening.passed ? "通过" : "不通过"}`);
|
|
@@ -467,7 +467,7 @@ async function testRecommendShouldPreferNetworkResumeWhenAvailable() {
|
|
|
467
467
|
assert.equal(result.result.resume_source, "network");
|
|
468
468
|
}
|
|
469
469
|
|
|
470
|
-
async function
|
|
470
|
+
async function testNetworkMissShouldFallbackToImageThenDom() {
|
|
471
471
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-network-dom-fallback-"));
|
|
472
472
|
const candidate = { key: "dom-1", geek_id: "dom-1", name: "dom candidate" };
|
|
473
473
|
const cli = new FakeRecommendScreenCli(createArgs(tempDir), {
|
|
@@ -485,13 +485,15 @@ async function testNetworkMissShouldFallbackToDomBeforeImageCapture() {
|
|
|
485
485
|
});
|
|
486
486
|
|
|
487
487
|
cli.waitForNetworkResumeCandidateInfo = async () => null;
|
|
488
|
+
let captureAttempted = false;
|
|
488
489
|
cli.callTextModel = async (resumeText) => ({
|
|
489
490
|
passed: true,
|
|
490
491
|
reason: resumeText.includes("华中科技大学") ? "dom fallback used" : "unexpected",
|
|
491
492
|
summary: "dom fallback used"
|
|
492
493
|
});
|
|
493
494
|
cli.captureResumeImage = async () => {
|
|
494
|
-
|
|
495
|
+
captureAttempted = true;
|
|
496
|
+
throw new Error("capture failed, should fallback to dom");
|
|
495
497
|
};
|
|
496
498
|
|
|
497
499
|
const result = await cli.run();
|
|
@@ -501,6 +503,7 @@ async function testNetworkMissShouldFallbackToDomBeforeImageCapture() {
|
|
|
501
503
|
assert.equal(cli.passedCandidates.length, 1);
|
|
502
504
|
assert.equal(cli.passedCandidates[0].school, "华中科技大学");
|
|
503
505
|
assert.equal(cli.passedCandidates[0].resumeSource, "dom_fallback");
|
|
506
|
+
assert.equal(captureAttempted, true);
|
|
504
507
|
}
|
|
505
508
|
|
|
506
509
|
async function testNetworkMissShouldFallbackToImageCapture() {
|
|
@@ -600,7 +603,7 @@ function testLatestPayloadShouldRemainAvailableWhenCandidateKeyMissing() {
|
|
|
600
603
|
key: "",
|
|
601
604
|
geek_id: ""
|
|
602
605
|
});
|
|
603
|
-
assert.equal(extracted?.resumeText, "recent resume payload");
|
|
606
|
+
assert.equal(extracted?.candidateInfo?.resumeText, "recent resume payload");
|
|
604
607
|
}
|
|
605
608
|
|
|
606
609
|
async function testVisionModelFailureShouldSkipCandidateAndContinue() {
|
|
@@ -638,25 +641,44 @@ async function testVisionModelFailureShouldSkipCandidateAndContinue() {
|
|
|
638
641
|
assert.equal(result.result.skipped_count, 1);
|
|
639
642
|
}
|
|
640
643
|
|
|
641
|
-
async function
|
|
644
|
+
async function testFeaturedNetworkMissShouldFallbackToDomAfterImageFailure() {
|
|
642
645
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-featured-network-only-"));
|
|
643
646
|
const args = createArgs(tempDir);
|
|
644
647
|
args.pageScope = "featured";
|
|
645
648
|
const candidate = { key: "featured-no-network", geek_id: "featured-no-network", name: "featured no network" };
|
|
646
649
|
const cli = new FakeRecommendScreenCli(args, {
|
|
647
|
-
candidates: [candidate]
|
|
650
|
+
candidates: [candidate],
|
|
651
|
+
domResumeByKey: new Map([
|
|
652
|
+
["featured-no-network", {
|
|
653
|
+
name: "featured no network",
|
|
654
|
+
school: "华中科技大学",
|
|
655
|
+
major: "软件工程",
|
|
656
|
+
company: "测试公司",
|
|
657
|
+
position: "后端工程师",
|
|
658
|
+
resumeText: "featured network miss 后应在截图失败后走 DOM 兜底。"
|
|
659
|
+
}]
|
|
660
|
+
])
|
|
648
661
|
});
|
|
649
662
|
cli.waitForNetworkResumeCandidateInfo = async () => null;
|
|
663
|
+
let captureAttempted = false;
|
|
664
|
+
cli.callTextModel = async () => ({
|
|
665
|
+
passed: true,
|
|
666
|
+
reason: "dom fallback used",
|
|
667
|
+
summary: "dom fallback used"
|
|
668
|
+
});
|
|
650
669
|
cli.captureResumeImage = async () => {
|
|
651
|
-
|
|
670
|
+
captureAttempted = true;
|
|
671
|
+
throw new Error("capture failed for featured scope");
|
|
652
672
|
};
|
|
653
673
|
|
|
654
674
|
const result = await cli.run();
|
|
655
675
|
assert.equal(result.status, "COMPLETED");
|
|
656
676
|
assert.equal(result.result.processed_count, 1);
|
|
657
|
-
assert.equal(result.result.passed_count,
|
|
658
|
-
assert.equal(result.result.skipped_count,
|
|
659
|
-
assert.equal(result.result.resume_source, "
|
|
677
|
+
assert.equal(result.result.passed_count, 1);
|
|
678
|
+
assert.equal(result.result.skipped_count, 0);
|
|
679
|
+
assert.equal(result.result.resume_source, "dom_fallback");
|
|
680
|
+
assert.equal(captureAttempted, true);
|
|
681
|
+
assert.equal(cli.passedCandidates[0].resumeSource, "dom_fallback");
|
|
660
682
|
}
|
|
661
683
|
|
|
662
684
|
async function testFeaturedFavoriteShouldNotUseDomFallback() {
|
|
@@ -1461,14 +1483,14 @@ async function main() {
|
|
|
1461
1483
|
await testTargetCountShouldNotTreatProcessedCountAsReached();
|
|
1462
1484
|
await testFeaturedShouldUseNetworkResumeOnly();
|
|
1463
1485
|
await testRecommendShouldPreferNetworkResumeWhenAvailable();
|
|
1464
|
-
await
|
|
1486
|
+
await testNetworkMissShouldFallbackToImageThenDom();
|
|
1465
1487
|
await testNetworkMissShouldFallbackToImageCapture();
|
|
1466
1488
|
await testLatestShouldPreferNetworkResumeWhenAvailable();
|
|
1467
1489
|
await testLatestNetworkMissShouldFallbackToImageCapture();
|
|
1468
1490
|
testLatestPayloadShouldNotLeakAcrossCandidates();
|
|
1469
1491
|
testLatestPayloadShouldRemainAvailableWhenCandidateKeyMissing();
|
|
1470
1492
|
await testVisionModelFailureShouldSkipCandidateAndContinue();
|
|
1471
|
-
await
|
|
1493
|
+
await testFeaturedNetworkMissShouldFallbackToDomAfterImageFailure();
|
|
1472
1494
|
await testFeaturedFavoriteShouldNotUseDomFallback();
|
|
1473
1495
|
await testFeaturedFavoriteShouldSkipClickWhenAlreadyInterested();
|
|
1474
1496
|
await testFeaturedFavoriteShouldRecognizeAlreadyFavoritedByDelThenAdd();
|