@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,65 @@
1
+ import { RunnableLike } from '@langchain/core/runnables';
2
+ import { AppToolNode, JunctionNode, Node, NodeType } from '../types/Flows.types';
3
+ import { PreCompiledGraph } from '../types/LangGraph.types';
4
+ import { Tool } from '../types/Tools.types';
5
+ import { BaseLanguageModel } from '@langchain/core/language_models/base';
6
+ import { addTriggerNode } from './addTriggerNode';
7
+ import { addToolNode } from './addToolNode';
8
+ import { addPromptNode } from './addPromptNode';
9
+ import { AgentEventRequestPayloads } from '../events/AgentEvents';
10
+ import { EmitSignature } from '../types/Agent.types';
11
+
12
+ const addJunctionNode = ({ graph, node }: { graph: PreCompiledGraph; node: JunctionNode }) => {
13
+ const callback: RunnableLike = async () => {};
14
+ graph.addNode(node.name, callback);
15
+ };
16
+
17
+ const addAppToolNode = ({
18
+ graph,
19
+ node,
20
+ }: {
21
+ graph: PreCompiledGraph;
22
+ node: AppToolNode;
23
+ tools: Tool<any, any>[];
24
+ llm: BaseLanguageModel;
25
+ }) => {
26
+ const callback: RunnableLike = async () => {
27
+ throw new Error('Not implemented');
28
+ };
29
+ graph.addNode(node.name, callback);
30
+ };
31
+
32
+ export const nodeFactory = ({
33
+ graph,
34
+ node,
35
+ tools,
36
+ llm,
37
+ emit,
38
+ }: {
39
+ graph: PreCompiledGraph;
40
+ node: Node;
41
+ tools: Tool<any, any>[];
42
+ llm: BaseLanguageModel;
43
+ emit: EmitSignature<any, keyof AgentEventRequestPayloads<any>>;
44
+ }) => {
45
+ const nodeType = node.type;
46
+ switch (nodeType) {
47
+ case NodeType.TRIGGER:
48
+ addTriggerNode({ graph, node });
49
+ break;
50
+ case NodeType.TOOL:
51
+ addToolNode({ graph, node, tools, llm });
52
+ break;
53
+ case NodeType.JUNCTION:
54
+ addJunctionNode({ graph, node });
55
+ break;
56
+ case NodeType.APP_TOOL:
57
+ addAppToolNode({ graph, node, tools, llm });
58
+ break;
59
+ case NodeType.PROMPT_NODE:
60
+ addPromptNode({ graph, node, tools, llm, emit });
61
+ break;
62
+ default:
63
+ throw new Error(`Unsupported node type: ${nodeType}`);
64
+ }
65
+ };
@@ -0,0 +1,16 @@
1
+ import { mindedRequest } from './mindedRequest';
2
+
3
+ const track = async <T>({ event, data, token, sessionId }: { event: string; data: T; token: string; sessionId: string }) => {
4
+ await mindedRequest({
5
+ path: '/analytics/events',
6
+ method: 'POST',
7
+ body: { event, data, sessionId },
8
+ token,
9
+ });
10
+ };
11
+
12
+ export const analyticsFactory = ({ token, sessionId }: { token: string; sessionId: string }) => {
13
+ return {
14
+ track: <T>(event: string, data: T) => track<T>({ event, data, token, sessionId }),
15
+ };
16
+ };
@@ -0,0 +1,74 @@
1
+ import {
2
+ BaseCheckpointSaver,
3
+ CheckpointTuple,
4
+ Checkpoint,
5
+ CheckpointMetadata,
6
+ ChannelVersions,
7
+ PendingWrite,
8
+ CheckpointListOptions,
9
+ } from '@langchain/langgraph-checkpoint';
10
+ import type { RunnableConfig } from '@langchain/core/runnables';
11
+ import { mindedRequest } from './mindedRequest';
12
+
13
+ export class MindedCheckpointSaver extends BaseCheckpointSaver<number> {
14
+ constructor(private token: string) {
15
+ super();
16
+ }
17
+
18
+ async getTuple(config: RunnableConfig<Record<string, any>>): Promise<CheckpointTuple | undefined> {
19
+ return await mindedRequest<CheckpointTuple | undefined, { config: RunnableConfig<Record<string, any>> }>({
20
+ path: '/checkpoint/get',
21
+ method: 'POST',
22
+ body: { config },
23
+ token: this.token,
24
+ });
25
+ }
26
+
27
+ async *list(config: RunnableConfig<Record<string, any>>, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple, any, any> {
28
+ const tuples = await mindedRequest<CheckpointTuple[], { config: RunnableConfig<Record<string, any>>; options?: CheckpointListOptions }>(
29
+ {
30
+ path: '/checkpoint/list',
31
+ method: 'POST',
32
+ body: { config, options },
33
+ token: this.token,
34
+ },
35
+ );
36
+
37
+ for (const tuple of tuples) {
38
+ yield tuple;
39
+ }
40
+ }
41
+
42
+ async put(
43
+ config: RunnableConfig<Record<string, any>>,
44
+ checkpoint: Checkpoint<string, string>,
45
+ metadata: CheckpointMetadata,
46
+ newVersions: ChannelVersions,
47
+ ): Promise<RunnableConfig<Record<string, any>>> {
48
+ const newConfig = await mindedRequest<
49
+ RunnableConfig<Record<string, any>>,
50
+ {
51
+ config: RunnableConfig<Record<string, any>>;
52
+ checkpoint: Checkpoint<string, string>;
53
+ metadata: CheckpointMetadata;
54
+ newVersions: ChannelVersions;
55
+ }
56
+ >({
57
+ path: '/checkpoint/put',
58
+ method: 'POST',
59
+ body: { config, checkpoint, metadata, newVersions },
60
+ token: this.token,
61
+ });
62
+
63
+ return newConfig;
64
+ }
65
+
66
+ async putWrites(config: RunnableConfig<Record<string, any>>, writes: PendingWrite[], taskId: string): Promise<void> {
67
+ await mindedRequest<void, { config: RunnableConfig<Record<string, any>>; writes: PendingWrite[]; taskId: string }>({
68
+ path: '/checkpoint/put-writes',
69
+ method: 'POST',
70
+ body: { config, writes, taskId },
71
+ token: this.token,
72
+ });
73
+ }
74
+ }
@@ -0,0 +1,106 @@
1
+ import { io, Socket } from 'socket.io-client';
2
+ import * as readline from 'readline';
3
+ import { BaseMindedConnectionSocketMessage, MindedConnectionSocketMessageType } from './mindedConnectionTypes';
4
+
5
+ export class MindedConnection {
6
+ private socket: Socket | null = null;
7
+ private rl: readline.Interface | null = null;
8
+ listeners: {
9
+ [key: string]: ((message: BaseMindedConnectionSocketMessage) => void)[]
10
+ } = {};
11
+
12
+ constructor() {
13
+ if (!process.env.MINDED_CONNECTION_TOKEN) {
14
+ this.rl = readline.createInterface({
15
+ input: process.stdin,
16
+ output: process.stdout
17
+ });
18
+ }
19
+ }
20
+
21
+ private async getMindedToken(): Promise<string> {
22
+ const envToken = process.env.MINDED_CONNECTION_TOKEN;
23
+
24
+ if (envToken) {
25
+ return envToken;
26
+ }
27
+
28
+ return new Promise((resolve) => {
29
+ this.rl!.question('Enter your Minded connection token: ', (token: string) => {
30
+ resolve(token);
31
+ });
32
+ });
33
+ }
34
+
35
+ public on = (
36
+ event: MindedConnectionSocketMessageType,
37
+ callback: (message: BaseMindedConnectionSocketMessage) => void,
38
+ ) => {
39
+ if (!this.listeners[event]) {
40
+ this.listeners[event] = [];
41
+ }
42
+ this.listeners[event].push(callback);
43
+ };
44
+
45
+
46
+ public emit = (
47
+ event: MindedConnectionSocketMessageType,
48
+ message: BaseMindedConnectionSocketMessage,
49
+ ) => {
50
+ if (this.socket) {
51
+ this.socket.emit(event, message);
52
+ }
53
+ };
54
+
55
+
56
+ public start(): void {
57
+ this.getMindedToken().then(token => {
58
+ this.socket = io('http://localhost:8888', {
59
+ path: '/minded-connect',
60
+ query: {
61
+ token
62
+ }
63
+ });
64
+
65
+ // Connection event handlers
66
+ this.socket.on('connect', () => {
67
+ console.log('\x1b[32mConnection with Minded platform is live!\x1b[0m');
68
+ console.log('\x1b[36mPress Ctrl+C to exit.\x1b[0m');
69
+ });
70
+
71
+ this.socket.on('connect_error', () => {
72
+ console.error('Failed to connect to minded platform');
73
+ });
74
+
75
+ this.socket.on('disconnect', () => {
76
+ console.log('Disconnected from local debugging socket');
77
+
78
+ });
79
+
80
+ // Listen for error messages from the server
81
+ this.socket.on('error', (error: { message: string }) => {
82
+ console.error('Server error:', error.message);
83
+ });
84
+
85
+ // Listen for specific message types
86
+ this.socket.onAny((event, message) => {
87
+ if (this.listeners[event]) {
88
+ this.listeners[event].forEach((listener) => {
89
+ listener(message);
90
+ });
91
+ }
92
+ });
93
+
94
+ // Handle process termination
95
+ process.on('SIGINT', () => {
96
+ if (this.socket?.connected) {
97
+ console.log('\nDisconnecting...');
98
+ this.socket.disconnect();
99
+ }
100
+ process.exit(0);
101
+ });
102
+
103
+ });
104
+
105
+ }
106
+ }
@@ -0,0 +1,15 @@
1
+
2
+ export enum MindedConnectionSocketMessageType {
3
+ OnAppTrigger = 'on-app-trigger',
4
+ }
5
+
6
+ export interface BaseMindedConnectionSocketMessage {
7
+ type: MindedConnectionSocketMessageType;
8
+ }
9
+
10
+ export interface OnAppTrigger extends BaseMindedConnectionSocketMessage {
11
+ name: string;
12
+ body: Record<string, any>;
13
+ }
14
+
15
+
@@ -0,0 +1,28 @@
1
+ import axios from 'axios';
2
+ const baseUrl = 'https://api.minded.com/sdk';
3
+
4
+ type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
5
+
6
+ export const mindedRequest = async <Response, Request = object>({
7
+ path,
8
+ method,
9
+ body,
10
+ token,
11
+ }: {
12
+ path: string;
13
+ method: Method;
14
+ body: Request;
15
+ token: string;
16
+ }): Promise<Response> => {
17
+ const response = await axios({
18
+ method,
19
+ url: `${baseUrl}${path}`,
20
+ data: body,
21
+ headers: {
22
+ 'Content-Type': 'application/json',
23
+ Authorization: `Bearer ${token}`,
24
+ },
25
+ });
26
+
27
+ return response.data;
28
+ };
@@ -0,0 +1,10 @@
1
+ import { AgentEventRequestPayloads, AgentEventResponsePayloads } from "../events/AgentEvents";
2
+ import { LLMConfig } from "./LLM.types";
3
+
4
+ export type EmitSignature<Memory, E extends keyof AgentEventRequestPayloads<Memory>> = (event: E, payload: AgentEventRequestPayloads<Memory>[E]) => Promise<(AgentEventResponsePayloads<Memory>[E])[]>;
5
+
6
+ export type MindedSDKConfig = {
7
+ flows: string[];
8
+ llm: LLMConfig;
9
+ tools: string[];
10
+ }
@@ -0,0 +1,103 @@
1
+ import { LLMConfig } from './LLM.types';
2
+ export interface Position {
3
+ x: number;
4
+ y: number;
5
+ }
6
+
7
+ export enum NodeType {
8
+ TRIGGER = 'trigger',
9
+ JUNCTION = 'junction',
10
+ TOOL = 'tool',
11
+ APP_TOOL = 'appTool',
12
+ PROMPT_NODE = 'promptNode',
13
+ }
14
+
15
+ export enum EdgeType {
16
+ LOGICAL_CONDITION = 'logicalCondition',
17
+ PROMPT_CONDITION = 'promptCondition',
18
+ STEP_FORWARD = 'stepForward',
19
+ }
20
+
21
+ export interface BaseNode {
22
+ name: string;
23
+ type: NodeType;
24
+ position?: Position;
25
+ humanInTheLoop?: boolean;
26
+ canStayOnNode?: boolean;
27
+ }
28
+
29
+ export enum TriggerType {
30
+ APP = 'app',
31
+ WEBHOOK = 'webhook',
32
+ MANUAL = 'manual',
33
+ }
34
+
35
+ export interface BaseTriggerNode extends BaseNode {
36
+ type: NodeType.TRIGGER;
37
+ }
38
+
39
+ export interface AppTriggerNode extends BaseTriggerNode {
40
+ triggerType: TriggerType.APP;
41
+ appTriggerId: string;
42
+ }
43
+
44
+ export interface WebhookTriggerNode extends BaseTriggerNode {
45
+ triggerType: TriggerType.WEBHOOK;
46
+ }
47
+
48
+ export interface ManualTriggerNode extends BaseTriggerNode {
49
+ triggerType: TriggerType.MANUAL;
50
+ }
51
+
52
+ export interface PromptNode extends BaseNode {
53
+ type: NodeType.PROMPT_NODE;
54
+ prompt: string;
55
+ llmConfig?: LLMConfig;
56
+ }
57
+
58
+ export type TriggerNode = AppTriggerNode | WebhookTriggerNode | ManualTriggerNode;
59
+
60
+ export interface JunctionNode extends BaseNode {
61
+ type: NodeType.JUNCTION;
62
+ }
63
+
64
+ export interface ToolNode extends BaseNode {
65
+ type: NodeType.TOOL;
66
+ toolName: string;
67
+ prompt: string;
68
+ }
69
+
70
+ export interface AppToolNode extends BaseNode {
71
+ type: NodeType.APP_TOOL;
72
+ prompt: string;
73
+ }
74
+
75
+ export type Node = TriggerNode | JunctionNode | ToolNode | AppToolNode | PromptNode;
76
+
77
+ export interface BaseEdge {
78
+ source: string;
79
+ target: string;
80
+ type: EdgeType;
81
+ }
82
+
83
+ export interface LogicalConditionEdge extends BaseEdge {
84
+ type: EdgeType.LOGICAL_CONDITION;
85
+ condition: string;
86
+ }
87
+
88
+ export interface PromptConditionEdge extends BaseEdge {
89
+ type: EdgeType.PROMPT_CONDITION;
90
+ prompt: string;
91
+ }
92
+
93
+ export interface StepForwardEdge extends BaseEdge {
94
+ type: EdgeType.STEP_FORWARD;
95
+ }
96
+
97
+ export type Edge = LogicalConditionEdge | PromptConditionEdge | StepForwardEdge;
98
+
99
+ export interface Flow {
100
+ name: string;
101
+ nodes: Node[];
102
+ edges: Edge[];
103
+ }
@@ -0,0 +1,13 @@
1
+ import { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';
2
+
3
+ export type LLMConfig = {
4
+ name: string,
5
+ properties: Record<string, any>
6
+ }
7
+
8
+ export type LLMProvider = 'ChatOpenAI' | 'AzureChatOpenAI';
9
+
10
+ export const LLMProviders = {
11
+ ChatOpenAI: ChatOpenAI,
12
+ AzureChatOpenAI: AzureChatOpenAI,
13
+ }
@@ -0,0 +1,25 @@
1
+ import { BaseMessage } from '@langchain/core/messages';
2
+ import { Annotation, CompiledStateGraph, StateGraph } from '@langchain/langgraph';
3
+
4
+ export const stateAnnotation = Annotation.Root({
5
+ messages: Annotation<Array<BaseMessage>>({
6
+ default: () => [],
7
+ reducer: (a, b) => a.concat(b),
8
+ }),
9
+ memory: Annotation<any>({
10
+ default: () => ({}),
11
+ reducer: (a, b) => ({ ...a, ...b }),
12
+ }),
13
+
14
+ triggerMetadata: Annotation<{
15
+ name: string;
16
+ triggerBody: any;
17
+ } | null>,
18
+ interruptedNode: Annotation<string | null>({
19
+ default: () => null,
20
+ reducer: (a, b) => b,
21
+ }),
22
+ });
23
+
24
+ export type CompiledGraph = CompiledStateGraph<any, any, string>;
25
+ export type PreCompiledGraph = StateGraph<any, any, string>;
@@ -0,0 +1,9 @@
1
+ import { z } from 'zod';
2
+
3
+ export interface Tool<Input extends z.ZodSchema, Memory> {
4
+ name: string;
5
+ description: string;
6
+ input: Input;
7
+ isGlobal?: boolean;
8
+ execute: ({ input, memory }: { input: z.infer<Input>; memory: Memory }) => Promise<{ memory?: Partial<Memory>, result?: any } | void>;
9
+ }
@@ -0,0 +1,148 @@
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
+ stayCount: z.number().optional(),
12
+ });
13
+
14
+ describe('Can 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
+ tools: [toolsPath],
26
+ flows: [flowsPath],
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
+ },
45
+ }),
46
+ },
47
+ ],
48
+ });
49
+
50
+ // Add trigger event handler
51
+ agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
52
+ if (triggerName === 'Trigger') {
53
+ return {
54
+ memory: {},
55
+ messages: [new HumanMessage(triggerBody.message)],
56
+ };
57
+ }
58
+ });
59
+ });
60
+
61
+ it('should stay on the same node multiple times when instructed to stay, then continue', async function () {
62
+ this.timeout(20000); // Set timeout to 40 seconds for this test
63
+
64
+ const sessionId = uuidv4();
65
+
66
+ // First invocation - triggers the flow and reaches the human-in-the-loop pause
67
+ const result1 = await agent.invoke({
68
+ triggerBody: {
69
+ message: 'Initial input for processing',
70
+ },
71
+ triggerName: 'Trigger',
72
+ sessionId,
73
+ });
74
+
75
+ // Should pause at human-in-the-loop, not reach success tool yet
76
+ expect(result1.memory.success).to.not.equal(true);
77
+ expect(result1.messages).to.have.length.greaterThan(0);
78
+
79
+ // Second invocation - provide "stay" instruction
80
+ const result2 = await agent.invoke({
81
+ triggerBody: {
82
+ message: 'stay',
83
+ },
84
+ triggerName: 'Trigger',
85
+ sessionId,
86
+ });
87
+
88
+ // Should stay on the node, pause again, not reach success tool
89
+ expect(result2.memory.success).to.not.equal(true);
90
+ expect(result2.messages).to.have.length.greaterThan(0);
91
+
92
+ // Third invocation - provide another "stay" instruction
93
+ const result3 = await agent.invoke({
94
+ triggerBody: {
95
+ message: 'stay',
96
+ },
97
+ triggerName: 'Trigger',
98
+ sessionId,
99
+ });
100
+
101
+ // Should still stay on the node, pause again
102
+ expect(result3.memory.success).to.not.equal(true);
103
+ expect(result3.messages).to.have.length.greaterThan(0);
104
+
105
+ // Fourth invocation - provide "continue" instruction
106
+ const result4 = await agent.invoke({
107
+ triggerBody: {
108
+ message: 'continue',
109
+ },
110
+ triggerName: 'Trigger',
111
+ sessionId,
112
+ });
113
+
114
+ // Should now move to success tool and complete
115
+ expect(result4.memory.success).to.equal(true);
116
+ });
117
+
118
+ it('should move to next node immediately when instructed to continue', async function () {
119
+ this.timeout(20000); // Set timeout to 20 seconds for this test
120
+
121
+ const sessionId = uuidv4();
122
+
123
+ // First invocation - triggers the flow and reaches the human-in-the-loop pause
124
+ const result1 = await agent.invoke({
125
+ triggerBody: {
126
+ message: 'Initial input for processing',
127
+ },
128
+ triggerName: 'Trigger',
129
+ sessionId,
130
+ });
131
+
132
+ // Should pause at human-in-the-loop, not reach success tool yet
133
+ expect(result1.memory.success).to.not.equal(true);
134
+ expect(result1.messages).to.have.length.greaterThan(0);
135
+
136
+ // Second invocation - provide "continue" instruction
137
+ const result2 = await agent.invoke({
138
+ triggerBody: {
139
+ message: 'continue',
140
+ },
141
+ triggerName: 'Trigger',
142
+ sessionId,
143
+ });
144
+
145
+ // Should now move to success tool and complete
146
+ expect(result2.memory.success).to.equal(true);
147
+ });
148
+ });
@@ -0,0 +1,25 @@
1
+ name: Can Stay On Node Test Flow
2
+ nodes:
3
+ - type: 'trigger'
4
+ triggerType: 'manual'
5
+ name: 'Trigger'
6
+
7
+ - type: 'promptNode'
8
+ name: 'DecisionNode'
9
+ prompt: 'I have processed your input. Would you like me to continue to the next step, or should I stay on this node for further processing? Please respond with "continue" to move forward or "stay" to remain here for additional analysis.'
10
+ canStayOnNode: true
11
+ humanInTheLoop: true
12
+
13
+ - type: 'tool'
14
+ name: 'Success'
15
+ toolName: 'successTool'
16
+
17
+ edges:
18
+ - source: 'Trigger'
19
+ target: 'DecisionNode'
20
+ type: 'stepForward'
21
+
22
+ - source: 'DecisionNode'
23
+ target: 'Success'
24
+ type: 'promptCondition'
25
+ prompt: 'move to success node if the user wants to continue or if processing is complete'