@aipack-ai/multi-agent 1.1.5 → 1.1.7

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/index.js CHANGED
@@ -57,6 +57,10 @@ function createSharedContext(init) {
57
57
  meta: init?.meta ?? {}
58
58
  };
59
59
  }
60
+ function storeOriginalInput(ctx, input) {
61
+ const inputText = typeof input === "string" ? input : input.message;
62
+ ctx.blackboard.set("__original_input__", inputText);
63
+ }
60
64
 
61
65
  // ../agent/core/types.ts
62
66
  function extractText(content) {
@@ -582,6 +586,14 @@ function resourceToMessage(resource) {
582
586
  content: resource.content,
583
587
  timestamp: resource.timestamp
584
588
  };
589
+ case "state_snapshot": {
590
+ const text = typeof resource.content === "string" ? resource.content : extractText(resource.content);
591
+ return {
592
+ role: "stateSnapshot",
593
+ content: text,
594
+ timestamp: resource.timestamp
595
+ };
596
+ }
585
597
  default:
586
598
  return resource.content;
587
599
  }
@@ -890,18 +902,25 @@ function withTimeoutSignal(parent, ms) {
890
902
  () => controller.abort(new Error(`Tool execution timeout after ${ms}ms`)),
891
903
  ms
892
904
  );
905
+ let onAbort;
893
906
  if (parent) {
894
907
  if (parent.aborted) {
895
908
  controller.abort(parent.reason);
896
909
  } else {
897
- parent.addEventListener(
898
- "abort",
899
- () => controller.abort(parent.reason),
900
- { once: true }
901
- );
910
+ onAbort = () => controller.abort(parent.reason);
911
+ parent.addEventListener("abort", onAbort, { once: true });
902
912
  }
903
913
  }
904
- return { signal: controller.signal, clear: () => clearTimeout(timer) };
914
+ return {
915
+ signal: controller.signal,
916
+ clear: () => {
917
+ clearTimeout(timer);
918
+ if (onAbort && parent) {
919
+ parent.removeEventListener("abort", onAbort);
920
+ onAbort = void 0;
921
+ }
922
+ }
923
+ };
905
924
  }
