@ai-setting/roy-agent-core 1.5.43 → 1.5.45
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/config/index.js +5 -5
- package/dist/env/agent/index.js +5 -5
- package/dist/env/commands/index.js +5 -5
- package/dist/env/context/index.js +4 -1
- package/dist/env/debug/index.js +5 -5
- package/dist/env/event-source/index.js +7 -7
- package/dist/env/hook/index.js +3 -3
- package/dist/env/index.js +24 -20
- package/dist/env/llm/index.js +5 -5
- package/dist/env/log-trace/index.js +5 -5
- package/dist/env/mcp/index.js +20 -6
- package/dist/env/memory/index.js +5 -5
- package/dist/env/plugin/index.js +5 -5
- package/dist/env/prompt/index.js +5 -5
- package/dist/env/session/index.js +6 -6
- package/dist/env/session/storage/index.js +1 -1
- package/dist/env/skill/index.js +5 -5
- package/dist/env/task/delegate/index.js +3 -3
- package/dist/env/task/index.js +6 -6
- package/dist/env/task/plugins/index.js +2 -2
- package/dist/env/tool/built-in/index.js +1 -1
- package/dist/env/tool/index.js +6 -6
- package/dist/env/workflow/decorators/index.js +1 -1
- package/dist/env/workflow/engine/index.js +10 -4
- package/dist/env/workflow/index.js +42 -24
- package/dist/env/workflow/nodes/index.js +5 -1
- package/dist/env/workflow/tools/index.js +14 -0
- package/dist/env/workflow/types/index.js +16 -2
- package/dist/env/workflow/utils/index.js +15 -196
- package/dist/index.js +35 -31
- package/dist/shared/@ai-setting/{roy-agent-core-kajktp3d.js → roy-agent-core-20fm423j.js} +47 -26
- package/dist/shared/@ai-setting/{roy-agent-core-ffb9fq4v.js → roy-agent-core-2vhsccvz.js} +54 -12
- package/dist/shared/@ai-setting/{roy-agent-core-69jskqjg.js → roy-agent-core-44g4dhzg.js} +75 -7
- package/dist/shared/@ai-setting/{roy-agent-core-e9fdm13a.js → roy-agent-core-4gmxjdhn.js} +4 -2
- package/dist/shared/@ai-setting/{roy-agent-core-b4wd9tn6.js → roy-agent-core-4k9a823d.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-68qy97r3.js +31 -0
- package/dist/shared/@ai-setting/roy-agent-core-6atd905e.js +42 -0
- package/dist/shared/@ai-setting/{roy-agent-core-4jqq077c.js → roy-agent-core-6e3wz81d.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-pwkk12p4.js → roy-agent-core-6mcb7nqa.js} +60 -0
- package/dist/shared/@ai-setting/roy-agent-core-6vxg2gmr.js +321 -0
- package/dist/shared/@ai-setting/{roy-agent-core-9p43ap7h.js → roy-agent-core-8y804aat.js} +4 -2
- package/dist/shared/@ai-setting/{roy-agent-core-0rtxwr28.js → roy-agent-core-9bmtxmp6.js} +77 -120
- package/dist/shared/@ai-setting/{roy-agent-core-r6rwsr54.js → roy-agent-core-9p604xjf.js} +29 -9
- package/dist/shared/@ai-setting/{roy-agent-core-z1xf2fdk.js → roy-agent-core-a67e90d1.js} +6 -4
- package/dist/shared/@ai-setting/{roy-agent-core-xkb264a8.js → roy-agent-core-bp3xggmb.js} +192 -26
- package/dist/shared/@ai-setting/{roy-agent-core-zrja5v78.js → roy-agent-core-ce9w0j8n.js} +10 -2
- package/dist/shared/@ai-setting/{roy-agent-core-bmr6bdfb.js → roy-agent-core-cr8xer31.js} +15 -8
- package/dist/shared/@ai-setting/roy-agent-core-dbxm76wf.js +190 -0
- package/dist/shared/@ai-setting/{roy-agent-core-nj8yerg9.js → roy-agent-core-eftqdsy5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-7fgf85wc.js → roy-agent-core-h0x19xgn.js} +6 -7
- package/dist/shared/@ai-setting/{roy-agent-core-psvwzdhj.js → roy-agent-core-hdszq729.js} +9 -5
- package/dist/shared/@ai-setting/{roy-agent-core-dxbsc1zy.js → roy-agent-core-ja9qhg6d.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-cevpwnq7.js → roy-agent-core-mjbfgqen.js} +5 -3
- package/dist/shared/@ai-setting/roy-agent-core-nhfy3p8q.js +132 -0
- package/dist/shared/@ai-setting/{roy-agent-core-2jnzv9at.js → roy-agent-core-nn9dmffw.js} +629 -288
- package/dist/shared/@ai-setting/roy-agent-core-qnrf2aw6.js +441 -0
- package/dist/shared/@ai-setting/{roy-agent-core-ee6nnnqw.js → roy-agent-core-r9hq4cjx.js} +8 -1
- package/dist/shared/@ai-setting/{roy-agent-core-jqy2mdyq.js → roy-agent-core-rgj6hq15.js} +52 -41
- package/dist/shared/@ai-setting/{roy-agent-core-z33en0cz.js → roy-agent-core-rm3hay00.js} +15 -2
- package/dist/shared/@ai-setting/{roy-agent-core-e130w7mv.js → roy-agent-core-rx74rye7.js} +5 -3
- package/dist/shared/@ai-setting/{roy-agent-core-pxcrzyv9.js → roy-agent-core-sk535ft2.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-v002ynpa.js +435 -0
- package/dist/shared/@ai-setting/{roy-agent-core-2dhd60aw.js → roy-agent-core-vdwvamre.js} +10 -0
- package/dist/shared/@ai-setting/{roy-agent-core-1zq3p19q.js → roy-agent-core-w64zachx.js} +8 -4
- package/dist/shared/@ai-setting/roy-agent-core-ye0z728h.js +18 -0
- package/dist/shared/@ai-setting/{roy-agent-core-rsybkb38.js → roy-agent-core-ysvh8er9.js} +36 -39
- package/dist/shared/@ai-setting/{roy-agent-core-9yxb3ty9.js → roy-agent-core-z5sxe4p7.js} +5 -1
- package/dist/shared/@ai-setting/{roy-agent-core-eg6nv09z.js → roy-agent-core-ztx5eh72.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-nqgrjja0.js → roy-agent-core-zwq6vhpj.js} +1 -1
- package/package.json +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-5x94xmt6.js +0 -350
- package/dist/shared/@ai-setting/roy-agent-core-dh9d7a3m.js +0 -11
- package/dist/shared/@ai-setting/roy-agent-core-jvatggbb.js +0 -603
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildWorkflowNodeMetadata,
|
|
3
|
+
getWorkflowNodeIdFromMetadata,
|
|
4
|
+
init_workflow_message_metadata,
|
|
5
|
+
patchAgentSessionIdOnMessage
|
|
6
|
+
} from "./roy-agent-core-6atd905e.js";
|
|
1
7
|
import {
|
|
2
8
|
AgentComponentAdapter,
|
|
3
9
|
init_agent_component_adapter
|
|
4
|
-
} from "./roy-agent-core-
|
|
10
|
+
} from "./roy-agent-core-44g4dhzg.js";
|
|
5
11
|
import {
|
|
6
12
|
SkillNode,
|
|
7
13
|
ToolNode,
|
|
@@ -9,12 +15,26 @@ import {
|
|
|
9
15
|
init_skill_node,
|
|
10
16
|
init_tool_node,
|
|
11
17
|
init_workflow_node
|
|
12
|
-
} from "./roy-agent-core-
|
|
18
|
+
} from "./roy-agent-core-6vxg2gmr.js";
|
|
19
|
+
import {
|
|
20
|
+
WORKFLOW_SUBMIT_OUTPUT_TOOL_NAME,
|
|
21
|
+
init_json_schema_to_zod,
|
|
22
|
+
init_submit_json_output_tool,
|
|
23
|
+
jsonSchemaToZod,
|
|
24
|
+
parseWorkflowJsonOutput,
|
|
25
|
+
validateJsonOutputSchema
|
|
26
|
+
} from "./roy-agent-core-nhfy3p8q.js";
|
|
27
|
+
import {
|
|
28
|
+
TemplateResolver,
|
|
29
|
+
init_template_resolver
|
|
30
|
+
} from "./roy-agent-core-v002ynpa.js";
|
|
13
31
|
import {
|
|
32
|
+
WorkflowError,
|
|
14
33
|
createWorkflowEvent,
|
|
15
34
|
init_event,
|
|
16
|
-
init_types
|
|
17
|
-
|
|
35
|
+
init_types,
|
|
36
|
+
init_workflow_error
|
|
37
|
+
} from "./roy-agent-core-qnrf2aw6.js";
|
|
18
38
|
import {
|
|
19
39
|
AskUserError,
|
|
20
40
|
createNodeInterruptEvent,
|
|
@@ -129,12 +149,14 @@ class DAGManager {
|
|
|
129
149
|
nodeMap;
|
|
130
150
|
extendedDefinition = null;
|
|
131
151
|
cachedAnalysis = null;
|
|
132
|
-
|
|
152
|
+
allowCycles;
|
|
153
|
+
constructor(workflow, options) {
|
|
133
154
|
if (!workflow.nodes || workflow.nodes.length === 0) {
|
|
134
155
|
throw new Error("At least one node is required");
|
|
135
156
|
}
|
|
136
157
|
this.workflow = workflow;
|
|
137
158
|
this.nodeMap = new Map;
|
|
159
|
+
this.allowCycles = options?.allowCycles ?? false;
|
|
138
160
|
for (const node of workflow.nodes) {
|
|
139
161
|
if (node.id === "") {
|
|
140
162
|
throw new Error("Node ID cannot be empty");
|
|
@@ -386,7 +408,7 @@ class DAGManager {
|
|
|
386
408
|
}
|
|
387
409
|
return result;
|
|
388
410
|
}
|
|
389
|
-
validate() {
|
|
411
|
+
validate(options) {
|
|
390
412
|
const errors = [];
|
|
391
413
|
const nodeIds = new Set;
|
|
392
414
|
for (const node of this.workflow.nodes) {
|
|
@@ -407,7 +429,7 @@ class DAGManager {
|
|
|
407
429
|
}
|
|
408
430
|
}
|
|
409
431
|
}
|
|
410
|
-
if (this.isCyclic()) {
|
|
432
|
+
if (!this.allowCycles && !options?.skipCycleCheck && this.isCyclic()) {
|
|
411
433
|
errors.push("Workflow contains a cycle");
|
|
412
434
|
}
|
|
413
435
|
return {
|
|
@@ -455,6 +477,27 @@ class DAGManager {
|
|
|
455
477
|
const analysis = this.analyze();
|
|
456
478
|
return analysis.dependents.get(nodeId) || [];
|
|
457
479
|
}
|
|
480
|
+
getDownstreamUntil(fromNodeId, untilNodeId) {
|
|
481
|
+
const result = [];
|
|
482
|
+
const visited = new Set;
|
|
483
|
+
const queue = [...this.getDependents(fromNodeId)];
|
|
484
|
+
while (queue.length > 0) {
|
|
485
|
+
const nodeId = queue.shift();
|
|
486
|
+
if (visited.has(nodeId))
|
|
487
|
+
continue;
|
|
488
|
+
visited.add(nodeId);
|
|
489
|
+
result.push(nodeId);
|
|
490
|
+
if (nodeId === untilNodeId) {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
for (const dependent of this.getDependents(nodeId)) {
|
|
494
|
+
if (!visited.has(dependent)) {
|
|
495
|
+
queue.push(dependent);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return result;
|
|
500
|
+
}
|
|
458
501
|
getDefinition() {
|
|
459
502
|
return this.workflow;
|
|
460
503
|
}
|
|
@@ -467,6 +510,20 @@ class DAGManager {
|
|
|
467
510
|
getNodeCount() {
|
|
468
511
|
return this.nodeMap.size;
|
|
469
512
|
}
|
|
513
|
+
buildEdges(explicitEdges = []) {
|
|
514
|
+
const derivedEdges = [];
|
|
515
|
+
const explicitEdgeSet = new Set(explicitEdges.map((e) => `${e.from}->${e.to}`));
|
|
516
|
+
for (const node of this.workflow.nodes) {
|
|
517
|
+
const deps = node.depends_on || [];
|
|
518
|
+
for (const dep of deps) {
|
|
519
|
+
const edgeKey = `${dep}->${node.id}`;
|
|
520
|
+
if (!explicitEdgeSet.has(edgeKey)) {
|
|
521
|
+
derivedEdges.push({ from: dep, to: node.id });
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return [...explicitEdges, ...derivedEdges];
|
|
526
|
+
}
|
|
470
527
|
}
|
|
471
528
|
var init_dag_manager = () => {};
|
|
472
529
|
|
|
@@ -542,6 +599,10 @@ class Scheduler {
|
|
|
542
599
|
return this.ready.has(nodeId);
|
|
543
600
|
}
|
|
544
601
|
markCompleted(nodeId) {
|
|
602
|
+
if (nodeId === "__end__" || nodeId === "__END__") {
|
|
603
|
+
logger.debug(`[Scheduler] Workflow marked as completed via __end__`);
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
545
606
|
this.running.delete(nodeId);
|
|
546
607
|
this.ready.delete(nodeId);
|
|
547
608
|
this.pending.delete(nodeId);
|
|
@@ -569,6 +630,21 @@ class Scheduler {
|
|
|
569
630
|
}
|
|
570
631
|
this.skipped.add(nodeId);
|
|
571
632
|
}
|
|
633
|
+
unmarkSkipped(nodeId) {
|
|
634
|
+
if (!this.skipped.has(nodeId)) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
this.skipped.delete(nodeId);
|
|
638
|
+
this.pending.add(nodeId);
|
|
639
|
+
}
|
|
640
|
+
resetNodeForReEntry(nodeId) {
|
|
641
|
+
this.running.delete(nodeId);
|
|
642
|
+
this.completed.delete(nodeId);
|
|
643
|
+
this.failed.delete(nodeId);
|
|
644
|
+
this.skipped.delete(nodeId);
|
|
645
|
+
this.ready.delete(nodeId);
|
|
646
|
+
this.pending.add(nodeId);
|
|
647
|
+
}
|
|
572
648
|
reset() {
|
|
573
649
|
this.running.clear();
|
|
574
650
|
this.completed.clear();
|
|
@@ -593,6 +669,11 @@ class Scheduler {
|
|
|
593
669
|
skipped: Array.from(this.skipped).sort()
|
|
594
670
|
};
|
|
595
671
|
}
|
|
672
|
+
markCompletedFromRestore(nodeIds) {
|
|
673
|
+
for (const nodeId of nodeIds) {
|
|
674
|
+
this.markCompleted(nodeId);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
596
677
|
updateReadyNodes(completedNodes) {
|
|
597
678
|
const allCompleted = new Set(completedNodes);
|
|
598
679
|
for (const nodeId of this.completed) {
|
|
@@ -616,8 +697,70 @@ class Scheduler {
|
|
|
616
697
|
setParallelLimit(limit) {
|
|
617
698
|
this.options.parallelLimit = limit;
|
|
618
699
|
}
|
|
700
|
+
getOutgoingEdges(nodeId, edges) {
|
|
701
|
+
return edges.filter((edge) => edge.from === nodeId);
|
|
702
|
+
}
|
|
703
|
+
processEdgesAfterCompletion(completedNodeId, edges, templateResolver, loopEnabled) {
|
|
704
|
+
const result = {
|
|
705
|
+
toStart: [],
|
|
706
|
+
reEntries: [],
|
|
707
|
+
skipped: [],
|
|
708
|
+
resetNodes: []
|
|
709
|
+
};
|
|
710
|
+
const completedNode = this.dagManager.getNode(completedNodeId);
|
|
711
|
+
if (completedNode?.condition) {
|
|
712
|
+
const conditionMet = templateResolver.evaluateCondition(completedNode.condition);
|
|
713
|
+
if (!conditionMet) {
|
|
714
|
+
for (const edge of this.getOutgoingEdges(completedNodeId, edges)) {
|
|
715
|
+
this.markSkipped(edge.to);
|
|
716
|
+
result.skipped.push({
|
|
717
|
+
nodeId: edge.to,
|
|
718
|
+
reason: `Inline condition false on node "${completedNodeId}"`
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
return result;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
const outgoingEdges = this.getOutgoingEdges(completedNodeId, edges);
|
|
725
|
+
for (const edge of outgoingEdges) {
|
|
726
|
+
const conditionMet = !edge.when || templateResolver.evaluateCondition(edge.when);
|
|
727
|
+
if (conditionMet) {
|
|
728
|
+
if (this.skipped.has(edge.to)) {
|
|
729
|
+
this.unmarkSkipped(edge.to);
|
|
730
|
+
}
|
|
731
|
+
const isReEntry = loopEnabled && this.completed.has(edge.to);
|
|
732
|
+
const canStart = loopEnabled ? !this.running.has(edge.to) && !this.failed.has(edge.to) : !this.completed.has(edge.to) && !this.running.has(edge.to) && !this.failed.has(edge.to);
|
|
733
|
+
if (canStart) {
|
|
734
|
+
if (isReEntry) {
|
|
735
|
+
const downstream = this.dagManager.getDownstreamUntil(edge.to, completedNodeId);
|
|
736
|
+
for (const nodeId of downstream) {
|
|
737
|
+
this.resetNodeForReEntry(nodeId);
|
|
738
|
+
result.resetNodes.push(nodeId);
|
|
739
|
+
}
|
|
740
|
+
this.resetNodeForReEntry(edge.to);
|
|
741
|
+
result.resetNodes.push(edge.to);
|
|
742
|
+
result.reEntries.push(edge.to);
|
|
743
|
+
}
|
|
744
|
+
result.toStart.push(edge.to);
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
if (!this.skipped.has(edge.to)) {
|
|
748
|
+
result.skipped.push({
|
|
749
|
+
nodeId: edge.to,
|
|
750
|
+
reason: edge.when ? `Edge condition false: ${edge.when}` : "Edge condition false"
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
this.markSkipped(edge.to);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return result;
|
|
757
|
+
}
|
|
619
758
|
}
|
|
620
|
-
var
|
|
759
|
+
var logger;
|
|
760
|
+
var init_scheduler = __esm(() => {
|
|
761
|
+
init_logger();
|
|
762
|
+
logger = createLogger("workflow.scheduler");
|
|
763
|
+
});
|
|
621
764
|
|
|
622
765
|
// src/env/workflow/engine/executor.ts
|
|
623
766
|
var Executor;
|
|
@@ -625,6 +768,7 @@ var init_executor = __esm(() => {
|
|
|
625
768
|
init_event();
|
|
626
769
|
init_types();
|
|
627
770
|
init_decorator();
|
|
771
|
+
init_workflow_message_metadata();
|
|
628
772
|
Executor = class Executor {
|
|
629
773
|
nodeRegistry;
|
|
630
774
|
eventBus;
|
|
@@ -817,15 +961,33 @@ var init_executor = __esm(() => {
|
|
|
817
961
|
role: "workflow.node.start",
|
|
818
962
|
content: contentSummary,
|
|
819
963
|
parts: [part],
|
|
820
|
-
metadata: {
|
|
821
|
-
_workflowNodeMetadata: true,
|
|
822
|
-
type: "workflow.node.start",
|
|
823
|
-
workflowNodeId: nodeId,
|
|
824
|
-
workflowNodeType: nodeType,
|
|
964
|
+
metadata: buildWorkflowNodeMetadata("workflow.node.start", nodeId, nodeType, {
|
|
825
965
|
...agentSessionId ? { agentSessionId } : {}
|
|
826
|
-
}
|
|
966
|
+
})
|
|
827
967
|
});
|
|
828
968
|
}
|
|
969
|
+
async attachAgentSessionToLastStart(sessionId, nodeId, agentSessionId) {
|
|
970
|
+
if (!this.sessionComponent?.getMessages || !this.sessionComponent.updateMessage) {
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
const messages = await this.sessionComponent.getMessages(sessionId);
|
|
974
|
+
for (let i = messages.length - 1;i >= 0; i--) {
|
|
975
|
+
const msg = messages[i];
|
|
976
|
+
const meta = msg.metadata;
|
|
977
|
+
if (meta?.type !== "workflow.node.start") {
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
if (getWorkflowNodeIdFromMetadata(meta) !== nodeId) {
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
if (meta.agentSessionId) {
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
const patched = patchAgentSessionIdOnMessage(meta, msg.parts, agentSessionId);
|
|
987
|
+
await this.sessionComponent.updateMessage(sessionId, msg.id, patched);
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
829
991
|
summarizeCall(nodeType, nodeId, input) {
|
|
830
992
|
if (input === undefined || input === null) {
|
|
831
993
|
return `[${nodeType}] ${nodeId} started`;
|
|
@@ -857,14 +1019,11 @@ var init_executor = __esm(() => {
|
|
|
857
1019
|
role: "workflow.node.interrupt",
|
|
858
1020
|
content: query,
|
|
859
1021
|
parts: [part],
|
|
860
|
-
metadata: {
|
|
861
|
-
_workflowNodeMetadata: true,
|
|
862
|
-
type: "workflow.node.interrupt",
|
|
863
|
-
workflowNodeId: nodeId,
|
|
864
|
-
workflowNodeType: nodeType,
|
|
1022
|
+
metadata: buildWorkflowNodeMetadata("workflow.node.interrupt", nodeId, nodeType, {
|
|
865
1023
|
query,
|
|
866
|
-
agentSessionId
|
|
867
|
-
|
|
1024
|
+
...agentSessionId ? { agentSessionId } : {},
|
|
1025
|
+
timestamp
|
|
1026
|
+
})
|
|
868
1027
|
});
|
|
869
1028
|
}
|
|
870
1029
|
async writeNodeEnd(sessionId, nodeId, nodeType, output, error, durationMs, agentSessionId) {
|
|
@@ -884,14 +1043,10 @@ var init_executor = __esm(() => {
|
|
|
884
1043
|
role: "workflow.node.end",
|
|
885
1044
|
content: contentSummary,
|
|
886
1045
|
parts: [part],
|
|
887
|
-
metadata: {
|
|
888
|
-
_workflowNodeMetadata: true,
|
|
889
|
-
type: "workflow.node.end",
|
|
890
|
-
workflowNodeId: nodeId,
|
|
891
|
-
workflowNodeType: nodeType,
|
|
1046
|
+
metadata: buildWorkflowNodeMetadata("workflow.node.end", nodeId, nodeType, {
|
|
892
1047
|
success: !error,
|
|
893
1048
|
...agentSessionId ? { agentSessionId } : {}
|
|
894
|
-
}
|
|
1049
|
+
})
|
|
895
1050
|
});
|
|
896
1051
|
}
|
|
897
1052
|
summarizeResult(nodeId, output, error, durationMs) {
|
|
@@ -913,7 +1068,7 @@ var init_executor = __esm(() => {
|
|
|
913
1068
|
const truncated = strOutput.length > 100 ? strOutput.substring(0, 100) + "..." : strOutput;
|
|
914
1069
|
return `✅ ${nodeId}: ${truncated} (${durationMs}ms)`;
|
|
915
1070
|
}
|
|
916
|
-
async writeNodeResume(sessionId, nodeId, response, agentSessionId) {
|
|
1071
|
+
async writeNodeResume(sessionId, nodeId, nodeType, response, agentSessionId) {
|
|
917
1072
|
if (!this.sessionComponent)
|
|
918
1073
|
return;
|
|
919
1074
|
const timestamp = Date.now();
|
|
@@ -928,12 +1083,11 @@ var init_executor = __esm(() => {
|
|
|
928
1083
|
role: "workflow.node.resume",
|
|
929
1084
|
content: response,
|
|
930
1085
|
parts: [part],
|
|
931
|
-
metadata: {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
}
|
|
1086
|
+
metadata: buildWorkflowNodeMetadata("workflow.node.resume", nodeId, nodeType, {
|
|
1087
|
+
response,
|
|
1088
|
+
...agentSessionId ? { agentSessionId } : {},
|
|
1089
|
+
timestamp
|
|
1090
|
+
})
|
|
937
1091
|
});
|
|
938
1092
|
}
|
|
939
1093
|
};
|
|
@@ -943,6 +1097,9 @@ var init_executor = __esm(() => {
|
|
|
943
1097
|
__legacyDecorateClassTS([
|
|
944
1098
|
TracedAs("workflow.executor.writeNodeStart", { recordParams: true, recordResult: true, log: true })
|
|
945
1099
|
], Executor.prototype, "writeNodeStart", null);
|
|
1100
|
+
__legacyDecorateClassTS([
|
|
1101
|
+
TracedAs("workflow.executor.attachAgentSessionToLastStart", { log: true })
|
|
1102
|
+
], Executor.prototype, "attachAgentSessionToLastStart", null);
|
|
946
1103
|
__legacyDecorateClassTS([
|
|
947
1104
|
TracedAs("workflow.executor.writeNodeInterrupt", { recordParams: true, recordResult: true, log: true })
|
|
948
1105
|
], Executor.prototype, "writeNodeInterrupt", null);
|
|
@@ -954,11 +1111,139 @@ var init_executor = __esm(() => {
|
|
|
954
1111
|
], Executor.prototype, "writeNodeResume", null);
|
|
955
1112
|
});
|
|
956
1113
|
|
|
1114
|
+
// src/env/workflow/utils/parse-agent-output-config.ts
|
|
1115
|
+
function parseAgentOutputConfig(config) {
|
|
1116
|
+
const output = config.output;
|
|
1117
|
+
if (!output) {
|
|
1118
|
+
return { mode: "string" };
|
|
1119
|
+
}
|
|
1120
|
+
const mode = output.mode === "json" ? "json" : "string";
|
|
1121
|
+
if (mode === "json") {
|
|
1122
|
+
if (output.schema === undefined) {
|
|
1123
|
+
throw new Error("AgentNode output.mode=json requires output.schema");
|
|
1124
|
+
}
|
|
1125
|
+
const schema = validateJsonOutputSchema(output.schema);
|
|
1126
|
+
return { mode, schema };
|
|
1127
|
+
}
|
|
1128
|
+
return { mode: "string" };
|
|
1129
|
+
}
|
|
1130
|
+
var init_parse_agent_output_config = __esm(() => {
|
|
1131
|
+
init_json_schema_to_zod();
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
// src/env/workflow/utils/extract-agent-json-output.ts
|
|
1135
|
+
function extractAgentJsonOutput(agentResult, schema) {
|
|
1136
|
+
const candidates = [
|
|
1137
|
+
agentResult.structuredOutput,
|
|
1138
|
+
asRecord(agentResult.output),
|
|
1139
|
+
extractFromToolCalls(agentResult),
|
|
1140
|
+
extractFromMessages(agentResult.messages)
|
|
1141
|
+
];
|
|
1142
|
+
for (const candidate of candidates) {
|
|
1143
|
+
const validated = validateAgainstSchema(candidate, schema);
|
|
1144
|
+
if (validated) {
|
|
1145
|
+
return validated;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
function asRecord(value) {
|
|
1151
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1152
|
+
return value;
|
|
1153
|
+
}
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
function extractFromToolCalls(agentResult) {
|
|
1157
|
+
const toolCalls = agentResult.metadata?.toolCallsDetail;
|
|
1158
|
+
if (!toolCalls?.length) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
for (let i = toolCalls.length - 1;i >= 0; i--) {
|
|
1162
|
+
const tc = toolCalls[i];
|
|
1163
|
+
if (tc.name === WORKFLOW_SUBMIT_OUTPUT_TOOL_NAME && tc.arguments) {
|
|
1164
|
+
return tc.arguments;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
function extractFromMessages(messages) {
|
|
1170
|
+
if (!messages?.length) {
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
for (let i = messages.length - 1;i >= 0; i--) {
|
|
1174
|
+
const msg = messages[i];
|
|
1175
|
+
if (msg.toolName !== WORKFLOW_SUBMIT_OUTPUT_TOOL_NAME || !msg.content) {
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
const fromMarker = parseWorkflowJsonOutput(msg.content);
|
|
1179
|
+
if (fromMarker) {
|
|
1180
|
+
return fromMarker;
|
|
1181
|
+
}
|
|
1182
|
+
try {
|
|
1183
|
+
const parsed = JSON.parse(msg.content);
|
|
1184
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1185
|
+
return parsed;
|
|
1186
|
+
}
|
|
1187
|
+
} catch {}
|
|
1188
|
+
}
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
function validateAgainstSchema(data, schema) {
|
|
1192
|
+
if (!data) {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
if (!schema) {
|
|
1196
|
+
return data;
|
|
1197
|
+
}
|
|
1198
|
+
try {
|
|
1199
|
+
return jsonSchemaToZod(schema).parse(data);
|
|
1200
|
+
} catch {
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
var init_extract_agent_json_output = __esm(() => {
|
|
1205
|
+
init_submit_json_output_tool();
|
|
1206
|
+
init_json_schema_to_zod();
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
// src/env/workflow/utils/build-agent-node-output.ts
|
|
1210
|
+
function buildAgentNodeOutput(agentResult, outputConfig) {
|
|
1211
|
+
const base = {
|
|
1212
|
+
metadata: agentResult.metadata,
|
|
1213
|
+
workflowHistory: agentResult.messages
|
|
1214
|
+
};
|
|
1215
|
+
if (outputConfig.mode === "json") {
|
|
1216
|
+
const schema = outputConfig.schema;
|
|
1217
|
+
const jsonData = extractAgentJsonOutput(agentResult, schema);
|
|
1218
|
+
if (!jsonData) {
|
|
1219
|
+
throw new Error("AgentNode json output mode requires structured JSON from workflow_submit_output");
|
|
1220
|
+
}
|
|
1221
|
+
return {
|
|
1222
|
+
result: jsonData,
|
|
1223
|
+
...jsonData,
|
|
1224
|
+
metadata: {
|
|
1225
|
+
...agentResult.metadata,
|
|
1226
|
+
outputMode: "json"
|
|
1227
|
+
},
|
|
1228
|
+
workflowHistory: agentResult.messages
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
return {
|
|
1232
|
+
result: agentResult.output,
|
|
1233
|
+
...base
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
var init_build_agent_node_output = __esm(() => {
|
|
1237
|
+
init_extract_agent_json_output();
|
|
1238
|
+
});
|
|
1239
|
+
|
|
957
1240
|
// src/env/workflow/nodes/agent-node.ts
|
|
958
1241
|
var AgentNode;
|
|
959
1242
|
var init_agent_node = __esm(() => {
|
|
960
1243
|
init_workflow_hil();
|
|
961
1244
|
init_decorator();
|
|
1245
|
+
init_parse_agent_output_config();
|
|
1246
|
+
init_build_agent_node_output();
|
|
962
1247
|
AgentNode = class AgentNode {
|
|
963
1248
|
definition;
|
|
964
1249
|
agentRunner;
|
|
@@ -972,11 +1257,17 @@ var init_agent_node = __esm(() => {
|
|
|
972
1257
|
async execute(context) {
|
|
973
1258
|
const startTime = Date.now();
|
|
974
1259
|
try {
|
|
975
|
-
const config = this.definition.config
|
|
1260
|
+
const config = context.resolvedConfig ?? this.definition.config ?? {};
|
|
976
1261
|
const agentType = config.agent_type || "general";
|
|
977
|
-
const promptTemplate = config.prompt || "";
|
|
978
1262
|
const options = config.options || {};
|
|
979
|
-
const
|
|
1263
|
+
const outputConfig = parseAgentOutputConfig(config);
|
|
1264
|
+
let resolvedPrompt;
|
|
1265
|
+
if (context.resolvedConfig && context.templateResolver) {
|
|
1266
|
+
resolvedPrompt = config.prompt || "";
|
|
1267
|
+
} else {
|
|
1268
|
+
const promptTemplate = config.prompt || "";
|
|
1269
|
+
resolvedPrompt = context.templateResolver?.resolveValue(promptTemplate) ?? promptTemplate;
|
|
1270
|
+
}
|
|
980
1271
|
if (this.agentRunner.registerAgent && this.agentRunner.hasAgent) {
|
|
981
1272
|
if (!this.agentRunner.hasAgent(agentType)) {
|
|
982
1273
|
this.agentRunner.registerAgent(agentType, {
|
|
@@ -986,19 +1277,30 @@ var init_agent_node = __esm(() => {
|
|
|
986
1277
|
});
|
|
987
1278
|
}
|
|
988
1279
|
}
|
|
989
|
-
const userQuery = context.input?.userQuery;
|
|
1280
|
+
const userQuery = context.input?.userQuery ?? context.workflowInput?.userQuery;
|
|
990
1281
|
let agentSessionId = context.agentSessionId;
|
|
1282
|
+
if (!agentSessionId && context.sessionComponent) {
|
|
1283
|
+
agentSessionId = await this.resolveAgentSessionIdFromWorkflow(context);
|
|
1284
|
+
if (agentSessionId) {
|
|
1285
|
+
context.agentSessionId = agentSessionId;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
991
1288
|
if (!agentSessionId && context.sessionComponent) {
|
|
992
1289
|
agentSessionId = await this.createAgentSubSession(context);
|
|
993
1290
|
context.agentSessionId = agentSessionId;
|
|
1291
|
+
if (context.attachAgentSessionToLastStart) {
|
|
1292
|
+
await context.attachAgentSessionToLastStart(this.definition.id, agentSessionId);
|
|
1293
|
+
}
|
|
994
1294
|
}
|
|
1295
|
+
const allowedTools = ["ask_user"];
|
|
995
1296
|
const agentConfig = {
|
|
996
1297
|
type: agentType,
|
|
997
1298
|
prompt: resolvedPrompt,
|
|
998
1299
|
options: {
|
|
999
1300
|
timeout: options.timeout,
|
|
1000
1301
|
model: options.model,
|
|
1001
|
-
allowedTools
|
|
1302
|
+
allowedTools,
|
|
1303
|
+
outputSchema: outputConfig.schema
|
|
1002
1304
|
},
|
|
1003
1305
|
workflowHistory: context.workflowHistory,
|
|
1004
1306
|
nodeId: this.definition.id,
|
|
@@ -1011,11 +1313,7 @@ var init_agent_node = __esm(() => {
|
|
|
1011
1313
|
const result = await this.agentRunner.run(agentConfig, resumeOptions);
|
|
1012
1314
|
const duration = Date.now() - startTime;
|
|
1013
1315
|
return {
|
|
1014
|
-
output:
|
|
1015
|
-
result: result.output,
|
|
1016
|
-
metadata: result.metadata,
|
|
1017
|
-
workflowHistory: result.messages
|
|
1018
|
-
},
|
|
1316
|
+
output: buildAgentNodeOutput(result, outputConfig),
|
|
1019
1317
|
error: undefined,
|
|
1020
1318
|
duration
|
|
1021
1319
|
};
|
|
@@ -1036,6 +1334,18 @@ var init_agent_node = __esm(() => {
|
|
|
1036
1334
|
};
|
|
1037
1335
|
}
|
|
1038
1336
|
}
|
|
1337
|
+
async resolveAgentSessionIdFromWorkflow(context) {
|
|
1338
|
+
const sessionComponent = context.sessionComponent;
|
|
1339
|
+
if (!sessionComponent) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const workflowSession = await sessionComponent.get(context.sessionId);
|
|
1343
|
+
const agentSessions = workflowSession?.metadata?.agentSessions;
|
|
1344
|
+
if (!agentSessions?.length) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
return agentSessions.find((ref) => ref.nodeId === this.definition.id)?.sessionId;
|
|
1348
|
+
}
|
|
1039
1349
|
async createAgentSubSession(context) {
|
|
1040
1350
|
const sessionComponent = context.sessionComponent;
|
|
1041
1351
|
if (!sessionComponent) {
|
|
@@ -1082,142 +1392,9 @@ var init_agent_node = __esm(() => {
|
|
|
1082
1392
|
}
|
|
1083
1393
|
return agentSessionId;
|
|
1084
1394
|
}
|
|
1085
|
-
resolveTemplate(template, context) {
|
|
1086
|
-
if (!template) {
|
|
1087
|
-
return "";
|
|
1088
|
-
}
|
|
1089
|
-
let resolved = template;
|
|
1090
|
-
resolved = resolved.replace(/\{\{input\.([^}]+)\}\}/g, (match, path) => {
|
|
1091
|
-
let value = this.getNestedValue(context.input, path);
|
|
1092
|
-
if (value === undefined && context.workflowInput) {
|
|
1093
|
-
value = this.getNestedValue(context.workflowInput, path);
|
|
1094
|
-
}
|
|
1095
|
-
return this.stringifyValue(value, match);
|
|
1096
|
-
});
|
|
1097
|
-
resolved = resolved.replace(/\{\{inputs\.([^}]+)\}\}/g, (match, path) => {
|
|
1098
|
-
let value = this.getNestedValue(context.input, path);
|
|
1099
|
-
if (value === undefined && context.workflowInput) {
|
|
1100
|
-
value = this.getNestedValue(context.workflowInput, path);
|
|
1101
|
-
}
|
|
1102
|
-
return this.stringifyValue(value, match);
|
|
1103
|
-
});
|
|
1104
|
-
resolved = resolved.replace(/\{\{nodes\.([^}]+)\}\}/g, (match, path) => {
|
|
1105
|
-
const segments = path.split(".");
|
|
1106
|
-
const nodeId = segments[0];
|
|
1107
|
-
let nodeOutput = context.previousOutputs.get(nodeId);
|
|
1108
|
-
if (nodeOutput === undefined) {
|
|
1109
|
-
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
1110
|
-
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
1111
|
-
if (normalizedUnderscore !== nodeId) {
|
|
1112
|
-
nodeOutput = context.previousOutputs.get(normalizedUnderscore);
|
|
1113
|
-
}
|
|
1114
|
-
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
1115
|
-
nodeOutput = context.previousOutputs.get(normalizedHyphen);
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
if (nodeOutput === undefined) {
|
|
1119
|
-
return match;
|
|
1120
|
-
}
|
|
1121
|
-
nodeOutput = this.extractFromWrapper(nodeOutput);
|
|
1122
|
-
if (segments.length === 1) {
|
|
1123
|
-
return this.stringifyValue(nodeOutput, match);
|
|
1124
|
-
}
|
|
1125
|
-
let value = nodeOutput;
|
|
1126
|
-
let startIndex = 1;
|
|
1127
|
-
if (segments.length > 1 && (segments[1] === "output" || segments[1] === "result" || segments[1] === "metadata")) {
|
|
1128
|
-
startIndex = 2;
|
|
1129
|
-
}
|
|
1130
|
-
for (let i = startIndex;i < segments.length; i++) {
|
|
1131
|
-
if (value === null || value === undefined) {
|
|
1132
|
-
return match;
|
|
1133
|
-
}
|
|
1134
|
-
value = value[segments[i]];
|
|
1135
|
-
}
|
|
1136
|
-
return this.stringifyValue(value, match);
|
|
1137
|
-
});
|
|
1138
|
-
resolved = resolved.replace(/\{\{([^}]+)\}\}/g, (match, path) => {
|
|
1139
|
-
if (path.startsWith("input.") || path.startsWith("nodes.")) {
|
|
1140
|
-
return match;
|
|
1141
|
-
}
|
|
1142
|
-
const segments = path.split(".");
|
|
1143
|
-
const nodeId = segments[0];
|
|
1144
|
-
let nodeOutput = context.previousOutputs.get(nodeId);
|
|
1145
|
-
if (nodeOutput === undefined) {
|
|
1146
|
-
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
1147
|
-
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
1148
|
-
if (normalizedUnderscore !== nodeId) {
|
|
1149
|
-
nodeOutput = context.previousOutputs.get(normalizedUnderscore);
|
|
1150
|
-
}
|
|
1151
|
-
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
1152
|
-
nodeOutput = context.previousOutputs.get(normalizedHyphen);
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
if (nodeOutput === undefined) {
|
|
1156
|
-
return match;
|
|
1157
|
-
}
|
|
1158
|
-
nodeOutput = this.extractFromWrapper(nodeOutput);
|
|
1159
|
-
if (segments.length === 1) {
|
|
1160
|
-
return this.stringifyValue(nodeOutput, match);
|
|
1161
|
-
}
|
|
1162
|
-
let value = nodeOutput;
|
|
1163
|
-
let startIndex = 1;
|
|
1164
|
-
if (segments.length > 1 && (segments[1] === "output" || segments[1] === "result" || segments[1] === "metadata")) {
|
|
1165
|
-
startIndex = 2;
|
|
1166
|
-
}
|
|
1167
|
-
for (let i = startIndex;i < segments.length; i++) {
|
|
1168
|
-
if (value === null || value === undefined) {
|
|
1169
|
-
return match;
|
|
1170
|
-
}
|
|
1171
|
-
value = value[segments[i]];
|
|
1172
|
-
}
|
|
1173
|
-
return this.stringifyValue(value, match);
|
|
1174
|
-
});
|
|
1175
|
-
return resolved;
|
|
1176
|
-
}
|
|
1177
|
-
stringifyValue(value, originalTemplate) {
|
|
1178
|
-
if (value === undefined) {
|
|
1179
|
-
return originalTemplate;
|
|
1180
|
-
}
|
|
1181
|
-
if (value === null) {
|
|
1182
|
-
return "null";
|
|
1183
|
-
}
|
|
1184
|
-
if (typeof value === "string") {
|
|
1185
|
-
return value;
|
|
1186
|
-
}
|
|
1187
|
-
return JSON.stringify(value);
|
|
1188
|
-
}
|
|
1189
|
-
extractFromWrapper(value) {
|
|
1190
|
-
if (value === null || value === undefined) {
|
|
1191
|
-
return value;
|
|
1192
|
-
}
|
|
1193
|
-
if (typeof value !== "object") {
|
|
1194
|
-
return value;
|
|
1195
|
-
}
|
|
1196
|
-
if ("result" in value && "metadata" in value) {
|
|
1197
|
-
return value.result;
|
|
1198
|
-
}
|
|
1199
|
-
if ("output" in value) {
|
|
1200
|
-
return value.output;
|
|
1201
|
-
}
|
|
1202
|
-
return value;
|
|
1203
|
-
}
|
|
1204
|
-
getNestedValue(obj, path) {
|
|
1205
|
-
if (!obj) {
|
|
1206
|
-
return;
|
|
1207
|
-
}
|
|
1208
|
-
if ("input" in obj && path in obj["input"]) {
|
|
1209
|
-
return obj["input"][path];
|
|
1210
|
-
}
|
|
1211
|
-
return path.split(".").reduce((current, key) => {
|
|
1212
|
-
if (current && typeof current === "object") {
|
|
1213
|
-
return current[key];
|
|
1214
|
-
}
|
|
1215
|
-
return;
|
|
1216
|
-
}, obj);
|
|
1217
|
-
}
|
|
1218
1395
|
};
|
|
1219
1396
|
__legacyDecorateClassTS([
|
|
1220
|
-
TracedAs("agent.
|
|
1397
|
+
TracedAs("workflow.agent.execute", { log: true })
|
|
1221
1398
|
], AgentNode.prototype, "execute", null);
|
|
1222
1399
|
__legacyDecorateClassTS([
|
|
1223
1400
|
TracedAs("agent.node.createAgentSubSession", { recordParams: true, recordResult: true, log: true })
|
|
@@ -1226,16 +1403,17 @@ var init_agent_node = __esm(() => {
|
|
|
1226
1403
|
|
|
1227
1404
|
// src/env/workflow/nodes/ask-user-node.ts
|
|
1228
1405
|
class AskUserNode {
|
|
1406
|
+
definition;
|
|
1229
1407
|
type = "ask_user";
|
|
1230
1408
|
id;
|
|
1231
|
-
config;
|
|
1232
1409
|
constructor(definition) {
|
|
1410
|
+
this.definition = definition;
|
|
1233
1411
|
this.id = definition.id;
|
|
1234
|
-
this.config = definition.config || {};
|
|
1235
1412
|
}
|
|
1236
1413
|
async execute(context) {
|
|
1237
|
-
const
|
|
1238
|
-
const
|
|
1414
|
+
const config = context.resolvedConfig ?? this.definition.config ?? {};
|
|
1415
|
+
const query = config.query || "确认继续吗?";
|
|
1416
|
+
const options = config.options;
|
|
1239
1417
|
const fullQuery = options ? `${query} (选项: ${options.join(", ")})` : query;
|
|
1240
1418
|
await context.eventBus.publish(createNodeInterruptEvent(context.runId, this.id, this.type, fullQuery));
|
|
1241
1419
|
throw new AskUserError(context.runId, context.sessionId, this.id, this.type, query);
|
|
@@ -1264,7 +1442,8 @@ class NodeRegistry {
|
|
|
1264
1442
|
agentComponent,
|
|
1265
1443
|
agentRunner,
|
|
1266
1444
|
workflowRunner,
|
|
1267
|
-
sessionComponent
|
|
1445
|
+
sessionComponent,
|
|
1446
|
+
llmComponent
|
|
1268
1447
|
} = options ?? {};
|
|
1269
1448
|
this.toolRegistry = toolRegistry;
|
|
1270
1449
|
this.skillRegistry = skillRegistry;
|
|
@@ -1275,8 +1454,11 @@ class NodeRegistry {
|
|
|
1275
1454
|
if (agentRunner.setSessionComponent && sessionComponent) {
|
|
1276
1455
|
agentRunner.setSessionComponent(sessionComponent);
|
|
1277
1456
|
}
|
|
1457
|
+
if (llmComponent && "setLLMComponent" in agentRunner && typeof agentRunner.setLLMComponent === "function") {
|
|
1458
|
+
agentRunner.setLLMComponent(llmComponent);
|
|
1459
|
+
}
|
|
1278
1460
|
} else if (agentComponent) {
|
|
1279
|
-
this.agentComponentAdapter = new AgentComponentAdapter(agentComponent, {}, sessionComponent);
|
|
1461
|
+
this.agentComponentAdapter = new AgentComponentAdapter(agentComponent, {}, sessionComponent, llmComponent);
|
|
1280
1462
|
this.agentRunner = this.agentComponentAdapter;
|
|
1281
1463
|
}
|
|
1282
1464
|
this.registerBuiltInTypes();
|
|
@@ -1346,9 +1528,24 @@ var init_node_registry = __esm(() => {
|
|
|
1346
1528
|
init_ask_user_node();
|
|
1347
1529
|
});
|
|
1348
1530
|
|
|
1531
|
+
// src/env/workflow/utils/agent-session-metadata.ts
|
|
1532
|
+
function updateAgentSessionStatus(agentSessions, nodeId, status) {
|
|
1533
|
+
if (!agentSessions?.length) {
|
|
1534
|
+
return agentSessions ?? [];
|
|
1535
|
+
}
|
|
1536
|
+
return agentSessions.map((ref) => ref.nodeId === nodeId ? { ...ref, status } : ref);
|
|
1537
|
+
}
|
|
1538
|
+
function markAllAgentSessionsCompleted(agentSessions) {
|
|
1539
|
+
if (!agentSessions?.length) {
|
|
1540
|
+
return agentSessions ?? [];
|
|
1541
|
+
}
|
|
1542
|
+
return agentSessions.map((ref) => ref.status === "active" || ref.status === "paused" ? { ...ref, status: "completed" } : ref);
|
|
1543
|
+
}
|
|
1544
|
+
var init_agent_session_metadata = () => {};
|
|
1545
|
+
|
|
1349
1546
|
// src/env/workflow/engine/engine.ts
|
|
1350
1547
|
import { EventEmitter } from "events";
|
|
1351
|
-
var
|
|
1548
|
+
var logger2, WorkflowEngine;
|
|
1352
1549
|
var init_engine = __esm(() => {
|
|
1353
1550
|
init_event();
|
|
1354
1551
|
init_workflow_hil();
|
|
@@ -1357,9 +1554,12 @@ var init_engine = __esm(() => {
|
|
|
1357
1554
|
init_scheduler();
|
|
1358
1555
|
init_executor();
|
|
1359
1556
|
init_node_registry();
|
|
1557
|
+
init_agent_session_metadata();
|
|
1360
1558
|
init_logger();
|
|
1361
1559
|
init_decorator();
|
|
1362
|
-
|
|
1560
|
+
init_template_resolver();
|
|
1561
|
+
init_workflow_error();
|
|
1562
|
+
logger2 = createLogger("workflow:engine");
|
|
1363
1563
|
WorkflowEngine = class WorkflowEngine extends EventEmitter {
|
|
1364
1564
|
activeSessions = new Map;
|
|
1365
1565
|
sessionIdCounter = 0;
|
|
@@ -1375,10 +1575,12 @@ var init_engine = __esm(() => {
|
|
|
1375
1575
|
static async create(options) {
|
|
1376
1576
|
const agentComponent = options.env?.getComponent("agent");
|
|
1377
1577
|
const sessionComponent = options.sessionComponent;
|
|
1578
|
+
const llmComponent = options.env?.getComponent("llm");
|
|
1378
1579
|
const nodeRegistry = new NodeRegistry({
|
|
1379
1580
|
toolRegistry: options.toolRegistry,
|
|
1380
1581
|
skillRegistry: options.skillRegistry,
|
|
1381
1582
|
agentComponent,
|
|
1583
|
+
llmComponent,
|
|
1382
1584
|
workflowRunner: options.workflowRunner,
|
|
1383
1585
|
sessionComponent
|
|
1384
1586
|
});
|
|
@@ -1406,6 +1608,8 @@ var init_engine = __esm(() => {
|
|
|
1406
1608
|
workflowName,
|
|
1407
1609
|
workflowVersion: definition.version,
|
|
1408
1610
|
status: "running",
|
|
1611
|
+
runId,
|
|
1612
|
+
startedAt: Date.now(),
|
|
1409
1613
|
input: options?.input,
|
|
1410
1614
|
agentSessions: []
|
|
1411
1615
|
};
|
|
@@ -1416,7 +1620,7 @@ var init_engine = __esm(() => {
|
|
|
1416
1620
|
metadata
|
|
1417
1621
|
});
|
|
1418
1622
|
}
|
|
1419
|
-
|
|
1623
|
+
logger2.info(`[WorkflowEngine] Created session: ${sessionId}`);
|
|
1420
1624
|
return sessionId;
|
|
1421
1625
|
}
|
|
1422
1626
|
async run(sessionId, options) {
|
|
@@ -1486,24 +1690,32 @@ var init_engine = __esm(() => {
|
|
|
1486
1690
|
}
|
|
1487
1691
|
});
|
|
1488
1692
|
metadata.input = { ...existingInput, ...newInput };
|
|
1489
|
-
|
|
1693
|
+
logger2.info(`[WorkflowEngine] Updated session ${sessionId} input with resume user input`);
|
|
1490
1694
|
}
|
|
1491
1695
|
}
|
|
1492
1696
|
const messages = this.sessionComponent ? await this.sessionComponent.getMessages(sessionId) : [];
|
|
1493
|
-
const {
|
|
1697
|
+
const {
|
|
1698
|
+
inferNextNode,
|
|
1699
|
+
extractResumeInfo,
|
|
1700
|
+
enrichResumeInfoWithAgentSessions,
|
|
1701
|
+
enrichResumePointWithAgentSessions
|
|
1702
|
+
} = await import("./roy-agent-core-2vhsccvz.js");
|
|
1494
1703
|
const entry = workflowDef.entry;
|
|
1495
1704
|
const entryNode = Array.isArray(entry) ? entry[0] : entry;
|
|
1496
|
-
const
|
|
1705
|
+
const agentSessions = metadata.agentSessions ?? [];
|
|
1706
|
+
const resumeInfo = enrichResumeInfoWithAgentSessions(extractResumeInfo(messages), agentSessions);
|
|
1707
|
+
const resumePoint = enrichResumePointWithAgentSessions(inferNextNode(messages, {
|
|
1497
1708
|
entryNode: entryNode !== "__default_entry__" ? entryNode : undefined,
|
|
1498
1709
|
edges: undefined
|
|
1499
|
-
});
|
|
1710
|
+
}), agentSessions);
|
|
1500
1711
|
const sessionState = await this.initializeSessionState(sessionId, workflowDef, workflowId, workflowName, options);
|
|
1501
1712
|
this.activeSessions.set(sessionId, sessionState);
|
|
1502
|
-
return this.runWithResume(sessionId, resumePoint, options);
|
|
1713
|
+
return this.runWithResume(sessionId, resumePoint, resumeInfo, options);
|
|
1503
1714
|
}
|
|
1504
1715
|
async initializeSessionState(sessionId, definition, workflowId, workflowName, options) {
|
|
1505
|
-
const
|
|
1506
|
-
const
|
|
1716
|
+
const loopEnabled = options?.loopEnabled ?? definition.config?.loopEnabled ?? false;
|
|
1717
|
+
const dagManager = new DAGManager(definition, { allowCycles: loopEnabled });
|
|
1718
|
+
const validation = dagManager.validate({ skipCycleCheck: loopEnabled });
|
|
1507
1719
|
if (!validation.valid) {
|
|
1508
1720
|
throw new Error(`Invalid workflow: ${validation.errors.join(", ")}`);
|
|
1509
1721
|
}
|
|
@@ -1516,10 +1728,28 @@ var init_engine = __esm(() => {
|
|
|
1516
1728
|
debug: options?.debug ?? definition.config?.debug ?? false
|
|
1517
1729
|
};
|
|
1518
1730
|
const executor = new Executor(this.nodeRegistry, eventBus, executorOptions, this.sessionComponent);
|
|
1731
|
+
const rawRuntimeInput = options?.workflowInput ?? options?.input;
|
|
1732
|
+
let persistedInput = {};
|
|
1733
|
+
if (this.sessionComponent) {
|
|
1734
|
+
const existingSession = await this.sessionComponent.get(sessionId);
|
|
1735
|
+
const metaInput = existingSession?.metadata?.input;
|
|
1736
|
+
if (metaInput) {
|
|
1737
|
+
const { userQuery: _omit, ...rest } = metaInput;
|
|
1738
|
+
persistedInput = rest;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
const { stripEphemeralResumeInput } = await import("./roy-agent-core-2vhsccvz.js");
|
|
1742
|
+
const { workflowInput: runtimeInput } = stripEphemeralResumeInput(rawRuntimeInput);
|
|
1743
|
+
const mergedWorkflowInput = { ...persistedInput, ...runtimeInput };
|
|
1744
|
+
const workflowInput = Object.keys(mergedWorkflowInput).length > 0 ? mergedWorkflowInput : undefined;
|
|
1519
1745
|
const config = {
|
|
1520
1746
|
parallelLimit,
|
|
1521
1747
|
timeout: options?.timeout ?? definition.config?.timeout ?? null,
|
|
1522
|
-
debug: options?.debug ?? definition.config?.debug ?? false
|
|
1748
|
+
debug: options?.debug ?? definition.config?.debug ?? false,
|
|
1749
|
+
strict: options?.strict ?? definition.config?.strict ?? false,
|
|
1750
|
+
maxIterations: options?.maxIterations ?? definition.config?.maxIterations ?? 100,
|
|
1751
|
+
loopEnabled,
|
|
1752
|
+
workflowInput
|
|
1523
1753
|
};
|
|
1524
1754
|
const abortController = new AbortController;
|
|
1525
1755
|
let resolveCompleted;
|
|
@@ -1546,12 +1776,14 @@ var init_engine = __esm(() => {
|
|
|
1546
1776
|
resolveCompleted,
|
|
1547
1777
|
rejectCompleted,
|
|
1548
1778
|
workflowHistory: [],
|
|
1549
|
-
agentSessions: new Map
|
|
1779
|
+
agentSessions: new Map,
|
|
1780
|
+
edges: dagManager.buildEdges(definition.edges || []),
|
|
1781
|
+
loopIterationCount: 0
|
|
1550
1782
|
};
|
|
1551
1783
|
this.setupEventHandlers(sessionState);
|
|
1552
1784
|
return sessionState;
|
|
1553
1785
|
}
|
|
1554
|
-
async runWithResume(sessionId, resumePoint, options) {
|
|
1786
|
+
async runWithResume(sessionId, resumePoint, resumeInfo, options) {
|
|
1555
1787
|
const sessionState = this.activeSessions.get(sessionId);
|
|
1556
1788
|
if (!sessionState) {
|
|
1557
1789
|
throw new Error(`Session not found: ${sessionId}`);
|
|
@@ -1580,12 +1812,17 @@ var init_engine = __esm(() => {
|
|
|
1580
1812
|
} else if (options?.input && typeof options.input === "object") {
|
|
1581
1813
|
inputForExecution = options.input;
|
|
1582
1814
|
}
|
|
1815
|
+
if (resumeInfo?.nodeOutputs) {
|
|
1816
|
+
const completedNodeIds = Array.from(resumeInfo.nodeOutputs.keys());
|
|
1817
|
+
sessionState.scheduler.markCompletedFromRestore(completedNodeIds);
|
|
1818
|
+
}
|
|
1583
1819
|
this.scheduleAndExecute(sessionState, {
|
|
1584
1820
|
input: inputForExecution,
|
|
1585
1821
|
pendingNodeId,
|
|
1586
|
-
agentSessionId
|
|
1822
|
+
agentSessionId,
|
|
1823
|
+
restoredOutputs: resumeInfo?.nodeOutputs
|
|
1587
1824
|
}).catch((error) => {
|
|
1588
|
-
|
|
1825
|
+
logger2.error(`Workflow ${sessionId} scheduling error:`, error);
|
|
1589
1826
|
this.failWorkflow(sessionState, error);
|
|
1590
1827
|
});
|
|
1591
1828
|
if (options?.sync !== false) {
|
|
@@ -1600,7 +1837,7 @@ var init_engine = __esm(() => {
|
|
|
1600
1837
|
const sessionId = await this.createSession(workflow, options);
|
|
1601
1838
|
const sessionState = await this.initializeSessionState(sessionId, definition, workflowId, workflowName, options);
|
|
1602
1839
|
this.activeSessions.set(sessionId, sessionState);
|
|
1603
|
-
return this.runWithResume(sessionId, { type: "entry_node" }, options);
|
|
1840
|
+
return this.runWithResume(sessionId, { type: "entry_node" }, undefined, options);
|
|
1604
1841
|
}
|
|
1605
1842
|
async pause(sessionId) {
|
|
1606
1843
|
const sessionState = this.activeSessions.get(sessionId);
|
|
@@ -1620,7 +1857,7 @@ var init_engine = __esm(() => {
|
|
|
1620
1857
|
});
|
|
1621
1858
|
}
|
|
1622
1859
|
await sessionState.eventBus.publish(createWorkflowEvent("workflow.paused", this.getRunIdFromSessionId(sessionId), {}));
|
|
1623
|
-
|
|
1860
|
+
logger2.info(`[WorkflowEngine] Workflow paused: ${sessionId}`);
|
|
1624
1861
|
}
|
|
1625
1862
|
async stop(sessionId, reason) {
|
|
1626
1863
|
const sessionState = this.activeSessions.get(sessionId);
|
|
@@ -1659,15 +1896,12 @@ var init_engine = __esm(() => {
|
|
|
1659
1896
|
eventBus.on("node.completed", async (event) => {
|
|
1660
1897
|
if (event.type !== "node.completed")
|
|
1661
1898
|
return;
|
|
1662
|
-
sessionState.nodeOutputs.set(event.node_id, event.output);
|
|
1663
|
-
scheduler.markCompleted(event.node_id);
|
|
1664
1899
|
if (event.output && typeof event.output === "object" && "workflowHistory" in event.output) {
|
|
1665
1900
|
const messages = event.output.workflowHistory;
|
|
1666
1901
|
if (Array.isArray(messages)) {
|
|
1667
1902
|
sessionState.workflowHistory.push(...messages);
|
|
1668
1903
|
}
|
|
1669
1904
|
}
|
|
1670
|
-
this.checkAndFinalize(sessionState);
|
|
1671
1905
|
});
|
|
1672
1906
|
eventBus.on("node.failed", async (event) => {
|
|
1673
1907
|
if (event.type !== "node.failed")
|
|
@@ -1678,20 +1912,27 @@ var init_engine = __esm(() => {
|
|
|
1678
1912
|
eventBus.on("node.interrupt", async (event) => {
|
|
1679
1913
|
if (event.type !== "node.interrupt")
|
|
1680
1914
|
return;
|
|
1681
|
-
|
|
1915
|
+
logger2.info(`Workflow paused at node "${event.node_id}" - ask_user pending`);
|
|
1682
1916
|
sessionState.status = "paused";
|
|
1683
1917
|
sessionState.abortController.abort();
|
|
1684
1918
|
if (this.sessionComponent) {
|
|
1685
1919
|
const metadata = await this.getSessionMetadata(sessionId);
|
|
1920
|
+
const agentSessions = updateAgentSessionStatus(metadata.agentSessions, event.node_id, "paused");
|
|
1686
1921
|
await this.sessionComponent.update(sessionId, {
|
|
1687
|
-
metadata: {
|
|
1922
|
+
metadata: {
|
|
1923
|
+
...metadata,
|
|
1924
|
+
status: "paused",
|
|
1925
|
+
pendingNodeId: event.node_id,
|
|
1926
|
+
pauseReason: "ask_user",
|
|
1927
|
+
agentSessions
|
|
1928
|
+
}
|
|
1688
1929
|
});
|
|
1689
1930
|
}
|
|
1690
1931
|
await eventBus.publish(createWorkflowEvent("workflow.paused", runId, {
|
|
1691
1932
|
pendingNodeId: event.node_id,
|
|
1692
1933
|
query: event.query
|
|
1693
1934
|
}));
|
|
1694
|
-
await
|
|
1935
|
+
await sessionState.executor.writeNodeInterrupt(sessionId, event.node_id, event.node_type, event.query, event.agent_session_id);
|
|
1695
1936
|
sessionState.resolveCompleted({
|
|
1696
1937
|
runId,
|
|
1697
1938
|
status: "paused",
|
|
@@ -1701,25 +1942,19 @@ var init_engine = __esm(() => {
|
|
|
1701
1942
|
});
|
|
1702
1943
|
});
|
|
1703
1944
|
}
|
|
1704
|
-
async writeNodeInterrupt(sessionId, nodeId, nodeType, query, agentSessionId) {
|
|
1705
|
-
if (this.sessionComponent) {
|
|
1706
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
1707
|
-
role: "workflow.node.interrupt",
|
|
1708
|
-
content: query,
|
|
1709
|
-
metadata: {
|
|
1710
|
-
type: "workflow.node.interrupt",
|
|
1711
|
-
workflowNodeId: nodeId,
|
|
1712
|
-
workflowNodeType: nodeType,
|
|
1713
|
-
query,
|
|
1714
|
-
agentSessionId,
|
|
1715
|
-
timestamp: Date.now()
|
|
1716
|
-
}
|
|
1717
|
-
});
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
1945
|
async scheduleAndExecute(sessionState, options) {
|
|
1721
1946
|
const { scheduler, executor, eventBus, abortController, nodeOutputs } = sessionState;
|
|
1722
1947
|
const { input: globalInput, pendingNodeId, agentSessionId, restoredOutputs } = options || {};
|
|
1948
|
+
const { stripEphemeralResumeInput } = await import("./roy-agent-core-2vhsccvz.js");
|
|
1949
|
+
const { workflowInput: inputToPersist, userQuery: resumeUserQuery } = stripEphemeralResumeInput(globalInput);
|
|
1950
|
+
if (inputToPersist) {
|
|
1951
|
+
sessionState.config.workflowInput = {
|
|
1952
|
+
...sessionState.config.workflowInput || {},
|
|
1953
|
+
...inputToPersist
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1956
|
+
sessionState.loopIterationCount = 0;
|
|
1957
|
+
const maxIterations = sessionState.config.maxIterations;
|
|
1723
1958
|
if (restoredOutputs) {
|
|
1724
1959
|
for (const [nodeId, output] of restoredOutputs) {
|
|
1725
1960
|
nodeOutputs.set(nodeId, output);
|
|
@@ -1739,7 +1974,7 @@ var init_engine = __esm(() => {
|
|
|
1739
1974
|
break;
|
|
1740
1975
|
if (scheduled >= (sessionState.config.parallelLimit ?? Infinity))
|
|
1741
1976
|
break;
|
|
1742
|
-
await this.startNode(sessionState, nodeId,
|
|
1977
|
+
await this.startNode(sessionState, nodeId, sessionState.config.workflowInput);
|
|
1743
1978
|
scheduled++;
|
|
1744
1979
|
}
|
|
1745
1980
|
return true;
|
|
@@ -1747,7 +1982,7 @@ var init_engine = __esm(() => {
|
|
|
1747
1982
|
if (pendingNodeId) {
|
|
1748
1983
|
await this.resumeNode(sessionState, pendingNodeId, {
|
|
1749
1984
|
agentSessionId,
|
|
1750
|
-
userQuery:
|
|
1985
|
+
userQuery: resumeUserQuery
|
|
1751
1986
|
});
|
|
1752
1987
|
} else {
|
|
1753
1988
|
await scheduleAvailableNodes();
|
|
@@ -1757,6 +1992,12 @@ var init_engine = __esm(() => {
|
|
|
1757
1992
|
if (state.pending.length === 0 && state.running.length === 0) {
|
|
1758
1993
|
break;
|
|
1759
1994
|
}
|
|
1995
|
+
if (sessionState.config.loopEnabled && sessionState.loopIterationCount >= maxIterations) {
|
|
1996
|
+
logger2.error(`[WorkflowEngine] Max loop iterations ${maxIterations} exceeded`);
|
|
1997
|
+
sessionState.rejectCompleted(new WorkflowError(`Workflow exceeded maximum loop iterations: ${maxIterations}`));
|
|
1998
|
+
await this.stop(sessionState.sessionId, "Max iterations exceeded");
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
1760
2001
|
try {
|
|
1761
2002
|
await this.waitForNextNodeEvent(sessionState, abortController.signal);
|
|
1762
2003
|
} catch {
|
|
@@ -1809,15 +2050,8 @@ var init_engine = __esm(() => {
|
|
|
1809
2050
|
scheduler.markFailed(nodeId);
|
|
1810
2051
|
return;
|
|
1811
2052
|
}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
executor.executeNode(nodeDef, context).catch(async (error) => {
|
|
1815
|
-
if (error instanceof AskUserError) {
|
|
1816
|
-
await eventBus.publish(createNodeInterruptEvent(runId, nodeId, nodeDef.type, error.query, error.agentSessionId));
|
|
1817
|
-
return;
|
|
1818
|
-
}
|
|
1819
|
-
scheduler.markFailed(nodeId);
|
|
1820
|
-
});
|
|
2053
|
+
const context = this.buildNodeContext(sessionState, nodeId, input);
|
|
2054
|
+
await this.validateAndExecute(nodeDef, context, sessionState);
|
|
1821
2055
|
}
|
|
1822
2056
|
async writeNodeStart(sessionId, nodeId, nodeType, input) {
|
|
1823
2057
|
if (this.sessionComponent) {
|
|
@@ -1833,66 +2067,143 @@ var init_engine = __esm(() => {
|
|
|
1833
2067
|
});
|
|
1834
2068
|
}
|
|
1835
2069
|
}
|
|
1836
|
-
async writeNodeResume(sessionId, nodeId, userResponse) {
|
|
1837
|
-
if (this.sessionComponent && userResponse) {
|
|
1838
|
-
await this.sessionComponent.addMessage(sessionId, {
|
|
1839
|
-
role: "workflow.node.resume",
|
|
1840
|
-
content: JSON.stringify({ userResponse }),
|
|
1841
|
-
metadata: {
|
|
1842
|
-
type: "workflow.node.resume",
|
|
1843
|
-
workflowNodeId: nodeId,
|
|
1844
|
-
timestamp: Date.now()
|
|
1845
|
-
}
|
|
1846
|
-
});
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
2070
|
async resumeNode(sessionState, nodeId, options) {
|
|
1850
2071
|
const { scheduler, executor, eventBus, dagManager } = sessionState;
|
|
1851
2072
|
const sessionId = sessionState.sessionId;
|
|
1852
2073
|
const runId = this.getRunIdFromSessionId(sessionId);
|
|
1853
2074
|
scheduler.markStarted(nodeId);
|
|
1854
|
-
|
|
2075
|
+
const nodeDef = dagManager.getNode(nodeId);
|
|
2076
|
+
if (!nodeDef) {
|
|
2077
|
+
scheduler.markFailed(nodeId);
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
let agentSessionId = options?.agentSessionId;
|
|
2081
|
+
if (!agentSessionId && this.sessionComponent) {
|
|
2082
|
+
const session = await this.sessionComponent.get(sessionId);
|
|
2083
|
+
const agentSessions = session?.metadata?.agentSessions;
|
|
2084
|
+
const { resolveAgentSessionId } = await import("./roy-agent-core-2vhsccvz.js");
|
|
2085
|
+
agentSessionId = resolveAgentSessionId(nodeId, undefined, agentSessions);
|
|
2086
|
+
}
|
|
2087
|
+
await sessionState.executor.writeNodeResume(sessionId, nodeId, nodeDef.type, options?.userQuery ?? "", agentSessionId);
|
|
1855
2088
|
await eventBus.publish(createWorkflowEvent("node.started", runId, {
|
|
1856
2089
|
node_id: nodeId,
|
|
1857
|
-
agentSessionId
|
|
2090
|
+
agentSessionId,
|
|
1858
2091
|
userQuery: options?.userQuery
|
|
1859
2092
|
}));
|
|
1860
|
-
const
|
|
2093
|
+
const context = this.buildNodeContext(sessionState, nodeId, sessionState.config.workflowInput);
|
|
2094
|
+
if (options?.userQuery !== undefined) {
|
|
2095
|
+
context.input.userQuery = options.userQuery;
|
|
2096
|
+
}
|
|
2097
|
+
if (agentSessionId) {
|
|
2098
|
+
context.agentSessionId = agentSessionId;
|
|
2099
|
+
}
|
|
2100
|
+
await this.validateAndExecute(nodeDef, context, sessionState);
|
|
2101
|
+
}
|
|
2102
|
+
async preExecuteValidation(nodeId, nodeDef, context, options) {
|
|
1861
2103
|
if (!nodeDef) {
|
|
1862
|
-
|
|
2104
|
+
logger2.warn(`Node ${nodeId} has no configuration`);
|
|
1863
2105
|
return;
|
|
1864
2106
|
}
|
|
1865
|
-
const
|
|
1866
|
-
if (
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
};
|
|
1879
|
-
try {
|
|
1880
|
-
await agentAdapter.resumeAgent(options.agentSessionId, options.userQuery || "", agentConfig);
|
|
1881
|
-
} catch (error) {
|
|
1882
|
-
console.error(`Failed to resume agent node ${nodeId}:`, error);
|
|
2107
|
+
const config = nodeDef.config || {};
|
|
2108
|
+
if (context.debug) {
|
|
2109
|
+
logger2.debug(`Pre-execute validation for node ${nodeId}`, {
|
|
2110
|
+
workflowInput: context.workflowInput,
|
|
2111
|
+
previousOutputs: Array.from(context.previousOutputs.keys()),
|
|
2112
|
+
hasTemplateResolver: !!context.templateResolver
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
if (context.templateResolver) {
|
|
2116
|
+
const { unresolved } = context.templateResolver.resolveAndValidate(config);
|
|
2117
|
+
if (unresolved.length > 0) {
|
|
2118
|
+
if (options?.strict) {
|
|
2119
|
+
context.templateResolver.resolveStrict(config, nodeId);
|
|
1883
2120
|
}
|
|
2121
|
+
logger2.warn(`[WorkflowEngine] Node "${nodeId}" has unresolved templates:`, unresolved);
|
|
1884
2122
|
}
|
|
1885
2123
|
}
|
|
1886
|
-
|
|
2124
|
+
}
|
|
2125
|
+
async validateAndExecute(nodeDef, context, sessionState) {
|
|
2126
|
+
const { scheduler, executor, eventBus } = sessionState;
|
|
2127
|
+
const { nodeId } = context;
|
|
2128
|
+
const strictMode = sessionState.config?.strict ?? false;
|
|
2129
|
+
try {
|
|
2130
|
+
await this.preExecuteValidation(nodeId, nodeDef, context, { strict: strictMode });
|
|
2131
|
+
} catch (err) {
|
|
2132
|
+
logger2.error(`[WorkflowEngine] Strict validation failed for node ${nodeId}:`, err);
|
|
2133
|
+
scheduler.markFailed(nodeId);
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
try {
|
|
2137
|
+
const result = await executor.executeNode(nodeDef, context);
|
|
2138
|
+
if (result.error) {
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
sessionState.nodeOutputs.set(nodeId, result.output);
|
|
2142
|
+
scheduler.markCompleted(nodeId);
|
|
2143
|
+
if (result.output && typeof result.output === "object" && "workflowHistory" in result.output) {
|
|
2144
|
+
const messages = result.output.workflowHistory;
|
|
2145
|
+
if (Array.isArray(messages)) {
|
|
2146
|
+
sessionState.workflowHistory.push(...messages);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
await this.processConditionalEdgesAfterCompletion(sessionState, nodeId);
|
|
2150
|
+
this.checkAndFinalize(sessionState);
|
|
2151
|
+
} catch (error) {
|
|
1887
2152
|
if (error instanceof AskUserError) {
|
|
1888
|
-
|
|
1889
|
-
eventBus.publish(event);
|
|
2153
|
+
await eventBus.publish(createNodeInterruptEvent(context.runId, nodeId, nodeDef.type, error.query, error.agentSessionId));
|
|
1890
2154
|
return;
|
|
1891
2155
|
}
|
|
1892
2156
|
scheduler.markFailed(nodeId);
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
async processConditionalEdgesAfterCompletion(sessionState, completedNodeId) {
|
|
2160
|
+
if (!sessionState.edges || sessionState.edges.length === 0) {
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
const { scheduler, eventBus } = sessionState;
|
|
2164
|
+
const runId = this.getRunIdFromSessionId(sessionState.sessionId);
|
|
2165
|
+
const templateResolver = new TemplateResolver({
|
|
2166
|
+
input: sessionState.config.workflowInput || {},
|
|
2167
|
+
previousOutputs: new Map(sessionState.nodeOutputs)
|
|
1893
2168
|
});
|
|
2169
|
+
logger2.debug(`[WorkflowEngine] Processing edges after "${completedNodeId}" completed. edges=${JSON.stringify(sessionState.edges)}`);
|
|
2170
|
+
const edgeResult = scheduler.processEdgesAfterCompletion(completedNodeId, sessionState.edges, templateResolver, sessionState.config.loopEnabled);
|
|
2171
|
+
logger2.debug(`[WorkflowEngine] Edge processing result: ${JSON.stringify(edgeResult)}`);
|
|
2172
|
+
for (const nodeId of edgeResult.resetNodes) {
|
|
2173
|
+
sessionState.nodeOutputs.delete(nodeId);
|
|
2174
|
+
}
|
|
2175
|
+
for (const { nodeId, reason } of edgeResult.skipped) {
|
|
2176
|
+
await eventBus.publish(createWorkflowEvent("node.skipped", runId, {
|
|
2177
|
+
node_id: nodeId,
|
|
2178
|
+
reason
|
|
2179
|
+
}));
|
|
2180
|
+
}
|
|
2181
|
+
if (edgeResult.reEntries.length > 0) {
|
|
2182
|
+
if (sessionState.config.loopEnabled) {
|
|
2183
|
+
const nextCount = sessionState.loopIterationCount + edgeResult.reEntries.length;
|
|
2184
|
+
if (nextCount > sessionState.config.maxIterations) {
|
|
2185
|
+
logger2.error(`[WorkflowEngine] Max loop iterations ${sessionState.config.maxIterations} exceeded (next=${nextCount})`);
|
|
2186
|
+
await this.failWorkflow(sessionState, new WorkflowError(`Workflow exceeded maximum loop iterations: ${sessionState.config.maxIterations}`));
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
sessionState.loopIterationCount = nextCount;
|
|
2190
|
+
} else {
|
|
2191
|
+
sessionState.loopIterationCount += edgeResult.reEntries.length;
|
|
2192
|
+
}
|
|
2193
|
+
logger2.debug(`[WorkflowEngine] Loop iteration #${sessionState.loopIterationCount}: re-entering ${edgeResult.reEntries.join(", ")}`);
|
|
2194
|
+
}
|
|
2195
|
+
const workflowInput = sessionState.config.workflowInput || {};
|
|
2196
|
+
for (const targetId of edgeResult.toStart) {
|
|
2197
|
+
if (targetId === "__end__" || targetId === "__END__") {
|
|
2198
|
+
logger2.info(`[WorkflowEngine] Workflow terminated via __end__ edge from node "${completedNodeId}"`);
|
|
2199
|
+
scheduler.markCompleted("__end__");
|
|
2200
|
+
await this.completeWorkflow(sessionState);
|
|
2201
|
+
} else {
|
|
2202
|
+
await this.startNode(sessionState, targetId, workflowInput);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
1894
2205
|
}
|
|
1895
|
-
|
|
2206
|
+
buildNodeContext(sessionState, nodeId, globalInput) {
|
|
1896
2207
|
const nodeDef = sessionState.dagManager.getNode(nodeId);
|
|
1897
2208
|
const runId = this.getRunIdFromSessionId(sessionState.sessionId);
|
|
1898
2209
|
const deps = nodeDef.depends_on || [];
|
|
@@ -1903,15 +2214,16 @@ var init_engine = __esm(() => {
|
|
|
1903
2214
|
input[depId] = depOutput;
|
|
1904
2215
|
}
|
|
1905
2216
|
}
|
|
1906
|
-
const
|
|
1907
|
-
const
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
2217
|
+
const rawWorkflowInput = globalInput ?? sessionState.config.workflowInput ?? {};
|
|
2218
|
+
const { userQuery: _ephemeral, ...workflowInput } = rawWorkflowInput;
|
|
2219
|
+
const templateResolver = new TemplateResolver({
|
|
2220
|
+
input: workflowInput,
|
|
2221
|
+
previousOutputs: new Map(sessionState.nodeOutputs)
|
|
2222
|
+
});
|
|
1911
2223
|
const askUser = (query) => {
|
|
1912
2224
|
throw new AskUserError(runId, sessionState.sessionId, nodeId, nodeDef.type, query);
|
|
1913
2225
|
};
|
|
1914
|
-
|
|
2226
|
+
const context = {
|
|
1915
2227
|
runId,
|
|
1916
2228
|
sessionId: sessionState.sessionId,
|
|
1917
2229
|
workflowName: sessionState.workflowName,
|
|
@@ -1924,8 +2236,15 @@ var init_engine = __esm(() => {
|
|
|
1924
2236
|
nodeOutputs: sessionState.nodeOutputs,
|
|
1925
2237
|
workflowHistory: sessionState.workflowHistory,
|
|
1926
2238
|
sessionComponent: this.sessionComponent,
|
|
1927
|
-
askUser
|
|
2239
|
+
askUser,
|
|
2240
|
+
attachAgentSessionToLastStart: async (targetNodeId, agentSessionId) => {
|
|
2241
|
+
await sessionState.executor.attachAgentSessionToLastStart(sessionState.sessionId, targetNodeId, agentSessionId);
|
|
2242
|
+
},
|
|
2243
|
+
workflowInput,
|
|
2244
|
+
templateResolver,
|
|
2245
|
+
resolvedConfig: templateResolver.resolveValue(nodeDef.config ?? {})
|
|
1928
2246
|
};
|
|
2247
|
+
return context;
|
|
1929
2248
|
}
|
|
1930
2249
|
checkAndFinalize(sessionState) {
|
|
1931
2250
|
const state = sessionState.scheduler.getState();
|
|
@@ -1938,6 +2257,10 @@ var init_engine = __esm(() => {
|
|
|
1938
2257
|
}
|
|
1939
2258
|
}
|
|
1940
2259
|
async completeWorkflow(sessionState) {
|
|
2260
|
+
if (sessionState.status !== "running") {
|
|
2261
|
+
return;
|
|
2262
|
+
}
|
|
2263
|
+
sessionState.status = "completed";
|
|
1941
2264
|
const durationMs = Date.now() - sessionState.startedAt.getTime();
|
|
1942
2265
|
const sessionId = sessionState.sessionId;
|
|
1943
2266
|
const runId = this.getRunIdFromSessionId(sessionId);
|
|
@@ -1948,7 +2271,16 @@ var init_engine = __esm(() => {
|
|
|
1948
2271
|
if (this.sessionComponent) {
|
|
1949
2272
|
const metadata = await this.getSessionMetadata(sessionId);
|
|
1950
2273
|
await this.sessionComponent.update(sessionId, {
|
|
1951
|
-
metadata: {
|
|
2274
|
+
metadata: {
|
|
2275
|
+
...metadata,
|
|
2276
|
+
status: "completed",
|
|
2277
|
+
completedAt: Date.now(),
|
|
2278
|
+
durationMs,
|
|
2279
|
+
output,
|
|
2280
|
+
pendingNodeId: undefined,
|
|
2281
|
+
pauseReason: undefined,
|
|
2282
|
+
agentSessions: markAllAgentSessionsCompleted(metadata.agentSessions)
|
|
2283
|
+
}
|
|
1952
2284
|
});
|
|
1953
2285
|
}
|
|
1954
2286
|
await sessionState.eventBus.publish(createWorkflowEvent("workflow.completed", runId, {
|
|
@@ -1964,6 +2296,10 @@ var init_engine = __esm(() => {
|
|
|
1964
2296
|
this.cleanupSession(sessionState);
|
|
1965
2297
|
}
|
|
1966
2298
|
async failWorkflow(sessionState, error) {
|
|
2299
|
+
if (sessionState.status !== "running") {
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2302
|
+
sessionState.status = "failed";
|
|
1967
2303
|
const durationMs = Date.now() - sessionState.startedAt.getTime();
|
|
1968
2304
|
const sessionId = sessionState.sessionId;
|
|
1969
2305
|
const runId = this.getRunIdFromSessionId(sessionId);
|
|
@@ -1971,7 +2307,12 @@ var init_engine = __esm(() => {
|
|
|
1971
2307
|
if (this.sessionComponent) {
|
|
1972
2308
|
const metadata = await this.getSessionMetadata(sessionId);
|
|
1973
2309
|
await this.sessionComponent.update(sessionId, {
|
|
1974
|
-
metadata: {
|
|
2310
|
+
metadata: {
|
|
2311
|
+
...metadata,
|
|
2312
|
+
status: "failed",
|
|
2313
|
+
failedAt: Date.now(),
|
|
2314
|
+
durationMs
|
|
2315
|
+
}
|
|
1975
2316
|
});
|
|
1976
2317
|
}
|
|
1977
2318
|
await sessionState.eventBus.publish(createWorkflowEvent("workflow.failed", runId, {
|
|
@@ -2044,9 +2385,6 @@ var init_engine = __esm(() => {
|
|
|
2044
2385
|
__legacyDecorateClassTS([
|
|
2045
2386
|
TracedAs("workflow.engine.stop", { recordParams: true, recordResult: true, log: true })
|
|
2046
2387
|
], WorkflowEngine.prototype, "stop", null);
|
|
2047
|
-
__legacyDecorateClassTS([
|
|
2048
|
-
TracedAs("workflow.engine.writeNodeInterrupt", { recordParams: true, recordResult: true, log: true })
|
|
2049
|
-
], WorkflowEngine.prototype, "writeNodeInterrupt", null);
|
|
2050
2388
|
__legacyDecorateClassTS([
|
|
2051
2389
|
TracedAs("workflow.engine.scheduleAndExecute", { recordParams: true, recordResult: true, log: true })
|
|
2052
2390
|
], WorkflowEngine.prototype, "scheduleAndExecute", null);
|
|
@@ -2059,12 +2397,15 @@ var init_engine = __esm(() => {
|
|
|
2059
2397
|
__legacyDecorateClassTS([
|
|
2060
2398
|
TracedAs("workflow.engine.writeNodeStart", { recordParams: true, recordResult: true, log: true })
|
|
2061
2399
|
], WorkflowEngine.prototype, "writeNodeStart", null);
|
|
2062
|
-
__legacyDecorateClassTS([
|
|
2063
|
-
TracedAs("workflow.engine.writeNodeResume", { recordParams: true, recordResult: true, log: true })
|
|
2064
|
-
], WorkflowEngine.prototype, "writeNodeResume", null);
|
|
2065
2400
|
__legacyDecorateClassTS([
|
|
2066
2401
|
TracedAs("workflow.engine.resumeNode", { recordParams: true, recordResult: true, log: true })
|
|
2067
2402
|
], WorkflowEngine.prototype, "resumeNode", null);
|
|
2403
|
+
__legacyDecorateClassTS([
|
|
2404
|
+
TracedAs("workflow.engine.preExecuteValidation", { log: true })
|
|
2405
|
+
], WorkflowEngine.prototype, "preExecuteValidation", null);
|
|
2406
|
+
__legacyDecorateClassTS([
|
|
2407
|
+
TracedAs("workflow.engine.buildNodeContext", { log: true })
|
|
2408
|
+
], WorkflowEngine.prototype, "buildNodeContext", null);
|
|
2068
2409
|
__legacyDecorateClassTS([
|
|
2069
2410
|
TracedAs("workflow.engine.checkAndFinalize", { recordParams: true, recordResult: true, log: true })
|
|
2070
2411
|
], WorkflowEngine.prototype, "checkAndFinalize", null);
|