@aipack-ai/multi-agent 1.1.6 → 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.d.ts +87 -5
- package/dist/index.js +780 -336
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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) {
|
|
@@ -2478,7 +2482,55 @@ function createRuntime(options) {
|
|
|
2478
2482
|
return AgentRuntime.create(options);
|
|
2479
2483
|
}
|
|
2480
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
|
+
|
|
2481
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
|
+
};
|
|
2482
2534
|
var runtimeCache = /* @__PURE__ */ new WeakMap();
|
|
2483
2535
|
function ensureRuntime(node) {
|
|
2484
2536
|
let rt = runtimeCache.get(node);
|
|
@@ -2491,19 +2543,52 @@ function ensureRuntime(node) {
|
|
|
2491
2543
|
runtimeCache.set(node, rt);
|
|
2492
2544
|
return rt;
|
|
2493
2545
|
}
|
|
2494
|
-
async function
|
|
2546
|
+
async function executeNodeOnce(node, req) {
|
|
2495
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) {
|
|
2496
2564
|
let req;
|
|
2497
2565
|
if (typeof input === "string") {
|
|
2498
2566
|
req = createRequest(input, { sessionKey: `multi-agent:${node.id}` });
|
|
2499
2567
|
} else {
|
|
2500
2568
|
req = { ...input, sessionKey: input.sessionKey ?? `multi-agent:${node.id}` };
|
|
2501
2569
|
}
|
|
2502
|
-
const
|
|
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
|
+
}
|
|
2503
2588
|
if (node.outputMapping) {
|
|
2504
|
-
node.outputMapping(
|
|
2589
|
+
node.outputMapping(succeeded, ctx);
|
|
2505
2590
|
}
|
|
2506
|
-
return
|
|
2591
|
+
return succeeded;
|
|
2507
2592
|
}
|
|
2508
2593
|
function resolveInput(edge, prevResult, ctx, node, originalInput) {
|
|
2509
2594
|
if (edge?.transform) {
|
|
@@ -2530,12 +2615,22 @@ var GraphExecutor = class {
|
|
|
2530
2615
|
entryId;
|
|
2531
2616
|
finishCondition;
|
|
2532
2617
|
abortController = new AbortController();
|
|
2618
|
+
/** 外部事件监听(on() API 的底层接线),事件会同步分发 */
|
|
2619
|
+
eventSink;
|
|
2620
|
+
/** 并行分支最大并发数(默认不限制) */
|
|
2621
|
+
concurrency;
|
|
2622
|
+
/** 单节点最大访问次数(环图防死循环) */
|
|
2623
|
+
maxVisitsPerNode;
|
|
2533
2624
|
state = {
|
|
2534
2625
|
nodeStates: /* @__PURE__ */ new Map(),
|
|
2535
2626
|
nodeResults: /* @__PURE__ */ new Map(),
|
|
2536
2627
|
stepsCompleted: 0,
|
|
2537
2628
|
finished: false
|
|
2538
2629
|
};
|
|
2630
|
+
constructor(opts) {
|
|
2631
|
+
this.concurrency = opts?.concurrency ?? Infinity;
|
|
2632
|
+
this.maxVisitsPerNode = opts?.maxVisitsPerNode ?? 10;
|
|
2633
|
+
}
|
|
2539
2634
|
addNode(node) {
|
|
2540
2635
|
this.nodes.set(node.id, node);
|
|
2541
2636
|
this.state.nodeStates.set(node.id, "pending");
|
|
@@ -2553,12 +2648,42 @@ var GraphExecutor = class {
|
|
|
2553
2648
|
this.finishCondition = condition;
|
|
2554
2649
|
return this;
|
|
2555
2650
|
}
|
|
2651
|
+
/** 注入外部事件监听(由 AgentGraph 实现的 on() 接线) */
|
|
2652
|
+
setEventSink(sink) {
|
|
2653
|
+
this.eventSink = sink;
|
|
2654
|
+
return this;
|
|
2655
|
+
}
|
|
2556
2656
|
getState() {
|
|
2557
|
-
return {
|
|
2657
|
+
return {
|
|
2658
|
+
...this.state,
|
|
2659
|
+
nodeStates: new Map(this.state.nodeStates),
|
|
2660
|
+
nodeResults: new Map(this.state.nodeResults)
|
|
2661
|
+
};
|
|
2558
2662
|
}
|
|
2559
2663
|
abort() {
|
|
2560
2664
|
this.abortController.abort();
|
|
2561
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
|
+
}
|
|
2562
2687
|
/** 同步执行图 */
|
|
2563
2688
|
async run(input) {
|
|
2564
2689
|
if (!this.entryId) {
|
|
@@ -2567,66 +2692,78 @@ var GraphExecutor = class {
|
|
|
2567
2692
|
if (!this.nodes.has(this.entryId)) {
|
|
2568
2693
|
throw new Error(`AgentGraph: \u5165\u53E3\u8282\u70B9 "${this.entryId}" \u4E0D\u5B58\u5728`);
|
|
2569
2694
|
}
|
|
2695
|
+
this.resetAbortController();
|
|
2696
|
+
this.resetState();
|
|
2570
2697
|
const ctx = createSharedContext({
|
|
2571
2698
|
meta: { traceId: `ma-${Date.now()}`, startTime: Date.now() }
|
|
2572
2699
|
});
|
|
2573
|
-
|
|
2700
|
+
storeOriginalInput(ctx, input);
|
|
2701
|
+
const emit = this.eventSink ?? (() => {
|
|
2702
|
+
});
|
|
2574
2703
|
try {
|
|
2575
|
-
const result = await this.executeGraph(input, ctx,
|
|
2704
|
+
const result = await this.executeGraph(input, ctx, emit);
|
|
2705
|
+
emit({ type: "graph_done", result });
|
|
2576
2706
|
return result;
|
|
2577
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 });
|
|
2578
2727
|
return {
|
|
2579
2728
|
content: "",
|
|
2580
2729
|
lastAgentId: this.state.currentAgentId ?? "",
|
|
2581
|
-
agentResults: this.state.nodeResults,
|
|
2730
|
+
agentResults: new Map(this.state.nodeResults),
|
|
2582
2731
|
totalUsage: {},
|
|
2583
2732
|
stepsCompleted: this.state.stepsCompleted,
|
|
2584
2733
|
stopReason: "error",
|
|
2585
2734
|
context: ctx,
|
|
2586
2735
|
success: false,
|
|
2587
|
-
error:
|
|
2736
|
+
error: errorMsg
|
|
2588
2737
|
};
|
|
2589
2738
|
}
|
|
2590
2739
|
}
|
|
2591
2740
|
/** 流式执行图 */
|
|
2592
|
-
|
|
2741
|
+
stream(input) {
|
|
2593
2742
|
if (!this.entryId) {
|
|
2594
2743
|
throw new Error("AgentGraph: \u5165\u53E3\u8282\u70B9\u672A\u8BBE\u7F6E\uFF0C\u8BF7\u8C03\u7528 setEntry()");
|
|
2595
2744
|
}
|
|
2596
2745
|
if (!this.nodes.has(this.entryId)) {
|
|
2597
2746
|
throw new Error(`AgentGraph: \u5165\u53E3\u8282\u70B9 "${this.entryId}" \u4E0D\u5B58\u5728`);
|
|
2598
2747
|
}
|
|
2748
|
+
this.resetAbortController();
|
|
2749
|
+
this.resetState();
|
|
2599
2750
|
const ctx = createSharedContext({
|
|
2600
2751
|
meta: { traceId: `ma-${Date.now()}`, startTime: Date.now() }
|
|
2601
2752
|
});
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
).finally(() => {
|
|
2617
|
-
done = true;
|
|
2618
|
-
resolveEvent?.();
|
|
2619
|
-
});
|
|
2620
|
-
while (!done || eventQueue.length > 0) {
|
|
2621
|
-
if (eventQueue.length > 0) {
|
|
2622
|
-
yield eventQueue.shift();
|
|
2623
|
-
} else {
|
|
2624
|
-
await new Promise((resolve) => {
|
|
2625
|
-
resolveEvent = resolve;
|
|
2626
|
-
});
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
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
|
+
);
|
|
2630
2767
|
}
|
|
2631
2768
|
/** 核心执行逻辑 */
|
|
2632
2769
|
async executeGraph(input, ctx, emit) {
|
|
@@ -2639,7 +2776,7 @@ var GraphExecutor = class {
|
|
|
2639
2776
|
const totalUsage = {};
|
|
2640
2777
|
this.state.currentAgentId = currentId;
|
|
2641
2778
|
this.state.nodeStates.set(currentId, "running");
|
|
2642
|
-
emit({ type: "agent_start", agentId: currentId, agentName: entryNode.name });
|
|
2779
|
+
emit({ type: "agent_start", agentId: currentId, agentName: entryNode.name, input: toInputText(currentInput) });
|
|
2643
2780
|
try {
|
|
2644
2781
|
lastResult = await executeNode(entryNode, currentInput, ctx);
|
|
2645
2782
|
this.state.nodeStates.set(currentId, "completed");
|
|
@@ -2658,50 +2795,134 @@ var GraphExecutor = class {
|
|
|
2658
2795
|
if (this.finishCondition?.(ctx)) {
|
|
2659
2796
|
return this.buildResult(lastResult, lastAgentId, ctx, totalUsage, stepsCompleted, "finish_condition");
|
|
2660
2797
|
}
|
|
2661
|
-
|
|
2798
|
+
let frontier = [{ id: currentId, result: lastResult }];
|
|
2662
2799
|
const visitCount = /* @__PURE__ */ new Map();
|
|
2663
|
-
|
|
2664
|
-
while (
|
|
2665
|
-
|
|
2666
|
-
|
|
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) {
|
|
2667
2818
|
break;
|
|
2668
2819
|
}
|
|
2669
|
-
const
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
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);
|
|
2673
2830
|
}
|
|
2674
|
-
|
|
2675
|
-
|
|
2831
|
+
if (allowed.length === 0) {
|
|
2832
|
+
if (truncated) stopReason = "max_visits_exceeded";
|
|
2676
2833
|
break;
|
|
2677
2834
|
}
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
this.state.nodeStates.set(
|
|
2688
|
-
|
|
2689
|
-
|
|
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);
|
|
2690
2859
|
stepsCompleted++;
|
|
2691
2860
|
this.state.stepsCompleted = stepsCompleted;
|
|
2692
|
-
emit({ type: "agent_result", agentId:
|
|
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 });
|
|
2693
2893
|
} catch (err) {
|
|
2694
2894
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
2695
|
-
this.state.nodeStates.set(
|
|
2696
|
-
emit({ type: "agent_error", agentId:
|
|
2895
|
+
this.state.nodeStates.set(t.node.id, "failed");
|
|
2896
|
+
emit({ type: "agent_error", agentId: t.node.id, agentName: t.node.name, error: errorMsg });
|
|
2697
2897
|
throw err;
|
|
2698
2898
|
}
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
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();
|
|
2702
2922
|
}
|
|
2703
2923
|
}
|
|
2704
|
-
|
|
2924
|
+
emit({ type: "parallel_done", results: new Map(results.map((r) => [r.id, r.result])) });
|
|
2925
|
+
return results;
|
|
2705
2926
|
}
|
|
2706
2927
|
buildResult(lastResult, lastAgentId, ctx, totalUsage, stepsCompleted, stopReason) {
|
|
2707
2928
|
this.state.finished = true;
|
|
@@ -2726,8 +2947,12 @@ var GraphExecutor = class {
|
|
|
2726
2947
|
|
|
2727
2948
|
// core/graph.ts
|
|
2728
2949
|
var AgentGraphImpl = class {
|
|
2729
|
-
executor
|
|
2730
|
-
|
|
2950
|
+
executor;
|
|
2951
|
+
/** on() 注册的监听器,按 MultiAgentEvent.type 分发 */
|
|
2952
|
+
bus = new SimpleEventBus();
|
|
2953
|
+
constructor(opts) {
|
|
2954
|
+
this.executor = new GraphExecutor(opts);
|
|
2955
|
+
}
|
|
2731
2956
|
addNode(node) {
|
|
2732
2957
|
this.executor.addNode(node);
|
|
2733
2958
|
return this;
|
|
@@ -2745,9 +2970,11 @@ var AgentGraphImpl = class {
|
|
|
2745
2970
|
return this;
|
|
2746
2971
|
}
|
|
2747
2972
|
async run(input) {
|
|
2973
|
+
this.executor.setEventSink((event) => this.bus.emit(event.type, event));
|
|
2748
2974
|
return this.executor.run(input);
|
|
2749
2975
|
}
|
|
2750
2976
|
async *stream(input) {
|
|
2977
|
+
this.executor.setEventSink((event) => this.bus.emit(event.type, event));
|
|
2751
2978
|
yield* this.executor.stream(input);
|
|
2752
2979
|
}
|
|
2753
2980
|
getState() {
|
|
@@ -2757,17 +2984,12 @@ var AgentGraphImpl = class {
|
|
|
2757
2984
|
this.executor.abort();
|
|
2758
2985
|
}
|
|
2759
2986
|
on(event, listener) {
|
|
2760
|
-
|
|
2761
|
-
if (!set) {
|
|
2762
|
-
set = /* @__PURE__ */ new Set();
|
|
2763
|
-
this.eventListeners.set(event, set);
|
|
2764
|
-
}
|
|
2765
|
-
set.add(listener);
|
|
2987
|
+
this.bus.on(event, listener);
|
|
2766
2988
|
return this;
|
|
2767
2989
|
}
|
|
2768
2990
|
};
|
|
2769
|
-
function createAgentGraph() {
|
|
2770
|
-
return new AgentGraphImpl();
|
|
2991
|
+
function createAgentGraph(opts) {
|
|
2992
|
+
return new AgentGraphImpl(opts);
|
|
2771
2993
|
}
|
|
2772
2994
|
|
|
2773
2995
|
// patterns/pipeline.ts
|
|
@@ -2805,14 +3027,19 @@ function createRouter(router, targets, opts) {
|
|
|
2805
3027
|
}
|
|
2806
3028
|
graph.setEntry(router.id);
|
|
2807
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
|
+
};
|
|
2808
3036
|
for (const target of targets) {
|
|
2809
3037
|
graph.addEdge({
|
|
2810
3038
|
from: router.id,
|
|
2811
3039
|
to: target.id,
|
|
2812
|
-
// 条件:从路由器结果中解析目标ID
|
|
3040
|
+
// 条件:从路由器结果中解析目标ID(含 defaultTarget 兜底),匹配当前目标
|
|
2813
3041
|
condition: (routerResult, _ctx) => {
|
|
2814
|
-
|
|
2815
|
-
return resolvedId === target.id;
|
|
3042
|
+
return resolveTarget(routerResult) === target.id;
|
|
2816
3043
|
},
|
|
2817
3044
|
// 转换:决定传给目标Agent的输入
|
|
2818
3045
|
transform: (_routerResult, _ctx) => {
|
|
@@ -2824,8 +3051,6 @@ function createRouter(router, targets, opts) {
|
|
|
2824
3051
|
}
|
|
2825
3052
|
});
|
|
2826
3053
|
}
|
|
2827
|
-
if (opts.defaultTarget && targetIds.has(opts.defaultTarget)) {
|
|
2828
|
-
}
|
|
2829
3054
|
return graph;
|
|
2830
3055
|
}
|
|
2831
3056
|
|
|
@@ -2834,6 +3059,11 @@ var SupervisorExecutor = class {
|
|
|
2834
3059
|
supervisorNode;
|
|
2835
3060
|
workerNodes;
|
|
2836
3061
|
opts;
|
|
3062
|
+
abortController = new AbortController();
|
|
3063
|
+
/** 外部事件监听(on() API 的底层接线) */
|
|
3064
|
+
eventSink;
|
|
3065
|
+
/** 最近一次 run 中失败的 Worker ID(onWorkerError='skip' 时使用) */
|
|
3066
|
+
failedAgents = [];
|
|
2837
3067
|
state = {
|
|
2838
3068
|
nodeStates: /* @__PURE__ */ new Map(),
|
|
2839
3069
|
nodeResults: /* @__PURE__ */ new Map(),
|
|
@@ -2846,7 +3076,8 @@ var SupervisorExecutor = class {
|
|
|
2846
3076
|
this.opts = {
|
|
2847
3077
|
schedule: opts?.schedule ?? "parallel",
|
|
2848
3078
|
concurrency: opts?.concurrency ?? Infinity,
|
|
2849
|
-
passOriginalInput: opts?.passOriginalInput ?? true
|
|
3079
|
+
passOriginalInput: opts?.passOriginalInput ?? true,
|
|
3080
|
+
onWorkerError: opts?.onWorkerError ?? "fail-fast"
|
|
2850
3081
|
};
|
|
2851
3082
|
this.state.nodeStates.set(supervisor.id, "pending");
|
|
2852
3083
|
for (const w of workers) {
|
|
@@ -2854,69 +3085,91 @@ var SupervisorExecutor = class {
|
|
|
2854
3085
|
}
|
|
2855
3086
|
}
|
|
2856
3087
|
getState() {
|
|
2857
|
-
return {
|
|
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
|
+
}
|
|
2858
3121
|
}
|
|
2859
3122
|
/** 执行 Supervisor 模式 */
|
|
2860
3123
|
async run(input) {
|
|
3124
|
+
this.resetRun();
|
|
2861
3125
|
const ctx = createSharedContext({
|
|
2862
3126
|
meta: { traceId: `sv-${Date.now()}`, startTime: Date.now() }
|
|
2863
3127
|
});
|
|
2864
3128
|
if (this.opts.passOriginalInput) {
|
|
2865
|
-
|
|
2866
|
-
ctx.blackboard.set("__original_input__", inputText);
|
|
3129
|
+
storeOriginalInput(ctx, input);
|
|
2867
3130
|
}
|
|
3131
|
+
const emit = this.eventSink ?? (() => {
|
|
3132
|
+
});
|
|
2868
3133
|
try {
|
|
2869
|
-
|
|
2870
|
-
});
|
|
3134
|
+
const result = await this.executeSupervisor(input, ctx, emit);
|
|
3135
|
+
emit({ type: "graph_done", result });
|
|
3136
|
+
return result;
|
|
2871
3137
|
} catch (err) {
|
|
2872
|
-
|
|
3138
|
+
const result = this.buildErrorResult(ctx, err);
|
|
3139
|
+
emit({ type: "graph_error", error: result.error ?? "" });
|
|
3140
|
+
return result;
|
|
2873
3141
|
}
|
|
2874
3142
|
}
|
|
2875
3143
|
/** 流式执行 Supervisor 模式 */
|
|
2876
|
-
|
|
3144
|
+
stream(input) {
|
|
3145
|
+
this.resetRun();
|
|
2877
3146
|
const ctx = createSharedContext({
|
|
2878
3147
|
meta: { traceId: `sv-${Date.now()}`, startTime: Date.now() }
|
|
2879
3148
|
});
|
|
2880
3149
|
if (this.opts.passOriginalInput) {
|
|
2881
|
-
|
|
2882
|
-
ctx.blackboard.set("__original_input__", inputText);
|
|
2883
|
-
}
|
|
2884
|
-
const eventQueue = [];
|
|
2885
|
-
let resolveEvent = null;
|
|
2886
|
-
let done = false;
|
|
2887
|
-
const emit = (event) => {
|
|
2888
|
-
eventQueue.push(event);
|
|
2889
|
-
resolveEvent?.();
|
|
2890
|
-
};
|
|
2891
|
-
const graphPromise = this.executeSupervisor(input, ctx, emit).then(
|
|
2892
|
-
(result) => {
|
|
2893
|
-
emit({ type: "graph_done", result });
|
|
2894
|
-
},
|
|
2895
|
-
(err) => {
|
|
2896
|
-
emit({ type: "graph_error", error: err instanceof Error ? err.message : String(err) });
|
|
2897
|
-
}
|
|
2898
|
-
).finally(() => {
|
|
2899
|
-
done = true;
|
|
2900
|
-
resolveEvent?.();
|
|
2901
|
-
});
|
|
2902
|
-
while (!done || eventQueue.length > 0) {
|
|
2903
|
-
if (eventQueue.length > 0) {
|
|
2904
|
-
yield eventQueue.shift();
|
|
2905
|
-
} else {
|
|
2906
|
-
await new Promise((resolve) => {
|
|
2907
|
-
resolveEvent = resolve;
|
|
2908
|
-
});
|
|
2909
|
-
}
|
|
3150
|
+
storeOriginalInput(ctx, input);
|
|
2910
3151
|
}
|
|
2911
|
-
|
|
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
|
+
);
|
|
2912
3164
|
}
|
|
2913
3165
|
/** 核心执行逻辑 */
|
|
2914
3166
|
async executeSupervisor(input, ctx, emit) {
|
|
2915
3167
|
let stepsCompleted = 0;
|
|
2916
3168
|
const totalUsage = {};
|
|
3169
|
+
this.throwIfAborted();
|
|
2917
3170
|
this.state.currentAgentId = this.supervisorNode.id;
|
|
2918
3171
|
this.state.nodeStates.set(this.supervisorNode.id, "running");
|
|
2919
|
-
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) });
|
|
2920
3173
|
let supervisorResult;
|
|
2921
3174
|
try {
|
|
2922
3175
|
supervisorResult = await executeNode(this.supervisorNode, input, ctx);
|
|
@@ -2943,18 +3196,21 @@ var SupervisorExecutor = class {
|
|
|
2943
3196
|
}
|
|
2944
3197
|
stepsCompleted += workerResults.size;
|
|
2945
3198
|
this.state.stepsCompleted = stepsCompleted;
|
|
2946
|
-
const
|
|
2947
|
-
const finalResult =
|
|
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;
|
|
2948
3203
|
this.state.finished = true;
|
|
2949
3204
|
return {
|
|
2950
3205
|
content: finalResult.content,
|
|
2951
|
-
lastAgentId:
|
|
3206
|
+
lastAgentId: finalAgentId,
|
|
2952
3207
|
agentResults: new Map(this.state.nodeResults),
|
|
2953
3208
|
totalUsage,
|
|
2954
3209
|
stepsCompleted,
|
|
2955
|
-
stopReason: "completed",
|
|
3210
|
+
stopReason: hasFailures ? "partial_failure" : "completed",
|
|
2956
3211
|
context: ctx,
|
|
2957
|
-
success: true
|
|
3212
|
+
success: true,
|
|
3213
|
+
...hasFailures ? { failedAgents: [...this.failedAgents] } : {}
|
|
2958
3214
|
};
|
|
2959
3215
|
}
|
|
2960
3216
|
/** 并行执行所有 Worker */
|
|
@@ -2962,16 +3218,28 @@ var SupervisorExecutor = class {
|
|
|
2962
3218
|
const results = /* @__PURE__ */ new Map();
|
|
2963
3219
|
const workers = this.workerNodes;
|
|
2964
3220
|
const concurrency = this.opts.concurrency;
|
|
3221
|
+
const skip = this.opts.onWorkerError === "skip";
|
|
2965
3222
|
emit({ type: "parallel_start", agentIds: workers.map((w) => w.id) });
|
|
2966
3223
|
if (concurrency >= workers.length) {
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
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
|
+
}
|
|
2975
3243
|
}
|
|
2976
3244
|
}
|
|
2977
3245
|
} else {
|
|
@@ -2980,12 +3248,20 @@ var SupervisorExecutor = class {
|
|
|
2980
3248
|
const enqueue = () => {
|
|
2981
3249
|
if (index >= workers.length) return null;
|
|
2982
3250
|
const worker = workers[index++];
|
|
2983
|
-
const p = this.executeWorker(worker, ctx, emit, totalUsage).then(
|
|
2984
|
-
|
|
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(() => {
|
|
2985
3260
|
executing.delete(p);
|
|
2986
|
-
return r;
|
|
2987
3261
|
});
|
|
2988
3262
|
executing.add(p);
|
|
3263
|
+
p.catch(() => {
|
|
3264
|
+
});
|
|
2989
3265
|
return p;
|
|
2990
3266
|
};
|
|
2991
3267
|
for (let i = 0; i < concurrency && index < workers.length; i++) {
|
|
@@ -3002,40 +3278,122 @@ var SupervisorExecutor = class {
|
|
|
3002
3278
|
/** 顺序执行所有 Worker */
|
|
3003
3279
|
async executeWorkersSequential(ctx, emit, totalUsage) {
|
|
3004
3280
|
const results = /* @__PURE__ */ new Map();
|
|
3281
|
+
const skip = this.opts.onWorkerError === "skip";
|
|
3005
3282
|
for (const worker of this.workerNodes) {
|
|
3006
|
-
|
|
3007
|
-
|
|
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
|
+
}
|
|
3008
3290
|
}
|
|
3009
3291
|
return results;
|
|
3010
3292
|
}
|
|
3011
|
-
/**
|
|
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
|
+
*/
|
|
3012
3302
|
async executeWorkersAuto(ctx, emit, totalUsage) {
|
|
3013
3303
|
const results = /* @__PURE__ */ new Map();
|
|
3014
|
-
const
|
|
3015
|
-
const
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
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());
|
|
3023
3320
|
}
|
|
3024
|
-
emit({ type: "parallel_done", results: new Map(results) });
|
|
3025
3321
|
}
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
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) });
|
|
3029
3387
|
}
|
|
3030
3388
|
return results;
|
|
3031
3389
|
}
|
|
3032
3390
|
/** 执行单个 Worker */
|
|
3033
3391
|
async executeWorker(worker, ctx, emit, totalUsage) {
|
|
3392
|
+
this.throwIfAborted();
|
|
3034
3393
|
this.state.currentAgentId = worker.id;
|
|
3035
3394
|
this.state.nodeStates.set(worker.id, "running");
|
|
3036
|
-
|
|
3395
|
+
let workerInput;
|
|
3037
3396
|
try {
|
|
3038
|
-
let workerInput;
|
|
3039
3397
|
if (worker.inputMapping) {
|
|
3040
3398
|
workerInput = worker.inputMapping(ctx);
|
|
3041
3399
|
} else {
|
|
@@ -3043,6 +3401,14 @@ var SupervisorExecutor = class {
|
|
|
3043
3401
|
const myTask = tasks?.find((t) => t.assignee === worker.id);
|
|
3044
3402
|
workerInput = myTask ? myTask.task : ctx.blackboard.get("__original_input__") ?? "";
|
|
3045
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 {
|
|
3046
3412
|
const result = await executeNode(worker, workerInput, ctx);
|
|
3047
3413
|
this.state.nodeStates.set(worker.id, "completed");
|
|
3048
3414
|
this.state.nodeResults.set(worker.id, result);
|
|
@@ -3059,16 +3425,21 @@ var SupervisorExecutor = class {
|
|
|
3059
3425
|
}
|
|
3060
3426
|
buildErrorResult(ctx, err) {
|
|
3061
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);
|
|
3062
3432
|
return {
|
|
3063
|
-
content: "",
|
|
3064
|
-
lastAgentId: this.supervisorNode.id,
|
|
3433
|
+
content: aborted ? lastCompleted?.content ?? "" : "",
|
|
3434
|
+
lastAgentId: this.state.currentAgentId ?? this.supervisorNode.id,
|
|
3065
3435
|
agentResults: new Map(this.state.nodeResults),
|
|
3066
3436
|
totalUsage: {},
|
|
3067
3437
|
stepsCompleted: this.state.stepsCompleted,
|
|
3068
|
-
stopReason: "error",
|
|
3438
|
+
stopReason: aborted ? "aborted" : "error",
|
|
3069
3439
|
context: ctx,
|
|
3070
3440
|
success: false,
|
|
3071
|
-
error:
|
|
3441
|
+
error: errorMsg,
|
|
3442
|
+
...this.failedAgents.length > 0 ? { failedAgents: [...this.failedAgents] } : {}
|
|
3072
3443
|
};
|
|
3073
3444
|
}
|
|
3074
3445
|
mergeUsage(total, usage) {
|
|
@@ -3081,7 +3452,8 @@ var SupervisorExecutor = class {
|
|
|
3081
3452
|
// patterns/supervisor.ts
|
|
3082
3453
|
var SupervisorGraphImpl = class {
|
|
3083
3454
|
executor;
|
|
3084
|
-
|
|
3455
|
+
/** on() 注册的监听器,按 MultiAgentEvent.type 分发 */
|
|
3456
|
+
bus = new SimpleEventBus();
|
|
3085
3457
|
constructor(supervisor, workers, opts) {
|
|
3086
3458
|
this.executor = new SupervisorExecutor(supervisor, workers, opts);
|
|
3087
3459
|
}
|
|
@@ -3099,23 +3471,21 @@ var SupervisorGraphImpl = class {
|
|
|
3099
3471
|
throw new Error("Supervisor \u6A21\u5F0F\u4E0D\u652F\u6301 setFinish\uFF0C\u7EC8\u6B62\u7531 Supervisor \u5224\u5B9A");
|
|
3100
3472
|
}
|
|
3101
3473
|
async run(input) {
|
|
3474
|
+
this.executor.setEventSink((event) => this.bus.emit(event.type, event));
|
|
3102
3475
|
return this.executor.run(input);
|
|
3103
3476
|
}
|
|
3104
3477
|
async *stream(input) {
|
|
3478
|
+
this.executor.setEventSink((event) => this.bus.emit(event.type, event));
|
|
3105
3479
|
yield* this.executor.stream(input);
|
|
3106
3480
|
}
|
|
3107
3481
|
getState() {
|
|
3108
3482
|
return this.executor.getState();
|
|
3109
3483
|
}
|
|
3110
3484
|
abort() {
|
|
3485
|
+
this.executor.abort();
|
|
3111
3486
|
}
|
|
3112
3487
|
on(event, listener) {
|
|
3113
|
-
|
|
3114
|
-
if (!set) {
|
|
3115
|
-
set = /* @__PURE__ */ new Set();
|
|
3116
|
-
this.eventListeners.set(event, set);
|
|
3117
|
-
}
|
|
3118
|
-
set.add(listener);
|
|
3488
|
+
this.bus.on(event, listener);
|
|
3119
3489
|
return this;
|
|
3120
3490
|
}
|
|
3121
3491
|
};
|
|
@@ -3133,6 +3503,9 @@ var DebateExecutor = class {
|
|
|
3133
3503
|
maxRounds;
|
|
3134
3504
|
convergeWhen;
|
|
3135
3505
|
feedbackTransform;
|
|
3506
|
+
abortController = new AbortController();
|
|
3507
|
+
/** 外部事件监听(on() API 的底层接线) */
|
|
3508
|
+
eventSink;
|
|
3136
3509
|
state = {
|
|
3137
3510
|
nodeStates: /* @__PURE__ */ new Map(),
|
|
3138
3511
|
nodeResults: /* @__PURE__ */ new Map(),
|
|
@@ -3155,53 +3528,75 @@ ${proposerResult.content}`;
|
|
|
3155
3528
|
this.state.nodeStates.set(reviewer.id, "pending");
|
|
3156
3529
|
}
|
|
3157
3530
|
getState() {
|
|
3158
|
-
return {
|
|
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
|
+
}
|
|
3159
3561
|
}
|
|
3160
3562
|
/** 执行 Debate */
|
|
3161
3563
|
async run(input) {
|
|
3564
|
+
this.resetAbortController();
|
|
3162
3565
|
const ctx = createSharedContext({
|
|
3163
3566
|
meta: { traceId: `debate-${Date.now()}`, startTime: Date.now() }
|
|
3164
3567
|
});
|
|
3568
|
+
storeOriginalInput(ctx, input);
|
|
3569
|
+
const emit = this.eventSink ?? (() => {
|
|
3570
|
+
});
|
|
3165
3571
|
try {
|
|
3166
|
-
|
|
3167
|
-
});
|
|
3572
|
+
const result = await this.executeDebate(input, ctx, emit);
|
|
3573
|
+
emit({ type: "graph_done", result });
|
|
3574
|
+
return result;
|
|
3168
3575
|
} catch (err) {
|
|
3169
|
-
|
|
3576
|
+
const result = this.buildErrorResult(ctx, err);
|
|
3577
|
+
emit({ type: "graph_error", error: result.error ?? "" });
|
|
3578
|
+
return result;
|
|
3170
3579
|
}
|
|
3171
3580
|
}
|
|
3172
3581
|
/** 流式执行 Debate */
|
|
3173
|
-
|
|
3582
|
+
stream(input) {
|
|
3583
|
+
this.resetAbortController();
|
|
3174
3584
|
const ctx = createSharedContext({
|
|
3175
3585
|
meta: { traceId: `debate-${Date.now()}`, startTime: Date.now() }
|
|
3176
3586
|
});
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
}
|
|
3191
|
-
).finally(() => {
|
|
3192
|
-
done = true;
|
|
3193
|
-
resolveEvent?.();
|
|
3194
|
-
});
|
|
3195
|
-
while (!done || eventQueue.length > 0) {
|
|
3196
|
-
if (eventQueue.length > 0) {
|
|
3197
|
-
yield eventQueue.shift();
|
|
3198
|
-
} else {
|
|
3199
|
-
await new Promise((resolve) => {
|
|
3200
|
-
resolveEvent = resolve;
|
|
3201
|
-
});
|
|
3202
|
-
}
|
|
3203
|
-
}
|
|
3204
|
-
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
|
+
);
|
|
3205
3600
|
}
|
|
3206
3601
|
/** 核心执行逻辑 */
|
|
3207
3602
|
async executeDebate(input, ctx, emit) {
|
|
@@ -3213,10 +3608,11 @@ ${proposerResult.content}`;
|
|
|
3213
3608
|
let convergeReason = "";
|
|
3214
3609
|
let currentInput = input;
|
|
3215
3610
|
for (let round = 1; round <= this.maxRounds; round++) {
|
|
3611
|
+
this.throwIfAborted();
|
|
3216
3612
|
emit({ type: "round_start", round });
|
|
3217
3613
|
this.state.currentAgentId = this.proposerNode.id;
|
|
3218
3614
|
this.state.nodeStates.set(this.proposerNode.id, "running");
|
|
3219
|
-
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) });
|
|
3220
3616
|
try {
|
|
3221
3617
|
lastProposerResult = await executeNode(this.proposerNode, currentInput, ctx);
|
|
3222
3618
|
this.state.nodeStates.set(this.proposerNode.id, "completed");
|
|
@@ -3233,7 +3629,7 @@ ${proposerResult.content}`;
|
|
|
3233
3629
|
}
|
|
3234
3630
|
this.state.currentAgentId = this.reviewerNode.id;
|
|
3235
3631
|
this.state.nodeStates.set(this.reviewerNode.id, "running");
|
|
3236
|
-
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 });
|
|
3237
3633
|
try {
|
|
3238
3634
|
lastReviewerResult = await executeNode(this.reviewerNode, lastProposerResult.content, ctx);
|
|
3239
3635
|
this.state.nodeStates.set(this.reviewerNode.id, "completed");
|
|
@@ -3272,16 +3668,20 @@ ${proposerResult.content}`;
|
|
|
3272
3668
|
}
|
|
3273
3669
|
buildErrorResult(ctx, err) {
|
|
3274
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);
|
|
3275
3675
|
return {
|
|
3276
|
-
content: "",
|
|
3676
|
+
content: aborted ? lastCompleted?.content ?? "" : "",
|
|
3277
3677
|
lastAgentId: this.proposerNode.id,
|
|
3278
3678
|
agentResults: new Map(this.state.nodeResults),
|
|
3279
3679
|
totalUsage: {},
|
|
3280
3680
|
stepsCompleted: this.state.stepsCompleted,
|
|
3281
|
-
stopReason: "error",
|
|
3681
|
+
stopReason: aborted ? "aborted" : "error",
|
|
3282
3682
|
context: ctx,
|
|
3283
3683
|
success: false,
|
|
3284
|
-
error:
|
|
3684
|
+
error: errorMsg
|
|
3285
3685
|
};
|
|
3286
3686
|
}
|
|
3287
3687
|
mergeUsage(total, usage) {
|
|
@@ -3294,7 +3694,8 @@ ${proposerResult.content}`;
|
|
|
3294
3694
|
// patterns/debate.ts
|
|
3295
3695
|
var DebateGraphImpl = class {
|
|
3296
3696
|
executor;
|
|
3297
|
-
|
|
3697
|
+
/** on() 注册的监听器,按 MultiAgentEvent.type 分发 */
|
|
3698
|
+
bus = new SimpleEventBus();
|
|
3298
3699
|
constructor(proposer, reviewer, opts) {
|
|
3299
3700
|
this.executor = new DebateExecutor(proposer, reviewer, opts);
|
|
3300
3701
|
}
|
|
@@ -3311,23 +3712,21 @@ var DebateGraphImpl = class {
|
|
|
3311
3712
|
throw new Error("Debate \u6A21\u5F0F\u4E0D\u652F\u6301 setFinish");
|
|
3312
3713
|
}
|
|
3313
3714
|
async run(input) {
|
|
3715
|
+
this.executor.setEventSink((event) => this.bus.emit(event.type, event));
|
|
3314
3716
|
return this.executor.run(input);
|
|
3315
3717
|
}
|
|
3316
3718
|
async *stream(input) {
|
|
3719
|
+
this.executor.setEventSink((event) => this.bus.emit(event.type, event));
|
|
3317
3720
|
yield* this.executor.stream(input);
|
|
3318
3721
|
}
|
|
3319
3722
|
getState() {
|
|
3320
3723
|
return this.executor.getState();
|
|
3321
3724
|
}
|
|
3322
3725
|
abort() {
|
|
3726
|
+
this.executor.abort();
|
|
3323
3727
|
}
|
|
3324
3728
|
on(event, listener) {
|
|
3325
|
-
|
|
3326
|
-
if (!set) {
|
|
3327
|
-
set = /* @__PURE__ */ new Set();
|
|
3328
|
-
this.eventListeners.set(event, set);
|
|
3329
|
-
}
|
|
3330
|
-
set.add(listener);
|
|
3729
|
+
this.bus.on(event, listener);
|
|
3331
3730
|
return this;
|
|
3332
3731
|
}
|
|
3333
3732
|
};
|
|
@@ -3341,7 +3740,11 @@ var MapReduceExecutor = class {
|
|
|
3341
3740
|
reducerNode;
|
|
3342
3741
|
split;
|
|
3343
3742
|
concurrency;
|
|
3743
|
+
onMapperError;
|
|
3344
3744
|
reduceInputFormat;
|
|
3745
|
+
abortController = new AbortController();
|
|
3746
|
+
/** 外部事件监听(on() API 的底层接线) */
|
|
3747
|
+
eventSink;
|
|
3345
3748
|
state = {
|
|
3346
3749
|
nodeStates: /* @__PURE__ */ new Map(),
|
|
3347
3750
|
nodeResults: /* @__PURE__ */ new Map(),
|
|
@@ -3353,6 +3756,7 @@ var MapReduceExecutor = class {
|
|
|
3353
3756
|
this.reducerNode = reducer;
|
|
3354
3757
|
this.split = opts.split;
|
|
3355
3758
|
this.concurrency = opts.concurrency ?? Infinity;
|
|
3759
|
+
this.onMapperError = opts.onMapperError ?? "fail-fast";
|
|
3356
3760
|
this.reduceInputFormat = opts.reduceInputFormat ?? ((mapperResults) => {
|
|
3357
3761
|
const parts = [];
|
|
3358
3762
|
for (const [idx, result] of mapperResults) {
|
|
@@ -3365,132 +3769,98 @@ ${result.content}`);
|
|
|
3365
3769
|
this.state.nodeStates.set(reducer.id, "pending");
|
|
3366
3770
|
}
|
|
3367
3771
|
getState() {
|
|
3368
|
-
return {
|
|
3772
|
+
return {
|
|
3773
|
+
...this.state,
|
|
3774
|
+
nodeStates: new Map(this.state.nodeStates),
|
|
3775
|
+
nodeResults: new Map(this.state.nodeResults)
|
|
3776
|
+
};
|
|
3369
3777
|
}
|
|
3370
|
-
/**
|
|
3371
|
-
|
|
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) {
|
|
3372
3805
|
const inputText = typeof input === "string" ? input : input.message;
|
|
3373
3806
|
const chunks = this.split(inputText);
|
|
3374
3807
|
if (chunks.length === 0) {
|
|
3375
3808
|
throw new Error("MapReduce: split \u51FD\u6570\u8FD4\u56DE\u4E86\u7A7A\u6570\u7EC4\uFF0C\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u4EFB\u52A1");
|
|
3376
3809
|
}
|
|
3810
|
+
return chunks;
|
|
3811
|
+
}
|
|
3812
|
+
/** 执行 MapReduce */
|
|
3813
|
+
async run(input) {
|
|
3814
|
+
this.resetAbortController();
|
|
3815
|
+
const chunks = this.splitInput(input);
|
|
3377
3816
|
const ctx = createSharedContext({
|
|
3378
3817
|
meta: { traceId: `mr-${Date.now()}`, startTime: Date.now() }
|
|
3379
3818
|
});
|
|
3819
|
+
storeOriginalInput(ctx, input);
|
|
3820
|
+
const emit = this.eventSink ?? (() => {
|
|
3821
|
+
});
|
|
3380
3822
|
try {
|
|
3381
|
-
|
|
3382
|
-
});
|
|
3823
|
+
const result = await this.executeMapReduce(chunks, ctx, emit);
|
|
3824
|
+
emit({ type: "graph_done", result });
|
|
3825
|
+
return result;
|
|
3383
3826
|
} catch (err) {
|
|
3384
|
-
|
|
3827
|
+
const result = this.buildErrorResult(ctx, err);
|
|
3828
|
+
emit({ type: "graph_error", error: result.error ?? "" });
|
|
3829
|
+
return result;
|
|
3385
3830
|
}
|
|
3386
3831
|
}
|
|
3387
3832
|
/** 流式执行 MapReduce */
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
const chunks = this.
|
|
3391
|
-
if (chunks.length === 0) {
|
|
3392
|
-
throw new Error("MapReduce: split \u51FD\u6570\u8FD4\u56DE\u4E86\u7A7A\u6570\u7EC4\uFF0C\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u4EFB\u52A1");
|
|
3393
|
-
}
|
|
3833
|
+
stream(input) {
|
|
3834
|
+
this.resetAbortController();
|
|
3835
|
+
const chunks = this.splitInput(input);
|
|
3394
3836
|
const ctx = createSharedContext({
|
|
3395
3837
|
meta: { traceId: `mr-${Date.now()}`, startTime: Date.now() }
|
|
3396
3838
|
});
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
}
|
|
3411
|
-
).finally(() => {
|
|
3412
|
-
done = true;
|
|
3413
|
-
resolveEvent?.();
|
|
3414
|
-
});
|
|
3415
|
-
while (!done || eventQueue.length > 0) {
|
|
3416
|
-
if (eventQueue.length > 0) {
|
|
3417
|
-
yield eventQueue.shift();
|
|
3418
|
-
} else {
|
|
3419
|
-
await new Promise((resolve) => {
|
|
3420
|
-
resolveEvent = resolve;
|
|
3421
|
-
});
|
|
3422
|
-
}
|
|
3423
|
-
}
|
|
3424
|
-
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
|
+
);
|
|
3425
3852
|
}
|
|
3426
3853
|
/** 核心执行逻辑 */
|
|
3427
|
-
async executeMapReduce(
|
|
3428
|
-
let stepsCompleted = 0;
|
|
3854
|
+
async executeMapReduce(chunks, ctx, emit) {
|
|
3429
3855
|
const totalUsage = {};
|
|
3430
|
-
|
|
3431
|
-
const chunks = this.split(inputText);
|
|
3432
|
-
const mapperResults = /* @__PURE__ */ new Map();
|
|
3856
|
+
this.throwIfAborted();
|
|
3433
3857
|
this.state.nodeStates.set(this.mapperNode.id, "running");
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
const result = await executeNode(this.mapperNode, chunk, ctx);
|
|
3441
|
-
this.state.nodeResults.set(`${this.mapperNode.id}_${index}`, result);
|
|
3442
|
-
this.mergeUsage(totalUsage, result.usage);
|
|
3443
|
-
stepsCompleted++;
|
|
3444
|
-
this.state.stepsCompleted = stepsCompleted;
|
|
3445
|
-
emit({ type: "agent_result", agentId: `${this.mapperNode.id}_${index}`, agentName: `${this.mapperNode.name}#${index + 1}`, result });
|
|
3446
|
-
return { index, result };
|
|
3447
|
-
} catch (err) {
|
|
3448
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
3449
|
-
emit({ type: "agent_error", agentId: `${this.mapperNode.id}_${index}`, agentName: `${this.mapperNode.name}#${index + 1}`, error: errorMsg });
|
|
3450
|
-
throw err;
|
|
3451
|
-
}
|
|
3452
|
-
});
|
|
3453
|
-
const settled = await Promise.allSettled(promises);
|
|
3454
|
-
for (const s of settled) {
|
|
3455
|
-
if (s.status === "fulfilled") {
|
|
3456
|
-
mapperResults.set(s.value.index, s.value.result);
|
|
3457
|
-
}
|
|
3458
|
-
}
|
|
3459
|
-
} else {
|
|
3460
|
-
let index = 0;
|
|
3461
|
-
const executing = /* @__PURE__ */ new Set();
|
|
3462
|
-
const enqueue = () => {
|
|
3463
|
-
if (index >= chunks.length) return null;
|
|
3464
|
-
const currentIndex = index++;
|
|
3465
|
-
const chunk = chunks[currentIndex];
|
|
3466
|
-
const p = (async () => {
|
|
3467
|
-
emit({ type: "agent_start", agentId: `${this.mapperNode.id}_${currentIndex}`, agentName: `${this.mapperNode.name}#${currentIndex + 1}` });
|
|
3468
|
-
try {
|
|
3469
|
-
const result = await executeNode(this.mapperNode, chunk, ctx);
|
|
3470
|
-
mapperResults.set(currentIndex, result);
|
|
3471
|
-
this.state.nodeResults.set(`${this.mapperNode.id}_${currentIndex}`, result);
|
|
3472
|
-
this.mergeUsage(totalUsage, result.usage);
|
|
3473
|
-
stepsCompleted++;
|
|
3474
|
-
this.state.stepsCompleted = stepsCompleted;
|
|
3475
|
-
emit({ type: "agent_result", agentId: `${this.mapperNode.id}_${currentIndex}`, agentName: `${this.mapperNode.name}#${currentIndex + 1}`, result });
|
|
3476
|
-
} catch (err) {
|
|
3477
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
3478
|
-
emit({ type: "agent_error", agentId: `${this.mapperNode.id}_${currentIndex}`, agentName: `${this.mapperNode.name}#${currentIndex + 1}`, error: errorMsg });
|
|
3479
|
-
throw err;
|
|
3480
|
-
}
|
|
3481
|
-
})();
|
|
3482
|
-
executing.add(p);
|
|
3483
|
-
p.finally(() => executing.delete(p));
|
|
3484
|
-
return p;
|
|
3485
|
-
};
|
|
3486
|
-
for (let i = 0; i < this.concurrency && index < chunks.length; i++) {
|
|
3487
|
-
enqueue();
|
|
3488
|
-
}
|
|
3489
|
-
while (executing.size > 0) {
|
|
3490
|
-
await Promise.race(executing);
|
|
3491
|
-
enqueue();
|
|
3492
|
-
}
|
|
3493
|
-
}
|
|
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;
|
|
3494
3864
|
this.state.nodeStates.set(this.mapperNode.id, "completed");
|
|
3495
3865
|
const mapperResultsForEmit = /* @__PURE__ */ new Map();
|
|
3496
3866
|
for (const [idx, result] of mapperResults) {
|
|
@@ -3498,10 +3868,14 @@ ${result.content}`);
|
|
|
3498
3868
|
}
|
|
3499
3869
|
emit({ type: "parallel_done", results: mapperResultsForEmit });
|
|
3500
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
|
+
}
|
|
3501
3874
|
const reduceInput = this.reduceInputFormat(mapperResults);
|
|
3875
|
+
this.throwIfAborted();
|
|
3502
3876
|
this.state.currentAgentId = this.reducerNode.id;
|
|
3503
3877
|
this.state.nodeStates.set(this.reducerNode.id, "running");
|
|
3504
|
-
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 });
|
|
3505
3879
|
let reducerResult;
|
|
3506
3880
|
try {
|
|
3507
3881
|
reducerResult = await executeNode(this.reducerNode, reduceInput, ctx);
|
|
@@ -3518,29 +3892,94 @@ ${result.content}`);
|
|
|
3518
3892
|
throw err;
|
|
3519
3893
|
}
|
|
3520
3894
|
this.state.finished = true;
|
|
3895
|
+
const hasFailures = failed.length > 0;
|
|
3521
3896
|
return {
|
|
3522
3897
|
content: reducerResult.content,
|
|
3523
3898
|
lastAgentId: this.reducerNode.id,
|
|
3524
3899
|
agentResults: new Map(this.state.nodeResults),
|
|
3525
3900
|
totalUsage,
|
|
3526
3901
|
stepsCompleted,
|
|
3527
|
-
stopReason: "completed",
|
|
3902
|
+
stopReason: hasFailures ? "partial_failure" : "completed",
|
|
3528
3903
|
context: ctx,
|
|
3529
|
-
success: true
|
|
3904
|
+
success: true,
|
|
3905
|
+
...hasFailures ? { failedAgents: failed } : {}
|
|
3530
3906
|
};
|
|
3531
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
|
+
}
|
|
3532
3967
|
buildErrorResult(ctx, err) {
|
|
3533
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);
|
|
3534
3973
|
return {
|
|
3535
|
-
content: "",
|
|
3974
|
+
content: aborted ? lastCompleted?.content ?? "" : "",
|
|
3536
3975
|
lastAgentId: this.mapperNode.id,
|
|
3537
3976
|
agentResults: new Map(this.state.nodeResults),
|
|
3538
3977
|
totalUsage: {},
|
|
3539
3978
|
stepsCompleted: this.state.stepsCompleted,
|
|
3540
|
-
stopReason: "error",
|
|
3979
|
+
stopReason: aborted ? "aborted" : "error",
|
|
3541
3980
|
context: ctx,
|
|
3542
3981
|
success: false,
|
|
3543
|
-
error:
|
|
3982
|
+
error: errorMsg
|
|
3544
3983
|
};
|
|
3545
3984
|
}
|
|
3546
3985
|
mergeUsage(total, usage) {
|
|
@@ -3553,7 +3992,8 @@ ${result.content}`);
|
|
|
3553
3992
|
// patterns/map-reduce.ts
|
|
3554
3993
|
var MapReduceGraphImpl = class {
|
|
3555
3994
|
executor;
|
|
3556
|
-
|
|
3995
|
+
/** on() 注册的监听器,按 MultiAgentEvent.type 分发 */
|
|
3996
|
+
bus = new SimpleEventBus();
|
|
3557
3997
|
constructor(mapper, reducer, opts) {
|
|
3558
3998
|
this.executor = new MapReduceExecutor(mapper, reducer, opts);
|
|
3559
3999
|
}
|
|
@@ -3570,23 +4010,21 @@ var MapReduceGraphImpl = class {
|
|
|
3570
4010
|
throw new Error("MapReduce \u6A21\u5F0F\u4E0D\u652F\u6301 setFinish");
|
|
3571
4011
|
}
|
|
3572
4012
|
async run(input) {
|
|
4013
|
+
this.executor.setEventSink((event) => this.bus.emit(event.type, event));
|
|
3573
4014
|
return this.executor.run(input);
|
|
3574
4015
|
}
|
|
3575
4016
|
async *stream(input) {
|
|
4017
|
+
this.executor.setEventSink((event) => this.bus.emit(event.type, event));
|
|
3576
4018
|
yield* this.executor.stream(input);
|
|
3577
4019
|
}
|
|
3578
4020
|
getState() {
|
|
3579
4021
|
return this.executor.getState();
|
|
3580
4022
|
}
|
|
3581
4023
|
abort() {
|
|
4024
|
+
this.executor.abort();
|
|
3582
4025
|
}
|
|
3583
4026
|
on(event, listener) {
|
|
3584
|
-
|
|
3585
|
-
if (!set) {
|
|
3586
|
-
set = /* @__PURE__ */ new Set();
|
|
3587
|
-
this.eventListeners.set(event, set);
|
|
3588
|
-
}
|
|
3589
|
-
set.add(listener);
|
|
4027
|
+
this.bus.on(event, listener);
|
|
3590
4028
|
return this;
|
|
3591
4029
|
}
|
|
3592
4030
|
};
|
|
@@ -4225,6 +4663,7 @@ var GraphDebugger = class {
|
|
|
4225
4663
|
const graphStartTime = Date.now();
|
|
4226
4664
|
const steps = [];
|
|
4227
4665
|
let stepIndex = 0;
|
|
4666
|
+
let finalResult;
|
|
4228
4667
|
for await (const event of this.graph.stream(input)) {
|
|
4229
4668
|
if (event.type === "agent_start") {
|
|
4230
4669
|
stepIndex++;
|
|
@@ -4234,7 +4673,7 @@ var GraphDebugger = class {
|
|
|
4234
4673
|
agentName: event.agentName,
|
|
4235
4674
|
startTime: Date.now(),
|
|
4236
4675
|
duration: 0,
|
|
4237
|
-
input: "",
|
|
4676
|
+
input: event.input ?? "",
|
|
4238
4677
|
output: "",
|
|
4239
4678
|
state: "running"
|
|
4240
4679
|
});
|
|
@@ -4259,6 +4698,8 @@ var GraphDebugger = class {
|
|
|
4259
4698
|
step.error = event.error;
|
|
4260
4699
|
step.state = "failed";
|
|
4261
4700
|
}
|
|
4701
|
+
} else if (event.type === "graph_done") {
|
|
4702
|
+
finalResult = event.result;
|
|
4262
4703
|
}
|
|
4263
4704
|
}
|
|
4264
4705
|
const state = this.graph.getState();
|
|
@@ -4269,10 +4710,10 @@ var GraphDebugger = class {
|
|
|
4269
4710
|
duration: graphDuration,
|
|
4270
4711
|
steps,
|
|
4271
4712
|
result: {
|
|
4272
|
-
success: !state.error,
|
|
4273
|
-
content:
|
|
4274
|
-
stopReason: state.error ? "error" : "completed",
|
|
4275
|
-
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
|
|
4276
4717
|
}
|
|
4277
4718
|
};
|
|
4278
4719
|
}
|
|
@@ -4324,13 +4765,16 @@ function createDebugger(graph) {
|
|
|
4324
4765
|
return new GraphDebugger(graph);
|
|
4325
4766
|
}
|
|
4326
4767
|
export {
|
|
4768
|
+
GraphAbortedError,
|
|
4327
4769
|
GraphDebugger,
|
|
4328
4770
|
MCPBridge,
|
|
4771
|
+
NodeTimeoutError,
|
|
4329
4772
|
SimpleEventBus,
|
|
4330
4773
|
SimpleToolRegistry,
|
|
4331
4774
|
createAgentGraph,
|
|
4332
4775
|
createDebate,
|
|
4333
4776
|
createDebugger,
|
|
4777
|
+
createEventStream,
|
|
4334
4778
|
createMCPBridge,
|
|
4335
4779
|
createMapReduce,
|
|
4336
4780
|
createMultiAgentMcpServerHost,
|