@reconcrap/boss-recommend-mcp 2.1.20 → 2.1.22
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 +5 -2
- package/bin/boss-recommend-mcp.js +4 -4
- package/config/screening-config.example.json +33 -33
- package/package.json +8 -8
- package/scripts/install-macos.sh +280 -280
- package/scripts/postinstall.cjs +44 -44
- package/skills/boss-chat/README.md +42 -42
- package/skills/boss-chat/SKILL.md +106 -106
- package/skills/boss-recommend-pipeline/README.md +13 -13
- package/skills/boss-recommend-pipeline/SKILL.md +219 -214
- package/skills/boss-recruit-pipeline/README.md +19 -19
- package/skills/boss-recruit-pipeline/SKILL.md +89 -89
- package/src/chat-mcp.js +127 -127
- package/src/chat-runtime-config.js +775 -775
- package/src/cli.js +573 -573
- package/src/core/boss-cards/index.js +199 -199
- package/src/core/browser/index.js +2419 -2372
- package/src/core/capture/index.js +1201 -1201
- package/src/core/cv-acquisition/index.js +238 -238
- package/src/core/cv-capture-target/index.js +299 -299
- package/src/core/greet-quota/index.js +71 -71
- package/src/core/infinite-list/index.js +1326 -1326
- package/src/core/reporting/legacy-csv.js +334 -332
- package/src/core/run/index.js +32 -32
- package/src/core/run/timing.js +33 -33
- package/src/core/screening/index.js +2135 -2135
- package/src/core/self-heal/index.js +973 -973
- package/src/core/self-heal/viewport.js +564 -564
- package/src/detached-worker.js +99 -99
- package/src/domains/chat/cards.js +137 -137
- package/src/domains/chat/constants.js +9 -9
- package/src/domains/chat/detail.js +113 -113
- package/src/domains/chat/index.js +7 -7
- package/src/domains/chat/jobs.js +620 -620
- package/src/domains/chat/page-guard.js +122 -122
- package/src/domains/chat/roots.js +56 -56
- package/src/domains/chat/run-service.js +529 -499
- package/src/domains/common/account-rights-panel.js +314 -314
- package/src/domains/common/recovery-settle.js +159 -159
- package/src/domains/recommend/actions.js +472 -472
- package/src/domains/recommend/cards.js +243 -243
- package/src/domains/recommend/colleague-contact.js +333 -333
- package/src/domains/recommend/constants.js +228 -159
- package/src/domains/recommend/detail.js +650 -650
- package/src/domains/recommend/filters.js +748 -377
- package/src/domains/recommend/index.js +4 -3
- package/src/domains/recommend/jobs.js +542 -542
- package/src/domains/recommend/location.js +736 -0
- package/src/domains/recommend/refresh.js +504 -361
- package/src/domains/recommend/roots.js +80 -80
- package/src/domains/recommend/run-service.js +987 -854
- package/src/domains/recommend/scopes.js +246 -246
- package/src/domains/recruit/actions.js +277 -277
- package/src/domains/recruit/cards.js +74 -74
- package/src/domains/recruit/constants.js +236 -236
- package/src/domains/recruit/detail.js +588 -588
- package/src/domains/recruit/index.js +9 -9
- package/src/domains/recruit/instruction-parser.js +866 -866
- package/src/domains/recruit/refresh.js +45 -45
- package/src/domains/recruit/roots.js +68 -68
- package/src/domains/recruit/run-service.js +1620 -1620
- package/src/domains/recruit/search.js +3229 -3229
- package/src/index.js +13 -0
- package/src/parser.js +376 -8
- package/src/recommend-mcp.js +929 -915
- package/src/recommend-scheduler.js +496 -496
- package/src/recruit-mcp.js +2121 -2121
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
captureScrolledNodeScreenshots,
|
|
3
|
-
captureViewportScreenshot
|
|
4
|
-
} from "../../core/capture/index.js";
|
|
1
|
+
import {
|
|
2
|
+
captureScrolledNodeScreenshots,
|
|
3
|
+
captureViewportScreenshot
|
|
4
|
+
} from "../../core/capture/index.js";
|
|
5
5
|
import { waitForCvCaptureTarget } from "../../core/cv-capture-target/index.js";
|
|
6
6
|
import {
|
|
7
7
|
clickPoint,
|
|
@@ -35,22 +35,22 @@ import {
|
|
|
35
35
|
resolveInfiniteListFallbackPoint
|
|
36
36
|
} from "../../core/infinite-list/index.js";
|
|
37
37
|
import { createViewportRunGuard } from "../../core/self-heal/index.js";
|
|
38
|
-
import {
|
|
39
|
-
createRunLifecycleManager,
|
|
40
|
-
RunCanceledError
|
|
41
|
-
} from "../../core/run/index.js";
|
|
38
|
+
import {
|
|
39
|
+
createRunLifecycleManager,
|
|
40
|
+
RunCanceledError
|
|
41
|
+
} from "../../core/run/index.js";
|
|
42
42
|
import {
|
|
43
43
|
addTiming,
|
|
44
44
|
imageEvidenceFilePath,
|
|
45
45
|
measureTiming
|
|
46
46
|
} from "../../core/run/timing.js";
|
|
47
|
-
import {
|
|
48
|
-
callScreeningLlm,
|
|
49
|
-
createFatalLlmRunError,
|
|
50
|
-
isFatalLlmProviderError,
|
|
51
|
-
normalizeText,
|
|
52
|
-
screenCandidate
|
|
53
|
-
} from "../../core/screening/index.js";
|
|
47
|
+
import {
|
|
48
|
+
callScreeningLlm,
|
|
49
|
+
createFatalLlmRunError,
|
|
50
|
+
isFatalLlmProviderError,
|
|
51
|
+
normalizeText,
|
|
52
|
+
screenCandidate
|
|
53
|
+
} from "../../core/screening/index.js";
|
|
54
54
|
import {
|
|
55
55
|
CHAT_BOTTOM_MARKER_SELECTORS,
|
|
56
56
|
CHAT_CARD_SELECTORS,
|
|
@@ -67,14 +67,14 @@ import {
|
|
|
67
67
|
closeChatBlockingPanels,
|
|
68
68
|
closeChatResumeModal,
|
|
69
69
|
createChatProfileNetworkRecorder,
|
|
70
|
-
extractChatProfileCandidate,
|
|
71
|
-
isChatOnlineResumeModalOpenFailureError,
|
|
72
|
-
isUnsafeChatOnlineResumeLinkError,
|
|
73
|
-
openChatOnlineResume,
|
|
74
|
-
quickChatResumeModalOpenProbe,
|
|
75
|
-
readChatActiveCandidateState,
|
|
76
|
-
readChatConversationReadyState,
|
|
77
|
-
requestChatResumeForPassedCandidate,
|
|
70
|
+
extractChatProfileCandidate,
|
|
71
|
+
isChatOnlineResumeModalOpenFailureError,
|
|
72
|
+
isUnsafeChatOnlineResumeLinkError,
|
|
73
|
+
openChatOnlineResume,
|
|
74
|
+
quickChatResumeModalOpenProbe,
|
|
75
|
+
readChatActiveCandidateState,
|
|
76
|
+
readChatConversationReadyState,
|
|
77
|
+
requestChatResumeForPassedCandidate,
|
|
78
78
|
selectChatMessageFilter,
|
|
79
79
|
selectChatPrimaryLabel,
|
|
80
80
|
waitForChatOnlineResumeButton,
|
|
@@ -91,6 +91,8 @@ import {
|
|
|
91
91
|
import { getChatRoots } from "./roots.js";
|
|
92
92
|
|
|
93
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;
|
|
94
96
|
|
|
95
97
|
function normalizeDetailSource(value) {
|
|
96
98
|
const normalized = String(value || "").trim().toLowerCase();
|
|
@@ -114,35 +116,35 @@ function compactScreening(screening) {
|
|
|
114
116
|
|
|
115
117
|
function compactLlmResult(llmResult) {
|
|
116
118
|
if (!llmResult) return null;
|
|
117
|
-
return {
|
|
118
|
-
ok: Boolean(llmResult.ok),
|
|
119
|
-
provider: llmResult.provider || null,
|
|
120
|
-
passed: llmResult.passed,
|
|
121
|
-
review_required: typeof llmResult.review_required === "boolean" ? llmResult.review_required : null,
|
|
122
|
-
cot: llmResult.cot || llmResult.decision_cot || "",
|
|
123
|
-
reasoning_content: llmResult.reasoning_content || "",
|
|
124
|
-
raw_model_output: llmResult.raw_model_output || "",
|
|
125
|
-
evidence_count: llmResult.evidence?.length || 0,
|
|
126
|
-
usage: llmResult.usage || null,
|
|
119
|
+
return {
|
|
120
|
+
ok: Boolean(llmResult.ok),
|
|
121
|
+
provider: llmResult.provider || null,
|
|
122
|
+
passed: llmResult.passed,
|
|
123
|
+
review_required: typeof llmResult.review_required === "boolean" ? llmResult.review_required : null,
|
|
124
|
+
cot: llmResult.cot || llmResult.decision_cot || "",
|
|
125
|
+
reasoning_content: llmResult.reasoning_content || "",
|
|
126
|
+
raw_model_output: llmResult.raw_model_output || "",
|
|
127
|
+
evidence_count: llmResult.evidence?.length || 0,
|
|
128
|
+
usage: llmResult.usage || null,
|
|
127
129
|
finish_reason: llmResult.finish_reason || null,
|
|
128
|
-
image_input_count: llmResult.image_input_count || 0,
|
|
129
|
-
attempt_count: llmResult.attempt_count || 0,
|
|
130
|
-
fallback_count: llmResult.fallback_count || 0,
|
|
131
|
-
llm_model_failures: Array.isArray(llmResult.llm_model_failures) ? llmResult.llm_model_failures : [],
|
|
132
|
-
screening_strategy: llmResult.screening_strategy || "",
|
|
133
|
-
fast_thinking_level: llmResult.fast_thinking_level || "",
|
|
134
|
-
verify_thinking_level: llmResult.verify_thinking_level || "",
|
|
135
|
-
verified: typeof llmResult.verified === "boolean" ? llmResult.verified : null,
|
|
136
|
-
verification_reason: llmResult.verification_reason || "",
|
|
137
|
-
decision_source: llmResult.decision_source || "",
|
|
138
|
-
fast_result: llmResult.fast_result || null,
|
|
139
|
-
verify_result: llmResult.verify_result || null,
|
|
140
|
-
error_code: llmResult.error_code || null,
|
|
141
|
-
fatal: Boolean(llmResult.fatal),
|
|
142
|
-
fatal_reason: llmResult.fatal_reason || "",
|
|
143
|
-
error: llmResult.error || null
|
|
144
|
-
};
|
|
145
|
-
}
|
|
130
|
+
image_input_count: llmResult.image_input_count || 0,
|
|
131
|
+
attempt_count: llmResult.attempt_count || 0,
|
|
132
|
+
fallback_count: llmResult.fallback_count || 0,
|
|
133
|
+
llm_model_failures: Array.isArray(llmResult.llm_model_failures) ? llmResult.llm_model_failures : [],
|
|
134
|
+
screening_strategy: llmResult.screening_strategy || "",
|
|
135
|
+
fast_thinking_level: llmResult.fast_thinking_level || "",
|
|
136
|
+
verify_thinking_level: llmResult.verify_thinking_level || "",
|
|
137
|
+
verified: typeof llmResult.verified === "boolean" ? llmResult.verified : null,
|
|
138
|
+
verification_reason: llmResult.verification_reason || "",
|
|
139
|
+
decision_source: llmResult.decision_source || "",
|
|
140
|
+
fast_result: llmResult.fast_result || null,
|
|
141
|
+
verify_result: llmResult.verify_result || null,
|
|
142
|
+
error_code: llmResult.error_code || null,
|
|
143
|
+
fatal: Boolean(llmResult.fatal),
|
|
144
|
+
fatal_reason: llmResult.fatal_reason || "",
|
|
145
|
+
error: llmResult.error || null
|
|
146
|
+
};
|
|
147
|
+
}
|
|
146
148
|
|
|
147
149
|
function compactCandidate(candidate) {
|
|
148
150
|
return {
|
|
@@ -361,9 +363,9 @@ function isRecoverableLlmScreeningError(error) {
|
|
|
361
363
|
}
|
|
362
364
|
|
|
363
365
|
function createFailedLlmResult(error) {
|
|
364
|
-
return {
|
|
365
|
-
ok: false,
|
|
366
|
-
passed: false,
|
|
366
|
+
return {
|
|
367
|
+
ok: false,
|
|
368
|
+
passed: false,
|
|
367
369
|
reason: "",
|
|
368
370
|
evidence: [],
|
|
369
371
|
cot: "",
|
|
@@ -371,110 +373,110 @@ function createFailedLlmResult(error) {
|
|
|
371
373
|
reasoning_content: "",
|
|
372
374
|
raw_model_output: "",
|
|
373
375
|
attempt_count: Number(error?.llm_attempt_count) || 0,
|
|
374
|
-
fallback_count: Array.isArray(error?.llm_model_failures) ? error.llm_model_failures.length : 0,
|
|
375
|
-
llm_model_failures: Array.isArray(error?.llm_model_failures) ? error.llm_model_failures : [],
|
|
376
|
-
error_code: error?.code || null,
|
|
377
|
-
fatal: Boolean(isFatalLlmProviderError(error)),
|
|
378
|
-
fatal_reason: error?.llm_fatal_reason || "",
|
|
379
|
-
error: error?.message || String(error || "unknown"),
|
|
380
|
-
screened_at: new Date().toISOString()
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function normalizeScreeningMode(value) {
|
|
385
|
-
const normalized = String(value || "llm").trim().toLowerCase();
|
|
386
|
-
if (["collect_cv", "collect-cv", "cv_collection", "request_cv", "request_resume"].includes(normalized)) {
|
|
387
|
-
return "collect_cv";
|
|
388
|
-
}
|
|
389
|
-
return ["deterministic", "local", "local_scorer"].includes(normalized)
|
|
390
|
-
? "deterministic"
|
|
391
|
-
: "llm";
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function isCvAcquiredOrAvailable(detailResult = null, preActionState = null) {
|
|
395
|
-
return Boolean(
|
|
396
|
-
preActionState?.attachment_resume_enabled
|
|
397
|
-
|| detailResult?.cv_acquisition?.full_cv_evidence?.full_cv_acquired
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function isChatResumeRequestAvailable(preActionState = null) {
|
|
402
|
-
return Boolean(preActionState?.ask_resume?.node_id && !preActionState.ask_resume.disabled);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
function shouldSkipCvCollectionForDetailReason(reason = "") {
|
|
406
|
-
const normalized = normalizeText(reason);
|
|
407
|
-
return [
|
|
408
|
-
"active_candidate_mismatch",
|
|
409
|
-
"forbidden_top_level_resume_navigation",
|
|
410
|
-
"online_resume_modal_did_not_open",
|
|
411
|
-
"unsafe_online_resume_navigation_link"
|
|
412
|
-
].includes(normalized)
|
|
413
|
-
|| normalized.startsWith("recoverable_cdp_node_stale:")
|
|
414
|
-
|| normalized.startsWith("resume_modal_close_failed:");
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
export function createCvCollectionScreening(screeningCandidate, {
|
|
418
|
-
detailResult = null,
|
|
419
|
-
detailUnavailableReason = "",
|
|
420
|
-
preActionState = null
|
|
421
|
-
} = {}) {
|
|
422
|
-
if (preActionState?.already_requested_resume) {
|
|
423
|
-
return {
|
|
424
|
-
status: "skip",
|
|
425
|
-
passed: false,
|
|
426
|
-
score: 0,
|
|
427
|
-
reasons: ["resume_request_already_pending"],
|
|
428
|
-
candidate: screeningCandidate
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
if (isCvAcquiredOrAvailable(detailResult, preActionState)) {
|
|
432
|
-
const reason = preActionState?.attachment_resume_enabled
|
|
433
|
-
? "attachment_resume_already_available"
|
|
434
|
-
: "online_cv_already_available";
|
|
435
|
-
return {
|
|
436
|
-
status: "skip",
|
|
437
|
-
passed: false,
|
|
438
|
-
score: 0,
|
|
439
|
-
reasons: [reason],
|
|
440
|
-
candidate: screeningCandidate
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
if (isChatResumeRequestAvailable(preActionState)) {
|
|
444
|
-
const reason = detailUnavailableReason || "request_cv_available";
|
|
445
|
-
return {
|
|
446
|
-
status: "pass",
|
|
447
|
-
passed: true,
|
|
448
|
-
score: 100,
|
|
449
|
-
reasons: [`collect_cv:${reason}`],
|
|
450
|
-
candidate: screeningCandidate
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
if (shouldSkipCvCollectionForDetailReason(detailUnavailableReason)) {
|
|
454
|
-
return {
|
|
455
|
-
status: "skip",
|
|
456
|
-
passed: false,
|
|
457
|
-
score: 0,
|
|
458
|
-
reasons: [detailUnavailableReason],
|
|
459
|
-
candidate: screeningCandidate
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
const reason = detailUnavailableReason || "cv_collection_missing_online_cv";
|
|
463
|
-
return {
|
|
464
|
-
status: "pass",
|
|
465
|
-
passed: true,
|
|
466
|
-
score: 100,
|
|
467
|
-
reasons: [`collect_cv:${reason}`],
|
|
468
|
-
candidate: screeningCandidate
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
export function shouldOpenOnlineResumeForChatDetail({
|
|
473
|
-
collectCvOnly = false,
|
|
474
|
-
detailResult = null
|
|
475
|
-
} = {}) {
|
|
476
|
-
return !collectCvOnly && !detailResult;
|
|
477
|
-
}
|
|
376
|
+
fallback_count: Array.isArray(error?.llm_model_failures) ? error.llm_model_failures.length : 0,
|
|
377
|
+
llm_model_failures: Array.isArray(error?.llm_model_failures) ? error.llm_model_failures : [],
|
|
378
|
+
error_code: error?.code || null,
|
|
379
|
+
fatal: Boolean(isFatalLlmProviderError(error)),
|
|
380
|
+
fatal_reason: error?.llm_fatal_reason || "",
|
|
381
|
+
error: error?.message || String(error || "unknown"),
|
|
382
|
+
screened_at: new Date().toISOString()
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function normalizeScreeningMode(value) {
|
|
387
|
+
const normalized = String(value || "llm").trim().toLowerCase();
|
|
388
|
+
if (["collect_cv", "collect-cv", "cv_collection", "request_cv", "request_resume"].includes(normalized)) {
|
|
389
|
+
return "collect_cv";
|
|
390
|
+
}
|
|
391
|
+
return ["deterministic", "local", "local_scorer"].includes(normalized)
|
|
392
|
+
? "deterministic"
|
|
393
|
+
: "llm";
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function isCvAcquiredOrAvailable(detailResult = null, preActionState = null) {
|
|
397
|
+
return Boolean(
|
|
398
|
+
preActionState?.attachment_resume_enabled
|
|
399
|
+
|| detailResult?.cv_acquisition?.full_cv_evidence?.full_cv_acquired
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function isChatResumeRequestAvailable(preActionState = null) {
|
|
404
|
+
return Boolean(preActionState?.ask_resume?.node_id && !preActionState.ask_resume.disabled);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function shouldSkipCvCollectionForDetailReason(reason = "") {
|
|
408
|
+
const normalized = normalizeText(reason);
|
|
409
|
+
return [
|
|
410
|
+
"active_candidate_mismatch",
|
|
411
|
+
"forbidden_top_level_resume_navigation",
|
|
412
|
+
"online_resume_modal_did_not_open",
|
|
413
|
+
"unsafe_online_resume_navigation_link"
|
|
414
|
+
].includes(normalized)
|
|
415
|
+
|| normalized.startsWith("recoverable_cdp_node_stale:")
|
|
416
|
+
|| normalized.startsWith("resume_modal_close_failed:");
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export function createCvCollectionScreening(screeningCandidate, {
|
|
420
|
+
detailResult = null,
|
|
421
|
+
detailUnavailableReason = "",
|
|
422
|
+
preActionState = null
|
|
423
|
+
} = {}) {
|
|
424
|
+
if (preActionState?.already_requested_resume) {
|
|
425
|
+
return {
|
|
426
|
+
status: "skip",
|
|
427
|
+
passed: false,
|
|
428
|
+
score: 0,
|
|
429
|
+
reasons: ["resume_request_already_pending"],
|
|
430
|
+
candidate: screeningCandidate
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
if (isCvAcquiredOrAvailable(detailResult, preActionState)) {
|
|
434
|
+
const reason = preActionState?.attachment_resume_enabled
|
|
435
|
+
? "attachment_resume_already_available"
|
|
436
|
+
: "online_cv_already_available";
|
|
437
|
+
return {
|
|
438
|
+
status: "skip",
|
|
439
|
+
passed: false,
|
|
440
|
+
score: 0,
|
|
441
|
+
reasons: [reason],
|
|
442
|
+
candidate: screeningCandidate
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
if (isChatResumeRequestAvailable(preActionState)) {
|
|
446
|
+
const reason = detailUnavailableReason || "request_cv_available";
|
|
447
|
+
return {
|
|
448
|
+
status: "pass",
|
|
449
|
+
passed: true,
|
|
450
|
+
score: 100,
|
|
451
|
+
reasons: [`collect_cv:${reason}`],
|
|
452
|
+
candidate: screeningCandidate
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
if (shouldSkipCvCollectionForDetailReason(detailUnavailableReason)) {
|
|
456
|
+
return {
|
|
457
|
+
status: "skip",
|
|
458
|
+
passed: false,
|
|
459
|
+
score: 0,
|
|
460
|
+
reasons: [detailUnavailableReason],
|
|
461
|
+
candidate: screeningCandidate
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
const reason = detailUnavailableReason || "cv_collection_missing_online_cv";
|
|
465
|
+
return {
|
|
466
|
+
status: "pass",
|
|
467
|
+
passed: true,
|
|
468
|
+
score: 100,
|
|
469
|
+
reasons: [`collect_cv:${reason}`],
|
|
470
|
+
candidate: screeningCandidate
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export function shouldOpenOnlineResumeForChatDetail({
|
|
475
|
+
collectCvOnly = false,
|
|
476
|
+
detailResult = null
|
|
477
|
+
} = {}) {
|
|
478
|
+
return !collectCvOnly && !detailResult;
|
|
479
|
+
}
|
|
478
480
|
|
|
479
481
|
function createMissingLlmConfigResult() {
|
|
480
482
|
return createFailedLlmResult(new Error("LLM screening config is required for production chat runs"));
|
|
@@ -496,81 +498,81 @@ function createSkippedDetailResult(cardCandidate, reason, error = null) {
|
|
|
496
498
|
};
|
|
497
499
|
}
|
|
498
500
|
|
|
499
|
-
function compactChatRuntimeError(error) {
|
|
500
|
-
if (!error) return null;
|
|
501
|
-
return {
|
|
502
|
-
name: error.name || "Error",
|
|
503
|
-
code: error.code || null,
|
|
504
|
-
message: error.message || String(error),
|
|
505
|
-
retryable: typeof error.retryable === "boolean" ? error.retryable : null,
|
|
506
|
-
attempts: Array.isArray(error.attempts) ? error.attempts : null,
|
|
507
|
-
close_result: error.close_result || null,
|
|
508
|
-
selection_ready_state: error.selection_ready_state || null,
|
|
509
|
-
page_state: error.page_state || null
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
async function captureChatFinalFailureArtifact(client, {
|
|
514
|
-
runControl,
|
|
515
|
-
imageOutputDir = "",
|
|
516
|
-
error = null
|
|
517
|
-
} = {}) {
|
|
518
|
-
if (!client || !imageOutputDir || !runControl?.runId) return null;
|
|
519
|
-
const artifact = {
|
|
520
|
-
schema_version: 1,
|
|
521
|
-
kind: "chat_final_failure_page",
|
|
522
|
-
captured_at: new Date().toISOString(),
|
|
523
|
-
run_id: runControl.runId,
|
|
524
|
-
error: compactChatRuntimeError(error),
|
|
525
|
-
page_state: null,
|
|
526
|
-
active_candidate_state: null,
|
|
527
|
-
conversation_ready_state: null,
|
|
528
|
-
screenshot: null,
|
|
529
|
-
screenshot_error: null
|
|
530
|
-
};
|
|
531
|
-
try {
|
|
532
|
-
artifact.page_state = await getChatTopLevelState(client);
|
|
533
|
-
} catch (pageError) {
|
|
534
|
-
artifact.page_state = {
|
|
535
|
-
error: pageError?.message || String(pageError)
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
try {
|
|
539
|
-
artifact.active_candidate_state = await readChatActiveCandidateState(client);
|
|
540
|
-
} catch (activeCandidateError) {
|
|
541
|
-
artifact.active_candidate_state = {
|
|
542
|
-
error: activeCandidateError?.message || String(activeCandidateError)
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
try {
|
|
546
|
-
artifact.conversation_ready_state = await readChatConversationReadyState(client);
|
|
547
|
-
} catch (conversationError) {
|
|
548
|
-
artifact.conversation_ready_state = {
|
|
549
|
-
error: conversationError?.message || String(conversationError)
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
try {
|
|
553
|
-
artifact.screenshot = await captureViewportScreenshot(client, {
|
|
554
|
-
filePath: imageEvidenceFilePath({
|
|
555
|
-
imageOutputDir,
|
|
556
|
-
domain: "chat-final-failure",
|
|
557
|
-
runId: runControl.runId,
|
|
558
|
-
index: 0,
|
|
559
|
-
extension: "jpg"
|
|
560
|
-
}),
|
|
561
|
-
format: "jpeg",
|
|
562
|
-
quality: 72,
|
|
563
|
-
metadata: {
|
|
564
|
-
domain: "chat",
|
|
565
|
-
run_id: runControl.runId,
|
|
566
|
-
reason: "final_failure"
|
|
567
|
-
}
|
|
568
|
-
});
|
|
569
|
-
} catch (screenshotError) {
|
|
570
|
-
artifact.screenshot_error = screenshotError?.message || String(screenshotError);
|
|
571
|
-
}
|
|
572
|
-
return artifact;
|
|
573
|
-
}
|
|
501
|
+
function compactChatRuntimeError(error) {
|
|
502
|
+
if (!error) return null;
|
|
503
|
+
return {
|
|
504
|
+
name: error.name || "Error",
|
|
505
|
+
code: error.code || null,
|
|
506
|
+
message: error.message || String(error),
|
|
507
|
+
retryable: typeof error.retryable === "boolean" ? error.retryable : null,
|
|
508
|
+
attempts: Array.isArray(error.attempts) ? error.attempts : null,
|
|
509
|
+
close_result: error.close_result || null,
|
|
510
|
+
selection_ready_state: error.selection_ready_state || null,
|
|
511
|
+
page_state: error.page_state || null
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async function captureChatFinalFailureArtifact(client, {
|
|
516
|
+
runControl,
|
|
517
|
+
imageOutputDir = "",
|
|
518
|
+
error = null
|
|
519
|
+
} = {}) {
|
|
520
|
+
if (!client || !imageOutputDir || !runControl?.runId) return null;
|
|
521
|
+
const artifact = {
|
|
522
|
+
schema_version: 1,
|
|
523
|
+
kind: "chat_final_failure_page",
|
|
524
|
+
captured_at: new Date().toISOString(),
|
|
525
|
+
run_id: runControl.runId,
|
|
526
|
+
error: compactChatRuntimeError(error),
|
|
527
|
+
page_state: null,
|
|
528
|
+
active_candidate_state: null,
|
|
529
|
+
conversation_ready_state: null,
|
|
530
|
+
screenshot: null,
|
|
531
|
+
screenshot_error: null
|
|
532
|
+
};
|
|
533
|
+
try {
|
|
534
|
+
artifact.page_state = await getChatTopLevelState(client);
|
|
535
|
+
} catch (pageError) {
|
|
536
|
+
artifact.page_state = {
|
|
537
|
+
error: pageError?.message || String(pageError)
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
try {
|
|
541
|
+
artifact.active_candidate_state = await readChatActiveCandidateState(client);
|
|
542
|
+
} catch (activeCandidateError) {
|
|
543
|
+
artifact.active_candidate_state = {
|
|
544
|
+
error: activeCandidateError?.message || String(activeCandidateError)
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
try {
|
|
548
|
+
artifact.conversation_ready_state = await readChatConversationReadyState(client);
|
|
549
|
+
} catch (conversationError) {
|
|
550
|
+
artifact.conversation_ready_state = {
|
|
551
|
+
error: conversationError?.message || String(conversationError)
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
try {
|
|
555
|
+
artifact.screenshot = await captureViewportScreenshot(client, {
|
|
556
|
+
filePath: imageEvidenceFilePath({
|
|
557
|
+
imageOutputDir,
|
|
558
|
+
domain: "chat-final-failure",
|
|
559
|
+
runId: runControl.runId,
|
|
560
|
+
index: 0,
|
|
561
|
+
extension: "jpg"
|
|
562
|
+
}),
|
|
563
|
+
format: "jpeg",
|
|
564
|
+
quality: 72,
|
|
565
|
+
metadata: {
|
|
566
|
+
domain: "chat",
|
|
567
|
+
run_id: runControl.runId,
|
|
568
|
+
reason: "final_failure"
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
} catch (screenshotError) {
|
|
572
|
+
artifact.screenshot_error = screenshotError?.message || String(screenshotError);
|
|
573
|
+
}
|
|
574
|
+
return artifact;
|
|
575
|
+
}
|
|
574
576
|
|
|
575
577
|
const CHAT_FULL_CV_DOM_MIN_TEXT_LENGTH = 500;
|
|
576
578
|
const CHAT_FULL_CV_DOM_MIN_SECTION_TEXT_LENGTH = 180;
|
|
@@ -738,15 +740,15 @@ async function resolveFreshChatCardNodeId(client, {
|
|
|
738
740
|
return freshNodeId || fallbackNodeId;
|
|
739
741
|
}
|
|
740
742
|
|
|
741
|
-
async function selectFreshChatCandidate(client, {
|
|
742
|
-
cardNodeId,
|
|
743
|
-
candidate,
|
|
744
|
-
timeoutMs,
|
|
745
|
-
settleMs = 1200,
|
|
746
|
-
onlineResumeProbe = true
|
|
747
|
-
} = {}) {
|
|
748
|
-
let lastError = null;
|
|
749
|
-
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
743
|
+
async function selectFreshChatCandidate(client, {
|
|
744
|
+
cardNodeId,
|
|
745
|
+
candidate,
|
|
746
|
+
timeoutMs,
|
|
747
|
+
settleMs = 1200,
|
|
748
|
+
onlineResumeProbe = true
|
|
749
|
+
} = {}) {
|
|
750
|
+
let lastError = null;
|
|
751
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
750
752
|
const modalGuard = await ensureNoOpenChatResumeModalBeforeCandidateClick(client);
|
|
751
753
|
const rootState = await getChatRoots(client);
|
|
752
754
|
const freshNodeId = await resolveFreshChatCardNodeId(client, {
|
|
@@ -757,18 +759,18 @@ async function selectFreshChatCandidate(client, {
|
|
|
757
759
|
try {
|
|
758
760
|
await scrollNodeIntoView(client, freshNodeId);
|
|
759
761
|
await sleep(250);
|
|
760
|
-
const box = await getNodeBox(client, freshNodeId);
|
|
761
|
-
await clickPoint(client, box.center.x, box.center.y);
|
|
762
|
-
if (settleMs > 0) await sleep(settleMs);
|
|
763
|
-
const ready = onlineResumeProbe
|
|
764
|
-
? await waitForChatOnlineResumeButton(client, {
|
|
765
|
-
timeoutMs,
|
|
766
|
-
expectedCandidateId: candidate?.id || ""
|
|
767
|
-
})
|
|
768
|
-
: await readSelectedChatCandidateState(client, candidate);
|
|
769
|
-
return {
|
|
770
|
-
card_box: box,
|
|
771
|
-
ready,
|
|
762
|
+
const box = await getNodeBox(client, freshNodeId);
|
|
763
|
+
await clickPoint(client, box.center.x, box.center.y);
|
|
764
|
+
if (settleMs > 0) await sleep(settleMs);
|
|
765
|
+
const ready = onlineResumeProbe
|
|
766
|
+
? await waitForChatOnlineResumeButton(client, {
|
|
767
|
+
timeoutMs,
|
|
768
|
+
expectedCandidateId: candidate?.id || ""
|
|
769
|
+
})
|
|
770
|
+
: await readSelectedChatCandidateState(client, candidate);
|
|
771
|
+
return {
|
|
772
|
+
card_box: box,
|
|
773
|
+
ready,
|
|
772
774
|
card_node_id: freshNodeId,
|
|
773
775
|
refreshed_node: freshNodeId !== cardNodeId,
|
|
774
776
|
modal_guard: modalGuard,
|
|
@@ -780,35 +782,35 @@ async function selectFreshChatCandidate(client, {
|
|
|
780
782
|
await sleep(350);
|
|
781
783
|
}
|
|
782
784
|
}
|
|
783
|
-
throw lastError || new Error("Chat candidate selection failed");
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
async function readSelectedChatCandidateState(client, candidate = null) {
|
|
787
|
-
const topLevelState = await getChatTopLevelState(client);
|
|
788
|
-
if (topLevelState.is_forbidden_resume_top_level) {
|
|
789
|
-
return {
|
|
790
|
-
forbidden_top_level_navigation: true,
|
|
791
|
-
top_level_state: topLevelState
|
|
792
|
-
};
|
|
793
|
-
}
|
|
794
|
-
const activeState = await readChatActiveCandidateState(client);
|
|
795
|
-
const expectedId = normalizeText(candidate?.id || "");
|
|
796
|
-
const activeCandidateId = normalizeText(activeState?.active_candidate?.candidate_id || "");
|
|
797
|
-
const candidateSelectionVerified = expectedId
|
|
798
|
-
? activeCandidateId === expectedId
|
|
799
|
-
: undefined;
|
|
800
|
-
return {
|
|
801
|
-
ok: !expectedId || candidateSelectionVerified === true,
|
|
802
|
-
reason: expectedId && candidateSelectionVerified !== true
|
|
803
|
-
? "active_candidate_mismatch"
|
|
804
|
-
: "online_resume_probe_skipped",
|
|
805
|
-
roots: activeState.roots,
|
|
806
|
-
activeCandidate: activeState.active_candidate,
|
|
807
|
-
expected_candidate_id: expectedId || null,
|
|
808
|
-
active_candidate_id: activeCandidateId || null,
|
|
809
|
-
candidate_selection_verified: candidateSelectionVerified
|
|
810
|
-
};
|
|
811
|
-
}
|
|
785
|
+
throw lastError || new Error("Chat candidate selection failed");
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
async function readSelectedChatCandidateState(client, candidate = null) {
|
|
789
|
+
const topLevelState = await getChatTopLevelState(client);
|
|
790
|
+
if (topLevelState.is_forbidden_resume_top_level) {
|
|
791
|
+
return {
|
|
792
|
+
forbidden_top_level_navigation: true,
|
|
793
|
+
top_level_state: topLevelState
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
const activeState = await readChatActiveCandidateState(client);
|
|
797
|
+
const expectedId = normalizeText(candidate?.id || "");
|
|
798
|
+
const activeCandidateId = normalizeText(activeState?.active_candidate?.candidate_id || "");
|
|
799
|
+
const candidateSelectionVerified = expectedId
|
|
800
|
+
? activeCandidateId === expectedId
|
|
801
|
+
: undefined;
|
|
802
|
+
return {
|
|
803
|
+
ok: !expectedId || candidateSelectionVerified === true,
|
|
804
|
+
reason: expectedId && candidateSelectionVerified !== true
|
|
805
|
+
? "active_candidate_mismatch"
|
|
806
|
+
: "online_resume_probe_skipped",
|
|
807
|
+
roots: activeState.roots,
|
|
808
|
+
activeCandidate: activeState.active_candidate,
|
|
809
|
+
expected_candidate_id: expectedId || null,
|
|
810
|
+
active_candidate_id: activeCandidateId || null,
|
|
811
|
+
candidate_selection_verified: candidateSelectionVerified
|
|
812
|
+
};
|
|
813
|
+
}
|
|
812
814
|
|
|
813
815
|
function selectedDetailNetworkEvents(detailSource, selectionEvents, resumeEvents) {
|
|
814
816
|
if (detailSource !== "network" && detailSource !== "cascade") return [];
|
|
@@ -942,7 +944,12 @@ export async function runChatWorkflow({
|
|
|
942
944
|
const effectiveHumanBehavior = normalizeHumanBehaviorOptions(humanBehavior, {
|
|
943
945
|
legacyEnabled: humanRestEnabled === true || llmConfig?.humanRestEnabled === true
|
|
944
946
|
});
|
|
945
|
-
const
|
|
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;
|
|
946
953
|
configureHumanInteraction(client, {
|
|
947
954
|
enabled: effectiveHumanBehavior.enabled,
|
|
948
955
|
clickMovementEnabled: effectiveHumanBehavior.clickMovement,
|
|
@@ -950,16 +957,15 @@ export async function runChatWorkflow({
|
|
|
950
957
|
safeClickPointEnabled: effectiveHumanBehavior.clickMovement,
|
|
951
958
|
actionCooldownEnabled: effectiveHumanBehavior.actionCooldown
|
|
952
959
|
});
|
|
953
|
-
const humanRestController = createHumanRestController({
|
|
954
|
-
enabled: effectiveHumanRestEnabled,
|
|
955
|
-
shortRestEnabled: effectiveHumanBehavior.shortRest,
|
|
956
|
-
batchRestEnabled: effectiveHumanBehavior.batchRest,
|
|
957
|
-
restLevel: effectiveHumanBehavior.restLevel
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
const useLlmScreening = normalizedScreeningMode === "llm" && !collectCvOnly;
|
|
960
|
+
const humanRestController = createHumanRestController({
|
|
961
|
+
enabled: effectiveHumanRestEnabled,
|
|
962
|
+
shortRestEnabled: effectiveHumanBehavior.shortRest,
|
|
963
|
+
batchRestEnabled: effectiveHumanBehavior.batchRest,
|
|
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
|
|
968
|
+
});
|
|
963
969
|
const processedLimit = Math.max(1, Number(maxCandidates) || 1);
|
|
964
970
|
const passTarget = Number.isFinite(Number(targetPassCount)) && Number(targetPassCount) > 0
|
|
965
971
|
? Number(targetPassCount)
|
|
@@ -1000,12 +1006,12 @@ export async function runChatWorkflow({
|
|
|
1000
1006
|
let requestedCount = 0;
|
|
1001
1007
|
let requestSatisfiedCount = 0;
|
|
1002
1008
|
let requestSkippedCount = 0;
|
|
1003
|
-
let contextSetup = {};
|
|
1004
|
-
let contextRecoveryAttempts = 0;
|
|
1005
|
-
const candidateRecoveryCounts = new Map();
|
|
1006
|
-
let lastHumanEvent = null;
|
|
1007
|
-
|
|
1008
|
-
function recordHumanEvent(event = null) {
|
|
1009
|
+
let contextSetup = {};
|
|
1010
|
+
let contextRecoveryAttempts = 0;
|
|
1011
|
+
const candidateRecoveryCounts = new Map();
|
|
1012
|
+
let lastHumanEvent = null;
|
|
1013
|
+
|
|
1014
|
+
function recordHumanEvent(event = null) {
|
|
1009
1015
|
if (!event) return lastHumanEvent;
|
|
1010
1016
|
lastHumanEvent = {
|
|
1011
1017
|
at: new Date().toISOString(),
|
|
@@ -1069,13 +1075,13 @@ export async function runChatWorkflow({
|
|
|
1069
1075
|
...setup.contextSetup,
|
|
1070
1076
|
initial_top_level_state: initialTopLevelState
|
|
1071
1077
|
};
|
|
1072
|
-
runControl.checkpoint({
|
|
1073
|
-
chat_context: contextSetup
|
|
1074
|
-
});
|
|
1075
|
-
|
|
1076
|
-
async function recoverAndReapplyChatContext(reason, error = null, {
|
|
1077
|
-
forceRefresh = false
|
|
1078
|
-
} = {}) {
|
|
1078
|
+
runControl.checkpoint({
|
|
1079
|
+
chat_context: contextSetup
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
async function recoverAndReapplyChatContext(reason, error = null, {
|
|
1083
|
+
forceRefresh = false
|
|
1084
|
+
} = {}) {
|
|
1079
1085
|
runControl.setPhase("chat:recover_shell");
|
|
1080
1086
|
contextRecoveryAttempts += 1;
|
|
1081
1087
|
const shellRecovery = await recoverChatShell(client, {
|
|
@@ -1180,6 +1186,9 @@ export async function runChatWorkflow({
|
|
|
1180
1186
|
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
1181
1187
|
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
1182
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,
|
|
1183
1192
|
human_rest_count: humanRestController.getState().rest_count,
|
|
1184
1193
|
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
1185
1194
|
last_human_event: lastHumanEvent
|
|
@@ -1205,10 +1214,10 @@ export async function runChatWorkflow({
|
|
|
1205
1214
|
last_human_event: lastHumanEvent,
|
|
1206
1215
|
list_end_reason: listEndReason,
|
|
1207
1216
|
target_pass_count: passTarget,
|
|
1208
|
-
process_until_list_end: Boolean(processUntilListEnd),
|
|
1209
|
-
processed_limit: processedLimit,
|
|
1210
|
-
detail_source: normalizedDetailSource,
|
|
1211
|
-
processed: 0,
|
|
1217
|
+
process_until_list_end: Boolean(processUntilListEnd),
|
|
1218
|
+
processed_limit: processedLimit,
|
|
1219
|
+
detail_source: normalizedDetailSource,
|
|
1220
|
+
processed: 0,
|
|
1212
1221
|
screened: 0,
|
|
1213
1222
|
detail_opened: 0,
|
|
1214
1223
|
llm_screened: 0,
|
|
@@ -1241,7 +1250,17 @@ export async function runChatWorkflow({
|
|
|
1241
1250
|
scroll_count: 0,
|
|
1242
1251
|
context_recoveries: contextRecoveryAttempts,
|
|
1243
1252
|
viewport_checks: viewportGuard.getStats().checks,
|
|
1244
|
-
viewport_recoveries: viewportGuard.getStats().recoveries
|
|
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
|
|
1245
1264
|
});
|
|
1246
1265
|
|
|
1247
1266
|
while (
|
|
@@ -1405,12 +1424,12 @@ export async function runChatWorkflow({
|
|
|
1405
1424
|
detailStep = "select_candidate";
|
|
1406
1425
|
networkRecorder.clear();
|
|
1407
1426
|
await maybeHumanActionCooldown("before_detail_open", timings);
|
|
1408
|
-
const selected = await measureTiming(timings, "candidate_click_ms", () => selectFreshChatCandidate(client, {
|
|
1409
|
-
cardNodeId,
|
|
1410
|
-
candidate: cardCandidate,
|
|
1411
|
-
timeoutMs: onlineResumeButtonTimeoutMs,
|
|
1412
|
-
onlineResumeProbe: !collectCvOnly
|
|
1413
|
-
}));
|
|
1427
|
+
const selected = await measureTiming(timings, "candidate_click_ms", () => selectFreshChatCandidate(client, {
|
|
1428
|
+
cardNodeId,
|
|
1429
|
+
candidate: cardCandidate,
|
|
1430
|
+
timeoutMs: onlineResumeButtonTimeoutMs,
|
|
1431
|
+
onlineResumeProbe: !collectCvOnly
|
|
1432
|
+
}));
|
|
1414
1433
|
if (selected.ready?.forbidden_top_level_navigation) {
|
|
1415
1434
|
throw makeForbiddenChatResumeNavigationError(selected.ready.top_level_state);
|
|
1416
1435
|
}
|
|
@@ -1430,11 +1449,11 @@ export async function runChatWorkflow({
|
|
|
1430
1449
|
detailResult.cv_acquisition.pre_detail_state = preActionState;
|
|
1431
1450
|
detailResult.cv_acquisition.selection_ready_state = selected.ready;
|
|
1432
1451
|
}
|
|
1433
|
-
if (!selected.ready?.ok) {
|
|
1434
|
-
if (detailResult) {
|
|
1435
|
-
// Already classified by the pre-detail conversation state.
|
|
1436
|
-
} else if (selected.ready?.reason === "active_candidate_mismatch") {
|
|
1437
|
-
throw makeChatCandidateSelectionMismatchError(selected, cardCandidate);
|
|
1452
|
+
if (!selected.ready?.ok) {
|
|
1453
|
+
if (detailResult) {
|
|
1454
|
+
// Already classified by the pre-detail conversation state.
|
|
1455
|
+
} else if (selected.ready?.reason === "active_candidate_mismatch") {
|
|
1456
|
+
throw makeChatCandidateSelectionMismatchError(selected, cardCandidate);
|
|
1438
1457
|
} else {
|
|
1439
1458
|
detailStep = "read_conversation_ready_state";
|
|
1440
1459
|
if (preActionState.attachment_resume_enabled) {
|
|
@@ -1444,18 +1463,18 @@ export async function runChatWorkflow({
|
|
|
1444
1463
|
} else {
|
|
1445
1464
|
detailUnavailableReason = "online_resume_button_unavailable";
|
|
1446
1465
|
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason);
|
|
1447
|
-
detailResult.cv_acquisition.pre_detail_state = preActionState;
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
}
|
|
1451
|
-
if (collectCvOnly && !detailResult) {
|
|
1452
|
-
detailUnavailableReason = preActionState?.has_online_resume
|
|
1453
|
-
? "collect_cv_request_candidate"
|
|
1454
|
-
: "collect_cv_missing_online_resume";
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
if (shouldOpenOnlineResumeForChatDetail({ collectCvOnly, detailResult })) {
|
|
1458
|
-
const waitPlan = getCvNetworkWaitPlan(cvAcquisitionState);
|
|
1466
|
+
detailResult.cv_acquisition.pre_detail_state = preActionState;
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
if (collectCvOnly && !detailResult) {
|
|
1471
|
+
detailUnavailableReason = preActionState?.has_online_resume
|
|
1472
|
+
? "collect_cv_request_candidate"
|
|
1473
|
+
: "collect_cv_missing_online_resume";
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
if (shouldOpenOnlineResumeForChatDetail({ collectCvOnly, detailResult })) {
|
|
1477
|
+
const waitPlan = getCvNetworkWaitPlan(cvAcquisitionState);
|
|
1459
1478
|
let networkWait = null;
|
|
1460
1479
|
let contentWait = {
|
|
1461
1480
|
ok: false,
|
|
@@ -1715,24 +1734,24 @@ export async function runChatWorkflow({
|
|
|
1715
1734
|
llmResult = createMissingLlmConfigResult();
|
|
1716
1735
|
} else {
|
|
1717
1736
|
try {
|
|
1718
|
-
llmResult = await measureTiming(timings, "vision_model_ms", () => callScreeningLlm({
|
|
1719
|
-
candidate: detailResult.candidate,
|
|
1720
|
-
criteria,
|
|
1721
|
-
config: llmConfig,
|
|
1722
|
-
timeoutMs: llmTimeoutMs,
|
|
1737
|
+
llmResult = await measureTiming(timings, "vision_model_ms", () => callScreeningLlm({
|
|
1738
|
+
candidate: detailResult.candidate,
|
|
1739
|
+
criteria,
|
|
1740
|
+
config: llmConfig,
|
|
1741
|
+
timeoutMs: llmTimeoutMs,
|
|
1723
1742
|
imageEvidence,
|
|
1724
1743
|
maxImages: llmImageLimit,
|
|
1725
1744
|
imageDetail: llmImageDetail
|
|
1726
1745
|
}));
|
|
1727
|
-
} catch (error) {
|
|
1728
|
-
if (isFatalLlmProviderError(error)) {
|
|
1729
|
-
throw createFatalLlmRunError(error, {
|
|
1730
|
-
domain: "chat",
|
|
1731
|
-
candidate: detailResult.candidate
|
|
1732
|
-
});
|
|
1733
|
-
}
|
|
1734
|
-
llmResult = createFailedLlmResult(error);
|
|
1735
|
-
}
|
|
1746
|
+
} catch (error) {
|
|
1747
|
+
if (isFatalLlmProviderError(error)) {
|
|
1748
|
+
throw createFatalLlmRunError(error, {
|
|
1749
|
+
domain: "chat",
|
|
1750
|
+
candidate: detailResult.candidate
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
llmResult = createFailedLlmResult(error);
|
|
1754
|
+
}
|
|
1736
1755
|
}
|
|
1737
1756
|
}
|
|
1738
1757
|
} else {
|
|
@@ -1794,24 +1813,24 @@ export async function runChatWorkflow({
|
|
|
1794
1813
|
const llmTimingKey = imageEvidence?.file_paths?.length
|
|
1795
1814
|
? "vision_model_ms"
|
|
1796
1815
|
: "text_model_ms";
|
|
1797
|
-
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1798
|
-
candidate: detailResult.candidate,
|
|
1799
|
-
criteria,
|
|
1800
|
-
config: llmConfig,
|
|
1816
|
+
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1817
|
+
candidate: detailResult.candidate,
|
|
1818
|
+
criteria,
|
|
1819
|
+
config: llmConfig,
|
|
1801
1820
|
timeoutMs: llmTimeoutMs,
|
|
1802
1821
|
imageEvidence,
|
|
1803
1822
|
maxImages: llmImageLimit,
|
|
1804
1823
|
imageDetail: llmImageDetail
|
|
1805
1824
|
}));
|
|
1806
|
-
} catch (error) {
|
|
1807
|
-
if (isFatalLlmProviderError(error)) {
|
|
1808
|
-
throw createFatalLlmRunError(error, {
|
|
1809
|
-
domain: "chat",
|
|
1810
|
-
candidate: detailResult.candidate
|
|
1811
|
-
});
|
|
1812
|
-
}
|
|
1813
|
-
llmResult = createFailedLlmResult(error);
|
|
1814
|
-
}
|
|
1825
|
+
} catch (error) {
|
|
1826
|
+
if (isFatalLlmProviderError(error)) {
|
|
1827
|
+
throw createFatalLlmRunError(error, {
|
|
1828
|
+
domain: "chat",
|
|
1829
|
+
candidate: detailResult.candidate
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
llmResult = createFailedLlmResult(error);
|
|
1833
|
+
}
|
|
1815
1834
|
}
|
|
1816
1835
|
}
|
|
1817
1836
|
}
|
|
@@ -1885,11 +1904,11 @@ export async function runChatWorkflow({
|
|
|
1885
1904
|
recovery
|
|
1886
1905
|
});
|
|
1887
1906
|
continue;
|
|
1888
|
-
} else if (isChatCandidateSelectionMismatchError(error)) {
|
|
1889
|
-
const retryCount = candidateRecoveryCounts.get(candidateKey) || 0;
|
|
1890
|
-
if (retryCount < 1) {
|
|
1891
|
-
candidateRecoveryCounts.set(candidateKey, retryCount + 1);
|
|
1892
|
-
const recovery = await recoverAndReapplyChatContext(
|
|
1907
|
+
} else if (isChatCandidateSelectionMismatchError(error)) {
|
|
1908
|
+
const retryCount = candidateRecoveryCounts.get(candidateKey) || 0;
|
|
1909
|
+
if (retryCount < 1) {
|
|
1910
|
+
candidateRecoveryCounts.set(candidateKey, retryCount + 1);
|
|
1911
|
+
const recovery = await recoverAndReapplyChatContext(
|
|
1893
1912
|
"active_candidate_mismatch",
|
|
1894
1913
|
error,
|
|
1895
1914
|
{ forceRefresh: true }
|
|
@@ -1901,35 +1920,35 @@ export async function runChatWorkflow({
|
|
|
1901
1920
|
continue;
|
|
1902
1921
|
}
|
|
1903
1922
|
detailUnavailableReason = "active_candidate_mismatch";
|
|
1904
|
-
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason, error);
|
|
1905
|
-
detailResult.cv_acquisition.selection_ready_state = error.selection_ready_state || null;
|
|
1906
|
-
detailResult.cv_acquisition.recovery_attempted = true;
|
|
1907
|
-
detailResult.cv_acquisition.recovery_attempt_count = retryCount;
|
|
1908
|
-
} else if (isChatOnlineResumeModalOpenFailureError(error)) {
|
|
1909
|
-
const retryCount = candidateRecoveryCounts.get(candidateKey) || 0;
|
|
1910
|
-
if (retryCount < 1) {
|
|
1911
|
-
candidateRecoveryCounts.set(candidateKey, retryCount + 1);
|
|
1912
|
-
const recovery = await recoverAndReapplyChatContext(
|
|
1913
|
-
"online_resume_modal_did_not_open",
|
|
1914
|
-
error,
|
|
1915
|
-
{ forceRefresh: true }
|
|
1916
|
-
);
|
|
1917
|
-
checkpointInProgressCandidate({
|
|
1918
|
-
event: "retry_after_online_resume_modal_open_failure",
|
|
1919
|
-
recovery
|
|
1920
|
-
});
|
|
1921
|
-
continue;
|
|
1922
|
-
}
|
|
1923
|
-
detailUnavailableReason = "online_resume_modal_did_not_open";
|
|
1924
|
-
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason, error);
|
|
1925
|
-
detailResult.cv_acquisition.attempts = error.attempts || null;
|
|
1926
|
-
detailResult.cv_acquisition.recovery_attempted = true;
|
|
1927
|
-
detailResult.cv_acquisition.recovery_attempt_count = retryCount;
|
|
1928
|
-
} else if (isUnsafeChatOnlineResumeLinkError(error)) {
|
|
1929
|
-
detailUnavailableReason = "unsafe_online_resume_navigation_link";
|
|
1930
|
-
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason, error);
|
|
1931
|
-
detailResult.cv_acquisition.blocked_pre_click = true;
|
|
1932
|
-
detailResult.cv_acquisition.button_href = error.href || null;
|
|
1923
|
+
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason, error);
|
|
1924
|
+
detailResult.cv_acquisition.selection_ready_state = error.selection_ready_state || null;
|
|
1925
|
+
detailResult.cv_acquisition.recovery_attempted = true;
|
|
1926
|
+
detailResult.cv_acquisition.recovery_attempt_count = retryCount;
|
|
1927
|
+
} else if (isChatOnlineResumeModalOpenFailureError(error)) {
|
|
1928
|
+
const retryCount = candidateRecoveryCounts.get(candidateKey) || 0;
|
|
1929
|
+
if (retryCount < 1) {
|
|
1930
|
+
candidateRecoveryCounts.set(candidateKey, retryCount + 1);
|
|
1931
|
+
const recovery = await recoverAndReapplyChatContext(
|
|
1932
|
+
"online_resume_modal_did_not_open",
|
|
1933
|
+
error,
|
|
1934
|
+
{ forceRefresh: true }
|
|
1935
|
+
);
|
|
1936
|
+
checkpointInProgressCandidate({
|
|
1937
|
+
event: "retry_after_online_resume_modal_open_failure",
|
|
1938
|
+
recovery
|
|
1939
|
+
});
|
|
1940
|
+
continue;
|
|
1941
|
+
}
|
|
1942
|
+
detailUnavailableReason = "online_resume_modal_did_not_open";
|
|
1943
|
+
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason, error);
|
|
1944
|
+
detailResult.cv_acquisition.attempts = error.attempts || null;
|
|
1945
|
+
detailResult.cv_acquisition.recovery_attempted = true;
|
|
1946
|
+
detailResult.cv_acquisition.recovery_attempt_count = retryCount;
|
|
1947
|
+
} else if (isUnsafeChatOnlineResumeLinkError(error)) {
|
|
1948
|
+
detailUnavailableReason = "unsafe_online_resume_navigation_link";
|
|
1949
|
+
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason, error);
|
|
1950
|
+
detailResult.cv_acquisition.blocked_pre_click = true;
|
|
1951
|
+
detailResult.cv_acquisition.button_href = error.href || null;
|
|
1933
1952
|
detailResult.cv_acquisition.button_selector = error.button_selector || null;
|
|
1934
1953
|
detailResult.cv_acquisition.attempts = error.attempts || null;
|
|
1935
1954
|
} else {
|
|
@@ -1940,43 +1959,43 @@ export async function runChatWorkflow({
|
|
|
1940
1959
|
await closeChatBlockingPanels(client, { attemptsLimit: 2 });
|
|
1941
1960
|
}
|
|
1942
1961
|
}
|
|
1943
|
-
screeningCandidate = detailResult?.candidate || cardCandidate;
|
|
1944
|
-
}
|
|
1962
|
+
screeningCandidate = detailResult?.candidate || cardCandidate;
|
|
1963
|
+
}
|
|
1945
1964
|
|
|
1946
1965
|
await runControl.waitIfPaused();
|
|
1947
1966
|
runControl.throwIfCanceled();
|
|
1948
1967
|
runControl.setPhase("chat:screening");
|
|
1949
1968
|
let cardOnlyLlmResult = null;
|
|
1950
|
-
if (useLlmScreening && !detailUnavailableReason && !detailResult?.llm_result) {
|
|
1951
|
-
detailUnavailableReason = detailResult
|
|
1952
|
-
? "full_cv_not_acquired"
|
|
1953
|
-
: "detail_not_opened_full_cv_required";
|
|
1954
|
-
}
|
|
1955
|
-
const effectiveLlmResult = detailResult?.llm_result || cardOnlyLlmResult;
|
|
1956
|
-
const screening = collectCvOnly
|
|
1957
|
-
? createCvCollectionScreening(screeningCandidate, {
|
|
1958
|
-
detailResult,
|
|
1959
|
-
detailUnavailableReason,
|
|
1960
|
-
preActionState
|
|
1961
|
-
})
|
|
1962
|
-
: detailUnavailableReason
|
|
1963
|
-
? {
|
|
1964
|
-
status: "skip",
|
|
1965
|
-
passed: false,
|
|
1966
|
-
score: 0,
|
|
1967
|
-
reasons: [detailUnavailableReason],
|
|
1968
|
-
candidate: screeningCandidate
|
|
1969
|
-
}
|
|
1970
|
-
: useLlmScreening
|
|
1971
|
-
? llmToScreening(effectiveLlmResult, screeningCandidate)
|
|
1972
|
-
: screenCandidate(screeningCandidate, { criteria });
|
|
1969
|
+
if (useLlmScreening && !detailUnavailableReason && !detailResult?.llm_result) {
|
|
1970
|
+
detailUnavailableReason = detailResult
|
|
1971
|
+
? "full_cv_not_acquired"
|
|
1972
|
+
: "detail_not_opened_full_cv_required";
|
|
1973
|
+
}
|
|
1974
|
+
const effectiveLlmResult = detailResult?.llm_result || cardOnlyLlmResult;
|
|
1975
|
+
const screening = collectCvOnly
|
|
1976
|
+
? createCvCollectionScreening(screeningCandidate, {
|
|
1977
|
+
detailResult,
|
|
1978
|
+
detailUnavailableReason,
|
|
1979
|
+
preActionState
|
|
1980
|
+
})
|
|
1981
|
+
: detailUnavailableReason
|
|
1982
|
+
? {
|
|
1983
|
+
status: "skip",
|
|
1984
|
+
passed: false,
|
|
1985
|
+
score: 0,
|
|
1986
|
+
reasons: [detailUnavailableReason],
|
|
1987
|
+
candidate: screeningCandidate
|
|
1988
|
+
}
|
|
1989
|
+
: useLlmScreening
|
|
1990
|
+
? llmToScreening(effectiveLlmResult, screeningCandidate)
|
|
1991
|
+
: screenCandidate(screeningCandidate, { criteria });
|
|
1973
1992
|
let postAction = null;
|
|
1974
1993
|
if (requestResumeForPassed && screening.passed) {
|
|
1975
1994
|
await maybeHumanActionCooldown("before_post_action", timings);
|
|
1976
|
-
postAction = await measureTiming(timings, "post_action_ms", () => requestChatResumeForPassedCandidate(client, {
|
|
1977
|
-
greetingText,
|
|
1978
|
-
dryRun: dryRunRequestCv
|
|
1979
|
-
}));
|
|
1995
|
+
postAction = await measureTiming(timings, "post_action_ms", () => requestChatResumeForPassedCandidate(client, {
|
|
1996
|
+
greetingText,
|
|
1997
|
+
dryRun: dryRunRequestCv
|
|
1998
|
+
}));
|
|
1980
1999
|
if (postAction?.requested) requestSatisfiedCount += 1;
|
|
1981
2000
|
if (postAction?.skipped) requestSkippedCount += 1;
|
|
1982
2001
|
if (postAction?.requested && !postAction?.skipped) requestedCount += 1;
|
|
@@ -2030,6 +2049,9 @@ export async function runChatWorkflow({
|
|
|
2030
2049
|
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
2031
2050
|
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2032
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,
|
|
2033
2055
|
human_rest_count: humanRestController.getState().rest_count,
|
|
2034
2056
|
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
2035
2057
|
last_human_event: lastHumanEvent,
|
|
@@ -2073,6 +2095,7 @@ export async function runChatWorkflow({
|
|
|
2073
2095
|
runControl.updateProgress({
|
|
2074
2096
|
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2075
2097
|
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2098
|
+
human_rest_per_candidate_enabled: collectCvPerCandidateRestEnabled,
|
|
2076
2099
|
human_rest_count: humanRestController.getState().rest_count,
|
|
2077
2100
|
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
2078
2101
|
human_rest_last: restResult,
|
|
@@ -2107,10 +2130,10 @@ export async function runChatWorkflow({
|
|
|
2107
2130
|
last_human_event: lastHumanEvent,
|
|
2108
2131
|
list_end_reason: listEndReason || null,
|
|
2109
2132
|
target_pass_count: passTarget,
|
|
2110
|
-
process_until_list_end: Boolean(processUntilListEnd),
|
|
2111
|
-
processed_limit: processedLimit,
|
|
2112
|
-
detail_source: normalizedDetailSource,
|
|
2113
|
-
processed: finalCounters.processed,
|
|
2133
|
+
process_until_list_end: Boolean(processUntilListEnd),
|
|
2134
|
+
processed_limit: processedLimit,
|
|
2135
|
+
detail_source: normalizedDetailSource,
|
|
2136
|
+
processed: finalCounters.processed,
|
|
2114
2137
|
screened: finalCounters.screened,
|
|
2115
2138
|
detail_opened: finalCounters.detail_opened,
|
|
2116
2139
|
llm_screened: finalCounters.llm_screened,
|
|
@@ -2173,14 +2196,16 @@ export function createChatRunService({
|
|
|
2173
2196
|
name = "chat-domain-run"
|
|
2174
2197
|
} = {}) {
|
|
2175
2198
|
if (!client) throw new Error("startChatRun requires a guarded CDP client");
|
|
2176
|
-
const normalizedDetailSource = normalizeDetailSource(detailSource);
|
|
2177
|
-
const normalizedScreeningMode = normalizeText(criteria) ? normalizeScreeningMode(screeningMode) : "collect_cv";
|
|
2199
|
+
const normalizedDetailSource = normalizeDetailSource(detailSource);
|
|
2200
|
+
const normalizedScreeningMode = normalizeText(criteria) ? normalizeScreeningMode(screeningMode) : "collect_cv";
|
|
2201
|
+
const collectCvOnly = normalizedScreeningMode === "collect_cv" || !normalizeText(criteria);
|
|
2178
2202
|
const processedLimit = Math.max(1, Number(maxCandidates) || 1);
|
|
2179
2203
|
const normalizedDetailLimit = detailLimit == null ? processedLimit : Math.max(0, Number(detailLimit) || 0);
|
|
2180
2204
|
const effectiveHumanBehavior = normalizeHumanBehaviorOptions(humanBehavior, {
|
|
2181
2205
|
legacyEnabled: humanRestEnabled === true || llmConfig?.humanRestEnabled === true
|
|
2182
2206
|
});
|
|
2183
|
-
const
|
|
2207
|
+
const collectCvPerCandidateRestEnabled = collectCvOnly && effectiveHumanBehavior.enabled;
|
|
2208
|
+
const effectiveHumanRestEnabled = effectiveHumanBehavior.restEnabled || collectCvPerCandidateRestEnabled;
|
|
2184
2209
|
return manager.startRun({
|
|
2185
2210
|
runId,
|
|
2186
2211
|
name,
|
|
@@ -2200,10 +2225,10 @@ export function createChatRunService({
|
|
|
2200
2225
|
dry_run_request_cv: Boolean(dryRunRequestCv),
|
|
2201
2226
|
greeting_text: greetingText,
|
|
2202
2227
|
cv_acquisition_mode: cvAcquisitionMode,
|
|
2203
|
-
call_llm_on_image: Boolean(callLlmOnImage),
|
|
2204
|
-
screening_mode: normalizedScreeningMode,
|
|
2205
|
-
cv_collection_mode: normalizedScreeningMode === "collect_cv",
|
|
2206
|
-
llm_configured: Boolean(llmConfig),
|
|
2228
|
+
call_llm_on_image: Boolean(callLlmOnImage),
|
|
2229
|
+
screening_mode: normalizedScreeningMode,
|
|
2230
|
+
cv_collection_mode: normalizedScreeningMode === "collect_cv",
|
|
2231
|
+
llm_configured: Boolean(llmConfig),
|
|
2207
2232
|
llm_timeout_ms: llmTimeoutMs,
|
|
2208
2233
|
llm_image_limit: llmImageLimit,
|
|
2209
2234
|
llm_image_detail: llmImageDetail,
|
|
@@ -2218,11 +2243,13 @@ export function createChatRunService({
|
|
|
2218
2243
|
image_output_dir: imageOutputDir || "",
|
|
2219
2244
|
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
2220
2245
|
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
2221
|
-
human_behavior: effectiveHumanBehavior,
|
|
2222
|
-
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2223
|
-
human_rest_enabled: effectiveHumanRestEnabled,
|
|
2224
|
-
|
|
2225
|
-
|
|
2246
|
+
human_behavior: effectiveHumanBehavior,
|
|
2247
|
+
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2248
|
+
human_rest_enabled: effectiveHumanRestEnabled,
|
|
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
|
|
2252
|
+
},
|
|
2226
2253
|
progress: {
|
|
2227
2254
|
card_count: 0,
|
|
2228
2255
|
target_count: targetPassCount || (processUntilListEnd ? "all" : processedLimit),
|
|
@@ -2242,68 +2269,71 @@ export function createChatRunService({
|
|
|
2242
2269
|
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
2243
2270
|
human_rest_level: effectiveHumanBehavior.restLevel,
|
|
2244
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,
|
|
2245
2275
|
human_rest_count: 0,
|
|
2246
2276
|
human_rest_ms: 0,
|
|
2247
2277
|
last_human_event: null
|
|
2248
2278
|
},
|
|
2249
|
-
checkpoint: {},
|
|
2250
|
-
task: async (runControl) => {
|
|
2251
|
-
try {
|
|
2252
|
-
return await workflow({
|
|
2253
|
-
client,
|
|
2254
|
-
targetUrl,
|
|
2255
|
-
job,
|
|
2256
|
-
startFrom,
|
|
2257
|
-
criteria,
|
|
2258
|
-
maxCandidates,
|
|
2259
|
-
targetPassCount,
|
|
2260
|
-
processUntilListEnd,
|
|
2261
|
-
detailLimit: normalizedDetailLimit,
|
|
2262
|
-
detailSource: normalizedDetailSource,
|
|
2263
|
-
closeResume,
|
|
2264
|
-
requestResumeForPassed,
|
|
2265
|
-
dryRunRequestCv,
|
|
2266
|
-
greetingText,
|
|
2267
|
-
delayMs,
|
|
2268
|
-
cardTimeoutMs,
|
|
2269
|
-
readyTimeoutMs,
|
|
2270
|
-
onlineResumeButtonTimeoutMs,
|
|
2271
|
-
resumeDomTimeoutMs,
|
|
2272
|
-
maxImagePages,
|
|
2273
|
-
imageWheelDeltaY,
|
|
2274
|
-
cvAcquisitionMode,
|
|
2275
|
-
callLlmOnImage,
|
|
2276
|
-
llmConfig,
|
|
2277
|
-
llmTimeoutMs,
|
|
2278
|
-
llmImageLimit,
|
|
2279
|
-
llmImageDetail,
|
|
2280
|
-
screeningMode: normalizedScreeningMode,
|
|
2281
|
-
listMaxScrolls,
|
|
2282
|
-
listStableSignatureLimit,
|
|
2283
|
-
listWheelDeltaY,
|
|
2284
|
-
listSettleMs,
|
|
2285
|
-
listFallbackPoint,
|
|
2286
|
-
imageOutputDir,
|
|
2287
|
-
humanRestEnabled: effectiveHumanRestEnabled,
|
|
2288
|
-
humanBehavior: effectiveHumanBehavior
|
|
2289
|
-
}, runControl);
|
|
2290
|
-
} catch (error) {
|
|
2291
|
-
if (error instanceof RunCanceledError) throw error;
|
|
2292
|
-
const finalFailureArtifact = await captureChatFinalFailureArtifact(client, {
|
|
2293
|
-
runControl,
|
|
2294
|
-
imageOutputDir,
|
|
2295
|
-
error
|
|
2296
|
-
});
|
|
2297
|
-
if (finalFailureArtifact) {
|
|
2298
|
-
runControl.checkpoint({
|
|
2299
|
-
final_failure_artifact: finalFailureArtifact
|
|
2300
|
-
});
|
|
2301
|
-
}
|
|
2302
|
-
throw error;
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2305
|
-
});
|
|
2306
|
-
}
|
|
2279
|
+
checkpoint: {},
|
|
2280
|
+
task: async (runControl) => {
|
|
2281
|
+
try {
|
|
2282
|
+
return await workflow({
|
|
2283
|
+
client,
|
|
2284
|
+
targetUrl,
|
|
2285
|
+
job,
|
|
2286
|
+
startFrom,
|
|
2287
|
+
criteria,
|
|
2288
|
+
maxCandidates,
|
|
2289
|
+
targetPassCount,
|
|
2290
|
+
processUntilListEnd,
|
|
2291
|
+
detailLimit: normalizedDetailLimit,
|
|
2292
|
+
detailSource: normalizedDetailSource,
|
|
2293
|
+
closeResume,
|
|
2294
|
+
requestResumeForPassed,
|
|
2295
|
+
dryRunRequestCv,
|
|
2296
|
+
greetingText,
|
|
2297
|
+
delayMs,
|
|
2298
|
+
cardTimeoutMs,
|
|
2299
|
+
readyTimeoutMs,
|
|
2300
|
+
onlineResumeButtonTimeoutMs,
|
|
2301
|
+
resumeDomTimeoutMs,
|
|
2302
|
+
maxImagePages,
|
|
2303
|
+
imageWheelDeltaY,
|
|
2304
|
+
cvAcquisitionMode,
|
|
2305
|
+
callLlmOnImage,
|
|
2306
|
+
llmConfig,
|
|
2307
|
+
llmTimeoutMs,
|
|
2308
|
+
llmImageLimit,
|
|
2309
|
+
llmImageDetail,
|
|
2310
|
+
screeningMode: normalizedScreeningMode,
|
|
2311
|
+
listMaxScrolls,
|
|
2312
|
+
listStableSignatureLimit,
|
|
2313
|
+
listWheelDeltaY,
|
|
2314
|
+
listSettleMs,
|
|
2315
|
+
listFallbackPoint,
|
|
2316
|
+
imageOutputDir,
|
|
2317
|
+
humanRestEnabled: effectiveHumanRestEnabled,
|
|
2318
|
+
humanBehavior: effectiveHumanBehavior
|
|
2319
|
+
}, runControl);
|
|
2320
|
+
} catch (error) {
|
|
2321
|
+
if (error instanceof RunCanceledError) throw error;
|
|
2322
|
+
const finalFailureArtifact = await captureChatFinalFailureArtifact(client, {
|
|
2323
|
+
runControl,
|
|
2324
|
+
imageOutputDir,
|
|
2325
|
+
error
|
|
2326
|
+
});
|
|
2327
|
+
if (finalFailureArtifact) {
|
|
2328
|
+
runControl.checkpoint({
|
|
2329
|
+
final_failure_artifact: finalFailureArtifact
|
|
2330
|
+
});
|
|
2331
|
+
}
|
|
2332
|
+
throw error;
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2307
2337
|
|
|
2308
2338
|
return {
|
|
2309
2339
|
startChatRun,
|