@minded-ai/mindedjs 1.0.103-beta-1 → 1.0.103-beta-4

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 (155) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +44 -31
  3. package/dist/agent.js.map +1 -1
  4. package/dist/browserTask/executeBrowserTask.d.ts +12 -0
  5. package/dist/browserTask/executeBrowserTask.d.ts.map +1 -0
  6. package/dist/browserTask/executeBrowserTask.js +181 -0
  7. package/dist/browserTask/executeBrowserTask.js.map +1 -0
  8. package/dist/checkpointer/checkpointSaverFactory.js +1 -1
  9. package/dist/checkpointer/checkpointSaverFactory.js.map +1 -1
  10. package/dist/cli/index.js +14 -14
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/edges/createDirectEdge.d.ts +2 -1
  13. package/dist/edges/createDirectEdge.d.ts.map +1 -1
  14. package/dist/edges/createDirectEdge.js +6 -2
  15. package/dist/edges/createDirectEdge.js.map +1 -1
  16. package/dist/edges/createLogicalRouter.d.ts.map +1 -1
  17. package/dist/edges/createLogicalRouter.js +23 -6
  18. package/dist/edges/createLogicalRouter.js.map +1 -1
  19. package/dist/edges/createPromptRouter.d.ts.map +1 -1
  20. package/dist/edges/createPromptRouter.js +12 -6
  21. package/dist/edges/createPromptRouter.js.map +1 -1
  22. package/dist/edges/edgeFactory.d.ts.map +1 -1
  23. package/dist/edges/edgeFactory.js +8 -3
  24. package/dist/edges/edgeFactory.js.map +1 -1
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +6 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/interrupts/BaseInterruptSessionManager.d.ts +4 -0
  30. package/dist/interrupts/BaseInterruptSessionManager.d.ts.map +1 -1
  31. package/dist/interrupts/BaseInterruptSessionManager.js +1 -1
  32. package/dist/interrupts/BaseInterruptSessionManager.js.map +1 -1
  33. package/dist/interrupts/MemoryInterruptSessionManager.d.ts +2 -0
  34. package/dist/interrupts/MemoryInterruptSessionManager.d.ts.map +1 -1
  35. package/dist/interrupts/MemoryInterruptSessionManager.js +6 -0
  36. package/dist/interrupts/MemoryInterruptSessionManager.js.map +1 -1
  37. package/dist/interrupts/MindedInterruptSessionManager.d.ts +2 -0
  38. package/dist/interrupts/MindedInterruptSessionManager.d.ts.map +1 -1
  39. package/dist/interrupts/MindedInterruptSessionManager.js +26 -0
  40. package/dist/interrupts/MindedInterruptSessionManager.js.map +1 -1
  41. package/dist/interrupts/interruptSessionManagerFactory.js +2 -2
  42. package/dist/interrupts/interruptSessionManagerFactory.js.map +1 -1
  43. package/dist/llm/createLlmInstance.d.ts +1 -1
  44. package/dist/llm/createLlmInstance.d.ts.map +1 -1
  45. package/dist/llm/createLlmInstance.js +18 -1
  46. package/dist/llm/createLlmInstance.js.map +1 -1
  47. package/dist/nodes/addAppToolNode.d.ts.map +1 -1
  48. package/dist/nodes/addAppToolNode.js +5 -4
  49. package/dist/nodes/addAppToolNode.js.map +1 -1
  50. package/dist/nodes/addBrowserTaskNode.d.ts +13 -0
  51. package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -0
  52. package/dist/nodes/addBrowserTaskNode.js +232 -0
  53. package/dist/nodes/addBrowserTaskNode.js.map +1 -0
  54. package/dist/nodes/addBrowserTaskRunNode.d.ts +13 -0
  55. package/dist/nodes/addBrowserTaskRunNode.d.ts.map +1 -0
  56. package/dist/nodes/addBrowserTaskRunNode.js +130 -0
  57. package/dist/nodes/addBrowserTaskRunNode.js.map +1 -0
  58. package/dist/nodes/addHumanInTheLoopNode.d.ts.map +1 -1
  59. package/dist/nodes/addHumanInTheLoopNode.js +1 -1
  60. package/dist/nodes/addHumanInTheLoopNode.js.map +1 -1
  61. package/dist/nodes/addJumpToNode.d.ts.map +1 -1
  62. package/dist/nodes/addJumpToNode.js +2 -1
  63. package/dist/nodes/addJumpToNode.js.map +1 -1
  64. package/dist/nodes/addJunctionNode.d.ts.map +1 -1
  65. package/dist/nodes/addJunctionNode.js +1 -0
  66. package/dist/nodes/addJunctionNode.js.map +1 -1
  67. package/dist/nodes/addPromptNode.d.ts.map +1 -1
  68. package/dist/nodes/addPromptNode.js +7 -17
  69. package/dist/nodes/addPromptNode.js.map +1 -1
  70. package/dist/nodes/addToolNode.d.ts.map +1 -1
  71. package/dist/nodes/addToolNode.js +2 -2
  72. package/dist/nodes/addToolNode.js.map +1 -1
  73. package/dist/nodes/addToolRunNode.d.ts.map +1 -1
  74. package/dist/nodes/addToolRunNode.js +2 -1
  75. package/dist/nodes/addToolRunNode.js.map +1 -1
  76. package/dist/nodes/addTriggerNode.d.ts.map +1 -1
  77. package/dist/nodes/addTriggerNode.js +2 -1
  78. package/dist/nodes/addTriggerNode.js.map +1 -1
  79. package/dist/nodes/nodeFactory.d.ts.map +1 -1
  80. package/dist/nodes/nodeFactory.js +4 -0
  81. package/dist/nodes/nodeFactory.js.map +1 -1
  82. package/dist/platform/mindedConnection.js +13 -13
  83. package/dist/platform/mindedConnection.js.map +1 -1
  84. package/dist/platform/mindedConnectionTypes.d.ts +3 -1
  85. package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
  86. package/dist/platform/mindedConnectionTypes.js +2 -0
  87. package/dist/platform/mindedConnectionTypes.js.map +1 -1
  88. package/dist/platform/models/mindedChatOpenAI.d.ts +20 -0
  89. package/dist/platform/models/mindedChatOpenAI.d.ts.map +1 -0
  90. package/dist/platform/models/mindedChatOpenAI.js +32 -0
  91. package/dist/platform/models/mindedChatOpenAI.js.map +1 -0
  92. package/dist/platform/models/parallelWrapper.d.ts +17 -0
  93. package/dist/platform/models/parallelWrapper.d.ts.map +1 -0
  94. package/dist/platform/models/parallelWrapper.js +105 -0
  95. package/dist/platform/models/parallelWrapper.js.map +1 -0
  96. package/dist/playbooks/playbooks.js +6 -6
  97. package/dist/playbooks/playbooks.js.map +1 -1
  98. package/dist/types/Flows.types.d.ts +18 -3
  99. package/dist/types/Flows.types.d.ts.map +1 -1
  100. package/dist/types/Flows.types.js +2 -0
  101. package/dist/types/Flows.types.js.map +1 -1
  102. package/dist/types/LLM.types.d.ts.map +1 -1
  103. package/dist/types/LLM.types.js +1 -1
  104. package/dist/types/LLM.types.js.map +1 -1
  105. package/dist/types/LangGraph.types.d.ts +2 -0
  106. package/dist/types/LangGraph.types.d.ts.map +1 -1
  107. package/dist/types/LangGraph.types.js +5 -0
  108. package/dist/types/LangGraph.types.js.map +1 -1
  109. package/dist/utils/logger.d.ts.map +1 -1
  110. package/dist/utils/logger.js +1 -2
  111. package/dist/utils/logger.js.map +1 -1
  112. package/dist/voice/voiceSession.d.ts.map +1 -1
  113. package/dist/voice/voiceSession.js +19 -18
  114. package/dist/voice/voiceSession.js.map +1 -1
  115. package/docs/SUMMARY.md +1 -0
  116. package/docs/low-code-editor/nodes.md +27 -0
  117. package/docs/low-code-editor/tools.md +32 -0
  118. package/docs/platform/parallel-llm.md +242 -0
  119. package/package.json +2 -1
  120. package/src/agent.ts +45 -33
  121. package/src/browserTask/executeBrowserTask.ts +213 -0
  122. package/src/checkpointer/checkpointSaverFactory.ts +1 -1
  123. package/src/cli/index.ts +14 -14
  124. package/src/edges/createDirectEdge.ts +7 -2
  125. package/src/edges/createLogicalRouter.ts +23 -6
  126. package/src/edges/createPromptRouter.ts +13 -6
  127. package/src/edges/edgeFactory.ts +20 -4
  128. package/src/index.ts +6 -0
  129. package/src/interrupts/BaseInterruptSessionManager.ts +5 -2
  130. package/src/interrupts/MemoryInterruptSessionManager.ts +8 -0
  131. package/src/interrupts/MindedInterruptSessionManager.ts +25 -0
  132. package/src/interrupts/interruptSessionManagerFactory.ts +2 -2
  133. package/src/llm/createLlmInstance.ts +25 -2
  134. package/src/nodes/addAppToolNode.ts +5 -4
  135. package/src/nodes/addBrowserTaskNode.ts +231 -0
  136. package/src/nodes/addBrowserTaskRunNode.ts +144 -0
  137. package/src/nodes/addHumanInTheLoopNode.ts +2 -1
  138. package/src/nodes/addJumpToNode.ts +2 -1
  139. package/src/nodes/addJunctionNode.ts +1 -0
  140. package/src/nodes/addPromptNode.ts +8 -16
  141. package/src/nodes/addToolNode.ts +3 -2
  142. package/src/nodes/addToolRunNode.ts +3 -1
  143. package/src/nodes/addTriggerNode.ts +2 -1
  144. package/src/nodes/nodeFactory.ts +5 -1
  145. package/src/platform/mindedConnection.ts +13 -13
  146. package/src/platform/mindedConnectionTypes.ts +2 -0
  147. package/src/platform/models/mindedChatOpenAI.ts +49 -0
  148. package/src/platform/models/parallelWrapper.ts +141 -0
  149. package/src/playbooks/playbooks.ts +6 -6
  150. package/src/types/Flows.types.ts +17 -1
  151. package/src/types/LLM.types.ts +5 -5
  152. package/src/types/LangGraph.types.ts +5 -0
  153. package/src/utils/logger.ts +1 -2
  154. package/src/voice/voiceSession.ts +20 -19
  155. package/src/platform/mindedChatOpenAI.ts +0 -19
