@reconcrap/boss-recommend-mcp 2.1.12 → 2.1.14

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.
@@ -38,11 +38,13 @@ import {
38
38
  imageEvidenceFilePath,
39
39
  measureTiming
40
40
  } from "../../core/run/timing.js";
41
- import {
42
- callScreeningLlm,
43
- normalizeText,
44
- screenCandidate
45
- } from "../../core/screening/index.js";
41
+ import {
42
+ callScreeningLlm,
43
+ createFatalLlmRunError,
44
+ isFatalLlmProviderError,
45
+ normalizeText,
46
+ screenCandidate
47
+ } from "../../core/screening/index.js";
46
48
  import {
47
49
  CHAT_BOTTOM_MARKER_SELECTORS,
48
50
  CHAT_CARD_SELECTORS,
@@ -104,23 +106,35 @@ function compactScreening(screening) {
104
106
 
105
107
  function compactLlmResult(llmResult) {
106
108
  if (!llmResult) return null;
107
- return {
108
- ok: Boolean(llmResult.ok),
109
- provider: llmResult.provider || null,
110
- passed: llmResult.passed,
111
- cot: llmResult.cot || llmResult.decision_cot || "",
112
- reasoning_content: llmResult.reasoning_content || "",
113
- raw_model_output: llmResult.raw_model_output || "",
114
- evidence_count: llmResult.evidence?.length || 0,
115
- usage: llmResult.usage || null,
109
+ return {
110
+ ok: Boolean(llmResult.ok),
111
+ provider: llmResult.provider || null,
112
+ passed: llmResult.passed,
113
+ review_required: typeof llmResult.review_required === "boolean" ? llmResult.review_required : null,
114
+ cot: llmResult.cot || llmResult.decision_cot || "",
115
+ reasoning_content: llmResult.reasoning_content || "",
116
+ raw_model_output: llmResult.raw_model_output || "",
117
+ evidence_count: llmResult.evidence?.length || 0,
118
+ usage: llmResult.usage || null,
116
119
  finish_reason: llmResult.finish_reason || null,
117
- image_input_count: llmResult.image_input_count || 0,
118
- attempt_count: llmResult.attempt_count || 0,
119
- fallback_count: llmResult.fallback_count || 0,
120
- llm_model_failures: Array.isArray(llmResult.llm_model_failures) ? llmResult.llm_model_failures : [],
121
- error: llmResult.error || null
122
- };
123
- }
120
+ image_input_count: llmResult.image_input_count || 0,
121
+ attempt_count: llmResult.attempt_count || 0,
122
+ fallback_count: llmResult.fallback_count || 0,
123
+ llm_model_failures: Array.isArray(llmResult.llm_model_failures) ? llmResult.llm_model_failures : [],
124
+ screening_strategy: llmResult.screening_strategy || "",
125
+ fast_thinking_level: llmResult.fast_thinking_level || "",
126
+ verify_thinking_level: llmResult.verify_thinking_level || "",
127
+ verified: typeof llmResult.verified === "boolean" ? llmResult.verified : null,
128
+ verification_reason: llmResult.verification_reason || "",
129
+ decision_source: llmResult.decision_source || "",
130
+ fast_result: llmResult.fast_result || null,
131
+ verify_result: llmResult.verify_result || null,
132
+ error_code: llmResult.error_code || null,
133
+ fatal: Boolean(llmResult.fatal),
134
+ fatal_reason: llmResult.fatal_reason || "",
135
+ error: llmResult.error || null
136
+ };
137
+ }
124
138
 
125
139
  function compactCandidate(candidate) {
126
140
  return {
@@ -339,9 +353,9 @@ function isRecoverableLlmScreeningError(error) {
339
353
  }
340
354
 
341
355
  function createFailedLlmResult(error) {
342
- return {
343
- ok: false,
344
- passed: false,
356
+ return {
357
+ ok: false,
358
+ passed: false,
345
359
  reason: "",
346
360
  evidence: [],
347
361
  cot: "",
@@ -349,12 +363,15 @@ function createFailedLlmResult(error) {
349
363
  reasoning_content: "",
350
364
  raw_model_output: "",
351
365
  attempt_count: Number(error?.llm_attempt_count) || 0,
352
- fallback_count: Array.isArray(error?.llm_model_failures) ? error.llm_model_failures.length : 0,
353
- llm_model_failures: Array.isArray(error?.llm_model_failures) ? error.llm_model_failures : [],
354
- error: error?.message || String(error || "unknown"),
355
- screened_at: new Date().toISOString()
356
- };
357
- }
366
+ fallback_count: Array.isArray(error?.llm_model_failures) ? error.llm_model_failures.length : 0,
367
+ llm_model_failures: Array.isArray(error?.llm_model_failures) ? error.llm_model_failures : [],
368
+ error_code: error?.code || null,
369
+ fatal: Boolean(isFatalLlmProviderError(error)),
370
+ fatal_reason: error?.llm_fatal_reason || "",
371
+ error: error?.message || String(error || "unknown"),
372
+ screened_at: new Date().toISOString()
373
+ };
374
+ }
358
375
 
359
376
  function normalizeScreeningMode(value) {
360
377
  const normalized = String(value || "llm").trim().toLowerCase();
@@ -743,12 +760,12 @@ export async function runChatWorkflow({
743
760
  safeClickPointEnabled: effectiveHumanBehavior.clickMovement,
744
761
  actionCooldownEnabled: effectiveHumanBehavior.actionCooldown
745
762
  });
746
- const humanRestController = createHumanRestController({
747
- enabled: effectiveHumanRestEnabled,
748
- shortRestEnabled: effectiveHumanBehavior.shortRest,
749
- batchRestEnabled: effectiveHumanBehavior.batchRest,
750
- restLevel: effectiveHumanBehavior.restLevel
751
- });
763
+ const humanRestController = createHumanRestController({
764
+ enabled: effectiveHumanRestEnabled,
765
+ shortRestEnabled: effectiveHumanBehavior.shortRest,
766
+ batchRestEnabled: effectiveHumanBehavior.batchRest,
767
+ restLevel: effectiveHumanBehavior.restLevel
768
+ });
752
769
  const normalizedDetailSource = normalizeDetailSource(detailSource);
753
770
  const normalizedScreeningMode = normalizeScreeningMode(screeningMode);
754
771
  const useLlmScreening = normalizedScreeningMode !== "deterministic";
@@ -792,12 +809,12 @@ export async function runChatWorkflow({
792
809
  let requestedCount = 0;
793
810
  let requestSatisfiedCount = 0;
794
811
  let requestSkippedCount = 0;
795
- let contextSetup = {};
796
- let contextRecoveryAttempts = 0;
797
- const candidateRecoveryCounts = new Map();
798
- let lastHumanEvent = null;
799
-
800
- function recordHumanEvent(event = null) {
812
+ let contextSetup = {};
813
+ let contextRecoveryAttempts = 0;
814
+ const candidateRecoveryCounts = new Map();
815
+ let lastHumanEvent = null;
816
+
817
+ function recordHumanEvent(event = null) {
801
818
  if (!event) return lastHumanEvent;
802
819
  lastHumanEvent = {
803
820
  at: new Date().toISOString(),
@@ -861,13 +878,13 @@ export async function runChatWorkflow({
861
878
  ...setup.contextSetup,
862
879
  initial_top_level_state: initialTopLevelState
863
880
  };
864
- runControl.checkpoint({
865
- chat_context: contextSetup
866
- });
867
-
868
- async function recoverAndReapplyChatContext(reason, error = null, {
869
- forceRefresh = false
870
- } = {}) {
881
+ runControl.checkpoint({
882
+ chat_context: contextSetup
883
+ });
884
+
885
+ async function recoverAndReapplyChatContext(reason, error = null, {
886
+ forceRefresh = false
887
+ } = {}) {
871
888
  runControl.setPhase("chat:recover_shell");
872
889
  contextRecoveryAttempts += 1;
873
890
  const shellRecovery = await recoverChatShell(client, {
@@ -967,12 +984,12 @@ export async function runChatWorkflow({
967
984
  context_recoveries: contextRecoveryAttempts,
968
985
  list_end_reason: listEndReason,
969
986
  viewport_checks: viewportGuard.getStats().checks,
970
- viewport_recoveries: viewportGuard.getStats().recoveries,
971
- human_behavior_enabled: effectiveHumanBehavior.enabled,
972
- human_behavior_profile: effectiveHumanBehavior.profile,
973
- human_rest_level: effectiveHumanBehavior.restLevel,
974
- human_rest_enabled: effectiveHumanRestEnabled,
975
- human_rest_count: humanRestController.getState().rest_count,
987
+ viewport_recoveries: viewportGuard.getStats().recoveries,
988
+ human_behavior_enabled: effectiveHumanBehavior.enabled,
989
+ human_behavior_profile: effectiveHumanBehavior.profile,
990
+ human_rest_level: effectiveHumanBehavior.restLevel,
991
+ human_rest_enabled: effectiveHumanRestEnabled,
992
+ human_rest_count: humanRestController.getState().rest_count,
976
993
  human_rest_ms: humanRestController.getState().total_rest_ms,
977
994
  last_human_event: lastHumanEvent
978
995
  });
@@ -997,10 +1014,10 @@ export async function runChatWorkflow({
997
1014
  last_human_event: lastHumanEvent,
998
1015
  list_end_reason: listEndReason,
999
1016
  target_pass_count: passTarget,
1000
- process_until_list_end: Boolean(processUntilListEnd),
1001
- processed_limit: processedLimit,
1002
- detail_source: normalizedDetailSource,
1003
- processed: 0,
1017
+ process_until_list_end: Boolean(processUntilListEnd),
1018
+ processed_limit: processedLimit,
1019
+ detail_source: normalizedDetailSource,
1020
+ processed: 0,
1004
1021
  screened: 0,
1005
1022
  detail_opened: 0,
1006
1023
  llm_screened: 0,
@@ -1501,18 +1518,24 @@ export async function runChatWorkflow({
1501
1518
  llmResult = createMissingLlmConfigResult();
1502
1519
  } else {
1503
1520
  try {
1504
- llmResult = await measureTiming(timings, "vision_model_ms", () => callScreeningLlm({
1505
- candidate: detailResult.candidate,
1506
- criteria,
1507
- config: llmConfig,
1508
- timeoutMs: llmTimeoutMs,
1521
+ llmResult = await measureTiming(timings, "vision_model_ms", () => callScreeningLlm({
1522
+ candidate: detailResult.candidate,
1523
+ criteria,
1524
+ config: llmConfig,
1525
+ timeoutMs: llmTimeoutMs,
1509
1526
  imageEvidence,
1510
1527
  maxImages: llmImageLimit,
1511
1528
  imageDetail: llmImageDetail
1512
1529
  }));
1513
- } catch (error) {
1514
- llmResult = createFailedLlmResult(error);
1515
- }
1530
+ } catch (error) {
1531
+ if (isFatalLlmProviderError(error)) {
1532
+ throw createFatalLlmRunError(error, {
1533
+ domain: "chat",
1534
+ candidate: detailResult.candidate
1535
+ });
1536
+ }
1537
+ llmResult = createFailedLlmResult(error);
1538
+ }
1516
1539
  }
1517
1540
  }
1518
1541
  } else {
@@ -1574,18 +1597,24 @@ export async function runChatWorkflow({
1574
1597
  const llmTimingKey = imageEvidence?.file_paths?.length
1575
1598
  ? "vision_model_ms"
1576
1599
  : "text_model_ms";
1577
- llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
1578
- candidate: detailResult.candidate,
1579
- criteria,
1580
- config: llmConfig,
1600
+ llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
1601
+ candidate: detailResult.candidate,
1602
+ criteria,
1603
+ config: llmConfig,
1581
1604
  timeoutMs: llmTimeoutMs,
1582
1605
  imageEvidence,
1583
1606
  maxImages: llmImageLimit,
1584
1607
  imageDetail: llmImageDetail
1585
1608
  }));
1586
- } catch (error) {
1587
- llmResult = createFailedLlmResult(error);
1588
- }
1609
+ } catch (error) {
1610
+ if (isFatalLlmProviderError(error)) {
1611
+ throw createFatalLlmRunError(error, {
1612
+ domain: "chat",
1613
+ candidate: detailResult.candidate
1614
+ });
1615
+ }
1616
+ llmResult = createFailedLlmResult(error);
1617
+ }
1589
1618
  }
1590
1619
  }
1591
1620
  }
@@ -1773,12 +1802,12 @@ export async function runChatWorkflow({
1773
1802
  context_recoveries: contextRecoveryAttempts,
1774
1803
  list_end_reason: listEndReason || null,
1775
1804
  viewport_checks: viewportGuard.getStats().checks,
1776
- viewport_recoveries: viewportGuard.getStats().recoveries,
1777
- human_behavior_enabled: effectiveHumanBehavior.enabled,
1778
- human_behavior_profile: effectiveHumanBehavior.profile,
1779
- human_rest_level: effectiveHumanBehavior.restLevel,
1780
- human_rest_enabled: effectiveHumanRestEnabled,
1781
- human_rest_count: humanRestController.getState().rest_count,
1805
+ viewport_recoveries: viewportGuard.getStats().recoveries,
1806
+ human_behavior_enabled: effectiveHumanBehavior.enabled,
1807
+ human_behavior_profile: effectiveHumanBehavior.profile,
1808
+ human_rest_level: effectiveHumanBehavior.restLevel,
1809
+ human_rest_enabled: effectiveHumanRestEnabled,
1810
+ human_rest_count: humanRestController.getState().rest_count,
1782
1811
  human_rest_ms: humanRestController.getState().total_rest_ms,
1783
1812
  last_human_event: lastHumanEvent,
1784
1813
  last_candidate_id: screeningCandidate.id || null,
@@ -1818,11 +1847,11 @@ export async function runChatWorkflow({
1818
1847
  compactResult.human_rest = restResult;
1819
1848
  addTiming(compactResult.timings, "human_rest_ms", restElapsed);
1820
1849
  compactResult.timings.total_ms = Date.now() - candidateStarted;
1821
- runControl.updateProgress({
1822
- human_rest_enabled: effectiveHumanRestEnabled,
1823
- human_rest_level: effectiveHumanBehavior.restLevel,
1824
- human_rest_count: humanRestController.getState().rest_count,
1825
- human_rest_ms: humanRestController.getState().total_rest_ms,
1850
+ runControl.updateProgress({
1851
+ human_rest_enabled: effectiveHumanRestEnabled,
1852
+ human_rest_level: effectiveHumanBehavior.restLevel,
1853
+ human_rest_count: humanRestController.getState().rest_count,
1854
+ human_rest_ms: humanRestController.getState().total_rest_ms,
1826
1855
  human_rest_last: restResult,
1827
1856
  context_recoveries: contextRecoveryAttempts,
1828
1857
  last_human_event: lastHumanEvent
@@ -1855,10 +1884,10 @@ export async function runChatWorkflow({
1855
1884
  last_human_event: lastHumanEvent,
1856
1885
  list_end_reason: listEndReason || null,
1857
1886
  target_pass_count: passTarget,
1858
- process_until_list_end: Boolean(processUntilListEnd),
1859
- processed_limit: processedLimit,
1860
- detail_source: normalizedDetailSource,
1861
- processed: finalCounters.processed,
1887
+ process_until_list_end: Boolean(processUntilListEnd),
1888
+ processed_limit: processedLimit,
1889
+ detail_source: normalizedDetailSource,
1890
+ processed: finalCounters.processed,
1862
1891
  screened: finalCounters.screened,
1863
1892
  detail_opened: finalCounters.detail_opened,
1864
1893
  llm_screened: finalCounters.llm_screened,
@@ -1880,10 +1909,10 @@ export function createChatRunService({
1880
1909
  } = {}) {
1881
1910
  const manager = lifecycle || createRunLifecycleManager({ idPrefix, onSnapshot });
1882
1911
 
1883
- function startChatRun({
1884
- runId = "",
1885
- client,
1886
- targetUrl = CHAT_TARGET_URL,
1912
+ function startChatRun({
1913
+ runId = "",
1914
+ client,
1915
+ targetUrl = CHAT_TARGET_URL,
1887
1916
  job = "",
1888
1917
  startFrom = "all",
1889
1918
  criteria = "",
@@ -1929,10 +1958,10 @@ export function createChatRunService({
1929
1958
  legacyEnabled: humanRestEnabled === true || llmConfig?.humanRestEnabled === true
1930
1959
  });
1931
1960
  const effectiveHumanRestEnabled = effectiveHumanBehavior.restEnabled;
1932
- return manager.startRun({
1933
- runId,
1934
- name,
1935
- context: {
1961
+ return manager.startRun({
1962
+ runId,
1963
+ name,
1964
+ context: {
1936
1965
  domain: "chat",
1937
1966
  target_url: targetUrl,
1938
1967
  criteria_present: Boolean(criteria),
@@ -1962,13 +1991,13 @@ export function createChatRunService({
1962
1991
  list_settle_ms: listSettleMs,
1963
1992
  list_fallback_point: listFallbackPoint,
1964
1993
  online_resume_button_timeout_ms: onlineResumeButtonTimeoutMs,
1965
- image_output_dir: imageOutputDir || "",
1966
- human_behavior_enabled: effectiveHumanBehavior.enabled,
1967
- human_behavior_profile: effectiveHumanBehavior.profile,
1968
- human_behavior: effectiveHumanBehavior,
1969
- human_rest_level: effectiveHumanBehavior.restLevel,
1970
- human_rest_enabled: effectiveHumanRestEnabled
1971
- },
1994
+ image_output_dir: imageOutputDir || "",
1995
+ human_behavior_enabled: effectiveHumanBehavior.enabled,
1996
+ human_behavior_profile: effectiveHumanBehavior.profile,
1997
+ human_behavior: effectiveHumanBehavior,
1998
+ human_rest_level: effectiveHumanBehavior.restLevel,
1999
+ human_rest_enabled: effectiveHumanRestEnabled
2000
+ },
1972
2001
  progress: {
1973
2002
  card_count: 0,
1974
2003
  target_count: targetPassCount || (processUntilListEnd ? "all" : processedLimit),
@@ -1983,11 +2012,11 @@ export function createChatRunService({
1983
2012
  requested: 0,
1984
2013
  request_satisfied: 0,
1985
2014
  request_skipped: 0,
1986
- context_recoveries: 0,
1987
- human_behavior_enabled: effectiveHumanBehavior.enabled,
1988
- human_behavior_profile: effectiveHumanBehavior.profile,
1989
- human_rest_level: effectiveHumanBehavior.restLevel,
1990
- human_rest_enabled: effectiveHumanRestEnabled,
2015
+ context_recoveries: 0,
2016
+ human_behavior_enabled: effectiveHumanBehavior.enabled,
2017
+ human_behavior_profile: effectiveHumanBehavior.profile,
2018
+ human_rest_level: effectiveHumanBehavior.restLevel,
2019
+ human_rest_enabled: effectiveHumanRestEnabled,
1991
2020
  human_rest_count: 0,
1992
2021
  human_rest_ms: 0,
1993
2022
  last_human_event: null
@@ -38,13 +38,15 @@ import {
38
38
  resolveInfiniteListFallbackPoint
39
39
  } from "../../core/infinite-list/index.js";
40
40
  import { createViewportRunGuard } from "../../core/self-heal/index.js";
41
- import {
42
- callScreeningLlm,
43
- compactScreeningLlmResult,
44
- createFailedLlmScreeningResult,
45
- llmResultToScreening,
46
- screenCandidate
47
- } from "../../core/screening/index.js";
41
+ import {
42
+ callScreeningLlm,
43
+ compactScreeningLlmResult,
44
+ createFatalLlmRunError,
45
+ createFailedLlmScreeningResult,
46
+ isFatalLlmProviderError,
47
+ llmResultToScreening,
48
+ screenCandidate
49
+ } from "../../core/screening/index.js";
48
50
  import {
49
51
  closeRecommendBlockingPanels,
50
52
  closeRecommendAvatarPreview,
@@ -906,8 +908,8 @@ export async function runRecommendWorkflow({
906
908
  recovery_reason: reason
907
909
  });
908
910
  return refreshResult;
909
- }
910
-
911
+ }
912
+
911
913
  runControl.setPhase("recommend:cleanup");
912
914
  await closeRecommendDetail(client, { attemptsLimit: 2 });
913
915
  await closeRecommendAvatarPreview(client, { attemptsLimit: 2 });
@@ -1334,18 +1336,24 @@ export async function runRecommendWorkflow({
1334
1336
  const llmTimingKey = detailResult?.image_evidence?.file_paths?.length
1335
1337
  ? "vision_model_ms"
1336
1338
  : "text_model_ms";
1337
- llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
1338
- candidate: screeningCandidate,
1339
- criteria,
1340
- config: llmConfig,
1341
- timeoutMs: llmTimeoutMs,
1339
+ llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
1340
+ candidate: screeningCandidate,
1341
+ criteria,
1342
+ config: llmConfig,
1343
+ timeoutMs: llmTimeoutMs,
1342
1344
  imageEvidence: detailResult?.image_evidence || null,
1343
1345
  maxImages: llmImageLimit,
1344
1346
  imageDetail: llmImageDetail
1345
1347
  }));
1346
- } catch (error) {
1347
- llmResult = createFailedLlmScreeningResult(error);
1348
- }
1348
+ } catch (error) {
1349
+ if (isFatalLlmProviderError(error)) {
1350
+ throw createFatalLlmRunError(error, {
1351
+ domain: "recommend",
1352
+ candidate: screeningCandidate
1353
+ });
1354
+ }
1355
+ llmResult = createFailedLlmScreeningResult(error);
1356
+ }
1349
1357
  }
1350
1358
  if (detailResult) detailResult.llm_result = llmResult;
1351
1359
  }
@@ -1532,7 +1540,7 @@ export async function runRecommendWorkflow({
1532
1540
  human_rest: humanRestController.getState(),
1533
1541
  last_human_event: lastHumanEvent,
1534
1542
  list_end_reason: listEndReason || null,
1535
- refresh_rounds: refreshRounds,
1543
+ refresh_rounds: refreshRounds,
1536
1544
  refresh_attempts: refreshAttempts,
1537
1545
  context_recoveries: contextRecoveryAttempts,
1538
1546
  ...countRecommendResultStatuses(results, { greetCount }),
@@ -39,7 +39,9 @@ import { createViewportRunGuard } from "../../core/self-heal/index.js";
39
39
  import {
40
40
  callScreeningLlm,
41
41
  compactScreeningLlmResult,
42
+ createFatalLlmRunError,
42
43
  createFailedLlmScreeningResult,
44
+ isFatalLlmProviderError,
43
45
  llmResultToScreening,
44
46
  screenCandidate
45
47
  } from "../../core/screening/index.js";
@@ -1022,6 +1024,12 @@ export async function runRecruitWorkflow({
1022
1024
  imageDetail: llmImageDetail
1023
1025
  }));
1024
1026
  } catch (error) {
1027
+ if (isFatalLlmProviderError(error)) {
1028
+ throw createFatalLlmRunError(error, {
1029
+ domain: "recruit",
1030
+ candidate: screeningCandidate
1031
+ });
1032
+ }
1025
1033
  llmResult = createFailedLlmScreeningResult(error);
1026
1034
  }
1027
1035
  }