@reconcrap/boss-recommend-mcp 2.1.9 → 2.1.11
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 +16 -11
- package/package.json +1 -1
- package/skills/boss-chat/README.md +3 -1
- package/skills/boss-chat/SKILL.md +5 -2
- package/skills/boss-recommend-pipeline/SKILL.md +17 -8
- package/src/cli.js +38 -5
- package/src/core/run/index.js +32 -25
- package/src/index.js +376 -140
- package/src/recommend-mcp.js +323 -72
package/src/recommend-mcp.js
CHANGED
|
@@ -75,13 +75,119 @@ let recommendRunService = createRecommendRunService({
|
|
|
75
75
|
});
|
|
76
76
|
const recommendRunMeta = new Map();
|
|
77
77
|
|
|
78
|
-
function normalizeText(value) {
|
|
79
|
-
return String(value || "").replace(/\s+/g, " ").trim();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
function normalizeText(value) {
|
|
79
|
+
return String(value || "").replace(/\s+/g, " ").trim();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function collectRecommendRouteText(args = {}) {
|
|
83
|
+
return normalizeText([
|
|
84
|
+
args.instruction,
|
|
85
|
+
args.criteria,
|
|
86
|
+
args.target_url_includes,
|
|
87
|
+
args.page_scope,
|
|
88
|
+
args.confirmation?.page_value,
|
|
89
|
+
args.confirmation?.job_value,
|
|
90
|
+
args.overrides?.criteria,
|
|
91
|
+
args.overrides?.page_scope,
|
|
92
|
+
args.overrides?.job,
|
|
93
|
+
args.overrides?.target_url_includes
|
|
94
|
+
].filter((value) => value !== undefined && value !== null).join(" "));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function findRouteSignals(text, patterns = []) {
|
|
98
|
+
const signals = [];
|
|
99
|
+
for (const { label, pattern } of patterns) {
|
|
100
|
+
if (pattern.test(text)) signals.push(label);
|
|
101
|
+
}
|
|
102
|
+
return signals;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function detectNonRecommendRoute(args = {}) {
|
|
106
|
+
const text = collectRecommendRouteText(args);
|
|
107
|
+
if (!text) return null;
|
|
108
|
+
const chatSignals = findRouteSignals(text, [
|
|
109
|
+
{ label: "chat-only", pattern: /\bchat[-\s]?only\b/i },
|
|
110
|
+
{ label: "boss-chat", pattern: /\bboss[-\s]?chat\b/i },
|
|
111
|
+
{ label: "chat page", pattern: /\bchat\s+page\b/i },
|
|
112
|
+
{ label: "chat/index", pattern: /(?:\/web\/chat\/index|chat\/index)/i },
|
|
113
|
+
{ label: "聊天页", pattern: /聊天页/ },
|
|
114
|
+
{ label: "聊天列表", pattern: /聊天列表/ },
|
|
115
|
+
{ label: "未读", pattern: /未读/ },
|
|
116
|
+
{ label: "全部聊天", pattern: /全部聊天|所有聊天/ },
|
|
117
|
+
{ label: "求简历", pattern: /求简历|索要简历|要简历|在线简历/ }
|
|
118
|
+
]);
|
|
119
|
+
if (chatSignals.length) {
|
|
120
|
+
return {
|
|
121
|
+
domain: "chat",
|
|
122
|
+
signals: chatSignals,
|
|
123
|
+
text
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const searchSignals = findRouteSignals(text, [
|
|
127
|
+
{ label: "search-only", pattern: /\bsearch[-\s]?only\b/i },
|
|
128
|
+
{ label: "search page", pattern: /\bsearch\s+page\b/i },
|
|
129
|
+
{ label: "recruit pipeline", pattern: /\brecruit\s+pipeline\b/i },
|
|
130
|
+
{ label: "chat/search", pattern: /(?:\/web\/chat\/search|chat\/search)/i },
|
|
131
|
+
{ label: "搜索页", pattern: /搜索页/ },
|
|
132
|
+
{ label: "招聘搜索", pattern: /招聘搜索/ }
|
|
133
|
+
]);
|
|
134
|
+
if (searchSignals.length) {
|
|
135
|
+
return {
|
|
136
|
+
domain: "search",
|
|
137
|
+
signals: searchSignals,
|
|
138
|
+
text
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function buildWrongRecommendRouteResponse(route) {
|
|
145
|
+
if (route?.domain === "chat") {
|
|
146
|
+
return {
|
|
147
|
+
status: "FAILED",
|
|
148
|
+
route_guard: true,
|
|
149
|
+
error: {
|
|
150
|
+
code: "WRONG_BOSS_TOOL_FOR_CHAT",
|
|
151
|
+
message: "This request is explicitly chat-only/chat-page work. Do not use recommend tools. Use boss_chat_health_check, then list_boss_chat_jobs or prepare_boss_chat_run, then start_boss_chat_run.",
|
|
152
|
+
retryable: false
|
|
153
|
+
},
|
|
154
|
+
detected_domain: "chat",
|
|
155
|
+
detected_signals: route.signals || [],
|
|
156
|
+
recommended_tool_sequence: [
|
|
157
|
+
"boss_chat_health_check",
|
|
158
|
+
"list_boss_chat_jobs",
|
|
159
|
+
"prepare_boss_chat_run",
|
|
160
|
+
"start_boss_chat_run"
|
|
161
|
+
]
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (route?.domain === "search") {
|
|
165
|
+
return {
|
|
166
|
+
status: "FAILED",
|
|
167
|
+
route_guard: true,
|
|
168
|
+
error: {
|
|
169
|
+
code: "WRONG_BOSS_TOOL_FOR_SEARCH",
|
|
170
|
+
message: "This request is explicitly search/recruit-page work. Do not use recommend tools. Use run_recruit_pipeline or start_recruit_pipeline_run.",
|
|
171
|
+
retryable: false
|
|
172
|
+
},
|
|
173
|
+
detected_domain: "search",
|
|
174
|
+
detected_signals: route.signals || [],
|
|
175
|
+
recommended_tool_sequence: [
|
|
176
|
+
"run_recruit_pipeline",
|
|
177
|
+
"start_recruit_pipeline_run"
|
|
178
|
+
]
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function guardRecommendRoute(args = {}) {
|
|
185
|
+
return buildWrongRecommendRouteResponse(detectNonRecommendRoute(args));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function parsePositiveInteger(raw, fallback) {
|
|
189
|
+
const parsed = Number.parseInt(String(raw || ""), 10);
|
|
190
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
85
191
|
}
|
|
86
192
|
|
|
87
193
|
function parseNonNegativeInteger(raw, fallback) {
|
|
@@ -345,9 +451,9 @@ function normalizeErrorText(error = {}) {
|
|
|
345
451
|
].join(" "));
|
|
346
452
|
}
|
|
347
453
|
|
|
348
|
-
function classifyRecommendRecovery(error = {}) {
|
|
349
|
-
const text = normalizeErrorText(error);
|
|
350
|
-
if (!text) return null;
|
|
454
|
+
function classifyRecommendRecovery(error = {}) {
|
|
455
|
+
const text = normalizeErrorText(error);
|
|
456
|
+
if (!text) return null;
|
|
351
457
|
if (/BOSS_LOGIN_REQUIRED/i.test(text)) return "login_required";
|
|
352
458
|
if (/Could not find node with given id|No node with given id|Node is detached|Cannot find node|DETAIL_STALE_NODE|IMAGE_CAPTURE_STALE_NODE/i.test(text)) {
|
|
353
459
|
return "transient_stale_dom";
|
|
@@ -358,8 +464,13 @@ function classifyRecommendRecovery(error = {}) {
|
|
|
358
464
|
if (/(?:aborted|abort|timeout|timed out|fetch failed|socket|network|ECONNRESET|ETIMEDOUT|EAI_AGAIN)/i.test(text)) {
|
|
359
465
|
return "transient_network_or_llm";
|
|
360
466
|
}
|
|
361
|
-
return null;
|
|
362
|
-
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function isCancelShutdownError(error = {}) {
|
|
471
|
+
const text = normalizeErrorText(error);
|
|
472
|
+
return /socket hang up|ECONNREFUSED|ECONNRESET|WebSocket is not open|Target closed|Session closed|Connection closed|RUN_PROCESS_EXITED|DETACHED_WORKER|RUN_WORKER/i.test(text);
|
|
473
|
+
}
|
|
363
474
|
|
|
364
475
|
function buildConstrainedAgentRecovery(snapshot = {}, meta = {}, artifacts = null) {
|
|
365
476
|
const error = snapshot?.error || snapshot?.result?.error || null;
|
|
@@ -574,15 +685,31 @@ function normalizeRunSnapshot(snapshot) {
|
|
|
574
685
|
};
|
|
575
686
|
}
|
|
576
687
|
|
|
577
|
-
function mergePersistedControlRequest(normalized, existing) {
|
|
578
|
-
const control = {
|
|
579
|
-
...(normalized?.control || {})
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
if (
|
|
584
|
-
|
|
585
|
-
|
|
688
|
+
function mergePersistedControlRequest(normalized, existing) {
|
|
689
|
+
const control = {
|
|
690
|
+
...(normalized?.control || {})
|
|
691
|
+
};
|
|
692
|
+
const existingControl = plainRecord(existing?.control);
|
|
693
|
+
if (!normalized) return control;
|
|
694
|
+
if (TERMINAL_STATUSES.has(normalized.state)) {
|
|
695
|
+
if (
|
|
696
|
+
normalized.state === RUN_STATUS_FAILED
|
|
697
|
+
&& existingControl.cancel_requested === true
|
|
698
|
+
&& isCancelShutdownError(normalized.error || normalized.result?.error || "")
|
|
699
|
+
) {
|
|
700
|
+
return {
|
|
701
|
+
...control,
|
|
702
|
+
pause_requested: true,
|
|
703
|
+
pause_requested_at: existingControl.pause_requested_at || control.pause_requested_at || new Date().toISOString(),
|
|
704
|
+
pause_requested_by: existingControl.pause_requested_by || control.pause_requested_by || "cancel_recommend_pipeline_run",
|
|
705
|
+
cancel_requested: true
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
return control;
|
|
709
|
+
}
|
|
710
|
+
if (existingControl.cancel_requested === true) {
|
|
711
|
+
return {
|
|
712
|
+
...control,
|
|
586
713
|
pause_requested: true,
|
|
587
714
|
pause_requested_at: existingControl.pause_requested_at || control.pause_requested_at || new Date().toISOString(),
|
|
588
715
|
pause_requested_by: existingControl.pause_requested_by || control.pause_requested_by || "cancel_recommend_pipeline_run",
|
|
@@ -605,22 +732,81 @@ function mergePersistedControlRequest(normalized, existing) {
|
|
|
605
732
|
pause_requested_by: null,
|
|
606
733
|
cancel_requested: false
|
|
607
734
|
};
|
|
608
|
-
}
|
|
609
|
-
return control;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
function
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
735
|
+
}
|
|
736
|
+
return control;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
function cancelErrorFromShutdown(shutdownError = null) {
|
|
740
|
+
return {
|
|
741
|
+
code: "PIPELINE_CANCELED",
|
|
742
|
+
message: "流水线已取消。",
|
|
743
|
+
retryable: true,
|
|
744
|
+
shutdown_error: shutdownError || undefined
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function coerceCanceledTerminalSnapshot(normalized, existing) {
|
|
749
|
+
const existingControl = plainRecord(existing?.control);
|
|
750
|
+
const shutdownError = normalized?.error || normalized?.result?.error || null;
|
|
751
|
+
const shouldWrapCanceledShutdown = (
|
|
752
|
+
normalized
|
|
753
|
+
&& (
|
|
754
|
+
(
|
|
755
|
+
normalized.state === RUN_STATUS_FAILED
|
|
756
|
+
&& existingControl.cancel_requested === true
|
|
757
|
+
)
|
|
758
|
+
|| normalized.state === RUN_STATUS_CANCELED
|
|
759
|
+
)
|
|
760
|
+
&& isCancelShutdownError(shutdownError || "")
|
|
761
|
+
);
|
|
762
|
+
if (
|
|
763
|
+
!shouldWrapCanceledShutdown
|
|
764
|
+
) {
|
|
765
|
+
return normalized;
|
|
766
|
+
}
|
|
767
|
+
const canceledError = cancelErrorFromShutdown(shutdownError);
|
|
768
|
+
return {
|
|
769
|
+
...normalized,
|
|
770
|
+
state: RUN_STATUS_CANCELED,
|
|
771
|
+
status: RUN_STATUS_CANCELED,
|
|
772
|
+
last_message: "流水线已取消;取消收尾时浏览器连接已关闭。",
|
|
773
|
+
control: {
|
|
774
|
+
pause_requested: false,
|
|
775
|
+
pause_requested_at: null,
|
|
776
|
+
pause_requested_by: null,
|
|
777
|
+
cancel_requested: false
|
|
778
|
+
},
|
|
779
|
+
error: canceledError,
|
|
780
|
+
result: normalized.result ? {
|
|
781
|
+
...normalized.result,
|
|
782
|
+
status: "CANCELED",
|
|
783
|
+
completion_reason: "canceled_by_user",
|
|
784
|
+
error: canceledError
|
|
785
|
+
} : {
|
|
786
|
+
status: "CANCELED",
|
|
787
|
+
completion_reason: "canceled_by_user",
|
|
788
|
+
error: canceledError,
|
|
789
|
+
run_id: normalized.run_id,
|
|
790
|
+
processed_count: normalized.progress?.processed || 0,
|
|
791
|
+
screened_count: normalized.progress?.screened || normalized.progress?.processed || 0,
|
|
792
|
+
passed_count: normalized.progress?.passed || 0
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
function persistRecommendRunSnapshot(snapshot, {
|
|
798
|
+
persistActiveCheckpoint = false
|
|
799
|
+
} = {}) {
|
|
800
|
+
let normalized = normalizeRunSnapshot(snapshot);
|
|
801
|
+
if (!normalized?.run_id) return normalized;
|
|
802
|
+
const artifacts = getRecommendRunArtifacts(normalized.run_id);
|
|
803
|
+
if (!artifacts) return normalized;
|
|
804
|
+
const existing = readJsonFile(artifacts.run_state_path);
|
|
805
|
+
normalized.control = mergePersistedControlRequest(normalized, existing);
|
|
806
|
+
normalized = coerceCanceledTerminalSnapshot(normalized, existing);
|
|
807
|
+
if (persistActiveCheckpoint) {
|
|
808
|
+
persistRecommendCheckpointSnapshot(normalized);
|
|
809
|
+
}
|
|
624
810
|
const payload = {
|
|
625
811
|
run_id: normalized.run_id,
|
|
626
812
|
mode: normalized.mode,
|
|
@@ -643,29 +829,59 @@ function persistRecommendRunSnapshot(snapshot, {
|
|
|
643
829
|
summary: normalized.summary,
|
|
644
830
|
artifacts: normalized.artifacts
|
|
645
831
|
};
|
|
646
|
-
writeJsonAtomic(artifacts.run_state_path, payload);
|
|
647
|
-
return normalized;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
function
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
832
|
+
writeJsonAtomic(artifacts.run_state_path, payload);
|
|
833
|
+
return normalized;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function patchPersistedRecommendRunControl(runId, controlPatch = {}, {
|
|
837
|
+
message = ""
|
|
838
|
+
} = {}) {
|
|
839
|
+
const artifacts = getRecommendRunArtifacts(runId);
|
|
840
|
+
if (!artifacts) return null;
|
|
841
|
+
const current = readJsonFile(artifacts.run_state_path);
|
|
842
|
+
const state = normalizeText(current?.state || current?.status || "");
|
|
843
|
+
if (!current || TERMINAL_STATUSES.has(state)) return null;
|
|
844
|
+
const now = new Date().toISOString();
|
|
845
|
+
const patched = {
|
|
846
|
+
...current,
|
|
847
|
+
updated_at: now,
|
|
848
|
+
heartbeat_at: current.heartbeat_at || now,
|
|
849
|
+
last_message: message || current.last_message || "",
|
|
850
|
+
control: {
|
|
851
|
+
...(current.control || {}),
|
|
852
|
+
...controlPatch
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
writeJsonAtomic(artifacts.run_state_path, patched);
|
|
856
|
+
return patched;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
function reconcilePersistedRecommendRunIfNeeded(persisted) {
|
|
860
|
+
if (!persisted || typeof persisted !== "object") return persisted;
|
|
861
|
+
const persistedState = normalizeText(persisted.state || persisted.status);
|
|
862
|
+
if (TERMINAL_STATUSES.has(persistedState)) return persisted;
|
|
654
863
|
if (isProcessAlive(persisted.pid)) return persisted;
|
|
655
864
|
|
|
656
|
-
const runId = normalizeRunId(persisted.run_id || persisted.runId);
|
|
657
|
-
const artifacts = getRecommendRunArtifacts(runId);
|
|
658
|
-
const checkpoint = artifacts?.checkpoint_path ? readJsonFile(artifacts.checkpoint_path) : null;
|
|
659
|
-
const now = new Date().toISOString();
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
865
|
+
const runId = normalizeRunId(persisted.run_id || persisted.runId);
|
|
866
|
+
const artifacts = getRecommendRunArtifacts(runId);
|
|
867
|
+
const checkpoint = artifacts?.checkpoint_path ? readJsonFile(artifacts.checkpoint_path) : null;
|
|
868
|
+
const now = new Date().toISOString();
|
|
869
|
+
const cancelRequested = persisted.control?.cancel_requested === true;
|
|
870
|
+
const processExitedError = {
|
|
871
|
+
code: "RUN_PROCESS_EXITED",
|
|
872
|
+
message: `检测到推荐任务进程已退出(pid=${persisted.pid || "unknown"})。`,
|
|
873
|
+
retryable: true
|
|
874
|
+
};
|
|
875
|
+
const error = cancelRequested
|
|
876
|
+
? cancelErrorFromShutdown(processExitedError)
|
|
877
|
+
: {
|
|
878
|
+
...processExitedError,
|
|
879
|
+
message: `检测到推荐任务进程已退出(pid=${persisted.pid || "unknown"}),已自动标记为失败。`
|
|
880
|
+
};
|
|
881
|
+
return persistRecommendRunSnapshot({
|
|
666
882
|
runId,
|
|
667
883
|
name: persisted.name || runId,
|
|
668
|
-
status: RUN_STATUS_FAILED,
|
|
884
|
+
status: cancelRequested ? RUN_STATUS_CANCELED : RUN_STATUS_FAILED,
|
|
669
885
|
phase: persisted.stage || persisted.phase || "recommend:orphaned",
|
|
670
886
|
progress: persisted.progress || {},
|
|
671
887
|
context: persisted.context || {},
|
|
@@ -745,9 +961,17 @@ async function readRecommendJobOptionsFromSession(session) {
|
|
|
745
961
|
};
|
|
746
962
|
}
|
|
747
963
|
|
|
748
|
-
export async function listRecommendJobsTool({ workspaceRoot = "", args = {} } = {}) {
|
|
749
|
-
const
|
|
750
|
-
|
|
964
|
+
export async function listRecommendJobsTool({ workspaceRoot = "", args = {} } = {}) {
|
|
965
|
+
const routeGuard = guardRecommendRoute(args);
|
|
966
|
+
if (routeGuard) {
|
|
967
|
+
return {
|
|
968
|
+
...routeGuard,
|
|
969
|
+
stage: "recommend_job_list",
|
|
970
|
+
message: "list_recommend_jobs is recommend-page only. For chat-only job lists, call list_boss_chat_jobs or prepare_boss_chat_run."
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
const configResolution = resolveBossScreeningConfig(workspaceRoot);
|
|
974
|
+
const host = normalizeText(args.host) || DEFAULT_RECOMMEND_HOST;
|
|
751
975
|
const port = parsePositiveInteger(
|
|
752
976
|
args.port,
|
|
753
977
|
configResolution.ok ? configResolution.config.debugPort : DEFAULT_RECOMMEND_PORT
|
|
@@ -1367,8 +1591,10 @@ function getRunOptions(args, parsed, normalized, session, configResolution = nul
|
|
|
1367
1591
|
};
|
|
1368
1592
|
}
|
|
1369
1593
|
|
|
1370
|
-
function prepareRecommendPipelineStart(args = {}, { workspaceRoot = "" } = {}) {
|
|
1371
|
-
const
|
|
1594
|
+
function prepareRecommendPipelineStart(args = {}, { workspaceRoot = "" } = {}) {
|
|
1595
|
+
const routeGuard = guardRecommendRoute(args);
|
|
1596
|
+
if (routeGuard) return { response: routeGuard };
|
|
1597
|
+
const parsed = parseRecommendPipelineRequest(args);
|
|
1372
1598
|
const gate = evaluateRecommendPipelineGate(parsed, args);
|
|
1373
1599
|
if (gate) return { response: gate };
|
|
1374
1600
|
const configResolution = resolveBossScreeningConfig(workspaceRoot);
|
|
@@ -1813,20 +2039,45 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
1813
2039
|
}, runId);
|
|
1814
2040
|
} catch {
|
|
1815
2041
|
const persisted = readRecommendRunState(runId);
|
|
1816
|
-
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
1817
|
-
return {
|
|
1818
|
-
status: "CANCEL_IGNORED",
|
|
1819
|
-
run: persisted,
|
|
1820
|
-
message: "目标任务已结束,无需取消。",
|
|
2042
|
+
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2043
|
+
return {
|
|
2044
|
+
status: "CANCEL_IGNORED",
|
|
2045
|
+
run: persisted,
|
|
2046
|
+
message: "目标任务已结束,无需取消。",
|
|
1821
2047
|
runtime_evaluate_used: false,
|
|
1822
2048
|
method_summary: {},
|
|
1823
2049
|
method_log: [],
|
|
1824
|
-
chrome: null
|
|
1825
|
-
};
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
2050
|
+
chrome: null
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
const cancelMessage = "已收到取消请求,将由 detached worker 在下一个安全边界停止。";
|
|
2054
|
+
const patched = patchPersistedRecommendRunControl(runId, {
|
|
2055
|
+
pause_requested: true,
|
|
2056
|
+
pause_requested_at: new Date().toISOString(),
|
|
2057
|
+
pause_requested_by: "cancel_recommend_pipeline_run",
|
|
2058
|
+
cancel_requested: true
|
|
2059
|
+
}, {
|
|
2060
|
+
message: cancelMessage
|
|
2061
|
+
});
|
|
2062
|
+
if (patched) {
|
|
2063
|
+
return {
|
|
2064
|
+
status: "CANCEL_REQUESTED",
|
|
2065
|
+
run: patched,
|
|
2066
|
+
message: cancelMessage,
|
|
2067
|
+
persistence: {
|
|
2068
|
+
source: "disk",
|
|
2069
|
+
active_control_available: false,
|
|
2070
|
+
detached_control_requested: true
|
|
2071
|
+
},
|
|
2072
|
+
runtime_evaluate_used: false,
|
|
2073
|
+
method_summary: {},
|
|
2074
|
+
method_log: [],
|
|
2075
|
+
chrome: null
|
|
2076
|
+
};
|
|
2077
|
+
}
|
|
2078
|
+
return getRecommendPipelineRunTool({ args });
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
1830
2081
|
|
|
1831
2082
|
export function getRecommendMcpHealthSnapshot(runId) {
|
|
1832
2083
|
const meta = getRecommendRunMeta(runId);
|