weacpx 0.4.0-beta.1 → 0.4.0-beta.3
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/dist/bridge/bridge-main.js +206 -34
- package/dist/channels/types.d.ts +14 -0
- package/dist/cli.js +790 -315
- package/dist/plugin-api.d.ts +1 -1
- package/dist/weixin/agent/interface.d.ts +3 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9477,211 +9477,6 @@ function readVersion(moduleUrl = import.meta.url) {
|
|
|
9477
9477
|
var PACKAGE_NAME = "weacpx";
|
|
9478
9478
|
var init_version = () => {};
|
|
9479
9479
|
|
|
9480
|
-
// src/formatting/render-text.ts
|
|
9481
|
-
function renderAgents(config2) {
|
|
9482
|
-
const names = Object.keys(config2.agents);
|
|
9483
|
-
if (names.length === 0) {
|
|
9484
|
-
return "还没有注册任何 Agent。";
|
|
9485
|
-
}
|
|
9486
|
-
return ["已注册的 Agent:", ...names.map((name) => `- ${name}`)].join(`
|
|
9487
|
-
`);
|
|
9488
|
-
}
|
|
9489
|
-
function renderWorkspaces(config2) {
|
|
9490
|
-
const names = Object.entries(config2.workspaces);
|
|
9491
|
-
if (names.length === 0) {
|
|
9492
|
-
return "还没有注册任何工作区。";
|
|
9493
|
-
}
|
|
9494
|
-
return ["已注册的工作区:", ...names.map(([name, workspace]) => `- ${name}: ${workspace.cwd}`)].join(`
|
|
9495
|
-
`);
|
|
9496
|
-
}
|
|
9497
|
-
function renderOrchestrationUnavailable() {
|
|
9498
|
-
return "当前未启用任务编排服务。";
|
|
9499
|
-
}
|
|
9500
|
-
function renderDelegateSuccess(taskId, workerSession) {
|
|
9501
|
-
return [`已创建委派任务「${taskId}」`, `worker 会话:${workerSession}`].join(`
|
|
9502
|
-
`);
|
|
9503
|
-
}
|
|
9504
|
-
function renderGroupCreated(group) {
|
|
9505
|
-
return [`已创建任务组「${group.groupId}」`, `- 标题:${group.title}`].join(`
|
|
9506
|
-
`);
|
|
9507
|
-
}
|
|
9508
|
-
function renderGroupList(groups) {
|
|
9509
|
-
if (groups.length === 0) {
|
|
9510
|
-
return "当前协调会话下还没有任务组。";
|
|
9511
|
-
}
|
|
9512
|
-
return ["当前协调会话的任务组:", ...groups.map((group) => renderGroupListItem(group))].join(`
|
|
9513
|
-
`);
|
|
9514
|
-
}
|
|
9515
|
-
function renderGroupSummary(summary) {
|
|
9516
|
-
const { group, tasks } = summary;
|
|
9517
|
-
const lines = [
|
|
9518
|
-
`任务组「${group.groupId}」`,
|
|
9519
|
-
`- 标题:${group.title}`,
|
|
9520
|
-
`- 协调会话:${group.coordinatorSession}`,
|
|
9521
|
-
`- 总任务数:${summary.totalTasks}`,
|
|
9522
|
-
`- 待确认:${summary.pendingApprovalTasks}`,
|
|
9523
|
-
`- 运行中:${summary.runningTasks}`,
|
|
9524
|
-
`- 已完成:${summary.completedTasks}`,
|
|
9525
|
-
`- 已失败:${summary.failedTasks}`,
|
|
9526
|
-
`- 已取消:${summary.cancelledTasks}`,
|
|
9527
|
-
`- 是否终态:${summary.terminal ? "是" : "否"}`
|
|
9528
|
-
];
|
|
9529
|
-
if (group.injectionPending !== undefined) {
|
|
9530
|
-
lines.push(`- 注入待处理:${group.injectionPending ? "是" : "否"}`);
|
|
9531
|
-
}
|
|
9532
|
-
if (group.injectionAppliedAt) {
|
|
9533
|
-
lines.push(`- 注入完成时间:${group.injectionAppliedAt}`);
|
|
9534
|
-
}
|
|
9535
|
-
if (group.lastInjectionError) {
|
|
9536
|
-
lines.push(`- 最近注入错误:${group.lastInjectionError}`);
|
|
9537
|
-
}
|
|
9538
|
-
if (tasks.length > 0) {
|
|
9539
|
-
lines.push("- 成员:");
|
|
9540
|
-
for (const task of tasks) {
|
|
9541
|
-
lines.push(` - ${task.taskId} [${task.status}] ${task.targetAgent}`);
|
|
9542
|
-
}
|
|
9543
|
-
}
|
|
9544
|
-
return lines.join(`
|
|
9545
|
-
`);
|
|
9546
|
-
}
|
|
9547
|
-
function renderGroupCancelSuccess(input) {
|
|
9548
|
-
return [
|
|
9549
|
-
`任务组「${input.summary.group.groupId}」已发起取消`,
|
|
9550
|
-
`- 已请求取消:${input.cancelledTaskIds.length}`,
|
|
9551
|
-
`- 已跳过终态任务:${input.skippedTaskIds.length}`
|
|
9552
|
-
].join(`
|
|
9553
|
-
`);
|
|
9554
|
-
}
|
|
9555
|
-
function renderTaskList(tasks) {
|
|
9556
|
-
if (tasks.length === 0) {
|
|
9557
|
-
return "当前协调会话下还没有任务。";
|
|
9558
|
-
}
|
|
9559
|
-
return ["当前协调会话的任务:", ...tasks.map((task) => renderTaskListItem(task))].join(`
|
|
9560
|
-
`);
|
|
9561
|
-
}
|
|
9562
|
-
function renderTaskSummary(task) {
|
|
9563
|
-
const header = [
|
|
9564
|
-
`任务「${task.taskId}」`,
|
|
9565
|
-
`- 状态:${task.status}`,
|
|
9566
|
-
`- 协调会话:${task.coordinatorSession}`,
|
|
9567
|
-
`- worker 会话:${task.workerSession ?? "未分配"}`,
|
|
9568
|
-
`- 目标 Agent:${task.targetAgent}`
|
|
9569
|
-
];
|
|
9570
|
-
if (task.role)
|
|
9571
|
-
header.push(`- 角色:${task.role}`);
|
|
9572
|
-
if (task.groupId)
|
|
9573
|
-
header.push(`- 任务组:${task.groupId}`);
|
|
9574
|
-
if (task.status === "needs_confirmation") {
|
|
9575
|
-
header.push(`- 来源:${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}`);
|
|
9576
|
-
}
|
|
9577
|
-
header.push(`- 任务:${task.task}`);
|
|
9578
|
-
if (task.summary.trim().length > 0)
|
|
9579
|
-
header.push(`- 摘要:${task.summary}`);
|
|
9580
|
-
if (task.resultText.trim().length > 0)
|
|
9581
|
-
header.push(`- 结果:${task.resultText}`);
|
|
9582
|
-
const events = [];
|
|
9583
|
-
events.push({ at: task.createdAt, event: "created" });
|
|
9584
|
-
if (task.workerSession && task.status !== "needs_confirmation") {
|
|
9585
|
-
events.push({ at: task.createdAt, event: "dispatched", detail: task.workerSession });
|
|
9586
|
-
}
|
|
9587
|
-
if (task.lastProgressAt)
|
|
9588
|
-
events.push({ at: task.lastProgressAt, event: "last_progress" });
|
|
9589
|
-
if (task.cancelRequestedAt)
|
|
9590
|
-
events.push({ at: task.cancelRequestedAt, event: "cancel_requested" });
|
|
9591
|
-
if (task.cancelCompletedAt)
|
|
9592
|
-
events.push({ at: task.cancelCompletedAt, event: "cancel_completed" });
|
|
9593
|
-
if (task.lastCancelError)
|
|
9594
|
-
events.push({ at: task.updatedAt, event: "cancel_failed", detail: task.lastCancelError });
|
|
9595
|
-
if (task.status === "completed")
|
|
9596
|
-
events.push({ at: task.updatedAt, event: "completed" });
|
|
9597
|
-
if (task.status === "failed")
|
|
9598
|
-
events.push({ at: task.updatedAt, event: "failed" });
|
|
9599
|
-
if (task.noticeSentAt)
|
|
9600
|
-
events.push({ at: task.noticeSentAt, event: "notice_sent", detail: task.deliveryAccountId });
|
|
9601
|
-
if (task.lastNoticeError)
|
|
9602
|
-
events.push({ at: task.updatedAt, event: "notice_failed", detail: task.lastNoticeError });
|
|
9603
|
-
if (task.injectionAppliedAt)
|
|
9604
|
-
events.push({ at: task.injectionAppliedAt, event: "injection_applied" });
|
|
9605
|
-
if (task.lastInjectionError)
|
|
9606
|
-
events.push({ at: task.updatedAt, event: "injection_failed", detail: task.lastInjectionError });
|
|
9607
|
-
events.sort((a, b) => a.at.localeCompare(b.at));
|
|
9608
|
-
const timeline = events.length > 0 ? ["- 时间线:", ...events.map((e) => ` - [${e.at}] ${e.event}${e.detail ? `: ${e.detail}` : ""}`)] : [];
|
|
9609
|
-
return [...header, ...timeline].join(`
|
|
9610
|
-
`);
|
|
9611
|
-
}
|
|
9612
|
-
function renderTaskCancelSuccess(task) {
|
|
9613
|
-
if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
|
|
9614
|
-
return [`任务「${task.taskId}」已结束。`, `- 当前状态:${task.status}`].join(`
|
|
9615
|
-
`);
|
|
9616
|
-
}
|
|
9617
|
-
if (task.cancelRequestedAt) {
|
|
9618
|
-
return [`已请求取消任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
|
|
9619
|
-
`);
|
|
9620
|
-
}
|
|
9621
|
-
return [`任务「${task.taskId}」已取消。`, `- 当前状态:${task.status}`].join(`
|
|
9622
|
-
`);
|
|
9623
|
-
}
|
|
9624
|
-
function renderTaskApprovalSuccess(task) {
|
|
9625
|
-
return [`已批准任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
|
|
9626
|
-
`);
|
|
9627
|
-
}
|
|
9628
|
-
function renderTaskRejectionSuccess(task) {
|
|
9629
|
-
return [`已拒绝任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
|
|
9630
|
-
`);
|
|
9631
|
-
}
|
|
9632
|
-
function renderTaskConfirmationUnavailable(task) {
|
|
9633
|
-
return [`任务「${task.taskId}」当前不是待确认状态。`, `- 当前状态:${task.status}`].join(`
|
|
9634
|
-
`);
|
|
9635
|
-
}
|
|
9636
|
-
function renderTasksCleanResult(removedTasks, removedBindings) {
|
|
9637
|
-
if (removedTasks === 0 && removedBindings === 0) {
|
|
9638
|
-
return "当前协调会话下没有可清理的任务。";
|
|
9639
|
-
}
|
|
9640
|
-
const lines = [];
|
|
9641
|
-
if (removedTasks > 0) {
|
|
9642
|
-
lines.push(`已清理 ${removedTasks} 个已结束的任务。`);
|
|
9643
|
-
}
|
|
9644
|
-
if (removedBindings > 0) {
|
|
9645
|
-
lines.push(`已释放 ${removedBindings} 个无效的 worker 绑定。`);
|
|
9646
|
-
}
|
|
9647
|
-
return lines.join(`
|
|
9648
|
-
`);
|
|
9649
|
-
}
|
|
9650
|
-
function renderTaskListItem(task) {
|
|
9651
|
-
const role = task.role ? ` / ${task.role}` : "";
|
|
9652
|
-
const group = task.groupId ? `;组:${task.groupId}` : "";
|
|
9653
|
-
const summary = task.summary.trim().length > 0 ? `:${task.summary}` : "";
|
|
9654
|
-
const source = task.status === "needs_confirmation" ? `;来源:${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}` : "";
|
|
9655
|
-
const reliability = [
|
|
9656
|
-
task.noticePending ? "通知待重试" : "",
|
|
9657
|
-
task.injectionPending ? "注入待重试" : "",
|
|
9658
|
-
task.cancelRequestedAt && !task.cancelCompletedAt && task.status === "running" ? "取消中" : ""
|
|
9659
|
-
].filter(Boolean).map((item) => `;${item}`).join("");
|
|
9660
|
-
return `- ${task.taskId} [${task.status}] ${task.targetAgent}${role} -> ${task.workerSession ?? "未分配"}${group}${source}${summary}${reliability}`;
|
|
9661
|
-
}
|
|
9662
|
-
function renderGroupListItem(group) {
|
|
9663
|
-
const reliability = [
|
|
9664
|
-
group.group.injectionPending ? "注入待重试" : ""
|
|
9665
|
-
].filter(Boolean).map((item) => `;${item}`).join("");
|
|
9666
|
-
return [
|
|
9667
|
-
`- ${group.group.groupId}`,
|
|
9668
|
-
group.group.title,
|
|
9669
|
-
`总计 ${group.totalTasks}`,
|
|
9670
|
-
`待确认 ${group.pendingApprovalTasks}`,
|
|
9671
|
-
`运行中 ${group.runningTasks}`,
|
|
9672
|
-
`完成 ${group.completedTasks}`,
|
|
9673
|
-
`失败 ${group.failedTasks}`,
|
|
9674
|
-
`取消 ${group.cancelledTasks}${reliability}`
|
|
9675
|
-
].join(" | ");
|
|
9676
|
-
}
|
|
9677
|
-
function renderTaskProgress(task, summary) {
|
|
9678
|
-
return `⏳ 任务「${task.taskId}」(${task.targetAgent}):${summary}`;
|
|
9679
|
-
}
|
|
9680
|
-
function renderTaskHeartbeat(task, elapsedSeconds) {
|
|
9681
|
-
const minutes = Math.floor(elapsedSeconds / 60);
|
|
9682
|
-
return `⏳ 任务「${task.taskId}」已运行 ${minutes} 分钟,等待中...`;
|
|
9683
|
-
}
|
|
9684
|
-
|
|
9685
9480
|
// src/orchestration/task-wait-timeouts.ts
|
|
9686
9481
|
var DEFAULT_TASK_WAIT_TIMEOUT_MS, MAX_TASK_WAIT_TIMEOUT_MS, DEFAULT_TASK_WAIT_POLL_INTERVAL_MS = 1000, MAX_TASK_WAIT_POLL_INTERVAL_MS = 1e4, TASK_WAIT_RPC_TIMEOUT_PADDING_MS = 5000;
|
|
9687
9482
|
var init_task_wait_timeouts = __esm(() => {
|
|
@@ -14358,7 +14153,7 @@ import { dirname as dirname6, join as join3 } from "node:path";
|
|
|
14358
14153
|
import { homedir as homedir3 } from "node:os";
|
|
14359
14154
|
function createWeixinConsumerLock(options = {}) {
|
|
14360
14155
|
const lockFilePath = options.lockFilePath ?? join3(homedir3(), ".weacpx", "runtime", "weixin-consumer.lock.json");
|
|
14361
|
-
const isProcessRunning = options.isProcessRunning ??
|
|
14156
|
+
const isProcessRunning = options.isProcessRunning ?? defaultIsProcessRunning4;
|
|
14362
14157
|
const onDiagnostic = options.onDiagnostic;
|
|
14363
14158
|
return {
|
|
14364
14159
|
async acquire(meta2) {
|
|
@@ -14445,7 +14240,7 @@ async function loadLockMetadata(path13) {
|
|
|
14445
14240
|
return null;
|
|
14446
14241
|
}
|
|
14447
14242
|
}
|
|
14448
|
-
function
|
|
14243
|
+
function defaultIsProcessRunning4(pid) {
|
|
14449
14244
|
try {
|
|
14450
14245
|
process.kill(pid, 0);
|
|
14451
14246
|
return true;
|
|
@@ -16774,8 +16569,10 @@ async function handleSessionRemove(context, chatKey, alias) {
|
|
|
16774
16569
|
return { text: lines.join(`
|
|
16775
16570
|
`) };
|
|
16776
16571
|
}
|
|
16777
|
-
async function promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal) {
|
|
16572
|
+
async function promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent) {
|
|
16778
16573
|
const effectiveReplyMode = session.replyMode ?? context.config?.channel.replyMode ?? "verbose";
|
|
16574
|
+
if (!session.replyMode)
|
|
16575
|
+
session.replyMode = effectiveReplyMode;
|
|
16779
16576
|
const transportReply = effectiveReplyMode !== "final" ? reply : undefined;
|
|
16780
16577
|
if (context.orchestration) {
|
|
16781
16578
|
try {
|
|
@@ -16796,8 +16593,8 @@ async function promptWithSession(context, session, chatKey, text, reply, replyCo
|
|
|
16796
16593
|
}
|
|
16797
16594
|
const { promptText, taskIds, groupIds, claimHumanReply } = await preparePromptWithFallback(context, session, chatKey, text, replyContextToken, accountId);
|
|
16798
16595
|
try {
|
|
16799
|
-
const replyContext = transportReply && context.quota ? { chatKey, quota: context.quota } : undefined;
|
|
16800
|
-
const result = await context.interaction.promptTransportSession(session, promptText, transportReply, replyContext, media, abortSignal);
|
|
16596
|
+
const replyContext = transportReply && context.quota && getChannelIdFromChatKey(chatKey) === "weixin" ? { chatKey, quota: context.quota } : undefined;
|
|
16597
|
+
const result = await context.interaction.promptTransportSession(session, promptText, transportReply, replyContext, media, abortSignal, onToolEvent);
|
|
16801
16598
|
if (claimHumanReply) {
|
|
16802
16599
|
try {
|
|
16803
16600
|
await context.orchestration?.claimActiveHumanReply?.(claimHumanReply);
|
|
@@ -16817,17 +16614,17 @@ async function promptWithSession(context, session, chatKey, text, reply, replyCo
|
|
|
16817
16614
|
throw error2;
|
|
16818
16615
|
}
|
|
16819
16616
|
}
|
|
16820
|
-
async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal) {
|
|
16617
|
+
async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent) {
|
|
16821
16618
|
const session = await context.sessions.getCurrentSession(chatKey);
|
|
16822
16619
|
if (!session) {
|
|
16823
16620
|
return { text: NO_CURRENT_SESSION_TEXT };
|
|
16824
16621
|
}
|
|
16825
16622
|
try {
|
|
16826
|
-
return await promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal);
|
|
16623
|
+
return await promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent);
|
|
16827
16624
|
} catch (error2) {
|
|
16828
16625
|
const recovered = await context.recovery.tryRecoverMissingSession(session, error2);
|
|
16829
16626
|
if (recovered) {
|
|
16830
|
-
return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal);
|
|
16627
|
+
return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent);
|
|
16831
16628
|
}
|
|
16832
16629
|
return context.recovery.renderTransportError(session, error2);
|
|
16833
16630
|
}
|
|
@@ -16957,6 +16754,211 @@ var init_session_handler = __esm(() => {
|
|
|
16957
16754
|
};
|
|
16958
16755
|
});
|
|
16959
16756
|
|
|
16757
|
+
// src/formatting/render-text.ts
|
|
16758
|
+
function renderAgents(config2) {
|
|
16759
|
+
const names = Object.keys(config2.agents);
|
|
16760
|
+
if (names.length === 0) {
|
|
16761
|
+
return "还没有注册任何 Agent。";
|
|
16762
|
+
}
|
|
16763
|
+
return ["已注册的 Agent:", ...names.map((name) => `- ${name}`)].join(`
|
|
16764
|
+
`);
|
|
16765
|
+
}
|
|
16766
|
+
function renderWorkspaces(config2) {
|
|
16767
|
+
const names = Object.entries(config2.workspaces);
|
|
16768
|
+
if (names.length === 0) {
|
|
16769
|
+
return "还没有注册任何工作区。";
|
|
16770
|
+
}
|
|
16771
|
+
return ["已注册的工作区:", ...names.map(([name, workspace]) => `- ${name}: ${workspace.cwd}`)].join(`
|
|
16772
|
+
`);
|
|
16773
|
+
}
|
|
16774
|
+
function renderOrchestrationUnavailable() {
|
|
16775
|
+
return "当前未启用任务编排服务。";
|
|
16776
|
+
}
|
|
16777
|
+
function renderDelegateSuccess2(taskId, workerSession) {
|
|
16778
|
+
return [`已创建委派任务「${taskId}」`, `worker 会话:${workerSession}`].join(`
|
|
16779
|
+
`);
|
|
16780
|
+
}
|
|
16781
|
+
function renderGroupCreated2(group) {
|
|
16782
|
+
return [`已创建任务组「${group.groupId}」`, `- 标题:${group.title}`].join(`
|
|
16783
|
+
`);
|
|
16784
|
+
}
|
|
16785
|
+
function renderGroupList2(groups) {
|
|
16786
|
+
if (groups.length === 0) {
|
|
16787
|
+
return "当前协调会话下还没有任务组。";
|
|
16788
|
+
}
|
|
16789
|
+
return ["当前协调会话的任务组:", ...groups.map((group) => renderGroupListItem2(group))].join(`
|
|
16790
|
+
`);
|
|
16791
|
+
}
|
|
16792
|
+
function renderGroupSummary2(summary) {
|
|
16793
|
+
const { group, tasks } = summary;
|
|
16794
|
+
const lines = [
|
|
16795
|
+
`任务组「${group.groupId}」`,
|
|
16796
|
+
`- 标题:${group.title}`,
|
|
16797
|
+
`- 协调会话:${group.coordinatorSession}`,
|
|
16798
|
+
`- 总任务数:${summary.totalTasks}`,
|
|
16799
|
+
`- 待确认:${summary.pendingApprovalTasks}`,
|
|
16800
|
+
`- 运行中:${summary.runningTasks}`,
|
|
16801
|
+
`- 已完成:${summary.completedTasks}`,
|
|
16802
|
+
`- 已失败:${summary.failedTasks}`,
|
|
16803
|
+
`- 已取消:${summary.cancelledTasks}`,
|
|
16804
|
+
`- 是否终态:${summary.terminal ? "是" : "否"}`
|
|
16805
|
+
];
|
|
16806
|
+
if (group.injectionPending !== undefined) {
|
|
16807
|
+
lines.push(`- 注入待处理:${group.injectionPending ? "是" : "否"}`);
|
|
16808
|
+
}
|
|
16809
|
+
if (group.injectionAppliedAt) {
|
|
16810
|
+
lines.push(`- 注入完成时间:${group.injectionAppliedAt}`);
|
|
16811
|
+
}
|
|
16812
|
+
if (group.lastInjectionError) {
|
|
16813
|
+
lines.push(`- 最近注入错误:${group.lastInjectionError}`);
|
|
16814
|
+
}
|
|
16815
|
+
if (tasks.length > 0) {
|
|
16816
|
+
lines.push("- 成员:");
|
|
16817
|
+
for (const task of tasks) {
|
|
16818
|
+
lines.push(` - ${task.taskId} [${task.status}] ${task.targetAgent}`);
|
|
16819
|
+
}
|
|
16820
|
+
}
|
|
16821
|
+
return lines.join(`
|
|
16822
|
+
`);
|
|
16823
|
+
}
|
|
16824
|
+
function renderGroupCancelSuccess2(input) {
|
|
16825
|
+
return [
|
|
16826
|
+
`任务组「${input.summary.group.groupId}」已发起取消`,
|
|
16827
|
+
`- 已请求取消:${input.cancelledTaskIds.length}`,
|
|
16828
|
+
`- 已跳过终态任务:${input.skippedTaskIds.length}`
|
|
16829
|
+
].join(`
|
|
16830
|
+
`);
|
|
16831
|
+
}
|
|
16832
|
+
function renderTaskList2(tasks) {
|
|
16833
|
+
if (tasks.length === 0) {
|
|
16834
|
+
return "当前协调会话下还没有任务。";
|
|
16835
|
+
}
|
|
16836
|
+
return ["当前协调会话的任务:", ...tasks.map((task) => renderTaskListItem2(task))].join(`
|
|
16837
|
+
`);
|
|
16838
|
+
}
|
|
16839
|
+
function renderTaskSummary2(task) {
|
|
16840
|
+
const header = [
|
|
16841
|
+
`任务「${task.taskId}」`,
|
|
16842
|
+
`- 状态:${task.status}`,
|
|
16843
|
+
`- 协调会话:${task.coordinatorSession}`,
|
|
16844
|
+
`- worker 会话:${task.workerSession ?? "未分配"}`,
|
|
16845
|
+
`- 目标 Agent:${task.targetAgent}`
|
|
16846
|
+
];
|
|
16847
|
+
if (task.role)
|
|
16848
|
+
header.push(`- 角色:${task.role}`);
|
|
16849
|
+
if (task.groupId)
|
|
16850
|
+
header.push(`- 任务组:${task.groupId}`);
|
|
16851
|
+
if (task.status === "needs_confirmation") {
|
|
16852
|
+
header.push(`- 来源:${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}`);
|
|
16853
|
+
}
|
|
16854
|
+
header.push(`- 任务:${task.task}`);
|
|
16855
|
+
if (task.summary.trim().length > 0)
|
|
16856
|
+
header.push(`- 摘要:${task.summary}`);
|
|
16857
|
+
if (task.resultText.trim().length > 0)
|
|
16858
|
+
header.push(`- 结果:${task.resultText}`);
|
|
16859
|
+
const events = [];
|
|
16860
|
+
events.push({ at: task.createdAt, event: "created" });
|
|
16861
|
+
if (task.workerSession && task.status !== "needs_confirmation") {
|
|
16862
|
+
events.push({ at: task.createdAt, event: "dispatched", detail: task.workerSession });
|
|
16863
|
+
}
|
|
16864
|
+
if (task.lastProgressAt)
|
|
16865
|
+
events.push({ at: task.lastProgressAt, event: "last_progress" });
|
|
16866
|
+
if (task.cancelRequestedAt)
|
|
16867
|
+
events.push({ at: task.cancelRequestedAt, event: "cancel_requested" });
|
|
16868
|
+
if (task.cancelCompletedAt)
|
|
16869
|
+
events.push({ at: task.cancelCompletedAt, event: "cancel_completed" });
|
|
16870
|
+
if (task.lastCancelError)
|
|
16871
|
+
events.push({ at: task.updatedAt, event: "cancel_failed", detail: task.lastCancelError });
|
|
16872
|
+
if (task.status === "completed")
|
|
16873
|
+
events.push({ at: task.updatedAt, event: "completed" });
|
|
16874
|
+
if (task.status === "failed")
|
|
16875
|
+
events.push({ at: task.updatedAt, event: "failed" });
|
|
16876
|
+
if (task.noticeSentAt)
|
|
16877
|
+
events.push({ at: task.noticeSentAt, event: "notice_sent", detail: task.deliveryAccountId });
|
|
16878
|
+
if (task.lastNoticeError)
|
|
16879
|
+
events.push({ at: task.updatedAt, event: "notice_failed", detail: task.lastNoticeError });
|
|
16880
|
+
if (task.injectionAppliedAt)
|
|
16881
|
+
events.push({ at: task.injectionAppliedAt, event: "injection_applied" });
|
|
16882
|
+
if (task.lastInjectionError)
|
|
16883
|
+
events.push({ at: task.updatedAt, event: "injection_failed", detail: task.lastInjectionError });
|
|
16884
|
+
events.sort((a, b) => a.at.localeCompare(b.at));
|
|
16885
|
+
const timeline = events.length > 0 ? ["- 时间线:", ...events.map((e) => ` - [${e.at}] ${e.event}${e.detail ? `: ${e.detail}` : ""}`)] : [];
|
|
16886
|
+
return [...header, ...timeline].join(`
|
|
16887
|
+
`);
|
|
16888
|
+
}
|
|
16889
|
+
function renderTaskCancelSuccess(task) {
|
|
16890
|
+
if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
|
|
16891
|
+
return [`任务「${task.taskId}」已结束。`, `- 当前状态:${task.status}`].join(`
|
|
16892
|
+
`);
|
|
16893
|
+
}
|
|
16894
|
+
if (task.cancelRequestedAt) {
|
|
16895
|
+
return [`已请求取消任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
|
|
16896
|
+
`);
|
|
16897
|
+
}
|
|
16898
|
+
return [`任务「${task.taskId}」已取消。`, `- 当前状态:${task.status}`].join(`
|
|
16899
|
+
`);
|
|
16900
|
+
}
|
|
16901
|
+
function renderTaskApprovalSuccess2(task) {
|
|
16902
|
+
return [`已批准任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
|
|
16903
|
+
`);
|
|
16904
|
+
}
|
|
16905
|
+
function renderTaskRejectionSuccess2(task) {
|
|
16906
|
+
return [`已拒绝任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
|
|
16907
|
+
`);
|
|
16908
|
+
}
|
|
16909
|
+
function renderTaskConfirmationUnavailable(task) {
|
|
16910
|
+
return [`任务「${task.taskId}」当前不是待确认状态。`, `- 当前状态:${task.status}`].join(`
|
|
16911
|
+
`);
|
|
16912
|
+
}
|
|
16913
|
+
function renderTasksCleanResult(removedTasks, removedBindings) {
|
|
16914
|
+
if (removedTasks === 0 && removedBindings === 0) {
|
|
16915
|
+
return "当前协调会话下没有可清理的任务。";
|
|
16916
|
+
}
|
|
16917
|
+
const lines = [];
|
|
16918
|
+
if (removedTasks > 0) {
|
|
16919
|
+
lines.push(`已清理 ${removedTasks} 个已结束的任务。`);
|
|
16920
|
+
}
|
|
16921
|
+
if (removedBindings > 0) {
|
|
16922
|
+
lines.push(`已释放 ${removedBindings} 个无效的 worker 绑定。`);
|
|
16923
|
+
}
|
|
16924
|
+
return lines.join(`
|
|
16925
|
+
`);
|
|
16926
|
+
}
|
|
16927
|
+
function renderTaskListItem2(task) {
|
|
16928
|
+
const role = task.role ? ` / ${task.role}` : "";
|
|
16929
|
+
const group = task.groupId ? `;组:${task.groupId}` : "";
|
|
16930
|
+
const summary = task.summary.trim().length > 0 ? `:${task.summary}` : "";
|
|
16931
|
+
const source = task.status === "needs_confirmation" ? `;来源:${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}` : "";
|
|
16932
|
+
const reliability = [
|
|
16933
|
+
task.noticePending ? "通知待重试" : "",
|
|
16934
|
+
task.injectionPending ? "注入待重试" : "",
|
|
16935
|
+
task.cancelRequestedAt && !task.cancelCompletedAt && task.status === "running" ? "取消中" : ""
|
|
16936
|
+
].filter(Boolean).map((item) => `;${item}`).join("");
|
|
16937
|
+
return `- ${task.taskId} [${task.status}] ${task.targetAgent}${role} -> ${task.workerSession ?? "未分配"}${group}${source}${summary}${reliability}`;
|
|
16938
|
+
}
|
|
16939
|
+
function renderGroupListItem2(group) {
|
|
16940
|
+
const reliability = [
|
|
16941
|
+
group.group.injectionPending ? "注入待重试" : ""
|
|
16942
|
+
].filter(Boolean).map((item) => `;${item}`).join("");
|
|
16943
|
+
return [
|
|
16944
|
+
`- ${group.group.groupId}`,
|
|
16945
|
+
group.group.title,
|
|
16946
|
+
`总计 ${group.totalTasks}`,
|
|
16947
|
+
`待确认 ${group.pendingApprovalTasks}`,
|
|
16948
|
+
`运行中 ${group.runningTasks}`,
|
|
16949
|
+
`完成 ${group.completedTasks}`,
|
|
16950
|
+
`失败 ${group.failedTasks}`,
|
|
16951
|
+
`取消 ${group.cancelledTasks}${reliability}`
|
|
16952
|
+
].join(" | ");
|
|
16953
|
+
}
|
|
16954
|
+
function renderTaskProgress(task, summary) {
|
|
16955
|
+
return `⏳ 任务「${task.taskId}」(${task.targetAgent}):${summary}`;
|
|
16956
|
+
}
|
|
16957
|
+
function renderTaskHeartbeat(task, elapsedSeconds) {
|
|
16958
|
+
const minutes = Math.floor(elapsedSeconds / 60);
|
|
16959
|
+
return `⏳ 任务「${task.taskId}」已运行 ${minutes} 分钟,等待中...`;
|
|
16960
|
+
}
|
|
16961
|
+
|
|
16960
16962
|
// src/commands/handlers/orchestration-handler.ts
|
|
16961
16963
|
async function handleDelegateRequest(context, chatKey, targetAgent, task, role, groupId, replyContextToken, accountId) {
|
|
16962
16964
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -16980,7 +16982,7 @@ async function handleDelegateRequest(context, chatKey, targetAgent, task, role,
|
|
|
16980
16982
|
...replyContextToken ? { replyContextToken } : {},
|
|
16981
16983
|
...accountId ? { accountId } : {}
|
|
16982
16984
|
});
|
|
16983
|
-
return { text:
|
|
16985
|
+
return { text: renderDelegateSuccess2(result.taskId, result.workerSession) };
|
|
16984
16986
|
}
|
|
16985
16987
|
async function handleGroupCreate(context, chatKey, title) {
|
|
16986
16988
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -16995,7 +16997,7 @@ async function handleGroupCreate(context, chatKey, title) {
|
|
|
16995
16997
|
coordinatorSession: session.transportSession,
|
|
16996
16998
|
title
|
|
16997
16999
|
});
|
|
16998
|
-
return { text:
|
|
17000
|
+
return { text: renderGroupCreated2(group) };
|
|
16999
17001
|
}
|
|
17000
17002
|
async function handleGroupList(context, chatKey, filter) {
|
|
17001
17003
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -17010,7 +17012,7 @@ async function handleGroupList(context, chatKey, filter) {
|
|
|
17010
17012
|
coordinatorSession: session.transportSession,
|
|
17011
17013
|
...filter ?? {}
|
|
17012
17014
|
});
|
|
17013
|
-
return { text:
|
|
17015
|
+
return { text: renderGroupList2(groups) };
|
|
17014
17016
|
}
|
|
17015
17017
|
async function handleGroupGet(context, chatKey, groupId) {
|
|
17016
17018
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -17028,7 +17030,7 @@ async function handleGroupGet(context, chatKey, groupId) {
|
|
|
17028
17030
|
if (!group) {
|
|
17029
17031
|
return { text: GROUP_NOT_FOUND_TEXT };
|
|
17030
17032
|
}
|
|
17031
|
-
return { text:
|
|
17033
|
+
return { text: renderGroupSummary2(group) };
|
|
17032
17034
|
}
|
|
17033
17035
|
async function handleGroupCancel(context, chatKey, groupId) {
|
|
17034
17036
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -17050,7 +17052,7 @@ async function handleGroupCancel(context, chatKey, groupId) {
|
|
|
17050
17052
|
groupId,
|
|
17051
17053
|
coordinatorSession: session.transportSession
|
|
17052
17054
|
});
|
|
17053
|
-
return { text:
|
|
17055
|
+
return { text: renderGroupCancelSuccess2(cancelled) };
|
|
17054
17056
|
}
|
|
17055
17057
|
async function handleGroupDelegate(context, chatKey, groupId, targetAgent, task, role, replyContextToken, accountId) {
|
|
17056
17058
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -17083,7 +17085,7 @@ async function handleTaskList(context, chatKey, filter) {
|
|
|
17083
17085
|
coordinatorSession: session.transportSession,
|
|
17084
17086
|
...filter ?? {}
|
|
17085
17087
|
});
|
|
17086
|
-
return { text:
|
|
17088
|
+
return { text: renderTaskList2(tasks) };
|
|
17087
17089
|
}
|
|
17088
17090
|
async function handleTaskGet(context, chatKey, taskId) {
|
|
17089
17091
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -17098,7 +17100,7 @@ async function handleTaskGet(context, chatKey, taskId) {
|
|
|
17098
17100
|
if (!task || task.coordinatorSession !== session.transportSession) {
|
|
17099
17101
|
return { text: TASK_NOT_FOUND_TEXT };
|
|
17100
17102
|
}
|
|
17101
|
-
return { text:
|
|
17103
|
+
return { text: renderTaskSummary2(task) };
|
|
17102
17104
|
}
|
|
17103
17105
|
async function handleTaskApprove(context, chatKey, taskId) {
|
|
17104
17106
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -17120,7 +17122,7 @@ async function handleTaskApprove(context, chatKey, taskId) {
|
|
|
17120
17122
|
taskId,
|
|
17121
17123
|
coordinatorSession: session.transportSession
|
|
17122
17124
|
});
|
|
17123
|
-
return { text:
|
|
17125
|
+
return { text: renderTaskApprovalSuccess2(approved) };
|
|
17124
17126
|
}
|
|
17125
17127
|
async function handleTaskReject(context, chatKey, taskId) {
|
|
17126
17128
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -17142,7 +17144,7 @@ async function handleTaskReject(context, chatKey, taskId) {
|
|
|
17142
17144
|
taskId,
|
|
17143
17145
|
coordinatorSession: session.transportSession
|
|
17144
17146
|
});
|
|
17145
|
-
return { text:
|
|
17147
|
+
return { text: renderTaskRejectionSuccess2(rejected) };
|
|
17146
17148
|
}
|
|
17147
17149
|
async function handleTaskCancel(context, chatKey, taskId) {
|
|
17148
17150
|
const session = await getCurrentSession(context, chatKey);
|
|
@@ -18148,7 +18150,7 @@ class CommandRouter {
|
|
|
18148
18150
|
this.quota = quota;
|
|
18149
18151
|
this.logger = logger2 ?? createNoopAppLogger();
|
|
18150
18152
|
}
|
|
18151
|
-
async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal) {
|
|
18153
|
+
async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent) {
|
|
18152
18154
|
const startedAt = Date.now();
|
|
18153
18155
|
const command = parseCommand(input);
|
|
18154
18156
|
await this.logger.debug("command.parsed", "parsed inbound command", {
|
|
@@ -18262,7 +18264,7 @@ class CommandRouter {
|
|
|
18262
18264
|
case "task.cancel":
|
|
18263
18265
|
return await handleTaskCancel(this.createHandlerContext(), chatKey, command.taskId);
|
|
18264
18266
|
case "prompt":
|
|
18265
|
-
return await handlePrompt(this.createSessionHandlerContext(), chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal);
|
|
18267
|
+
return await handlePrompt(this.createSessionHandlerContext(), chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent);
|
|
18266
18268
|
}
|
|
18267
18269
|
});
|
|
18268
18270
|
}
|
|
@@ -18314,7 +18316,7 @@ class CommandRouter {
|
|
|
18314
18316
|
return {
|
|
18315
18317
|
setModeTransportSession: (session, modeId) => this.setModeTransportSession(session, modeId),
|
|
18316
18318
|
cancelTransportSession: (session) => this.cancelTransportSession(session),
|
|
18317
|
-
promptTransportSession: (session, text, reply, replyContext, media, abortSignal) => this.promptTransportSession(session, text, reply, replyContext, media, abortSignal)
|
|
18319
|
+
promptTransportSession: (session, text, reply, replyContext, media, abortSignal, onToolEvent) => this.promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent)
|
|
18318
18320
|
};
|
|
18319
18321
|
}
|
|
18320
18322
|
createSessionRenderRecoveryOps() {
|
|
@@ -18477,7 +18479,7 @@ class CommandRouter {
|
|
|
18477
18479
|
async checkTransportSession(session) {
|
|
18478
18480
|
return await this.measureTransportCall("has_session", session, () => this.transport.hasSession(session));
|
|
18479
18481
|
}
|
|
18480
|
-
async promptTransportSession(session, text, reply, replyContext, media, abortSignal) {
|
|
18482
|
+
async promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent) {
|
|
18481
18483
|
session.mcpCoordinatorSession ??= session.transportSession;
|
|
18482
18484
|
let done = false;
|
|
18483
18485
|
let cancelOnAbort;
|
|
@@ -18514,7 +18516,10 @@ class CommandRouter {
|
|
|
18514
18516
|
abortSignal.addEventListener("abort", cancelOnAbort, { once: true });
|
|
18515
18517
|
}
|
|
18516
18518
|
try {
|
|
18517
|
-
return await this.measureTransportCall("prompt", session, () => this.transport.prompt(session, text, reply, replyContext,
|
|
18519
|
+
return await this.measureTransportCall("prompt", session, () => this.transport.prompt(session, text, reply, replyContext, {
|
|
18520
|
+
...media ? { media } : {},
|
|
18521
|
+
...onToolEvent ? { onToolEvent } : {}
|
|
18522
|
+
}));
|
|
18518
18523
|
} finally {
|
|
18519
18524
|
done = true;
|
|
18520
18525
|
if (cancelOnAbort && abortSignal) {
|
|
@@ -18665,7 +18670,7 @@ class ConsoleAgent {
|
|
|
18665
18670
|
mimeType: m.mimeType,
|
|
18666
18671
|
...m.fileName ? { fileName: m.fileName } : {}
|
|
18667
18672
|
})) : undefined;
|
|
18668
|
-
return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal);
|
|
18673
|
+
return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent);
|
|
18669
18674
|
}
|
|
18670
18675
|
isKnownCommand(text) {
|
|
18671
18676
|
return isKnownWeacpxCommandText(text);
|
|
@@ -22765,6 +22770,10 @@ function encodeBridgePromptSegmentEvent(event) {
|
|
|
22765
22770
|
return `${JSON.stringify(event)}
|
|
22766
22771
|
`;
|
|
22767
22772
|
}
|
|
22773
|
+
function encodeBridgePromptToolEvent(event) {
|
|
22774
|
+
return `${JSON.stringify(event)}
|
|
22775
|
+
`;
|
|
22776
|
+
}
|
|
22768
22777
|
function encodeBridgeSessionProgressEvent(event) {
|
|
22769
22778
|
return `${JSON.stringify(event)}
|
|
22770
22779
|
`;
|
|
@@ -22832,6 +22841,11 @@ class AcpxBridgeClient {
|
|
|
22832
22841
|
type: "prompt.segment",
|
|
22833
22842
|
text: message.text
|
|
22834
22843
|
});
|
|
22844
|
+
} else if (message.event === "prompt.tool_event") {
|
|
22845
|
+
pending.onEvent?.({
|
|
22846
|
+
type: "prompt.tool_event",
|
|
22847
|
+
event: message.toolEvent
|
|
22848
|
+
});
|
|
22835
22849
|
} else if (message.event === "session.progress") {
|
|
22836
22850
|
pending.onEvent?.({
|
|
22837
22851
|
type: "session.progress",
|
|
@@ -23155,6 +23169,17 @@ var init_quota_gated_reply_sink = __esm(() => {
|
|
|
23155
23169
|
ADAPTIVE_WINDOW_SCHEDULE_MS = [3000, 6000, 12000, 24000, 48000, 60000];
|
|
23156
23170
|
});
|
|
23157
23171
|
|
|
23172
|
+
// src/transport/tool-event-mode.ts
|
|
23173
|
+
function resolveToolEventMode(input) {
|
|
23174
|
+
if (input?.toolEventMode !== undefined) {
|
|
23175
|
+
return input.toolEventMode;
|
|
23176
|
+
}
|
|
23177
|
+
if (input?.onToolEvent !== undefined) {
|
|
23178
|
+
return "structured";
|
|
23179
|
+
}
|
|
23180
|
+
return "text";
|
|
23181
|
+
}
|
|
23182
|
+
|
|
23158
23183
|
// src/transport/acpx-bridge/acpx-bridge-transport.ts
|
|
23159
23184
|
class AcpxBridgeTransport {
|
|
23160
23185
|
client;
|
|
@@ -23177,10 +23202,18 @@ class AcpxBridgeTransport {
|
|
|
23177
23202
|
}) : null;
|
|
23178
23203
|
let segmentError;
|
|
23179
23204
|
let segmentChain = Promise.resolve();
|
|
23205
|
+
let toolEventError;
|
|
23206
|
+
let toolEventChain = Promise.resolve();
|
|
23207
|
+
let toolEventMode = resolveToolEventMode(options);
|
|
23208
|
+
if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
|
|
23209
|
+
toolEventMode = "text";
|
|
23210
|
+
}
|
|
23180
23211
|
const result = await this.client.request("prompt", {
|
|
23181
23212
|
...this.toParams(session),
|
|
23182
23213
|
text,
|
|
23183
|
-
...options?.media ? { media: options.media } : {}
|
|
23214
|
+
...options?.media ? { media: options.media } : {},
|
|
23215
|
+
...toolEventMode === "structured" || toolEventMode === "both" ? { toolEvents: true } : {},
|
|
23216
|
+
toolEventMode
|
|
23184
23217
|
}, (event) => {
|
|
23185
23218
|
if (event.type === "prompt.segment") {
|
|
23186
23219
|
const onSegment = options?.onSegment;
|
|
@@ -23191,9 +23224,21 @@ class AcpxBridgeTransport {
|
|
|
23191
23224
|
});
|
|
23192
23225
|
}
|
|
23193
23226
|
sink?.feedSegment(event.text);
|
|
23227
|
+
return;
|
|
23228
|
+
}
|
|
23229
|
+
if (event.type === "prompt.tool_event") {
|
|
23230
|
+
const onToolEvent = options?.onToolEvent;
|
|
23231
|
+
if (onToolEvent) {
|
|
23232
|
+
const toolEvent = event.event;
|
|
23233
|
+
toolEventChain = toolEventChain.then(() => onToolEvent(toolEvent)).catch((error2) => {
|
|
23234
|
+
toolEventError ??= error2;
|
|
23235
|
+
});
|
|
23236
|
+
}
|
|
23237
|
+
return;
|
|
23194
23238
|
}
|
|
23195
23239
|
});
|
|
23196
23240
|
await segmentChain;
|
|
23241
|
+
await toolEventChain;
|
|
23197
23242
|
if (sink) {
|
|
23198
23243
|
const { overflowCount } = sink.finalize();
|
|
23199
23244
|
await sink.drain({ timeoutMs: 30000 });
|
|
@@ -23205,6 +23250,9 @@ class AcpxBridgeTransport {
|
|
|
23205
23250
|
if (segmentError) {
|
|
23206
23251
|
throw segmentError;
|
|
23207
23252
|
}
|
|
23253
|
+
if (toolEventError) {
|
|
23254
|
+
throw toolEventError;
|
|
23255
|
+
}
|
|
23208
23256
|
return { text: summary ? `${summary}
|
|
23209
23257
|
|
|
23210
23258
|
${result.text}` : "" };
|
|
@@ -23212,6 +23260,9 @@ ${result.text}` : "" };
|
|
|
23212
23260
|
if (segmentError) {
|
|
23213
23261
|
throw segmentError;
|
|
23214
23262
|
}
|
|
23263
|
+
if (toolEventError) {
|
|
23264
|
+
throw toolEventError;
|
|
23265
|
+
}
|
|
23215
23266
|
return result;
|
|
23216
23267
|
}
|
|
23217
23268
|
async setMode(session, modeId) {
|
|
@@ -23244,7 +23295,7 @@ ${result.text}` : "" };
|
|
|
23244
23295
|
name: session.transportSession,
|
|
23245
23296
|
mcpCoordinatorSession: session.mcpCoordinatorSession,
|
|
23246
23297
|
mcpSourceHandle: session.mcpSourceHandle,
|
|
23247
|
-
|
|
23298
|
+
replyMode: session.replyMode ?? "verbose"
|
|
23248
23299
|
};
|
|
23249
23300
|
}
|
|
23250
23301
|
}
|
|
@@ -23398,8 +23449,37 @@ var init_prompt_media = __esm(() => {
|
|
|
23398
23449
|
};
|
|
23399
23450
|
});
|
|
23400
23451
|
|
|
23452
|
+
// src/transport/tool-kind-emoji.ts
|
|
23453
|
+
var TOOL_KIND_EMOJI, DEFAULT_TOOL_EMOJI;
|
|
23454
|
+
var init_tool_kind_emoji = __esm(() => {
|
|
23455
|
+
TOOL_KIND_EMOJI = {
|
|
23456
|
+
read: "\uD83D\uDCD6",
|
|
23457
|
+
search: "\uD83D\uDD0D",
|
|
23458
|
+
execute: "\uD83D\uDCBB",
|
|
23459
|
+
edit: "✏️",
|
|
23460
|
+
think: "\uD83E\uDDE0",
|
|
23461
|
+
other: "\uD83D\uDD27"
|
|
23462
|
+
};
|
|
23463
|
+
DEFAULT_TOOL_EMOJI = TOOL_KIND_EMOJI.other;
|
|
23464
|
+
});
|
|
23465
|
+
|
|
23401
23466
|
// src/transport/streaming-prompt.ts
|
|
23402
|
-
function createStreamingPromptState(formatToolCalls = false) {
|
|
23467
|
+
function createStreamingPromptState(formatToolCalls = false, options) {
|
|
23468
|
+
let toolEventMode;
|
|
23469
|
+
let onToolEvent;
|
|
23470
|
+
if (options === undefined) {
|
|
23471
|
+
toolEventMode = "text";
|
|
23472
|
+
onToolEvent = undefined;
|
|
23473
|
+
} else if (typeof options === "function") {
|
|
23474
|
+
onToolEvent = options;
|
|
23475
|
+
toolEventMode = "structured";
|
|
23476
|
+
} else {
|
|
23477
|
+
onToolEvent = options.onToolEvent;
|
|
23478
|
+
toolEventMode = resolveToolEventMode({
|
|
23479
|
+
toolEventMode: options.mode,
|
|
23480
|
+
onToolEvent
|
|
23481
|
+
});
|
|
23482
|
+
}
|
|
23403
23483
|
return {
|
|
23404
23484
|
buffer: "",
|
|
23405
23485
|
segments: [],
|
|
@@ -23407,6 +23487,8 @@ function createStreamingPromptState(formatToolCalls = false) {
|
|
|
23407
23487
|
pendingLine: "",
|
|
23408
23488
|
formatToolCalls,
|
|
23409
23489
|
emittedToolCallIds: new Set,
|
|
23490
|
+
toolEventMode,
|
|
23491
|
+
onToolEvent,
|
|
23410
23492
|
finalize() {
|
|
23411
23493
|
if (this.pendingLine.trim().length > 0) {
|
|
23412
23494
|
parseStreamingChunks(this, this.pendingLine);
|
|
@@ -23444,15 +23526,24 @@ function parseStreamingChunks(state, line) {
|
|
|
23444
23526
|
if (!update)
|
|
23445
23527
|
return;
|
|
23446
23528
|
if (state.formatToolCalls && (update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update")) {
|
|
23447
|
-
const
|
|
23448
|
-
|
|
23449
|
-
|
|
23450
|
-
|
|
23451
|
-
|
|
23452
|
-
|
|
23453
|
-
|
|
23529
|
+
const wantsStructured = state.toolEventMode === "structured" || state.toolEventMode === "both";
|
|
23530
|
+
const wantsText = state.toolEventMode === "text" || state.toolEventMode === "both";
|
|
23531
|
+
if (wantsStructured && state.onToolEvent) {
|
|
23532
|
+
const toolEvent = buildToolUseEvent(update);
|
|
23533
|
+
if (toolEvent)
|
|
23534
|
+
state.onToolEvent(toolEvent);
|
|
23535
|
+
}
|
|
23536
|
+
if (wantsText) {
|
|
23537
|
+
const formatted = formatToolCallEvent(update, update.sessionUpdate);
|
|
23538
|
+
if (formatted) {
|
|
23539
|
+
const toolCallId = update.toolCallId;
|
|
23540
|
+
if (toolCallId) {
|
|
23541
|
+
if (state.emittedToolCallIds.has(toolCallId))
|
|
23542
|
+
return;
|
|
23543
|
+
state.emittedToolCallIds.add(toolCallId);
|
|
23544
|
+
}
|
|
23545
|
+
state.segments.push(formatted);
|
|
23454
23546
|
}
|
|
23455
|
-
state.segments.push(formatted);
|
|
23456
23547
|
}
|
|
23457
23548
|
return;
|
|
23458
23549
|
}
|
|
@@ -23482,27 +23573,71 @@ function formatToolCallEvent(update, sessionUpdate) {
|
|
|
23482
23573
|
const title = update.title ?? "";
|
|
23483
23574
|
if (title.length === 0)
|
|
23484
23575
|
return null;
|
|
23485
|
-
const emoji2 =
|
|
23486
|
-
const
|
|
23487
|
-
|
|
23488
|
-
|
|
23489
|
-
}
|
|
23490
|
-
if (sessionUpdate === "tool_call_update" || isGenericToolTitle(kind, title))
|
|
23576
|
+
const emoji2 = TOOL_KIND_EMOJI[kind] ?? DEFAULT_TOOL_EMOJI;
|
|
23577
|
+
const inputSummary = summarizeToolInput(update.rawInput, title);
|
|
23578
|
+
const status = readString(update, "status");
|
|
23579
|
+
if (!inputSummary && status === "pending")
|
|
23491
23580
|
return null;
|
|
23492
|
-
|
|
23581
|
+
if (!inputSummary && isGenericToolTitle(kind, title))
|
|
23582
|
+
return null;
|
|
23583
|
+
const summaryText = inputSummary && inputSummary !== title ? `: ${truncateToolDisplay(inputSummary)}` : "";
|
|
23584
|
+
const statusText = status ? ` (${status})` : "";
|
|
23585
|
+
return `${emoji2} ${title}${statusText}${summaryText}`;
|
|
23493
23586
|
}
|
|
23494
|
-
function
|
|
23587
|
+
function buildToolUseEvent(update) {
|
|
23495
23588
|
if (!update)
|
|
23496
23589
|
return null;
|
|
23497
|
-
const
|
|
23498
|
-
if (
|
|
23499
|
-
return
|
|
23590
|
+
const toolCallId = update.toolCallId;
|
|
23591
|
+
if (!toolCallId)
|
|
23592
|
+
return null;
|
|
23593
|
+
const kindRaw = update.kind ?? "";
|
|
23594
|
+
const kind = (() => {
|
|
23595
|
+
switch (kindRaw) {
|
|
23596
|
+
case "read":
|
|
23597
|
+
case "search":
|
|
23598
|
+
case "execute":
|
|
23599
|
+
case "edit":
|
|
23600
|
+
case "think":
|
|
23601
|
+
return kindRaw;
|
|
23602
|
+
default:
|
|
23603
|
+
return "other";
|
|
23604
|
+
}
|
|
23605
|
+
})();
|
|
23606
|
+
const title = (update.title ?? "").trim();
|
|
23607
|
+
const toolName = title || "Tool";
|
|
23608
|
+
const summaryRaw = summarizeToolInput(update.rawInput, title);
|
|
23609
|
+
const summary = summaryRaw && summaryRaw !== title ? summaryRaw : undefined;
|
|
23610
|
+
const statusRaw = readString(update, "status");
|
|
23611
|
+
const status = statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : "running";
|
|
23612
|
+
return {
|
|
23613
|
+
toolCallId,
|
|
23614
|
+
toolName,
|
|
23615
|
+
kind,
|
|
23616
|
+
...summary ? { summary } : {},
|
|
23617
|
+
status
|
|
23618
|
+
};
|
|
23619
|
+
}
|
|
23620
|
+
function summarizeToolInput(rawInput, title = "") {
|
|
23621
|
+
if (rawInput == null)
|
|
23622
|
+
return;
|
|
23623
|
+
if (typeof rawInput === "string" || typeof rawInput === "number" || typeof rawInput === "boolean") {
|
|
23624
|
+
return String(rawInput);
|
|
23625
|
+
}
|
|
23626
|
+
if (!isRecord3(rawInput))
|
|
23627
|
+
return;
|
|
23628
|
+
const taskSummary = summarizeTaskInput(rawInput, title);
|
|
23629
|
+
if (taskSummary)
|
|
23630
|
+
return taskSummary;
|
|
23631
|
+
const command = readFirstString(rawInput, ["command", "cmd", "program"]);
|
|
23632
|
+
const args = readFirstStringArray(rawInput, ["args", "arguments"]);
|
|
23633
|
+
if (command) {
|
|
23634
|
+
return [command, ...args ?? []].join(" ");
|
|
23500
23635
|
}
|
|
23501
|
-
const parsedCmd =
|
|
23502
|
-
if (parsedCmd && parsedCmd.length > 0) {
|
|
23636
|
+
const parsedCmd = rawInput.parsed_cmd;
|
|
23637
|
+
if (Array.isArray(parsedCmd) && parsedCmd.length > 0) {
|
|
23503
23638
|
const parts = [];
|
|
23504
23639
|
for (const entry of parsedCmd) {
|
|
23505
|
-
if (entry && typeof entry.cmd === "string" && entry.cmd.length > 0) {
|
|
23640
|
+
if (isRecord3(entry) && typeof entry.cmd === "string" && entry.cmd.length > 0) {
|
|
23506
23641
|
parts.push(entry.cmd);
|
|
23507
23642
|
}
|
|
23508
23643
|
}
|
|
@@ -23510,7 +23645,62 @@ function getToolDisplayCommand(update) {
|
|
|
23510
23645
|
return parts.join(" ");
|
|
23511
23646
|
}
|
|
23512
23647
|
}
|
|
23513
|
-
return
|
|
23648
|
+
return readFirstString(rawInput, [
|
|
23649
|
+
"path",
|
|
23650
|
+
"file",
|
|
23651
|
+
"filePath",
|
|
23652
|
+
"filepath",
|
|
23653
|
+
"file_path",
|
|
23654
|
+
"target",
|
|
23655
|
+
"uri",
|
|
23656
|
+
"url",
|
|
23657
|
+
"query",
|
|
23658
|
+
"pattern",
|
|
23659
|
+
"text",
|
|
23660
|
+
"search",
|
|
23661
|
+
"name",
|
|
23662
|
+
"description"
|
|
23663
|
+
]);
|
|
23664
|
+
}
|
|
23665
|
+
function summarizeTaskInput(rawInput, title) {
|
|
23666
|
+
const subagentType = readFirstString(rawInput, ["subagent_type", "subagentType", "agent", "agentType"]);
|
|
23667
|
+
const description = readFirstString(rawInput, ["description", "task", "summary"]);
|
|
23668
|
+
if (subagentType && description) {
|
|
23669
|
+
return description === title ? subagentType : `${subagentType}: ${description}`;
|
|
23670
|
+
}
|
|
23671
|
+
if (subagentType)
|
|
23672
|
+
return subagentType;
|
|
23673
|
+
return;
|
|
23674
|
+
}
|
|
23675
|
+
function readFirstString(record3, keys) {
|
|
23676
|
+
for (const key of keys) {
|
|
23677
|
+
const value = record3[key];
|
|
23678
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
23679
|
+
return value.trim();
|
|
23680
|
+
}
|
|
23681
|
+
}
|
|
23682
|
+
return;
|
|
23683
|
+
}
|
|
23684
|
+
function readFirstStringArray(record3, keys) {
|
|
23685
|
+
for (const key of keys) {
|
|
23686
|
+
const value = record3[key];
|
|
23687
|
+
if (!Array.isArray(value))
|
|
23688
|
+
continue;
|
|
23689
|
+
const entries = value.map((entry) => typeof entry === "string" && entry.trim().length > 0 ? entry.trim() : undefined).filter((entry) => entry !== undefined);
|
|
23690
|
+
if (entries.length > 0) {
|
|
23691
|
+
return entries;
|
|
23692
|
+
}
|
|
23693
|
+
}
|
|
23694
|
+
return;
|
|
23695
|
+
}
|
|
23696
|
+
function isRecord3(value) {
|
|
23697
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23698
|
+
}
|
|
23699
|
+
function readString(rawInput, key) {
|
|
23700
|
+
if (!isRecord3(rawInput))
|
|
23701
|
+
return;
|
|
23702
|
+
const value = rawInput[key];
|
|
23703
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
23514
23704
|
}
|
|
23515
23705
|
function truncateToolDisplay(text) {
|
|
23516
23706
|
return text.length > 60 ? `${text.slice(0, 57)}...` : text;
|
|
@@ -23528,14 +23718,8 @@ function isGenericToolTitle(kind, title) {
|
|
|
23528
23718
|
}
|
|
23529
23719
|
return false;
|
|
23530
23720
|
}
|
|
23531
|
-
var KIND_EMOJI;
|
|
23532
23721
|
var init_streaming_prompt = __esm(() => {
|
|
23533
|
-
|
|
23534
|
-
read: "\uD83D\uDCD6",
|
|
23535
|
-
search: "\uD83D\uDD0D",
|
|
23536
|
-
execute: "\uD83D\uDCBB",
|
|
23537
|
-
edit: "✏️"
|
|
23538
|
-
};
|
|
23722
|
+
init_tool_kind_emoji();
|
|
23539
23723
|
});
|
|
23540
23724
|
|
|
23541
23725
|
// src/transport/acpx-cli/node-pty-helper.ts
|
|
@@ -23845,7 +24029,8 @@ class AcpxCliTransport {
|
|
|
23845
24029
|
runCommand;
|
|
23846
24030
|
runPtyCommand;
|
|
23847
24031
|
queueOwnerLauncher;
|
|
23848
|
-
|
|
24032
|
+
streamingHooks;
|
|
24033
|
+
constructor(options, runCommand = defaultRunner, runPtyCommand = defaultPtyRunner, queueOwnerLauncher, streamingHooks = {}) {
|
|
23849
24034
|
this.command = options.command ?? "acpx";
|
|
23850
24035
|
this.sessionInitTimeoutMs = options.sessionInitTimeoutMs ?? 120000;
|
|
23851
24036
|
this.permissionMode = options.permissionMode ?? "approve-all";
|
|
@@ -23855,6 +24040,7 @@ class AcpxCliTransport {
|
|
|
23855
24040
|
this.queueOwnerLauncher = queueOwnerLauncher ?? new AcpxQueueOwnerLauncher({
|
|
23856
24041
|
acpxCommand: this.command
|
|
23857
24042
|
});
|
|
24043
|
+
this.streamingHooks = streamingHooks;
|
|
23858
24044
|
}
|
|
23859
24045
|
async ensureSession(session, _onProgress) {
|
|
23860
24046
|
const args = this.buildArgs(session, [
|
|
@@ -23873,9 +24059,13 @@ class AcpxCliTransport {
|
|
|
23873
24059
|
const structuredPrompt = await createStructuredPromptFile(text, options?.media);
|
|
23874
24060
|
const args = this.buildPromptArgs(session, text, structuredPrompt?.filePath);
|
|
23875
24061
|
try {
|
|
23876
|
-
if (reply || options?.onSegment) {
|
|
23877
|
-
const formatToolCalls = session.replyMode === "verbose";
|
|
23878
|
-
|
|
24062
|
+
if (reply || options?.onSegment || options?.onToolEvent) {
|
|
24063
|
+
const formatToolCalls = (session.replyMode ?? "verbose") === "verbose";
|
|
24064
|
+
let toolEventMode = resolveToolEventMode(options);
|
|
24065
|
+
if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
|
|
24066
|
+
toolEventMode = "text";
|
|
24067
|
+
}
|
|
24068
|
+
const { result: result2, overflowCount } = await this.runStreamingPrompt(this.command, args, reply, formatToolCalls, toolEventMode, replyContext, options?.onSegment, options?.onToolEvent);
|
|
23879
24069
|
const baseText = getPromptText(result2);
|
|
23880
24070
|
if (!reply) {
|
|
23881
24071
|
return { text: baseText };
|
|
@@ -24012,16 +24202,35 @@ ${baseText}` : "" };
|
|
|
24012
24202
|
})
|
|
24013
24203
|
]);
|
|
24014
24204
|
}
|
|
24015
|
-
async runStreamingPrompt(command, args, reply,
|
|
24205
|
+
async runStreamingPrompt(command, args, reply, formatToolCalls = false, toolEventMode = "text", replyContext, onSegment, onToolEvent) {
|
|
24206
|
+
const hooks = this.streamingHooks;
|
|
24207
|
+
const doSpawn = hooks.spawnPrompt ?? ((cmd, spawnArgs) => spawn8(cmd, spawnArgs, { stdio: ["ignore", "pipe", "pipe"] }));
|
|
24208
|
+
const setIntervalFn = hooks.setIntervalFn ?? ((fn, delay) => setInterval(fn, delay));
|
|
24209
|
+
const clearIntervalFn = hooks.clearIntervalFn ?? ((timer) => clearInterval(timer));
|
|
24210
|
+
const maxSegmentWaitMs = hooks.maxSegmentWaitMs ?? 30000;
|
|
24211
|
+
const flushCheckIntervalMs = hooks.flushCheckIntervalMs ?? 5000;
|
|
24212
|
+
const now = hooks.now ?? (() => Date.now());
|
|
24016
24213
|
return await new Promise((resolve3, reject) => {
|
|
24017
24214
|
const spawnSpec = resolveSpawnCommand(command, args);
|
|
24018
|
-
const child =
|
|
24215
|
+
const child = doSpawn(spawnSpec.command, spawnSpec.args);
|
|
24019
24216
|
let stdout2 = "";
|
|
24020
24217
|
let stderr = "";
|
|
24021
|
-
|
|
24022
|
-
let lastReplyAt = Date.now();
|
|
24218
|
+
let lastReplyAt = now();
|
|
24023
24219
|
let segmentChain = Promise.resolve();
|
|
24024
24220
|
let segmentError;
|
|
24221
|
+
let toolEventChain = Promise.resolve();
|
|
24222
|
+
let toolEventError;
|
|
24223
|
+
const userOnToolEvent = onToolEvent;
|
|
24224
|
+
const state = createStreamingPromptState(formatToolCalls, {
|
|
24225
|
+
mode: toolEventMode,
|
|
24226
|
+
...userOnToolEvent ? {
|
|
24227
|
+
onToolEvent: (event) => {
|
|
24228
|
+
toolEventChain = toolEventChain.then(() => userOnToolEvent(event)).catch((error2) => {
|
|
24229
|
+
toolEventError ??= error2;
|
|
24230
|
+
});
|
|
24231
|
+
}
|
|
24232
|
+
} : {}
|
|
24233
|
+
});
|
|
24025
24234
|
const sink = reply ? createQuotaGatedReplySink({
|
|
24026
24235
|
reply,
|
|
24027
24236
|
...replyContext ? { replyContext } : {}
|
|
@@ -24033,7 +24242,7 @@ ${baseText}` : "" };
|
|
|
24033
24242
|
});
|
|
24034
24243
|
}
|
|
24035
24244
|
sink?.feedSegment(segment);
|
|
24036
|
-
lastReplyAt =
|
|
24245
|
+
lastReplyAt = now();
|
|
24037
24246
|
};
|
|
24038
24247
|
const flushBuffer = () => {
|
|
24039
24248
|
const remaining = state.buffer.trim();
|
|
@@ -24042,11 +24251,11 @@ ${baseText}` : "" };
|
|
|
24042
24251
|
feedSegment(remaining);
|
|
24043
24252
|
}
|
|
24044
24253
|
};
|
|
24045
|
-
const timer =
|
|
24046
|
-
if (state.buffer.trim().length > 0 &&
|
|
24254
|
+
const timer = setIntervalFn(() => {
|
|
24255
|
+
if (state.buffer.trim().length > 0 && now() - lastReplyAt >= maxSegmentWaitMs) {
|
|
24047
24256
|
flushBuffer();
|
|
24048
24257
|
}
|
|
24049
|
-
},
|
|
24258
|
+
}, flushCheckIntervalMs);
|
|
24050
24259
|
child.stdout.setEncoding("utf8");
|
|
24051
24260
|
child.stdout.on("data", (chunk) => {
|
|
24052
24261
|
stdout2 += String(chunk);
|
|
@@ -24059,11 +24268,11 @@ ${baseText}` : "" };
|
|
|
24059
24268
|
stderr += String(chunk);
|
|
24060
24269
|
});
|
|
24061
24270
|
child.on("error", (err) => {
|
|
24062
|
-
|
|
24271
|
+
clearIntervalFn(timer);
|
|
24063
24272
|
reject(err);
|
|
24064
24273
|
});
|
|
24065
24274
|
child.on("close", (code) => {
|
|
24066
|
-
|
|
24275
|
+
clearIntervalFn(timer);
|
|
24067
24276
|
const remaining = state.finalize();
|
|
24068
24277
|
if (remaining.length > 0) {
|
|
24069
24278
|
feedSegment(remaining);
|
|
@@ -24071,7 +24280,8 @@ ${baseText}` : "" };
|
|
|
24071
24280
|
const { overflowCount } = sink?.finalize() ?? { overflowCount: 0 };
|
|
24072
24281
|
Promise.all([
|
|
24073
24282
|
sink?.drain({ timeoutMs: 30000 }) ?? Promise.resolve(),
|
|
24074
|
-
segmentChain
|
|
24283
|
+
segmentChain,
|
|
24284
|
+
toolEventChain
|
|
24075
24285
|
]).then(() => {
|
|
24076
24286
|
const deferred = sink?.getPendingError();
|
|
24077
24287
|
if (deferred) {
|
|
@@ -24082,6 +24292,10 @@ ${baseText}` : "" };
|
|
|
24082
24292
|
reject(segmentError);
|
|
24083
24293
|
return;
|
|
24084
24294
|
}
|
|
24295
|
+
if (toolEventError) {
|
|
24296
|
+
reject(toolEventError);
|
|
24297
|
+
return;
|
|
24298
|
+
}
|
|
24085
24299
|
resolve3({
|
|
24086
24300
|
result: { code: code ?? 1, stdout: stdout2, stderr },
|
|
24087
24301
|
overflowCount
|
|
@@ -25068,7 +25282,7 @@ async function checkDaemon(options = {}) {
|
|
|
25068
25282
|
cliEntryPath: options.cliEntryPath ?? resolveCliEntryPath(),
|
|
25069
25283
|
cwd: options.cwd ?? process.cwd(),
|
|
25070
25284
|
env: options.env ?? process.env,
|
|
25071
|
-
isProcessRunning: options.isProcessRunning ??
|
|
25285
|
+
isProcessRunning: options.isProcessRunning ?? defaultIsProcessRunning5
|
|
25072
25286
|
});
|
|
25073
25287
|
try {
|
|
25074
25288
|
const status = await controller.getStatus();
|
|
@@ -25139,7 +25353,7 @@ async function checkDaemon(options = {}) {
|
|
|
25139
25353
|
};
|
|
25140
25354
|
}
|
|
25141
25355
|
}
|
|
25142
|
-
function
|
|
25356
|
+
function defaultIsProcessRunning5(pid) {
|
|
25143
25357
|
try {
|
|
25144
25358
|
process.kill(pid, 0);
|
|
25145
25359
|
return true;
|
|
@@ -38385,7 +38599,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38385
38599
|
return [
|
|
38386
38600
|
{
|
|
38387
38601
|
name: "delegate_request",
|
|
38388
|
-
description: `Delegate a subtask to another agent under the current coordinator.${availableAgents && availableAgents.length > 0 ? ` Available agents: ${availableAgents.join(", ")}.` : ""}`,
|
|
38602
|
+
description: `Delegate a subtask to another agent under the current coordinator. Pass an absolute workingDirectory for the worker.${availableAgents && availableAgents.length > 0 ? ` Available agents: ${availableAgents.join(", ")}.` : ""}`,
|
|
38389
38603
|
inputSchema: exports_external.object({
|
|
38390
38604
|
targetAgent: exports_external.string().min(1),
|
|
38391
38605
|
task: exports_external.string().min(1),
|
|
@@ -38400,12 +38614,12 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38400
38614
|
...sourceHandle ? { sourceHandle } : {},
|
|
38401
38615
|
...input2
|
|
38402
38616
|
});
|
|
38403
|
-
return createSuccessResult(
|
|
38617
|
+
return createSuccessResult(renderDelegateSuccess(result), result);
|
|
38404
38618
|
})
|
|
38405
38619
|
},
|
|
38406
38620
|
{
|
|
38407
38621
|
name: "group_new",
|
|
38408
|
-
description: "Create a new task group
|
|
38622
|
+
description: "Create a new task group under the current coordinator.",
|
|
38409
38623
|
inputSchema: exports_external.object({
|
|
38410
38624
|
title: exports_external.string().min(1)
|
|
38411
38625
|
}).strict(),
|
|
@@ -38414,12 +38628,12 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38414
38628
|
coordinatorSession,
|
|
38415
38629
|
title: args.title
|
|
38416
38630
|
});
|
|
38417
|
-
return createSuccessResult(
|
|
38631
|
+
return createSuccessResult(renderGroupCreated(group), group);
|
|
38418
38632
|
})
|
|
38419
38633
|
},
|
|
38420
38634
|
{
|
|
38421
38635
|
name: "group_get",
|
|
38422
|
-
description: "Fetch a single task
|
|
38636
|
+
description: "Fetch a single task-group summary under the current coordinator.",
|
|
38423
38637
|
inputSchema: exports_external.object({
|
|
38424
38638
|
groupId: exports_external.string().min(1)
|
|
38425
38639
|
}).strict(),
|
|
@@ -38433,7 +38647,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38433
38647
|
},
|
|
38434
38648
|
{
|
|
38435
38649
|
name: "group_list",
|
|
38436
|
-
description: "List task groups
|
|
38650
|
+
description: "List task groups under the current coordinator.",
|
|
38437
38651
|
inputSchema: exports_external.object({
|
|
38438
38652
|
status: groupStatusSchema.optional(),
|
|
38439
38653
|
stuck: exports_external.boolean().optional(),
|
|
@@ -38454,7 +38668,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38454
38668
|
},
|
|
38455
38669
|
{
|
|
38456
38670
|
name: "group_cancel",
|
|
38457
|
-
description: "Cancel all unfinished tasks in a task group
|
|
38671
|
+
description: "Cancel all unfinished tasks in a task group under the current coordinator.",
|
|
38458
38672
|
inputSchema: exports_external.object({
|
|
38459
38673
|
groupId: exports_external.string().min(1)
|
|
38460
38674
|
}).strict(),
|
|
@@ -38468,7 +38682,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38468
38682
|
},
|
|
38469
38683
|
{
|
|
38470
38684
|
name: "task_get",
|
|
38471
|
-
description: "Fetch a single
|
|
38685
|
+
description: "Fetch a single task under the current coordinator.",
|
|
38472
38686
|
inputSchema: exports_external.object({
|
|
38473
38687
|
taskId: exports_external.string().min(1)
|
|
38474
38688
|
}).strict(),
|
|
@@ -38482,7 +38696,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38482
38696
|
},
|
|
38483
38697
|
{
|
|
38484
38698
|
name: "task_list",
|
|
38485
|
-
description: "List
|
|
38699
|
+
description: "List tasks under the current coordinator.",
|
|
38486
38700
|
inputSchema: exports_external.object({
|
|
38487
38701
|
status: taskStatusSchema.optional(),
|
|
38488
38702
|
stuck: exports_external.boolean().optional(),
|
|
@@ -38503,7 +38717,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38503
38717
|
},
|
|
38504
38718
|
{
|
|
38505
38719
|
name: "task_approve",
|
|
38506
|
-
description: "Approve a pending
|
|
38720
|
+
description: "Approve a pending task under the current coordinator.",
|
|
38507
38721
|
inputSchema: exports_external.object({
|
|
38508
38722
|
taskId: exports_external.string().min(1)
|
|
38509
38723
|
}).strict(),
|
|
@@ -38517,7 +38731,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38517
38731
|
},
|
|
38518
38732
|
{
|
|
38519
38733
|
name: "task_reject",
|
|
38520
|
-
description: "Reject a pending
|
|
38734
|
+
description: "Reject a pending task under the current coordinator.",
|
|
38521
38735
|
inputSchema: exports_external.object({
|
|
38522
38736
|
taskId: exports_external.string().min(1)
|
|
38523
38737
|
}).strict(),
|
|
@@ -38531,7 +38745,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38531
38745
|
},
|
|
38532
38746
|
{
|
|
38533
38747
|
name: "task_cancel",
|
|
38534
|
-
description: "Request cancellation for
|
|
38748
|
+
description: "Request cancellation for a task under the current coordinator.",
|
|
38535
38749
|
inputSchema: exports_external.object({
|
|
38536
38750
|
taskId: exports_external.string().min(1)
|
|
38537
38751
|
}).strict(),
|
|
@@ -38540,12 +38754,12 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38540
38754
|
coordinatorSession,
|
|
38541
38755
|
taskId: args.taskId
|
|
38542
38756
|
});
|
|
38543
|
-
return createSuccessResult(
|
|
38757
|
+
return createSuccessResult(renderTaskCancelRequest(task), task);
|
|
38544
38758
|
})
|
|
38545
38759
|
},
|
|
38546
38760
|
{
|
|
38547
38761
|
name: "task_wait",
|
|
38548
|
-
description:
|
|
38762
|
+
description: `Wait for a task to finish or require attention. Defaults: timeout ${DEFAULT_TASK_WAIT_TIMEOUT_MS} ms, poll interval ${DEFAULT_TASK_WAIT_POLL_INTERVAL_MS} ms. Maximums: timeout ${MAX_TASK_WAIT_TIMEOUT_MS} ms, poll interval ${MAX_TASK_WAIT_POLL_INTERVAL_MS} ms.`,
|
|
38549
38763
|
inputSchema: exports_external.object({
|
|
38550
38764
|
taskId: exports_external.string().min(1),
|
|
38551
38765
|
timeoutMs: exports_external.number().int().min(0).max(MAX_TASK_WAIT_TIMEOUT_MS).optional(),
|
|
@@ -38561,7 +38775,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38561
38775
|
},
|
|
38562
38776
|
{
|
|
38563
38777
|
name: "worker_raise_question",
|
|
38564
|
-
description: "Raise a blocker question for the current bound session.",
|
|
38778
|
+
description: "Raise a blocker question for the current bound worker session.",
|
|
38565
38779
|
inputSchema: exports_external.object({
|
|
38566
38780
|
taskId: exports_external.string().min(1),
|
|
38567
38781
|
question: exports_external.string().min(1),
|
|
@@ -38576,8 +38790,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38576
38790
|
sourceHandle,
|
|
38577
38791
|
...args
|
|
38578
38792
|
});
|
|
38579
|
-
return createSuccessResult(
|
|
38580
|
-
`), result);
|
|
38793
|
+
return createSuccessResult(renderWorkerRaiseQuestionSuccess(result), result);
|
|
38581
38794
|
})
|
|
38582
38795
|
},
|
|
38583
38796
|
{
|
|
@@ -38593,8 +38806,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38593
38806
|
coordinatorSession,
|
|
38594
38807
|
...args
|
|
38595
38808
|
});
|
|
38596
|
-
return createSuccessResult(
|
|
38597
|
-
`), task);
|
|
38809
|
+
return createSuccessResult(renderCoordinatorAnswerQuestionSuccess(task), task);
|
|
38598
38810
|
})
|
|
38599
38811
|
},
|
|
38600
38812
|
{
|
|
@@ -38610,10 +38822,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38610
38822
|
coordinatorSession,
|
|
38611
38823
|
...args
|
|
38612
38824
|
});
|
|
38613
|
-
|
|
38614
|
-
`) : [`问题已加入当前 human question queue。`, `- 已排队任务:${result.queuedTaskIds.length}`].join(`
|
|
38615
|
-
`);
|
|
38616
|
-
return createSuccessResult(text, result);
|
|
38825
|
+
return createSuccessResult(renderCoordinatorRequestHumanInputSuccess(result), result);
|
|
38617
38826
|
})
|
|
38618
38827
|
},
|
|
38619
38828
|
{
|
|
@@ -38630,13 +38839,12 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38630
38839
|
coordinatorSession,
|
|
38631
38840
|
...args
|
|
38632
38841
|
});
|
|
38633
|
-
return createSuccessResult(
|
|
38634
|
-
`), result);
|
|
38842
|
+
return createSuccessResult(renderCoordinatorFollowUpHumanPackageSuccess(result), result);
|
|
38635
38843
|
})
|
|
38636
38844
|
},
|
|
38637
38845
|
{
|
|
38638
38846
|
name: "coordinator_review_contested_result",
|
|
38639
|
-
description: "Review a contested
|
|
38847
|
+
description: "Review a contested result under the current coordinator.",
|
|
38640
38848
|
inputSchema: exports_external.object({
|
|
38641
38849
|
taskId: exports_external.string().min(1),
|
|
38642
38850
|
reviewId: exports_external.string().min(1),
|
|
@@ -38649,9 +38857,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
38649
38857
|
decision,
|
|
38650
38858
|
...rest
|
|
38651
38859
|
});
|
|
38652
|
-
|
|
38653
|
-
return createSuccessResult([`${actionText}任务「${task.taskId}」的 contested result。`, `- 当前状态:${task.status}`].join(`
|
|
38654
|
-
`), task);
|
|
38860
|
+
return createSuccessResult(renderCoordinatorReviewContestedResultSuccess(task, decision), task);
|
|
38655
38861
|
})
|
|
38656
38862
|
}
|
|
38657
38863
|
];
|
|
@@ -38702,10 +38908,185 @@ function createErrorResult(message) {
|
|
|
38702
38908
|
isError: true
|
|
38703
38909
|
};
|
|
38704
38910
|
}
|
|
38911
|
+
function renderDelegateSuccess(result) {
|
|
38912
|
+
return [`Delegation task "${result.taskId}" created.`, `- Status: ${result.status}`].join(`
|
|
38913
|
+
`);
|
|
38914
|
+
}
|
|
38915
|
+
function renderGroupCreated(group) {
|
|
38916
|
+
return [`Task group "${group.groupId}" created.`, `- Title: ${group.title}`].join(`
|
|
38917
|
+
`);
|
|
38918
|
+
}
|
|
38919
|
+
function renderGroupSummary(summary) {
|
|
38920
|
+
const { group, tasks } = summary;
|
|
38921
|
+
const lines = [
|
|
38922
|
+
`Task group "${group.groupId}"`,
|
|
38923
|
+
`- Title: ${group.title}`,
|
|
38924
|
+
`- Coordinator session: ${group.coordinatorSession}`,
|
|
38925
|
+
`- Total tasks: ${summary.totalTasks}`,
|
|
38926
|
+
`- Pending approval: ${summary.pendingApprovalTasks}`,
|
|
38927
|
+
`- Running: ${summary.runningTasks}`,
|
|
38928
|
+
`- Completed: ${summary.completedTasks}`,
|
|
38929
|
+
`- Failed: ${summary.failedTasks}`,
|
|
38930
|
+
`- Cancelled: ${summary.cancelledTasks}`,
|
|
38931
|
+
`- Terminal: ${summary.terminal ? "yes" : "no"}`
|
|
38932
|
+
];
|
|
38933
|
+
if (group.injectionPending !== undefined) {
|
|
38934
|
+
lines.push(`- Injection pending: ${group.injectionPending ? "yes" : "no"}`);
|
|
38935
|
+
}
|
|
38936
|
+
if (group.injectionAppliedAt) {
|
|
38937
|
+
lines.push(`- Injection completed at: ${group.injectionAppliedAt}`);
|
|
38938
|
+
}
|
|
38939
|
+
if (group.lastInjectionError) {
|
|
38940
|
+
lines.push(`- Last injection error: ${group.lastInjectionError}`);
|
|
38941
|
+
}
|
|
38942
|
+
if (tasks.length > 0) {
|
|
38943
|
+
lines.push("- Members:");
|
|
38944
|
+
for (const task of tasks) {
|
|
38945
|
+
lines.push(` - ${task.taskId} [${task.status}] ${task.targetAgent}`);
|
|
38946
|
+
}
|
|
38947
|
+
}
|
|
38948
|
+
return lines.join(`
|
|
38949
|
+
`);
|
|
38950
|
+
}
|
|
38951
|
+
function renderGroupList(groups) {
|
|
38952
|
+
if (groups.length === 0) {
|
|
38953
|
+
return "There are no task groups under the current coordinator.";
|
|
38954
|
+
}
|
|
38955
|
+
return ["Task groups for the current coordinator:", ...groups.map((group) => renderGroupListItem(group))].join(`
|
|
38956
|
+
`);
|
|
38957
|
+
}
|
|
38958
|
+
function renderGroupListItem(group) {
|
|
38959
|
+
const reliability = group.group.injectionPending ? " | injection pending" : "";
|
|
38960
|
+
return [
|
|
38961
|
+
`- ${group.group.groupId}`,
|
|
38962
|
+
group.group.title,
|
|
38963
|
+
`total ${group.totalTasks}`,
|
|
38964
|
+
`pending ${group.pendingApprovalTasks}`,
|
|
38965
|
+
`running ${group.runningTasks}`,
|
|
38966
|
+
`completed ${group.completedTasks}`,
|
|
38967
|
+
`failed ${group.failedTasks}`,
|
|
38968
|
+
`cancelled ${group.cancelledTasks}${reliability}`
|
|
38969
|
+
].join(" | ");
|
|
38970
|
+
}
|
|
38971
|
+
function renderGroupCancelSuccess(input) {
|
|
38972
|
+
return [
|
|
38973
|
+
`Task group "${input.summary.group.groupId}" cancellation requested.`,
|
|
38974
|
+
`- Cancel requested: ${input.cancelledTaskIds.length}`,
|
|
38975
|
+
`- Skipped terminal tasks: ${input.skippedTaskIds.length}`
|
|
38976
|
+
].join(`
|
|
38977
|
+
`);
|
|
38978
|
+
}
|
|
38979
|
+
function renderTaskList(tasks) {
|
|
38980
|
+
if (tasks.length === 0) {
|
|
38981
|
+
return "There are no tasks under the current coordinator.";
|
|
38982
|
+
}
|
|
38983
|
+
return ["Tasks for the current coordinator:", ...tasks.map((task) => renderTaskListItem(task))].join(`
|
|
38984
|
+
`);
|
|
38985
|
+
}
|
|
38986
|
+
function renderTaskListItem(task) {
|
|
38987
|
+
const role = task.role ? ` / ${task.role}` : "";
|
|
38988
|
+
const group = task.groupId ? `; group: ${task.groupId}` : "";
|
|
38989
|
+
const summary = task.summary.trim().length > 0 ? `: ${task.summary}` : "";
|
|
38990
|
+
const source = task.status === "needs_confirmation" ? `; source: ${task.targetAgent}${task.role ? ` / ${task.role}` : ""}` : "";
|
|
38991
|
+
const reliability = [
|
|
38992
|
+
task.noticePending ? "notice pending retry" : "",
|
|
38993
|
+
task.injectionPending ? "injection pending retry" : "",
|
|
38994
|
+
task.cancelRequestedAt && !task.cancelCompletedAt && task.status === "running" ? "cancelling" : ""
|
|
38995
|
+
].filter(Boolean).map((item) => `; ${item}`).join("");
|
|
38996
|
+
return `- ${task.taskId} [${task.status}] ${task.targetAgent}${role} -> ${task.workerSession ?? "unassigned"}${group}${source}${summary}${reliability}`;
|
|
38997
|
+
}
|
|
38998
|
+
function renderTaskSummary(task) {
|
|
38999
|
+
const header = [
|
|
39000
|
+
`Task "${task.taskId}"`,
|
|
39001
|
+
`- Status: ${task.status}`,
|
|
39002
|
+
`- Coordinator session: ${task.coordinatorSession}`,
|
|
39003
|
+
`- Worker session: ${task.workerSession ?? "unassigned"}`,
|
|
39004
|
+
`- Target agent: ${task.targetAgent}`
|
|
39005
|
+
];
|
|
39006
|
+
if (task.role)
|
|
39007
|
+
header.push(`- Role: ${task.role}`);
|
|
39008
|
+
if (task.groupId)
|
|
39009
|
+
header.push(`- Group: ${task.groupId}`);
|
|
39010
|
+
if (task.status === "needs_confirmation") {
|
|
39011
|
+
header.push(`- Source: ${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}`);
|
|
39012
|
+
}
|
|
39013
|
+
header.push(`- Task: ${task.task}`);
|
|
39014
|
+
if (task.summary.trim().length > 0)
|
|
39015
|
+
header.push(`- Summary: ${task.summary}`);
|
|
39016
|
+
if (task.resultText.trim().length > 0)
|
|
39017
|
+
header.push(`- Result: ${task.resultText}`);
|
|
39018
|
+
const events = [];
|
|
39019
|
+
events.push({ at: task.createdAt, event: "created" });
|
|
39020
|
+
if (task.workerSession && task.status !== "needs_confirmation") {
|
|
39021
|
+
events.push({ at: task.createdAt, event: "dispatched", detail: task.workerSession });
|
|
39022
|
+
}
|
|
39023
|
+
if (task.lastProgressAt)
|
|
39024
|
+
events.push({ at: task.lastProgressAt, event: "last progress" });
|
|
39025
|
+
if (task.cancelRequestedAt)
|
|
39026
|
+
events.push({ at: task.cancelRequestedAt, event: "cancel requested" });
|
|
39027
|
+
if (task.cancelCompletedAt)
|
|
39028
|
+
events.push({ at: task.cancelCompletedAt, event: "cancel completed" });
|
|
39029
|
+
if (task.lastCancelError)
|
|
39030
|
+
events.push({ at: task.updatedAt, event: "cancel failed", detail: task.lastCancelError });
|
|
39031
|
+
if (task.status === "completed")
|
|
39032
|
+
events.push({ at: task.updatedAt, event: "completed" });
|
|
39033
|
+
if (task.status === "failed")
|
|
39034
|
+
events.push({ at: task.updatedAt, event: "failed" });
|
|
39035
|
+
if (task.noticeSentAt)
|
|
39036
|
+
events.push({ at: task.noticeSentAt, event: "notice sent", detail: task.deliveryAccountId });
|
|
39037
|
+
if (task.lastNoticeError)
|
|
39038
|
+
events.push({ at: task.updatedAt, event: "notice failed", detail: task.lastNoticeError });
|
|
39039
|
+
if (task.injectionAppliedAt)
|
|
39040
|
+
events.push({ at: task.injectionAppliedAt, event: "injection applied" });
|
|
39041
|
+
if (task.lastInjectionError)
|
|
39042
|
+
events.push({ at: task.updatedAt, event: "injection failed", detail: task.lastInjectionError });
|
|
39043
|
+
events.sort((a, b) => a.at.localeCompare(b.at));
|
|
39044
|
+
const timeline = events.length > 0 ? ["- Timeline:", ...events.map((e) => ` - [${e.at}] ${e.event}${e.detail ? `: ${e.detail}` : ""}`)] : [];
|
|
39045
|
+
return [...header, ...timeline].join(`
|
|
39046
|
+
`);
|
|
39047
|
+
}
|
|
39048
|
+
function renderTaskCancelRequest(task) {
|
|
39049
|
+
if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
|
|
39050
|
+
return [`Task "${task.taskId}" has already finished.`, `- Current status: ${task.status}`].join(`
|
|
39051
|
+
`);
|
|
39052
|
+
}
|
|
39053
|
+
return [`Cancellation requested for task "${task.taskId}".`, `- Current status: ${task.status}`].join(`
|
|
39054
|
+
`);
|
|
39055
|
+
}
|
|
39056
|
+
function renderTaskApprovalSuccess(task) {
|
|
39057
|
+
return [`Task "${task.taskId}" approved.`, `- Current status: ${task.status}`].join(`
|
|
39058
|
+
`);
|
|
39059
|
+
}
|
|
39060
|
+
function renderTaskRejectionSuccess(task) {
|
|
39061
|
+
return [`Task "${task.taskId}" rejected.`, `- Current status: ${task.status}`].join(`
|
|
39062
|
+
`);
|
|
39063
|
+
}
|
|
39064
|
+
function renderWorkerRaiseQuestionSuccess(task) {
|
|
39065
|
+
return [`Blocker question submitted for task "${task.taskId}".`, `- questionId: ${task.questionId}`].join(`
|
|
39066
|
+
`);
|
|
39067
|
+
}
|
|
39068
|
+
function renderCoordinatorAnswerQuestionSuccess(task) {
|
|
39069
|
+
return [`Answered the blocker question for task "${task.taskId}".`, `- Current status: ${task.status}`].join(`
|
|
39070
|
+
`);
|
|
39071
|
+
}
|
|
39072
|
+
function renderCoordinatorRequestHumanInputSuccess(result) {
|
|
39073
|
+
return result.packageId ? [`Created human question package "${result.packageId}".`, `- Queued tasks: ${result.queuedTaskIds.length}`].join(`
|
|
39074
|
+
`) : [`Queued the question in the current human question queue.`, `- Queued tasks: ${result.queuedTaskIds.length}`].join(`
|
|
39075
|
+
`);
|
|
39076
|
+
}
|
|
39077
|
+
function renderCoordinatorFollowUpHumanPackageSuccess(result) {
|
|
39078
|
+
return [`Appended follow-up to human package "${result.packageId}".`, `- messageId: ${result.messageId}`].join(`
|
|
39079
|
+
`);
|
|
39080
|
+
}
|
|
39081
|
+
function renderCoordinatorReviewContestedResultSuccess(task, decision) {
|
|
39082
|
+
const actionText = decision === "accept" ? "Accepted" : "Discarded";
|
|
39083
|
+
return [`${actionText} contested result for task "${task.taskId}".`, `- Current status: ${task.status}`].join(`
|
|
39084
|
+
`);
|
|
39085
|
+
}
|
|
38705
39086
|
function formatToolError(error2) {
|
|
38706
39087
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
38707
39088
|
if (/ECONNREFUSED|ENOENT|server closed without a response|socket hang up|connect /i.test(message)) {
|
|
38708
|
-
return
|
|
39089
|
+
return `Failed to connect to the orchestration daemon: ${message}`;
|
|
38709
39090
|
}
|
|
38710
39091
|
return message;
|
|
38711
39092
|
}
|
|
@@ -38925,6 +39306,9 @@ function createWeacpxMcpServer(options) {
|
|
|
38925
39306
|
return await toolStatePromise;
|
|
38926
39307
|
}
|
|
38927
39308
|
toolStatePromise = resolveMcpIdentity(server, options).then((identity) => {
|
|
39309
|
+
if (!options.transport) {
|
|
39310
|
+
throw new Error("weacpx MCP transport is not configured");
|
|
39311
|
+
}
|
|
38928
39312
|
toolState = buildToolState({
|
|
38929
39313
|
transport: options.transport,
|
|
38930
39314
|
coordinatorSession: identity.coordinatorSession,
|
|
@@ -38983,8 +39367,84 @@ async function resolveMcpIdentity(server, options) {
|
|
|
38983
39367
|
}
|
|
38984
39368
|
throw new McpError(ErrorCode.InvalidRequest, "weacpx MCP identity is not configured; run through `weacpx mcp-stdio` or provide --coordinator-session");
|
|
38985
39369
|
}
|
|
39370
|
+
function installMcpStdioShutdownHooks(options) {
|
|
39371
|
+
const platform = options.platform ?? process.platform;
|
|
39372
|
+
const signalSource = options.signalSource ?? process;
|
|
39373
|
+
const isProcessRunning = options.isProcessRunning ?? defaultIsProcessRunning3;
|
|
39374
|
+
const setIntervalFn = options.setIntervalFn ?? ((callback, ms) => setInterval(callback, ms));
|
|
39375
|
+
const clearIntervalFn = options.clearIntervalFn ?? ((handle) => clearInterval(handle));
|
|
39376
|
+
const parentPid = options.parentPid ?? process.ppid;
|
|
39377
|
+
const parentCheckIntervalMs = options.parentCheckIntervalMs ?? parseParentCheckIntervalMs(process.env.WEACPX_MCP_PARENT_CHECK_INTERVAL_MS);
|
|
39378
|
+
let disposed = false;
|
|
39379
|
+
const triggerShutdown = (reason, context) => {
|
|
39380
|
+
if (disposed)
|
|
39381
|
+
return;
|
|
39382
|
+
options.onDiagnostic?.("mcp.stdio.shutdown", { reason, ...context ?? {} });
|
|
39383
|
+
options.shutdown();
|
|
39384
|
+
};
|
|
39385
|
+
const onStreamEnd = () => triggerShutdown("stdin.end");
|
|
39386
|
+
const onStreamClose = () => triggerShutdown("stdin.close");
|
|
39387
|
+
const onStdinError = (error2) => triggerShutdown("stdin.error", errorContext(error2));
|
|
39388
|
+
const onStdoutError = (error2) => triggerShutdown("stdout.error", errorContext(error2));
|
|
39389
|
+
const onSignal = (signal) => triggerShutdown("signal", { signal });
|
|
39390
|
+
options.stdin.on("end", onStreamEnd);
|
|
39391
|
+
options.stdin.on("close", onStreamClose);
|
|
39392
|
+
options.stdin.on("error", onStdinError);
|
|
39393
|
+
options.stdout.on("error", onStdoutError);
|
|
39394
|
+
const signals = platform === "win32" ? ["SIGINT", "SIGTERM", "SIGBREAK"] : ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
39395
|
+
const signalListeners = signals.map((signal) => ({ signal, listener: () => onSignal(signal) }));
|
|
39396
|
+
for (const { signal, listener } of signalListeners) {
|
|
39397
|
+
signalSource.on(signal, listener);
|
|
39398
|
+
}
|
|
39399
|
+
let parentTimer;
|
|
39400
|
+
if (parentPid > 1 && parentCheckIntervalMs > 0) {
|
|
39401
|
+
parentTimer = setIntervalFn(() => {
|
|
39402
|
+
if (!isProcessRunning(parentPid)) {
|
|
39403
|
+
triggerShutdown("parent_dead", { parentPid });
|
|
39404
|
+
}
|
|
39405
|
+
}, parentCheckIntervalMs);
|
|
39406
|
+
parentTimer.unref?.();
|
|
39407
|
+
}
|
|
39408
|
+
return () => {
|
|
39409
|
+
if (disposed)
|
|
39410
|
+
return;
|
|
39411
|
+
disposed = true;
|
|
39412
|
+
options.stdin.off("end", onStreamEnd);
|
|
39413
|
+
options.stdin.off("close", onStreamClose);
|
|
39414
|
+
options.stdin.off("error", onStdinError);
|
|
39415
|
+
options.stdout.off("error", onStdoutError);
|
|
39416
|
+
for (const { signal, listener } of signalListeners) {
|
|
39417
|
+
signalSource.off(signal, listener);
|
|
39418
|
+
}
|
|
39419
|
+
if (parentTimer) {
|
|
39420
|
+
clearIntervalFn(parentTimer);
|
|
39421
|
+
}
|
|
39422
|
+
};
|
|
39423
|
+
}
|
|
39424
|
+
function parseParentCheckIntervalMs(raw) {
|
|
39425
|
+
if (raw === undefined || raw.trim().length === 0)
|
|
39426
|
+
return 5000;
|
|
39427
|
+
const parsed = Number(raw);
|
|
39428
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 5000;
|
|
39429
|
+
}
|
|
39430
|
+
function errorContext(error2) {
|
|
39431
|
+
const record3 = error2;
|
|
39432
|
+
return {
|
|
39433
|
+
...typeof record3?.code === "string" ? { code: record3.code } : {},
|
|
39434
|
+
...typeof record3?.message === "string" ? { message: record3.message } : {}
|
|
39435
|
+
};
|
|
39436
|
+
}
|
|
39437
|
+
function defaultIsProcessRunning3(pid) {
|
|
39438
|
+
try {
|
|
39439
|
+
process.kill(pid, 0);
|
|
39440
|
+
return true;
|
|
39441
|
+
} catch (error2) {
|
|
39442
|
+
const code = error2?.code;
|
|
39443
|
+
return code !== "ESRCH";
|
|
39444
|
+
}
|
|
39445
|
+
}
|
|
38986
39446
|
async function runWeacpxMcpServer(options) {
|
|
38987
|
-
const transport = createOrchestrationTransport(options.endpoint ?? resolveDefaultOrchestrationEndpoint(process.env, process.platform));
|
|
39447
|
+
const transport = options.transport ?? createOrchestrationTransport(options.endpoint ?? resolveDefaultOrchestrationEndpoint(process.env, process.platform));
|
|
38988
39448
|
const server = createWeacpxMcpServer({
|
|
38989
39449
|
transport,
|
|
38990
39450
|
...options.coordinatorSession ? { coordinatorSession: options.coordinatorSession } : {},
|
|
@@ -38993,11 +39453,14 @@ async function runWeacpxMcpServer(options) {
|
|
|
38993
39453
|
...options.availableAgents ? { availableAgents: options.availableAgents } : {}
|
|
38994
39454
|
});
|
|
38995
39455
|
const stdio = new StdioServerTransport(stdin, stdout);
|
|
39456
|
+
let cleanupShutdownHooks;
|
|
38996
39457
|
let shuttingDown = false;
|
|
38997
39458
|
const shutdown = async () => {
|
|
38998
39459
|
if (shuttingDown)
|
|
38999
39460
|
return;
|
|
39000
39461
|
shuttingDown = true;
|
|
39462
|
+
cleanupShutdownHooks?.();
|
|
39463
|
+
options.onDiagnostic?.("mcp.stdio.stopping");
|
|
39001
39464
|
const forceExit = setTimeout(() => process.exit(0), 3000);
|
|
39002
39465
|
forceExit.unref();
|
|
39003
39466
|
try {
|
|
@@ -39005,11 +39468,16 @@ async function runWeacpxMcpServer(options) {
|
|
|
39005
39468
|
await stdio.close();
|
|
39006
39469
|
} catch {}
|
|
39007
39470
|
clearTimeout(forceExit);
|
|
39471
|
+
options.onDiagnostic?.("mcp.stdio.stopped");
|
|
39008
39472
|
process.exit(0);
|
|
39009
39473
|
};
|
|
39010
|
-
|
|
39011
|
-
|
|
39012
|
-
|
|
39474
|
+
options.onDiagnostic?.("mcp.stdio.start", { parentPid: process.ppid, platform: process.platform });
|
|
39475
|
+
cleanupShutdownHooks = installMcpStdioShutdownHooks({
|
|
39476
|
+
stdin,
|
|
39477
|
+
stdout,
|
|
39478
|
+
shutdown,
|
|
39479
|
+
onDiagnostic: options.onDiagnostic
|
|
39480
|
+
});
|
|
39013
39481
|
await server.connect(stdio);
|
|
39014
39482
|
}
|
|
39015
39483
|
function normalizeInputSchemaJson(schema) {
|
|
@@ -40765,6 +41233,7 @@ async function defaultMcpStdio(args, deps = {}) {
|
|
|
40765
41233
|
let coordinatorSession;
|
|
40766
41234
|
let sourceHandle;
|
|
40767
41235
|
let endpoint;
|
|
41236
|
+
let transport;
|
|
40768
41237
|
let identityResolver;
|
|
40769
41238
|
let availableAgents;
|
|
40770
41239
|
try {
|
|
@@ -40773,6 +41242,7 @@ async function defaultMcpStdio(args, deps = {}) {
|
|
|
40773
41242
|
const workspace = parseCoordinatorWorkspace(args, process.env);
|
|
40774
41243
|
endpoint = resolveDefaultOrchestrationEndpoint(process.env, process.platform);
|
|
40775
41244
|
const client = new OrchestrationClient(endpoint);
|
|
41245
|
+
transport = createOrchestrationTransport(endpoint, { client });
|
|
40776
41246
|
const runtimePaths = (await init_main().then(() => exports_main)).resolveRuntimePaths();
|
|
40777
41247
|
await ensureConfigExists(runtimePaths.configPath);
|
|
40778
41248
|
const config2 = await loadConfig(runtimePaths.configPath);
|
|
@@ -40786,7 +41256,7 @@ async function defaultMcpStdio(args, deps = {}) {
|
|
|
40786
41256
|
state,
|
|
40787
41257
|
client
|
|
40788
41258
|
});
|
|
40789
|
-
const eagerIdentity = parsedCoordinatorSession
|
|
41259
|
+
const eagerIdentity = parsedCoordinatorSession ? await resolveIdentity({ clientName: undefined, listRoots: async () => [] }) : null;
|
|
40790
41260
|
coordinatorSession = eagerIdentity?.coordinatorSession ?? "";
|
|
40791
41261
|
identityResolver = eagerIdentity ? undefined : resolveIdentity;
|
|
40792
41262
|
} catch (error2) {
|
|
@@ -40795,11 +41265,16 @@ async function defaultMcpStdio(args, deps = {}) {
|
|
|
40795
41265
|
return 2;
|
|
40796
41266
|
}
|
|
40797
41267
|
await runWeacpxMcpServer({
|
|
40798
|
-
|
|
41268
|
+
transport,
|
|
40799
41269
|
...coordinatorSession ? { coordinatorSession } : {},
|
|
40800
41270
|
...sourceHandle ? { sourceHandle } : {},
|
|
40801
41271
|
...identityResolver ? { resolveIdentity: identityResolver } : {},
|
|
40802
|
-
...availableAgents ? { availableAgents } : {}
|
|
41272
|
+
...availableAgents ? { availableAgents } : {},
|
|
41273
|
+
onDiagnostic: (event, context) => {
|
|
41274
|
+
const suffix = context && Object.keys(context).length > 0 ? ` ${JSON.stringify(context)}` : "";
|
|
41275
|
+
(deps.stderr ?? ((text) => process.stderr.write(text)))(`[weacpx:mcp] ${event}${suffix}
|
|
41276
|
+
`);
|
|
41277
|
+
}
|
|
40803
41278
|
});
|
|
40804
41279
|
return 0;
|
|
40805
41280
|
}
|