@@ -0,0 +1,213 @@
1
+ import { logger } from '../utils/logger';
2
+
3
+ // Browser Use Cloud API configuration
4
+ const BROWSER_USE_API_BASE_URL = 'https://api.browser-use.com/api/v1';
5
+
6
+ // Types for Browser Use Cloud API
7
+ export interface CloudTaskResponse {
8
+ id: string;
9
+ status: string;
10
+ live_url?: string;
11
+ steps?: any[];
12
+ output?: string;
13
+ }
14
+
15
+ // Browser Use Cloud API methods
16
+ export const createCloudTask = async (prompt: string, model?: string): Promise<string> => {
17
+ const apiKey = process.env.BROWSER_USE_API_KEY;
18
+ if (!apiKey) {
19
+ throw new Error('BROWSER_USE_API_KEY environment variable is required');
20
+ }
21
+
22
+ logger.debug({ msg: 'Creating cloud browser task', prompt: prompt.substring(0, 100) + '...' });
23
+
24
+ const response = await fetch(`${BROWSER_USE_API_BASE_URL}/run-task`, {
25
+ method: 'POST',
26
+ headers: {
27
+ Authorization: `Bearer ${apiKey}`,
28
+ 'Content-Type': 'application/json',
29
+ },
30
+ body: JSON.stringify({
31
+ task: prompt,
32
+ use_proxy: false,
33
+ llm_model: model || 'gpt-4o',
34
+ }),
35
+ });
36
+
37
+ if (!response.ok) {
38
+ logger.error({ msg: 'Failed to create cloud browser task', status: response.status, statusText: response.statusText });
39
+ throw new Error(`Failed to create browser task: ${response.statusText}`);
40
+ }
41
+
42
+ const data = await response.json();
43
+ logger.debug({ msg: 'Cloud browser task created', taskId: data.id });
44
+ return data.id;
45
+ };
46
+
47
+ export const getTaskDetails = async (taskId: string): Promise<CloudTaskResponse> => {
48
+ const apiKey = process.env.BROWSER_USE_API_KEY;
49
+ if (!apiKey) {
50
+ throw new Error('BROWSER_USE_API_KEY environment variable is required');
51
+ }
52
+
53
+ const response = await fetch(`${BROWSER_USE_API_BASE_URL}/task/${taskId}`, {
54
+ headers: {
55
+ Authorization: `Bearer ${apiKey}`,
56
+ },
57
+ });
58
+
59
+ if (!response.ok) {
60
+ logger.error({ msg: 'Failed to get task details', taskId, status: response.status, statusText: response.statusText });
61
+ throw new Error(`Failed to get task details: ${response.statusText}`);
62
+ }
63
+
64
+ return response.json();
65
+ };
66
+
67
+ export const waitForLiveUrl = async (taskId: string, maxWaitTime: number = 30000): Promise<CloudTaskResponse> => {
68
+ const startTime = Date.now();
69
+ const pollInterval = 2000; // 2 seconds
70
+ let pollCount = 0;
71
+
72
+ logger.debug({ msg: 'Starting to poll for live_url', taskId, maxWaitTime, pollInterval });
73
+
74
+ while (Date.now() - startTime < maxWaitTime) {
75
+ pollCount++;
76
+ const elapsedTime = Date.now() - startTime;
77
+
78
+ logger.trace({
79
+ msg: 'Polling for live_url',
80
+ taskId,
81
+ pollCount,
82
+ elapsedTime,
83
+ remainingTime: maxWaitTime - elapsedTime,
84
+ });
85
+
86
+ const taskDetails = await getTaskDetails(taskId);
87
+
88
+ logger.trace({
89
+ msg: 'Task details received',
90
+ taskId,
91
+ status: taskDetails.status,
92
+ hasLiveUrl: !!taskDetails.live_url,
93
+ pollCount,
94
+ });
95
+
96
+ if (taskDetails.live_url) {
97
+ logger.debug({
98
+ msg: 'Live URL available',
99
+ taskId,
100
+ liveUrl: taskDetails.live_url,
101
+ pollCount,
102
+ totalTime: elapsedTime,
103
+ });
104
+ return taskDetails;
105
+ }
106
+
107
+ if (taskDetails.status === 'failed' || taskDetails.status === 'stopped') {
108
+ logger.error({
109
+ msg: 'Task failed while waiting for live_url',
110
+ taskId,
111
+ status: taskDetails.status,
112
+ pollCount,
113
+ elapsedTime,
114
+ });
115
+ throw new Error(`Task failed with status: ${taskDetails.status}`);
116
+ }
117
+
118
+ logger.trace({
119
+ msg: 'Live URL not yet available, continuing to poll',
120
+ taskId,
121
+ status: taskDetails.status,
122
+ pollCount,
123
+ nextPollIn: pollInterval,
124
+ });
125
+
126
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
127
+ }
128
+
129
+ logger.error({
130
+ msg: 'Timeout waiting for live_url',
131
+ taskId,
132
+ pollCount,
133
+ totalTime: Date.now() - startTime,
134
+ maxWaitTime,
135
+ });
136
+ throw new Error('Timeout waiting for live_url to become available');
137
+ };
138
+
139
+ export const waitForCompletion = async (taskId: string, maxWaitTime: number = 300000): Promise<CloudTaskResponse> => {
140
+ const startTime = Date.now();
141
+ const pollInterval = 3000; // 3 seconds for completion polling
142
+ let pollCount = 0;
143
+
144
+ logger.debug({ msg: 'Starting to poll for task completion', taskId, maxWaitTime, pollInterval });
145
+
146
+ while (Date.now() - startTime < maxWaitTime) {
147
+ pollCount++;
148
+ const elapsedTime = Date.now() - startTime;
149
+
150
+ logger.trace({
151
+ msg: 'Polling for task completion',
152
+ taskId,
153
+ pollCount,
154
+ elapsedTime,
155
+ remainingTime: maxWaitTime - elapsedTime,
156
+ });
157
+
158
+ const taskDetails = await getTaskDetails(taskId);
159
+
160
+ logger.trace({
161
+ msg: 'Task completion status received',
162
+ taskId,
163
+ status: taskDetails.status,
164
+ pollCount,
165
+ hasOutput: !!taskDetails.output,
166
+ stepCount: taskDetails.steps?.length || 0,
167
+ });
168
+
169
+ if (taskDetails.status === 'finished') {
170
+ logger.debug({
171
+ msg: 'Task completed successfully',
172
+ taskId,
173
+ pollCount,
174
+ totalTime: elapsedTime,
175
+ stepCount: taskDetails.steps?.length || 0,
176
+ hasOutput: !!taskDetails.output,
177
+ });
178
+ return taskDetails;
179
+ }
180
+
181
+ if (taskDetails.status === 'failed' || taskDetails.status === 'stopped') {
182
+ logger.error({
183
+ msg: 'Task failed during completion polling',
184
+ taskId,
185
+ status: taskDetails.status,
186
+ pollCount,
187
+ elapsedTime,
188
+ stepCount: taskDetails.steps?.length || 0,
189
+ });
190
+ throw new Error(`Task failed with status: ${taskDetails.status}`);
191
+ }
192
+
193
+ logger.trace({
194
+ msg: 'Task still in progress, continuing to poll',
195
+ taskId,
196
+ status: taskDetails.status,
197
+ pollCount,
198
+ stepCount: taskDetails.steps?.length || 0,
199
+ nextPollIn: pollInterval,
200
+ });
201
+
202
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
203
+ }
204
+
205
+ logger.error({
206
+ msg: 'Timeout waiting for task completion',
207
+ taskId,
208
+ pollCount,
209
+ totalTime: Date.now() - startTime,
210
+ maxWaitTime,
211
+ });
212
+ throw new Error('Timeout waiting for task completion');
213
+ };
@@ -13,6 +13,6 @@ export function createCheckpointSaver(): BaseCheckpointSaver {
13
13
  return new MemorySaver();
14
14
  }
