@reconcrap/boss-recommend-mcp 2.1.19 → 2.1.21
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/core/browser/index.js +44 -1
- package/src/domains/chat/run-service.js +81 -51
- package/src/recommend-mcp.js +253 -105
- package/src/recommend-scheduler.js +15 -1
package/package.json
CHANGED
|
@@ -462,6 +462,9 @@ export function createHumanRestController({
|
|
|
462
462
|
shortRestProbability = 0.08,
|
|
463
463
|
shortRestMinMs = 3000,
|
|
464
464
|
shortRestMaxMs = 7000,
|
|
465
|
+
perCandidateRestEnabled = false,
|
|
466
|
+
perCandidateRestMinMs = 0,
|
|
467
|
+
perCandidateRestMaxMs = 0,
|
|
465
468
|
batchThresholdBase = 25,
|
|
466
469
|
batchThresholdJitter = 8,
|
|
467
470
|
batchRestMinMs = 15000,
|
|
@@ -470,7 +473,10 @@ export function createHumanRestController({
|
|
|
470
473
|
const nextRandom = normalizeRandom(random);
|
|
471
474
|
const readNow = typeof nowFn === "function" ? nowFn : Date.now;
|
|
472
475
|
const normalizedRestLevel = normalizeHumanRestLevel(restLevel);
|
|
473
|
-
const
|
|
476
|
+
const perCandidateMinMs = Math.max(0, Number(perCandidateRestMinMs) || 0);
|
|
477
|
+
const perCandidateMaxMs = Math.max(perCandidateMinMs, Number(perCandidateRestMaxMs) || perCandidateMinMs);
|
|
478
|
+
const perCandidateEnabled = enabled === true && perCandidateRestEnabled === true && perCandidateMaxMs > 0;
|
|
479
|
+
const budgetProfile = !perCandidateEnabled && (shortRestEnabled !== false || batchRestEnabled !== false)
|
|
474
480
|
? HUMAN_REST_LEVEL_PROFILES[normalizedRestLevel] || null
|
|
475
481
|
: null;
|
|
476
482
|
const nextBudgetRestInterval = () => budgetProfile
|
|
@@ -479,6 +485,9 @@ export function createHumanRestController({
|
|
|
479
485
|
const state = {
|
|
480
486
|
enabled: enabled === true,
|
|
481
487
|
rest_level: normalizedRestLevel,
|
|
488
|
+
per_candidate_rest_enabled: perCandidateEnabled,
|
|
489
|
+
per_candidate_rest_min_ms: perCandidateMinMs,
|
|
490
|
+
per_candidate_rest_max_ms: perCandidateMaxMs,
|
|
482
491
|
short_rest_enabled: enabled === true && shortRestEnabled !== false,
|
|
483
492
|
batch_rest_enabled: enabled === true && batchRestEnabled !== false,
|
|
484
493
|
rest_counter: 0,
|
|
@@ -569,6 +578,40 @@ export function createHumanRestController({
|
|
|
569
578
|
}
|
|
570
579
|
const sleeper = typeof sleepFn === "function" ? sleepFn : sleep;
|
|
571
580
|
updateActiveElapsed();
|
|
581
|
+
if (state.per_candidate_rest_enabled) {
|
|
582
|
+
state.rest_counter += 1;
|
|
583
|
+
state.processed_count += 1;
|
|
584
|
+
state.candidates_since_last_rest += 1;
|
|
585
|
+
const pauseMs = Math.round(randomBetween(
|
|
586
|
+
nextRandom,
|
|
587
|
+
state.per_candidate_rest_min_ms,
|
|
588
|
+
state.per_candidate_rest_max_ms
|
|
589
|
+
));
|
|
590
|
+
await sleeper(pauseMs);
|
|
591
|
+
state.rest_count += 1;
|
|
592
|
+
state.total_rest_ms += pauseMs;
|
|
593
|
+
state.last_active_at_ms = Number(readNow()) || state.last_active_at_ms;
|
|
594
|
+
const event = {
|
|
595
|
+
kind: "per_candidate_rest",
|
|
596
|
+
rest_level: normalizedRestLevel,
|
|
597
|
+
pause_ms: pauseMs,
|
|
598
|
+
processed_since_last_rest: state.candidates_since_last_rest
|
|
599
|
+
};
|
|
600
|
+
state.candidates_since_last_rest = 0;
|
|
601
|
+
return {
|
|
602
|
+
enabled: true,
|
|
603
|
+
rested: true,
|
|
604
|
+
pause_ms: pauseMs,
|
|
605
|
+
rest_level: normalizedRestLevel,
|
|
606
|
+
rest_counter: state.rest_counter,
|
|
607
|
+
rest_threshold: state.rest_threshold,
|
|
608
|
+
processed_count: state.processed_count,
|
|
609
|
+
active_elapsed_ms: state.active_elapsed_ms,
|
|
610
|
+
rest_count: state.rest_count,
|
|
611
|
+
total_rest_ms: state.total_rest_ms,
|
|
612
|
+
events: [event]
|
|
613
|
+
};
|
|
614
|
+
}
|
|
572
615
|
if (budgetProfile) {
|
|
573
616
|
const budgetEvent = await takeBudgetBreakIfNeeded(sleeper);
|
|
574
617
|
const pauseMs = budgetEvent?.pause_ms || 0;
|
|
@@ -88,11 +88,13 @@ import {
|
|
|
88
88
|
makeForbiddenChatResumeNavigationError,
|
|
89
89
|
recoverChatShell
|
|
90
90
|
} from "./page-guard.js";
|
|
91
|
-
import { getChatRoots } from "./roots.js";
|
|
92
|
-
|
|
93
|
-
const DETAIL_SOURCES = new Set(["cascade", "network", "dom", "image"]);
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
import { getChatRoots } from "./roots.js";
|
|
92
|
+
|
|
93
|
+
const DETAIL_SOURCES = new Set(["cascade", "network", "dom", "image"]);
|
|
94
|
+
const CHAT_COLLECT_CV_PER_CANDIDATE_REST_MIN_MS = 5000;
|
|
95
|
+
const CHAT_COLLECT_CV_PER_CANDIDATE_REST_MAX_MS = 8000;
|
|
96
|
+
|
|
97
|
+
function normalizeDetailSource(value) {
|
|
96
98
|
const normalized = String(value || "").trim().toLowerCase();
|
|
97
99
|
return DETAIL_SOURCES.has(normalized) ? normalized : "cascade";
|
|
98
100
|
}
|
|
@@ -939,13 +941,18 @@ export async function runChatWorkflow({
|
|
|
939
941
|
humanBehavior = null
|
|
940
942
|
} = {}, runControl) {
|
|
941
943
|
if (!client) throw new Error("runChatWorkflow requires a guarded CDP client");
|
|
942
|
-
const effectiveHumanBehavior = normalizeHumanBehaviorOptions(humanBehavior, {
|
|
943
|
-
legacyEnabled: humanRestEnabled === true || llmConfig?.humanRestEnabled === true
|
|
944
|
-
});
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
944
|
+
const effectiveHumanBehavior = normalizeHumanBehaviorOptions(humanBehavior, {
|
|
945
|
+
legacyEnabled: humanRestEnabled === true || llmConfig?.humanRestEnabled === true
|
|
946
|
+
});
|
|
947
|
+
const normalizedDetailSource = normalizeDetailSource(detailSource);
|
|
948
|
+
const normalizedScreeningMode = normalizeText(criteria) ? normalizeScreeningMode(screeningMode) : "collect_cv";
|
|
949
|
+
const collectCvOnly = normalizedScreeningMode === "collect_cv" || !normalizeText(criteria);
|
|
950
|
+
const useLlmScreening = normalizedScreeningMode === "llm" && !collectCvOnly;
|
|
951
|
+
const collectCvPerCandidateRestEnabled = collectCvOnly && effectiveHumanBehavior.enabled;
|
|
952
|
+
const effectiveHumanRestEnabled = effectiveHumanBehavior.restEnabled || collectCvPerCandidateRestEnabled;
|
|
953
|
+
configureHumanInteraction(client, {
|
|
954
|
+
enabled: effectiveHumanBehavior.enabled,
|
|
955
|
+
clickMovementEnabled: effectiveHumanBehavior.clickMovement,
|
|
949
956
|
textEntryEnabled: effectiveHumanBehavior.textEntry,
|
|
950
957
|
safeClickPointEnabled: effectiveHumanBehavior.clickMovement,
|
|
951
958
|
actionCooldownEnabled: effectiveHumanBehavior.actionCooldown
|
|
@@ -954,13 +961,12 @@ export async function runChatWorkflow({
|
|
|
954
961
|
enabled: effectiveHumanRestEnabled,
|
|
955
962
|
shortRestEnabled: effectiveHumanBehavior.shortRest,
|
|
956
963
|
batchRestEnabled: effectiveHumanBehavior.batchRest,
|
|
957
|
-
restLevel: effectiveHumanBehavior.restLevel
|
|
964
|
+
restLevel: effectiveHumanBehavior.restLevel,
|
|
965
|
+
perCandidateRestEnabled: collectCvPerCandidateRestEnabled,
|
|
966
|
+
perCandidateRestMinMs: CHAT_COLLECT_CV_PER_CANDIDATE_REST_MIN_MS,
|
|
967
|
+
perCandidateRestMaxMs: CHAT_COLLECT_CV_PER_CANDIDATE_REST_MAX_MS
|
|
958
968
|
});
|
|
959
|
-
const
|
|
960
|
-
const normalizedScreeningMode = normalizeText(criteria) ? normalizeScreeningMode(screeningMode) : "collect_cv";
|
|
961
|
-
const collectCvOnly = normalizedScreeningMode === "collect_cv" || !normalizeText(criteria);
|
|
962
|
-
const useLlmScreening = normalizedScreeningMode === "llm" && !collectCvOnly;
|
|
963
|
-
const processedLimit = Math.max(1, Number(maxCandidates) || 1);
|
|
969
|
+
const processedLimit = Math.max(1, Number(maxCandidates) || 1);
|
|
964
970
|
const passTarget = Number.isFinite(Number(targetPassCount)) && Number(targetPassCount) > 0
|
|
965
971
|
? Number(targetPassCount)
|
|
966
972
|
: null;
|
|
@@ -1177,11 +1183,14 @@ export async function runChatWorkflow({
|
|
|
1177
1183
|
viewport_checks: viewportGuard.getStats().checks,
|
|
1178
1184
|
viewport_recoveries: viewportGuard.getStats().recoveries,
|
|
1179
1185
|
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
1180
|
-
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
1181
|
-
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
1182
|
-
human_rest_enabled: effectiveHumanRestEnabled,
|
|
1183
|
-
|
|
1184
|
-
|
|
1186
|
+
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
1187
|
+
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
1188
|
+
human_rest_enabled: effectiveHumanRestEnabled,
|
|
1189
|
+
human_rest_per_candidate_enabled: collectCvPerCandidateRestEnabled,
|
|
1190
|
+
human_rest_per_candidate_min_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MIN_MS : null,
|
|
1191
|
+
human_rest_per_candidate_max_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MAX_MS : null,
|
|
1192
|
+
human_rest_count: humanRestController.getState().rest_count,
|
|
1193
|
+
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
1185
1194
|
last_human_event: lastHumanEvent
|
|
1186
1195
|
});
|
|
1187
1196
|
runControl.setPhase("chat:done");
|
|
@@ -1239,10 +1248,20 @@ export async function runChatWorkflow({
|
|
|
1239
1248
|
screening_mode: normalizedScreeningMode,
|
|
1240
1249
|
unique_seen: compactInfiniteListState(listState).seen_count,
|
|
1241
1250
|
scroll_count: 0,
|
|
1242
|
-
context_recoveries: contextRecoveryAttempts,
|
|
1243
|
-
viewport_checks: viewportGuard.getStats().checks,
|
|
1244
|
-
viewport_recoveries: viewportGuard.getStats().recoveries
|
|
1245
|
-
|
|
1251
|
+
context_recoveries: contextRecoveryAttempts,
|
|
1252
|
+
viewport_checks: viewportGuard.getStats().checks,
|
|
1253
|
+
viewport_recoveries: viewportGuard.getStats().recoveries,
|
|
1254
|
+
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
1255
|
+
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
1256
|
+
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
1257
|
+
human_rest_enabled: effectiveHumanRestEnabled,
|
|
1258
|
+
human_rest_per_candidate_enabled: collectCvPerCandidateRestEnabled,
|
|
1259
|
+
human_rest_per_candidate_min_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MIN_MS : null,
|
|
1260
|
+
human_rest_per_candidate_max_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MAX_MS : null,
|
|
1261
|
+
human_rest_count: humanRestController.getState().rest_count,
|
|
1262
|
+
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
1263
|
+
last_human_event: lastHumanEvent
|
|
1264
|
+
});
|
|
1246
1265
|
|
|
1247
1266
|
while (
|
|
1248
1267
|
results.length < processedLimit
|
|
@@ -2027,11 +2046,14 @@ export async function runChatWorkflow({
|
|
|
2027
2046
|
viewport_checks: viewportGuard.getStats().checks,
|
|
2028
2047
|
viewport_recoveries: viewportGuard.getStats().recoveries,
|
|
2029
2048
|
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
2030
|
-
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
2031
|
-
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2032
|
-
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2033
|
-
|
|
2034
|
-
|
|
2049
|
+
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
2050
|
+
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2051
|
+
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2052
|
+
human_rest_per_candidate_enabled: collectCvPerCandidateRestEnabled,
|
|
2053
|
+
human_rest_per_candidate_min_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MIN_MS : null,
|
|
2054
|
+
human_rest_per_candidate_max_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MAX_MS : null,
|
|
2055
|
+
human_rest_count: humanRestController.getState().rest_count,
|
|
2056
|
+
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
2035
2057
|
last_human_event: lastHumanEvent,
|
|
2036
2058
|
last_candidate_id: screeningCandidate.id || null,
|
|
2037
2059
|
last_candidate_key: candidateKey,
|
|
@@ -2071,10 +2093,11 @@ export async function runChatWorkflow({
|
|
|
2071
2093
|
addTiming(compactResult.timings, "human_rest_ms", restElapsed);
|
|
2072
2094
|
compactResult.timings.total_ms = Date.now() - candidateStarted;
|
|
2073
2095
|
runControl.updateProgress({
|
|
2074
|
-
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2075
|
-
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2076
|
-
|
|
2077
|
-
|
|
2096
|
+
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2097
|
+
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2098
|
+
human_rest_per_candidate_enabled: collectCvPerCandidateRestEnabled,
|
|
2099
|
+
human_rest_count: humanRestController.getState().rest_count,
|
|
2100
|
+
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
2078
2101
|
human_rest_last: restResult,
|
|
2079
2102
|
context_recoveries: contextRecoveryAttempts,
|
|
2080
2103
|
last_human_event: lastHumanEvent
|
|
@@ -2175,12 +2198,14 @@ export function createChatRunService({
|
|
|
2175
2198
|
if (!client) throw new Error("startChatRun requires a guarded CDP client");
|
|
2176
2199
|
const normalizedDetailSource = normalizeDetailSource(detailSource);
|
|
2177
2200
|
const normalizedScreeningMode = normalizeText(criteria) ? normalizeScreeningMode(screeningMode) : "collect_cv";
|
|
2178
|
-
const
|
|
2179
|
-
const
|
|
2180
|
-
const
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2201
|
+
const collectCvOnly = normalizedScreeningMode === "collect_cv" || !normalizeText(criteria);
|
|
2202
|
+
const processedLimit = Math.max(1, Number(maxCandidates) || 1);
|
|
2203
|
+
const normalizedDetailLimit = detailLimit == null ? processedLimit : Math.max(0, Number(detailLimit) || 0);
|
|
2204
|
+
const effectiveHumanBehavior = normalizeHumanBehaviorOptions(humanBehavior, {
|
|
2205
|
+
legacyEnabled: humanRestEnabled === true || llmConfig?.humanRestEnabled === true
|
|
2206
|
+
});
|
|
2207
|
+
const collectCvPerCandidateRestEnabled = collectCvOnly && effectiveHumanBehavior.enabled;
|
|
2208
|
+
const effectiveHumanRestEnabled = effectiveHumanBehavior.restEnabled || collectCvPerCandidateRestEnabled;
|
|
2184
2209
|
return manager.startRun({
|
|
2185
2210
|
runId,
|
|
2186
2211
|
name,
|
|
@@ -2206,10 +2231,10 @@ export function createChatRunService({
|
|
|
2206
2231
|
llm_configured: Boolean(llmConfig),
|
|
2207
2232
|
llm_timeout_ms: llmTimeoutMs,
|
|
2208
2233
|
llm_image_limit: llmImageLimit,
|
|
2209
|
-
llm_image_detail: llmImageDetail,
|
|
2210
|
-
max_image_pages: maxImagePages,
|
|
2211
|
-
image_wheel_delta_y: imageWheelDeltaY,
|
|
2212
|
-
list_max_scrolls: listMaxScrolls,
|
|
2234
|
+
llm_image_detail: llmImageDetail,
|
|
2235
|
+
max_image_pages: maxImagePages,
|
|
2236
|
+
image_wheel_delta_y: imageWheelDeltaY,
|
|
2237
|
+
list_max_scrolls: listMaxScrolls,
|
|
2213
2238
|
list_stable_signature_limit: listStableSignatureLimit,
|
|
2214
2239
|
list_wheel_delta_y: listWheelDeltaY,
|
|
2215
2240
|
list_settle_ms: listSettleMs,
|
|
@@ -2221,7 +2246,9 @@ export function createChatRunService({
|
|
|
2221
2246
|
human_behavior: effectiveHumanBehavior,
|
|
2222
2247
|
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2223
2248
|
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2224
|
-
|
|
2249
|
+
human_rest_per_candidate_enabled: collectCvPerCandidateRestEnabled,
|
|
2250
|
+
human_rest_per_candidate_min_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MIN_MS : null,
|
|
2251
|
+
human_rest_per_candidate_max_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MAX_MS : null
|
|
2225
2252
|
},
|
|
2226
2253
|
progress: {
|
|
2227
2254
|
card_count: 0,
|
|
@@ -2239,10 +2266,13 @@ export function createChatRunService({
|
|
|
2239
2266
|
request_skipped: 0,
|
|
2240
2267
|
context_recoveries: 0,
|
|
2241
2268
|
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
2242
|
-
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
2243
|
-
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2244
|
-
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2245
|
-
|
|
2269
|
+
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
2270
|
+
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2271
|
+
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2272
|
+
human_rest_per_candidate_enabled: collectCvPerCandidateRestEnabled,
|
|
2273
|
+
human_rest_per_candidate_min_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MIN_MS : null,
|
|
2274
|
+
human_rest_per_candidate_max_ms: collectCvPerCandidateRestEnabled ? CHAT_COLLECT_CV_PER_CANDIDATE_REST_MAX_MS : null,
|
|
2275
|
+
human_rest_count: 0,
|
|
2246
2276
|
human_rest_ms: 0,
|
|
2247
2277
|
last_human_event: null
|
|
2248
2278
|
},
|
package/src/recommend-mcp.js
CHANGED
|
@@ -54,6 +54,7 @@ import { DEFAULT_MAX_IMAGE_PAGES } from "./core/cv-acquisition/index.js";
|
|
|
54
54
|
const DEFAULT_RECOMMEND_HOST = "127.0.0.1";
|
|
55
55
|
const DEFAULT_RECOMMEND_PORT = 9222;
|
|
56
56
|
const DEFAULT_RECOMMEND_POLL_AFTER_SEC = 10;
|
|
57
|
+
const STATUS_METHOD_LOG_TAIL_LIMIT = 25;
|
|
57
58
|
const TARGET_COUNT_SEMANTICS = "target_count means candidates that pass screening; scan continues until that many candidates pass or the list ends";
|
|
58
59
|
const RUN_MODE_ASYNC = "async";
|
|
59
60
|
const REST_LEVEL_OPTIONS = ["low", "medium", "high"];
|
|
@@ -302,15 +303,23 @@ function resolveRecommendDetailLimit(args = {}, normalized = {}) {
|
|
|
302
303
|
return requested;
|
|
303
304
|
}
|
|
304
305
|
|
|
305
|
-
function methodSummary(methodLog = []) {
|
|
306
|
+
function methodSummary(methodLog = []) {
|
|
306
307
|
const summary = {};
|
|
307
308
|
for (const entry of methodLog || []) {
|
|
308
309
|
summary[entry.method] = (summary[entry.method] || 0) + 1;
|
|
309
310
|
}
|
|
310
|
-
return summary;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function
|
|
311
|
+
return summary;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function compactMethodLogForStatus(methodLog = []) {
|
|
315
|
+
if (!Array.isArray(methodLog)) return [];
|
|
316
|
+
return methodLog.slice(-STATUS_METHOD_LOG_TAIL_LIMIT).map((entry) => ({
|
|
317
|
+
method: normalizeText(entry?.method || entry || ""),
|
|
318
|
+
at: normalizeText(entry?.at || "")
|
|
319
|
+
}));
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function clonePlain(value, fallback = null) {
|
|
314
323
|
try {
|
|
315
324
|
return value === undefined ? fallback : JSON.parse(JSON.stringify(value));
|
|
316
325
|
} catch {
|
|
@@ -477,7 +486,7 @@ function secondsBetween(startedAt, endedAt) {
|
|
|
477
486
|
return Math.max(1, Math.round((endMs - startMs) / 1000));
|
|
478
487
|
}
|
|
479
488
|
|
|
480
|
-
function normalizeLegacyProgress(progress = {}, summary = null) {
|
|
489
|
+
function normalizeLegacyProgress(progress = {}, summary = null) {
|
|
481
490
|
const processed = Number.isInteger(progress.processed)
|
|
482
491
|
? progress.processed
|
|
483
492
|
: Number.isInteger(summary?.processed)
|
|
@@ -502,12 +511,146 @@ function normalizeLegacyProgress(progress = {}, summary = null) {
|
|
|
502
511
|
skipped: Number.isInteger(progress.skipped) ? progress.skipped : Math.max(processed - passed, 0),
|
|
503
512
|
greet_count: Number.isInteger(progress.greet_count) ? progress.greet_count : 0,
|
|
504
513
|
post_action_clicked: Number.isInteger(progress.post_action_clicked) ? progress.post_action_clicked : 0
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const STATUS_COUNT_KEYS = [
|
|
518
|
+
"processed",
|
|
519
|
+
"screened",
|
|
520
|
+
"detail_opened",
|
|
521
|
+
"passed",
|
|
522
|
+
"skipped",
|
|
523
|
+
"llm_screened",
|
|
524
|
+
"greet_count",
|
|
525
|
+
"post_action_clicked",
|
|
526
|
+
"image_capture_failed",
|
|
527
|
+
"detail_open_failed",
|
|
528
|
+
"transient_recovered",
|
|
529
|
+
"colleague_contact_checked",
|
|
530
|
+
"recent_colleague_contact_skipped",
|
|
531
|
+
"colleague_contact_panel_missing",
|
|
532
|
+
"context_recoveries",
|
|
533
|
+
"human_rest_count",
|
|
534
|
+
"human_rest_ms",
|
|
535
|
+
"card_count",
|
|
536
|
+
"refresh_rounds"
|
|
537
|
+
];
|
|
538
|
+
|
|
539
|
+
function compactPositiveInteger(value, fallback = null) {
|
|
540
|
+
return Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function compactSmallRecord(value, fallback = null) {
|
|
544
|
+
const record = plainRecord(value);
|
|
545
|
+
if (!Object.keys(record).length) return fallback;
|
|
546
|
+
return clonePlain(record, fallback);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function compactRecommendSummaryForStatus(summary) {
|
|
550
|
+
if (!summary || typeof summary !== "object" || Array.isArray(summary)) return null;
|
|
551
|
+
const compact = {
|
|
552
|
+
domain: normalizeText(summary.domain || "recommend") || "recommend"
|
|
553
|
+
};
|
|
554
|
+
for (const key of STATUS_COUNT_KEYS) {
|
|
555
|
+
if (Number.isInteger(summary[key])) compact[key] = summary[key];
|
|
556
|
+
}
|
|
557
|
+
if (summary.target_url) compact.target_url = normalizeText(summary.target_url);
|
|
558
|
+
if (summary.list_end_reason) compact.list_end_reason = normalizeText(summary.list_end_reason);
|
|
559
|
+
if (Array.isArray(summary.results)) {
|
|
560
|
+
compact.results_count = summary.results.length;
|
|
561
|
+
} else if (Number.isInteger(summary.results_count)) {
|
|
562
|
+
compact.results_count = summary.results_count;
|
|
563
|
+
}
|
|
564
|
+
if (Array.isArray(summary.refresh_attempts)) {
|
|
565
|
+
compact.refresh_attempt_count = summary.refresh_attempts.length;
|
|
566
|
+
}
|
|
567
|
+
if (Array.isArray(summary.context_recoveries)) {
|
|
568
|
+
compact.context_recovery_count = summary.context_recoveries.length;
|
|
569
|
+
} else if (Number.isInteger(summary.context_recoveries)) {
|
|
570
|
+
compact.context_recoveries = summary.context_recoveries;
|
|
571
|
+
}
|
|
572
|
+
if (summary.job_selection) compact.job_selection = compactSmallRecord(summary.job_selection);
|
|
573
|
+
if (summary.page_scope) compact.page_scope = compactSmallRecord(summary.page_scope);
|
|
574
|
+
if (summary.filter) compact.filter = compactSmallRecord(summary.filter);
|
|
575
|
+
if (summary.candidate_list) {
|
|
576
|
+
const candidateList = plainRecord(summary.candidate_list);
|
|
577
|
+
compact.candidate_list = {
|
|
578
|
+
total_count: compactPositiveInteger(candidateList.total_count ?? candidateList.card_count, null),
|
|
579
|
+
visible_count: compactPositiveInteger(candidateList.visible_count, null),
|
|
580
|
+
list_end_reason: normalizeText(candidateList.list_end_reason || "")
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
if (summary.viewport_health?.stats) {
|
|
584
|
+
compact.viewport_health = {
|
|
585
|
+
stats: clonePlain(summary.viewport_health.stats, {})
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
if (summary.human_behavior) {
|
|
589
|
+
compact.human_behavior = {
|
|
590
|
+
enabled: summary.human_behavior.enabled === true,
|
|
591
|
+
profile: normalizeText(summary.human_behavior.profile || ""),
|
|
592
|
+
restLevel: normalizeText(summary.human_behavior.restLevel || summary.human_behavior.rest_level || "")
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
if (summary.human_rest) {
|
|
596
|
+
const humanRest = plainRecord(summary.human_rest);
|
|
597
|
+
compact.human_rest = {
|
|
598
|
+
enabled: humanRest.enabled === true,
|
|
599
|
+
restLevel: normalizeText(humanRest.restLevel || humanRest.rest_level || ""),
|
|
600
|
+
rest_count: compactPositiveInteger(humanRest.rest_count ?? humanRest.count, null),
|
|
601
|
+
total_pause_ms: compactPositiveInteger(humanRest.total_pause_ms ?? humanRest.pause_ms, null)
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
return compact;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function compactRecommendCheckpointForStatus(checkpoint) {
|
|
608
|
+
if (!checkpoint || typeof checkpoint !== "object" || Array.isArray(checkpoint)) return {};
|
|
609
|
+
const compact = {};
|
|
610
|
+
if (checkpoint.updatedAt || checkpoint.updated_at) {
|
|
611
|
+
compact.updatedAt = normalizeText(checkpoint.updatedAt || checkpoint.updated_at);
|
|
612
|
+
}
|
|
613
|
+
if (Array.isArray(checkpoint.results)) {
|
|
614
|
+
compact.results_count = checkpoint.results.length;
|
|
615
|
+
} else if (Number.isInteger(checkpoint.results_count)) {
|
|
616
|
+
compact.results_count = checkpoint.results_count;
|
|
617
|
+
}
|
|
618
|
+
for (const key of STATUS_COUNT_KEYS) {
|
|
619
|
+
if (Number.isInteger(checkpoint[key])) compact[key] = checkpoint[key];
|
|
620
|
+
}
|
|
621
|
+
return compact;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function compactRecommendResultForStatus(result) {
|
|
625
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) return result || null;
|
|
626
|
+
const compact = {
|
|
627
|
+
...result
|
|
628
|
+
};
|
|
629
|
+
if (Array.isArray(result.results)) {
|
|
630
|
+
compact.results_count = result.results.length;
|
|
631
|
+
compact.results_available = result.results.length > 0;
|
|
632
|
+
} else if (Number.isInteger(result.results_count)) {
|
|
633
|
+
compact.results_count = result.results_count;
|
|
634
|
+
compact.results_available = result.results_available === true || result.results_count > 0;
|
|
635
|
+
}
|
|
636
|
+
delete compact.results;
|
|
637
|
+
return compact;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
export function compactRecommendRunForStatus(run) {
|
|
641
|
+
if (!run || typeof run !== "object" || Array.isArray(run)) return run || null;
|
|
642
|
+
const compact = {
|
|
643
|
+
...run
|
|
644
|
+
};
|
|
645
|
+
if (compact.result) compact.result = compactRecommendResultForStatus(compact.result);
|
|
646
|
+
if (compact.summary) compact.summary = compactRecommendSummaryForStatus(compact.summary);
|
|
647
|
+
if (compact.checkpoint) compact.checkpoint = compactRecommendCheckpointForStatus(compact.checkpoint);
|
|
648
|
+
return compact;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function completionReason(status) {
|
|
652
|
+
if (status === RUN_STATUS_COMPLETED) return "completed";
|
|
653
|
+
if (status === RUN_STATUS_CANCELED) return "canceled_by_user";
|
|
511
654
|
if (status === RUN_STATUS_FAILED) return "failed";
|
|
512
655
|
if (status === RUN_STATUS_PAUSED) return "paused";
|
|
513
656
|
return null;
|
|
@@ -685,13 +828,14 @@ function buildLegacyRecommendResult(snapshot) {
|
|
|
685
828
|
effective_scope: meta.normalized?.pageScope || meta.parsed?.page_scope || "recommend"
|
|
686
829
|
},
|
|
687
830
|
search_params: clonePlain(meta.parsed?.searchParams || {}, {}),
|
|
688
|
-
screen_params: clonePlain(meta.parsed?.screenParams || {}, {}),
|
|
689
|
-
target_count_semantics: TARGET_COUNT_SEMANTICS,
|
|
690
|
-
error: snapshot.error || null,
|
|
691
|
-
recovery: buildConstrainedAgentRecovery(snapshot, meta, artifacts),
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
}
|
|
831
|
+
screen_params: clonePlain(meta.parsed?.screenParams || {}, {}),
|
|
832
|
+
target_count_semantics: TARGET_COUNT_SEMANTICS,
|
|
833
|
+
error: snapshot.error || null,
|
|
834
|
+
recovery: buildConstrainedAgentRecovery(snapshot, meta, artifacts),
|
|
835
|
+
results_count: resultRows.length,
|
|
836
|
+
results_available: resultRows.length > 0
|
|
837
|
+
};
|
|
838
|
+
}
|
|
695
839
|
|
|
696
840
|
function normalizeRunSnapshot(snapshot) {
|
|
697
841
|
if (!snapshot) return null;
|
|
@@ -714,10 +858,12 @@ function normalizeRunSnapshot(snapshot) {
|
|
|
714
858
|
follow_up: clonePlain(metaArgs.follow_up ?? snapshotContext.follow_up ?? null, null),
|
|
715
859
|
target_count_semantics: TARGET_COUNT_SEMANTICS
|
|
716
860
|
};
|
|
717
|
-
return {
|
|
718
|
-
...snapshot,
|
|
719
|
-
|
|
720
|
-
|
|
861
|
+
return {
|
|
862
|
+
...snapshot,
|
|
863
|
+
checkpoint: compactRecommendCheckpointForStatus(snapshot.checkpoint),
|
|
864
|
+
summary: compactRecommendSummaryForStatus(summary),
|
|
865
|
+
progress,
|
|
866
|
+
run_id: snapshot.runId,
|
|
721
867
|
mode: RUN_MODE_ASYNC,
|
|
722
868
|
state: snapshot.status,
|
|
723
869
|
stage: snapshot.phase,
|
|
@@ -874,7 +1020,7 @@ function persistRecommendRunSnapshot(snapshot, {
|
|
|
874
1020
|
normalized.control = mergePersistedControlRequest(normalized, existing);
|
|
875
1021
|
normalized = coerceCanceledTerminalSnapshot(normalized, existing);
|
|
876
1022
|
if (persistActiveCheckpoint) {
|
|
877
|
-
persistRecommendCheckpointSnapshot(
|
|
1023
|
+
persistRecommendCheckpointSnapshot(snapshot);
|
|
878
1024
|
}
|
|
879
1025
|
const payload = {
|
|
880
1026
|
run_id: normalized.run_id,
|
|
@@ -970,17 +1116,19 @@ function persistRecommendLifecycleSnapshot(snapshot, event = {}) {
|
|
|
970
1116
|
});
|
|
971
1117
|
}
|
|
972
1118
|
|
|
973
|
-
function attachMethodEvidence(payload, runId) {
|
|
974
|
-
const meta = getRecommendRunMeta(runId);
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1119
|
+
function attachMethodEvidence(payload, runId) {
|
|
1120
|
+
const meta = getRecommendRunMeta(runId);
|
|
1121
|
+
const methodLog = meta.methodLog || [];
|
|
1122
|
+
assertNoForbiddenCdpCalls(methodLog);
|
|
1123
|
+
return {
|
|
1124
|
+
...payload,
|
|
1125
|
+
runtime_evaluate_used: false,
|
|
1126
|
+
method_summary: methodSummary(methodLog),
|
|
1127
|
+
method_log: compactMethodLogForStatus(methodLog),
|
|
1128
|
+
method_log_total: Array.isArray(methodLog) ? methodLog.length : 0,
|
|
1129
|
+
chrome: meta.chrome || null
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
984
1132
|
|
|
985
1133
|
function compactRecommendJobListOption(option, index) {
|
|
986
1134
|
const label = normalizeText(option?.label);
|
|
@@ -1945,19 +2093,19 @@ export function getRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
1945
2093
|
};
|
|
1946
2094
|
}
|
|
1947
2095
|
try {
|
|
1948
|
-
const run = recommendRunService.getRecommendRun(runId);
|
|
1949
|
-
const normalizedRun = persistRecommendRunSnapshot(run);
|
|
1950
|
-
return attachMethodEvidence({
|
|
1951
|
-
status: "RUN_STATUS",
|
|
1952
|
-
run: normalizedRun
|
|
1953
|
-
}, runId);
|
|
1954
|
-
} catch {
|
|
1955
|
-
const persisted = readRecommendRunState(runId);
|
|
1956
|
-
if (persisted) {
|
|
1957
|
-
const reconciled = reconcilePersistedRecommendRunIfNeeded(persisted);
|
|
1958
|
-
return {
|
|
1959
|
-
status: "RUN_STATUS",
|
|
1960
|
-
run: reconciled,
|
|
2096
|
+
const run = recommendRunService.getRecommendRun(runId);
|
|
2097
|
+
const normalizedRun = persistRecommendRunSnapshot(run);
|
|
2098
|
+
return attachMethodEvidence({
|
|
2099
|
+
status: "RUN_STATUS",
|
|
2100
|
+
run: compactRecommendRunForStatus(normalizedRun)
|
|
2101
|
+
}, runId);
|
|
2102
|
+
} catch {
|
|
2103
|
+
const persisted = readRecommendRunState(runId);
|
|
2104
|
+
if (persisted) {
|
|
2105
|
+
const reconciled = compactRecommendRunForStatus(reconcilePersistedRecommendRunIfNeeded(persisted));
|
|
2106
|
+
return {
|
|
2107
|
+
status: "RUN_STATUS",
|
|
2108
|
+
run: reconciled,
|
|
1961
2109
|
persistence: {
|
|
1962
2110
|
source: "disk",
|
|
1963
2111
|
active_control_available: false,
|
|
@@ -1985,36 +2133,36 @@ export function pauseRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
1985
2133
|
try {
|
|
1986
2134
|
const before = recommendRunService.getRecommendRun(runId);
|
|
1987
2135
|
if (TERMINAL_STATUSES.has(before.status)) {
|
|
1988
|
-
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
1989
|
-
return attachMethodEvidence({
|
|
1990
|
-
status: "PAUSE_IGNORED",
|
|
1991
|
-
run: normalizedBefore,
|
|
1992
|
-
message: "目标任务已结束,无需暂停。"
|
|
1993
|
-
}, runId);
|
|
2136
|
+
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
2137
|
+
return attachMethodEvidence({
|
|
2138
|
+
status: "PAUSE_IGNORED",
|
|
2139
|
+
run: compactRecommendRunForStatus(normalizedBefore),
|
|
2140
|
+
message: "目标任务已结束,无需暂停。"
|
|
2141
|
+
}, runId);
|
|
1994
2142
|
}
|
|
1995
2143
|
if (before.status === RUN_STATUS_PAUSED) {
|
|
1996
|
-
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
1997
|
-
return attachMethodEvidence({
|
|
1998
|
-
status: "PAUSE_IGNORED",
|
|
1999
|
-
run: normalizedBefore,
|
|
2000
|
-
message: "目标任务已经处于 paused 状态。"
|
|
2001
|
-
}, runId);
|
|
2144
|
+
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
2145
|
+
return attachMethodEvidence({
|
|
2146
|
+
status: "PAUSE_IGNORED",
|
|
2147
|
+
run: compactRecommendRunForStatus(normalizedBefore),
|
|
2148
|
+
message: "目标任务已经处于 paused 状态。"
|
|
2149
|
+
}, runId);
|
|
2002
2150
|
}
|
|
2003
2151
|
const run = recommendRunService.pauseRecommendRun(runId);
|
|
2004
|
-
const normalizedRun = persistRecommendRunSnapshot(run);
|
|
2005
|
-
return attachMethodEvidence({
|
|
2006
|
-
status: "PAUSE_REQUESTED",
|
|
2007
|
-
run: normalizedRun,
|
|
2008
|
-
message: "暂停请求已接收,将在当前候选人处理完成后进入 paused。"
|
|
2009
|
-
}, runId);
|
|
2152
|
+
const normalizedRun = persistRecommendRunSnapshot(run);
|
|
2153
|
+
return attachMethodEvidence({
|
|
2154
|
+
status: "PAUSE_REQUESTED",
|
|
2155
|
+
run: compactRecommendRunForStatus(normalizedRun),
|
|
2156
|
+
message: "暂停请求已接收,将在当前候选人处理完成后进入 paused。"
|
|
2157
|
+
}, runId);
|
|
2010
2158
|
} catch {
|
|
2011
2159
|
const persisted = readRecommendRunState(runId);
|
|
2012
2160
|
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2013
|
-
return {
|
|
2014
|
-
status: "PAUSE_IGNORED",
|
|
2015
|
-
run: persisted,
|
|
2016
|
-
message: "目标任务已结束,无需暂停。",
|
|
2017
|
-
runtime_evaluate_used: false,
|
|
2161
|
+
return {
|
|
2162
|
+
status: "PAUSE_IGNORED",
|
|
2163
|
+
run: compactRecommendRunForStatus(persisted),
|
|
2164
|
+
message: "目标任务已结束,无需暂停。",
|
|
2165
|
+
runtime_evaluate_used: false,
|
|
2018
2166
|
method_summary: {},
|
|
2019
2167
|
method_log: [],
|
|
2020
2168
|
chrome: null
|
|
@@ -2029,28 +2177,28 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2029
2177
|
try {
|
|
2030
2178
|
const before = recommendRunService.getRecommendRun(runId);
|
|
2031
2179
|
if (TERMINAL_STATUSES.has(before.status)) {
|
|
2032
|
-
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
2033
|
-
return attachMethodEvidence({
|
|
2034
|
-
status: "FAILED",
|
|
2180
|
+
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
2181
|
+
return attachMethodEvidence({
|
|
2182
|
+
status: "FAILED",
|
|
2035
2183
|
error: {
|
|
2036
2184
|
code: "RUN_ALREADY_TERMINATED",
|
|
2037
2185
|
message: "目标任务已结束,无法继续。",
|
|
2038
2186
|
retryable: false
|
|
2039
2187
|
},
|
|
2040
|
-
run: normalizedBefore
|
|
2041
|
-
}, runId);
|
|
2188
|
+
run: compactRecommendRunForStatus(normalizedBefore)
|
|
2189
|
+
}, runId);
|
|
2042
2190
|
}
|
|
2043
2191
|
if (before.status !== RUN_STATUS_PAUSED) {
|
|
2044
|
-
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
2045
|
-
return attachMethodEvidence({
|
|
2046
|
-
status: "FAILED",
|
|
2192
|
+
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
2193
|
+
return attachMethodEvidence({
|
|
2194
|
+
status: "FAILED",
|
|
2047
2195
|
error: {
|
|
2048
2196
|
code: "RUN_NOT_PAUSED",
|
|
2049
2197
|
message: "仅 paused 状态的 run 才能继续。",
|
|
2050
2198
|
retryable: true
|
|
2051
2199
|
},
|
|
2052
|
-
run: normalizedBefore
|
|
2053
|
-
}, runId);
|
|
2200
|
+
run: compactRecommendRunForStatus(normalizedBefore)
|
|
2201
|
+
}, runId);
|
|
2054
2202
|
}
|
|
2055
2203
|
const run = recommendRunService.resumeRecommendRun(runId);
|
|
2056
2204
|
const meta = getRecommendRunMeta(runId);
|
|
@@ -2058,12 +2206,12 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2058
2206
|
meta.resumeCount = (meta.resumeCount || 0) + 1;
|
|
2059
2207
|
meta.lastResumedAt = new Date().toISOString();
|
|
2060
2208
|
}
|
|
2061
|
-
const normalizedRun = persistRecommendRunSnapshot(run);
|
|
2062
|
-
return attachMethodEvidence({
|
|
2063
|
-
status: "RESUME_REQUESTED",
|
|
2064
|
-
run: normalizedRun,
|
|
2065
|
-
poll_after_sec: DEFAULT_RECOMMEND_POLL_AFTER_SEC,
|
|
2066
|
-
message: "已恢复 Recommend run,请使用 get_recommend_pipeline_run 按需轮询。"
|
|
2209
|
+
const normalizedRun = persistRecommendRunSnapshot(run);
|
|
2210
|
+
return attachMethodEvidence({
|
|
2211
|
+
status: "RESUME_REQUESTED",
|
|
2212
|
+
run: compactRecommendRunForStatus(normalizedRun),
|
|
2213
|
+
poll_after_sec: DEFAULT_RECOMMEND_POLL_AFTER_SEC,
|
|
2214
|
+
message: "已恢复 Recommend run,请使用 get_recommend_pipeline_run 按需轮询。"
|
|
2067
2215
|
}, runId);
|
|
2068
2216
|
} catch {
|
|
2069
2217
|
const persisted = readRecommendRunState(runId);
|
|
@@ -2077,9 +2225,9 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2077
2225
|
: "该 run 只有磁盘快照,没有当前进程内的活动 CDP 会话,无法安全继续。",
|
|
2078
2226
|
retryable: !TERMINAL_STATUSES.has(persisted.state)
|
|
2079
2227
|
},
|
|
2080
|
-
run: persisted,
|
|
2081
|
-
persistence: {
|
|
2082
|
-
source: "disk",
|
|
2228
|
+
run: compactRecommendRunForStatus(persisted),
|
|
2229
|
+
persistence: {
|
|
2230
|
+
source: "disk",
|
|
2083
2231
|
active_control_available: false
|
|
2084
2232
|
},
|
|
2085
2233
|
runtime_evaluate_used: false,
|
|
@@ -2097,28 +2245,28 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2097
2245
|
try {
|
|
2098
2246
|
const before = recommendRunService.getRecommendRun(runId);
|
|
2099
2247
|
if (TERMINAL_STATUSES.has(before.status)) {
|
|
2100
|
-
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
2101
|
-
return attachMethodEvidence({
|
|
2102
|
-
status: "CANCEL_IGNORED",
|
|
2103
|
-
run: normalizedBefore,
|
|
2104
|
-
message: "目标任务已结束,无需取消。"
|
|
2105
|
-
}, runId);
|
|
2248
|
+
const normalizedBefore = persistRecommendRunSnapshot(before);
|
|
2249
|
+
return attachMethodEvidence({
|
|
2250
|
+
status: "CANCEL_IGNORED",
|
|
2251
|
+
run: compactRecommendRunForStatus(normalizedBefore),
|
|
2252
|
+
message: "目标任务已结束,无需取消。"
|
|
2253
|
+
}, runId);
|
|
2106
2254
|
}
|
|
2107
2255
|
const run = recommendRunService.cancelRecommendRun(runId);
|
|
2108
|
-
const normalizedRun = persistRecommendRunSnapshot(run);
|
|
2109
|
-
return attachMethodEvidence({
|
|
2110
|
-
status: "CANCEL_REQUESTED",
|
|
2111
|
-
run: normalizedRun,
|
|
2112
|
-
message: "已收到取消请求,将在当前候选人处理完成后安全停止。"
|
|
2113
|
-
}, runId);
|
|
2256
|
+
const normalizedRun = persistRecommendRunSnapshot(run);
|
|
2257
|
+
return attachMethodEvidence({
|
|
2258
|
+
status: "CANCEL_REQUESTED",
|
|
2259
|
+
run: compactRecommendRunForStatus(normalizedRun),
|
|
2260
|
+
message: "已收到取消请求,将在当前候选人处理完成后安全停止。"
|
|
2261
|
+
}, runId);
|
|
2114
2262
|
} catch {
|
|
2115
2263
|
const persisted = readRecommendRunState(runId);
|
|
2116
2264
|
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2117
2265
|
return {
|
|
2118
2266
|
status: "CANCEL_IGNORED",
|
|
2119
|
-
run: persisted,
|
|
2267
|
+
run: compactRecommendRunForStatus(persisted),
|
|
2120
2268
|
message: "目标任务已结束,无需取消。",
|
|
2121
|
-
runtime_evaluate_used: false,
|
|
2269
|
+
runtime_evaluate_used: false,
|
|
2122
2270
|
method_summary: {},
|
|
2123
2271
|
method_log: [],
|
|
2124
2272
|
chrome: null
|
|
@@ -2136,7 +2284,7 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2136
2284
|
if (patched) {
|
|
2137
2285
|
return {
|
|
2138
2286
|
status: "CANCEL_REQUESTED",
|
|
2139
|
-
run: patched,
|
|
2287
|
+
run: compactRecommendRunForStatus(patched),
|
|
2140
2288
|
message: cancelMessage,
|
|
2141
2289
|
persistence: {
|
|
2142
2290
|
source: "disk",
|
|
@@ -5,6 +5,7 @@ import { spawn } from "node:child_process";
|
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { getStateHome } from "./run-state.js";
|
|
7
7
|
import {
|
|
8
|
+
compactRecommendRunForStatus,
|
|
8
9
|
getRecommendPipelineRunTool,
|
|
9
10
|
prepareRecommendPipelineRunTool,
|
|
10
11
|
startRecommendPipelineRunTool
|
|
@@ -142,6 +143,19 @@ function writeSchedule(scheduleId, patch) {
|
|
|
142
143
|
});
|
|
143
144
|
}
|
|
144
145
|
|
|
146
|
+
function compactScheduleForStatus(schedule) {
|
|
147
|
+
if (!schedule || typeof schedule !== "object" || Array.isArray(schedule)) return schedule || null;
|
|
148
|
+
const compact = clonePlain(schedule, schedule);
|
|
149
|
+
if (compact.run) compact.run = compactRecommendRunForStatus(compact.run);
|
|
150
|
+
if (compact.launch_payload?.run) {
|
|
151
|
+
compact.launch_payload = {
|
|
152
|
+
...compact.launch_payload,
|
|
153
|
+
run: compactRecommendRunForStatus(compact.launch_payload.run)
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return compact;
|
|
157
|
+
}
|
|
158
|
+
|
|
145
159
|
function isProcessAlive(pid) {
|
|
146
160
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
147
161
|
try {
|
|
@@ -355,7 +369,7 @@ export function getRecommendScheduledRunTool({ args = {} } = {}) {
|
|
|
355
369
|
return {
|
|
356
370
|
status: "OK",
|
|
357
371
|
schedule_id: scheduleId,
|
|
358
|
-
schedule: next
|
|
372
|
+
schedule: compactScheduleForStatus(next)
|
|
359
373
|
};
|
|
360
374
|
}
|
|
361
375
|
|