906
925
  function buildImageContent(media) {
907
926
  const dataMatch = media.match(/^data:([^;]+);base64,(.*)$/s);
@@ -935,6 +954,7 @@ var DEFAULT_COMPACTION_PROMPT = [
935
954
  "5. \u76F4\u63A5\u8F93\u51FA\u6458\u8981\u6B63\u6587\uFF0C\u4E0D\u8981\u4EFB\u4F55\u524D\u540E\u7F00\u8BF4\u660E\u3002"
936
955
  ].join("\n");
937
956
  var COMPACTION_USER_PREFIX = "[\u4EE5\u4E0B\u4E3A\u6B64\u524D\u5BF9\u8BDD\u5386\u53F2\u7684\u538B\u7F29\u6458\u8981\uFF0C\u4F5C\u4E3A\u4E0A\u4E0B\u6587\u53C2\u8003]";
957
+ var STATE_SNAPSHOT_USER_PREFIX = "[\u4EE5\u4E0B\u4E3A\u5F53\u524D\u72B6\u6001\u5FEB\u7167\uFF0C\u4F5C\u4E3A\u4E0A\u4E0B\u6587\u53C2\u8003]";
938
958
  function messageToSummaryLine(msg) {
939
959
  const clamp = (text) => text.length > COMPACTION_LINE_CLAMP ? `${text.slice(0, COMPACTION_LINE_CLAMP)}\u2026(\u5DF2\u622A\u65AD)` : text;
940
960
  switch (msg.role) {
@@ -1446,7 +1466,7 @@ var AgentRuntime = class _AgentRuntime {
1446
1466
  toolCallId: toolCall.id
1447
1467
  };
1448
1468
  }
1449
- const outcome = await this.executeToolCallsStreaming(
1469
+ const outcome = await this.executeToolCalls(
1450
1470
  compilation,
1451
1471
  toolCalls,
1452
1472
  session.abortController.signal
@@ -1482,16 +1502,6 @@ var AgentRuntime = class _AgentRuntime {
1482
1502
  }
1483
1503
  return outcome;
1484
1504
  }
1485
- /** 流式循环:执行工具调用,返回结果(消息由调用方追加) */
1486
- async executeToolCallsStreaming(compilation, toolCalls, signal) {
1487
- const outcome = await this.runTools(toolCalls, signal, compilation.request, compilation.traceId);
1488
- for (let i = 0; i < toolCalls.length; i++) {
1489
- compilation.messages.push(
1490
- this.buildToolResultMessage(toolCalls[i], outcome.results[i])
1491
- );
1492
- }
1493
- return outcome;
1494
- }
1495
1505
  /**
1496
1506
  * 执行一组工具调用:parallelToolCalls 为 true 时并行,否则串行。
1497
1507
  * 返回 ToolExecutionOutcome:任一工具请求 terminate 即终止整个 run;
@@ -1849,9 +1859,14 @@ var AgentRuntime = class _AgentRuntime {
1849
1859
  const tools = Array.from(this._globalTools.values());
1850
1860
  return {
1851
1861
  systemPrompt: this._systemPrompt,
1852
- // compactionSummary 为内部扩展 role,provider 适配层仅支持
1853
- // user/assistant/toolResult,发出前统一转为带标注的 user 消息
1854
- messages: messages.filter((m) => m.role !== "system").map((m) => m.role === "compactionSummary" ? this.compactionSummaryToUser(m) : m),
1862
+ // compactionSummary / stateSnapshot 为内部扩展 role,provider 适配层
1863
+ // 仅支持 user/assistant/toolResult,发出前统一转为带标注的 user 消息
1864
+ messages: messages.filter((m) => m.role !== "system").map((m) => {
1865
+ const role = m.role;
1866
+ if (role === "compactionSummary") return this.compactionSummaryToUser(m);
1867
+ if (role === "stateSnapshot") return this.stateSnapshotToUser(m);
1868
+ return m;
1869
+ }),
1855
1870
  tools: tools.length > 0 ? tools : void 0
1856
1871
  };
1857
1872
  }
@@ -1861,6 +1876,16 @@ var AgentRuntime = class _AgentRuntime {
1861
1876
  return {
1862
1877
  role: "user",
1863
1878
  content: `${COMPACTION_USER_PREFIX}
1879
+ ${text}`,
1880
+ timestamp: msg.timestamp
1881
+ };
1882
+ }
1883
+ /** stateSnapshot 消息 → user 消息(所有 provider 均兼容 user role) */
1884
+ stateSnapshotToUser(msg) {
1885
+ const text = typeof msg.content === "string" ? msg.content : extractText(msg.content);
1886
+ return {
1887
+ role: "user",
1888
+ content: `${STATE_SNAPSHOT_USER_PREFIX}
1864
1889
  ${text}`,
1865
1890
  timestamp: msg.timestamp
1866
1891
  };
@@ -2457,7 +2482,55 @@ function createRuntime(options) {
2457
2482
  return AgentRuntime.create(options);
2458
2483
  }
2459
2484
 
2485
+ // core/event-stream.ts
2486
+ function createEventStream(execute, sink) {
2487
+ const eventQueue = [];
2488
+ let resolveEvent = null;
2489
+ let done = false;
2490
+ const emit = (event) => {
2491
+ eventQueue.push(event);
2492
+ if (sink) {
2493
+ try {
2494
+ sink(event);
2495
+ } catch {
2496
+ }
2497
+ }
2498
+ resolveEvent?.();
2499
+ };
2500
+ const graphPromise = execute(emit).finally(() => {
2501
+ done = true;
2502
+ resolveEvent?.();
2503
+ });
2504
+ return (async function* () {
2505
+ while (!done || eventQueue.length > 0) {
2506
+ if (eventQueue.length > 0) {
2507
+ yield eventQueue.shift();
2508
+ } else {
2509
+ await new Promise((resolve) => {
2510
+ resolveEvent = resolve;
2511
+ });
2512
+ }
2513
+ }
2514
+ await graphPromise;
2515
+ })();
2516
+ }
2517
+
2460
2518
  // core/executor.ts
2519
+ var GraphAbortedError = class extends Error {
2520
+ constructor() {
2521
+ super("AgentGraph: \u6267\u884C\u5DF2\u88AB\u4E2D\u6B62");
2522
+ this.name = "GraphAbortedError";
2523
+ }
2524
+ };
2525
+ function toInputText(input) {
2526
+ return typeof input === "string" ? input : input.message;
2527
+ }
2528
+ var NodeTimeoutError = class extends Error {
2529
+ constructor(nodeId, timeoutMs) {
2530
+ super(`AgentGraph: \u8282\u70B9 "${nodeId}" \u6267\u884C\u8D85\u65F6\uFF08${timeoutMs}ms\uFF09`);
2531
+ this.name = "NodeTimeoutError";
2532
+ }
2533
+ };
2461
2534
  var runtimeCache = /* @__PURE__ */ new WeakMap();
2462
2535
  function ensureRuntime(node) {
2463
2536
  let rt = runtimeCache.get(node);
@@ -2470,19 +2543,52 @@ function ensureRuntime(node) {
2470
2543
  runtimeCache.set(node, rt);
2471
2544
  return rt;
2472
2545
  }
2473
- async function executeNode(node, input, ctx) {
2546
+ async function executeNodeOnce(node, req) {
2474
2547
  const runtime = ensureRuntime(node);
2548
+ if (node.timeoutMs != null && node.timeoutMs > 0) {
2549
+ let timer;
2550
+ try {
2551
+ return await Promise.race([
2552
+ runtime.run(req),
2553
+ new Promise((_, reject) => {
2554
+ timer = setTimeout(() => reject(new NodeTimeoutError(node.id, node.timeoutMs)), node.timeoutMs);
2555
+ })
2556
+ ]);
2557
+ } finally {
2558
+ if (timer !== void 0) clearTimeout(timer);
2559
+ }
2560
+ }
2561
+ return runtime.run(req);
2562
+ }
2563
+ async function executeNode(node, input, ctx) {
2475
2564
  let req;
2476
2565
  if (typeof input === "string") {
2477
2566
  req = createRequest(input, { sessionKey: `multi-agent:${node.id}` });
2478
2567
  } else {
2479
2568
  req = { ...input, sessionKey: input.sessionKey ?? `multi-agent:${node.id}` };
2480
2569
  }
2481
- const result = await runtime.run(req);
2570
+ const maxAttempts = Math.max(1, node.retry?.maxAttempts ?? 1);
2571
+ const backoffMs = node.retry?.backoffMs ?? 0;
2572
+ let lastErr;
2573
+ let succeeded;
2574
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
2575
+ if (attempt > 1 && backoffMs > 0) {
2576
+ await new Promise((resolve) => setTimeout(resolve, backoffMs));
2577
+ }
2578
+ try {
2579
+ succeeded = await executeNodeOnce(node, req);
2580
+ break;
2581
+ } catch (err) {
2582
+ lastErr = err;
2583
+ }
2584
+ }
2585
+ if (succeeded === void 0) {
2586
+ throw lastErr;
2587
+ }
2482
2588
  if (node.outputMapping) {
2483
- node.outputMapping(result, ctx);
2589
+ node.outputMapping(succeeded, ctx);
2484
2590
  }
2485
- return result;
2591
+ return succeeded;
2486
2592
  }
2487
2593
  function resolveInput(edge, prevResult, ctx, node, originalInput) {
2488
2594
  if (edge?.transform) {
@@ -2509,12 +2615,22 @@ var GraphExecutor = class {
2509
2615
  entryId;
2510
2616
  finishCondition;
2511
2617
  abortController = new AbortController();
2618
+ /** 外部事件监听(on() API 的底层接线),事件会同步分发 */
2619
+ eventSink;
2620
+ /** 并行分支最大并发数(默认不限制) */
2621
+ concurrency;
2622
+ /** 单节点最大访问次数(环图防死循环) */
2623
+ maxVisitsPerNode;
2512
2624
  state = {
2513
2625
  nodeStates: /* @__PURE__ */ new Map(),
2514
2626
  nodeResults: /* @__PURE__ */ new Map(),
2515
2627
  stepsCompleted: 0,
2516
2628
  finished: false
2517
2629
  };
2630
+ constructor(opts) {
2631
+ this.concurrency = opts?.concurrency ?? Infinity;
2632
+ this.maxVisitsPerNode = opts?.maxVisitsPerNode ?? 10;
2633
+ }
2518
2634
  addNode(node) {
2519
2635
  this.nodes.set(node.id, node);
2520
2636
  this.state.nodeStates.set(node.id, "pending");
@@ -2532,12 +2648,42 @@ var GraphExecutor = class {
2532
2648
  this.finishCondition = condition;
2533
2649
  return this;
2534
2650
  }
2651
+ /** 注入外部事件监听(由 AgentGraph 实现的 on() 接线) */
2652
+ setEventSink(sink) {
2653
+ this.eventSink = sink;
2654
+ return this;
2655
+ }
2535
2656
  getState() {
2536
- return { ...this.state };
2657
+ return {
2658
+ ...this.state,
2659
+ nodeStates: new Map(this.state.nodeStates),
2660
+ nodeResults: new Map(this.state.nodeResults)
2661
+ };
2537
2662
  }
2538
2663
  abort() {
2539
2664
  this.abortController.abort();
2540
2665
  }
2666
+ /** 每次 run/stream 前重置中止信号,避免上一次的 abort 永久失效 */
2667
+ resetAbortController() {
2668
+ this.abortController = new AbortController();
2669
+ }
2670
+ /** 每次 run/stream 前重置执行状态,避免残留上一次的 nodeStates/结果 */
2671
+ resetState() {
2672
+ this.state = {
2673
+ nodeStates: /* @__PURE__ */ new Map(),
2674
+ nodeResults: /* @__PURE__ */ new Map(),
2675
+ stepsCompleted: 0,
2676
+ finished: false
2677
+ };
2678
+ for (const id of this.nodes.keys()) {
2679
+ this.state.nodeStates.set(id, "pending");
2680
+ }
2681
+ }
2682
+ throwIfAborted() {
2683
+ if (this.abortController.signal.aborted) {
2684
+ throw new GraphAbortedError();
2685
+ }
2686
+ }
2541
2687
  /** 同步执行图 */
2542
2688
  async run(input) {
2543
2689
  if (!this.entryId) {
@@ -2546,66 +2692,78 @@ var GraphExecutor = class {
2546
2692
  if (!this.nodes.has(this.entryId)) {
2547
2693
  throw new Error(`AgentGraph: \u5165\u53E3\u8282\u70B9 "${this.entryId}" \u4E0D\u5B58\u5728`);
2548
2694
  }
2695
+ this.resetAbortController();
2696
+ this.resetState();
2549
2697
  const ctx = createSharedContext({
2550
2698
  meta: { traceId: `ma-${Date.now()}`, startTime: Date.now() }
2551
2699
  });
2552
- const events = [];
2700
+ storeOriginalInput(ctx, input);
2701
+ const emit = this.eventSink ?? (() => {
2702
+ });
2553
2703
  try {
2554
- const result = await this.executeGraph(input, ctx, (event) => events.push(event));
2704
+ const result = await this.executeGraph(input, ctx, emit);
2705
+ emit({ type: "graph_done", result });
2555
2706
  return result;
2556
2707
  } catch (err) {
2708
+ const errorMsg = err instanceof Error ? err.message : String(err);
2709
+ this.state.error = errorMsg;
2710
+ if (err instanceof GraphAbortedError) {
2711
+ const lastCompleted = [...this.state.nodeResults.values()].at(-1);
2712
+ const abortedResult = {
2713
+ content: lastCompleted?.content ?? "",
2714
+ lastAgentId: this.state.currentAgentId ?? "",
2715
+ agentResults: new Map(this.state.nodeResults),
2716
+ totalUsage: {},
2717
+ stepsCompleted: this.state.stepsCompleted,
2718
+ stopReason: "aborted",
2719
+ context: ctx,
2720
+ success: false,
2721
+ error: err.message
2722
+ };
2723
+ emit({ type: "graph_error", error: err.message });
2724
+ return abortedResult;
2725
+ }
2726
+ emit({ type: "graph_error", error: errorMsg });
2557
2727
  return {
2558
2728
  content: "",
2559
2729
  lastAgentId: this.state.currentAgentId ?? "",
2560
- agentResults: this.state.nodeResults,
2730
+ agentResults: new Map(this.state.nodeResults),
2561
2731
  totalUsage: {},
2562
2732
  stepsCompleted: this.state.stepsCompleted,
2563
2733
  stopReason: "error",
2564
2734
  context: ctx,
2565
2735
  success: false,
2566
- error: err instanceof Error ? err.message : String(err)
2736
+ error: errorMsg
2567
2737
  };
2568
2738
  }
2569
2739
  }
2570
2740
  /** 流式执行图 */
2571
- async *stream(input) {
2741
+ stream(input) {
2572
2742
  if (!this.entryId) {
2573
2743
  throw new Error("AgentGraph: \u5165\u53E3\u8282\u70B9\u672A\u8BBE\u7F6E\uFF0C\u8BF7\u8C03\u7528 setEntry()");
2574
2744
  }
2575
2745
  if (!this.nodes.has(this.entryId)) {
2576
2746
  throw new Error(`AgentGraph: \u5165\u53E3\u8282\u70B9 "${this.entryId}" \u4E0D\u5B58\u5728`);
2577
2747
  }
2748
+ this.resetAbortController();
2749
+ this.resetState();
2578
2750
  const ctx = createSharedContext({
2579
2751
  meta: { traceId: `ma-${Date.now()}`, startTime: Date.now() }
2580
2752
  });
2581
- const eventQueue = [];
2582
- let resolveEvent = null;
2583
- let done = false;
2584
- const emit = (event) => {
2585
- eventQueue.push(event);
2586
- resolveEvent?.();
2587
- };
2588
- const graphPromise = this.executeGraph(input, ctx, emit).then(
2589
- (result) => {
2590
- emit({ type: "graph_done", result });
2591
- },
2592
- (err) => {
2593
- emit({ type: "graph_error", error: err instanceof Error ? err.message : String(err) });
2594
- }
2595
- ).finally(() => {
2596
- done = true;
2597
- resolveEvent?.();
2598
- });
2599
- while (!done || eventQueue.length > 0) {
2600
- if (eventQueue.length > 0) {
2601
- yield eventQueue.shift();
2602
- } else {
2603
- await new Promise((resolve) => {
2604
- resolveEvent = resolve;
2605
- });
2606
- }
2607
- }
2608
- await graphPromise;
2753
+ storeOriginalInput(ctx, input);
2754
+ return createEventStream(
2755
+ (emit) => this.executeGraph(input, ctx, emit).then(
2756
+ (result) => {
2757
+ emit({ type: "graph_done", result });
2758
+ },
2759
+ (err) => {
2760
+ const errorMsg = err instanceof Error ? err.message : String(err);
2761
+ this.state.error = errorMsg;
2762
+ emit({ type: "graph_error", error: errorMsg });
2763
+ }
2764
+ ),
2765
+ this.eventSink
2766
+ );
2609
2767
  }
2610
2768
  /** 核心执行逻辑 */
2611
2769
  async executeGraph(input, ctx, emit) {
@@ -2618,7 +2776,7 @@ var GraphExecutor = class {
2618
2776
  const totalUsage = {};
2619
2777
  this.state.currentAgentId = currentId;
2620
2778
  this.state.nodeStates.set(currentId, "running");
2621
- emit({ type: "agent_start", agentId: currentId, agentName: entryNode.name });
2779
+ emit({ type: "agent_start", agentId: currentId, agentName: entryNode.name, input: toInputText(currentInput) });
2622
2780
  try {
2623
2781
  lastResult = await executeNode(entryNode, currentInput, ctx);
2624
2782
  this.state.nodeStates.set(currentId, "completed");
@@ -2637,50 +2795,134 @@ var GraphExecutor = class {
2637
2795
  if (this.finishCondition?.(ctx)) {
2638
2796
  return this.buildResult(lastResult, lastAgentId, ctx, totalUsage, stepsCompleted, "finish_condition");
2639
2797
  }
2640
- const visited = /* @__PURE__ */ new Set();
2798
+ let frontier = [{ id: currentId, result: lastResult }];
2641
2799
  const visitCount = /* @__PURE__ */ new Map();
2642
- const MAX_VISITS_PER_NODE = 10;
2643
- while (lastResult) {
2644
- const nextEdges = findNextEdges(currentId, this.edges, lastResult, ctx);
2645
- if (nextEdges.length === 0) {
2800
+ let stopReason = "completed";
2801
+ while (frontier.length > 0) {
2802
+ this.throwIfAborted();
2803
+ const candidates = [];
2804
+ const seenTargets = /* @__PURE__ */ new Set();
2805
+ for (const from of frontier) {
2806
+ const nextEdges = findNextEdges(from.id, this.edges, from.result, ctx);
2807
+ for (const edge of nextEdges) {
2808
+ if (seenTargets.has(edge.to)) continue;
2809
+ seenTargets.add(edge.to);
2810
+ const nextNode = this.nodes.get(edge.to);
2811
+ if (!nextNode) {
2812
+ throw new Error(`AgentGraph: \u76EE\u6807\u8282\u70B9 "${edge.to}" \u4E0D\u5B58\u5728`);
2813
+ }
2814
+ candidates.push({ edge, from, node: nextNode });
2815
+ }
2816
+ }
2817
+ if (candidates.length === 0) {
2646
2818
  break;
2647
2819
  }
2648
- const edge = nextEdges[0];
2649
- const nextNode = this.nodes.get(edge.to);
2650
- if (!nextNode) {
2651
- throw new Error(`AgentGraph: \u76EE\u6807\u8282\u70B9 "${edge.to}" \u4E0D\u5B58\u5728`);
2820
+ const allowed = [];
2821
+ let truncated = false;
2822
+ for (const c of candidates) {
2823
+ const count = (visitCount.get(c.edge.to) ?? 0) + 1;
2824
+ if (count > this.maxVisitsPerNode) {
2825
+ truncated = true;
2826
+ continue;
2827
+ }
2828
+ visitCount.set(c.edge.to, count);
2829
+ allowed.push(c);
2652
2830
  }
2653
- const count = (visitCount.get(edge.to) ?? 0) + 1;
2654
- if (count > MAX_VISITS_PER_NODE) {
2831
+ if (allowed.length === 0) {
2832
+ if (truncated) stopReason = "max_visits_exceeded";
2655
2833
  break;
2656
2834
  }
2657
- visitCount.set(edge.to, count);
2658
- currentInput = resolveInput(edge, lastResult, ctx, nextNode, input);
2659
- currentId = edge.to;
2660
- this.state.currentAgentId = currentId;
2661
- this.state.nodeStates.set(currentId, "running");
2662
- emit({ type: "edge_traversed", from: edge.from, to: edge.to });
2663
- emit({ type: "agent_start", agentId: currentId, agentName: nextNode.name });
2664
- try {
2665
- lastResult = await executeNode(nextNode, currentInput, ctx);
2666
- this.state.nodeStates.set(currentId, "completed");
2667
- this.state.nodeResults.set(currentId, lastResult);
2668
- this.mergeUsage(totalUsage, lastResult.usage);
2835
+ const tasks = allowed.map((c) => ({
2836
+ node: c.node,
2837
+ input: resolveInput(c.edge, c.from.result, ctx, c.node, input),
2838
+ fromId: c.edge.from
2839
+ }));
2840
+ let waveResults;
2841
+ if (tasks.length === 1) {
2842
+ const t = tasks[0];
2843
+ this.state.currentAgentId = t.node.id;
2844
+ this.state.nodeStates.set(t.node.id, "running");
2845
+ emit({ type: "edge_traversed", from: t.fromId, to: t.node.id });
2846
+ emit({ type: "agent_start", agentId: t.node.id, agentName: t.node.name, input: toInputText(t.input) });
2847
+ let result;
2848
+ try {
2849
+ result = await executeNode(t.node, t.input, ctx);
2850
+ } catch (err) {
2851
+ const errorMsg = err instanceof Error ? err.message : String(err);
2852
+ this.state.nodeStates.set(t.node.id, "failed");
2853
+ emit({ type: "agent_error", agentId: t.node.id, agentName: t.node.name, error: errorMsg });
2854
+ throw err;
2855
+ }
2856
+ this.state.nodeStates.set(t.node.id, "completed");
2857
+ this.state.nodeResults.set(t.node.id, result);
2858
+ this.mergeUsage(totalUsage, result.usage);
2669
2859
  stepsCompleted++;
2670
2860
  this.state.stepsCompleted = stepsCompleted;
2671
- emit({ type: "agent_result", agentId: currentId, agentName: nextNode.name, result: lastResult });
2861
+ emit({ type: "agent_result", agentId: t.node.id, agentName: t.node.name, result });
2862
+ waveResults = [{ id: t.node.id, result }];
2863
+ } else {
2864
+ waveResults = await this.executeWave(tasks, ctx, emit, totalUsage);
2865
+ stepsCompleted += waveResults.length;
2866
+ this.state.stepsCompleted = stepsCompleted;
2867
+ }
2868
+ lastResult = waveResults[waveResults.length - 1].result;
2869
+ lastAgentId = waveResults[waveResults.length - 1].id;
2870
+ frontier = waveResults;
2871
+ if (this.finishCondition?.(ctx)) {
2872
+ return this.buildResult(lastResult, lastAgentId, ctx, totalUsage, stepsCompleted, "finish_condition");
2873
+ }
2874
+ }
2875
+ return this.buildResult(lastResult, lastAgentId, ctx, totalUsage, stepsCompleted, stopReason);
2876
+ }
2877
+ /** 并行执行一个 wave 的节点(fail-fast + concurrency 限流) */
2878
+ async executeWave(tasks, ctx, emit, totalUsage) {
2879
+ const results = [];
2880
+ emit({ type: "parallel_start", agentIds: tasks.map((t) => t.node.id) });
2881
+ const runOne = async (t) => {
2882
+ this.state.currentAgentId = t.node.id;
2883
+ this.state.nodeStates.set(t.node.id, "running");
2884
+ emit({ type: "edge_traversed", from: t.fromId, to: t.node.id });
2885
+ emit({ type: "agent_start", agentId: t.node.id, agentName: t.node.name, input: toInputText(t.input) });
2886
+ try {
2887
+ const result = await executeNode(t.node, t.input, ctx);
2888
+ this.state.nodeStates.set(t.node.id, "completed");
2889
+ this.state.nodeResults.set(t.node.id, result);
2890
+ this.mergeUsage(totalUsage, result.usage);
2891
+ results.push({ id: t.node.id, result });
2892
+ emit({ type: "agent_result", agentId: t.node.id, agentName: t.node.name, result });
2672
2893
  } catch (err) {
2673
2894
  const errorMsg = err instanceof Error ? err.message : String(err);
2674
- this.state.nodeStates.set(currentId, "failed");
2675
- emit({ type: "agent_error", agentId: currentId, agentName: nextNode.name, error: errorMsg });
2895
+ this.state.nodeStates.set(t.node.id, "failed");
2896
+ emit({ type: "agent_error", agentId: t.node.id, agentName: t.node.name, error: errorMsg });
2676
2897
  throw err;
2677
2898
  }
2678
- lastAgentId = currentId;
2679
- if (this.finishCondition?.(ctx)) {
2680
- return this.buildResult(lastResult, lastAgentId, ctx, totalUsage, stepsCompleted, "finish_condition");
2899
+ };
2900
+ if (this.concurrency >= tasks.length) {
2901
+ await Promise.all(tasks.map((t) => runOne(t)));
2902
+ } else {
2903
+ let index = 0;
2904
+ const executing = /* @__PURE__ */ new Set();
2905
+ const enqueue = () => {
2906
+ if (index >= tasks.length) return null;
2907
+ const i = index++;
2908
+ const p = runOne(tasks[i]).finally(() => {
2909
+ executing.delete(p);
2910
+ });
2911
+ executing.add(p);
2912
+ p.catch(() => {
2913
+ });
2914
+ return p;
2915
+ };
2916
+ for (let i = 0; i < this.concurrency && index < tasks.length; i++) {
2917
+ enqueue();
2918
+ }
2919
+ while (executing.size > 0) {
2920
+ await Promise.race(executing);
2921
+ enqueue();
2681
2922
  }
2682
2923
  }
2683
- return this.buildResult(lastResult, lastAgentId, ctx, totalUsage, stepsCompleted, "completed");
2924
+ emit({ type: "parallel_done", results: new Map(results.map((r) => [r.id, r.result])) });
2925
+ return results;
2684
2926
  }
2685
2927
  buildResult(lastResult, lastAgentId, ctx, totalUsage, stepsCompleted, stopReason) {
2686
2928
  this.state.finished = true;
@@ -2705,8 +2947,12 @@ var GraphExecutor = class {
2705
2947
 
2706
2948
  // core/graph.ts
2707
2949
  var AgentGraphImpl = class {
2708
- executor = new GraphExecutor();
2709
- eventListeners = /* @__PURE__ */ new Map();
2950
+ executor;
2951
+ /** on() 注册的监听器,按 MultiAgentEvent.type 分发 */
2952
+ bus = new SimpleEventBus();
2953
+ constructor(opts) {
2954
+ this.executor = new GraphExecutor(opts);
2955
+ }
2710
2956
  addNode(node) {
2711
2957
  this.executor.addNode(node);
2712
2958
  return this;
@@ -2724,9 +2970,11 @@ var AgentGraphImpl = class {
2724
2970
  return this;
2725
2971
  }
2726
2972
  async run(input) {
2973
+ this.executor.setEventSink((event) => this.bus.emit(event.type, event));
2727
2974
  return this.executor.run(input);
2728
2975
  }
2729
2976
  async *stream(input) {
2977
+ this.executor.setEventSink((event) => this.bus.emit(event.type, event));
2730
2978
  yield* this.executor.stream(input);
2731
2979
  }
2732
2980
  getState() {
@@ -2736,17 +2984,12 @@ var AgentGraphImpl = class {
2736
2984
  this.executor.abort();
2737
2985
  }
2738
2986
  on(event, listener) {
2739
- let set = this.eventListeners.get(event);
2740
- if (!set) {
2741
- set = /* @__PURE__ */ new Set();
2742
- this.eventListeners.set(event, set);
2743
- }
2744
- set.add(listener);
2987
+ this.bus.on(event, listener);
2745
2988
  return this;
2746
2989
  }
2747
2990
  };
2748
- function createAgentGraph() {
2749
- return new AgentGraphImpl();
2991
+ function createAgentGraph(opts) {
2992
+ return new AgentGraphImpl(opts);
2750
2993
  }
2751
2994
 
2752
2995
  // patterns/pipeline.ts
@@ -2784,14 +3027,19 @@ function createRouter(router, targets, opts) {
2784
3027
  }
2785
3028
  graph.setEntry(router.id);
2786
3029
  const targetIds = new Set(targets.map((t) => t.id));
3030
+ const defaultTarget = opts.defaultTarget && targetIds.has(opts.defaultTarget) ? opts.defaultTarget : void 0;
3031
+ const resolveTarget = (routerResult) => {
3032
+ const resolvedId = opts.resolve(routerResult);
3033
+ if (targetIds.has(resolvedId)) return resolvedId;
3034
+ return defaultTarget ?? resolvedId;
3035
+ };
2787
3036
  for (const target of targets) {
2788
3037
  graph.addEdge({
2789
3038
  from: router.id,
2790
3039
  to: target.id,
2791
- // 条件:从路由器结果中解析目标ID,匹配当前目标
3040
+ // 条件:从路由器结果中解析目标ID(含 defaultTarget 兜底),匹配当前目标
2792
3041
  condition: (routerResult, _ctx) => {
2793
- const resolvedId = opts.resolve(routerResult);
2794
- return resolvedId === target.id;
3042
+ return resolveTarget(routerResult) === target.id;
2795
3043
  },
2796
3044
  // 转换:决定传给目标Agent的输入
2797
3045
  transform: (_routerResult, _ctx) => {
@@ -2803,8 +3051,6 @@ function createRouter(router, targets, opts) {
2803
3051
  }
2804
3052
  });
2805
3053
  }
2806
- if (opts.defaultTarget && targetIds.has(opts.defaultTarget)) {
2807
- }
2808
3054
  return graph;
2809
3055
  }
2810
3056
 
@@ -2813,6 +3059,11 @@ var SupervisorExecutor = class {
2813
3059
  supervisorNode;
2814
3060
  workerNodes;
2815
3061
  opts;
3062
+ abortController = new AbortController();
3063
+ /** 外部事件监听(on() API 的底层接线) */
3064
+ eventSink;
3065
+ /** 最近一次 run 中失败的 Worker ID(onWorkerError='skip' 时使用) */
3066
+ failedAgents = [];
2816
3067
  state = {
2817
3068
  nodeStates: /* @__PURE__ */ new Map(),
2818
3069
  nodeResults: /* @__PURE__ */ new Map(),
@@ -2825,7 +3076,8 @@ var SupervisorExecutor = class {
2825
3076
  this.opts = {
2826
3077
  schedule: opts?.schedule ?? "parallel",
2827
3078
  concurrency: opts?.concurrency ?? Infinity,
2828
- passOriginalInput: opts?.passOriginalInput ?? true
3079
+ passOriginalInput: opts?.passOriginalInput ?? true,
3080
+ onWorkerError: opts?.onWorkerError ?? "fail-fast"
2829
3081
  };
2830
3082
  this.state.nodeStates.set(supervisor.id, "pending");
2831
3083
  for (const w of workers) {
@@ -2833,69 +3085,91 @@ var SupervisorExecutor = class {
2833
3085
  }
2834
3086
  }
2835
3087
  getState() {
2836
- return { ...this.state };
3088
+ return {
3089
+ ...this.state,
3090
+ nodeStates: new Map(this.state.nodeStates),
3091
+ nodeResults: new Map(this.state.nodeResults)
3092
+ };
3093
+ }
3094
+ /** 注入外部事件监听(由 AgentGraph 实现的 on() 接线) */
3095
+ setEventSink(sink) {
3096
+ this.eventSink = sink;
3097
+ return this;
3098
+ }
3099
+ abort() {
3100
+ this.abortController.abort();
3101
+ }
3102
+ /** 每次 run/stream 前重置中止信号、失败记录与执行状态 */
3103
+ resetRun() {
3104
+ this.abortController = new AbortController();
3105
+ this.failedAgents = [];
3106
+ this.state = {
3107
+ nodeStates: /* @__PURE__ */ new Map(),
3108
+ nodeResults: /* @__PURE__ */ new Map(),
3109
+ stepsCompleted: 0,
3110
+ finished: false
3111
+ };
3112
+ this.state.nodeStates.set(this.supervisorNode.id, "pending");
3113
+ for (const w of this.workerNodes) {
3114
+ this.state.nodeStates.set(w.id, "pending");
3115
+ }
3116
+ }
3117
+ throwIfAborted() {
3118
+ if (this.abortController.signal.aborted) {
3119
+ throw new GraphAbortedError();
3120
+ }
2837
3121
  }
2838
3122
  /** 执行 Supervisor 模式 */
2839
3123
  async run(input) {
3124
+ this.resetRun();
2840
3125
  const ctx = createSharedContext({
2841
3126
  meta: { traceId: `sv-${Date.now()}`, startTime: Date.now() }
2842
3127
  });
2843
3128
  if (this.opts.passOriginalInput) {
2844
- const inputText = typeof input === "string" ? input : input.message;
2845
- ctx.blackboard.set("__original_input__", inputText);
3129
+ storeOriginalInput(ctx, input);
2846
3130
  }
3131
+ const emit = this.eventSink ?? (() => {
3132
+ });
2847
3133
  try {
2848
- return await this.executeSupervisor(input, ctx, () => {
2849
- });
3134
+ const result = await this.executeSupervisor(input, ctx, emit);
3135
+ emit({ type: "graph_done", result });
3136
+ return result;
2850
3137
  } catch (err) {
2851
- return this.buildErrorResult(ctx, err);
3138
+ const result = this.buildErrorResult(ctx, err);
3139
+ emit({ type: "graph_error", error: result.error ?? "" });
3140
+ return result;
2852
3141
  }
2853
3142
  }
2854
3143
  /** 流式执行 Supervisor 模式 */
2855
- async *stream(input) {
3144
+ stream(input) {
3145
+ this.resetRun();
2856
3146
  const ctx = createSharedContext({
2857
3147
  meta: { traceId: `sv-${Date.now()}`, startTime: Date.now() }
2858
3148
  });
2859
3149
  if (this.opts.passOriginalInput) {
2860
- const inputText = typeof input === "string" ? input : input.message;
2861
- ctx.blackboard.set("__original_input__", inputText);
2862
- }
2863
- const eventQueue = [];
2864
- let resolveEvent = null;
2865
- let done = false;
2866
- const emit = (event) => {
2867
- eventQueue.push(event);
2868
- resolveEvent?.();
2869
- };
2870
- const graphPromise = this.executeSupervisor(input, ctx, emit).then(
2871
- (result) => {
2872
- emit({ type: "graph_done", result });
2873
- },
2874
- (err) => {
2875
- emit({ type: "graph_error", error: err instanceof Error ? err.message : String(err) });
2876
- }
2877
- ).finally(() => {
2878
- done = true;
2879
- resolveEvent?.();
2880
- });
2881
- while (!done || eventQueue.length > 0) {
2882
- if (eventQueue.length > 0) {
2883
- yield eventQueue.shift();
2884
- } else {
2885
- await new Promise((resolve) => {
2886
- resolveEvent = resolve;
2887
- });
2888
- }
3150
+ storeOriginalInput(ctx, input);
2889
3151
  }
2890
- await graphPromise;
3152
+ return createEventStream(
3153
+ (emit) => this.executeSupervisor(input, ctx, emit).then(
3154
+ (result) => {
3155
+ emit({ type: "graph_done", result });
3156
+ },
3157
+ (err) => {
3158
+ this.state.error = err instanceof Error ? err.message : String(err);
3159
+ emit({ type: "graph_error", error: this.state.error });
3160
+ }
3161
+ ),
3162
+ this.eventSink
3163
+ );
2891
3164
  }
2892
3165
  /** 核心执行逻辑 */
2893
3166
  async executeSupervisor(input, ctx, emit) {
2894
3167
  let stepsCompleted = 0;
2895
3168
  const totalUsage = {};
3169
+ this.throwIfAborted();
2896
3170
  this.state.currentAgentId = this.supervisorNode.id;
2897
3171
  this.state.nodeStates.set(this.supervisorNode.id, "running");
2898
- emit({ type: "agent_start", agentId: this.supervisorNode.id, agentName: this.supervisorNode.name });
3172
+ emit({ type: "agent_start", agentId: this.supervisorNode.id, agentName: this.supervisorNode.name, input: toInputText(input) });
2899
3173
  let supervisorResult;
2900
3174
  try {
2901
3175
  supervisorResult = await executeNode(this.supervisorNode, input, ctx);
@@ -2922,18 +3196,21 @@ var SupervisorExecutor = class {
2922
3196
  }
2923
3197
  stepsCompleted += workerResults.size;
2924
3198
  this.state.stepsCompleted = stepsCompleted;
2925
- const lastWorkerId = this.workerNodes[this.workerNodes.length - 1].id;
2926
- const finalResult = workerResults.get(lastWorkerId) ?? supervisorResult;
3199
+ const lastEntry = [...workerResults.entries()].at(-1);
3200
+ const finalResult = lastEntry?.[1] ?? supervisorResult;
3201
+ const finalAgentId = lastEntry?.[0] ?? this.supervisorNode.id;
3202
+ const hasFailures = this.failedAgents.length > 0;
2927
3203
  this.state.finished = true;
2928
3204
  return {
2929
3205
  content: finalResult.content,
2930
- lastAgentId: lastWorkerId,
3206
+ lastAgentId: finalAgentId,
2931
3207
  agentResults: new Map(this.state.nodeResults),
2932
3208
  totalUsage,
2933
3209
  stepsCompleted,
2934
- stopReason: "completed",
3210
+ stopReason: hasFailures ? "partial_failure" : "completed",
2935
3211
  context: ctx,
2936
- success: true
3212
+ success: true,
3213
+ ...hasFailures ? { failedAgents: [...this.failedAgents] } : {}
2937
3214
  };
2938
3215
  }
2939
3216
  /** 并行执行所有 Worker */
@@ -2941,16 +3218,28 @@ var SupervisorExecutor = class {
2941
3218
  const results = /* @__PURE__ */ new Map();
2942
3219
  const workers = this.workerNodes;
2943
3220
  const concurrency = this.opts.concurrency;
3221
+ const skip = this.opts.onWorkerError === "skip";
2944
3222
  emit({ type: "parallel_start", agentIds: workers.map((w) => w.id) });
2945
3223
  if (concurrency >= workers.length) {
2946
- const promises = workers.map(async (worker) => {
2947
- return this.executeWorker(worker, ctx, emit, totalUsage);
2948
- });
2949
- const settled = await Promise.allSettled(promises);
2950
- for (let i = 0; i < settled.length; i++) {
2951
- const s = settled[i];
2952
- if (s.status === "fulfilled") {
2953
- results.set(workers[i].id, s.value);
3224
+ if (!skip) {
3225
+ await Promise.all(
3226
+ workers.map(async (worker) => {
3227
+ const r = await this.executeWorker(worker, ctx, emit, totalUsage);
3228
+ results.set(worker.id, r);
3229
+ return r;
3230
+ })
3231
+ );
3232
+ } else {
3233
+ const settled = await Promise.allSettled(
3234
+ workers.map((worker) => this.executeWorker(worker, ctx, emit, totalUsage))
3235
+ );
3236
+ for (let i = 0; i < settled.length; i++) {
3237
+ const s = settled[i];
3238
+ if (s.status === "fulfilled") {
3239
+ results.set(workers[i].id, s.value);
3240
+ } else {
3241
+ this.failedAgents.push(workers[i].id);
3242
+ }
2954
3243
  }
2955
3244
  }
2956
3245
  } else {
@@ -2959,12 +3248,20 @@ var SupervisorExecutor = class {
2959
3248
  const enqueue = () => {
2960
3249
  if (index >= workers.length) return null;
2961
3250
  const worker = workers[index++];
2962
- const p = this.executeWorker(worker, ctx, emit, totalUsage).then((r) => {
2963
- results.set(worker.id, r);
3251
+ const p = this.executeWorker(worker, ctx, emit, totalUsage).then(
3252
+ (r) => {
3253
+ results.set(worker.id, r);
3254
+ },
3255
+ (err) => {
3256
+ if (!skip) throw err;
3257
+ this.failedAgents.push(worker.id);
3258
+ }
3259
+ ).finally(() => {
2964
3260
  executing.delete(p);
2965
- return r;
2966
3261
  });
2967
3262
  executing.add(p);
3263
+ p.catch(() => {
3264
+ });
2968
3265
  return p;
2969
3266
  };
2970
3267
  for (let i = 0; i < concurrency && index < workers.length; i++) {
@@ -2981,40 +3278,122 @@ var SupervisorExecutor = class {
2981
3278
  /** 顺序执行所有 Worker */
2982
3279
  async executeWorkersSequential(ctx, emit, totalUsage) {
2983
3280
  const results = /* @__PURE__ */ new Map();
3281
+ const skip = this.opts.onWorkerError === "skip";
2984
3282
  for (const worker of this.workerNodes) {
2985
- const result = await this.executeWorker(worker, ctx, emit, totalUsage);
2986
- results.set(worker.id, result);
3283
+ try {
3284
+ const result = await this.executeWorker(worker, ctx, emit, totalUsage);
3285
+ results.set(worker.id, result);
3286
+ } catch (err) {
3287
+ if (!skip) throw err;
3288
+ this.failedAgents.push(worker.id);
3289
+ }
2987
3290
  }
2988
3291
  return results;
2989
3292
  }
2990
- /** 自动调度:根据 inputMapping 依赖分层执行 */
3293
+ /** 自动调度:按依赖分层执行
3294
+ *
3295
+ * 依赖推导规则:
3296
+ * 1. 显式声明 dependsOn 的 worker:依赖指定的 worker(依赖必须都在 workers 列表中,否则报错)
3297
+ * 2. 未声明 dependsOn 但有 inputMapping 的 worker:隐式依赖所有"第 0 层"worker(保持向后兼容)
3298
+ * 3. 其余 worker(无 dependsOn 且无 inputMapping):第 0 层,首批并行
3299
+ *
3300
+ * 按拓扑分层:同层并行执行(受 concurrency 限制),层间按序执行;依赖成环时报错。
3301
+ */
2991
3302
  async executeWorkersAuto(ctx, emit, totalUsage) {
2992
3303
  const results = /* @__PURE__ */ new Map();
2993
- const noInputMapping = this.workerNodes.filter((w) => !w.inputMapping);
2994
- const withInputMapping = this.workerNodes.filter((w) => !!w.inputMapping);
2995
- if (noInputMapping.length > 0) {
2996
- emit({ type: "parallel_start", agentIds: noInputMapping.map((w) => w.id) });
2997
- const batchResults = await Promise.all(
2998
- noInputMapping.map((w) => this.executeWorker(w, ctx, emit, totalUsage))
2999
- );
3000
- for (let i = 0; i < noInputMapping.length; i++) {
3001
- results.set(noInputMapping[i].id, batchResults[i]);
3304
+ const skip = this.opts.onWorkerError === "skip";
3305
+ const workerIds = new Set(this.workerNodes.map((w) => w.id));
3306
+ const layer0 = this.workerNodes.filter((w) => !w.inputMapping && !w.dependsOn);
3307
+ const deps = /* @__PURE__ */ new Map();
3308
+ for (const w of this.workerNodes) {
3309
+ if (w.dependsOn) {
3310
+ for (const dep of w.dependsOn) {
3311
+ if (!workerIds.has(dep)) {
3312
+ throw new Error(`Supervisor: Worker "${w.id}" \u7684 dependsOn \u5F15\u7528\u4E86\u4E0D\u5B58\u5728\u7684 Worker "${dep}"`);
3313
+ }
3314
+ }
3315
+ deps.set(w.id, new Set(w.dependsOn));
3316
+ } else if (w.inputMapping) {
3317
+ deps.set(w.id, new Set(layer0.map((l) => l.id)));
3318
+ } else {
3319
+ deps.set(w.id, /* @__PURE__ */ new Set());
3002
3320
  }
3003
- emit({ type: "parallel_done", results: new Map(results) });
3004
3321
  }
3005
- for (const worker of withInputMapping) {
3006
- const result = await this.executeWorker(worker, ctx, emit, totalUsage);
3007
- results.set(worker.id, result);
3322
+ const remaining = new Map(deps);
3323
+ const layers = [];
3324
+ const doneIds = /* @__PURE__ */ new Set();
3325
+ while (remaining.size > 0) {
3326
+ const layer = [];
3327
+ for (const [id, depSet] of remaining) {
3328
+ if ([...depSet].every((d) => doneIds.has(d))) {
3329
+ layer.push(this.workerNodes.find((w) => w.id === id));
3330
+ }
3331
+ }
3332
+ if (layer.length === 0) {
3333
+ throw new Error(`Supervisor: auto \u8C03\u5EA6\u7684 Worker \u4F9D\u8D56\u5B58\u5728\u73AF\uFF08\u6D89\u53CA: ${[...remaining.keys()].join(", ")}\uFF09`);
3334
+ }
3335
+ for (const w of layer) {
3336
+ remaining.delete(w.id);
3337
+ doneIds.add(w.id);
3338
+ }
3339
+ layers.push(layer);
3340
+ }
3341
+ for (const layer of layers) {
3342
+ if (layer.length === 1) {
3343
+ try {
3344
+ const r = await this.executeWorker(layer[0], ctx, emit, totalUsage);
3345
+ results.set(layer[0].id, r);
3346
+ } catch (err) {
3347
+ if (!skip) throw err;
3348
+ this.failedAgents.push(layer[0].id);
3349
+ }
3350
+ continue;
3351
+ }
3352
+ emit({ type: "parallel_start", agentIds: layer.map((w) => w.id) });
3353
+ const runOne = async (worker) => {
3354
+ try {
3355
+ const r = await this.executeWorker(worker, ctx, emit, totalUsage);
3356
+ results.set(worker.id, r);
3357
+ } catch (err) {
3358
+ if (!skip) throw err;
3359
+ this.failedAgents.push(worker.id);
3360
+ }
3361
+ };
3362
+ if (this.opts.concurrency >= layer.length) {
3363
+ await Promise.all(layer.map((w) => runOne(w)));
3364
+ } else {
3365
+ let index = 0;
3366
+ const executing = /* @__PURE__ */ new Set();
3367
+ const enqueue = () => {
3368
+ if (index >= layer.length) return null;
3369
+ const i = index++;
3370
+ const p = runOne(layer[i]).finally(() => {
3371
+ executing.delete(p);
3372
+ });
3373
+ executing.add(p);
3374
+ p.catch(() => {
3375
+ });
3376
+ return p;
3377
+ };
3378
+ for (let i = 0; i < this.opts.concurrency && index < layer.length; i++) {
3379
+ enqueue();
3380
+ }
3381
+ while (executing.size > 0) {
3382
+ await Promise.race(executing);
3383
+ enqueue();
3384
+ }
3385
+ }
3386
+ emit({ type: "parallel_done", results: new Map(results) });
3008
3387
  }
3009
3388
  return results;
3010
3389
  }
3011
3390
  /** 执行单个 Worker */
3012
3391
  async executeWorker(worker, ctx, emit, totalUsage) {
3392
+ this.throwIfAborted();
3013
3393
  this.state.currentAgentId = worker.id;
3014
3394
  this.state.nodeStates.set(worker.id, "running");
3015
- emit({ type: "agent_start", agentId: worker.id, agentName: worker.name });
3395
+ let workerInput;
3016
3396
  try {
3017
- let workerInput;
3018
3397
  if (worker.inputMapping) {
3019
3398
  workerInput = worker.inputMapping(ctx);
3020
3399
  } else {
@@ -3022,6 +3401,14 @@ var SupervisorExecutor = class {
3022
3401
  const myTask = tasks?.find((t) => t.assignee === worker.id);
3023
3402
  workerInput = myTask ? myTask.task : ctx.blackboard.get("__original_input__") ?? "";
3024
3403
  }
3404
+ } catch (err) {
3405
+ const errorMsg = err instanceof Error ? err.message : String(err);
3406
+ this.state.nodeStates.set(worker.id, "failed");
3407
+ emit({ type: "agent_error", agentId: worker.id, agentName: worker.name, error: errorMsg });
3408
+ throw err;
3409
+ }
3410
+ emit({ type: "agent_start", agentId: worker.id, agentName: worker.name, input: toInputText(workerInput) });
3411
+ try {
3025
3412
  const result = await executeNode(worker, workerInput, ctx);
3026
3413
  this.state.nodeStates.set(worker.id, "completed");
3027
3414
  this.state.nodeResults.set(worker.id, result);
@@ -3038,16 +3425,21 @@ var SupervisorExecutor = class {
3038
3425
  }
3039
3426
  buildErrorResult(ctx, err) {
3040
3427
  this.state.finished = true;
3428
+ const aborted = err instanceof GraphAbortedError;
3429
+ const errorMsg = err instanceof Error ? err.message : String(err);
3430
+ this.state.error = errorMsg;
3431
+ const lastCompleted = [...this.state.nodeResults.values()].at(-1);
3041
3432
  return {
3042
- content: "",
3043
- lastAgentId: this.supervisorNode.id,
3433
+ content: aborted ? lastCompleted?.content ?? "" : "",
3434
+ lastAgentId: this.state.currentAgentId ?? this.supervisorNode.id,
3044
3435
  agentResults: new Map(this.state.nodeResults),
3045
3436
  totalUsage: {},
3046
3437
  stepsCompleted: this.state.stepsCompleted,
3047
- stopReason: "error",
3438
+ stopReason: aborted ? "aborted" : "error",
3048
3439
  context: ctx,
3049
3440
  success: false,
3050
- error: err instanceof Error ? err.message : String(err)
3441
+ error: errorMsg,
3442
+ ...this.failedAgents.length > 0 ? { failedAgents: [...this.failedAgents] } : {}
3051
3443
  };
3052
3444
  }
3053
3445
  mergeUsage(total, usage) {
@@ -3060,7 +3452,8 @@ var SupervisorExecutor = class {
3060
3452
  // patterns/supervisor.ts
3061
3453
  var SupervisorGraphImpl = class {
3062
3454
  executor;
3063
- eventListeners = /* @__PURE__ */ new Map();
3455
+ /** on() 注册的监听器,按 MultiAgentEvent.type 分发 */
3456
+ bus = new SimpleEventBus();
3064
3457
  constructor(supervisor, workers, opts) {
3065
3458
  this.executor = new SupervisorExecutor(supervisor, workers, opts);
3066
3459
  }
@@ -3078,23 +3471,21 @@ var SupervisorGraphImpl = class {
3078
3471
  throw new Error("Supervisor \u6A21\u5F0F\u4E0D\u652F\u6301 setFinish\uFF0C\u7EC8\u6B62\u7531 Supervisor \u5224\u5B9A");
3079
3472
  }
3080
3473
  async run(input) {
3474
+ this.executor.setEventSink((event) => this.bus.emit(event.type, event));
3081
3475
  return this.executor.run(input);
3082
3476
  }
3083
3477
  async *stream(input) {
3478
+ this.executor.setEventSink((event) => this.bus.emit(event.type, event));
3084
3479
  yield* this.executor.stream(input);
3085
3480
  }
3086
3481
  getState() {
3087
3482
  return this.executor.getState();
3088
3483
  }
3089
3484
  abort() {
3485
+ this.executor.abort();
3090
3486
  }
3091
3487
  on(event, listener) {
3092
- let set = this.eventListeners.get(event);
3093
- if (!set) {
3094
- set = /* @__PURE__ */ new Set();
3095
- this.eventListeners.set(event, set);
3096
- }
3097
- set.add(listener);
3488
+ this.bus.on(event, listener);
3098
3489
  return this;
3099
3490
  }
3100
3491
  };
@@ -3112,6 +3503,9 @@ var DebateExecutor = class {
3112
3503
  maxRounds;
3113
3504
  convergeWhen;
3114
3505
  feedbackTransform;
3506
+ abortController = new AbortController();
3507
+ /** 外部事件监听(on() API 的底层接线) */
3508
+ eventSink;
3115
3509
  state = {
3116
3510
  nodeStates: /* @__PURE__ */ new Map(),
3117
3511
  nodeResults: /* @__PURE__ */ new Map(),
@@ -3134,53 +3528,75 @@ ${proposerResult.content}`;
3134
3528
  this.state.nodeStates.set(reviewer.id, "pending");
3135
3529
  }
3136
3530
  getState() {
3137
- return { ...this.state };
3531
+ return {
3532
+ ...this.state,
3533
+ nodeStates: new Map(this.state.nodeStates),
3534
+ nodeResults: new Map(this.state.nodeResults)
3535
+ };
3536
+ }
3537
+ /** 注入外部事件监听(由 AgentGraph 实现的 on() 接线) */
3538
+ setEventSink(sink) {
3539
+ this.eventSink = sink;
3540
+ return this;
3541
+ }
3542
+ abort() {
3543
+ this.abortController.abort();
3544
+ }
3545
+ /** 每次 run/stream 前重置中止信号与执行状态 */
3546
+ resetAbortController() {
3547
+ this.abortController = new AbortController();
3548
+ this.state = {
3549
+ nodeStates: /* @__PURE__ */ new Map(),
3550
+ nodeResults: /* @__PURE__ */ new Map(),
3551
+ stepsCompleted: 0,
3552
+ finished: false
3553
+ };
3554
+ this.state.nodeStates.set(this.proposerNode.id, "pending");
3555
+ this.state.nodeStates.set(this.reviewerNode.id, "pending");
3556
+ }
3557
+ throwIfAborted() {
3558
+ if (this.abortController.signal.aborted) {
3559
+ throw new GraphAbortedError();
3560
+ }
3138
3561
  }
3139
3562
  /** 执行 Debate */
3140
3563
  async run(input) {
3564
+ this.resetAbortController();
3141
3565
  const ctx = createSharedContext({
3142
3566
  meta: { traceId: `debate-${Date.now()}`, startTime: Date.now() }
3143
3567
  });
3568
+ storeOriginalInput(ctx, input);
3569
+ const emit = this.eventSink ?? (() => {
3570
+ });
3144
3571
  try {
3145
- return await this.executeDebate(input, ctx, () => {
3146
- });
3572
+ const result = await this.executeDebate(input, ctx, emit);
3573
+ emit({ type: "graph_done", result });
3574
+ return result;
3147
3575
  } catch (err) {
3148
- return this.buildErrorResult(ctx, err);
3576
+ const result = this.buildErrorResult(ctx, err);
3577
+ emit({ type: "graph_error", error: result.error ?? "" });
3578
+ return result;
3149
3579
  }
3150
3580
  }
3151
3581
  /** 流式执行 Debate */
3152
- async *stream(input) {
3582
+ stream(input) {
3583
+ this.resetAbortController();
3153
3584
  const ctx = createSharedContext({
3154
3585
  meta: { traceId: `debate-${Date.now()}`, startTime: Date.now() }
3155
3586
  });
3156
- const eventQueue = [];
3157
- let resolveEvent = null;
3158
- let done = false;
3159
- const emit = (event) => {
3160
- eventQueue.push(event);
3161
- resolveEvent?.();
3162
- };
3163
- const graphPromise = this.executeDebate(input, ctx, emit).then(
3164
- (result) => {
3165
- emit({ type: "graph_done", result });
3166
- },
3167
- (err) => {
3168
- emit({ type: "graph_error", error: err instanceof Error ? err.message : String(err) });
3169
- }
3170
- ).finally(() => {
3171
- done = true;
3172
- resolveEvent?.();
3173
- });
3174
- while (!done || eventQueue.length > 0) {
3175
- if (eventQueue.length > 0) {
3176
- yield eventQueue.shift();
3177
- } else {
3178
- await new Promise((resolve) => {
3179
- resolveEvent = resolve;
3180
- });
3181
- }
3182
- }
3183
- await graphPromise;
3587
+ storeOriginalInput(ctx, input);
3588
+ return createEventStream(
3589
+ (emit) => this.executeDebate(input, ctx, emit).then(
3590
+ (result) => {
3591
+ emit({ type: "graph_done", result });
3592
+ },
3593
+ (err) => {
3594
+ this.state.error = err instanceof Error ? err.message : String(err);
3595
+ emit({ type: "graph_error", error: this.state.error });
3596
+ }
3597
+ ),
3598
+ this.eventSink
3599
+ );
3184
3600
  }
3185
3601
  /** 核心执行逻辑 */
3186
3602
  async executeDebate(input, ctx, emit) {
@@ -3192,10 +3608,11 @@ ${proposerResult.content}`;
3192
3608
  let convergeReason = "";
3193
3609
  let currentInput = input;
3194
3610
  for (let round = 1; round <= this.maxRounds; round++) {
3611
+ this.throwIfAborted();
3195
3612
  emit({ type: "round_start", round });
3196
3613
  this.state.currentAgentId = this.proposerNode.id;
3197
3614
  this.state.nodeStates.set(this.proposerNode.id, "running");
3198
- emit({ type: "agent_start", agentId: this.proposerNode.id, agentName: this.proposerNode.name });
3615
+ emit({ type: "agent_start", agentId: this.proposerNode.id, agentName: this.proposerNode.name, input: toInputText(currentInput) });
3199
3616
  try {
3200
3617
  lastProposerResult = await executeNode(this.proposerNode, currentInput, ctx);
3201
3618
  this.state.nodeStates.set(this.proposerNode.id, "completed");
@@ -3212,7 +3629,7 @@ ${proposerResult.content}`;
3212
3629
  }
3213
3630
  this.state.currentAgentId = this.reviewerNode.id;
3214
3631
  this.state.nodeStates.set(this.reviewerNode.id, "running");
3215
- emit({ type: "agent_start", agentId: this.reviewerNode.id, agentName: this.reviewerNode.name });
3632
+ emit({ type: "agent_start", agentId: this.reviewerNode.id, agentName: this.reviewerNode.name, input: lastProposerResult.content });
3216
3633
  try {
3217
3634
  lastReviewerResult = await executeNode(this.reviewerNode, lastProposerResult.content, ctx);
3218
3635
  this.state.nodeStates.set(this.reviewerNode.id, "completed");
@@ -3251,16 +3668,20 @@ ${proposerResult.content}`;
3251
3668
  }
3252
3669
  buildErrorResult(ctx, err) {
3253
3670
  this.state.finished = true;
3671
+ const aborted = err instanceof GraphAbortedError;
3672
+ const errorMsg = err instanceof Error ? err.message : String(err);
3673
+ this.state.error = errorMsg;
3674
+ const lastCompleted = [...this.state.nodeResults.values()].at(-1);
3254
3675
  return {
3255
- content: "",
3676
+ content: aborted ? lastCompleted?.content ?? "" : "",
3256
3677
  lastAgentId: this.proposerNode.id,
3257
3678
  agentResults: new Map(this.state.nodeResults),
3258
3679
  totalUsage: {},
3259
3680
  stepsCompleted: this.state.stepsCompleted,
3260
- stopReason: "error",
3681
+ stopReason: aborted ? "aborted" : "error",
3261
3682
  context: ctx,
3262
3683
  success: false,
3263
- error: err instanceof Error ? err.message : String(err)
3684
+ error: errorMsg
3264
3685
  };
3265
3686
  }
3266
3687
  mergeUsage(total, usage) {
@@ -3273,7 +3694,8 @@ ${proposerResult.content}`;
3273
3694
  // patterns/debate.ts
3274
3695
  var DebateGraphImpl = class {
3275
3696
  executor;
3276
- eventListeners = /* @__PURE__ */ new Map();
3697
+ /** on() 注册的监听器,按 MultiAgentEvent.type 分发 */
3698
+ bus = new SimpleEventBus();
3277
3699
  constructor(proposer, reviewer, opts) {
3278
3700
  this.executor = new DebateExecutor(proposer, reviewer, opts);
3279
3701
  }
@@ -3290,23 +3712,21 @@ var DebateGraphImpl = class {
3290
3712
  throw new Error("Debate \u6A21\u5F0F\u4E0D\u652F\u6301 setFinish");
3291
3713
  }
3292
3714
  async run(input) {
3715
+ this.executor.setEventSink((event) => this.bus.emit(event.type, event));
3293
3716
  return this.executor.run(input);
3294
3717
  }
3295
3718
  async *stream(input) {
3719
+ this.executor.setEventSink((event) => this.bus.emit(event.type, event));
3296
3720
  yield* this.executor.stream(input);
3297
3721
  }
3298
3722
  getState() {
3299
3723
  return this.executor.getState();
3300
3724
  }
3301
3725
  abort() {
3726
+ this.executor.abort();
3302
3727
  }
3303
3728
  on(event, listener) {
3304
- let set = this.eventListeners.get(event);
3305
- if (!set) {
3306
- set = /* @__PURE__ */ new Set();
3307
- this.eventListeners.set(event, set);
3308
- }
3309
- set.add(listener);
3729
+ this.bus.on(event, listener);
3310
3730
  return this;
3311
3731
  }
3312
3732
  };
@@ -3320,7 +3740,11 @@ var MapReduceExecutor = class {
3320
3740
  reducerNode;
3321
3741
  split;
3322
3742
  concurrency;
3743
+ onMapperError;
3323
3744
  reduceInputFormat;
3745
+ abortController = new AbortController();
3746
+ /** 外部事件监听(on() API 的底层接线) */
3747
+ eventSink;
3324
3748
  state = {
3325
3749
  nodeStates: /* @__PURE__ */ new Map(),
3326
3750
  nodeResults: /* @__PURE__ */ new Map(),
@@ -3332,6 +3756,7 @@ var MapReduceExecutor = class {
3332
3756
  this.reducerNode = reducer;
3333
3757
  this.split = opts.split;
3334
3758
  this.concurrency = opts.concurrency ?? Infinity;
3759
+ this.onMapperError = opts.onMapperError ?? "fail-fast";
3335
3760
  this.reduceInputFormat = opts.reduceInputFormat ?? ((mapperResults) => {
3336
3761
  const parts = [];
3337
3762
  for (const [idx, result] of mapperResults) {
@@ -3344,132 +3769,98 @@ ${result.content}`);
3344
3769
  this.state.nodeStates.set(reducer.id, "pending");
3345
3770
  }
3346
3771
  getState() {
3347
- return { ...this.state };
3772
+ return {
3773
+ ...this.state,
3774
+ nodeStates: new Map(this.state.nodeStates),
3775
+ nodeResults: new Map(this.state.nodeResults)
3776
+ };
3348
3777
  }
3349
- /** 执行 MapReduce */
3350
- async run(input) {
3778
+ /** 注入外部事件监听(由 AgentGraph 实现的 on() 接线) */
3779
+ setEventSink(sink) {
3780
+ this.eventSink = sink;
3781
+ return this;
3782
+ }
3783
+ abort() {
3784
+ this.abortController.abort();
3785
+ }
3786
+ /** 每次 run/stream 前重置中止信号与执行状态 */
3787
+ resetAbortController() {
3788
+ this.abortController = new AbortController();
3789
+ this.state = {
3790
+ nodeStates: /* @__PURE__ */ new Map(),
3791
+ nodeResults: /* @__PURE__ */ new Map(),
3792
+ stepsCompleted: 0,
3793
+ finished: false
3794
+ };
3795
+ this.state.nodeStates.set(this.mapperNode.id, "pending");
3796
+ this.state.nodeStates.set(this.reducerNode.id, "pending");
3797
+ }
3798
+ throwIfAborted() {
3799
+ if (this.abortController.signal.aborted) {
3800
+ throw new GraphAbortedError();
3801
+ }
3802
+ }
3803
+ /** 拆分输入并校验(每次 run/stream 只调用一次 split,避免副作用放大) */
3804
+ splitInput(input) {
3351
3805
  const inputText = typeof input === "string" ? input : input.message;
3352
3806
  const chunks = this.split(inputText);
3353
3807
  if (chunks.length === 0) {
3354
3808
  throw new Error("MapReduce: split \u51FD\u6570\u8FD4\u56DE\u4E86\u7A7A\u6570\u7EC4\uFF0C\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u4EFB\u52A1");
3355
3809
  }
3810
+ return chunks;
3811
+ }
3812
+ /** 执行 MapReduce */
3813
+ async run(input) {
3814
+ this.resetAbortController();
3815
+ const chunks = this.splitInput(input);
3356
3816
  const ctx = createSharedContext({
3357
3817
  meta: { traceId: `mr-${Date.now()}`, startTime: Date.now() }
3358
3818
  });
3819
+ storeOriginalInput(ctx, input);
3820
+ const emit = this.eventSink ?? (() => {
3821
+ });
3359
3822
  try {
3360
- return await this.executeMapReduce(input, ctx, () => {
3361
- });
3823
+ const result = await this.executeMapReduce(chunks, ctx, emit);
3824
+ emit({ type: "graph_done", result });
3825
+ return result;
3362
3826
  } catch (err) {
3363
- return this.buildErrorResult(ctx, err);
3827
+ const result = this.buildErrorResult(ctx, err);
3828
+ emit({ type: "graph_error", error: result.error ?? "" });
3829
+ return result;
3364
3830
  }
3365
3831
  }
3366
3832
  /** 流式执行 MapReduce */
3367
- async *stream(input) {
3368
- const inputText = typeof input === "string" ? input : input.message;
3369
- const chunks = this.split(inputText);
3370
- if (chunks.length === 0) {
3371
- throw new Error("MapReduce: split \u51FD\u6570\u8FD4\u56DE\u4E86\u7A7A\u6570\u7EC4\uFF0C\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u4EFB\u52A1");
3372
- }
3833
+ stream(input) {
3834
+ this.resetAbortController();
3835
+ const chunks = this.splitInput(input);
3373
3836
  const ctx = createSharedContext({
3374
3837
  meta: { traceId: `mr-${Date.now()}`, startTime: Date.now() }
3375
3838
  });
3376
- const eventQueue = [];
3377
- let resolveEvent = null;
3378
- let done = false;
3379
- const emit = (event) => {
3380
- eventQueue.push(event);
3381
- resolveEvent?.();
3382
- };
3383
- const graphPromise = this.executeMapReduce(input, ctx, emit).then(
3384
- (result) => {
3385
- emit({ type: "graph_done", result });
3386
- },
3387
- (err) => {
3388
- emit({ type: "graph_error", error: err instanceof Error ? err.message : String(err) });
3389
- }
3390
- ).finally(() => {
3391
- done = true;
3392
- resolveEvent?.();
3393
- });
3394
- while (!done || eventQueue.length > 0) {
3395
- if (eventQueue.length > 0) {
3396
- yield eventQueue.shift();
3397
- } else {
3398
- await new Promise((resolve) => {
3399
- resolveEvent = resolve;
3400
- });
3401
- }
3402
- }
3403
- await graphPromise;
3839
+ storeOriginalInput(ctx, input);
3840
+ return createEventStream(
3841
+ (emit) => this.executeMapReduce(chunks, ctx, emit).then(
3842
+ (result) => {
3843
+ emit({ type: "graph_done", result });
3844
+ },
3845
+ (err) => {
3846
+ this.state.error = err instanceof Error ? err.message : String(err);
3847
+ emit({ type: "graph_error", error: this.state.error });
3848
+ }
3849
+ ),
3850
+ this.eventSink
3851
+ );
3404
3852
  }
3405
3853
  /** 核心执行逻辑 */
3406
- async executeMapReduce(input, ctx, emit) {
3407
- let stepsCompleted = 0;
3854
+ async executeMapReduce(chunks, ctx, emit) {
3408
3855
  const totalUsage = {};
3409
- const inputText = typeof input === "string" ? input : input.message;
3410
- const chunks = this.split(inputText);
3411
- const mapperResults = /* @__PURE__ */ new Map();
3856
+ this.throwIfAborted();
3412
3857
  this.state.nodeStates.set(this.mapperNode.id, "running");
3413
- const mapperAgentIds = chunks.map((_, i) => `${this.mapperNode.id}_${i}`);
3414
- emit({ type: "parallel_start", agentIds: mapperAgentIds });
3415
- if (this.concurrency >= chunks.length) {
3416
- const promises = chunks.map(async (chunk, index) => {
3417
- emit({ type: "agent_start", agentId: `${this.mapperNode.id}_${index}`, agentName: `${this.mapperNode.name}#${index + 1}` });
3418
- try {
3419
- const result = await executeNode(this.mapperNode, chunk, ctx);
3420
- this.state.nodeResults.set(`${this.mapperNode.id}_${index}`, result);
3421
- this.mergeUsage(totalUsage, result.usage);
3422
- stepsCompleted++;
3423
- this.state.stepsCompleted = stepsCompleted;
3424
- emit({ type: "agent_result", agentId: `${this.mapperNode.id}_${index}`, agentName: `${this.mapperNode.name}#${index + 1}`, result });
3425
- return { index, result };
3426
- } catch (err) {
3427
- const errorMsg = err instanceof Error ? err.message : String(err);
3428
- emit({ type: "agent_error", agentId: `${this.mapperNode.id}_${index}`, agentName: `${this.mapperNode.name}#${index + 1}`, error: errorMsg });
3429
- throw err;
3430
- }
3431
- });
3432
- const settled = await Promise.allSettled(promises);
3433
- for (const s of settled) {
3434
- if (s.status === "fulfilled") {
3435
- mapperResults.set(s.value.index, s.value.result);
3436
- }
3437
- }
3438
- } else {
3439
- let index = 0;
3440
- const executing = /* @__PURE__ */ new Set();
3441
- const enqueue = () => {
3442
- if (index >= chunks.length) return null;
3443
- const currentIndex = index++;
3444
- const chunk = chunks[currentIndex];
3445
- const p = (async () => {
3446
- emit({ type: "agent_start", agentId: `${this.mapperNode.id}_${currentIndex}`, agentName: `${this.mapperNode.name}#${currentIndex + 1}` });
3447
- try {
3448
- const result = await executeNode(this.mapperNode, chunk, ctx);
3449
- mapperResults.set(currentIndex, result);
3450
- this.state.nodeResults.set(`${this.mapperNode.id}_${currentIndex}`, result);
3451
- this.mergeUsage(totalUsage, result.usage);
3452
- stepsCompleted++;
3453
- this.state.stepsCompleted = stepsCompleted;
3454
- emit({ type: "agent_result", agentId: `${this.mapperNode.id}_${currentIndex}`, agentName: `${this.mapperNode.name}#${currentIndex + 1}`, result });
3455
- } catch (err) {
3456
- const errorMsg = err instanceof Error ? err.message : String(err);
3457
- emit({ type: "agent_error", agentId: `${this.mapperNode.id}_${currentIndex}`, agentName: `${this.mapperNode.name}#${currentIndex + 1}`, error: errorMsg });
3458
- throw err;
3459
- }
3460
- })();
3461
- executing.add(p);
3462
- p.finally(() => executing.delete(p));
3463
- return p;
3464
- };
3465
- for (let i = 0; i < this.concurrency && index < chunks.length; i++) {
3466
- enqueue();
3467
- }
3468
- while (executing.size > 0) {
3469
- await Promise.race(executing);
3470
- enqueue();
3471
- }
3472
- }
3858
+ chunks.forEach((_, i) => {
3859
+ this.state.nodeStates.set(`${this.mapperNode.id}_${i}`, "pending");
3860
+ });
3861
+ const { results: mapperResults, failed } = await this.runMappers(chunks, ctx, emit, totalUsage);
3862
+ let stepsCompleted = mapperResults.size + failed.length;
3863
+ this.state.stepsCompleted = stepsCompleted;
3473
3864
  this.state.nodeStates.set(this.mapperNode.id, "completed");
3474
3865
  const mapperResultsForEmit = /* @__PURE__ */ new Map();
3475
3866
  for (const [idx, result] of mapperResults) {
@@ -3477,10 +3868,14 @@ ${result.content}`);
3477
3868
  }
3478
3869
  emit({ type: "parallel_done", results: mapperResultsForEmit });
3479
3870
  ctx.blackboard.set("mapper_results", mapperResults);
3871
+ if (failed.length > 0 && mapperResults.size === 0) {
3872
+ throw new Error(`MapReduce: \u6240\u6709 mapper \u5747\u5931\u8D25\uFF08${failed.length}/${chunks.length}\uFF09`);
3873
+ }
3480
3874
  const reduceInput = this.reduceInputFormat(mapperResults);
3875
+ this.throwIfAborted();
3481
3876
  this.state.currentAgentId = this.reducerNode.id;
3482
3877
  this.state.nodeStates.set(this.reducerNode.id, "running");
3483
- emit({ type: "agent_start", agentId: this.reducerNode.id, agentName: this.reducerNode.name });
3878
+ emit({ type: "agent_start", agentId: this.reducerNode.id, agentName: this.reducerNode.name, input: reduceInput });
3484
3879
  let reducerResult;
3485
3880
  try {
3486
3881
  reducerResult = await executeNode(this.reducerNode, reduceInput, ctx);
@@ -3497,29 +3892,94 @@ ${result.content}`);
3497
3892
  throw err;
3498
3893
  }
3499
3894
  this.state.finished = true;
3895
+ const hasFailures = failed.length > 0;
3500
3896
  return {
3501
3897
  content: reducerResult.content,
3502
3898
  lastAgentId: this.reducerNode.id,
3503
3899
  agentResults: new Map(this.state.nodeResults),
3504
3900
  totalUsage,
3505
3901
  stepsCompleted,
3506
- stopReason: "completed",
3902
+ stopReason: hasFailures ? "partial_failure" : "completed",
3507
3903
  context: ctx,
3508
- success: true
3904
+ success: true,
3905
+ ...hasFailures ? { failedAgents: failed } : {}
3509
3906
  };
3510
3907
  }
3908
+ /** 并行执行所有 mapper 子任务(统一处理并发限制与失败策略) */
3909
+ async runMappers(chunks, ctx, emit, totalUsage) {
3910
+ const results = /* @__PURE__ */ new Map();
3911
+ const failed = [];
3912
+ const skip = this.onMapperError === "skip";
3913
+ const mapperId = this.mapperNode.id;
3914
+ const mapperAgentIds = chunks.map((_, i) => `${mapperId}_${i}`);
3915
+ emit({ type: "parallel_start", agentIds: mapperAgentIds });
3916
+ const runOne = async (index) => {
3917
+ const agentId = `${mapperId}_${index}`;
3918
+ const agentName = `${this.mapperNode.name}#${index + 1}`;
3919
+ emit({ type: "agent_start", agentId, agentName, input: chunks[index] });
3920
+ this.state.nodeStates.set(agentId, "running");
3921
+ try {
3922
+ const result = await executeNode(this.mapperNode, chunks[index], ctx);
3923
+ this.state.nodeResults.set(agentId, result);
3924
+ this.state.nodeStates.set(agentId, "completed");
3925
+ this.mergeUsage(totalUsage, result.usage);
3926
+ results.set(index, result);
3927
+ emit({ type: "agent_result", agentId, agentName, result });
3928
+ } catch (err) {
3929
+ const errorMsg = err instanceof Error ? err.message : String(err);
3930
+ this.state.nodeStates.set(agentId, "failed");
3931
+ emit({ type: "agent_error", agentId, agentName, error: errorMsg });
3932
+ if (!skip) throw err;
3933
+ failed.push(agentId);
3934
+ }
3935
+ };
3936
+ if (this.concurrency >= chunks.length) {
3937
+ const promises = chunks.map((_, i) => runOne(i));
3938
+ if (!skip) {
3939
+ await Promise.all(promises);
3940
+ } else {
3941
+ await Promise.allSettled(promises);
3942
+ }
3943
+ } else {
3944
+ let index = 0;
3945
+ const executing = /* @__PURE__ */ new Set();
3946
+ const enqueue = () => {
3947
+ if (index >= chunks.length) return null;
3948
+ const i = index++;
3949
+ const p = runOne(i).finally(() => {
3950
+ executing.delete(p);
3951
+ });
3952
+ executing.add(p);
3953
+ p.catch(() => {
3954
+ });
3955
+ return p;
3956
+ };
3957
+ for (let i = 0; i < this.concurrency && index < chunks.length; i++) {
3958
+ enqueue();
3959
+ }
3960
+ while (executing.size > 0) {
3961
+ await Promise.race(executing);
3962
+ enqueue();
3963
+ }
3964
+ }
3965
+ return { results, failed };
3966
+ }
3511
3967
  buildErrorResult(ctx, err) {
3512
3968
  this.state.finished = true;
3969
+ const aborted = err instanceof GraphAbortedError;
3970
+ const errorMsg = err instanceof Error ? err.message : String(err);
3971
+ this.state.error = errorMsg;
3972
+ const lastCompleted = [...this.state.nodeResults.values()].at(-1);
3513
3973
  return {
3514
- content: "",
3974
+ content: aborted ? lastCompleted?.content ?? "" : "",
3515
3975
  lastAgentId: this.mapperNode.id,
3516
3976
  agentResults: new Map(this.state.nodeResults),
3517
3977
  totalUsage: {},
3518
3978
  stepsCompleted: this.state.stepsCompleted,
3519
- stopReason: "error",
3979
+ stopReason: aborted ? "aborted" : "error",
3520
3980
  context: ctx,
3521
3981
  success: false,
3522
- error: err instanceof Error ? err.message : String(err)
3982
+ error: errorMsg
3523
3983
  };
3524
3984
  }
3525
3985
  mergeUsage(total, usage) {
@@ -3532,7 +3992,8 @@ ${result.content}`);
3532
3992
  // patterns/map-reduce.ts
3533
3993
  var MapReduceGraphImpl = class {
3534
3994
  executor;
3535
- eventListeners = /* @__PURE__ */ new Map();
3995
+ /** on() 注册的监听器,按 MultiAgentEvent.type 分发 */
3996
+ bus = new SimpleEventBus();
3536
3997
  constructor(mapper, reducer, opts) {
3537
3998
  this.executor = new MapReduceExecutor(mapper, reducer, opts);
3538
3999
  }
@@ -3549,23 +4010,21 @@ var MapReduceGraphImpl = class {
3549
4010
  throw new Error("MapReduce \u6A21\u5F0F\u4E0D\u652F\u6301 setFinish");
3550
4011
  }
3551
4012
  async run(input) {
4013
+ this.executor.setEventSink((event) => this.bus.emit(event.type, event));
3552
4014
  return this.executor.run(input);
3553
4015
  }
3554
4016
  async *stream(input) {
4017
+ this.executor.setEventSink((event) => this.bus.emit(event.type, event));
3555
4018
  yield* this.executor.stream(input);
3556
4019
  }
3557
4020
  getState() {
3558
4021
  return this.executor.getState();
3559
4022
  }
3560
4023
  abort() {
4024
+ this.executor.abort();
3561
4025
  }
3562
4026
  on(event, listener) {
3563
- let set = this.eventListeners.get(event);
3564
- if (!set) {
3565
- set = /* @__PURE__ */ new Set();
3566
- this.eventListeners.set(event, set);
3567
- }
3568
- set.add(listener);
4027
+ this.bus.on(event, listener);
3569
4028
  return this;
3570
4029
  }
3571
4030
  };
@@ -3786,6 +4245,13 @@ var McpServerHost = class {
3786
4245
  notifyToolsListChanged() {
3787
4246
  this.onNotification?.(createListChangedNotification());
3788
4247
  }
4248
+ /**
4249
+ * 注入通知分发钩子(由传输层如 http-runner 调用):host 经此回调发出主动通知。
4250
+ * 与 setOutboundRequest 对称。重复调用以最后一次为准。
4251
+ */
4252
+ setOnNotification(fn) {
4253
+ this.onNotification = fn;
4254
+ }
3789
4255
  /**
3790
4256
  * 注入出站请求通道(由传输层如 stdio-runner 调用):写入 JSON-RPC 请求
3791
4257
  * 并关联响应。注入后 `sampleLLM` 可向外部 client 请求 LLM 补全。
@@ -4197,6 +4663,7 @@ var GraphDebugger = class {
4197
4663
  const graphStartTime = Date.now();
4198
4664
  const steps = [];
4199
4665
  let stepIndex = 0;
4666
+ let finalResult;
4200
4667
  for await (const event of this.graph.stream(input)) {
4201
4668
  if (event.type === "agent_start") {
4202
4669
  stepIndex++;
@@ -4206,7 +4673,7 @@ var GraphDebugger = class {
4206
4673
  agentName: event.agentName,
4207
4674
  startTime: Date.now(),
4208
4675
  duration: 0,
4209
- input: "",
4676
+ input: event.input ?? "",
4210
4677
  output: "",
4211
4678
  state: "running"
4212
4679
  });
@@ -4231,6 +4698,8 @@ var GraphDebugger = class {
4231
4698
  step.error = event.error;
4232
4699
  step.state = "failed";
4233
4700
  }
4701
+ } else if (event.type === "graph_done") {
4702
+ finalResult = event.result;
4234
4703
  }
4235
4704
  }
4236
4705
  const state = this.graph.getState();
@@ -4241,10 +4710,10 @@ var GraphDebugger = class {
4241
4710
  duration: graphDuration,
4242
4711
  steps,
4243
4712
  result: {
4244
- success: !state.error,
4245
- content: state.error ?? "",
4246
- stopReason: state.error ? "error" : "completed",
4247
- stepsCompleted: state.stepsCompleted
4713
+ success: finalResult ? finalResult.success : !state.error,
4714
+ content: finalResult?.content ?? "",
4715
+ stopReason: finalResult?.stopReason ?? (state.error ? "error" : "completed"),
4716
+ stepsCompleted: finalResult?.stepsCompleted ?? state.stepsCompleted
4248
4717
  }
4249
4718
  };
4250
4719
  }
@@ -4296,13 +4765,16 @@ function createDebugger(graph) {
4296
4765
  return new GraphDebugger(graph);
4297
4766
  }
4298
4767
  export {
4768
+ GraphAbortedError,
4299
4769
  GraphDebugger,
4300
4770
  MCPBridge,
4771
+ NodeTimeoutError,
4301
4772
  SimpleEventBus,
4302
4773
  SimpleToolRegistry,
4303
4774
  createAgentGraph,
4304
4775
  createDebate,
4305
4776
  createDebugger,
4777
+ createEventStream,
4306
4778
  createMCPBridge,
4307
4779
  createMapReduce,
4308
4780
  createMultiAgentMcpServerHost,