@reconcrap/boss-recommend-mcp 2.0.13 → 2.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/domains/chat/jobs.js +100 -9
- package/src/domains/chat/run-service.js +179 -40
package/package.json
CHANGED
package/src/domains/chat/jobs.js
CHANGED
|
@@ -223,6 +223,15 @@ function matchJobOption(option, jobLabel = "") {
|
|
|
223
223
|
));
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
function activeMatchingJobOption(options = [], jobLabel = "") {
|
|
227
|
+
return (options || []).find((option) => option.active && matchJobOption(option, jobLabel)) || null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function selectedLabelMatches(label = "", jobLabel = "") {
|
|
231
|
+
const normalized = normalizeJobText(label);
|
|
232
|
+
return Boolean(normalized && matchJobOption({ label: normalized, value: normalized, title: normalized }, jobLabel));
|
|
233
|
+
}
|
|
234
|
+
|
|
226
235
|
async function clickFirstVisible(client, rootNodeId, selectors = []) {
|
|
227
236
|
for (const selector of selectors) {
|
|
228
237
|
const nodeIds = await safeQuerySelectorAll(client, rootNodeId, selector);
|
|
@@ -247,6 +256,62 @@ async function clickFirstVisible(client, rootNodeId, selectors = []) {
|
|
|
247
256
|
};
|
|
248
257
|
}
|
|
249
258
|
|
|
259
|
+
async function waitForChatJobOptions(client, rootNodeId, {
|
|
260
|
+
timeoutMs = 12000,
|
|
261
|
+
intervalMs = 300,
|
|
262
|
+
requireVisible = false
|
|
263
|
+
} = {}) {
|
|
264
|
+
const started = Date.now();
|
|
265
|
+
let latest = null;
|
|
266
|
+
while (Date.now() - started <= timeoutMs) {
|
|
267
|
+
const currentRootNodeId = await freshTopRootNodeId(client, rootNodeId);
|
|
268
|
+
latest = await readChatJobOptions(client, currentRootNodeId, {
|
|
269
|
+
timeoutMs: Math.min(intervalMs, 300),
|
|
270
|
+
intervalMs
|
|
271
|
+
});
|
|
272
|
+
const options = latest.job_options || [];
|
|
273
|
+
if (options.length && (!requireVisible || options.some((option) => option.visible))) {
|
|
274
|
+
return latest;
|
|
275
|
+
}
|
|
276
|
+
await sleep(intervalMs);
|
|
277
|
+
}
|
|
278
|
+
return latest || {
|
|
279
|
+
selector: "",
|
|
280
|
+
source: "chat-job-list",
|
|
281
|
+
selected_label: "",
|
|
282
|
+
job_options: []
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async function waitForSelectedChatJob(client, rootNodeId, jobLabel = "", {
|
|
287
|
+
timeoutMs = 5000,
|
|
288
|
+
intervalMs = 300
|
|
289
|
+
} = {}) {
|
|
290
|
+
const started = Date.now();
|
|
291
|
+
let latest = null;
|
|
292
|
+
while (Date.now() - started <= timeoutMs) {
|
|
293
|
+
const currentRootNodeId = await freshTopRootNodeId(client, rootNodeId);
|
|
294
|
+
latest = await readChatJobOptions(client, currentRootNodeId, {
|
|
295
|
+
timeoutMs: Math.min(intervalMs, 300),
|
|
296
|
+
intervalMs
|
|
297
|
+
});
|
|
298
|
+
if (
|
|
299
|
+
selectedLabelMatches(latest.selected_label, jobLabel)
|
|
300
|
+
|| activeMatchingJobOption(latest.job_options || [], jobLabel)
|
|
301
|
+
) {
|
|
302
|
+
return {
|
|
303
|
+
verified: true,
|
|
304
|
+
result: latest
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
await sleep(intervalMs);
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
verified: false,
|
|
311
|
+
result: latest
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
250
315
|
export async function selectChatJob(client, rootNodeId, {
|
|
251
316
|
jobLabel = "",
|
|
252
317
|
timeoutMs = 12000,
|
|
@@ -267,14 +332,34 @@ export async function selectChatJob(client, rootNodeId, {
|
|
|
267
332
|
intervalMs
|
|
268
333
|
});
|
|
269
334
|
let matched = (optionsResult.job_options || []).find((option) => matchJobOption(option, requested)) || null;
|
|
335
|
+
if (
|
|
336
|
+
matched
|
|
337
|
+
&& (
|
|
338
|
+
matched.active
|
|
339
|
+
|| selectedLabelMatches(optionsResult.selected_label, matched.label)
|
|
340
|
+
|| selectedLabelMatches(optionsResult.selected_label, requested)
|
|
341
|
+
)
|
|
342
|
+
) {
|
|
343
|
+
return {
|
|
344
|
+
selected: true,
|
|
345
|
+
verified: true,
|
|
346
|
+
already_current: true,
|
|
347
|
+
requested,
|
|
348
|
+
selected_option: matched,
|
|
349
|
+
options: optionsResult.job_options || [],
|
|
350
|
+
selected_label: optionsResult.selected_label || matched.label
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
270
354
|
if (!matched || !matched.visible) {
|
|
271
355
|
const triggerRootNodeId = await freshTopRootNodeId(client, currentRootNodeId);
|
|
272
356
|
const trigger = await clickFirstVisible(client, triggerRootNodeId, CHAT_JOB_TRIGGER_SELECTORS);
|
|
273
357
|
if (settleMs > 0) await sleep(settleMs);
|
|
274
358
|
currentRootNodeId = await freshTopRootNodeId(client, triggerRootNodeId);
|
|
275
|
-
optionsResult = await
|
|
359
|
+
optionsResult = await waitForChatJobOptions(client, currentRootNodeId, {
|
|
276
360
|
timeoutMs,
|
|
277
|
-
intervalMs
|
|
361
|
+
intervalMs,
|
|
362
|
+
requireVisible: true
|
|
278
363
|
});
|
|
279
364
|
matched = (optionsResult.job_options || []).find((option) => matchJobOption(option, requested)) || null;
|
|
280
365
|
if (!matched || !matched.visible) {
|
|
@@ -292,6 +377,7 @@ export async function selectChatJob(client, rootNodeId, {
|
|
|
292
377
|
if (matched.active || normalizeJobText(optionsResult.selected_label).toLowerCase() === normalizeJobText(matched.label).toLowerCase()) {
|
|
293
378
|
return {
|
|
294
379
|
selected: true,
|
|
380
|
+
verified: true,
|
|
295
381
|
already_current: true,
|
|
296
382
|
requested,
|
|
297
383
|
selected_option: matched,
|
|
@@ -310,22 +396,27 @@ export async function selectChatJob(client, rootNodeId, {
|
|
|
310
396
|
if (settleMs > 0) await sleep(settleMs);
|
|
311
397
|
|
|
312
398
|
const afterRootNodeId = await freshTopRootNodeId(client, currentRootNodeId);
|
|
313
|
-
const
|
|
314
|
-
timeoutMs: Math.min(timeoutMs,
|
|
399
|
+
const verification = await waitForSelectedChatJob(client, afterRootNodeId, matched.label, {
|
|
400
|
+
timeoutMs: Math.min(timeoutMs, 5000),
|
|
315
401
|
intervalMs
|
|
316
402
|
});
|
|
403
|
+
const after = verification.result || {
|
|
404
|
+
selected_label: "",
|
|
405
|
+
job_options: []
|
|
406
|
+
};
|
|
317
407
|
const afterMatch = (after.job_options || []).find((option) => matchJobOption(option, matched.label)) || matched;
|
|
318
|
-
const selectedLabel = normalizeJobText(after.selected_label ||
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
: true;
|
|
408
|
+
const selectedLabel = normalizeJobText(after.selected_label || "");
|
|
409
|
+
const activeMatch = activeMatchingJobOption(after.job_options || [], matched.label);
|
|
410
|
+
const verified = Boolean(verification.verified || selectedLabelMatches(selectedLabel, matched.label) || activeMatch);
|
|
322
411
|
|
|
323
412
|
return {
|
|
324
|
-
selected:
|
|
413
|
+
selected: verified,
|
|
325
414
|
verified,
|
|
326
415
|
already_current: false,
|
|
416
|
+
reason: verified ? "verified" : "job_selection_not_verified",
|
|
327
417
|
requested,
|
|
328
418
|
selected_option: afterMatch,
|
|
419
|
+
active_option: activeMatch,
|
|
329
420
|
options: after.job_options || optionsResult.job_options || [],
|
|
330
421
|
selected_label: selectedLabel,
|
|
331
422
|
before: optionsResult,
|
|
@@ -203,6 +203,115 @@ function createSkippedDetailResult(cardCandidate, reason, error = null) {
|
|
|
203
203
|
};
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
const CHAT_FULL_CV_DOM_MIN_TEXT_LENGTH = 500;
|
|
207
|
+
const CHAT_FULL_CV_DOM_MIN_SECTION_TEXT_LENGTH = 180;
|
|
208
|
+
const CHAT_FULL_CV_SECTION_PATTERNS = Object.freeze([
|
|
209
|
+
/教育(?:经历|背景|经验)?/i,
|
|
210
|
+
/工作(?:经历|经验)?/i,
|
|
211
|
+
/项目(?:经历|经验)?/i,
|
|
212
|
+
/实习(?:经历|经验)?/i,
|
|
213
|
+
/科研(?:经历|经验)?/i,
|
|
214
|
+
/论文|会议|专利/i,
|
|
215
|
+
/个人(?:优势|总结|介绍|评价)/i,
|
|
216
|
+
/专业技能|技能(?:特长|标签)?/i,
|
|
217
|
+
/求职(?:期望|意向)/i,
|
|
218
|
+
/校园经历|在校经历|竞赛|证书/i
|
|
219
|
+
]);
|
|
220
|
+
|
|
221
|
+
function detailTextForFullCvCheck(detailResult = {}) {
|
|
222
|
+
return [
|
|
223
|
+
detailResult?.detail?.popup_text,
|
|
224
|
+
detailResult?.detail?.content_text,
|
|
225
|
+
detailResult?.detail?.resume_iframe_text
|
|
226
|
+
].filter(Boolean).join("\n\n");
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function resumeSectionMatchCount(text = "") {
|
|
230
|
+
const normalized = normalizeText(text);
|
|
231
|
+
if (!normalized) return 0;
|
|
232
|
+
return CHAT_FULL_CV_SECTION_PATTERNS
|
|
233
|
+
.filter((pattern) => pattern.test(normalized))
|
|
234
|
+
.length;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function hasResumeLikeDomText(text = "") {
|
|
238
|
+
const normalized = normalizeText(text);
|
|
239
|
+
if (normalized.length >= CHAT_FULL_CV_DOM_MIN_TEXT_LENGTH) return true;
|
|
240
|
+
return normalized.length >= CHAT_FULL_CV_DOM_MIN_SECTION_TEXT_LENGTH
|
|
241
|
+
&& resumeSectionMatchCount(normalized) >= 2;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function networkProfileTextLength(profileResult = {}) {
|
|
245
|
+
return normalizeText(profileResult?.profile?.text || "").length;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function isFullCvNetworkProfile(profileResult = {}) {
|
|
249
|
+
if (!profileResult?.ok) return false;
|
|
250
|
+
const sourceKeys = profileResult.profile?.source_keys || {};
|
|
251
|
+
const textLength = networkProfileTextLength(profileResult);
|
|
252
|
+
const sectionCount = resumeSectionMatchCount(profileResult.profile?.text || "");
|
|
253
|
+
|
|
254
|
+
if (sourceKeys.geek_detail_info || sourceKeys.geek_detail) return true;
|
|
255
|
+
if (sourceKeys.network_html_text) {
|
|
256
|
+
return textLength >= CHAT_FULL_CV_DOM_MIN_TEXT_LENGTH
|
|
257
|
+
|| sectionCount >= 2;
|
|
258
|
+
}
|
|
259
|
+
if (sourceKeys.chat_history_resume) {
|
|
260
|
+
const educationCount = Number(sourceKeys.education_count) || 0;
|
|
261
|
+
const workCount = Number(sourceKeys.work_count) || 0;
|
|
262
|
+
return (educationCount + workCount) > 0
|
|
263
|
+
&& (textLength >= CHAT_FULL_CV_DOM_MIN_SECTION_TEXT_LENGTH || sectionCount >= 2);
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function hasUsableImageEvidence(imageEvidence = null) {
|
|
269
|
+
if (!imageEvidence || imageEvidence.ok === false) return false;
|
|
270
|
+
return Boolean(
|
|
271
|
+
(Array.isArray(imageEvidence.llm_file_paths) && imageEvidence.llm_file_paths.length)
|
|
272
|
+
|| (Array.isArray(imageEvidence.file_paths) && imageEvidence.file_paths.length)
|
|
273
|
+
|| Number(imageEvidence.llm_screenshot_count) > 0
|
|
274
|
+
|| Number(imageEvidence.unique_screenshot_count) > 0
|
|
275
|
+
|| Number(imageEvidence.screenshot_count) > 0
|
|
276
|
+
|| Number(imageEvidence.capture_count) > 0
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function summarizeChatFullCvEvidence({
|
|
281
|
+
detailResult = null,
|
|
282
|
+
contentWait = null,
|
|
283
|
+
imageEvidence = null
|
|
284
|
+
} = {}) {
|
|
285
|
+
const parsedProfiles = (detailResult?.parsed_network_profiles || []).filter((item) => item?.ok);
|
|
286
|
+
const fullNetworkProfiles = parsedProfiles.filter(isFullCvNetworkProfile);
|
|
287
|
+
const profileOnlyCount = Math.max(0, parsedProfiles.length - fullNetworkProfiles.length);
|
|
288
|
+
const detailText = detailTextForFullCvCheck(detailResult);
|
|
289
|
+
const domTextLength = detailText.length;
|
|
290
|
+
const domSectionCount = resumeSectionMatchCount(detailText);
|
|
291
|
+
const domFullCv = Boolean(contentWait?.ok) && hasResumeLikeDomText(detailText);
|
|
292
|
+
const imageFullCv = hasUsableImageEvidence(imageEvidence);
|
|
293
|
+
const source = fullNetworkProfiles.length
|
|
294
|
+
? "network"
|
|
295
|
+
: domFullCv
|
|
296
|
+
? "dom"
|
|
297
|
+
: imageFullCv
|
|
298
|
+
? "image"
|
|
299
|
+
: null;
|
|
300
|
+
return {
|
|
301
|
+
full_cv_acquired: Boolean(source),
|
|
302
|
+
source,
|
|
303
|
+
network_full_cv_count: fullNetworkProfiles.length,
|
|
304
|
+
network_profile_only_count: profileOnlyCount,
|
|
305
|
+
parsed_network_profile_count: parsedProfiles.length,
|
|
306
|
+
dom_full_cv: domFullCv,
|
|
307
|
+
dom_text_length: domTextLength,
|
|
308
|
+
dom_section_count: domSectionCount,
|
|
309
|
+
content_wait_ok: Boolean(contentWait?.ok),
|
|
310
|
+
image_full_cv: imageFullCv,
|
|
311
|
+
image_summary: summarizeImageEvidence(imageEvidence)
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
206
315
|
async function resolveFreshChatCardNodeId(client, {
|
|
207
316
|
fallbackNodeId,
|
|
208
317
|
candidate,
|
|
@@ -306,6 +415,9 @@ async function setupChatRunContext(client, {
|
|
|
306
415
|
if (normalizeText(job) && !jobSelection.selected) {
|
|
307
416
|
throw new Error(`Chat job selection failed: ${jobSelection.reason || "unknown"}`);
|
|
308
417
|
}
|
|
418
|
+
if (normalizeText(job) && jobSelection.verified !== true) {
|
|
419
|
+
throw new Error(`Chat job selection was not verified: requested=${jobSelection.requested || job}; selected=${jobSelection.selected_label || "unknown"}`);
|
|
420
|
+
}
|
|
309
421
|
rootState = await getChatRoots(client);
|
|
310
422
|
if (ensureViewport) {
|
|
311
423
|
rootState = await ensureViewport(rootState, "context_job");
|
|
@@ -770,11 +882,12 @@ export async function runChatWorkflow({
|
|
|
770
882
|
});
|
|
771
883
|
addTiming(timings, "late_network_retry_ms", detailResult.network_parse_retry_elapsed_ms);
|
|
772
884
|
parsedNetworkProfileCount = countParsedNetworkProfiles(detailResult);
|
|
773
|
-
|
|
885
|
+
const networkEvidence = summarizeChatFullCvEvidence({ detailResult, contentWait });
|
|
886
|
+
if (networkEvidence.network_full_cv_count > 0) {
|
|
774
887
|
contentWait = {
|
|
775
888
|
ok: true,
|
|
776
889
|
skipped: true,
|
|
777
|
-
reason: "
|
|
890
|
+
reason: "network_full_cv_parsed_before_dom_wait",
|
|
778
891
|
elapsed_ms: 0,
|
|
779
892
|
text_length: 0
|
|
780
893
|
};
|
|
@@ -816,8 +929,9 @@ export async function runChatWorkflow({
|
|
|
816
929
|
let imageEvidence = null;
|
|
817
930
|
let llmResult = null;
|
|
818
931
|
const captureNodeId = captureNodeIdFromResumeState(resumeState);
|
|
932
|
+
let fullCvEvidence = summarizeChatFullCvEvidence({ detailResult, contentWait });
|
|
819
933
|
const shouldCaptureImage = normalizedDetailSource === "image"
|
|
820
|
-
|| (normalizedDetailSource === "cascade" &&
|
|
934
|
+
|| (normalizedDetailSource === "cascade" && !fullCvEvidence.full_cv_acquired);
|
|
821
935
|
if (shouldCaptureImage) {
|
|
822
936
|
if (captureNodeId) {
|
|
823
937
|
detailStep = "capture_image_fallback";
|
|
@@ -858,12 +972,20 @@ export async function runChatWorkflow({
|
|
|
858
972
|
}
|
|
859
973
|
}));
|
|
860
974
|
source = "image";
|
|
975
|
+
fullCvEvidence = summarizeChatFullCvEvidence({
|
|
976
|
+
detailResult,
|
|
977
|
+
contentWait,
|
|
978
|
+
imageEvidence
|
|
979
|
+
});
|
|
861
980
|
recordCvImageFallback(cvAcquisitionState, {
|
|
981
|
+
reason: fullCvEvidence.network_profile_only_count > 0
|
|
982
|
+
? "profile_only_network_image_fallback"
|
|
983
|
+
: "network_miss_image_fallback",
|
|
862
984
|
parsedNetworkProfileCount,
|
|
863
985
|
waitResult: networkWait,
|
|
864
986
|
imageEvidence
|
|
865
987
|
});
|
|
866
|
-
if (callLlmOnImage) {
|
|
988
|
+
if (callLlmOnImage && fullCvEvidence.full_cv_acquired) {
|
|
867
989
|
detailStep = "llm_image_screening";
|
|
868
990
|
if (!llmConfig) {
|
|
869
991
|
llmResult = createMissingLlmConfigResult();
|
|
@@ -885,14 +1007,39 @@ export async function runChatWorkflow({
|
|
|
885
1007
|
}
|
|
886
1008
|
} else {
|
|
887
1009
|
source = "missing_capture_node";
|
|
1010
|
+
fullCvEvidence = summarizeChatFullCvEvidence({
|
|
1011
|
+
detailResult,
|
|
1012
|
+
contentWait,
|
|
1013
|
+
imageEvidence
|
|
1014
|
+
});
|
|
888
1015
|
recordCvNetworkMiss(cvAcquisitionState, {
|
|
889
1016
|
reason: "network_miss_no_capture_node",
|
|
890
1017
|
parsedNetworkProfileCount,
|
|
891
1018
|
waitResult: networkWait
|
|
892
1019
|
});
|
|
893
1020
|
}
|
|
894
|
-
} else if (
|
|
1021
|
+
} else if (fullCvEvidence.network_full_cv_count > 0) {
|
|
1022
|
+
source = "network";
|
|
895
1023
|
recordCvNetworkHit(cvAcquisitionState, {
|
|
1024
|
+
reason: "full_cv_network_profile",
|
|
1025
|
+
parsedNetworkProfileCount,
|
|
1026
|
+
waitResult: networkWait
|
|
1027
|
+
});
|
|
1028
|
+
} else if (fullCvEvidence.dom_full_cv) {
|
|
1029
|
+
source = "dom";
|
|
1030
|
+
if (normalizedDetailSource !== "dom") {
|
|
1031
|
+
recordCvNetworkMiss(cvAcquisitionState, {
|
|
1032
|
+
reason: parsedNetworkProfileCount > 0
|
|
1033
|
+
? "profile_only_network_dom_fallback"
|
|
1034
|
+
: "network_miss_dom_fallback",
|
|
1035
|
+
parsedNetworkProfileCount,
|
|
1036
|
+
waitResult: networkWait
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
} else if (parsedNetworkProfileCount > 0) {
|
|
1040
|
+
source = "profile_only_network";
|
|
1041
|
+
recordCvNetworkMiss(cvAcquisitionState, {
|
|
1042
|
+
reason: "profile_only_network_not_full_cv",
|
|
896
1043
|
parsedNetworkProfileCount,
|
|
897
1044
|
waitResult: networkWait
|
|
898
1045
|
});
|
|
@@ -906,25 +1053,29 @@ export async function runChatWorkflow({
|
|
|
906
1053
|
}
|
|
907
1054
|
|
|
908
1055
|
if (useLlmScreening && !llmResult) {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
llmResult = createMissingLlmConfigResult();
|
|
1056
|
+
if (!fullCvEvidence.full_cv_acquired) {
|
|
1057
|
+
detailUnavailableReason = "full_cv_not_acquired";
|
|
912
1058
|
} else {
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1059
|
+
detailStep = "llm_screening";
|
|
1060
|
+
if (!llmConfig) {
|
|
1061
|
+
llmResult = createMissingLlmConfigResult();
|
|
1062
|
+
} else {
|
|
1063
|
+
try {
|
|
1064
|
+
const llmTimingKey = imageEvidence?.file_paths?.length
|
|
1065
|
+
? "vision_model_ms"
|
|
1066
|
+
: "text_model_ms";
|
|
1067
|
+
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1068
|
+
candidate: detailResult.candidate,
|
|
1069
|
+
criteria,
|
|
1070
|
+
config: llmConfig,
|
|
1071
|
+
timeoutMs: llmTimeoutMs,
|
|
1072
|
+
imageEvidence,
|
|
1073
|
+
maxImages: llmImageLimit,
|
|
1074
|
+
imageDetail: llmImageDetail
|
|
1075
|
+
}));
|
|
1076
|
+
} catch (error) {
|
|
1077
|
+
llmResult = createFailedLlmResult(error);
|
|
1078
|
+
}
|
|
928
1079
|
}
|
|
929
1080
|
}
|
|
930
1081
|
}
|
|
@@ -952,7 +1103,8 @@ export async function runChatWorkflow({
|
|
|
952
1103
|
text_length: contentWait.text_length
|
|
953
1104
|
},
|
|
954
1105
|
parsed_network_profile_count: parsedNetworkProfileCount,
|
|
955
|
-
image_evidence: summarizeImageEvidence(imageEvidence)
|
|
1106
|
+
image_evidence: summarizeImageEvidence(imageEvidence),
|
|
1107
|
+
full_cv_evidence: fullCvEvidence
|
|
956
1108
|
};
|
|
957
1109
|
}
|
|
958
1110
|
} catch (error) {
|
|
@@ -976,22 +1128,9 @@ export async function runChatWorkflow({
|
|
|
976
1128
|
runControl.setPhase("chat:screening");
|
|
977
1129
|
let cardOnlyLlmResult = null;
|
|
978
1130
|
if (useLlmScreening && !detailUnavailableReason && !detailResult?.llm_result) {
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
try {
|
|
983
|
-
cardOnlyLlmResult = await measureTiming(timings, "text_model_ms", () => callScreeningLlm({
|
|
984
|
-
candidate: screeningCandidate,
|
|
985
|
-
criteria,
|
|
986
|
-
config: llmConfig,
|
|
987
|
-
timeoutMs: llmTimeoutMs,
|
|
988
|
-
maxImages: llmImageLimit,
|
|
989
|
-
imageDetail: llmImageDetail
|
|
990
|
-
}));
|
|
991
|
-
} catch (error) {
|
|
992
|
-
cardOnlyLlmResult = createFailedLlmResult(error);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
1131
|
+
detailUnavailableReason = detailResult
|
|
1132
|
+
? "full_cv_not_acquired"
|
|
1133
|
+
: "detail_not_opened_full_cv_required";
|
|
995
1134
|
}
|
|
996
1135
|
const effectiveLlmResult = detailResult?.llm_result || cardOnlyLlmResult;
|
|
997
1136
|
const screening = detailUnavailableReason
|