@reconcrap/boss-recommend-mcp 1.3.22 → 1.3.23

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.22",
3
+ "version": "1.3.23",
4
4
  "description": "Unified MCP pipeline for recommend-page filtering and screening on Boss Zhipin",
5
5
  "keywords": [
6
6
  "boss",
@@ -475,6 +475,15 @@ function toStringArray(value, maxItems = 8) {
475
475
  return normalized;
476
476
  }
477
477
 
478
+ function hasEvidenceGateSignal(parsed, parsedEvidence = null) {
479
+ if (!parsed || typeof parsed !== "object") return false;
480
+ if (parsed?.evidenceGateEligible === true) return true;
481
+ if (Number.isFinite(Number(parsed?.evidenceRawCount))) return true;
482
+ if (Number.isFinite(Number(parsed?.evidenceMatchedCount))) return true;
483
+ const normalizedEvidence = Array.isArray(parsedEvidence) ? parsedEvidence : toStringArray(parsed?.evidence);
484
+ return normalizedEvidence.length > 0;
485
+ }
486
+
478
487
  function toLowerSafe(text) {
479
488
  return String(text || "").toLowerCase();
480
489
  }
@@ -4959,11 +4968,8 @@ class RecommendScreenCli {
4959
4968
  applyVisionEvidenceGate(result) {
4960
4969
  const parsed = result && typeof result === "object" ? result : {};
4961
4970
  const rawPassed = parsed?.rawPassed === true || parsed?.passed === true;
4962
- const evidenceGateEligible = parsed?.evidenceGateEligible === true
4963
- || Array.isArray(parsed?.evidence)
4964
- || Number.isFinite(Number(parsed?.evidenceRawCount))
4965
- || Number.isFinite(Number(parsed?.evidenceMatchedCount));
4966
- const parsedEvidence = evidenceGateEligible ? toStringArray(parsed?.evidence) : [];
4971
+ const parsedEvidence = toStringArray(parsed?.evidence);
4972
+ const evidenceGateEligible = hasEvidenceGateSignal(parsed, parsedEvidence);
4967
4973
  const evidenceRawCount = evidenceGateEligible
4968
4974
  ? (Number.isFinite(Number(parsed?.evidenceRawCount))
4969
4975
  ? Number(parsed.evidenceRawCount)
@@ -5273,10 +5279,8 @@ class RecommendScreenCli {
5273
5279
  const cot = normalizeText(extractCotFromChoice(choice, parsed));
5274
5280
  const reason = cot || (rawPassed ? "模型判定符合筛选标准。" : "模型判定不符合筛选标准。");
5275
5281
  const summary = reason;
5276
- const evidenceGateEligible = Array.isArray(parsed?.evidence)
5277
- || Number.isFinite(Number(parsed?.evidenceRawCount))
5278
- || Number.isFinite(Number(parsed?.evidenceMatchedCount));
5279
- const parsedEvidence = evidenceGateEligible ? toStringArray(parsed?.evidence) : [];
5282
+ const parsedEvidence = toStringArray(parsed?.evidence);
5283
+ const evidenceGateEligible = hasEvidenceGateSignal(parsed, parsedEvidence);
5280
5284
  const evidenceRawCount = evidenceGateEligible
5281
5285
  ? (Number.isFinite(Number(parsed?.evidenceRawCount)) ? Number(parsed.evidenceRawCount) : parsedEvidence.length)
5282
5286
  : null;
@@ -5440,10 +5444,8 @@ class RecommendScreenCli {
5440
5444
  const cot = normalizeText(extractCotFromChoice(choice, parsed));
5441
5445
  const normalizedResume = normalizeText(safeResumeText);
5442
5446
  const normalizedResumeLower = toLowerSafe(normalizedResume);
5443
- const evidenceGateEligible = Array.isArray(parsed?.evidence)
5444
- || Number.isFinite(Number(parsed?.evidenceRawCount))
5445
- || Number.isFinite(Number(parsed?.evidenceMatchedCount));
5446
- const parsedEvidence = evidenceGateEligible ? toStringArray(parsed.evidence) : [];
5447
+ const parsedEvidence = toStringArray(parsed?.evidence);
5448
+ const evidenceGateEligible = hasEvidenceGateSignal(parsed, parsedEvidence);
5447
5449
  const evidence = [];
5448
5450
  const unmatchedEvidence = [];
5449
5451
  if (evidenceGateEligible) {
@@ -1695,7 +1695,7 @@ async function testCloseDetailPageShouldContinueWhenListReady() {
1695
1695
  assert.equal(closed, true);
1696
1696
  }
1697
1697
 
1698
- async function testVisionEvidenceGateShouldDemoteImageFallbackWithoutEvidence() {
1698
+ async function testVisionEvidenceGateShouldKeepRawPassWithoutExplicitEvidenceProtocol() {
1699
1699
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-vision-evidence-gate-"));
1700
1700
  const cli = new RecommendScreenCli(createArgs(tempDir));
1701
1701
  cli.prepareVisionImageSegmentsForModel = async () => ({
@@ -1713,6 +1713,33 @@ async function testVisionEvidenceGateShouldDemoteImageFallbackWithoutEvidence()
1713
1713
  });
1714
1714
  const result = await cli.callVisionModel(path.join(tempDir, "fake.png"));
1715
1715
  assert.equal(result.rawPassed, true);
1716
+ assert.equal(result.passed, true);
1717
+ assert.equal(result.evidenceGateDemoted, false);
1718
+ assert.equal(result.evidenceRawCount, null);
1719
+ assert.equal(result.evidenceMatchedCount, null);
1720
+ }
1721
+
1722
+ async function testVisionEvidenceGateShouldDemoteWhenExplicitlyArmedWithoutEvidence() {
1723
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-vision-evidence-gate-explicit-"));
1724
+ const cli = new RecommendScreenCli(createArgs(tempDir));
1725
+ cli.prepareVisionImageSegmentsForModel = async () => ({
1726
+ imagePaths: ["segment-1"],
1727
+ source: "test",
1728
+ sourcePixels: 100,
1729
+ currentPixels: 100
1730
+ });
1731
+ cli.requestVisionModel = async () => ({
1732
+ passed: true,
1733
+ rawPassed: true,
1734
+ reason: "matched",
1735
+ summary: "matched",
1736
+ evidence: [],
1737
+ evidenceGateEligible: true,
1738
+ evidenceRawCount: 0,
1739
+ evidenceMatchedCount: 0
1740
+ });
1741
+ const result = await cli.callVisionModel(path.join(tempDir, "fake.png"));
1742
+ assert.equal(result.rawPassed, true);
1716
1743
  assert.equal(result.passed, false);
1717
1744
  assert.equal(result.evidenceGateDemoted, true);
1718
1745
  assert.equal(result.evidenceRawCount, 0);
@@ -1815,7 +1842,8 @@ async function main() {
1815
1842
  await testTextModelShouldDefaultThinkingLowForVolcengine();
1816
1843
  await testTextModelShouldSupportLowThinkingForVolcengine();
1817
1844
  await testPrepareVisionImageSegmentsShouldSplitLongImage();
1818
- await testVisionEvidenceGateShouldDemoteImageFallbackWithoutEvidence();
1845
+ await testVisionEvidenceGateShouldKeepRawPassWithoutExplicitEvidenceProtocol();
1846
+ await testVisionEvidenceGateShouldDemoteWhenExplicitlyArmedWithoutEvidence();
1819
1847
  await testVisionModelShouldSendAllOrderedChunks();
1820
1848
  testRecoverablePostActionErrorShouldTreatGreetContinueAndNoButtonAsRecoverable();
1821
1849
  await testRecoverableGreetContinueButtonShouldNotAbortWhenDetailCloseFails();