@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.
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +44 -31
- package/dist/agent.js.map +1 -1
- package/dist/browserTask/executeBrowserTask.d.ts +12 -0
- package/dist/browserTask/executeBrowserTask.d.ts.map +1 -0
- package/dist/browserTask/executeBrowserTask.js +181 -0
- package/dist/browserTask/executeBrowserTask.js.map +1 -0
- package/dist/checkpointer/checkpointSaverFactory.js +1 -1
- package/dist/checkpointer/checkpointSaverFactory.js.map +1 -1
- package/dist/cli/index.js +14 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/edges/createDirectEdge.d.ts +2 -1
- package/dist/edges/createDirectEdge.d.ts.map +1 -1
- package/dist/edges/createDirectEdge.js +6 -2
- package/dist/edges/createDirectEdge.js.map +1 -1
- package/dist/edges/createLogicalRouter.d.ts.map +1 -1
- package/dist/edges/createLogicalRouter.js +23 -6
- package/dist/edges/createLogicalRouter.js.map +1 -1
- package/dist/edges/createPromptRouter.d.ts.map +1 -1
- package/dist/edges/createPromptRouter.js +12 -6
- package/dist/edges/createPromptRouter.js.map +1 -1
- package/dist/edges/edgeFactory.d.ts.map +1 -1
- package/dist/edges/edgeFactory.js +8 -3
- package/dist/edges/edgeFactory.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/interrupts/BaseInterruptSessionManager.d.ts +4 -0
- package/dist/interrupts/BaseInterruptSessionManager.d.ts.map +1 -1
- package/dist/interrupts/BaseInterruptSessionManager.js +1 -1
- package/dist/interrupts/BaseInterruptSessionManager.js.map +1 -1
- package/dist/interrupts/MemoryInterruptSessionManager.d.ts +2 -0
- package/dist/interrupts/MemoryInterruptSessionManager.d.ts.map +1 -1
- package/dist/interrupts/MemoryInterruptSessionManager.js +6 -0
- package/dist/interrupts/MemoryInterruptSessionManager.js.map +1 -1
- package/dist/interrupts/MindedInterruptSessionManager.d.ts +2 -0
- package/dist/interrupts/MindedInterruptSessionManager.d.ts.map +1 -1
- package/dist/interrupts/MindedInterruptSessionManager.js +26 -0
- package/dist/interrupts/MindedInterruptSessionManager.js.map +1 -1
- package/dist/interrupts/interruptSessionManagerFactory.js +2 -2
- package/dist/interrupts/interruptSessionManagerFactory.js.map +1 -1
- package/dist/llm/createLlmInstance.d.ts +1 -1
- package/dist/llm/createLlmInstance.d.ts.map +1 -1
- package/dist/llm/createLlmInstance.js +18 -1
- package/dist/llm/createLlmInstance.js.map +1 -1
- package/dist/nodes/addAppToolNode.d.ts.map +1 -1
- package/dist/nodes/addAppToolNode.js +5 -4
- package/dist/nodes/addAppToolNode.js.map +1 -1
- package/dist/nodes/addBrowserTaskNode.d.ts +13 -0
- package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -0
- package/dist/nodes/addBrowserTaskNode.js +232 -0
- package/dist/nodes/addBrowserTaskNode.js.map +1 -0
- package/dist/nodes/addBrowserTaskRunNode.d.ts +13 -0
- package/dist/nodes/addBrowserTaskRunNode.d.ts.map +1 -0
- package/dist/nodes/addBrowserTaskRunNode.js +130 -0
- package/dist/nodes/addBrowserTaskRunNode.js.map +1 -0
- package/dist/nodes/addHumanInTheLoopNode.d.ts.map +1 -1
- package/dist/nodes/addHumanInTheLoopNode.js +1 -1
- package/dist/nodes/addHumanInTheLoopNode.js.map +1 -1
- package/dist/nodes/addJumpToNode.d.ts.map +1 -1
- package/dist/nodes/addJumpToNode.js +2 -1
- package/dist/nodes/addJumpToNode.js.map +1 -1
- package/dist/nodes/addJunctionNode.d.ts.map +1 -1
- package/dist/nodes/addJunctionNode.js +1 -0
- package/dist/nodes/addJunctionNode.js.map +1 -1
- package/dist/nodes/addPromptNode.d.ts.map +1 -1
- package/dist/nodes/addPromptNode.js +7 -17
- package/dist/nodes/addPromptNode.js.map +1 -1
- package/dist/nodes/addToolNode.d.ts.map +1 -1
- package/dist/nodes/addToolNode.js +2 -2
- package/dist/nodes/addToolNode.js.map +1 -1
- package/dist/nodes/addToolRunNode.d.ts.map +1 -1
- package/dist/nodes/addToolRunNode.js +2 -1
- package/dist/nodes/addToolRunNode.js.map +1 -1
- package/dist/nodes/addTriggerNode.d.ts.map +1 -1
- package/dist/nodes/addTriggerNode.js +2 -1
- package/dist/nodes/addTriggerNode.js.map +1 -1
- package/dist/nodes/nodeFactory.d.ts.map +1 -1
- package/dist/nodes/nodeFactory.js +4 -0
- package/dist/nodes/nodeFactory.js.map +1 -1
- package/dist/platform/mindedConnection.js +13 -13
- package/dist/platform/mindedConnection.js.map +1 -1
- package/dist/platform/mindedConnectionTypes.d.ts +3 -1
- package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
- package/dist/platform/mindedConnectionTypes.js +2 -0
- package/dist/platform/mindedConnectionTypes.js.map +1 -1
- package/dist/platform/models/mindedChatOpenAI.d.ts +20 -0
- package/dist/platform/models/mindedChatOpenAI.d.ts.map +1 -0
- package/dist/platform/models/mindedChatOpenAI.js +32 -0
- package/dist/platform/models/mindedChatOpenAI.js.map +1 -0
- package/dist/platform/models/parallelWrapper.d.ts +17 -0
- package/dist/platform/models/parallelWrapper.d.ts.map +1 -0
- package/dist/platform/models/parallelWrapper.js +105 -0
- package/dist/platform/models/parallelWrapper.js.map +1 -0
- package/dist/playbooks/playbooks.js +6 -6
- package/dist/playbooks/playbooks.js.map +1 -1
- package/dist/types/Flows.types.d.ts +18 -3
- package/dist/types/Flows.types.d.ts.map +1 -1
- package/dist/types/Flows.types.js +2 -0
- package/dist/types/Flows.types.js.map +1 -1
- package/dist/types/LLM.types.d.ts.map +1 -1
- package/dist/types/LLM.types.js +1 -1
- package/dist/types/LLM.types.js.map +1 -1
- package/dist/types/LangGraph.types.d.ts +2 -0
- package/dist/types/LangGraph.types.d.ts.map +1 -1
- package/dist/types/LangGraph.types.js +5 -0
- package/dist/types/LangGraph.types.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +1 -2
- package/dist/utils/logger.js.map +1 -1
- package/dist/voice/voiceSession.d.ts.map +1 -1
- package/dist/voice/voiceSession.js +19 -18
- package/dist/voice/voiceSession.js.map +1 -1
- package/docs/SUMMARY.md +1 -0
- package/docs/low-code-editor/nodes.md +27 -0
- package/docs/low-code-editor/tools.md +32 -0
- package/docs/platform/parallel-llm.md +242 -0
- package/package.json +2 -1
- package/src/agent.ts +45 -33
- package/src/browserTask/executeBrowserTask.ts +213 -0
- package/src/checkpointer/checkpointSaverFactory.ts +1 -1
- package/src/cli/index.ts +14 -14
- package/src/edges/createDirectEdge.ts +7 -2
- package/src/edges/createLogicalRouter.ts +23 -6
- package/src/edges/createPromptRouter.ts +13 -6
- package/src/edges/edgeFactory.ts +20 -4
- package/src/index.ts +6 -0
- package/src/interrupts/BaseInterruptSessionManager.ts +5 -2
- package/src/interrupts/MemoryInterruptSessionManager.ts +8 -0
- package/src/interrupts/MindedInterruptSessionManager.ts +25 -0
- package/src/interrupts/interruptSessionManagerFactory.ts +2 -2
- package/src/llm/createLlmInstance.ts +25 -2
- package/src/nodes/addAppToolNode.ts +5 -4
- package/src/nodes/addBrowserTaskNode.ts +231 -0
- package/src/nodes/addBrowserTaskRunNode.ts +144 -0
- package/src/nodes/addHumanInTheLoopNode.ts +2 -1
- package/src/nodes/addJumpToNode.ts +2 -1
- package/src/nodes/addJunctionNode.ts +1 -0
- package/src/nodes/addPromptNode.ts +8 -16
- package/src/nodes/addToolNode.ts +3 -2
- package/src/nodes/addToolRunNode.ts +3 -1
- package/src/nodes/addTriggerNode.ts +2 -1
- package/src/nodes/nodeFactory.ts +5 -1
- package/src/platform/mindedConnection.ts +13 -13
- package/src/platform/mindedConnectionTypes.ts +2 -0
- package/src/platform/models/mindedChatOpenAI.ts +49 -0
- package/src/platform/models/parallelWrapper.ts +141 -0
- package/src/playbooks/playbooks.ts +6 -6
- package/src/types/Flows.types.ts +17 -1
- package/src/types/LLM.types.ts +5 -5
- package/src/types/LangGraph.types.ts +5 -0
- package/src/utils/logger.ts +1 -2
- package/src/voice/voiceSession.ts +20 -19
- 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
|
+
};
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
105
|
+
logger.info({ msg: `Generated Lambda handler at ${outputPath}` });
|
|
106
106
|
|
|
107
107
|
// Compile the index.ts file using TypeScript
|
|
108
|
-
logger.info({
|
|
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({
|
|
141
|
+
logger.info({ msg: `Successfully compiled Lambda handler to ${outDir}/index.js` });
|
|
142
142
|
} catch (compileError) {
|
|
143
|
-
logger.error({
|
|
143
|
+
logger.error({ msg: 'Failed to compile Lambda handler', error: compileError });
|
|
144
144
|
}
|
|
145
145
|
} catch (error) {
|
|
146
|
-
logger.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({
|
|
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({
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
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({
|
|
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({
|
|
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.
|
|
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({
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
201
|
+
msg: '[Router] Prompt router reached max retries, using fallback',
|
|
195
202
|
fallbackNode,
|
|
196
203
|
lastError: lastError.message,
|
|
197
204
|
});
|
package/src/edges/edgeFactory.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import {
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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
|
|
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
|
-
|
|
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
|
};
|