15
15
 
16
- logger.debug('Using remote checkpoint saver');
16
+ logger.debug('[Agent] Using remote checkpoint saver');
17
17
  return new MindedCheckpointSaver();
18
18
  }
package/src/cli/index.ts CHANGED
@@ -19,7 +19,7 @@ function setToken(token: string): void {
19
19
  if (!fs.existsSync(envPath)) {
20
20
  // Create .env file with the token
21
21
  fs.writeFileSync(envPath, tokenLine + '\n');
22
- logger.info({ message: `Created ${envPath} and added token` });
22
+ logger.info({ msg: `Created ${envPath} and added token` });
23
23
  } else {
24
24
  // Read existing .env file
25
25
  const envContent = fs.readFileSync(envPath, 'utf8');
@@ -29,12 +29,12 @@ function setToken(token: string): void {
29
29
  // Replace existing token
30
30
  const updatedContent = envContent.replace(/MINDED_CONNECTION_TOKEN=.*/, tokenLine);
31
31
  fs.writeFileSync(envPath, updatedContent);
32
- logger.info({ message: `Updated MINDED_CONNECTION_TOKEN in ${envPath}` });
32
+ logger.info({ msg: `Updated MINDED_CONNECTION_TOKEN in ${envPath}` });
33
33
  } else {
34
34
  // Append token to existing file
35
35
  const newContent = envContent.endsWith('\n') ? envContent + tokenLine + '\n' : envContent + '\n' + tokenLine + '\n';
36
36
  fs.writeFileSync(envPath, newContent);
37
- logger.info({ message: `Added MINDED_CONNECTION_TOKEN to ${envPath}` });
37
+ logger.info({ msg: `Added MINDED_CONNECTION_TOKEN to ${envPath}` });
38
38
  }
39
39
  }
40
40
  }
