@reconcrap/boss-recommend-mcp 2.0.28 → 2.0.29
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 +1 -1
- package/src/domains/recommend/run-service.js +131 -39
- package/src/recommend-mcp.js +2 -0
package/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import { createRunLifecycleManager } from "../../core/run/index.js";
|
|
2
4
|
import {
|
|
3
5
|
addTiming,
|
|
@@ -376,6 +378,66 @@ function compactError(error, fallbackCode = "RECOMMEND_RUN_ERROR") {
|
|
|
376
378
|
};
|
|
377
379
|
}
|
|
378
380
|
|
|
381
|
+
export function isRecoverableImageCaptureError(error) {
|
|
382
|
+
const code = String(error?.code || "");
|
|
383
|
+
if (code === "IMAGE_CAPTURE_TIMEOUT" || code === "IMAGE_CAPTURE_TOTAL_TIMEOUT") return true;
|
|
384
|
+
return /Image fallback capture timed out/i.test(String(error?.message || error || ""));
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function collectPartialImageEvidencePaths(basePath = "", extension = "jpg", maxCount = 12) {
|
|
388
|
+
const resolved = String(basePath || "").trim();
|
|
389
|
+
if (!resolved) return [];
|
|
390
|
+
const parsed = path.parse(resolved);
|
|
391
|
+
const ext = parsed.ext || `.${String(extension || "jpg").replace(/^\./, "") || "jpg"}`;
|
|
392
|
+
const files = [];
|
|
393
|
+
for (let index = 0; index < Math.max(1, Number(maxCount) || 1); index += 1) {
|
|
394
|
+
const page = String(index + 1).padStart(2, "0");
|
|
395
|
+
const candidatePath = path.join(parsed.dir, `${parsed.name}-page-${page}${ext}`);
|
|
396
|
+
if (fs.existsSync(candidatePath)) files.push(candidatePath);
|
|
397
|
+
}
|
|
398
|
+
return files;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export function createRecoverableImageCaptureEvidence(error, {
|
|
402
|
+
elapsedMs = 0,
|
|
403
|
+
filePath = "",
|
|
404
|
+
extension = "jpg",
|
|
405
|
+
maxScreenshots = 8
|
|
406
|
+
} = {}) {
|
|
407
|
+
const filePaths = collectPartialImageEvidencePaths(filePath, extension, maxScreenshots);
|
|
408
|
+
return {
|
|
409
|
+
schema_version: 1,
|
|
410
|
+
ok: false,
|
|
411
|
+
source: "image-scroll-sequence",
|
|
412
|
+
elapsed_ms: Math.max(0, Math.round(Number(error?.elapsed_ms ?? elapsedMs) || 0)),
|
|
413
|
+
capture_count: filePaths.length,
|
|
414
|
+
screenshot_count: filePaths.length,
|
|
415
|
+
unique_screenshot_count: filePaths.length,
|
|
416
|
+
dropped_duplicate_count: 0,
|
|
417
|
+
total_byte_length: 0,
|
|
418
|
+
original_total_byte_length: 0,
|
|
419
|
+
llm_screenshot_count: 0,
|
|
420
|
+
llm_total_byte_length: 0,
|
|
421
|
+
llm_original_total_byte_length: 0,
|
|
422
|
+
llm_composition_error: null,
|
|
423
|
+
error_code: error?.code || "IMAGE_CAPTURE_FAILED",
|
|
424
|
+
error: error?.message || String(error || "Image capture failed"),
|
|
425
|
+
file_paths: filePaths,
|
|
426
|
+
llm_file_paths: []
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function createImageCaptureFailureScreening(candidate, error) {
|
|
431
|
+
return {
|
|
432
|
+
status: "fail",
|
|
433
|
+
passed: false,
|
|
434
|
+
score: 0,
|
|
435
|
+
reasons: ["image_capture_failed"],
|
|
436
|
+
error: compactError(error, "IMAGE_CAPTURE_FAILED"),
|
|
437
|
+
candidate
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
379
441
|
export async function runRecommendWorkflow({
|
|
380
442
|
client,
|
|
381
443
|
targetUrl = "",
|
|
@@ -742,42 +804,57 @@ export async function runRecommendWorkflow({
|
|
|
742
804
|
|| openedDetail.detail_state?.resumeIframe?.node_id
|
|
743
805
|
|| null;
|
|
744
806
|
if (captureNodeId) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
807
|
+
const imageEvidencePath = imageEvidenceFilePath({
|
|
808
|
+
imageOutputDir,
|
|
809
|
+
domain: "recommend",
|
|
810
|
+
runId: runControl?.runId,
|
|
811
|
+
index,
|
|
812
|
+
extension: "jpg"
|
|
813
|
+
});
|
|
814
|
+
try {
|
|
815
|
+
imageEvidence = await measureTiming(timings, "screenshot_capture_ms", () => captureScrolledNodeScreenshots(client, captureNodeId, {
|
|
816
|
+
filePath: imageEvidencePath,
|
|
817
|
+
format: "jpeg",
|
|
818
|
+
quality: 72,
|
|
819
|
+
optimize: true,
|
|
820
|
+
resizeMaxWidth: 1100,
|
|
821
|
+
captureViewport: true,
|
|
822
|
+
padding: 4,
|
|
823
|
+
maxScreenshots: maxImagePages,
|
|
824
|
+
wheelDeltaY: imageWheelDeltaY,
|
|
825
|
+
settleMs: 350,
|
|
826
|
+
scrollMethod: "dom-anchor-fallback-input",
|
|
827
|
+
stepTimeoutMs: 45000,
|
|
828
|
+
totalTimeoutMs: 90000,
|
|
829
|
+
duplicateStopCount: 1,
|
|
830
|
+
skipDuplicateScreenshots: true,
|
|
831
|
+
composeForLlm: true,
|
|
832
|
+
llmPagesPerImage: 3,
|
|
833
|
+
llmResizeMaxWidth: 1100,
|
|
834
|
+
llmQuality: 72,
|
|
835
|
+
metadata: {
|
|
836
|
+
domain: "recommend",
|
|
837
|
+
capture_mode: "scroll_sequence",
|
|
838
|
+
acquisition_reason: "network_miss_image_fallback",
|
|
839
|
+
run_candidate_index: index,
|
|
840
|
+
candidate_key: candidateKey
|
|
841
|
+
}
|
|
842
|
+
}));
|
|
843
|
+
source = "image";
|
|
844
|
+
} catch (error) {
|
|
845
|
+
if (!isRecoverableImageCaptureError(error)) throw error;
|
|
846
|
+
imageEvidence = createRecoverableImageCaptureEvidence(error, {
|
|
847
|
+
elapsedMs: timings.screenshot_capture_ms,
|
|
848
|
+
filePath: imageEvidencePath,
|
|
849
|
+
extension: "jpg",
|
|
850
|
+
maxScreenshots: maxImagePages
|
|
851
|
+
});
|
|
852
|
+
source = "image_capture_failed";
|
|
853
|
+
}
|
|
780
854
|
recordCvImageFallback(cvAcquisitionState, {
|
|
855
|
+
reason: source === "image_capture_failed"
|
|
856
|
+
? "network_miss_image_capture_failed"
|
|
857
|
+
: "network_miss_image_fallback",
|
|
781
858
|
parsedNetworkProfileCount,
|
|
782
859
|
waitResult: networkWait,
|
|
783
860
|
imageEvidence
|
|
@@ -809,7 +886,9 @@ export async function runRecommendWorkflow({
|
|
|
809
886
|
runControl.setPhase("recommend:screening");
|
|
810
887
|
let llmResult = null;
|
|
811
888
|
if (useLlmScreening) {
|
|
812
|
-
if (
|
|
889
|
+
if (detailResult?.image_evidence?.ok === false) {
|
|
890
|
+
llmResult = null;
|
|
891
|
+
} else if (!llmConfig) {
|
|
813
892
|
llmResult = createMissingLlmConfigResult();
|
|
814
893
|
} else {
|
|
815
894
|
try {
|
|
@@ -831,9 +910,14 @@ export async function runRecommendWorkflow({
|
|
|
831
910
|
}
|
|
832
911
|
if (detailResult) detailResult.llm_result = llmResult;
|
|
833
912
|
}
|
|
834
|
-
const screening =
|
|
835
|
-
?
|
|
836
|
-
|
|
913
|
+
const screening = detailResult?.image_evidence?.ok === false
|
|
914
|
+
? createImageCaptureFailureScreening(screeningCandidate, {
|
|
915
|
+
code: detailResult.image_evidence.error_code,
|
|
916
|
+
message: detailResult.image_evidence.error
|
|
917
|
+
})
|
|
918
|
+
: useLlmScreening
|
|
919
|
+
? llmResultToScreening(llmResult, screeningCandidate)
|
|
920
|
+
: screenCandidate(screeningCandidate, { criteria });
|
|
837
921
|
let actionDiscovery = null;
|
|
838
922
|
let postActionResult = null;
|
|
839
923
|
if (postActionEnabled && detailResult) {
|
|
@@ -875,6 +959,12 @@ export async function runRecommendWorkflow({
|
|
|
875
959
|
screening: compactScreening(screening),
|
|
876
960
|
action_discovery: compactActionDiscovery(actionDiscovery),
|
|
877
961
|
post_action: postActionResult,
|
|
962
|
+
error: detailResult?.image_evidence?.ok === false
|
|
963
|
+
? compactError({
|
|
964
|
+
code: detailResult.image_evidence.error_code,
|
|
965
|
+
message: detailResult.image_evidence.error
|
|
966
|
+
}, "IMAGE_CAPTURE_FAILED")
|
|
967
|
+
: null,
|
|
878
968
|
timings
|
|
879
969
|
};
|
|
880
970
|
results.push(compactResult);
|
|
@@ -896,6 +986,7 @@ export async function runRecommendWorkflow({
|
|
|
896
986
|
llm_screened: results.filter((item) => item.detail?.llm_screening || item.llm_screening).length,
|
|
897
987
|
greet_count: greetCount,
|
|
898
988
|
post_action_clicked: results.filter((item) => item.post_action?.action_clicked).length,
|
|
989
|
+
image_capture_failed: results.filter((item) => item.detail?.image_evidence?.ok === false).length,
|
|
899
990
|
unique_seen: compactInfiniteListState(listState).seen_count,
|
|
900
991
|
scroll_count: compactInfiniteListState(listState).scroll_count,
|
|
901
992
|
refresh_rounds: refreshRounds,
|
|
@@ -920,6 +1011,7 @@ export async function runRecommendWorkflow({
|
|
|
920
1011
|
score: screening.score
|
|
921
1012
|
},
|
|
922
1013
|
llm_screening: compactScreeningLlmResult(llmResult),
|
|
1014
|
+
error: compactResult.error,
|
|
923
1015
|
post_action: postActionResult
|
|
924
1016
|
}
|
|
925
1017
|
});
|
package/src/recommend-mcp.js
CHANGED
|
@@ -317,6 +317,8 @@ function ensureRecommendRunArtifacts(snapshot) {
|
|
|
317
317
|
progress: snapshot.progress || {},
|
|
318
318
|
context: snapshot.context || {},
|
|
319
319
|
checkpoint,
|
|
320
|
+
error: snapshot.error || null,
|
|
321
|
+
last_message: snapshot.error?.message || snapshot.phase || snapshot.stage || null,
|
|
320
322
|
summary: artifactSummary,
|
|
321
323
|
generated_at: new Date().toISOString()
|
|
322
324
|
});
|