@reconcrap/boss-recommend-mcp 2.1.21 → 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 -2415
- 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 +571 -571
- 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,
|
|
@@ -88,13 +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
|
-
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) {
|
|
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) {
|
|
98
98
|
const normalized = String(value || "").trim().toLowerCase();
|
|
99
99
|
return DETAIL_SOURCES.has(normalized) ? normalized : "cascade";
|
|
100
100
|
}
|
|
@@ -116,35 +116,35 @@ function compactScreening(screening) {
|
|
|
116
116
|
|
|
117
117
|
function compactLlmResult(llmResult) {
|
|
118
118
|
if (!llmResult) return 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,
|
|
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,
|
|
129
129
|
finish_reason: llmResult.finish_reason || null,
|
|
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
|
-
}
|
|
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
|
+
}
|
|
148
148
|
|
|
149
149
|
function compactCandidate(candidate) {
|
|
150
150
|
return {
|
|
@@ -363,9 +363,9 @@ function isRecoverableLlmScreeningError(error) {
|
|
|
363
363
|
}
|
|
364
364
|
|
|
365
365
|
function createFailedLlmResult(error) {
|
|
366
|
-
return {
|
|
367
|
-
ok: false,
|
|
368
|
-
passed: false,
|
|
366
|
+
return {
|
|
367
|
+
ok: false,
|
|
368
|
+
passed: false,
|
|
369
369
|
reason: "",
|
|
370
370
|
evidence: [],
|
|
371
371
|
cot: "",
|
|
@@ -373,110 +373,110 @@ function createFailedLlmResult(error) {
|
|
|
373
373
|
reasoning_content: "",
|
|
374
374
|
raw_model_output: "",
|
|
375
375
|
attempt_count: Number(error?.llm_attempt_count) || 0,
|
|
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
|
-
}
|
|
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
|
+
}
|
|
480
480
|
|
|
481
481
|
function createMissingLlmConfigResult() {
|
|
482
482
|
return createFailedLlmResult(new Error("LLM screening config is required for production chat runs"));
|
|
@@ -498,81 +498,81 @@ function createSkippedDetailResult(cardCandidate, reason, error = null) {
|
|
|
498
498
|
};
|
|
499
499
|
}
|
|
500
500
|
|
|
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
|
-
}
|
|
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
|
+
}
|
|
576
576
|
|
|
577
577
|
const CHAT_FULL_CV_DOM_MIN_TEXT_LENGTH = 500;
|
|
578
578
|
const CHAT_FULL_CV_DOM_MIN_SECTION_TEXT_LENGTH = 180;
|
|
@@ -740,15 +740,15 @@ async function resolveFreshChatCardNodeId(client, {
|
|
|
740
740
|
return freshNodeId || fallbackNodeId;
|
|
741
741
|
}
|
|
742
742
|
|
|
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) {
|
|
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) {
|
|
752
752
|
const modalGuard = await ensureNoOpenChatResumeModalBeforeCandidateClick(client);
|
|
753
753
|
const rootState = await getChatRoots(client);
|
|
754
754
|
const freshNodeId = await resolveFreshChatCardNodeId(client, {
|
|
@@ -759,18 +759,18 @@ async function selectFreshChatCandidate(client, {
|
|
|
759
759
|
try {
|
|
760
760
|
await scrollNodeIntoView(client, freshNodeId);
|
|
761
761
|
await sleep(250);
|
|
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,
|
|
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,
|
|
774
774
|
card_node_id: freshNodeId,
|
|
775
775
|
refreshed_node: freshNodeId !== cardNodeId,
|
|
776
776
|
modal_guard: modalGuard,
|
|
@@ -782,35 +782,35 @@ async function selectFreshChatCandidate(client, {
|
|
|
782
782
|
await sleep(350);
|
|
783
783
|
}
|
|
784
784
|
}
|
|
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
|
-
}
|
|
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
|
+
}
|
|
814
814
|
|
|
815
815
|
function selectedDetailNetworkEvents(detailSource, selectionEvents, resumeEvents) {
|
|
816
816
|
if (detailSource !== "network" && detailSource !== "cascade") return [];
|
|
@@ -941,32 +941,32 @@ export async function runChatWorkflow({
|
|
|
941
941
|
humanBehavior = null
|
|
942
942
|
} = {}, runControl) {
|
|
943
943
|
if (!client) throw new Error("runChatWorkflow requires a guarded CDP client");
|
|
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,
|
|
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,
|
|
956
956
|
textEntryEnabled: effectiveHumanBehavior.textEntry,
|
|
957
957
|
safeClickPointEnabled: effectiveHumanBehavior.clickMovement,
|
|
958
958
|
actionCooldownEnabled: effectiveHumanBehavior.actionCooldown
|
|
959
959
|
});
|
|
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
|
-
});
|
|
969
|
-
const processedLimit = Math.max(1, Number(maxCandidates) || 1);
|
|
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
|
+
});
|
|
969
|
+
const processedLimit = Math.max(1, Number(maxCandidates) || 1);
|
|
970
970
|
const passTarget = Number.isFinite(Number(targetPassCount)) && Number(targetPassCount) > 0
|
|
971
971
|
? Number(targetPassCount)
|
|
972
972
|
: null;
|
|
@@ -1006,12 +1006,12 @@ export async function runChatWorkflow({
|
|
|
1006
1006
|
let requestedCount = 0;
|
|
1007
1007
|
let requestSatisfiedCount = 0;
|
|
1008
1008
|
let requestSkippedCount = 0;
|
|
1009
|
-
let contextSetup = {};
|
|
1010
|
-
let contextRecoveryAttempts = 0;
|
|
1011
|
-
const candidateRecoveryCounts = new Map();
|
|
1012
|
-
let lastHumanEvent = null;
|
|
1013
|
-
|
|
1014
|
-
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) {
|
|
1015
1015
|
if (!event) return lastHumanEvent;
|
|
1016
1016
|
lastHumanEvent = {
|
|
1017
1017
|
at: new Date().toISOString(),
|
|
@@ -1075,13 +1075,13 @@ export async function runChatWorkflow({
|
|
|
1075
1075
|
...setup.contextSetup,
|
|
1076
1076
|
initial_top_level_state: initialTopLevelState
|
|
1077
1077
|
};
|
|
1078
|
-
runControl.checkpoint({
|
|
1079
|
-
chat_context: contextSetup
|
|
1080
|
-
});
|
|
1081
|
-
|
|
1082
|
-
async function recoverAndReapplyChatContext(reason, error = null, {
|
|
1083
|
-
forceRefresh = false
|
|
1084
|
-
} = {}) {
|
|
1078
|
+
runControl.checkpoint({
|
|
1079
|
+
chat_context: contextSetup
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
async function recoverAndReapplyChatContext(reason, error = null, {
|
|
1083
|
+
forceRefresh = false
|
|
1084
|
+
} = {}) {
|
|
1085
1085
|
runControl.setPhase("chat:recover_shell");
|
|
1086
1086
|
contextRecoveryAttempts += 1;
|
|
1087
1087
|
const shellRecovery = await recoverChatShell(client, {
|
|
@@ -1183,14 +1183,14 @@ export async function runChatWorkflow({
|
|
|
1183
1183
|
viewport_checks: viewportGuard.getStats().checks,
|
|
1184
1184
|
viewport_recoveries: viewportGuard.getStats().recoveries,
|
|
1185
1185
|
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
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,
|
|
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,
|
|
1194
1194
|
last_human_event: lastHumanEvent
|
|
1195
1195
|
});
|
|
1196
1196
|
runControl.setPhase("chat:done");
|
|
@@ -1214,10 +1214,10 @@ export async function runChatWorkflow({
|
|
|
1214
1214
|
last_human_event: lastHumanEvent,
|
|
1215
1215
|
list_end_reason: listEndReason,
|
|
1216
1216
|
target_pass_count: passTarget,
|
|
1217
|
-
process_until_list_end: Boolean(processUntilListEnd),
|
|
1218
|
-
processed_limit: processedLimit,
|
|
1219
|
-
detail_source: normalizedDetailSource,
|
|
1220
|
-
processed: 0,
|
|
1217
|
+
process_until_list_end: Boolean(processUntilListEnd),
|
|
1218
|
+
processed_limit: processedLimit,
|
|
1219
|
+
detail_source: normalizedDetailSource,
|
|
1220
|
+
processed: 0,
|
|
1221
1221
|
screened: 0,
|
|
1222
1222
|
detail_opened: 0,
|
|
1223
1223
|
llm_screened: 0,
|
|
@@ -1248,20 +1248,20 @@ export async function runChatWorkflow({
|
|
|
1248
1248
|
screening_mode: normalizedScreeningMode,
|
|
1249
1249
|
unique_seen: compactInfiniteListState(listState).seen_count,
|
|
1250
1250
|
scroll_count: 0,
|
|
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
|
-
});
|
|
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
|
+
});
|
|
1265
1265
|
|
|
1266
1266
|
while (
|
|
1267
1267
|
results.length < processedLimit
|
|
@@ -1424,12 +1424,12 @@ export async function runChatWorkflow({
|
|
|
1424
1424
|
detailStep = "select_candidate";
|
|
1425
1425
|
networkRecorder.clear();
|
|
1426
1426
|
await maybeHumanActionCooldown("before_detail_open", timings);
|
|
1427
|
-
const selected = await measureTiming(timings, "candidate_click_ms", () => selectFreshChatCandidate(client, {
|
|
1428
|
-
cardNodeId,
|
|
1429
|
-
candidate: cardCandidate,
|
|
1430
|
-
timeoutMs: onlineResumeButtonTimeoutMs,
|
|
1431
|
-
onlineResumeProbe: !collectCvOnly
|
|
1432
|
-
}));
|
|
1427
|
+
const selected = await measureTiming(timings, "candidate_click_ms", () => selectFreshChatCandidate(client, {
|
|
1428
|
+
cardNodeId,
|
|
1429
|
+
candidate: cardCandidate,
|
|
1430
|
+
timeoutMs: onlineResumeButtonTimeoutMs,
|
|
1431
|
+
onlineResumeProbe: !collectCvOnly
|
|
1432
|
+
}));
|
|
1433
1433
|
if (selected.ready?.forbidden_top_level_navigation) {
|
|
1434
1434
|
throw makeForbiddenChatResumeNavigationError(selected.ready.top_level_state);
|
|
1435
1435
|
}
|
|
@@ -1449,11 +1449,11 @@ export async function runChatWorkflow({
|
|
|
1449
1449
|
detailResult.cv_acquisition.pre_detail_state = preActionState;
|
|
1450
1450
|
detailResult.cv_acquisition.selection_ready_state = selected.ready;
|
|
1451
1451
|
}
|
|
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);
|
|
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);
|
|
1457
1457
|
} else {
|
|
1458
1458
|
detailStep = "read_conversation_ready_state";
|
|
1459
1459
|
if (preActionState.attachment_resume_enabled) {
|
|
@@ -1463,18 +1463,18 @@ export async function runChatWorkflow({
|
|
|
1463
1463
|
} else {
|
|
1464
1464
|
detailUnavailableReason = "online_resume_button_unavailable";
|
|
1465
1465
|
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason);
|
|
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);
|
|
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);
|
|
1478
1478
|
let networkWait = null;
|
|
1479
1479
|
let contentWait = {
|
|
1480
1480
|
ok: false,
|
|
@@ -1734,24 +1734,24 @@ export async function runChatWorkflow({
|
|
|
1734
1734
|
llmResult = createMissingLlmConfigResult();
|
|
1735
1735
|
} else {
|
|
1736
1736
|
try {
|
|
1737
|
-
llmResult = await measureTiming(timings, "vision_model_ms", () => callScreeningLlm({
|
|
1738
|
-
candidate: detailResult.candidate,
|
|
1739
|
-
criteria,
|
|
1740
|
-
config: llmConfig,
|
|
1741
|
-
timeoutMs: llmTimeoutMs,
|
|
1737
|
+
llmResult = await measureTiming(timings, "vision_model_ms", () => callScreeningLlm({
|
|
1738
|
+
candidate: detailResult.candidate,
|
|
1739
|
+
criteria,
|
|
1740
|
+
config: llmConfig,
|
|
1741
|
+
timeoutMs: llmTimeoutMs,
|
|
1742
1742
|
imageEvidence,
|
|
1743
1743
|
maxImages: llmImageLimit,
|
|
1744
1744
|
imageDetail: llmImageDetail
|
|
1745
1745
|
}));
|
|
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
|
-
}
|
|
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
|
+
}
|
|
1755
1755
|
}
|
|
1756
1756
|
}
|
|
1757
1757
|
} else {
|
|
@@ -1813,24 +1813,24 @@ export async function runChatWorkflow({
|
|
|
1813
1813
|
const llmTimingKey = imageEvidence?.file_paths?.length
|
|
1814
1814
|
? "vision_model_ms"
|
|
1815
1815
|
: "text_model_ms";
|
|
1816
|
-
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1817
|
-
candidate: detailResult.candidate,
|
|
1818
|
-
criteria,
|
|
1819
|
-
config: llmConfig,
|
|
1816
|
+
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1817
|
+
candidate: detailResult.candidate,
|
|
1818
|
+
criteria,
|
|
1819
|
+
config: llmConfig,
|
|
1820
1820
|
timeoutMs: llmTimeoutMs,
|
|
1821
1821
|
imageEvidence,
|
|
1822
1822
|
maxImages: llmImageLimit,
|
|
1823
1823
|
imageDetail: llmImageDetail
|
|
1824
1824
|
}));
|
|
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
|
-
}
|
|
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
|
+
}
|
|
1834
1834
|
}
|
|
1835
1835
|
}
|
|
1836
1836
|
}
|
|
@@ -1904,11 +1904,11 @@ export async function runChatWorkflow({
|
|
|
1904
1904
|
recovery
|
|
1905
1905
|
});
|
|
1906
1906
|
continue;
|
|
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(
|
|
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(
|
|
1912
1912
|
"active_candidate_mismatch",
|
|
1913
1913
|
error,
|
|
1914
1914
|
{ forceRefresh: true }
|
|
@@ -1920,35 +1920,35 @@ export async function runChatWorkflow({
|
|
|
1920
1920
|
continue;
|
|
1921
1921
|
}
|
|
1922
1922
|
detailUnavailableReason = "active_candidate_mismatch";
|
|
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;
|
|
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;
|
|
1952
1952
|
detailResult.cv_acquisition.button_selector = error.button_selector || null;
|
|
1953
1953
|
detailResult.cv_acquisition.attempts = error.attempts || null;
|
|
1954
1954
|
} else {
|
|
@@ -1959,43 +1959,43 @@ export async function runChatWorkflow({
|
|
|
1959
1959
|
await closeChatBlockingPanels(client, { attemptsLimit: 2 });
|
|
1960
1960
|
}
|
|
1961
1961
|
}
|
|
1962
|
-
screeningCandidate = detailResult?.candidate || cardCandidate;
|
|
1963
|
-
}
|
|
1962
|
+
screeningCandidate = detailResult?.candidate || cardCandidate;
|
|
1963
|
+
}
|
|
1964
1964
|
|
|
1965
1965
|
await runControl.waitIfPaused();
|
|
1966
1966
|
runControl.throwIfCanceled();
|
|
1967
1967
|
runControl.setPhase("chat:screening");
|
|
1968
1968
|
let cardOnlyLlmResult = null;
|
|
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 });
|
|
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 });
|
|
1992
1992
|
let postAction = null;
|
|
1993
1993
|
if (requestResumeForPassed && screening.passed) {
|
|
1994
1994
|
await maybeHumanActionCooldown("before_post_action", timings);
|
|
1995
|
-
postAction = await measureTiming(timings, "post_action_ms", () => requestChatResumeForPassedCandidate(client, {
|
|
1996
|
-
greetingText,
|
|
1997
|
-
dryRun: dryRunRequestCv
|
|
1998
|
-
}));
|
|
1995
|
+
postAction = await measureTiming(timings, "post_action_ms", () => requestChatResumeForPassedCandidate(client, {
|
|
1996
|
+
greetingText,
|
|
1997
|
+
dryRun: dryRunRequestCv
|
|
1998
|
+
}));
|
|
1999
1999
|
if (postAction?.requested) requestSatisfiedCount += 1;
|
|
2000
2000
|
if (postAction?.skipped) requestSkippedCount += 1;
|
|
2001
2001
|
if (postAction?.requested && !postAction?.skipped) requestedCount += 1;
|
|
@@ -2046,14 +2046,14 @@ export async function runChatWorkflow({
|
|
|
2046
2046
|
viewport_checks: viewportGuard.getStats().checks,
|
|
2047
2047
|
viewport_recoveries: viewportGuard.getStats().recoveries,
|
|
2048
2048
|
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
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,
|
|
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,
|
|
2057
2057
|
last_human_event: lastHumanEvent,
|
|
2058
2058
|
last_candidate_id: screeningCandidate.id || null,
|
|
2059
2059
|
last_candidate_key: candidateKey,
|
|
@@ -2093,11 +2093,11 @@ export async function runChatWorkflow({
|
|
|
2093
2093
|
addTiming(compactResult.timings, "human_rest_ms", restElapsed);
|
|
2094
2094
|
compactResult.timings.total_ms = Date.now() - candidateStarted;
|
|
2095
2095
|
runControl.updateProgress({
|
|
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,
|
|
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,
|
|
2101
2101
|
human_rest_last: restResult,
|
|
2102
2102
|
context_recoveries: contextRecoveryAttempts,
|
|
2103
2103
|
last_human_event: lastHumanEvent
|
|
@@ -2130,10 +2130,10 @@ export async function runChatWorkflow({
|
|
|
2130
2130
|
last_human_event: lastHumanEvent,
|
|
2131
2131
|
list_end_reason: listEndReason || null,
|
|
2132
2132
|
target_pass_count: passTarget,
|
|
2133
|
-
process_until_list_end: Boolean(processUntilListEnd),
|
|
2134
|
-
processed_limit: processedLimit,
|
|
2135
|
-
detail_source: normalizedDetailSource,
|
|
2136
|
-
processed: finalCounters.processed,
|
|
2133
|
+
process_until_list_end: Boolean(processUntilListEnd),
|
|
2134
|
+
processed_limit: processedLimit,
|
|
2135
|
+
detail_source: normalizedDetailSource,
|
|
2136
|
+
processed: finalCounters.processed,
|
|
2137
2137
|
screened: finalCounters.screened,
|
|
2138
2138
|
detail_opened: finalCounters.detail_opened,
|
|
2139
2139
|
llm_screened: finalCounters.llm_screened,
|
|
@@ -2196,16 +2196,16 @@ export function createChatRunService({
|
|
|
2196
2196
|
name = "chat-domain-run"
|
|
2197
2197
|
} = {}) {
|
|
2198
2198
|
if (!client) throw new Error("startChatRun requires a guarded CDP client");
|
|
2199
|
-
const normalizedDetailSource = normalizeDetailSource(detailSource);
|
|
2200
|
-
const normalizedScreeningMode = normalizeText(criteria) ? normalizeScreeningMode(screeningMode) : "collect_cv";
|
|
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;
|
|
2199
|
+
const normalizedDetailSource = normalizeDetailSource(detailSource);
|
|
2200
|
+
const normalizedScreeningMode = normalizeText(criteria) ? normalizeScreeningMode(screeningMode) : "collect_cv";
|
|
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;
|
|
2209
2209
|
return manager.startRun({
|
|
2210
2210
|
runId,
|
|
2211
2211
|
name,
|
|
@@ -2225,16 +2225,16 @@ export function createChatRunService({
|
|
|
2225
2225
|
dry_run_request_cv: Boolean(dryRunRequestCv),
|
|
2226
2226
|
greeting_text: greetingText,
|
|
2227
2227
|
cv_acquisition_mode: cvAcquisitionMode,
|
|
2228
|
-
call_llm_on_image: Boolean(callLlmOnImage),
|
|
2229
|
-
screening_mode: normalizedScreeningMode,
|
|
2230
|
-
cv_collection_mode: normalizedScreeningMode === "collect_cv",
|
|
2231
|
-
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),
|
|
2232
2232
|
llm_timeout_ms: llmTimeoutMs,
|
|
2233
2233
|
llm_image_limit: llmImageLimit,
|
|
2234
|
-
llm_image_detail: llmImageDetail,
|
|
2235
|
-
max_image_pages: maxImagePages,
|
|
2236
|
-
image_wheel_delta_y: imageWheelDeltaY,
|
|
2237
|
-
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,
|
|
2238
2238
|
list_stable_signature_limit: listStableSignatureLimit,
|
|
2239
2239
|
list_wheel_delta_y: listWheelDeltaY,
|
|
2240
2240
|
list_settle_ms: listSettleMs,
|
|
@@ -2243,13 +2243,13 @@ export function createChatRunService({
|
|
|
2243
2243
|
image_output_dir: imageOutputDir || "",
|
|
2244
2244
|
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
2245
2245
|
human_behavior_profile: effectiveHumanBehavior.profile,
|
|
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
|
-
},
|
|
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
|
+
},
|
|
2253
2253
|
progress: {
|
|
2254
2254
|
card_count: 0,
|
|
2255
2255
|
target_count: targetPassCount || (processUntilListEnd ? "all" : processedLimit),
|
|
@@ -2266,74 +2266,74 @@ export function createChatRunService({
|
|
|
2266
2266
|
request_skipped: 0,
|
|
2267
2267
|
context_recoveries: 0,
|
|
2268
2268
|
human_behavior_enabled: effectiveHumanBehavior.enabled,
|
|
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,
|
|
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,
|
|
2276
2276
|
human_rest_ms: 0,
|
|
2277
2277
|
last_human_event: null
|
|
2278
2278
|
},
|
|
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
|
-
}
|
|
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
|
+
}
|
|
2337
2337
|
|
|
2338
2338
|
return {
|
|
2339
2339
|
startChatRun,
|