@minded-ai/mindedjs 1.0.19

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.
Files changed (183) hide show
  1. package/.github/workflows/CI.yml +34 -0
  2. package/.prettierrc +8 -0
  3. package/README.md +6 -0
  4. package/dist/agent.d.ts +36 -0
  5. package/dist/agent.js +199 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/analytics.d.ts +6 -0
  8. package/dist/analytics.js +19 -0
  9. package/dist/analytics.js.map +1 -0
  10. package/dist/edges/createDirectEdge.d.ts +4 -0
  11. package/dist/edges/createDirectEdge.js +14 -0
  12. package/dist/edges/createDirectEdge.js.map +1 -0
  13. package/dist/edges/createLogicalRouter.d.ts +5 -0
  14. package/dist/edges/createLogicalRouter.js +18 -0
  15. package/dist/edges/createLogicalRouter.js.map +1 -0
  16. package/dist/edges/createPromptRouter.d.ts +7 -0
  17. package/dist/edges/createPromptRouter.js +54 -0
  18. package/dist/edges/createPromptRouter.js.map +1 -0
  19. package/dist/edges/edgeFactory.d.ts +9 -0
  20. package/dist/edges/edgeFactory.js +65 -0
  21. package/dist/edges/edgeFactory.js.map +1 -0
  22. package/dist/events/AgentEvents.d.ts +22 -0
  23. package/dist/events/AgentEvents.js +9 -0
  24. package/dist/events/AgentEvents.js.map +1 -0
  25. package/dist/events/index.d.ts +2 -0
  26. package/dist/events/index.js +5 -0
  27. package/dist/events/index.js.map +1 -0
  28. package/dist/index.d.ts +6 -0
  29. package/dist/index.js +15 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/infrastructure.ts/mindedRequest.d.ts +8 -0
  32. package/dist/infrastructure.ts/mindedRequest.js +22 -0
  33. package/dist/infrastructure.ts/mindedRequest.js.map +1 -0
  34. package/dist/llm/createLlmInstance.d.ts +2 -0
  35. package/dist/llm/createLlmInstance.js +14 -0
  36. package/dist/llm/createLlmInstance.js.map +1 -0
  37. package/dist/nodes/addHumanInTheLoopNode.d.ts +8 -0
  38. package/dist/nodes/addHumanInTheLoopNode.js +17 -0
  39. package/dist/nodes/addHumanInTheLoopNode.js.map +1 -0
  40. package/dist/nodes/addPromptNode.d.ts +15 -0
  41. package/dist/nodes/addPromptNode.js +52 -0
  42. package/dist/nodes/addPromptNode.js.map +1 -0
  43. package/dist/nodes/addToolNode.d.ts +10 -0
  44. package/dist/nodes/addToolNode.js +82 -0
  45. package/dist/nodes/addToolNode.js.map +1 -0
  46. package/dist/nodes/addTriggerNode.d.ts +6 -0
  47. package/dist/nodes/addTriggerNode.js +12 -0
  48. package/dist/nodes/addTriggerNode.js.map +1 -0
  49. package/dist/nodes/nodeFactory.d.ts +13 -0
  50. package/dist/nodes/nodeFactory.js +41 -0
  51. package/dist/nodes/nodeFactory.js.map +1 -0
  52. package/dist/platform/analytics.d.ts +6 -0
  53. package/dist/platform/analytics.js +19 -0
  54. package/dist/platform/analytics.js.map +1 -0
  55. package/dist/platform/mindedCheckpointSaver.d.ts +10 -0
  56. package/dist/platform/mindedCheckpointSaver.js +49 -0
  57. package/dist/platform/mindedCheckpointSaver.js.map +1 -0
  58. package/dist/platform/mindedConnection.d.ts +13 -0
  59. package/dist/platform/mindedConnection.js +117 -0
  60. package/dist/platform/mindedConnection.js.map +1 -0
  61. package/dist/platform/mindedConnectionTypes.d.ts +10 -0
  62. package/dist/platform/mindedConnectionTypes.js +8 -0
  63. package/dist/platform/mindedConnectionTypes.js.map +1 -0
  64. package/dist/platform/mindedRequest.d.ts +8 -0
  65. package/dist/platform/mindedRequest.js +22 -0
  66. package/dist/platform/mindedRequest.js.map +1 -0
  67. package/dist/types/Agent.types.d.ts +8 -0
  68. package/dist/types/Agent.types.js +3 -0
  69. package/dist/types/Agent.types.js.map +1 -0
  70. package/dist/types/Flows.types.d.ts +83 -0
  71. package/dist/types/Flows.types.js +24 -0
  72. package/dist/types/Flows.types.js.map +1 -0
  73. package/dist/types/LLM.types.d.ts +10 -0
  74. package/dist/types/LLM.types.js +9 -0
  75. package/dist/types/LLM.types.js.map +1 -0
  76. package/dist/types/LangGraph.types.d.ts +29 -0
  77. package/dist/types/LangGraph.types.js +20 -0
  78. package/dist/types/LangGraph.types.js.map +1 -0
  79. package/dist/types/Tools.types.d.ts +14 -0
  80. package/dist/types/Tools.types.js +3 -0
  81. package/dist/types/Tools.types.js.map +1 -0
  82. package/dist/types/Triggers.types.d.ts +1 -0
  83. package/dist/types/Triggers.types.js +3 -0
  84. package/dist/types/Triggers.types.js.map +1 -0
  85. package/docs/.gitbook/assets/image.png +0 -0
  86. package/docs/README.md +51 -0
  87. package/docs/SUMMARY.md +21 -0
  88. package/docs/api-reference/.nojekyll +1 -0
  89. package/docs/api-reference/assets/hierarchy.js +1 -0
  90. package/docs/api-reference/assets/highlight.css +120 -0
  91. package/docs/api-reference/assets/icons.js +18 -0
  92. package/docs/api-reference/assets/icons.svg +1 -0
  93. package/docs/api-reference/assets/main.js +60 -0
  94. package/docs/api-reference/assets/navigation.js +1 -0
  95. package/docs/api-reference/assets/search.js +1 -0
  96. package/docs/api-reference/assets/style.css +1640 -0
  97. package/docs/api-reference/classes/index.Agent.html +4 -0
  98. package/docs/api-reference/enums/index.EdgeType.html +4 -0
  99. package/docs/api-reference/enums/index.NodeType.html +6 -0
  100. package/docs/api-reference/enums/index.TriggerType.html +4 -0
  101. package/docs/api-reference/enums/index.events.html +3 -0
  102. package/docs/api-reference/hierarchy.html +1 -0
  103. package/docs/api-reference/index.html +310 -0
  104. package/docs/api-reference/interfaces/index.AppToolNode.html +5 -0
  105. package/docs/api-reference/interfaces/index.AppTriggerNode.html +6 -0
  106. package/docs/api-reference/interfaces/index.Flow.html +4 -0
  107. package/docs/api-reference/interfaces/index.JunctionNode.html +4 -0
  108. package/docs/api-reference/interfaces/index.LogicalConditionEdge.html +5 -0
  109. package/docs/api-reference/interfaces/index.ManualTriggerNode.html +5 -0
  110. package/docs/api-reference/interfaces/index.PromptConditionEdge.html +5 -0
  111. package/docs/api-reference/interfaces/index.PromptNode.html +6 -0
  112. package/docs/api-reference/interfaces/index.StepForwardEdge.html +4 -0
  113. package/docs/api-reference/interfaces/index.Tool.html +6 -0
  114. package/docs/api-reference/interfaces/index.ToolNode.html +5 -0
  115. package/docs/api-reference/modules/index-1.html +1 -0
  116. package/docs/api-reference/modules/index.html +1 -0
  117. package/docs/api-reference/modules.html +1 -0
  118. package/docs/api-reference/types/index.Edge.html +1 -0
  119. package/docs/api-reference/types/index.Node.html +1 -0
  120. package/docs/api-reference/types/index.TriggerNode.html +1 -0
  121. package/docs/core-concepts/edges.md +242 -0
  122. package/docs/core-concepts/events.md +161 -0
  123. package/docs/core-concepts/flows.md +74 -0
  124. package/docs/core-concepts/memory-types.md +208 -0
  125. package/docs/core-concepts/nodes.md +239 -0
  126. package/docs/core-concepts/tools.md +205 -0
  127. package/docs/examples/order-refund-flow.md +560 -0
  128. package/docs/getting-started/installation.md +34 -0
  129. package/docs/getting-started/quick-start.md +264 -0
  130. package/docs-structure.md +144 -0
  131. package/eslint.config.js +68 -0
  132. package/examples/orderRefundAgent/flows/orderRefundFlow.yaml +32 -0
  133. package/examples/orderRefundAgent/minded.json +14 -0
  134. package/examples/orderRefundAgent/orderRefundAgent.ts +58 -0
  135. package/examples/orderRefundAgent/schema.ts +7 -0
  136. package/examples/orderRefundAgent/tools/escalateConversation.ts +28 -0
  137. package/examples/orderRefundAgent/tools/index.ts +4 -0
  138. package/examples/orderRefundAgent/tools/refundOrder.ts +27 -0
  139. package/package.json +46 -0
  140. package/src/agent.ts +216 -0
  141. package/src/edges/createDirectEdge.ts +11 -0
  142. package/src/edges/createLogicalRouter.ts +16 -0
  143. package/src/edges/createPromptRouter.ts +52 -0
  144. package/src/edges/edgeFactory.ts +85 -0
  145. package/src/events/AgentEvents.ts +22 -0
  146. package/src/events/index.ts +3 -0
  147. package/src/index.ts +22 -0
  148. package/src/llm/createLlmInstance.ts +10 -0
  149. package/src/nodes/addHumanInTheLoopNode.ts +20 -0
  150. package/src/nodes/addPromptNode.ts +66 -0
  151. package/src/nodes/addToolNode.ts +95 -0
  152. package/src/nodes/addTriggerNode.ts +12 -0
  153. package/src/nodes/nodeFactory.ts +65 -0
  154. package/src/platform/analytics.ts +16 -0
  155. package/src/platform/mindedCheckpointSaver.ts +74 -0
  156. package/src/platform/mindedConnection.ts +106 -0
  157. package/src/platform/mindedConnectionTypes.ts +15 -0
  158. package/src/platform/mindedRequest.ts +28 -0
  159. package/src/types/Agent.types.ts +10 -0
  160. package/src/types/Flows.types.ts +103 -0
  161. package/src/types/LLM.types.ts +13 -0
  162. package/src/types/LangGraph.types.ts +25 -0
  163. package/src/types/Tools.types.ts +9 -0
  164. package/test/can-stay-on-node/can-stay-on-node.test.ts +148 -0
  165. package/test/can-stay-on-node/flows/test-flow.yaml +25 -0
  166. package/test/cannot-stay-on-node/cannot-stay-on-node.test.ts +201 -0
  167. package/test/cannot-stay-on-node/flows/test-flow.yaml +34 -0
  168. package/test/human-in-the-loop-node/flows/test-flow.yaml +23 -0
  169. package/test/human-in-the-loop-node/human-in-the-loop-node.test.ts +92 -0
  170. package/test/logical-edges/flows/logical-edge-test-flow.yaml +24 -0
  171. package/test/logical-edges/logical-edges.test.ts +66 -0
  172. package/test/no-human-in-the-loop-node/flows/test-flow.yaml +23 -0
  173. package/test/no-human-in-the-loop-node/no-human-in-the-loop-node.test.ts +80 -0
  174. package/test/prompt-edges/flows/test-flow.yaml +24 -0
  175. package/test/prompt-edges/prompt-edges.test.ts +90 -0
  176. package/test/prompt-node/flows/test-flow.yaml +24 -0
  177. package/test/prompt-node/prompt-node.test.ts +86 -0
  178. package/test/setup.ts +5 -0
  179. package/test/tool-node/flows/test-flow.yaml +14 -0
  180. package/test/tool-node/tool-node.test.ts +67 -0
  181. package/test/trigger/flows/test-flow.yaml +7 -0
  182. package/test/trigger/trigger.test.ts +57 -0
  183. package/tsconfig.json +17 -0
