@reconcrap/boss-recommend-mcp 1.2.10 → 1.3.1
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 +82 -1
- package/package.json +2 -1
- package/skills/boss-chat/README.md +5 -0
- package/skills/boss-chat/SKILL.md +69 -0
- package/skills/boss-recommend-pipeline/SKILL.md +40 -4
- package/src/adapters.js +19 -5
- package/src/boss-chat.js +436 -0
- package/src/cli.js +294 -129
- package/src/index.js +459 -108
- package/src/pipeline.js +605 -8
- package/src/run-state.js +5 -0
- package/src/test-adapters-runtime.js +69 -0
- package/src/test-boss-chat.js +399 -0
- package/src/test-index-async.js +238 -4
- package/src/test-pipeline.js +408 -1
- package/vendor/boss-chat-cli/README.md +134 -0
- package/vendor/boss-chat-cli/package.json +53 -0
- package/vendor/boss-chat-cli/src/app.js +783 -0
- package/vendor/boss-chat-cli/src/browser/chat-page.js +2698 -0
- package/vendor/boss-chat-cli/src/cli.js +1350 -0
- package/vendor/boss-chat-cli/src/mcp/server.js +149 -0
- package/vendor/boss-chat-cli/src/mcp/tool-runtime.js +193 -0
- package/vendor/boss-chat-cli/src/runtime/async-run-state.js +260 -0
- package/vendor/boss-chat-cli/src/runtime/interaction.js +102 -0
- package/vendor/boss-chat-cli/src/runtime/run-control.js +102 -0
- package/vendor/boss-chat-cli/src/services/chrome-client.js +97 -0
- package/vendor/boss-chat-cli/src/services/llm.js +352 -0
- package/vendor/boss-chat-cli/src/services/profile-store.js +157 -0
- package/vendor/boss-chat-cli/src/services/report-store.js +19 -0
- package/vendor/boss-chat-cli/src/services/resume-capture.js +554 -0
- package/vendor/boss-chat-cli/src/services/state-store.js +217 -0
- package/vendor/boss-chat-cli/src/utils/customer-key.js +82 -0
- package/vendor/boss-recommend-screen-cli/boss-recommend-screen-cli.cjs +902 -56
- package/vendor/boss-recommend-screen-cli/test-recoverable-resume-failures.cjs +387 -1
package/src/index.js
CHANGED
|
@@ -8,11 +8,20 @@ import {
|
|
|
8
8
|
getFeaturedCalibrationResolution,
|
|
9
9
|
runRecommendCalibration
|
|
10
10
|
} from "./adapters.js";
|
|
11
|
+
import {
|
|
12
|
+
cancelBossChatRun,
|
|
13
|
+
getBossChatHealthCheck,
|
|
14
|
+
getBossChatRun,
|
|
15
|
+
pauseBossChatRun,
|
|
16
|
+
resumeBossChatRun,
|
|
17
|
+
startBossChatRun
|
|
18
|
+
} from "./boss-chat.js";
|
|
11
19
|
import { runRecommendPipeline } from "./pipeline.js";
|
|
12
20
|
import { runRecommendSelfHeal } from "./self-heal.js";
|
|
13
|
-
import {
|
|
14
|
-
RUN_MODE_ASYNC,
|
|
15
|
-
|
|
21
|
+
import {
|
|
22
|
+
RUN_MODE_ASYNC,
|
|
23
|
+
RUN_STAGE_CHAT_FOLLOWUP,
|
|
24
|
+
RUN_STAGE_PREFLIGHT,
|
|
16
25
|
RUN_STATE_CANCELED,
|
|
17
26
|
RUN_STATE_COMPLETED,
|
|
18
27
|
RUN_STATE_FAILED,
|
|
@@ -41,6 +50,12 @@ const TOOL_RESUME_RUN = "resume_recommend_pipeline_run";
|
|
|
41
50
|
const TOOL_RUN_FEATURED_CALIBRATION = "run_featured_calibration";
|
|
42
51
|
const TOOL_GET_FEATURED_CALIBRATION_STATUS = "get_featured_calibration_status";
|
|
43
52
|
const TOOL_RUN_RECOMMEND_SELF_HEAL = "run_recommend_self_heal";
|
|
53
|
+
const TOOL_BOSS_CHAT_HEALTH_CHECK = "boss_chat_health_check";
|
|
54
|
+
const TOOL_BOSS_CHAT_START_RUN = "start_boss_chat_run";
|
|
55
|
+
const TOOL_BOSS_CHAT_GET_RUN = "get_boss_chat_run";
|
|
56
|
+
const TOOL_BOSS_CHAT_PAUSE_RUN = "pause_boss_chat_run";
|
|
57
|
+
const TOOL_BOSS_CHAT_RESUME_RUN = "resume_boss_chat_run";
|
|
58
|
+
const TOOL_BOSS_CHAT_CANCEL_RUN = "cancel_boss_chat_run";
|
|
44
59
|
|
|
45
60
|
const SERVER_NAME = "boss-recommend-mcp";
|
|
46
61
|
const FRAMING_UNKNOWN = "unknown";
|
|
@@ -64,10 +79,41 @@ function parsePositiveInteger(raw, fallback) {
|
|
|
64
79
|
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
65
80
|
}
|
|
66
81
|
|
|
67
|
-
function getDefaultPollAfterSec() {
|
|
68
|
-
const fromEnv = parsePositiveInteger(process.env.BOSS_RECOMMEND_POLL_AFTER_SEC,
|
|
69
|
-
return Math.max(
|
|
70
|
-
}
|
|
82
|
+
function getDefaultPollAfterSec() {
|
|
83
|
+
const fromEnv = parsePositiveInteger(process.env.BOSS_RECOMMEND_POLL_AFTER_SEC, 1800);
|
|
84
|
+
return Math.max(60, fromEnv);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getLongRunPollAfterSec() {
|
|
88
|
+
const fromEnv = parsePositiveInteger(process.env.BOSS_RECOMMEND_LONG_POLL_AFTER_SEC, 1800);
|
|
89
|
+
return Math.max(60, fromEnv);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getRecommendedPollAfterSec(args = {}) {
|
|
93
|
+
return hasFollowUpChatRequest(args)
|
|
94
|
+
? getLongRunPollAfterSec()
|
|
95
|
+
: getDefaultPollAfterSec();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function hasFollowUpChatRequest(args = {}) {
|
|
99
|
+
const directChat = args?.follow_up?.chat && typeof args.follow_up.chat === "object"
|
|
100
|
+
? args.follow_up.chat
|
|
101
|
+
: null;
|
|
102
|
+
const overrideChat = args?.overrides?.follow_up?.chat && typeof args.overrides.follow_up.chat === "object"
|
|
103
|
+
? args.overrides.follow_up.chat
|
|
104
|
+
: null;
|
|
105
|
+
return Boolean(directChat || overrideChat);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getDefaultAcceptedMessage(args = {}) {
|
|
109
|
+
if (hasFollowUpChatRequest(args)) {
|
|
110
|
+
return "异步流水线已启动(detached)。recommend+chat 联动任务可能耗时较长,默认建议至少每 30 分钟查询一次 get_recommend_pipeline_run;若手动查询时已完成,将立即进入聊天衔接。";
|
|
111
|
+
}
|
|
112
|
+
const fromEnv = parsePositiveInteger(process.env.BOSS_RECOMMEND_POLL_AFTER_SEC, 1800);
|
|
113
|
+
const recommendedSeconds = Math.max(60, fromEnv);
|
|
114
|
+
const recommendedMinutes = Math.max(1, Math.round(recommendedSeconds / 60));
|
|
115
|
+
return `异步流水线已启动(detached)。默认不自动轮询;如需进度请按需调用 get_recommend_pipeline_run(建议至少每 ${recommendedMinutes} 分钟查询一次)。`;
|
|
116
|
+
}
|
|
71
117
|
|
|
72
118
|
function getRunArtifacts(runId) {
|
|
73
119
|
const normalizedRunId = normalizeText(runId);
|
|
@@ -77,14 +123,15 @@ function getRunArtifacts(runId) {
|
|
|
77
123
|
};
|
|
78
124
|
}
|
|
79
125
|
|
|
80
|
-
function buildRunContext(workspaceRoot, args = {}) {
|
|
81
|
-
return {
|
|
82
|
-
workspace_root: path.resolve(workspaceRoot),
|
|
83
|
-
instruction: String(args?.instruction || ""),
|
|
84
|
-
confirmation: args?.confirmation && typeof args.confirmation === "object" ? args.confirmation : {},
|
|
85
|
-
overrides: args?.overrides && typeof args.overrides === "object" ? args.overrides : {}
|
|
86
|
-
|
|
87
|
-
}
|
|
126
|
+
function buildRunContext(workspaceRoot, args = {}) {
|
|
127
|
+
return {
|
|
128
|
+
workspace_root: path.resolve(workspaceRoot),
|
|
129
|
+
instruction: String(args?.instruction || ""),
|
|
130
|
+
confirmation: args?.confirmation && typeof args.confirmation === "object" ? args.confirmation : {},
|
|
131
|
+
overrides: args?.overrides && typeof args.overrides === "object" ? args.overrides : {},
|
|
132
|
+
follow_up: args?.follow_up && typeof args.follow_up === "object" ? args.follow_up : null
|
|
133
|
+
};
|
|
134
|
+
}
|
|
88
135
|
|
|
89
136
|
function resolveRunContext(snapshot) {
|
|
90
137
|
const workspaceRoot = normalizeText(snapshot?.context?.workspace_root || "");
|
|
@@ -95,16 +142,19 @@ function resolveRunContext(snapshot) {
|
|
|
95
142
|
return {
|
|
96
143
|
workspaceRoot,
|
|
97
144
|
args: {
|
|
98
|
-
instruction,
|
|
99
|
-
confirmation: snapshot?.context?.confirmation && typeof snapshot.context.confirmation === "object"
|
|
100
|
-
? snapshot.context.confirmation
|
|
101
|
-
: {},
|
|
102
|
-
overrides: snapshot?.context?.overrides && typeof snapshot.context.overrides === "object"
|
|
103
|
-
? snapshot.context.overrides
|
|
104
|
-
: {}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
145
|
+
instruction,
|
|
146
|
+
confirmation: snapshot?.context?.confirmation && typeof snapshot.context.confirmation === "object"
|
|
147
|
+
? snapshot.context.confirmation
|
|
148
|
+
: {},
|
|
149
|
+
overrides: snapshot?.context?.overrides && typeof snapshot.context.overrides === "object"
|
|
150
|
+
? snapshot.context.overrides
|
|
151
|
+
: {},
|
|
152
|
+
follow_up: snapshot?.context?.follow_up && typeof snapshot.context.follow_up === "object"
|
|
153
|
+
? snapshot.context.follow_up
|
|
154
|
+
: null
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
108
158
|
|
|
109
159
|
function isRunPauseRequested(runId) {
|
|
110
160
|
const snapshot = readRunState(runId);
|
|
@@ -292,13 +342,79 @@ function createRunInputSchema() {
|
|
|
292
342
|
type: "string",
|
|
293
343
|
enum: ["favorite", "greet", "none"]
|
|
294
344
|
}
|
|
295
|
-
},
|
|
296
|
-
additionalProperties: false
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
345
|
+
},
|
|
346
|
+
additionalProperties: false
|
|
347
|
+
},
|
|
348
|
+
follow_up: {
|
|
349
|
+
type: "object",
|
|
350
|
+
properties: {
|
|
351
|
+
chat: {
|
|
352
|
+
type: "object",
|
|
353
|
+
properties: {
|
|
354
|
+
profile: { type: "string" },
|
|
355
|
+
criteria: { type: "string" },
|
|
356
|
+
start_from: {
|
|
357
|
+
type: "string",
|
|
358
|
+
enum: ["unread", "all"]
|
|
359
|
+
},
|
|
360
|
+
target_count: {
|
|
361
|
+
type: "integer",
|
|
362
|
+
minimum: 1
|
|
363
|
+
},
|
|
364
|
+
dry_run: { type: "boolean" },
|
|
365
|
+
no_state: { type: "boolean" },
|
|
366
|
+
safe_pacing: { type: "boolean" },
|
|
367
|
+
batch_rest_enabled: { type: "boolean" }
|
|
368
|
+
},
|
|
369
|
+
additionalProperties: false
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
additionalProperties: false
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
required: ["instruction"],
|
|
376
|
+
additionalProperties: false
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function createBossChatStartInputSchema() {
|
|
381
|
+
return {
|
|
382
|
+
type: "object",
|
|
383
|
+
properties: {
|
|
384
|
+
profile: {
|
|
385
|
+
type: "string",
|
|
386
|
+
description: "可选,boss-chat profile 名称,默认 default"
|
|
387
|
+
},
|
|
388
|
+
job: {
|
|
389
|
+
type: "string",
|
|
390
|
+
description: "岗位,支持岗位名/编号/value"
|
|
391
|
+
},
|
|
392
|
+
start_from: {
|
|
393
|
+
type: "string",
|
|
394
|
+
enum: ["unread", "all"],
|
|
395
|
+
description: "从未读或全部聊天列表开始"
|
|
396
|
+
},
|
|
397
|
+
criteria: {
|
|
398
|
+
type: "string",
|
|
399
|
+
description: "boss-chat 的筛选 criteria"
|
|
400
|
+
},
|
|
401
|
+
target_count: {
|
|
402
|
+
type: "integer",
|
|
403
|
+
minimum: 1,
|
|
404
|
+
description: "本次处理人数上限;chat-only 模式必填(可先不传,服务会返回 NEED_INPUT 引导补齐)"
|
|
405
|
+
},
|
|
406
|
+
port: {
|
|
407
|
+
type: "integer",
|
|
408
|
+
minimum: 1,
|
|
409
|
+
description: "可选,覆盖 Chrome 调试端口;未传时读取 screening-config.json.debugPort"
|
|
410
|
+
},
|
|
411
|
+
dry_run: { type: "boolean" },
|
|
412
|
+
no_state: { type: "boolean" },
|
|
413
|
+
safe_pacing: { type: "boolean" },
|
|
414
|
+
batch_rest_enabled: { type: "boolean" }
|
|
415
|
+
},
|
|
416
|
+
additionalProperties: false
|
|
417
|
+
};
|
|
302
418
|
}
|
|
303
419
|
|
|
304
420
|
function createRunFeaturedCalibrationInputSchema() {
|
|
@@ -434,6 +550,77 @@ function createToolsSchema() {
|
|
|
434
550
|
name: TOOL_RUN_RECOMMEND_SELF_HEAL,
|
|
435
551
|
description: "手动运维自愈工具:扫描 Boss recommend 相关 selector / network 规则漂移,并在确认后应用高置信度修复。",
|
|
436
552
|
inputSchema: createRunRecommendSelfHealInputSchema()
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
name: TOOL_BOSS_CHAT_HEALTH_CHECK,
|
|
556
|
+
description: "检查内置 boss-chat 运行时与共享 screening-config.json 是否可用。",
|
|
557
|
+
inputSchema: {
|
|
558
|
+
type: "object",
|
|
559
|
+
properties: {
|
|
560
|
+
port: {
|
|
561
|
+
type: "integer",
|
|
562
|
+
minimum: 1
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
additionalProperties: false
|
|
566
|
+
}
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
name: TOOL_BOSS_CHAT_START_RUN,
|
|
570
|
+
description: "异步启动一次 boss-chat 任务。若缺少必填参数会先返回 NEED_INPUT(含岗位列表与待确认字段)。",
|
|
571
|
+
inputSchema: createBossChatStartInputSchema()
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
name: TOOL_BOSS_CHAT_GET_RUN,
|
|
575
|
+
description: "查询 boss-chat run_id 的当前状态。",
|
|
576
|
+
inputSchema: {
|
|
577
|
+
type: "object",
|
|
578
|
+
properties: {
|
|
579
|
+
run_id: { type: "string" },
|
|
580
|
+
profile: { type: "string" }
|
|
581
|
+
},
|
|
582
|
+
required: ["run_id"],
|
|
583
|
+
additionalProperties: false
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
name: TOOL_BOSS_CHAT_PAUSE_RUN,
|
|
588
|
+
description: "暂停运行中的 boss-chat 任务。",
|
|
589
|
+
inputSchema: {
|
|
590
|
+
type: "object",
|
|
591
|
+
properties: {
|
|
592
|
+
run_id: { type: "string" },
|
|
593
|
+
profile: { type: "string" }
|
|
594
|
+
},
|
|
595
|
+
required: ["run_id"],
|
|
596
|
+
additionalProperties: false
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
name: TOOL_BOSS_CHAT_RESUME_RUN,
|
|
601
|
+
description: "继续已暂停的 boss-chat 任务。",
|
|
602
|
+
inputSchema: {
|
|
603
|
+
type: "object",
|
|
604
|
+
properties: {
|
|
605
|
+
run_id: { type: "string" },
|
|
606
|
+
profile: { type: "string" }
|
|
607
|
+
},
|
|
608
|
+
required: ["run_id"],
|
|
609
|
+
additionalProperties: false
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
name: TOOL_BOSS_CHAT_CANCEL_RUN,
|
|
614
|
+
description: "取消运行中的 boss-chat 任务。",
|
|
615
|
+
inputSchema: {
|
|
616
|
+
type: "object",
|
|
617
|
+
properties: {
|
|
618
|
+
run_id: { type: "string" },
|
|
619
|
+
profile: { type: "string" }
|
|
620
|
+
},
|
|
621
|
+
required: ["run_id"],
|
|
622
|
+
additionalProperties: false
|
|
623
|
+
}
|
|
437
624
|
}
|
|
438
625
|
];
|
|
439
626
|
}
|
|
@@ -456,13 +643,48 @@ function createToolResultResponse(id, payload, isError = false) {
|
|
|
456
643
|
}
|
|
457
644
|
|
|
458
645
|
function validateRunArgs(args) {
|
|
459
|
-
if (!args || typeof args !== "object") {
|
|
460
|
-
return "arguments must be an object";
|
|
461
|
-
}
|
|
462
|
-
if (!args.instruction || typeof args.instruction !== "string") {
|
|
646
|
+
if (!args || typeof args !== "object") {
|
|
647
|
+
return "arguments must be an object";
|
|
648
|
+
}
|
|
649
|
+
if (!args.instruction || typeof args.instruction !== "string") {
|
|
463
650
|
return "instruction is required and must be a string";
|
|
464
|
-
}
|
|
465
|
-
return null;
|
|
651
|
+
}
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function validateBossChatStartArgs(args) {
|
|
656
|
+
if (!args || typeof args !== "object" || Array.isArray(args)) {
|
|
657
|
+
return "arguments must be an object";
|
|
658
|
+
}
|
|
659
|
+
if (Object.prototype.hasOwnProperty.call(args, "job")) {
|
|
660
|
+
if (typeof args.job !== "string" || !normalizeText(args.job)) {
|
|
661
|
+
return "job must be a non-empty string when provided";
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (Object.prototype.hasOwnProperty.call(args, "start_from")) {
|
|
665
|
+
const startFrom = normalizeText(args.start_from).toLowerCase();
|
|
666
|
+
if (!["unread", "all"].includes(startFrom)) {
|
|
667
|
+
return "start_from must be one of: unread, all";
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if (Object.prototype.hasOwnProperty.call(args, "criteria")) {
|
|
671
|
+
if (typeof args.criteria !== "string" || !normalizeText(args.criteria)) {
|
|
672
|
+
return "criteria must be a non-empty string when provided";
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (Object.prototype.hasOwnProperty.call(args, "target_count")) {
|
|
676
|
+
const targetCount = Number.parseInt(String(args.target_count), 10);
|
|
677
|
+
if (!Number.isFinite(targetCount) || targetCount <= 0) {
|
|
678
|
+
return "target_count must be a positive integer";
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (Object.prototype.hasOwnProperty.call(args, "port")) {
|
|
682
|
+
const port = Number.parseInt(String(args.port), 10);
|
|
683
|
+
if (!Number.isFinite(port) || port <= 0) {
|
|
684
|
+
return "port must be a positive integer";
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return null;
|
|
466
688
|
}
|
|
467
689
|
|
|
468
690
|
function validateRunFeaturedCalibrationArgs(args) {
|
|
@@ -560,13 +782,14 @@ function buildAsyncPrecheckConfirmation(confirmation) {
|
|
|
560
782
|
};
|
|
561
783
|
}
|
|
562
784
|
|
|
563
|
-
function buildAsyncPrecheckArgs(args) {
|
|
564
|
-
return {
|
|
565
|
-
instruction: args.instruction,
|
|
566
|
-
confirmation: buildAsyncPrecheckConfirmation(args.confirmation),
|
|
567
|
-
overrides: args.overrides
|
|
568
|
-
|
|
569
|
-
}
|
|
785
|
+
function buildAsyncPrecheckArgs(args) {
|
|
786
|
+
return {
|
|
787
|
+
instruction: args.instruction,
|
|
788
|
+
confirmation: buildAsyncPrecheckConfirmation(args.confirmation),
|
|
789
|
+
overrides: args.overrides,
|
|
790
|
+
follow_up: args.follow_up
|
|
791
|
+
};
|
|
792
|
+
}
|
|
570
793
|
|
|
571
794
|
function isFinalReviewOnlyConfirmation(result) {
|
|
572
795
|
if (result?.status !== "NEED_CONFIRMATION") return false;
|
|
@@ -619,6 +842,46 @@ function readCheckpointProgress(checkpointPath) {
|
|
|
619
842
|
}
|
|
620
843
|
}
|
|
621
844
|
|
|
845
|
+
function getBossChatRunIdFromSnapshot(snapshot) {
|
|
846
|
+
return normalizeText(
|
|
847
|
+
snapshot?.resume?.chat_run_id
|
|
848
|
+
|| snapshot?.result?.follow_up?.chat?.run_id
|
|
849
|
+
|| ""
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function mergeFollowUpResult(currentResult, event = {}) {
|
|
854
|
+
const currentBase = currentResult && typeof currentResult === "object" ? currentResult : {};
|
|
855
|
+
const recommendPayload = event?.recommend_payload && typeof event.recommend_payload === "object"
|
|
856
|
+
? event.recommend_payload
|
|
857
|
+
: null;
|
|
858
|
+
const baseResult = recommendPayload
|
|
859
|
+
? {
|
|
860
|
+
...currentBase,
|
|
861
|
+
...recommendPayload
|
|
862
|
+
}
|
|
863
|
+
: { ...currentBase };
|
|
864
|
+
const followUp = event?.follow_up && typeof event.follow_up === "object" ? event.follow_up : {};
|
|
865
|
+
const currentFollowUp = baseResult.follow_up && typeof baseResult.follow_up === "object"
|
|
866
|
+
? baseResult.follow_up
|
|
867
|
+
: {};
|
|
868
|
+
const nextChat = followUp.chat && typeof followUp.chat === "object"
|
|
869
|
+
? {
|
|
870
|
+
...(currentFollowUp.chat && typeof currentFollowUp.chat === "object" ? currentFollowUp.chat : {}),
|
|
871
|
+
...followUp.chat
|
|
872
|
+
}
|
|
873
|
+
: currentFollowUp.chat;
|
|
874
|
+
return {
|
|
875
|
+
...baseResult,
|
|
876
|
+
...(event?.recommend_result ? { result: event.recommend_result } : {}),
|
|
877
|
+
follow_up: {
|
|
878
|
+
...currentFollowUp,
|
|
879
|
+
...followUp,
|
|
880
|
+
...(nextChat ? { chat: nextChat } : {})
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
|
|
622
885
|
function reconcileOrphanRunIfNeeded(runId, snapshot) {
|
|
623
886
|
if (!snapshot || TERMINAL_RUN_STATES.has(snapshot.state)) {
|
|
624
887
|
return snapshot;
|
|
@@ -730,10 +993,10 @@ function finalizeCanceledRun(runId, snapshot) {
|
|
|
730
993
|
}) || readRunState(runId) || snapshot;
|
|
731
994
|
}
|
|
732
995
|
|
|
733
|
-
function createRuntimeCallbacks(runId, heartbeatIntervalMs) {
|
|
734
|
-
let lastStage = RUN_STAGE_PREFLIGHT;
|
|
735
|
-
let lastOutputPersistAt = 0;
|
|
736
|
-
return {
|
|
996
|
+
function createRuntimeCallbacks(runId, heartbeatIntervalMs) {
|
|
997
|
+
let lastStage = RUN_STAGE_PREFLIGHT;
|
|
998
|
+
let lastOutputPersistAt = 0;
|
|
999
|
+
return {
|
|
737
1000
|
heartbeatIntervalMs,
|
|
738
1001
|
onStage(event) {
|
|
739
1002
|
const stage = normalizeText(event?.stage) || RUN_STAGE_PREFLIGHT;
|
|
@@ -772,11 +1035,11 @@ function createRuntimeCallbacks(runId, heartbeatIntervalMs) {
|
|
|
772
1035
|
last_message: message
|
|
773
1036
|
});
|
|
774
1037
|
},
|
|
775
|
-
onProgress(event) {
|
|
776
|
-
const stage = normalizeText(event?.stage) || lastStage;
|
|
777
|
-
lastStage = stage || lastStage;
|
|
778
|
-
safeUpdateRunState(runId, { stage: lastStage });
|
|
779
|
-
safeUpdateRunProgress(
|
|
1038
|
+
onProgress(event) {
|
|
1039
|
+
const stage = normalizeText(event?.stage) || lastStage;
|
|
1040
|
+
lastStage = stage || lastStage;
|
|
1041
|
+
safeUpdateRunState(runId, { stage: lastStage });
|
|
1042
|
+
safeUpdateRunProgress(
|
|
780
1043
|
runId,
|
|
781
1044
|
{
|
|
782
1045
|
processed: Number.isInteger(event?.processed) ? event.processed : undefined,
|
|
@@ -784,14 +1047,34 @@ function createRuntimeCallbacks(runId, heartbeatIntervalMs) {
|
|
|
784
1047
|
skipped: Number.isInteger(event?.skipped) ? event.skipped : undefined,
|
|
785
1048
|
greet_count: Number.isInteger(event?.greet_count) ? event.greet_count : undefined
|
|
786
1049
|
},
|
|
787
|
-
normalizeText(event?.line || "")
|
|
788
|
-
);
|
|
789
|
-
},
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1050
|
+
normalizeText(event?.line || "")
|
|
1051
|
+
);
|
|
1052
|
+
},
|
|
1053
|
+
onFollowUp(event) {
|
|
1054
|
+
const stage = normalizeText(event?.stage) || RUN_STAGE_CHAT_FOLLOWUP;
|
|
1055
|
+
lastStage = stage || lastStage;
|
|
1056
|
+
safeUpdateRunState(runId, (current) => ({
|
|
1057
|
+
state: RUN_STATE_RUNNING,
|
|
1058
|
+
stage: lastStage,
|
|
1059
|
+
last_message: normalizeText(event?.last_message || current?.last_message || ""),
|
|
1060
|
+
resume: {
|
|
1061
|
+
...current?.resume,
|
|
1062
|
+
follow_up_phase: RUN_STAGE_CHAT_FOLLOWUP,
|
|
1063
|
+
chat_run_id: normalizeText(
|
|
1064
|
+
event?.follow_up?.chat?.run_id
|
|
1065
|
+
|| getBossChatRunIdFromSnapshot(current)
|
|
1066
|
+
|| ""
|
|
1067
|
+
) || null,
|
|
1068
|
+
chat_state: normalizeText(event?.follow_up?.chat?.state || current?.resume?.chat_state || "") || null
|
|
1069
|
+
},
|
|
1070
|
+
result: mergeFollowUpResult(current?.result, event)
|
|
1071
|
+
}));
|
|
1072
|
+
},
|
|
1073
|
+
getLastStage() {
|
|
1074
|
+
return lastStage;
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
795
1078
|
|
|
796
1079
|
|
|
797
1080
|
async function executeTrackedPipeline({
|
|
@@ -806,43 +1089,56 @@ async function executeTrackedPipeline({
|
|
|
806
1089
|
const runtimeCallbacks = createRuntimeCallbacks(runId, heartbeatIntervalMs);
|
|
807
1090
|
const artifacts = getRunArtifacts(runId);
|
|
808
1091
|
const existingSnapshot = readRunState(runId);
|
|
809
|
-
const resumeConfig = {
|
|
810
|
-
resume: resumeRun === true,
|
|
811
|
-
checkpoint_path: normalizeText(existingSnapshot?.resume?.checkpoint_path || artifacts.checkpoint_path),
|
|
812
|
-
pause_control_path: normalizeText(existingSnapshot?.resume?.pause_control_path || artifacts.run_state_path),
|
|
813
|
-
output_csv: normalizeText(existingSnapshot?.resume?.output_csv || "") || null,
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
1092
|
+
const resumeConfig = {
|
|
1093
|
+
resume: resumeRun === true,
|
|
1094
|
+
checkpoint_path: normalizeText(existingSnapshot?.resume?.checkpoint_path || artifacts.checkpoint_path),
|
|
1095
|
+
pause_control_path: normalizeText(existingSnapshot?.resume?.pause_control_path || artifacts.run_state_path),
|
|
1096
|
+
output_csv: normalizeText(existingSnapshot?.resume?.output_csv || "") || null,
|
|
1097
|
+
follow_up_phase: normalizeText(existingSnapshot?.resume?.follow_up_phase || "") || null,
|
|
1098
|
+
chat_run_id: normalizeText(existingSnapshot?.resume?.chat_run_id || "") || null,
|
|
1099
|
+
chat_state: normalizeText(existingSnapshot?.resume?.chat_state || "") || null,
|
|
1100
|
+
recommend_result: existingSnapshot?.result?.result || null,
|
|
1101
|
+
recommend_search_params: existingSnapshot?.result?.search_params || null,
|
|
1102
|
+
recommend_screen_params: existingSnapshot?.result?.screen_params || null,
|
|
1103
|
+
previous_completion_reason: getCompletionReasonFromResult(existingSnapshot?.result || null)
|
|
1104
|
+
};
|
|
1105
|
+
safeUpdateRunState(runId, {
|
|
1106
|
+
state: RUN_STATE_RUNNING,
|
|
1107
|
+
stage: resumeConfig.follow_up_phase === RUN_STAGE_CHAT_FOLLOWUP ? RUN_STAGE_CHAT_FOLLOWUP : RUN_STAGE_PREFLIGHT,
|
|
1108
|
+
last_message: resumeRun
|
|
1109
|
+
? (
|
|
1110
|
+
resumeConfig.follow_up_phase === RUN_STAGE_CHAT_FOLLOWUP
|
|
1111
|
+
? "流水线继续执行中,准备恢复 boss-chat follow-up。"
|
|
1112
|
+
: "流水线继续执行中,等待 preflight。"
|
|
1113
|
+
)
|
|
1114
|
+
: "流水线已启动,等待 preflight。",
|
|
1115
|
+
resume: resumeConfig
|
|
1116
|
+
});
|
|
824
1117
|
|
|
825
1118
|
let result;
|
|
826
1119
|
try {
|
|
827
1120
|
result = await runPipelineImpl(
|
|
828
1121
|
{
|
|
829
1122
|
workspaceRoot,
|
|
830
|
-
instruction: args.instruction,
|
|
831
|
-
confirmation: args.confirmation,
|
|
832
|
-
overrides: args.overrides,
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1123
|
+
instruction: args.instruction,
|
|
1124
|
+
confirmation: args.confirmation,
|
|
1125
|
+
overrides: args.overrides,
|
|
1126
|
+
followUp: args.follow_up,
|
|
1127
|
+
resume: resumeConfig
|
|
1128
|
+
},
|
|
1129
|
+
undefined,
|
|
1130
|
+
{
|
|
1131
|
+
signal,
|
|
1132
|
+
heartbeatIntervalMs,
|
|
1133
|
+
isPauseRequested: () => isRunPauseRequested(runId),
|
|
1134
|
+
isCancelRequested: () => isRunCancelRequested(runId),
|
|
1135
|
+
onStage: runtimeCallbacks.onStage,
|
|
1136
|
+
onHeartbeat: runtimeCallbacks.onHeartbeat,
|
|
1137
|
+
onOutput: runtimeCallbacks.onOutput,
|
|
1138
|
+
onProgress: runtimeCallbacks.onProgress,
|
|
1139
|
+
onFollowUp: runtimeCallbacks.onFollowUp
|
|
1140
|
+
}
|
|
1141
|
+
);
|
|
846
1142
|
} catch (error) {
|
|
847
1143
|
const canceled = Boolean(signal?.aborted) || error?.code === "PIPELINE_ABORTED";
|
|
848
1144
|
if (canceled) {
|
|
@@ -1036,15 +1332,16 @@ async function handleStartRunTool({ workspaceRoot, args }) {
|
|
|
1036
1332
|
let precheckResult;
|
|
1037
1333
|
try {
|
|
1038
1334
|
precheckResult = await runPipelineImpl(
|
|
1039
|
-
{
|
|
1040
|
-
workspaceRoot,
|
|
1041
|
-
instruction: precheckArgs.instruction,
|
|
1042
|
-
confirmation: precheckArgs.confirmation,
|
|
1043
|
-
overrides: precheckArgs.overrides
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1335
|
+
{
|
|
1336
|
+
workspaceRoot,
|
|
1337
|
+
instruction: precheckArgs.instruction,
|
|
1338
|
+
confirmation: precheckArgs.confirmation,
|
|
1339
|
+
overrides: precheckArgs.overrides,
|
|
1340
|
+
followUp: precheckArgs.follow_up
|
|
1341
|
+
},
|
|
1342
|
+
undefined,
|
|
1343
|
+
null
|
|
1344
|
+
);
|
|
1048
1345
|
} catch (error) {
|
|
1049
1346
|
precheckResult = {
|
|
1050
1347
|
status: "FAILED",
|
|
@@ -1110,8 +1407,8 @@ async function handleStartRunTool({ workspaceRoot, args }) {
|
|
|
1110
1407
|
status: "ACCEPTED",
|
|
1111
1408
|
run_id: runId,
|
|
1112
1409
|
state: "queued",
|
|
1113
|
-
poll_after_sec:
|
|
1114
|
-
message:
|
|
1410
|
+
poll_after_sec: getRecommendedPollAfterSec(args),
|
|
1411
|
+
message: getDefaultAcceptedMessage(args)
|
|
1115
1412
|
};
|
|
1116
1413
|
}
|
|
1117
1414
|
|
|
@@ -1367,8 +1664,10 @@ function handleResumeRunTool(args) {
|
|
|
1367
1664
|
return {
|
|
1368
1665
|
status: "RESUME_REQUESTED",
|
|
1369
1666
|
run: started,
|
|
1370
|
-
poll_after_sec:
|
|
1371
|
-
message:
|
|
1667
|
+
poll_after_sec: getRecommendedPollAfterSec(executionContext?.args || {}),
|
|
1668
|
+
message: hasFollowUpChatRequest(executionContext?.args || {})
|
|
1669
|
+
? "已恢复 Recommend 流水线(detached)。recommend+chat 联动任务建议按 30 分钟间隔查询状态;手动查询到完成时会立即衔接聊天流程。"
|
|
1670
|
+
: "已恢复 Recommend 流水线(detached)。默认不自动轮询;如需进度请按需调用 get_recommend_pipeline_run。"
|
|
1372
1671
|
};
|
|
1373
1672
|
}
|
|
1374
1673
|
|
|
@@ -1425,6 +1724,30 @@ async function handleRunRecommendSelfHealTool({ workspaceRoot, args }) {
|
|
|
1425
1724
|
return runSelfHealImpl({ workspaceRoot, args });
|
|
1426
1725
|
}
|
|
1427
1726
|
|
|
1727
|
+
function handleBossChatHealthCheckTool(workspaceRoot, args) {
|
|
1728
|
+
return getBossChatHealthCheck(workspaceRoot, args);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
async function handleBossChatStartRunTool({ workspaceRoot, args }) {
|
|
1732
|
+
return startBossChatRun({ workspaceRoot, input: args });
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
async function handleBossChatGetRunTool({ workspaceRoot, args }) {
|
|
1736
|
+
return getBossChatRun({ workspaceRoot, input: args });
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
async function handleBossChatPauseRunTool({ workspaceRoot, args }) {
|
|
1740
|
+
return pauseBossChatRun({ workspaceRoot, input: args });
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
async function handleBossChatResumeRunTool({ workspaceRoot, args }) {
|
|
1744
|
+
return resumeBossChatRun({ workspaceRoot, input: args });
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
async function handleBossChatCancelRunTool({ workspaceRoot, args }) {
|
|
1748
|
+
return cancelBossChatRun({ workspaceRoot, input: args });
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1428
1751
|
async function handleRequest(message, workspaceRoot) {
|
|
1429
1752
|
if (!message || message.jsonrpc !== "2.0") {
|
|
1430
1753
|
return createJsonRpcError(null, -32600, "Invalid JSON-RPC request");
|
|
@@ -1488,11 +1811,27 @@ async function handleRequest(message, workspaceRoot) {
|
|
|
1488
1811
|
}
|
|
1489
1812
|
}
|
|
1490
1813
|
|
|
1491
|
-
if (
|
|
1814
|
+
if (toolName === TOOL_BOSS_CHAT_START_RUN) {
|
|
1815
|
+
const inputError = validateBossChatStartArgs(args);
|
|
1816
|
+
if (inputError) {
|
|
1817
|
+
return createJsonRpcError(id, -32602, inputError);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
if ([
|
|
1822
|
+
TOOL_GET_RUN,
|
|
1823
|
+
TOOL_CANCEL_RUN,
|
|
1824
|
+
TOOL_PAUSE_RUN,
|
|
1825
|
+
TOOL_RESUME_RUN,
|
|
1826
|
+
TOOL_BOSS_CHAT_GET_RUN,
|
|
1827
|
+
TOOL_BOSS_CHAT_CANCEL_RUN,
|
|
1828
|
+
TOOL_BOSS_CHAT_PAUSE_RUN,
|
|
1829
|
+
TOOL_BOSS_CHAT_RESUME_RUN
|
|
1830
|
+
].includes(toolName)) {
|
|
1492
1831
|
if (!args || typeof args.run_id !== "string" || !normalizeText(args.run_id)) {
|
|
1493
1832
|
return createJsonRpcError(id, -32602, "run_id is required and must be a string");
|
|
1494
1833
|
}
|
|
1495
|
-
}
|
|
1834
|
+
}
|
|
1496
1835
|
|
|
1497
1836
|
try {
|
|
1498
1837
|
let payload;
|
|
@@ -1512,6 +1851,18 @@ async function handleRequest(message, workspaceRoot) {
|
|
|
1512
1851
|
payload = await handleRunFeaturedCalibrationTool({ workspaceRoot, args });
|
|
1513
1852
|
} else if (toolName === TOOL_RUN_RECOMMEND_SELF_HEAL) {
|
|
1514
1853
|
payload = await handleRunRecommendSelfHealTool({ workspaceRoot, args });
|
|
1854
|
+
} else if (toolName === TOOL_BOSS_CHAT_HEALTH_CHECK) {
|
|
1855
|
+
payload = handleBossChatHealthCheckTool(workspaceRoot, args);
|
|
1856
|
+
} else if (toolName === TOOL_BOSS_CHAT_START_RUN) {
|
|
1857
|
+
payload = await handleBossChatStartRunTool({ workspaceRoot, args });
|
|
1858
|
+
} else if (toolName === TOOL_BOSS_CHAT_GET_RUN) {
|
|
1859
|
+
payload = await handleBossChatGetRunTool({ workspaceRoot, args });
|
|
1860
|
+
} else if (toolName === TOOL_BOSS_CHAT_PAUSE_RUN) {
|
|
1861
|
+
payload = await handleBossChatPauseRunTool({ workspaceRoot, args });
|
|
1862
|
+
} else if (toolName === TOOL_BOSS_CHAT_RESUME_RUN) {
|
|
1863
|
+
payload = await handleBossChatResumeRunTool({ workspaceRoot, args });
|
|
1864
|
+
} else if (toolName === TOOL_BOSS_CHAT_CANCEL_RUN) {
|
|
1865
|
+
payload = await handleBossChatCancelRunTool({ workspaceRoot, args });
|
|
1515
1866
|
} else {
|
|
1516
1867
|
return createJsonRpcError(id, -32602, `Unknown tool: ${toolName || ""}`);
|
|
1517
1868
|
}
|