weacpx 0.4.0-beta.2 → 0.4.0
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 +144 -22
- package/dist/channels/types.d.ts +14 -0
- package/dist/cli.js +395 -145
- package/dist/plugin-api.d.ts +1 -1
- package/dist/weixin/agent/interface.d.ts +3 -0
- package/dist/weixin/storage/ensure-dir.d.ts +1 -0
- package/package.json +1 -1
|
@@ -56,6 +56,10 @@ function encodeBridgePromptSegmentEvent(event) {
|
|
|
56
56
|
return `${JSON.stringify(event)}
|
|
57
57
|
`;
|
|
58
58
|
}
|
|
59
|
+
function encodeBridgePromptToolEvent(event) {
|
|
60
|
+
return `${JSON.stringify(event)}
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
59
63
|
function encodeBridgeSessionProgressEvent(event) {
|
|
60
64
|
return `${JSON.stringify(event)}
|
|
61
65
|
`;
|
|
@@ -343,8 +347,48 @@ var init_prompt_media = __esm(() => {
|
|
|
343
347
|
};
|
|
344
348
|
});
|
|
345
349
|
|
|
350
|
+
// src/transport/tool-event-mode.ts
|
|
351
|
+
function resolveToolEventMode(input) {
|
|
352
|
+
if (input?.toolEventMode !== undefined) {
|
|
353
|
+
return input.toolEventMode;
|
|
354
|
+
}
|
|
355
|
+
if (input?.onToolEvent !== undefined) {
|
|
356
|
+
return "structured";
|
|
357
|
+
}
|
|
358
|
+
return "text";
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/transport/tool-kind-emoji.ts
|
|
362
|
+
var TOOL_KIND_EMOJI, DEFAULT_TOOL_EMOJI;
|
|
363
|
+
var init_tool_kind_emoji = __esm(() => {
|
|
364
|
+
TOOL_KIND_EMOJI = {
|
|
365
|
+
read: "\uD83D\uDCD6",
|
|
366
|
+
search: "\uD83D\uDD0D",
|
|
367
|
+
execute: "\uD83D\uDCBB",
|
|
368
|
+
edit: "✏️",
|
|
369
|
+
think: "\uD83E\uDDE0",
|
|
370
|
+
other: "\uD83D\uDD27"
|
|
371
|
+
};
|
|
372
|
+
DEFAULT_TOOL_EMOJI = TOOL_KIND_EMOJI.other;
|
|
373
|
+
});
|
|
374
|
+
|
|
346
375
|
// src/transport/streaming-prompt.ts
|
|
347
|
-
function createStreamingPromptState(formatToolCalls = false) {
|
|
376
|
+
function createStreamingPromptState(formatToolCalls = false, options) {
|
|
377
|
+
let toolEventMode;
|
|
378
|
+
let onToolEvent;
|
|
379
|
+
if (options === undefined) {
|
|
380
|
+
toolEventMode = "text";
|
|
381
|
+
onToolEvent = undefined;
|
|
382
|
+
} else if (typeof options === "function") {
|
|
383
|
+
onToolEvent = options;
|
|
384
|
+
toolEventMode = "structured";
|
|
385
|
+
} else {
|
|
386
|
+
onToolEvent = options.onToolEvent;
|
|
387
|
+
toolEventMode = resolveToolEventMode({
|
|
388
|
+
toolEventMode: options.mode,
|
|
389
|
+
onToolEvent
|
|
390
|
+
});
|
|
391
|
+
}
|
|
348
392
|
return {
|
|
349
393
|
buffer: "",
|
|
350
394
|
segments: [],
|
|
@@ -352,6 +396,8 @@ function createStreamingPromptState(formatToolCalls = false) {
|
|
|
352
396
|
pendingLine: "",
|
|
353
397
|
formatToolCalls,
|
|
354
398
|
emittedToolCallIds: new Set,
|
|
399
|
+
toolEventMode,
|
|
400
|
+
onToolEvent,
|
|
355
401
|
finalize() {
|
|
356
402
|
if (this.pendingLine.trim().length > 0) {
|
|
357
403
|
parseStreamingChunks(this, this.pendingLine);
|
|
@@ -389,15 +435,24 @@ function parseStreamingChunks(state, line) {
|
|
|
389
435
|
if (!update)
|
|
390
436
|
return;
|
|
391
437
|
if (state.formatToolCalls && (update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update")) {
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
438
|
+
const wantsStructured = state.toolEventMode === "structured" || state.toolEventMode === "both";
|
|
439
|
+
const wantsText = state.toolEventMode === "text" || state.toolEventMode === "both";
|
|
440
|
+
if (wantsStructured && state.onToolEvent) {
|
|
441
|
+
const toolEvent = buildToolUseEvent(update);
|
|
442
|
+
if (toolEvent)
|
|
443
|
+
state.onToolEvent(toolEvent);
|
|
444
|
+
}
|
|
445
|
+
if (wantsText) {
|
|
446
|
+
const formatted = formatToolCallEvent(update, update.sessionUpdate);
|
|
447
|
+
if (formatted) {
|
|
448
|
+
const toolCallId = update.toolCallId;
|
|
449
|
+
if (toolCallId) {
|
|
450
|
+
if (state.emittedToolCallIds.has(toolCallId))
|
|
451
|
+
return;
|
|
452
|
+
state.emittedToolCallIds.add(toolCallId);
|
|
453
|
+
}
|
|
454
|
+
state.segments.push(formatted);
|
|
399
455
|
}
|
|
400
|
-
state.segments.push(formatted);
|
|
401
456
|
}
|
|
402
457
|
return;
|
|
403
458
|
}
|
|
@@ -427,16 +482,51 @@ function formatToolCallEvent(update, sessionUpdate) {
|
|
|
427
482
|
const title = update.title ?? "";
|
|
428
483
|
if (title.length === 0)
|
|
429
484
|
return null;
|
|
430
|
-
const emoji =
|
|
431
|
-
const inputSummary = summarizeToolInput(update.rawInput);
|
|
485
|
+
const emoji = TOOL_KIND_EMOJI[kind] ?? DEFAULT_TOOL_EMOJI;
|
|
486
|
+
const inputSummary = summarizeToolInput(update.rawInput, title);
|
|
432
487
|
const status = readString(update, "status");
|
|
488
|
+
if (!inputSummary && status === "pending")
|
|
489
|
+
return null;
|
|
433
490
|
if (!inputSummary && isGenericToolTitle(kind, title))
|
|
434
491
|
return null;
|
|
435
|
-
const summaryText = inputSummary ? `: ${truncateToolDisplay(inputSummary)}` : "";
|
|
492
|
+
const summaryText = inputSummary && inputSummary !== title ? `: ${truncateToolDisplay(inputSummary)}` : "";
|
|
436
493
|
const statusText = status ? ` (${status})` : "";
|
|
437
494
|
return `${emoji} ${title}${statusText}${summaryText}`;
|
|
438
495
|
}
|
|
439
|
-
function
|
|
496
|
+
function buildToolUseEvent(update) {
|
|
497
|
+
if (!update)
|
|
498
|
+
return null;
|
|
499
|
+
const toolCallId = update.toolCallId;
|
|
500
|
+
if (!toolCallId)
|
|
501
|
+
return null;
|
|
502
|
+
const kindRaw = update.kind ?? "";
|
|
503
|
+
const kind = (() => {
|
|
504
|
+
switch (kindRaw) {
|
|
505
|
+
case "read":
|
|
506
|
+
case "search":
|
|
507
|
+
case "execute":
|
|
508
|
+
case "edit":
|
|
509
|
+
case "think":
|
|
510
|
+
return kindRaw;
|
|
511
|
+
default:
|
|
512
|
+
return "other";
|
|
513
|
+
}
|
|
514
|
+
})();
|
|
515
|
+
const title = (update.title ?? "").trim();
|
|
516
|
+
const toolName = title || "Tool";
|
|
517
|
+
const summaryRaw = summarizeToolInput(update.rawInput, title);
|
|
518
|
+
const summary = summaryRaw && summaryRaw !== title ? summaryRaw : undefined;
|
|
519
|
+
const statusRaw = readString(update, "status");
|
|
520
|
+
const status = statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : "running";
|
|
521
|
+
return {
|
|
522
|
+
toolCallId,
|
|
523
|
+
toolName,
|
|
524
|
+
kind,
|
|
525
|
+
...summary ? { summary } : {},
|
|
526
|
+
status
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
function summarizeToolInput(rawInput, title = "") {
|
|
440
530
|
if (rawInput == null)
|
|
441
531
|
return;
|
|
442
532
|
if (typeof rawInput === "string" || typeof rawInput === "number" || typeof rawInput === "boolean") {
|
|
@@ -444,6 +534,9 @@ function summarizeToolInput(rawInput) {
|
|
|
444
534
|
}
|
|
445
535
|
if (!isRecord(rawInput))
|
|
446
536
|
return;
|
|
537
|
+
const taskSummary = summarizeTaskInput(rawInput, title);
|
|
538
|
+
if (taskSummary)
|
|
539
|
+
return taskSummary;
|
|
447
540
|
const command = readFirstString(rawInput, ["command", "cmd", "program"]);
|
|
448
541
|
const args = readFirstStringArray(rawInput, ["args", "arguments"]);
|
|
449
542
|
if (command) {
|
|
@@ -466,6 +559,7 @@ function summarizeToolInput(rawInput) {
|
|
|
466
559
|
"file",
|
|
467
560
|
"filePath",
|
|
468
561
|
"filepath",
|
|
562
|
+
"file_path",
|
|
469
563
|
"target",
|
|
470
564
|
"uri",
|
|
471
565
|
"url",
|
|
@@ -477,6 +571,16 @@ function summarizeToolInput(rawInput) {
|
|
|
477
571
|
"description"
|
|
478
572
|
]);
|
|
479
573
|
}
|
|
574
|
+
function summarizeTaskInput(rawInput, title) {
|
|
575
|
+
const subagentType = readFirstString(rawInput, ["subagent_type", "subagentType", "agent", "agentType"]);
|
|
576
|
+
const description = readFirstString(rawInput, ["description", "task", "summary"]);
|
|
577
|
+
if (subagentType && description) {
|
|
578
|
+
return description === title ? subagentType : `${subagentType}: ${description}`;
|
|
579
|
+
}
|
|
580
|
+
if (subagentType)
|
|
581
|
+
return subagentType;
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
480
584
|
function readFirstString(record, keys) {
|
|
481
585
|
for (const key of keys) {
|
|
482
586
|
const value = record[key];
|
|
@@ -523,14 +627,8 @@ function isGenericToolTitle(kind, title) {
|
|
|
523
627
|
}
|
|
524
628
|
return false;
|
|
525
629
|
}
|
|
526
|
-
var KIND_EMOJI;
|
|
527
630
|
var init_streaming_prompt = __esm(() => {
|
|
528
|
-
|
|
529
|
-
read: "\uD83D\uDCD6",
|
|
530
|
-
search: "\uD83D\uDD0D",
|
|
531
|
-
execute: "\uD83D\uDCBB",
|
|
532
|
-
edit: "✏️"
|
|
533
|
-
};
|
|
631
|
+
init_tool_kind_emoji();
|
|
534
632
|
});
|
|
535
633
|
|
|
536
634
|
// src/recovery/discover-parent-package-paths.ts
|
|
@@ -1123,8 +1221,12 @@ class BridgeRuntime {
|
|
|
1123
1221
|
...structuredPrompt ? ["--file", structuredPrompt.filePath] : [input.text]
|
|
1124
1222
|
]));
|
|
1125
1223
|
const formatToolCalls = (input.replyMode ?? "verbose") === "verbose";
|
|
1224
|
+
const toolEventMode = input.toolEventMode ?? (input.toolEvents === true ? "structured" : "text");
|
|
1126
1225
|
try {
|
|
1127
|
-
const result = onEvent ? await this.runPromptCommand(spawnSpec.command, spawnSpec.args, onEvent, {
|
|
1226
|
+
const result = onEvent ? await this.runPromptCommand(spawnSpec.command, spawnSpec.args, onEvent, {
|
|
1227
|
+
formatToolCalls,
|
|
1228
|
+
toolEventMode
|
|
1229
|
+
}) : await this.run(spawnSpec.command, spawnSpec.args);
|
|
1128
1230
|
return { text: getPromptText(result) };
|
|
1129
1231
|
} finally {
|
|
1130
1232
|
try {
|
|
@@ -1303,7 +1405,11 @@ async function runStreamingPrompt(command, args, onEvent, options = {}) {
|
|
|
1303
1405
|
const child = spawnPrompt(command, args);
|
|
1304
1406
|
let stdout = "";
|
|
1305
1407
|
let stderr = "";
|
|
1306
|
-
const
|
|
1408
|
+
const toolEventMode = options.toolEventMode ?? "text";
|
|
1409
|
+
const state = createStreamingPromptState(options.formatToolCalls ?? false, {
|
|
1410
|
+
mode: toolEventMode,
|
|
1411
|
+
...onEvent && (toolEventMode === "structured" || toolEventMode === "both") ? { onToolEvent: (toolEvent) => onEvent({ type: "prompt.tool_event", event: toolEvent }) } : {}
|
|
1412
|
+
});
|
|
1307
1413
|
let lastReplyAt = now();
|
|
1308
1414
|
const flushBuffer = () => {
|
|
1309
1415
|
const remaining = state.buffer.trim();
|
|
@@ -1525,6 +1631,7 @@ class BridgeServer {
|
|
|
1525
1631
|
});
|
|
1526
1632
|
case "prompt":
|
|
1527
1633
|
const media = asOptionalPromptMediaInput(params.media);
|
|
1634
|
+
const resolvedToolEventMode = asOptionalToolEventMode(params.toolEventMode);
|
|
1528
1635
|
return await this.runtime.prompt({
|
|
1529
1636
|
agent: requireString(params, "agent"),
|
|
1530
1637
|
agentCommand: asOptionalString(params.agentCommand),
|
|
@@ -1534,6 +1641,8 @@ class BridgeServer {
|
|
|
1534
1641
|
mcpSourceHandle: asOptionalString(params.mcpSourceHandle),
|
|
1535
1642
|
text: requirePromptText(params, media),
|
|
1536
1643
|
replyMode: asOptionalReplyMode(params.replyMode),
|
|
1644
|
+
toolEvents: params.toolEvents === true,
|
|
1645
|
+
...resolvedToolEventMode ? { toolEventMode: resolvedToolEventMode } : {},
|
|
1537
1646
|
media
|
|
1538
1647
|
}, (event) => {
|
|
1539
1648
|
if (event.type === "prompt.segment") {
|
|
@@ -1542,6 +1651,12 @@ class BridgeServer {
|
|
|
1542
1651
|
event: "prompt.segment",
|
|
1543
1652
|
text: event.text
|
|
1544
1653
|
}));
|
|
1654
|
+
} else if (event.type === "prompt.tool_event") {
|
|
1655
|
+
writeLine?.(encodeBridgePromptToolEvent({
|
|
1656
|
+
id: requestId,
|
|
1657
|
+
event: "prompt.tool_event",
|
|
1658
|
+
toolEvent: event.event
|
|
1659
|
+
}));
|
|
1545
1660
|
}
|
|
1546
1661
|
});
|
|
1547
1662
|
case "setMode":
|
|
@@ -1707,6 +1822,13 @@ function asOptionalReplyMode(value) {
|
|
|
1707
1822
|
}
|
|
1708
1823
|
return value;
|
|
1709
1824
|
}
|
|
1825
|
+
var VALID_TOOL_EVENT_MODES = new Set(["text", "structured", "both"]);
|
|
1826
|
+
function asOptionalToolEventMode(value) {
|
|
1827
|
+
if (typeof value !== "string" || !VALID_TOOL_EVENT_MODES.has(value)) {
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
return value;
|
|
1831
|
+
}
|
|
1710
1832
|
|
|
1711
1833
|
// src/bridge/bridge-main.ts
|
|
1712
1834
|
async function processBridgeInput(options) {
|
package/dist/channels/types.d.ts
CHANGED
|
@@ -59,3 +59,17 @@ export interface MessageChannelRuntime {
|
|
|
59
59
|
notifyTaskProgress(task: OrchestrationTaskRecord, text: string): Promise<void>;
|
|
60
60
|
sendCoordinatorMessage(input: CoordinatorMessageInput): Promise<void>;
|
|
61
61
|
}
|
|
62
|
+
export type ToolUseStatus = "running" | "success" | "error";
|
|
63
|
+
export type ToolUseKind = "read" | "search" | "execute" | "edit" | "think" | "other";
|
|
64
|
+
export interface ToolUseEvent {
|
|
65
|
+
toolCallId: string;
|
|
66
|
+
/** Free-form tool name from the agent (e.g. "Read File", "Bash"). */
|
|
67
|
+
toolName: string;
|
|
68
|
+
/** Coarse classifier produced by the transport from the agent's tool kind; channels use it to pick an icon. */
|
|
69
|
+
kind: ToolUseKind;
|
|
70
|
+
/** Best-effort one-line summary derived from `rawInput`. */
|
|
71
|
+
summary?: string;
|
|
72
|
+
status: ToolUseStatus;
|
|
73
|
+
/** Set when status transitions out of "running". */
|
|
74
|
+
durationMs?: number;
|
|
75
|
+
}
|