@@ -0,0 +1,201 @@
1
+ import { expect } from 'chai';
2
+ import { Agent } from '../../src/agent';
3
+ import { z } from 'zod';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import path from 'path';
6
+ import { AgentEvents } from '../../src/events/AgentEvents';
7
+ import { HumanMessage } from '@langchain/core/messages';
8
+
9
+ const memorySchema = z.object({
10
+ success: z.boolean(),
11
+ alternative: z.boolean(),
12
+ });
13
+
14
+ describe('Cannot Stay On Node', function () {
15
+ this.timeout(10000); // Set timeout to 10 seconds for all tests in this suite
16
+
17
+ let agent: Agent;
18
+
19
+ beforeEach(() => {
20
+ const flowsPath = path.join(__dirname, 'flows');
21
+ const toolsPath = path.join(__dirname, 'tools');
22
+ agent = new Agent({
23
+ memorySchema,
24
+ config: {
25
+ flows: [flowsPath],
26
+ tools: [toolsPath],
27
+ llm: {
28
+ name: 'ChatOpenAI',
29
+ properties: {
30
+ model: 'gpt-4o-mini',
31
+ },
32
+ },
33
+ },
34
+ tools: [
35
+ {
36
+ name: 'successTool',
37
+ description: 'Success Tool that marks completion',
38
+ input: z.object({
39
+ name: z.string(),
40
+ }),
41
+ execute: async () => ({
42
+ memory: {
43
+ success: true,
44
+ alternative: false,
45
+ },
46
+ }),
47
+ },
48
+ {
49
+ name: 'alternativeTool',
50
+ description: 'Alternative Tool that marks alternative completion',
51
+ input: z.object({
52
+ name: z.string(),
53
+ }),
54
+ execute: async () => ({
55
+ memory: {
56
+ success: false,
57
+ alternative: true,
58
+ },
59
+ }),
60
+ },
61
+ ],
62
+ });
63
+
64
+ // Add trigger event handler
65
+ agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
66
+ if (triggerName === 'Trigger') {
67
+ return {
68
+ memory: {},
69
+ messages: [new HumanMessage(triggerBody.message)],
70
+ };
71
+ }
72
+ });
73
+ });
74
+
75
+ it('should NOT stay on node when explicitly requested to stay (canStayOnNode is false)', async function () {
76
+ this.timeout(20000);
77
+
78
+ const sessionId = uuidv4();
79
+
80
+ // First invocation - triggers the flow and reaches the human-in-the-loop pause
81
+ const result1 = await agent.invoke({
82
+ triggerBody: {
83
+ message: 'Initial input for processing',
84
+ },
85
+ triggerName: 'Trigger',
86
+ sessionId,
87
+ });
88
+
89
+ // Should pause at human-in-the-loop, not reach any tool yet
90
+ expect(result1.memory.success).to.not.equal(true);
91
+ expect(result1.memory.alternative).to.not.equal(true);
92
+ expect(result1.messages).to.have.length.greaterThan(0);
93
+
94
+ // Second invocation - explicitly request to stay on the node
95
+ const result2 = await agent.invoke({
96
+ triggerBody: {
97
+ message: 'You must stay at the node! Do not move to the next step. Stay here and continue processing on this same node.',
98
+ },
99
+ triggerName: 'Trigger',
100
+ sessionId,
101
+ });
102
+
103
+ // Should NOT stay on the node - should move to one of the target nodes
104
+ // Since canStayOnNode is false, the router has no self-referencing edge option
105
+ expect(result2.memory.success || result2.memory.alternative).to.equal(true);
106
+ });
107
+
108
+ it('should move to success node when user requests main workflow', async function () {
109
+ this.timeout(20000);
110
+
111
+ const sessionId = uuidv4();
112
+
113
+ // First invocation - initial trigger
114
+ const result1 = await agent.invoke({
115
+ triggerBody: {
116
+ message: 'Start processing',
117
+ },
118
+ triggerName: 'Trigger',
119
+ sessionId,
120
+ });
121
+
122
+ expect(result1.memory.success).to.not.equal(true);
123
+ expect(result1.memory.alternative).to.not.equal(true);
124
+
125
+ // Second invocation - request main workflow
126
+ const result2 = await agent.invoke({
127
+ triggerBody: {
128
+ message: 'Proceed with the main workflow',
129
+ },
130
+ triggerName: 'Trigger',
131
+ sessionId,
132
+ });
133
+
134
+ // Should move to success node
135
+ expect(result2.memory.success).to.equal(true);
136
+ expect(result2.memory.alternative).to.equal(false);
137
+ });
138
+
139
+ it('should move to alternative node when user requests alternative approach', async function () {
140
+ this.timeout(20000);
141
+
142
+ const sessionId = uuidv4();
143
+
144
+ // First invocation - initial trigger
145
+ const result1 = await agent.invoke({
146
+ triggerBody: {
147
+ message: 'Begin workflow',
148
+ },
149
+ triggerName: 'Trigger',
150
+ sessionId,
151
+ });
152
+
153
+ expect(result1.memory.success).to.not.equal(true);
154
+ expect(result1.memory.alternative).to.not.equal(true);
155
+
156
+ // Second invocation - request alternative approach
157
+ const result2 = await agent.invoke({
158
+ triggerBody: {
159
+ message: 'I want an alternative approach instead',
160
+ },
161
+ triggerName: 'Trigger',
162
+ sessionId,
163
+ });
164
+
165
+ // Should move to alternative node
166
+ expect(result2.memory.success).to.equal(false);
167
+ expect(result2.memory.alternative).to.equal(true);
168
+ });
169
+
170
+ it('should force progression even with strong stay requests', async function () {
171
+ this.timeout(20000);
172
+
173
+ const sessionId = uuidv4();
174
+
175
+ // First invocation - initial trigger
176
+ const result1 = await agent.invoke({
177
+ triggerBody: {
178
+ message: 'Process this data',
179
+ },
180
+ triggerName: 'Trigger',
181
+ sessionId,
182
+ });
183
+
184
+ expect(result1.memory.success).to.not.equal(true);
185
+ expect(result1.memory.alternative).to.not.equal(true);
186
+
187
+ // Second invocation - very strong request to stay
188
+ const result2 = await agent.invoke({
189
+ triggerBody: {
190
+ message:
191
+ 'STAY! Do not proceed! You must remain on this current node and not move forward. Keep processing here. Do not go to any other node.',
192
+ },
193
+ triggerName: 'Trigger',
194
+ sessionId,
195
+ });
196
+
197
+ // Should still be forced to move to one of the available target nodes
198
+ // because there's no self-referencing edge (canStayOnNode is false)
199
+ expect(result2.memory.success || result2.memory.alternative).to.equal(true);
200
+ });
201
+ });
@@ -0,0 +1,34 @@
1
+ name: Cannot Stay On Node Test Flow
2
+ nodes:
3
+ - type: 'trigger'
4
+ triggerType: 'manual'
5
+ name: 'Trigger'
6
+
7
+ - type: 'promptNode'
8
+ name: 'ProcessingNode'
9
+ prompt: 'I have processed your input. Please provide your feedback or additional instructions.'
10
+ humanInTheLoop: true
11
+ # Note: canStayOnNode is NOT set to true
12
+
13
+ - type: 'tool'
14
+ name: 'Success'
15
+ toolName: 'successTool'
16
+
17
+ - type: 'tool'
18
+ name: 'Alternative'
19
+ toolName: 'alternativeTool'
20
+
21
+ edges:
22
+ - source: 'Trigger'
23
+ target: 'ProcessingNode'
24
+ type: 'stepForward'
25
+
26
+ - source: 'ProcessingNode'
27
+ target: 'Success'
28
+ type: 'promptCondition'
29
+ prompt: 'move to success node if the user wants to proceed with the main workflow'
30
+
31
+ - source: 'ProcessingNode'
32
+ target: 'Alternative'
33
+ type: 'promptCondition'
34
+ prompt: 'move to alternative node if the user wants an alternative approach'
@@ -0,0 +1,23 @@
1
+ name: Human In The Loop Test Flow
2
+ nodes:
3
+ - type: 'trigger'
4
+ triggerType: 'manual'
5
+ name: 'Trigger'
6
+
7
+ - type: 'promptNode'
8
+ name: 'ProcessingNode'
9
+ prompt: 'Process the user input and prepare for human review'
10
+ humanInTheLoop: true
11
+
12
+ - type: 'tool'
13
+ name: 'Success'
14
+ toolName: 'successTool'
15
+
16
+ edges:
17
+ - source: 'Trigger'
18
+ target: 'ProcessingNode'
19
+ type: 'stepForward'
20
+
21
+ - source: 'ProcessingNode'
22
+ target: 'Success'
23
+ type: 'stepForward'
@@ -0,0 +1,92 @@
1
+ import { expect } from 'chai';
2
+ import { Agent } from '../../src/agent';
3
+ import { z } from 'zod';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import path from 'path';
6
+ import { AgentEvents } from '../../src/events/AgentEvents';
7
+ import { HumanMessage } from '@langchain/core/messages';
8
+
9
+ const memorySchema = z.object({
10
+ success: z.boolean(),
11
+ });
12
+
13
+ describe('Human In The Loop Node', function () {
14
+ this.timeout(10000); // Set timeout to 10 seconds for all tests in this suite
15
+
16
+ let agent: Agent;
17
+
18
+ beforeEach(() => {
19
+ const flowsPath = path.join(__dirname, 'flows');
20
+ const toolsPath = path.join(__dirname, 'tools');
21
+ agent = new Agent({
22
+ memorySchema,
23
+ config: {
24
+ flows: [flowsPath],
25
+ tools: [toolsPath],
26
+ llm: {
27
+ name: 'ChatOpenAI',
28
+ properties: {
29
+ model: 'gpt-4.1',
30
+ },
31
+ },
32
+ },
33
+ tools: [
34
+ {
35
+ name: 'successTool',
36
+ description: 'Success Tool',
37
+ input: z.object({
38
+ name: z.string(),
39
+ }),
40
+ execute: async () => ({
41
+ memory: {
42
+ success: true,
43
+ },
44
+ }),
45
+ },
46
+ ],
47
+ });
48
+
49
+ // Add trigger event handler
50
+ agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
51
+ if (triggerName === 'Trigger') {
52
+ return {
53
+ memory: {},
54
+ messages: [new HumanMessage(triggerBody.message)],
55
+ };
56
+ }
57
+ });
58
+ });
59
+
60
+ it('should pause execution at human-in-the-loop node and resume after human input', async function () {
61
+ this.timeout(20000); // Set timeout to 20 seconds for this test
62
+
63
+ const sessionId = uuidv4();
64
+
65
+ // First invocation should execute the ProcessingNode and then pause at the human-in-the-loop node
66
+ const result = await agent.invoke({
67
+ triggerBody: {
68
+ message: 'Initial user input for processing',
69
+ },
70
+ triggerName: 'Trigger',
71
+ sessionId,
72
+ });
73
+
74
+ // Should pause execution at human-in-the-loop node, not reaching the success tool yet
75
+ expect(result.memory.success).to.not.equal(true);
76
+
77
+ // Verify that we have messages from the processing node
78
+ expect(result.messages).to.have.length.greaterThan(0);
79
+
80
+ // Second invocation should provide human input and continue to the Success node
81
+ const result2 = await agent.invoke({
82
+ triggerBody: {
83
+ message: 'Human approval: proceed with the workflow',
84
+ },
85
+ triggerName: 'Trigger',
86
+ sessionId,
87
+ });
88
+
89
+ // Should complete execution and reach the success tool
90
+ expect(result2.memory.success).to.equal(true);
91
+ });
92
+ });
@@ -0,0 +1,24 @@
1
+ name: Age Flow
2
+ nodes:
3
+ - type: "trigger"
4
+ triggerType: "manual"
5
+ name: "AgeTrigger"
6
+
7
+ - type: "tool"
8
+ name: "Adult Tool"
9
+ toolName: "adultTool"
10
+
11
+ - type: "tool"
12
+ name: "Minor Tool"
13
+ toolName: "minorTool"
14
+
15
+ edges:
16
+ - source: "AgeTrigger"
17
+ target: "Adult Tool"
18
+ type: "logicalCondition"
19
+ condition: "({ memory }) => memory.userAge >= 18"
20
+
21
+ - source: "AgeTrigger"
22
+ target: "Minor Tool"
23
+ type: "logicalCondition"
24
+ condition: "({ memory }) => memory.userAge < 18"
@@ -0,0 +1,66 @@
1
+ import { expect } from 'chai';
2
+ import { Agent } from "../../src/agent";
3
+ import { z } from "zod";
4
+ import path from 'path';
5
+ import { AgentEvents } from "../../src/events/AgentEvents";
6
+
7
+ const memorySchema = z.object({
8
+ userAge: z.number(),
9
+ isMinor: z.boolean(),
10
+ });
11
+
12
+ describe('Logical Edges', () => {
13
+ const flowsPath = path.join(__dirname, 'flows');
14
+ const toolsPath = path.join(__dirname, 'tools');
15
+ const agent = new Agent({
16
+ memorySchema,
17
+ config: {
18
+ flows: [flowsPath],
19
+ tools: [toolsPath],
20
+ llm: {
21
+ name: 'ChatOpenAI',
22
+ properties: {
23
+ model: 'gpt-4.1'
24
+ }
25
+ }
26
+ },
27
+ tools: [
28
+ {
29
+ name: 'adultTool',
30
+ description: 'Adult Tool',
31
+ input: z.object({}),
32
+ execute: async () => ({ memory: { isMinor: false } }),
33
+ },
34
+ {
35
+ name: 'minorTool',
36
+ description: 'Minor Tool',
37
+ input: z.object({}),
38
+ execute: async () => ({ memory: { isMinor: true } }),
39
+ },
40
+ ],
41
+ });
42
+
43
+ agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerBody }) => {
44
+ return {
45
+ memory: triggerBody
46
+ }
47
+ });
48
+
49
+ it('should execute the Adult Tool', async function () {
50
+ this.timeout(10000); // Increase timeout to 10 seconds
51
+ const result = await agent.invoke({
52
+ triggerName: 'AgeTrigger',
53
+ triggerBody: { userAge: 25 },
54
+ });
55
+ expect(result.memory.isMinor).to.equal(false);
56
+ });
57
+
58
+ it('should execute the Minor Tool', async function () {
59
+ this.timeout(10000); // Increase timeout to 10 seconds
60
+ const result = await agent.invoke({
61
+ triggerName: 'AgeTrigger',
62
+ triggerBody: { userAge: 15 },
63
+ });
64
+ expect(result.memory.isMinor).to.equal(true);
65
+ });
66
+ });
@@ -0,0 +1,23 @@
1
+ name: No Human In The Loop Test Flow
2
+ nodes:
3
+ - type: 'trigger'
4
+ triggerType: 'manual'
5
+ name: 'Trigger'
6
+
7
+ - type: 'promptNode'
8
+ name: 'ProcessingNode'
9
+ prompt: 'Process the user input and prepare for completion'
10
+ humanInTheLoop: false
11
+
12
+ - type: 'tool'
13
+ name: 'Success'
14
+ toolName: 'successTool'
15
+
16
+ edges:
17
+ - source: 'Trigger'
18
+ target: 'ProcessingNode'
19
+ type: 'stepForward'
20
+
21
+ - source: 'ProcessingNode'
22
+ target: 'Success'
23
+ type: 'stepForward'
@@ -0,0 +1,80 @@
1
+ import { expect } from 'chai';
2
+ import { Agent } from '../../src/agent';
3
+ import { z } from 'zod';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import path from 'path';
6
+ import { AgentEvents } from '../../src/events/AgentEvents';
7
+ import { HumanMessage } from '@langchain/core/messages';
8
+
9
+ const memorySchema = z.object({
10
+ success: z.boolean(),
11
+ });
12
+
13
+ describe('No Human In The Loop Node', function () {
14
+ this.timeout(10000); // Set timeout to 10 seconds for all tests in this suite
15
+
16
+ let agent: Agent;
17
+
18
+ beforeEach(() => {
19
+ const flowsPath = path.join(__dirname, 'flows');
20
+ const toolsPath = path.join(__dirname, 'tools');
21
+ agent = new Agent({
22
+ memorySchema,
23
+ config: {
24
+ flows: [flowsPath],
25
+ tools: [toolsPath],
26
+ llm: {
27
+ name: 'ChatOpenAI',
28
+ properties: {
29
+ model: 'gpt-4.1',
30
+ },
31
+ },
32
+ },
33
+ tools: [
34
+ {
35
+ name: 'successTool',
36
+ description: 'Success Tool',
37
+ input: z.object({
38
+ name: z.string(),
39
+ }),
40
+ execute: async () => ({
41
+ memory: {
42
+ success: true,
43
+ },
44
+ }),
45
+ },
46
+ ],
47
+ });
48
+
49
+ // Add trigger event handler
50
+ agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
51
+ if (triggerName === 'Trigger') {
52
+ return {
53
+ memory: {},
54
+ messages: [new HumanMessage(triggerBody.message)],
55
+ };
56
+ }
57
+ });
58
+ });
59
+
60
+ it('should complete execution without pausing when humanInTheLoop is false', async function () {
61
+ this.timeout(20000); // Set timeout to 20 seconds for this test
62
+
63
+ const sessionId = uuidv4();
64
+
65
+ // Single invocation should complete the entire flow without pausing
66
+ const result = await agent.invoke({
67
+ triggerBody: {
68
+ message: 'Input for processing without human intervention',
69
+ },
70
+ triggerName: 'Trigger',
71
+ sessionId,
72
+ });
73
+
74
+ // Should complete execution and reach the success tool in one go
75
+ expect(result.memory.success).to.equal(true);
76
+
77
+ // Verify that we have messages from both the processing node and the tool execution
78
+ expect(result.messages).to.have.length.greaterThan(0);
79
+ });
80
+ });
@@ -0,0 +1,24 @@
1
+ name: Test Flow
2
+ nodes:
3
+ - type: 'trigger'
4
+ triggerType: 'manual'
5
+ name: 'Trigger'
6
+
7
+ - type: 'tool'
8
+ name: 'Success Tool'
9
+ toolName: 'successTool'
10
+
11
+ - type: 'tool'
12
+ name: 'Failure Tool'
13
+ toolName: 'failureTool'
14
+
15
+ edges:
16
+ - source: 'Trigger'
17
+ target: 'Success Tool'
18
+ type: 'promptCondition'
19
+ prompt: 'User name is Itay'
20
+
21
+ - source: 'Trigger'
22
+ target: 'Failure Tool'
23
+ type: 'promptCondition'
24
+ prompt: 'User name is not Itay'
@@ -0,0 +1,90 @@
1
+ import { expect } from 'chai';
2
+ import { Agent } from '../../src/agent';
3
+ import { z } from 'zod';
4
+ import path from 'path';
5
+ import { AgentEvents } from '../../src/events/AgentEvents';
6
+ import { HumanMessage } from '@langchain/core/messages';
7
+
8
+ const memorySchema = z.object({
9
+ userName: z.string(),
10
+ });
11
+
12
+ describe('Prompt Edges', () => {
13
+ let agent: Agent;
14
+
15
+ beforeEach(() => {
16
+ const flowsPath = path.join(__dirname, 'flows');
17
+ const toolsPath = path.join(__dirname, 'tools');
18
+ agent = new Agent({
19
+ memorySchema,
20
+ config: {
21
+ flows: [flowsPath],
22
+ tools: [toolsPath],
23
+ llm: {
24
+ name: 'ChatOpenAI',
25
+ properties: {
26
+ model: 'gpt-4.1'
27
+ }
28
+ }
29
+ },
30
+ tools: [
31
+ {
32
+ name: 'successTool',
33
+ description: 'Success Tool',
34
+ input: z.object({
35
+ userName: z.string(),
36
+ }),
37
+ execute: async ({ input }) => ({
38
+ memory: { userName: input.userName },
39
+ }),
40
+ },
41
+ {
42
+ name: 'failureTool',
43
+ description: 'Failure Tool',
44
+ input: z.object({
45
+ userName: z.string(),
46
+ }),
47
+ execute: async ({ input }) => ({
48
+ memory: { userName: input.userName },
49
+ }),
50
+ },
51
+ ],
52
+ });
53
+
54
+ // Add trigger event handler
55
+ agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
56
+ if (triggerName === 'Trigger') {
57
+ return {
58
+ memory: {},
59
+ messages: [new HumanMessage(triggerBody.message)],
60
+ };
61
+ }
62
+ });
63
+ });
64
+
65
+ it('should evaluate prompt condition edge correctly', async function () {
66
+ this.timeout(10000); // Increase timeout to 10 seconds
67
+
68
+ const result = await agent.invoke({
69
+ triggerBody: {
70
+ message: 'Hi, my name is Itay',
71
+ },
72
+ triggerName: 'Trigger',
73
+ });
74
+
75
+ expect(result.memory.userName).to.equal('Itay');
76
+ });
77
+
78
+ it('should evaluate prompt condition edge correctly', async function () {
79
+ this.timeout(10000); // Increase timeout to 10 seconds
80
+
81
+ const result = await agent.invoke({
82
+ triggerBody: {
83
+ message: 'Hi, my name is Ilan',
84
+ },
85
+ triggerName: 'Trigger',
86
+ });
87
+
88
+ expect(result.memory.userName).to.equal('Ilan');
89
+ });
90
+ });
@@ -0,0 +1,24 @@
1
+ name: Test Flow
2
+ nodes:
3
+ - type: 'trigger'
4
+ triggerType: 'manual'
5
+ name: 'Trigger'
6
+
7
+ - type: 'promptNode'
8
+ name: 'Prompt'
9
+ prompt: 'Ask the user for their name'
10
+ humanInTheLoop: true
11
+ canStayOnNode: true
12
+
13
+ - type: 'tool'
14
+ name: 'Success'
15
+ toolName: 'successTool'
16
+
17
+ edges:
18
+ - source: 'Trigger'
19
+ target: 'Prompt'
20
+ type: 'stepForward'
21
+
22
+ - source: 'Prompt'
23
+ target: 'Success'
24
+ type: 'stepForward'