@reconcrap/boss-recommend-mcp 2.1.11 → 2.1.13
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 +6 -2
- package/package.json +1 -1
- package/skills/boss-chat/SKILL.md +2 -0
- package/skills/boss-recommend-pipeline/SKILL.md +2 -0
- package/skills/boss-recruit-pipeline/SKILL.md +2 -0
- package/src/chat-mcp.js +2174 -2174
- package/src/cli.js +129 -85
- package/src/core/reporting/legacy-csv.js +4 -15
- package/src/core/screening/index.js +33 -13
- package/src/domains/chat/run-service.js +83 -83
- package/src/domains/recommend/run-service.js +15 -15
- package/src/index.js +238 -18
|
@@ -38,11 +38,11 @@ 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
|
+
normalizeText,
|
|
44
|
+
screenCandidate
|
|
45
|
+
} from "../../core/screening/index.js";
|
|
46
46
|
import {
|
|
47
47
|
CHAT_BOTTOM_MARKER_SELECTORS,
|
|
48
48
|
CHAT_CARD_SELECTORS,
|
|
@@ -104,11 +104,11 @@ function compactScreening(screening) {
|
|
|
104
104
|
|
|
105
105
|
function compactLlmResult(llmResult) {
|
|
106
106
|
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 || "",
|
|
107
|
+
return {
|
|
108
|
+
ok: Boolean(llmResult.ok),
|
|
109
|
+
provider: llmResult.provider || null,
|
|
110
|
+
passed: llmResult.passed,
|
|
111
|
+
cot: llmResult.cot || llmResult.decision_cot || "",
|
|
112
112
|
reasoning_content: llmResult.reasoning_content || "",
|
|
113
113
|
raw_model_output: llmResult.raw_model_output || "",
|
|
114
114
|
evidence_count: llmResult.evidence?.length || 0,
|
|
@@ -743,12 +743,12 @@ export async function runChatWorkflow({
|
|
|
743
743
|
safeClickPointEnabled: effectiveHumanBehavior.clickMovement,
|
|
744
744
|
actionCooldownEnabled: effectiveHumanBehavior.actionCooldown
|
|
745
745
|
});
|
|
746
|
-
const humanRestController = createHumanRestController({
|
|
747
|
-
enabled: effectiveHumanRestEnabled,
|
|
748
|
-
shortRestEnabled: effectiveHumanBehavior.shortRest,
|
|
749
|
-
batchRestEnabled: effectiveHumanBehavior.batchRest,
|
|
750
|
-
restLevel: effectiveHumanBehavior.restLevel
|
|
751
|
-
});
|
|
746
|
+
const humanRestController = createHumanRestController({
|
|
747
|
+
enabled: effectiveHumanRestEnabled,
|
|
748
|
+
shortRestEnabled: effectiveHumanBehavior.shortRest,
|
|
749
|
+
batchRestEnabled: effectiveHumanBehavior.batchRest,
|
|
750
|
+
restLevel: effectiveHumanBehavior.restLevel
|
|
751
|
+
});
|
|
752
752
|
const normalizedDetailSource = normalizeDetailSource(detailSource);
|
|
753
753
|
const normalizedScreeningMode = normalizeScreeningMode(screeningMode);
|
|
754
754
|
const useLlmScreening = normalizedScreeningMode !== "deterministic";
|
|
@@ -792,12 +792,12 @@ export async function runChatWorkflow({
|
|
|
792
792
|
let requestedCount = 0;
|
|
793
793
|
let requestSatisfiedCount = 0;
|
|
794
794
|
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) {
|
|
795
|
+
let contextSetup = {};
|
|
796
|
+
let contextRecoveryAttempts = 0;
|
|
797
|
+
const candidateRecoveryCounts = new Map();
|
|
798
|
+
let lastHumanEvent = null;
|
|
799
|
+
|
|
800
|
+
function recordHumanEvent(event = null) {
|
|
801
801
|
if (!event) return lastHumanEvent;
|
|
802
802
|
lastHumanEvent = {
|
|
803
803
|
at: new Date().toISOString(),
|
|
@@ -861,13 +861,13 @@ export async function runChatWorkflow({
|
|
|
861
861
|
...setup.contextSetup,
|
|
862
862
|
initial_top_level_state: initialTopLevelState
|
|
863
863
|
};
|
|
864
|
-
runControl.checkpoint({
|
|
865
|
-
chat_context: contextSetup
|
|
866
|
-
});
|
|
867
|
-
|
|
868
|
-
async function recoverAndReapplyChatContext(reason, error = null, {
|
|
869
|
-
forceRefresh = false
|
|
870
|
-
} = {}) {
|
|
864
|
+
runControl.checkpoint({
|
|
865
|
+
chat_context: contextSetup
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
async function recoverAndReapplyChatContext(reason, error = null, {
|
|
869
|
+
forceRefresh = false
|
|
870
|
+
} = {}) {
|
|
871
871
|
runControl.setPhase("chat:recover_shell");
|
|
872
872
|
contextRecoveryAttempts += 1;
|
|
873
873
|
const shellRecovery = await recoverChatShell(client, {
|
|
@@ -967,12 +967,12 @@ export async function runChatWorkflow({
|
|
|
967
967
|
context_recoveries: contextRecoveryAttempts,
|
|
968
968
|
list_end_reason: listEndReason,
|
|
969
969
|
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,
|
|
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,
|
|
976
976
|
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
977
977
|
last_human_event: lastHumanEvent
|
|
978
978
|
});
|
|
@@ -997,10 +997,10 @@ export async function runChatWorkflow({
|
|
|
997
997
|
last_human_event: lastHumanEvent,
|
|
998
998
|
list_end_reason: listEndReason,
|
|
999
999
|
target_pass_count: passTarget,
|
|
1000
|
-
process_until_list_end: Boolean(processUntilListEnd),
|
|
1001
|
-
processed_limit: processedLimit,
|
|
1002
|
-
detail_source: normalizedDetailSource,
|
|
1003
|
-
processed: 0,
|
|
1000
|
+
process_until_list_end: Boolean(processUntilListEnd),
|
|
1001
|
+
processed_limit: processedLimit,
|
|
1002
|
+
detail_source: normalizedDetailSource,
|
|
1003
|
+
processed: 0,
|
|
1004
1004
|
screened: 0,
|
|
1005
1005
|
detail_opened: 0,
|
|
1006
1006
|
llm_screened: 0,
|
|
@@ -1501,11 +1501,11 @@ export async function runChatWorkflow({
|
|
|
1501
1501
|
llmResult = createMissingLlmConfigResult();
|
|
1502
1502
|
} else {
|
|
1503
1503
|
try {
|
|
1504
|
-
llmResult = await measureTiming(timings, "vision_model_ms", () => callScreeningLlm({
|
|
1505
|
-
candidate: detailResult.candidate,
|
|
1506
|
-
criteria,
|
|
1507
|
-
config: llmConfig,
|
|
1508
|
-
timeoutMs: llmTimeoutMs,
|
|
1504
|
+
llmResult = await measureTiming(timings, "vision_model_ms", () => callScreeningLlm({
|
|
1505
|
+
candidate: detailResult.candidate,
|
|
1506
|
+
criteria,
|
|
1507
|
+
config: llmConfig,
|
|
1508
|
+
timeoutMs: llmTimeoutMs,
|
|
1509
1509
|
imageEvidence,
|
|
1510
1510
|
maxImages: llmImageLimit,
|
|
1511
1511
|
imageDetail: llmImageDetail
|
|
@@ -1574,10 +1574,10 @@ export async function runChatWorkflow({
|
|
|
1574
1574
|
const llmTimingKey = imageEvidence?.file_paths?.length
|
|
1575
1575
|
? "vision_model_ms"
|
|
1576
1576
|
: "text_model_ms";
|
|
1577
|
-
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1578
|
-
candidate: detailResult.candidate,
|
|
1579
|
-
criteria,
|
|
1580
|
-
config: llmConfig,
|
|
1577
|
+
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1578
|
+
candidate: detailResult.candidate,
|
|
1579
|
+
criteria,
|
|
1580
|
+
config: llmConfig,
|
|
1581
1581
|
timeoutMs: llmTimeoutMs,
|
|
1582
1582
|
imageEvidence,
|
|
1583
1583
|
maxImages: llmImageLimit,
|
|
@@ -1773,12 +1773,12 @@ export async function runChatWorkflow({
|
|
|
1773
1773
|
context_recoveries: contextRecoveryAttempts,
|
|
1774
1774
|
list_end_reason: listEndReason || null,
|
|
1775
1775
|
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,
|
|
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,
|
|
1782
1782
|
human_rest_ms: humanRestController.getState().total_rest_ms,
|
|
1783
1783
|
last_human_event: lastHumanEvent,
|
|
1784
1784
|
last_candidate_id: screeningCandidate.id || null,
|
|
@@ -1818,11 +1818,11 @@ export async function runChatWorkflow({
|
|
|
1818
1818
|
compactResult.human_rest = restResult;
|
|
1819
1819
|
addTiming(compactResult.timings, "human_rest_ms", restElapsed);
|
|
1820
1820
|
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,
|
|
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,
|
|
1826
1826
|
human_rest_last: restResult,
|
|
1827
1827
|
context_recoveries: contextRecoveryAttempts,
|
|
1828
1828
|
last_human_event: lastHumanEvent
|
|
@@ -1855,10 +1855,10 @@ export async function runChatWorkflow({
|
|
|
1855
1855
|
last_human_event: lastHumanEvent,
|
|
1856
1856
|
list_end_reason: listEndReason || null,
|
|
1857
1857
|
target_pass_count: passTarget,
|
|
1858
|
-
process_until_list_end: Boolean(processUntilListEnd),
|
|
1859
|
-
processed_limit: processedLimit,
|
|
1860
|
-
detail_source: normalizedDetailSource,
|
|
1861
|
-
processed: finalCounters.processed,
|
|
1858
|
+
process_until_list_end: Boolean(processUntilListEnd),
|
|
1859
|
+
processed_limit: processedLimit,
|
|
1860
|
+
detail_source: normalizedDetailSource,
|
|
1861
|
+
processed: finalCounters.processed,
|
|
1862
1862
|
screened: finalCounters.screened,
|
|
1863
1863
|
detail_opened: finalCounters.detail_opened,
|
|
1864
1864
|
llm_screened: finalCounters.llm_screened,
|
|
@@ -1880,10 +1880,10 @@ export function createChatRunService({
|
|
|
1880
1880
|
} = {}) {
|
|
1881
1881
|
const manager = lifecycle || createRunLifecycleManager({ idPrefix, onSnapshot });
|
|
1882
1882
|
|
|
1883
|
-
function startChatRun({
|
|
1884
|
-
runId = "",
|
|
1885
|
-
client,
|
|
1886
|
-
targetUrl = CHAT_TARGET_URL,
|
|
1883
|
+
function startChatRun({
|
|
1884
|
+
runId = "",
|
|
1885
|
+
client,
|
|
1886
|
+
targetUrl = CHAT_TARGET_URL,
|
|
1887
1887
|
job = "",
|
|
1888
1888
|
startFrom = "all",
|
|
1889
1889
|
criteria = "",
|
|
@@ -1929,10 +1929,10 @@ export function createChatRunService({
|
|
|
1929
1929
|
legacyEnabled: humanRestEnabled === true || llmConfig?.humanRestEnabled === true
|
|
1930
1930
|
});
|
|
1931
1931
|
const effectiveHumanRestEnabled = effectiveHumanBehavior.restEnabled;
|
|
1932
|
-
return manager.startRun({
|
|
1933
|
-
runId,
|
|
1934
|
-
name,
|
|
1935
|
-
context: {
|
|
1932
|
+
return manager.startRun({
|
|
1933
|
+
runId,
|
|
1934
|
+
name,
|
|
1935
|
+
context: {
|
|
1936
1936
|
domain: "chat",
|
|
1937
1937
|
target_url: targetUrl,
|
|
1938
1938
|
criteria_present: Boolean(criteria),
|
|
@@ -1962,13 +1962,13 @@ export function createChatRunService({
|
|
|
1962
1962
|
list_settle_ms: listSettleMs,
|
|
1963
1963
|
list_fallback_point: listFallbackPoint,
|
|
1964
1964
|
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
|
-
},
|
|
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
|
+
},
|
|
1972
1972
|
progress: {
|
|
1973
1973
|
card_count: 0,
|
|
1974
1974
|
target_count: targetPassCount || (processUntilListEnd ? "all" : processedLimit),
|
|
@@ -1983,11 +1983,11 @@ export function createChatRunService({
|
|
|
1983
1983
|
requested: 0,
|
|
1984
1984
|
request_satisfied: 0,
|
|
1985
1985
|
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,
|
|
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,
|
|
1991
1991
|
human_rest_count: 0,
|
|
1992
1992
|
human_rest_ms: 0,
|
|
1993
1993
|
last_human_event: null
|
|
@@ -38,13 +38,13 @@ 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
|
+
createFailedLlmScreeningResult,
|
|
45
|
+
llmResultToScreening,
|
|
46
|
+
screenCandidate
|
|
47
|
+
} from "../../core/screening/index.js";
|
|
48
48
|
import {
|
|
49
49
|
closeRecommendBlockingPanels,
|
|
50
50
|
closeRecommendAvatarPreview,
|
|
@@ -906,8 +906,8 @@ export async function runRecommendWorkflow({
|
|
|
906
906
|
recovery_reason: reason
|
|
907
907
|
});
|
|
908
908
|
return refreshResult;
|
|
909
|
-
}
|
|
910
|
-
|
|
909
|
+
}
|
|
910
|
+
|
|
911
911
|
runControl.setPhase("recommend:cleanup");
|
|
912
912
|
await closeRecommendDetail(client, { attemptsLimit: 2 });
|
|
913
913
|
await closeRecommendAvatarPreview(client, { attemptsLimit: 2 });
|
|
@@ -1334,11 +1334,11 @@ export async function runRecommendWorkflow({
|
|
|
1334
1334
|
const llmTimingKey = detailResult?.image_evidence?.file_paths?.length
|
|
1335
1335
|
? "vision_model_ms"
|
|
1336
1336
|
: "text_model_ms";
|
|
1337
|
-
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1338
|
-
candidate: screeningCandidate,
|
|
1339
|
-
criteria,
|
|
1340
|
-
config: llmConfig,
|
|
1341
|
-
timeoutMs: llmTimeoutMs,
|
|
1337
|
+
llmResult = await measureTiming(timings, llmTimingKey, () => callScreeningLlm({
|
|
1338
|
+
candidate: screeningCandidate,
|
|
1339
|
+
criteria,
|
|
1340
|
+
config: llmConfig,
|
|
1341
|
+
timeoutMs: llmTimeoutMs,
|
|
1342
1342
|
imageEvidence: detailResult?.image_evidence || null,
|
|
1343
1343
|
maxImages: llmImageLimit,
|
|
1344
1344
|
imageDetail: llmImageDetail
|
|
@@ -1532,7 +1532,7 @@ export async function runRecommendWorkflow({
|
|
|
1532
1532
|
human_rest: humanRestController.getState(),
|
|
1533
1533
|
last_human_event: lastHumanEvent,
|
|
1534
1534
|
list_end_reason: listEndReason || null,
|
|
1535
|
-
refresh_rounds: refreshRounds,
|
|
1535
|
+
refresh_rounds: refreshRounds,
|
|
1536
1536
|
refresh_attempts: refreshAttempts,
|
|
1537
1537
|
context_recoveries: contextRecoveryAttempts,
|
|
1538
1538
|
...countRecommendResultStatuses(results, { greetCount }),
|
package/src/index.js
CHANGED
|
@@ -123,8 +123,50 @@ const TOOL_GET_RECRUIT_PIPELINE_RUN = "get_recruit_pipeline_run";
|
|
|
123
123
|
const TOOL_CANCEL_RECRUIT_PIPELINE_RUN = "cancel_recruit_pipeline_run";
|
|
124
124
|
const TOOL_PAUSE_RECRUIT_PIPELINE_RUN = "pause_recruit_pipeline_run";
|
|
125
125
|
const TOOL_RESUME_RECRUIT_PIPELINE_RUN = "resume_recruit_pipeline_run";
|
|
126
|
-
|
|
127
|
-
const SERVER_NAME = "boss-recommend-mcp";
|
|
126
|
+
|
|
127
|
+
const SERVER_NAME = "boss-recommend-mcp";
|
|
128
|
+
const MCP_TOOLSET_ENV = "BOSS_RECOMMEND_MCP_TOOLSET";
|
|
129
|
+
const MCP_TOOLSET_ALL = "all";
|
|
130
|
+
const MCP_TOOLSET_RECOMMEND = "recommend";
|
|
131
|
+
const MCP_TOOLSET_CHAT = "chat";
|
|
132
|
+
const MCP_TOOLSET_RECRUIT = "recruit";
|
|
133
|
+
const VALID_MCP_TOOLSETS = new Set([
|
|
134
|
+
MCP_TOOLSET_ALL,
|
|
135
|
+
MCP_TOOLSET_RECOMMEND,
|
|
136
|
+
MCP_TOOLSET_CHAT,
|
|
137
|
+
MCP_TOOLSET_RECRUIT
|
|
138
|
+
]);
|
|
139
|
+
const RECOMMEND_TOOL_NAMES = new Set([
|
|
140
|
+
TOOL_LIST_RECOMMEND_JOBS,
|
|
141
|
+
TOOL_RUN_RECOMMEND,
|
|
142
|
+
TOOL_START_RUN,
|
|
143
|
+
TOOL_PREPARE_RUN,
|
|
144
|
+
TOOL_SCHEDULE_RUN,
|
|
145
|
+
TOOL_GET_SCHEDULED_RUN,
|
|
146
|
+
TOOL_GET_RUN,
|
|
147
|
+
TOOL_LIST_RUNS,
|
|
148
|
+
TOOL_CANCEL_RUN,
|
|
149
|
+
TOOL_PAUSE_RUN,
|
|
150
|
+
TOOL_RESUME_RUN
|
|
151
|
+
]);
|
|
152
|
+
const BOSS_CHAT_TOOL_NAMES = new Set([
|
|
153
|
+
TOOL_BOSS_CHAT_HEALTH_CHECK,
|
|
154
|
+
TOOL_BOSS_CHAT_LIST_JOBS,
|
|
155
|
+
TOOL_BOSS_CHAT_PREPARE_RUN,
|
|
156
|
+
TOOL_BOSS_CHAT_START_RUN,
|
|
157
|
+
TOOL_BOSS_CHAT_GET_RUN,
|
|
158
|
+
TOOL_BOSS_CHAT_PAUSE_RUN,
|
|
159
|
+
TOOL_BOSS_CHAT_RESUME_RUN,
|
|
160
|
+
TOOL_BOSS_CHAT_CANCEL_RUN
|
|
161
|
+
]);
|
|
162
|
+
const RECRUIT_TOOL_NAMES = new Set([
|
|
163
|
+
TOOL_RUN_RECRUIT_PIPELINE,
|
|
164
|
+
TOOL_START_RECRUIT_PIPELINE_RUN,
|
|
165
|
+
TOOL_GET_RECRUIT_PIPELINE_RUN,
|
|
166
|
+
TOOL_CANCEL_RECRUIT_PIPELINE_RUN,
|
|
167
|
+
TOOL_PAUSE_RECRUIT_PIPELINE_RUN,
|
|
168
|
+
TOOL_RESUME_RECRUIT_PIPELINE_RUN
|
|
169
|
+
]);
|
|
128
170
|
const FRAMING_UNKNOWN = "unknown";
|
|
129
171
|
const FRAMING_HEADER = "header";
|
|
130
172
|
const FRAMING_LINE = "line";
|
|
@@ -454,6 +496,26 @@ function readRawRunState(runId) {
|
|
|
454
496
|
}
|
|
455
497
|
}
|
|
456
498
|
|
|
499
|
+
function compactProgressForList(progress = {}) {
|
|
500
|
+
const compact = {};
|
|
501
|
+
for (const key of [
|
|
502
|
+
"processed",
|
|
503
|
+
"screened",
|
|
504
|
+
"passed",
|
|
505
|
+
"skipped",
|
|
506
|
+
"target_count",
|
|
507
|
+
"card_count",
|
|
508
|
+
"detail_opened",
|
|
509
|
+
"greet_count",
|
|
510
|
+
"post_action_clicked"
|
|
511
|
+
]) {
|
|
512
|
+
if (Number.isFinite(progress?.[key])) {
|
|
513
|
+
compact[key] = progress[key];
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return compact;
|
|
517
|
+
}
|
|
518
|
+
|
|
457
519
|
function getRunSortTime(run = {}, fallbackMs = 0) {
|
|
458
520
|
for (const key of ["updated_at", "heartbeat_at", "completed_at", "started_at", "updatedAt", "completedAt", "startedAt"]) {
|
|
459
521
|
const ms = Date.parse(run?.[key] || "");
|
|
@@ -477,7 +539,7 @@ function compactRunForList(run = {}) {
|
|
|
477
539
|
heartbeat_at: run.heartbeat_at || null,
|
|
478
540
|
completed_at: run.completed_at || run.completedAt || null,
|
|
479
541
|
pid: Number.isInteger(run.pid) && run.pid > 0 ? run.pid : null,
|
|
480
|
-
progress: run.progress
|
|
542
|
+
progress: compactProgressForList(run.progress),
|
|
481
543
|
last_message: normalizeText(run.last_message || error?.message || ""),
|
|
482
544
|
control: {
|
|
483
545
|
pause_requested: run.control?.pause_requested === true,
|
|
@@ -494,11 +556,10 @@ function compactRunForList(run = {}) {
|
|
|
494
556
|
report_json: normalizeText(result.report_json || result.result?.report_json || ""),
|
|
495
557
|
checkpoint_path: normalizeText(result.checkpoint_path || result.result?.checkpoint_path || "")
|
|
496
558
|
} : null,
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
worker_stderr_path: normalizeText(run.resume?.worker_stderr_path || "")
|
|
559
|
+
artifacts: {
|
|
560
|
+
output_csv: normalizeText(result?.output_csv || result?.result?.output_csv || ""),
|
|
561
|
+
report_json: normalizeText(result?.report_json || result?.result?.report_json || ""),
|
|
562
|
+
checkpoint_path: normalizeText(result?.checkpoint_path || result?.result?.checkpoint_path || "")
|
|
502
563
|
}
|
|
503
564
|
};
|
|
504
565
|
}
|
|
@@ -1294,8 +1355,154 @@ function createScheduleRunInputSchema() {
|
|
|
1294
1355
|
};
|
|
1295
1356
|
}
|
|
1296
1357
|
|
|
1297
|
-
function
|
|
1298
|
-
|
|
1358
|
+
function createCompactRunInputSchema() {
|
|
1359
|
+
const targetCountSchema = {
|
|
1360
|
+
anyOf: [
|
|
1361
|
+
{ type: "integer", minimum: 0 },
|
|
1362
|
+
{ type: "string" }
|
|
1363
|
+
],
|
|
1364
|
+
description: "目标通过人数;扫到底/不限可传 all"
|
|
1365
|
+
};
|
|
1366
|
+
return {
|
|
1367
|
+
type: "object",
|
|
1368
|
+
properties: {
|
|
1369
|
+
instruction: {
|
|
1370
|
+
type: "string",
|
|
1371
|
+
description: "用户原始筛选标准/任务说明;正式启动时逐字复用"
|
|
1372
|
+
},
|
|
1373
|
+
confirmation: {
|
|
1374
|
+
type: "object",
|
|
1375
|
+
properties: {
|
|
1376
|
+
final_confirmed: {
|
|
1377
|
+
type: "boolean",
|
|
1378
|
+
description: "用户完成总确认后传 true"
|
|
1379
|
+
}
|
|
1380
|
+
},
|
|
1381
|
+
additionalProperties: true
|
|
1382
|
+
},
|
|
1383
|
+
overrides: {
|
|
1384
|
+
type: "object",
|
|
1385
|
+
properties: {
|
|
1386
|
+
page_scope: { type: "string", enum: ["recommend", "latest", "featured"] },
|
|
1387
|
+
school_tag: {
|
|
1388
|
+
anyOf: [
|
|
1389
|
+
{ type: "string" },
|
|
1390
|
+
{ type: "array", items: { type: "string" } }
|
|
1391
|
+
]
|
|
1392
|
+
},
|
|
1393
|
+
degree: {
|
|
1394
|
+
anyOf: [
|
|
1395
|
+
{ type: "string" },
|
|
1396
|
+
{ type: "array", items: { type: "string" } }
|
|
1397
|
+
]
|
|
1398
|
+
},
|
|
1399
|
+
gender: { type: "string" },
|
|
1400
|
+
recent_not_view: { type: "string" },
|
|
1401
|
+
criteria: { type: "string" },
|
|
1402
|
+
target_count: targetCountSchema,
|
|
1403
|
+
post_action: { type: "string", enum: ["greet", "none"] },
|
|
1404
|
+
max_greet_count: targetCountSchema,
|
|
1405
|
+
job: { type: "string" }
|
|
1406
|
+
},
|
|
1407
|
+
additionalProperties: true
|
|
1408
|
+
},
|
|
1409
|
+
human_behavior: {
|
|
1410
|
+
type: "object",
|
|
1411
|
+
properties: {
|
|
1412
|
+
restLevel: { type: "string", enum: ["low", "medium", "high"] },
|
|
1413
|
+
rest_level: { type: "string", enum: ["low", "medium", "high"] }
|
|
1414
|
+
},
|
|
1415
|
+
additionalProperties: true
|
|
1416
|
+
},
|
|
1417
|
+
host: { type: "string" },
|
|
1418
|
+
port: { type: "integer", minimum: 1 },
|
|
1419
|
+
slow_live: { type: "boolean" },
|
|
1420
|
+
delay_ms: { type: "integer", minimum: 0 },
|
|
1421
|
+
detail_limit: { type: "integer", minimum: 0 },
|
|
1422
|
+
execute_post_action: { type: "boolean" },
|
|
1423
|
+
no_filter: { type: "boolean" },
|
|
1424
|
+
dry_run: { type: "boolean" }
|
|
1425
|
+
},
|
|
1426
|
+
required: ["instruction"],
|
|
1427
|
+
additionalProperties: true
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
function createCompactScheduleRunInputSchema() {
|
|
1432
|
+
const base = createCompactRunInputSchema();
|
|
1433
|
+
return {
|
|
1434
|
+
...base,
|
|
1435
|
+
properties: {
|
|
1436
|
+
...base.properties,
|
|
1437
|
+
schedule_id: {
|
|
1438
|
+
type: "string",
|
|
1439
|
+
description: "可选,自定义定时任务 id;默认自动生成"
|
|
1440
|
+
},
|
|
1441
|
+
schedule_run_at: {
|
|
1442
|
+
type: "string",
|
|
1443
|
+
description: "ISO 时间字符串"
|
|
1444
|
+
},
|
|
1445
|
+
schedule_delay_minutes: {
|
|
1446
|
+
type: "number",
|
|
1447
|
+
minimum: 0
|
|
1448
|
+
},
|
|
1449
|
+
schedule_delay_seconds: {
|
|
1450
|
+
type: "number",
|
|
1451
|
+
minimum: 0
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
function normalizeMcpToolset(value) {
|
|
1458
|
+
const raw = String(value || "").trim().toLowerCase().replace(/[\s_]+/g, "-");
|
|
1459
|
+
if (!raw) return MCP_TOOLSET_ALL;
|
|
1460
|
+
if (raw === "boss-recommend" || raw === "recommend-page" || raw === "recommended") return MCP_TOOLSET_RECOMMEND;
|
|
1461
|
+
if (raw === "boss-chat" || raw === "chat-only" || raw === "chat-page") return MCP_TOOLSET_CHAT;
|
|
1462
|
+
if (raw === "boss-recruit" || raw === "search" || raw === "search-page" || raw === "recruit-page") return MCP_TOOLSET_RECRUIT;
|
|
1463
|
+
return VALID_MCP_TOOLSETS.has(raw) ? raw : MCP_TOOLSET_ALL;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
function getConfiguredMcpToolset(argv = process.argv, env = process.env) {
|
|
1467
|
+
const args = Array.isArray(argv) ? argv.slice(2) : [];
|
|
1468
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1469
|
+
const arg = String(args[index] || "");
|
|
1470
|
+
if (arg === "--toolset" || arg === "--tools") {
|
|
1471
|
+
return normalizeMcpToolset(args[index + 1]);
|
|
1472
|
+
}
|
|
1473
|
+
if (arg.startsWith("--toolset=")) {
|
|
1474
|
+
return normalizeMcpToolset(arg.slice("--toolset=".length));
|
|
1475
|
+
}
|
|
1476
|
+
if (arg.startsWith("--tools=")) {
|
|
1477
|
+
return normalizeMcpToolset(arg.slice("--tools=".length));
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
return normalizeMcpToolset(env?.[MCP_TOOLSET_ENV]);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
function toolNamesForMcpToolset(toolset) {
|
|
1484
|
+
const normalized = normalizeMcpToolset(toolset);
|
|
1485
|
+
if (normalized === MCP_TOOLSET_RECOMMEND) return RECOMMEND_TOOL_NAMES;
|
|
1486
|
+
if (normalized === MCP_TOOLSET_CHAT) return BOSS_CHAT_TOOL_NAMES;
|
|
1487
|
+
if (normalized === MCP_TOOLSET_RECRUIT) return RECRUIT_TOOL_NAMES;
|
|
1488
|
+
return null;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
function filterToolsForMcpToolset(tools, toolset = getConfiguredMcpToolset()) {
|
|
1492
|
+
const names = toolNamesForMcpToolset(toolset);
|
|
1493
|
+
if (!names) return tools;
|
|
1494
|
+
return tools.filter((tool) => names.has(tool.name));
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
function createToolsSchema(toolset = getConfiguredMcpToolset()) {
|
|
1498
|
+
const normalizedToolset = normalizeMcpToolset(toolset);
|
|
1499
|
+
const runInputSchema = normalizedToolset === MCP_TOOLSET_RECOMMEND
|
|
1500
|
+
? createCompactRunInputSchema()
|
|
1501
|
+
: createRunInputSchema();
|
|
1502
|
+
const scheduleRunInputSchema = normalizedToolset === MCP_TOOLSET_RECOMMEND
|
|
1503
|
+
? createCompactScheduleRunInputSchema()
|
|
1504
|
+
: createScheduleRunInputSchema();
|
|
1505
|
+
const tools = [
|
|
1299
1506
|
{
|
|
1300
1507
|
name: TOOL_BOSS_CHAT_HEALTH_CHECK,
|
|
1301
1508
|
description: "Boss 聊天页/chat-only 健康检查。chat-only、未读、全部聊天、求简历等任务必须先走 boss-chat 工具,不要调用 list_recommend_jobs 或 start_recommend_pipeline_run。",
|
|
@@ -1402,22 +1609,22 @@ function createToolsSchema() {
|
|
|
1402
1609
|
{
|
|
1403
1610
|
name: TOOL_RUN_RECOMMEND,
|
|
1404
1611
|
description: "立即通过原生 MCP 启动 Boss 推荐页筛选。它是 start_recommend_pipeline_run 的短别名;用户已经确认并要现在启动时,优先调用本工具,不需要先调用 prepare_recommend_pipeline_run。必须作为 MCP tool call 调用,禁止通过 terminal/shell/run_command/PowerShell/CLI/manual JSON-RPC 代替,也不要用 schedule_recommend_pipeline_run 冒充立即启动。",
|
|
1405
|
-
inputSchema:
|
|
1612
|
+
inputSchema: runInputSchema
|
|
1406
1613
|
},
|
|
1407
1614
|
{
|
|
1408
1615
|
name: TOOL_START_RUN,
|
|
1409
1616
|
description: "立即通过原生 MCP 异步启动 Boss 推荐页流水线(含同步门禁预检)。用户已经确认并要现在启动时,优先调用本工具或 run_recommend,不需要先调用 prepare_recommend_pipeline_run。必须作为 MCP tool call 调用,禁止通过 terminal/shell/run_command/PowerShell/CLI/manual JSON-RPC 代替,也不要用 schedule_recommend_pipeline_run 冒充立即启动。",
|
|
1410
|
-
inputSchema:
|
|
1617
|
+
inputSchema: runInputSchema
|
|
1411
1618
|
},
|
|
1412
1619
|
{
|
|
1413
1620
|
name: TOOL_PREPARE_RUN,
|
|
1414
1621
|
description: "只校验 Boss 推荐页流水线参数是否完整;不会启动筛选任务。主要用于显式预检或稍后/cron/定时启动前校验。若用户要现在运行,READY/cron_ready=true 后必须继续调用本 MCP server 的 run_recommend 或 start_recommend_pipeline_run;prepare 能返回结果就证明原生 MCP 可用,禁止改用 terminal/shell/run_command/PowerShell/CLI/manual JSON-RPC,也禁止再次调用 prepare 试图启动。",
|
|
1415
|
-
inputSchema:
|
|
1622
|
+
inputSchema: runInputSchema
|
|
1416
1623
|
},
|
|
1417
1624
|
{
|
|
1418
1625
|
name: TOOL_SCHEDULE_RUN,
|
|
1419
1626
|
description: "只用于用户明确要求稍后/cron/定时启动的 package-owned Boss 推荐页定时任务。若用户要现在运行,必须调用 run_recommend 或 start_recommend_pipeline_run,不要用短延迟 schedule 冒充立即启动。schedule 会先校验 READY/cron_ready,再保存完整 payload,并由 detached scheduler 到点直接启动,不依赖 AI harness 自己拼 shell cron。",
|
|
1420
|
-
inputSchema:
|
|
1627
|
+
inputSchema: scheduleRunInputSchema
|
|
1421
1628
|
},
|
|
1422
1629
|
{
|
|
1423
1630
|
name: TOOL_GET_SCHEDULED_RUN,
|
|
@@ -1558,6 +1765,7 @@ function createToolsSchema() {
|
|
|
1558
1765
|
inputSchema: createRecruitRunIdInputSchema()
|
|
1559
1766
|
}
|
|
1560
1767
|
];
|
|
1768
|
+
return filterToolsForMcpToolset(tools, toolset);
|
|
1561
1769
|
}
|
|
1562
1770
|
|
|
1563
1771
|
function createToolResultResponse(id, payload, isError = false) {
|
|
@@ -2859,10 +3067,19 @@ async function handleRequest(message, workspaceRoot) {
|
|
|
2859
3067
|
};
|
|
2860
3068
|
}
|
|
2861
3069
|
|
|
2862
|
-
if (method === "tools/call") {
|
|
2863
|
-
const toolName = params?.name;
|
|
2864
|
-
const args = params?.arguments || {};
|
|
2865
|
-
|
|
3070
|
+
if (method === "tools/call") {
|
|
3071
|
+
const toolName = params?.name;
|
|
3072
|
+
const args = params?.arguments || {};
|
|
3073
|
+
const toolset = getConfiguredMcpToolset();
|
|
3074
|
+
const visibleToolNames = new Set(createToolsSchema(toolset).map((tool) => tool.name));
|
|
3075
|
+
if (!visibleToolNames.has(toolName)) {
|
|
3076
|
+
return createJsonRpcError(
|
|
3077
|
+
id,
|
|
3078
|
+
-32602,
|
|
3079
|
+
`Tool ${toolName || ""} is not available in the ${toolset} boss-recommend-mcp toolset. Use the MCP server/toolset that exposes this domain instead of terminal or CLI fallback.`
|
|
3080
|
+
);
|
|
3081
|
+
}
|
|
3082
|
+
|
|
2866
3083
|
if ([TOOL_RUN_RECOMMEND, TOOL_START_RUN].includes(toolName)) {
|
|
2867
3084
|
const inputError = validateRunArgs(args);
|
|
2868
3085
|
if (inputError) {
|
|
@@ -3105,6 +3322,9 @@ export function startServer() {
|
|
|
3105
3322
|
}
|
|
3106
3323
|
|
|
3107
3324
|
export const __testables = {
|
|
3325
|
+
createToolsSchema,
|
|
3326
|
+
getConfiguredMcpToolset,
|
|
3327
|
+
normalizeMcpToolset,
|
|
3108
3328
|
handleRequest,
|
|
3109
3329
|
runDetachedWorkerForTests(options = {}) {
|
|
3110
3330
|
return runDetachedWorker(options);
|