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
|
@@ -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,27 +482,71 @@ 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
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
if (
|
|
485
|
+
const emoji = TOOL_KIND_EMOJI[kind] ?? DEFAULT_TOOL_EMOJI;
|
|
486
|
+
const inputSummary = summarizeToolInput(update.rawInput, title);
|
|
487
|
+
const status = readString(update, "status");
|
|
488
|
+
if (!inputSummary && status === "pending")
|
|
489
|
+
return null;
|
|
490
|
+
if (!inputSummary && isGenericToolTitle(kind, title))
|
|
436
491
|
return null;
|
|
437
|
-
|
|
492
|
+
const summaryText = inputSummary && inputSummary !== title ? `: ${truncateToolDisplay(inputSummary)}` : "";
|
|
493
|
+
const statusText = status ? ` (${status})` : "";
|
|
494
|
+
return `${emoji} ${title}${statusText}${summaryText}`;
|
|
438
495
|
}
|
|
439
|
-
function
|
|
496
|
+
function buildToolUseEvent(update) {
|
|
440
497
|
if (!update)
|
|
441
498
|
return null;
|
|
442
|
-
const
|
|
443
|
-
if (
|
|
444
|
-
return
|
|
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 = "") {
|
|
530
|
+
if (rawInput == null)
|
|
531
|
+
return;
|
|
532
|
+
if (typeof rawInput === "string" || typeof rawInput === "number" || typeof rawInput === "boolean") {
|
|
533
|
+
return String(rawInput);
|
|
445
534
|
}
|
|
446
|
-
|
|
447
|
-
|
|
535
|
+
if (!isRecord(rawInput))
|
|
536
|
+
return;
|
|
537
|
+
const taskSummary = summarizeTaskInput(rawInput, title);
|
|
538
|
+
if (taskSummary)
|
|
539
|
+
return taskSummary;
|
|
540
|
+
const command = readFirstString(rawInput, ["command", "cmd", "program"]);
|
|
541
|
+
const args = readFirstStringArray(rawInput, ["args", "arguments"]);
|
|
542
|
+
if (command) {
|
|
543
|
+
return [command, ...args ?? []].join(" ");
|
|
544
|
+
}
|
|
545
|
+
const parsedCmd = rawInput.parsed_cmd;
|
|
546
|
+
if (Array.isArray(parsedCmd) && parsedCmd.length > 0) {
|
|
448
547
|
const parts = [];
|
|
449
548
|
for (const entry of parsedCmd) {
|
|
450
|
-
if (entry && typeof entry.cmd === "string" && entry.cmd.length > 0) {
|
|
549
|
+
if (isRecord(entry) && typeof entry.cmd === "string" && entry.cmd.length > 0) {
|
|
451
550
|
parts.push(entry.cmd);
|
|
452
551
|
}
|
|
453
552
|
}
|
|
@@ -455,7 +554,62 @@ function getToolDisplayCommand(update) {
|
|
|
455
554
|
return parts.join(" ");
|
|
456
555
|
}
|
|
457
556
|
}
|
|
458
|
-
return
|
|
557
|
+
return readFirstString(rawInput, [
|
|
558
|
+
"path",
|
|
559
|
+
"file",
|
|
560
|
+
"filePath",
|
|
561
|
+
"filepath",
|
|
562
|
+
"file_path",
|
|
563
|
+
"target",
|
|
564
|
+
"uri",
|
|
565
|
+
"url",
|
|
566
|
+
"query",
|
|
567
|
+
"pattern",
|
|
568
|
+
"text",
|
|
569
|
+
"search",
|
|
570
|
+
"name",
|
|
571
|
+
"description"
|
|
572
|
+
]);
|
|
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
|
+
}
|
|
584
|
+
function readFirstString(record, keys) {
|
|
585
|
+
for (const key of keys) {
|
|
586
|
+
const value = record[key];
|
|
587
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
588
|
+
return value.trim();
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
function readFirstStringArray(record, keys) {
|
|
594
|
+
for (const key of keys) {
|
|
595
|
+
const value = record[key];
|
|
596
|
+
if (!Array.isArray(value))
|
|
597
|
+
continue;
|
|
598
|
+
const entries = value.map((entry) => typeof entry === "string" && entry.trim().length > 0 ? entry.trim() : undefined).filter((entry) => entry !== undefined);
|
|
599
|
+
if (entries.length > 0) {
|
|
600
|
+
return entries;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
function isRecord(value) {
|
|
606
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
607
|
+
}
|
|
608
|
+
function readString(rawInput, key) {
|
|
609
|
+
if (!isRecord(rawInput))
|
|
610
|
+
return;
|
|
611
|
+
const value = rawInput[key];
|
|
612
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
459
613
|
}
|
|
460
614
|
function truncateToolDisplay(text) {
|
|
461
615
|
return text.length > 60 ? `${text.slice(0, 57)}...` : text;
|
|
@@ -473,14 +627,8 @@ function isGenericToolTitle(kind, title) {
|
|
|
473
627
|
}
|
|
474
628
|
return false;
|
|
475
629
|
}
|
|
476
|
-
var KIND_EMOJI;
|
|
477
630
|
var init_streaming_prompt = __esm(() => {
|
|
478
|
-
|
|
479
|
-
read: "\uD83D\uDCD6",
|
|
480
|
-
search: "\uD83D\uDD0D",
|
|
481
|
-
execute: "\uD83D\uDCBB",
|
|
482
|
-
edit: "✏️"
|
|
483
|
-
};
|
|
631
|
+
init_tool_kind_emoji();
|
|
484
632
|
});
|
|
485
633
|
|
|
486
634
|
// src/recovery/discover-parent-package-paths.ts
|
|
@@ -1072,9 +1220,13 @@ class BridgeRuntime {
|
|
|
1072
1220
|
input.name,
|
|
1073
1221
|
...structuredPrompt ? ["--file", structuredPrompt.filePath] : [input.text]
|
|
1074
1222
|
]));
|
|
1075
|
-
const formatToolCalls = input.replyMode === "verbose";
|
|
1223
|
+
const formatToolCalls = (input.replyMode ?? "verbose") === "verbose";
|
|
1224
|
+
const toolEventMode = input.toolEventMode ?? (input.toolEvents === true ? "structured" : "text");
|
|
1076
1225
|
try {
|
|
1077
|
-
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);
|
|
1078
1230
|
return { text: getPromptText(result) };
|
|
1079
1231
|
} finally {
|
|
1080
1232
|
try {
|
|
@@ -1253,7 +1405,11 @@ async function runStreamingPrompt(command, args, onEvent, options = {}) {
|
|
|
1253
1405
|
const child = spawnPrompt(command, args);
|
|
1254
1406
|
let stdout = "";
|
|
1255
1407
|
let stderr = "";
|
|
1256
|
-
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
|
+
});
|
|
1257
1413
|
let lastReplyAt = now();
|
|
1258
1414
|
const flushBuffer = () => {
|
|
1259
1415
|
const remaining = state.buffer.trim();
|
|
@@ -1475,6 +1631,7 @@ class BridgeServer {
|
|
|
1475
1631
|
});
|
|
1476
1632
|
case "prompt":
|
|
1477
1633
|
const media = asOptionalPromptMediaInput(params.media);
|
|
1634
|
+
const resolvedToolEventMode = asOptionalToolEventMode(params.toolEventMode);
|
|
1478
1635
|
return await this.runtime.prompt({
|
|
1479
1636
|
agent: requireString(params, "agent"),
|
|
1480
1637
|
agentCommand: asOptionalString(params.agentCommand),
|
|
@@ -1484,6 +1641,8 @@ class BridgeServer {
|
|
|
1484
1641
|
mcpSourceHandle: asOptionalString(params.mcpSourceHandle),
|
|
1485
1642
|
text: requirePromptText(params, media),
|
|
1486
1643
|
replyMode: asOptionalReplyMode(params.replyMode),
|
|
1644
|
+
toolEvents: params.toolEvents === true,
|
|
1645
|
+
...resolvedToolEventMode ? { toolEventMode: resolvedToolEventMode } : {},
|
|
1487
1646
|
media
|
|
1488
1647
|
}, (event) => {
|
|
1489
1648
|
if (event.type === "prompt.segment") {
|
|
@@ -1492,6 +1651,12 @@ class BridgeServer {
|
|
|
1492
1651
|
event: "prompt.segment",
|
|
1493
1652
|
text: event.text
|
|
1494
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
|
+
}));
|
|
1495
1660
|
}
|
|
1496
1661
|
});
|
|
1497
1662
|
case "setMode":
|
|
@@ -1657,6 +1822,13 @@ function asOptionalReplyMode(value) {
|
|
|
1657
1822
|
}
|
|
1658
1823
|
return value;
|
|
1659
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
|
+
}
|
|
1660
1832
|
|
|
1661
1833
|
// src/bridge/bridge-main.ts
|
|
1662
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
|
+
}
|