@@ -44,7 +44,7 @@ function generateLambdaHandler(): void {
44
44
 
45
45
  // Check if minded.json exists
46
46
  if (!fs.existsSync(mindedConfigPath)) {
47
- logger.error({ message: 'minded.json not found in the current directory' });
47
+ logger.error({ msg: 'minded.json not found in the current directory' });
48
48
  process.exit(1);
49
49
  }
50
50
 
@@ -54,14 +54,14 @@ function generateLambdaHandler(): void {
54
54
  const configContent = fs.readFileSync(mindedConfigPath, 'utf8');
55
55
  mindedConfig = JSON.parse(configContent);
56
56
  } catch (error) {
57
- logger.error({ message: 'Failed to read or parse minded.json:', error });
57
+ logger.error({ msg: 'Failed to read or parse minded.json:', error });
58
58
  process.exit(1);
59
59
  }
60
60
 
61
61
  // Get the agent path
62
62
  const agentPath = mindedConfig.agent;
63
63
  if (!agentPath) {
64
- logger.error({ message: 'No agent path found in minded.json' });
64
+ logger.error({ msg: 'No agent path found in minded.json' });
65
65
  process.exit(1);
66
66
  }
67
67
 
@@ -91,7 +91,7 @@ function generateLambdaHandler(): void {
91
91
  }
92
92
 
93
93
  if (!templateContent) {
94
- logger.error({ message: 'Could not find Lambda handler template file' });
94
+ logger.error({ msg: 'Could not find Lambda handler template file' });
95
95
  process.exit(1);
96
96
  }
97
97
 
@@ -102,10 +102,10 @@ function generateLambdaHandler(): void {
102
102
  // Write the Lambda handler to index.ts at the root
103
103
  const outputPath = path.join(process.cwd(), 'index.ts');
104
104
  fs.writeFileSync(outputPath, templateContent);
105
- logger.info({ message: `Generated Lambda handler at ${outputPath}` });
105
+ logger.info({ msg: `Generated Lambda handler at ${outputPath}` });
106
106
 
107
107
  // Compile the index.ts file using TypeScript
108
- logger.info({ message: 'Compiling the Lambda handler...' });
108
+ logger.info({ msg: 'Compiling the Lambda handler...' });
109
109
 
110
110
  try {
111
111
  // Read tsconfig.json to get the outDir
@@ -138,12 +138,12 @@ function generateLambdaHandler(): void {
138
138
  cwd: process.cwd(),
139
139
  });
140
140
 
141
- logger.info({ message: `Successfully compiled Lambda handler to ${outDir}/index.js` });
141
+ logger.info({ msg: `Successfully compiled Lambda handler to ${outDir}/index.js` });
142
142
  } catch (compileError) {
143
- logger.error({ message: 'Failed to compile Lambda handler', error: compileError });
143
+ logger.error({ msg: 'Failed to compile Lambda handler', error: compileError });
144
144
  }
145
145
  } catch (error) {
146
- logger.error({ message: 'Failed to generate Lambda handler', error: error });
146
+ logger.error({ msg: 'Failed to generate Lambda handler', error: error });
147
147
  process.exit(1);
148
148
  }
149
149
  }
@@ -155,14 +155,14 @@ function main() {
155
155
  if (command === 'token') {
156
156
  const token = args[1];
157
157
  if (!token) {
158
- logger.error({ message: 'Please provide a token' });
158
+ logger.error({ msg: 'Please provide a token' });
159
159
  process.exit(1);
160
160
  }
161
161
  setToken(token);
162
162
  } else if (command === 'generate-lambda-ts-handler') {
163
163
  generateLambdaHandler();
164
164
  } else {
165
- logger.error({ message: 'Unknown command. Available commands: token, generate-lambda-ts-handler' });
165
+ logger.error({ msg: 'Unknown command. Available commands: token, generate-lambda-ts-handler' });
166
166
  process.exit(1);
167
167
  }
168
168
  }
@@ -1,11 +1,16 @@
1
1
  import { StepForwardEdge } from '../types/Flows.types';
2
+ import { stateAnnotation } from '../types/LangGraph.types';
2
3
  import { logger } from '../utils/logger';
3
4
 
4
5
  export const createDirectEdge = (edge: StepForwardEdge) => {
5
- return async () => {
6
+ return async (state: typeof stateAnnotation.State) => {
7
+ if (state.goto) {
8
+ console.log('Jumping to node', state.goto);
9
+ return state.goto;
10
+ }
6
11
  // For direct edges, we just return the target of the first edge
7
12
  // since there's no conditional logic needed
8
- logger.info({ message: `Executing edge ${JSON.stringify(edge)}` });
13
+ logger.info({ msg: `[Router] Direct edge`, target: edge.target });
9
14
  return edge.target;
10
15
  };
11
16
  };
@@ -8,7 +8,12 @@ const CONDITION_TIMEOUT = 5000; // 5 seconds
8
8
 
9
9
  export const createLogicalRouter = ({ edges }: { edges: LogicalConditionEdge[] }) => {
10
10
  return async (state: typeof stateAnnotation.State) => {
11
- logger.debug(`Evaluating logical conditions for ${edges.length} edges`);
11
+ logger.debug({ msg: `[Router] Evaluating logical conditions for ${edges.length} edges` });
12
+
13
+ if (state.goto) {
14
+ console.log('Jumping to node', state.goto);
15
+ return state.goto;
16
+ }
12
17
 
13
18
  // Separate regular conditions from "else" conditions
14
19
  const regularEdges = edges.filter((edge) => edge.condition.trim() !== 'else');
@@ -59,7 +64,16 @@ export const createLogicalRouter = ({ edges }: { edges: LogicalConditionEdge[] }
59
64
  ]);
60
65
 
61
66
  if (result === true) {
62
- logger.info({ message: `Condition matched for edge ${edge.source} ${edge.target}` });
67
+ if (edge.source == edge.target) {
68
+ logger.info({ msg: `[Router] Stay at node ${edge.source}`, node: edge.source, condition: edge.condition });
69
+ } else {
70
+ logger.info({
71
+ msg: `[Router] Logical condition matched`,
72
+ transitionFrom: edge.source,
73
+ transitionTo: edge.target,
74
+ condition: edge.condition,
75
+ });
76
+ }
63
77
  return edge.target;
64
78
  }
65
79
  } catch (error) {
@@ -68,7 +82,7 @@ export const createLogicalRouter = ({ edges }: { edges: LogicalConditionEdge[] }
68
82
  const conditionPreview = edge.condition.length > 100 ? `${edge.condition.substring(0, 100)}...` : edge.condition;
69
83
 
70
84
  logger.error({
71
- message: `Error evaluating condition for edge ${edge.source} → ${edge.target}`,
85
+ msg: `[Router] Error evaluating condition for edge ${edge.source} → ${edge.target}`,
72
86
  condition: conditionPreview,
73
87
  error: errorMessage,
74
88
  edgeIndex: edges.indexOf(edge),
@@ -83,15 +97,18 @@ export const createLogicalRouter = ({ edges }: { edges: LogicalConditionEdge[] }
83
97
 
84
98
  // If no regular conditions matched, check for "else" conditions
85
99
  if (elseEdges.length > 0) {
86
- logger.info({ message: `No regular conditions matched, evaluating ${elseEdges.length} else condition(s)` });
87
100
  // Return the first "else" condition's target
88
101
  const elseEdge = elseEdges[0];
89
- logger.info({ message: `Else condition matched for edge ${elseEdge.source} → ${elseEdge.target}`, edge: elseEdge });
102
+ logger.info({
103
+ msg: `[Router] Else condition matched`,
104
+ transitionFrom: elseEdge.source,
105
+ transitionTo: elseEdge.target,
106
+ });
90
107
  return elseEdge.target;
91
108
  }
92
109
 
93
110
  // If no conditions matched or all failed, return to the source node
94
- logger.info({ message: 'No conditions matched' });
111
+ logger.info({ msg: `[Router] Stay at node ${edges[0].source}, no conditions matched`, node: edges[0].source });
95
112
  return null;
96
113
  };
97
114
  };
@@ -70,11 +70,19 @@ export const createPromptRouter = ({
70
70
  currentNodeName?: string;
71
71
  }) => {
72
72
  return async (state: typeof stateAnnotation.State) => {
73
- logger.info({ message: `Executing prompt router. Edges: ${JSON.stringify(edges)}` });
73
+ logger.debug({ msg: `[Router] Executing prompt router`, edges: JSON.stringify(edges) });
74
+
75
+ if (state.goto) {
76
+ console.log('Jumping to node', state.goto);
77
+ return state.goto;
78
+ }
74
79
 
75
80
  // If canStayInCurrentNode is true and there are no edges, return current node immediately
76
81
  if (canStayInCurrentNode && edges.length === 0 && currentNodeName) {
77
- logger.info({ message: `No edges available and canStayInCurrentNode is true, staying in current node: ${currentNodeName}` });
82
+ logger.info({
83
+ msg: `[Router] Stay at node, No edges available and canStayInCurrentNode==true`,
84
+ node: currentNodeName,
85
+ });
78
86
  return currentNodeName;
79
87
  }
80
88
 
@@ -174,14 +182,13 @@ export const createPromptRouter = ({
174
182
 
175
183
  const decision = validatedResponse.nextNodeId === currentNodeName ? 'stay in current node' : validatedResponse.nextNodeId;
176
184
  const reasoning = includeReasoning && 'reasoning' in validatedResponse ? ` - Reasoning: ${validatedResponse.reasoning}` : '';
177
- logger.info({ message: `Router decision: ${decision}`, reasoning });
185
+ logger.debug({ msg: `[Router] Decision: ${decision}`, reasoning });
178
186
 
179
187
  return validatedResponse.nextNodeId;
180
188
  } catch (error) {
181
189
  lastError = error instanceof Error ? error : new Error(String(error));
182
190
  logger.warn({
183
- message: `Prompt router attempt ${attempts} failed`,
184
- edge: edges,
191
+ msg: `[Router] Prompt router attempt ${attempts} failed`,
185
192
  error: lastError.message,
186
193
  attempt: attempts,
187
194
  maxRetries,
@@ -191,7 +198,7 @@ export const createPromptRouter = ({
191
198
  // If all retries failed, return the first available edge as fallback
192
199
  const fallbackNode = edges[0]?.target;
193
200
  logger.error({
194
- message: 'Prompt router reached max retries, using fallback',
201
+ msg: '[Router] Prompt router reached max retries, using fallback',
195
202
  fallbackNode,
196
203
  lastError: lastError.message,
197
204
  });
@@ -1,4 +1,14 @@
1
- import { Edge, EdgeType, Node, PromptConditionEdge, LogicalConditionEdge, StepForwardEdge, NodeType, ToolNode } from '../types/Flows.types';
1
+ import {
2
+ Edge,
3
+ EdgeType,
4
+ Node,
5
+ PromptConditionEdge,
6
+ LogicalConditionEdge,
7
+ StepForwardEdge,
8
+ NodeType,
9
+ ToolNode,
10
+ BrowserTaskNode,
11
+ } from '../types/Flows.types';
2
12
  import { PreCompiledGraph } from '../types/LangGraph.types';
3
13
  import { BaseLanguageModel } from '@langchain/core/language_models/base';
4
14
  import { createPromptRouter } from './createPromptRouter';
@@ -6,6 +16,7 @@ import { createLogicalRouter } from './createLogicalRouter';
6
16
  import { createDirectEdge } from './createDirectEdge';
7
17
  import { addHumanInTheLoopNode, buildHumanInTheLoopNodeName } from '../nodes/addHumanInTheLoopNode';
8
18
  import { addToolRunNode, buildToolRunNodeName } from '../nodes/addToolRunNode';
19
+ import { addBrowserTaskRunNode, buildBrowserTaskRunNodeName } from '../nodes/addBrowserTaskRunNode';
9
20
  import { Tool } from '../types/Tools.types';
10
21
  import { Agent } from '../agent';
11
22
  import { logger } from '../utils/logger';
@@ -39,7 +50,7 @@ export const edgeFactory = ({
39
50
  // Priority 1: Step forward edge (max 1)
40
51
  if (edgesBySource.stepForward) {
41
52
  const directRouter = createDirectEdge(edgesBySource.stepForward);
42
- return await directRouter();
53
+ return await directRouter(state);
43
54
  }
44
55
 
45
56
  // Priority 2: Logical condition edges
@@ -49,7 +60,7 @@ export const edgeFactory = ({
49
60
  if (result) {
50
61
  return result;
51
62
  } else {
52
- logger.debug({ message: 'No logical conditions matched, continuing to prompt conditions' });
63
+ logger.debug({ msg: 'No logical conditions matched, continuing to prompt conditions' });
53
64
  }
54
65
  }
55
66
 
@@ -69,7 +80,7 @@ export const edgeFactory = ({
69
80
 
70
81
  // Fallback: stay at current source node
71
82
  const source = originalNode?.name || sourceNode;
72
- logger.info({ message: `No conditions matched, returning to source: ${source}` });
83
+ logger.info({ msg: `No conditions matched, returning to source: ${source}` });
73
84
  return source;
74
85
  };
75
86
  };
@@ -92,6 +103,11 @@ export const edgeFactory = ({
92
103
  effectiveSource = buildToolRunNodeName(source);
93
104
  }
94
105
 
106
+ if (originalNode?.type === NodeType.BROWSER_TASK) {
107
+ addBrowserTaskRunNode({ graph, browserTaskNode: originalNode as BrowserTaskNode, attachedToNodeName: source, agent });
108
+ effectiveSource = buildBrowserTaskRunNodeName(source);
109
+ }
110
+
95
111
  // Create and add the combined conditional edge with original node reference
96
112
  const combinedRouter = createCombinedRouter(effectiveSource, edgesBySource, originalNode);
97
113
  graph.addConditionalEdges(effectiveSource as any, combinedRouter);
package/src/index.ts CHANGED
@@ -7,6 +7,12 @@ import { resetTimer, cancelTimer, onTimer } from './internalTools/timer';
7
7
  export type { ElevenLabsContext } from './types/Voice.types';
8
8
  export { Agent, events, logger, sendPlaceholderMessage, resetTimer, cancelTimer, onTimer };
9
9
 
10
+ // Export LLM implementations
11
+ export { MindedChatOpenAI } from './platform/models/mindedChatOpenAI';
12
+ export { createParallelWrapper } from './platform/models/parallelWrapper';
13
+ export type { MindedChatOpenAIFields, BaseParallelChatFields } from './platform/models/mindedChatOpenAI';
14
+ export type { BaseParallelChatFields as ParallelWrapperFields } from './platform/models/parallelWrapper';
15
+
10
16
  // HTTP module for PII masking - only public API
11
17
  export type { PIIGatewayInstance, HttpRequestConfig, HttpResponse } from './platform/piiGateway';
12
18
 
@@ -41,6 +41,8 @@ export interface InterruptSessionManager {
41
41
  dequeueAll(sessionId: string): QueuedMessage[] | Promise<QueuedMessage[]>;
42
42
  dequeue(sessionId: string): QueuedMessage | null | Promise<QueuedMessage | null>;
43
43
  checkQueueAndInterrupt(sessionId: string, updateStateObject?: Partial<State>): Promise<boolean>;
44
+ interrupt(sessionId: string): void | Promise<void>;
45
+ isInterrupted(sessionId: string): boolean | Promise<boolean>;
44
46
  }
45
47
 
46
48
  export abstract class BaseInterruptSessionManager implements InterruptSessionManager {
@@ -59,7 +61,8 @@ export abstract class BaseInterruptSessionManager implements InterruptSessionMan
59
61
  abstract enqueueMessage(sessionId: string, message: QueuedMessage): void | Promise<void>;
60
62
  abstract dequeueAll(sessionId: string): QueuedMessage[] | Promise<QueuedMessage[]>;
61
63
  abstract dequeue(sessionId: string): QueuedMessage | null | Promise<QueuedMessage | null>;
62
-
64
+ abstract interrupt(sessionId: string): void | Promise<void>;
65
+ abstract isInterrupted(sessionId: string): boolean | Promise<boolean>;
63
66
  // Abstract method to check if queue has messages - this is the only queue-specific part
64
67
  protected abstract hasQueuedMessages(sessionId: string): boolean | Promise<boolean>;
65
68
  protected abstract getQueuedMessages(sessionId: string): QueuedMessage[] | Promise<QueuedMessage[]>;
@@ -67,7 +70,7 @@ export abstract class BaseInterruptSessionManager implements InterruptSessionMan
67
70
  // Common implementation of checkQueueAndInterrupt
68
71
  async checkQueueAndInterrupt(sessionId: string, updateStateObject?: Partial<State>): Promise<boolean> {
69
72
  if (await this.hasQueuedMessages(sessionId)) {
70
- logger.trace({ message: 'graph has queued messagess, interrupting graph', sessionId });
73
+ logger.trace({ msg: 'graph has queued messagess, interrupting graph', sessionId });
71
74
 
72
75
  // Interrupt the graph with NEW_TRIGGERS flag and optional updateStateObject
73
76
  const interruptPayload: InterruptPayload = { type: InterruptType.NEW_TRIGGERS };
@@ -4,6 +4,14 @@ export class MemoryInterruptSessionManager extends BaseInterruptSessionManager {
4
4
  private sessionProcessing: Map<string, boolean> = new Map();
5
5
  private sessionMessageQueues: Map<string, QueuedMessage[]> = new Map();
6
6
 
7
+ interrupt(sessionId: string): void {
8
+ this.sessionProcessing.set(sessionId, true);
9
+ }
10
+
11
+ isInterrupted(sessionId: string): boolean {
12
+ return this.sessionProcessing.get(sessionId) || false;
13
+ }
14
+
7
15
  isProcessed(sessionId: string): boolean {
8
16
  return this.sessionProcessing.get(sessionId) || false;
9
17
  }
@@ -88,6 +88,31 @@ export class MindedInterruptSessionManager extends BaseInterruptSessionManager {
88
88
  }
89
89
  }
90
90
 
91
+ async isInterrupted(sessionId: string): Promise<boolean> {
92
+ try {
93
+ const response = await mindedConnection.awaitEmit<any, any>(mindedConnectionSocketMessageType.INTERRUPT_SESSION_IS_INTERRUPTED, {
94
+ type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_IS_INTERRUPTED,
95
+ sessionId,
96
+ });
97
+ return response.isInterrupted ?? false;
98
+ } catch (error) {
99
+ console.error('Error checking if session is interrupted:', error);
100
+ return false;
101
+ }
102
+ }
103
+
104
+ async interrupt(sessionId: string): Promise<void> {
105
+ try {
106
+ await mindedConnection.awaitEmit<any, any>(mindedConnectionSocketMessageType.INTERRUPT_SESSION_INTERRUPT, {
107
+ type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_INTERRUPT,
108
+ sessionId,
109
+ });
110
+ } catch (error) {
111
+ console.error('Error interrupting session:', error);
112
+ throw error;
113
+ }
114
+ }
115
+
91
116
  async dequeueAll(sessionId: string): Promise<QueuedMessage[]> {
92
117
  try {
93
118
  const response = await mindedConnection.awaitEmit<InterruptSessionDequeueAllRequest, InterruptSessionDequeueAllResponse>(
@@ -8,13 +8,13 @@ import { logger } from '../utils/logger';
8
8
  export function createInterruptSessionManager(): InterruptSessionManager {
9
9
  const { runLocally } = getConfig();
10
10
  if (runLocally) {
11
- logger.info({ message: 'Using memory interrupt session manager' });
11
+ logger.info({ msg: 'Using memory interrupt session manager' });
12
12
  return new MemoryInterruptSessionManager();
13
13
  } else {
14
14
  if (!mindedConnection.isConnected()) {
15
15
  throw new Error('MindedConnection is required for platform interrupt session manager');
16
16
  }
17
- logger.info({ message: 'Using Minded interrupt session manager' });
17
+ logger.info({ msg: 'Using Minded interrupt session manager' });
18
18
  return new MindedInterruptSessionManager();
19
19
  }
20
20
  }
@@ -1,4 +1,5 @@
1
- import { LLMConfig, LLMProviders, LLMProvider } from "../types/LLM.types";
1
+ import { LLMConfig, LLMProviders, LLMProvider } from '../types/LLM.types';
2
+ import { createParallelWrapper, BaseParallelChatFields } from '../platform/models/parallelWrapper';
2
3
 
3
4
  export const createLlmInstance = (llmConfig: LLMConfig) => {
4
5
  const { name, properties } = llmConfig;
@@ -6,5 +7,27 @@ export const createLlmInstance = (llmConfig: LLMConfig) => {
6
7
  if (!LLMClass) {
7
8
  throw new Error(`Unsupported LLM provider: ${name}`);
8
9
  }
9
- return new LLMClass(properties);
10
+
11
+ // Create the base LLM instance
12
+ const llmInstance = new LLMClass(properties);
13
+
14
+ // Check if parallel configuration is present
15
+ const hasParallelConfig = properties.numParallelRequests && properties.numParallelRequests > 1;
16
+
17
+ // For MindedChatOpenAI, parallel functionality is handled on the backend
18
+ if (name === 'MindedChatOpenAI') {
19
+ return llmInstance;
20
+ }
21
+
22
+ // For other LLM providers, apply client-side parallel wrapper if configured
23
+ if (hasParallelConfig) {
24
+ const parallelOptions: BaseParallelChatFields = {
25
+ numParallelRequests: properties.numParallelRequests,
26
+ logTimings: properties.logTimings,
27
+ };
28
+
29
+ return createParallelWrapper(llmInstance, parallelOptions);
30
+ }
31
+
32
+ return llmInstance;
10
33
  };