@minded-ai/mindedjs 1.0.128 → 1.0.130
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 +7 -4
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +45 -72
- package/dist/agent.js.map +1 -1
- package/dist/browserTask/executeBrowserTask.d.ts +2 -13
- package/dist/browserTask/executeBrowserTask.d.ts.map +1 -1
- package/dist/browserTask/executeBrowserTask.js +9 -180
- package/dist/browserTask/executeBrowserTask.js.map +1 -1
- package/dist/debugging/index.d.ts +2 -0
- package/dist/debugging/index.d.ts.map +1 -0
- package/dist/debugging/index.js +6 -0
- package/dist/debugging/index.js.map +1 -0
- package/dist/debugging/llmCallbackHandler.d.ts +83 -0
- package/dist/debugging/llmCallbackHandler.d.ts.map +1 -0
- package/dist/debugging/llmCallbackHandler.js +102 -0
- package/dist/debugging/llmCallbackHandler.js.map +1 -0
- package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -1
- package/dist/nodes/addBrowserTaskNode.js +2 -1
- package/dist/nodes/addBrowserTaskNode.js.map +1 -1
- package/dist/nodes/addBrowserTaskRunNode.d.ts +1 -1
- package/dist/nodes/addBrowserTaskRunNode.d.ts.map +1 -1
- package/dist/nodes/addBrowserTaskRunNode.js +10 -2
- package/dist/nodes/addBrowserTaskRunNode.js.map +1 -1
- package/dist/platform/mindedConnectionTypes.d.ts +28 -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/toolExecutor.d.ts +29 -0
- package/dist/platform/toolExecutor.d.ts.map +1 -0
- package/dist/platform/toolExecutor.js +95 -0
- package/dist/platform/toolExecutor.js.map +1 -0
- package/dist/platform/utils/tools.d.ts +6 -0
- package/dist/platform/utils/tools.d.ts.map +1 -0
- package/dist/platform/utils/tools.js +57 -0
- package/dist/platform/utils/tools.js.map +1 -0
- package/dist/types/Flows.types.d.ts +1 -0
- package/dist/types/Flows.types.d.ts.map +1 -1
- package/dist/types/Flows.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/types/Tools.types.d.ts +3 -2
- package/dist/types/Tools.types.d.ts.map +1 -1
- package/dist/utils/agentUtils.d.ts +5 -0
- package/dist/utils/agentUtils.d.ts.map +1 -0
- package/dist/utils/agentUtils.js +86 -0
- package/dist/utils/agentUtils.js.map +1 -0
- package/dist/utils/history.d.ts +1 -0
- package/dist/utils/history.d.ts.map +1 -1
- package/dist/utils/history.js +20 -0
- package/dist/utils/history.js.map +1 -1
- package/docs/SUMMARY.md +1 -0
- package/docs/sdk/agent-api.md +524 -0
- package/docs/sdk/debugging.md +42 -306
- package/package.json +2 -2
- package/src/agent.ts +53 -103
- package/src/browserTask/executeBrowserTask.ts +11 -215
- package/src/debugging/index.ts +1 -0
- package/src/debugging/llmCallbackHandler.ts +126 -0
- package/src/nodes/addBrowserTaskNode.ts +3 -2
- package/src/nodes/addBrowserTaskRunNode.ts +21 -2
- package/src/platform/mindedConnectionTypes.ts +33 -1
- package/src/platform/toolExecutor.ts +118 -0
- package/src/platform/utils/tools.ts +55 -0
- package/src/types/Flows.types.ts +1 -0
- package/src/types/LangGraph.types.ts +5 -0
- package/src/types/Tools.types.ts +2 -1
- package/src/utils/agentUtils.ts +68 -0
- package/src/utils/history.ts +29 -1
|
@@ -5,222 +5,11 @@ import {
|
|
|
5
5
|
CreateBrowserSessionResponse,
|
|
6
6
|
InvokeBrowserTaskResponse,
|
|
7
7
|
CreateBrowserSessionRequest,
|
|
8
|
+
InvokeBrowserTaskRequest,
|
|
8
9
|
} from '../platform/mindedConnectionTypes';
|
|
9
10
|
|
|
10
|
-
// Browser Use Cloud API configuration
|
|
11
|
-
const BROWSER_USE_API_BASE_URL = 'https://api.browser-use.com/api/v1';
|
|
12
|
-
|
|
13
|
-
// Types for Browser Use Cloud API
|
|
14
|
-
export interface CloudTaskResponse {
|
|
15
|
-
id: string;
|
|
16
|
-
status: string;
|
|
17
|
-
live_url?: string;
|
|
18
|
-
steps?: any[];
|
|
19
|
-
output?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Browser Use Cloud API methods
|
|
23
|
-
export const createCloudTask = async (prompt: string, model?: string): Promise<string> => {
|
|
24
|
-
const apiKey = process.env.BROWSER_USE_API_KEY;
|
|
25
|
-
if (!apiKey) {
|
|
26
|
-
throw new Error('BROWSER_USE_API_KEY environment variable is required');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
logger.debug({ msg: 'Creating cloud browser task', prompt: prompt.substring(0, 100) + '...' });
|
|
30
|
-
|
|
31
|
-
const response = await fetch(`${BROWSER_USE_API_BASE_URL}/run-task`, {
|
|
32
|
-
method: 'POST',
|
|
33
|
-
headers: {
|
|
34
|
-
Authorization: `Bearer ${apiKey}`,
|
|
35
|
-
'Content-Type': 'application/json',
|
|
36
|
-
},
|
|
37
|
-
body: JSON.stringify({
|
|
38
|
-
task: prompt,
|
|
39
|
-
use_proxy: false,
|
|
40
|
-
llm_model: model || 'gpt-4o',
|
|
41
|
-
}),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
logger.error({ msg: 'Failed to create cloud browser task', status: response.status, statusText: response.statusText });
|
|
46
|
-
throw new Error(`Failed to create browser task: ${response.statusText}`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const data = await response.json();
|
|
50
|
-
logger.debug({ msg: 'Cloud browser task created', taskId: data.id });
|
|
51
|
-
return data.id;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export const getTaskDetails = async (taskId: string): Promise<CloudTaskResponse> => {
|
|
55
|
-
const apiKey = process.env.BROWSER_USE_API_KEY;
|
|
56
|
-
if (!apiKey) {
|
|
57
|
-
throw new Error('BROWSER_USE_API_KEY environment variable is required');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const response = await fetch(`${BROWSER_USE_API_BASE_URL}/task/${taskId}`, {
|
|
61
|
-
headers: {
|
|
62
|
-
Authorization: `Bearer ${apiKey}`,
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (!response.ok) {
|
|
67
|
-
logger.error({ msg: 'Failed to get task details', taskId, status: response.status, statusText: response.statusText });
|
|
68
|
-
throw new Error(`Failed to get task details: ${response.statusText}`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return response.json();
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export const waitForLiveUrl = async (taskId: string, maxWaitTime: number = 30000): Promise<CloudTaskResponse> => {
|
|
75
|
-
const startTime = Date.now();
|
|
76
|
-
const pollInterval = 2000; // 2 seconds
|
|
77
|
-
let pollCount = 0;
|
|
78
|
-
|
|
79
|
-
logger.debug({ msg: 'Starting to poll for live_url', taskId, maxWaitTime, pollInterval });
|
|
80
|
-
|
|
81
|
-
while (Date.now() - startTime < maxWaitTime) {
|
|
82
|
-
pollCount++;
|
|
83
|
-
const elapsedTime = Date.now() - startTime;
|
|
84
|
-
|
|
85
|
-
logger.trace({
|
|
86
|
-
msg: 'Polling for live_url',
|
|
87
|
-
taskId,
|
|
88
|
-
pollCount,
|
|
89
|
-
elapsedTime,
|
|
90
|
-
remainingTime: maxWaitTime - elapsedTime,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const taskDetails = await getTaskDetails(taskId);
|
|
94
|
-
|
|
95
|
-
logger.trace({
|
|
96
|
-
msg: 'Task details received',
|
|
97
|
-
taskId,
|
|
98
|
-
status: taskDetails.status,
|
|
99
|
-
hasLiveUrl: !!taskDetails.live_url,
|
|
100
|
-
pollCount,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
if (taskDetails.live_url) {
|
|
104
|
-
logger.debug({
|
|
105
|
-
msg: 'Live URL available',
|
|
106
|
-
taskId,
|
|
107
|
-
liveUrl: taskDetails.live_url,
|
|
108
|
-
pollCount,
|
|
109
|
-
totalTime: elapsedTime,
|
|
110
|
-
});
|
|
111
|
-
return taskDetails;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (taskDetails.status === 'failed' || taskDetails.status === 'stopped') {
|
|
115
|
-
logger.error({
|
|
116
|
-
msg: 'Task failed while waiting for live_url',
|
|
117
|
-
taskId,
|
|
118
|
-
status: taskDetails.status,
|
|
119
|
-
pollCount,
|
|
120
|
-
elapsedTime,
|
|
121
|
-
});
|
|
122
|
-
throw new Error(`Task failed with status: ${taskDetails.status}`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
logger.trace({
|
|
126
|
-
msg: 'Live URL not yet available, continuing to poll',
|
|
127
|
-
taskId,
|
|
128
|
-
status: taskDetails.status,
|
|
129
|
-
pollCount,
|
|
130
|
-
nextPollIn: pollInterval,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
logger.error({
|
|
137
|
-
msg: 'Timeout waiting for live_url',
|
|
138
|
-
taskId,
|
|
139
|
-
pollCount,
|
|
140
|
-
totalTime: Date.now() - startTime,
|
|
141
|
-
maxWaitTime,
|
|
142
|
-
});
|
|
143
|
-
throw new Error('Timeout waiting for live_url to become available');
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
export const waitForCompletion = async (taskId: string, maxWaitTime: number = 300000): Promise<CloudTaskResponse> => {
|
|
147
|
-
const startTime = Date.now();
|
|
148
|
-
const pollInterval = 3000; // 3 seconds for completion polling
|
|
149
|
-
let pollCount = 0;
|
|
150
|
-
|
|
151
|
-
logger.debug({ msg: 'Starting to poll for task completion', taskId, maxWaitTime, pollInterval });
|
|
152
|
-
|
|
153
|
-
while (Date.now() - startTime < maxWaitTime) {
|
|
154
|
-
pollCount++;
|
|
155
|
-
const elapsedTime = Date.now() - startTime;
|
|
156
|
-
|
|
157
|
-
logger.trace({
|
|
158
|
-
msg: 'Polling for task completion',
|
|
159
|
-
taskId,
|
|
160
|
-
pollCount,
|
|
161
|
-
elapsedTime,
|
|
162
|
-
remainingTime: maxWaitTime - elapsedTime,
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const taskDetails = await getTaskDetails(taskId);
|
|
166
|
-
|
|
167
|
-
logger.trace({
|
|
168
|
-
msg: 'Task completion status received',
|
|
169
|
-
taskId,
|
|
170
|
-
status: taskDetails.status,
|
|
171
|
-
pollCount,
|
|
172
|
-
hasOutput: !!taskDetails.output,
|
|
173
|
-
stepCount: taskDetails.steps?.length || 0,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
if (taskDetails.status === 'finished') {
|
|
177
|
-
logger.debug({
|
|
178
|
-
msg: 'Task completed successfully',
|
|
179
|
-
taskId,
|
|
180
|
-
pollCount,
|
|
181
|
-
totalTime: elapsedTime,
|
|
182
|
-
stepCount: taskDetails.steps?.length || 0,
|
|
183
|
-
hasOutput: !!taskDetails.output,
|
|
184
|
-
});
|
|
185
|
-
return taskDetails;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (taskDetails.status === 'failed' || taskDetails.status === 'stopped') {
|
|
189
|
-
logger.error({
|
|
190
|
-
msg: 'Task failed during completion polling',
|
|
191
|
-
taskId,
|
|
192
|
-
status: taskDetails.status,
|
|
193
|
-
pollCount,
|
|
194
|
-
elapsedTime,
|
|
195
|
-
stepCount: taskDetails.steps?.length || 0,
|
|
196
|
-
});
|
|
197
|
-
throw new Error(`Task failed with status: ${taskDetails.status}`);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
logger.trace({
|
|
201
|
-
msg: 'Task still in progress, continuing to poll',
|
|
202
|
-
taskId,
|
|
203
|
-
status: taskDetails.status,
|
|
204
|
-
pollCount,
|
|
205
|
-
stepCount: taskDetails.steps?.length || 0,
|
|
206
|
-
nextPollIn: pollInterval,
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
logger.error({
|
|
213
|
-
msg: 'Timeout waiting for task completion',
|
|
214
|
-
taskId,
|
|
215
|
-
pollCount,
|
|
216
|
-
totalTime: Date.now() - startTime,
|
|
217
|
-
maxWaitTime,
|
|
218
|
-
});
|
|
219
|
-
throw new Error('Timeout waiting for task completion');
|
|
220
|
-
};
|
|
221
|
-
|
|
222
11
|
// Socket-based browser task functions
|
|
223
|
-
export const createBrowserSession = async (proxy?: string): Promise<CreateBrowserSessionResponse> => {
|
|
12
|
+
export const createBrowserSession = async (proxy?: string, onPrem?: boolean): Promise<CreateBrowserSessionResponse> => {
|
|
224
13
|
logger.debug({ msg: 'Creating browser session via socket', proxy });
|
|
225
14
|
|
|
226
15
|
try {
|
|
@@ -229,6 +18,7 @@ export const createBrowserSession = async (proxy?: string): Promise<CreateBrowse
|
|
|
229
18
|
{
|
|
230
19
|
type: mindedConnectionSocketMessageType.CREATE_BROWSER_SESSION,
|
|
231
20
|
proxy,
|
|
21
|
+
onPrem: onPrem,
|
|
232
22
|
},
|
|
233
23
|
60000, // 60 seconds timeout
|
|
234
24
|
);
|
|
@@ -257,6 +47,8 @@ export const invokeBrowserTask = async (
|
|
|
257
47
|
task: string,
|
|
258
48
|
keepAlive?: boolean,
|
|
259
49
|
hooks?: { name: string }[],
|
|
50
|
+
onPrem?: boolean,
|
|
51
|
+
toolSchemas?: any[],
|
|
260
52
|
outputSchema?: {
|
|
261
53
|
name: string;
|
|
262
54
|
type: 'string' | 'number';
|
|
@@ -270,18 +62,22 @@ export const invokeBrowserTask = async (
|
|
|
270
62
|
taskLength: task.length,
|
|
271
63
|
keepAlive,
|
|
272
64
|
hooksCount: hooks?.length || 0,
|
|
65
|
+
onPrem,
|
|
273
66
|
outputSchemaFields: outputSchema?.length || 0,
|
|
274
67
|
});
|
|
275
68
|
|
|
276
69
|
try {
|
|
277
|
-
const response = await mindedConnection.awaitEmit<
|
|
70
|
+
const response = await mindedConnection.awaitEmit<InvokeBrowserTaskRequest, InvokeBrowserTaskResponse>(
|
|
278
71
|
mindedConnectionSocketMessageType.INVOKE_BROWSER_TASK,
|
|
279
72
|
{
|
|
280
|
-
|
|
73
|
+
type: mindedConnectionSocketMessageType.INVOKE_BROWSER_TASK,
|
|
281
74
|
cdpUrl,
|
|
282
75
|
task,
|
|
76
|
+
sessionId,
|
|
283
77
|
keepAlive,
|
|
284
78
|
hooks,
|
|
79
|
+
onPrem,
|
|
80
|
+
toolSchemas,
|
|
285
81
|
outputSchema,
|
|
286
82
|
},
|
|
287
83
|
900000, // 15 minutes timeout
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { LLMDebugCallbackHandler } from './llmCallbackHandler';
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/* eslint-disable no-debugger */
|
|
3
|
+
|
|
4
|
+
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
5
|
+
import { Serialized } from '@langchain/core/load/serializable';
|
|
6
|
+
import { LLMResult } from '@langchain/core/outputs';
|
|
7
|
+
import { BaseMessage } from '@langchain/core/messages';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A callback handler for debugging LLM interactions in MindedJS agents.
|
|
11
|
+
* This handler allows you to inspect messages before they are sent to the LLM
|
|
12
|
+
* and see the responses received.
|
|
13
|
+
*
|
|
14
|
+
* This class extends BaseCallbackHandler from LangChain and provides several
|
|
15
|
+
* callback methods. You can override additional methods for more comprehensive debugging:
|
|
16
|
+
*
|
|
17
|
+
* Available LangChain Callback Methods:
|
|
18
|
+
* - handleChatModelStart - For chat model requests (receives BaseMessage arrays)
|
|
19
|
+
* - handleLLMStart - For standard LLM requests (receives string prompts)
|
|
20
|
+
* - handleLLMNewToken - For streaming tokens as they're generated
|
|
21
|
+
* - handleLLMEnd - When LLM finishes generating
|
|
22
|
+
* - handleLLMError - When LLM encounters an error
|
|
23
|
+
* - handleChainStart - When a LangChain chain starts execution
|
|
24
|
+
* - handleChainEnd - When a chain completes execution
|
|
25
|
+
* - handleChainError - When a chain encounters an error
|
|
26
|
+
* - handleToolStart - When a tool/function starts execution
|
|
27
|
+
* - handleToolEnd - When a tool completes execution
|
|
28
|
+
* - handleToolError - When a tool encounters an error
|
|
29
|
+
* - handleAgentAction - When an agent takes an action
|
|
30
|
+
* - handleAgentFinish - When an agent completes its task
|
|
31
|
+
*
|
|
32
|
+
* For more details on all available callbacks and their signatures, see the LangChain documentation:
|
|
33
|
+
* https://js.langchain.com/docs/modules/callbacks/
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { Agent, LLMDebugCallbackHandler } from '@minded-ai/mindedjs';
|
|
38
|
+
*
|
|
39
|
+
* const debugHandler = new LLMDebugCallbackHandler();
|
|
40
|
+
*
|
|
41
|
+
* const agent = new Agent({
|
|
42
|
+
* config: {
|
|
43
|
+
* ...config,
|
|
44
|
+
* llm: {
|
|
45
|
+
* ...config.llm,
|
|
46
|
+
* properties: {
|
|
47
|
+
* ...config.llm.properties,
|
|
48
|
+
* callbacks: [debugHandler],
|
|
49
|
+
* },
|
|
50
|
+
* },
|
|
51
|
+
* },
|
|
52
|
+
* // ... other agent configuration
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export class LLMDebugCallbackHandler extends BaseCallbackHandler {
|
|
57
|
+
name = 'LLMDebugCallbackHandler';
|
|
58
|
+
|
|
59
|
+
constructor() {
|
|
60
|
+
super();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Called when a chat model (like GPT-4) starts processing.
|
|
65
|
+
* This is triggered before the messages are sent to the LLM.
|
|
66
|
+
* The messages parameter contains the full conversation history.
|
|
67
|
+
*/
|
|
68
|
+
async handleChatModelStart(
|
|
69
|
+
llm: Serialized,
|
|
70
|
+
messages: BaseMessage[][],
|
|
71
|
+
runId: string,
|
|
72
|
+
parentRunId?: string,
|
|
73
|
+
extraParams?: Record<string, unknown>,
|
|
74
|
+
tags?: string[],
|
|
75
|
+
metadata?: Record<string, unknown>,
|
|
76
|
+
name?: string,
|
|
77
|
+
): Promise<void> {
|
|
78
|
+
console.log('handleChatModelStart called with messages:', messages);
|
|
79
|
+
// Set a breakpoint here to inspect messages
|
|
80
|
+
debugger;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Called when any LLM starts processing (including non-chat models).
|
|
85
|
+
* For chat models, the messages are available in extraParams.messages.
|
|
86
|
+
* This is a more general callback that works with all LLM types.
|
|
87
|
+
*/
|
|
88
|
+
async handleLLMStart(
|
|
89
|
+
llm: Serialized,
|
|
90
|
+
prompts: string[],
|
|
91
|
+
runId: string,
|
|
92
|
+
parentRunId?: string,
|
|
93
|
+
extraParams?: Record<string, unknown>,
|
|
94
|
+
tags?: string[],
|
|
95
|
+
metadata?: Record<string, unknown>,
|
|
96
|
+
name?: string,
|
|
97
|
+
): Promise<void> {
|
|
98
|
+
console.log('handleLLMStart called with extraParams.messages:', extraParams?.messages);
|
|
99
|
+
// Set a breakpoint here to inspect messages
|
|
100
|
+
debugger;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Called when a chat model finishes processing and returns a response.
|
|
105
|
+
* The output contains the generated message and metadata.
|
|
106
|
+
*/
|
|
107
|
+
async handleChatModelEnd(output: LLMResult, runId: string, parentRunId?: string): Promise<void> {
|
|
108
|
+
console.log('handleChatModelEnd called with output:', output);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Called when any LLM finishes processing and returns a response.
|
|
113
|
+
* This is called for all LLM types, including chat models.
|
|
114
|
+
*/
|
|
115
|
+
async handleLLMEnd(output: LLMResult, runId: string, parentRunId?: string): Promise<void> {
|
|
116
|
+
console.log('handleLLMEnd called with output:', output);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Called when an error occurs during LLM processing.
|
|
121
|
+
* This captures any errors that happen during the LLM call.
|
|
122
|
+
*/
|
|
123
|
+
async handleLLMError(err: Error, runId: string, parentRunId?: string): Promise<void> {
|
|
124
|
+
console.log('handleLLMError called with error:', err);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -54,7 +54,7 @@ export const addBrowserTaskNode = async ({ graph, node, agent, llm }: AddBrowser
|
|
|
54
54
|
const zodSchema = z.object(schemaFields);
|
|
55
55
|
|
|
56
56
|
// Create langchain tool
|
|
57
|
-
const tool = langchainTool(() => {
|
|
57
|
+
const tool = langchainTool(() => {}, {
|
|
58
58
|
name: 'browser-task',
|
|
59
59
|
description: node.prompt,
|
|
60
60
|
schema: zodSchema,
|
|
@@ -98,7 +98,7 @@ ${compiledPrompt}
|
|
|
98
98
|
${Object.keys(inputParams).length > 0 ? `# Input parameters:\n${JSON.stringify(inputParams, null, 2)}\n\n` : ''}`;
|
|
99
99
|
|
|
100
100
|
// Create browser session using socket
|
|
101
|
-
const session = await createBrowserSession(node.proxy);
|
|
101
|
+
const session = await createBrowserSession(node.proxy, node.onPrem);
|
|
102
102
|
|
|
103
103
|
if (!session.sessionId || !session.cdpUrl) {
|
|
104
104
|
throw new Error('Failed to create browser session: missing session details');
|
|
@@ -137,6 +137,7 @@ ${Object.keys(inputParams).length > 0 ? `# Input parameters:\n${JSON.stringify(i
|
|
|
137
137
|
liveUrl: session.liveViewUrl,
|
|
138
138
|
keepAlive,
|
|
139
139
|
hooks: node.hooks || [],
|
|
140
|
+
onPrem: node.onPrem,
|
|
140
141
|
outputSchema: node.outputSchema,
|
|
141
142
|
},
|
|
142
143
|
},
|
|
@@ -8,6 +8,7 @@ import { createHistoryStep } from '../utils/history';
|
|
|
8
8
|
import { HistoryStep } from '../types/Agent.types';
|
|
9
9
|
import { v4 as uuidv4 } from 'uuid';
|
|
10
10
|
import { invokeBrowserTask } from '../browserTask/executeBrowserTask';
|
|
11
|
+
import { zodSchemaToParams } from '../platform/utils/tools';
|
|
11
12
|
|
|
12
13
|
type AddBrowserTaskRunNodeParams = {
|
|
13
14
|
graph: PreCompiledGraph;
|
|
@@ -18,7 +19,7 @@ type AddBrowserTaskRunNodeParams = {
|
|
|
18
19
|
|
|
19
20
|
export const buildBrowserTaskRunNodeName = (nodeName: string) => `${nodeName}${internalNodesSuffix.BROWSER_TASK_RUN}`;
|
|
20
21
|
|
|
21
|
-
export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedToNodeName }: AddBrowserTaskRunNodeParams) => {
|
|
22
|
+
export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedToNodeName, agent }: AddBrowserTaskRunNodeParams) => {
|
|
22
23
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
23
24
|
logger.info(`Executing browser task run node for ${browserTaskNode.displayName}`);
|
|
24
25
|
|
|
@@ -30,13 +31,31 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
|
|
|
30
31
|
const toolCall = toolCallObj.tool_calls[0];
|
|
31
32
|
const { prompt, ...inputParams } = toolCall.args;
|
|
32
33
|
const { sessionId, cdpUrl, keepAlive, hooks, outputSchema } = toolCallMindedMetadata;
|
|
34
|
+
|
|
33
35
|
try {
|
|
34
36
|
if (!sessionId || !cdpUrl || !prompt) {
|
|
35
37
|
throw new Error('Missing required parameters: sessionId, cdpUrl, or prompt');
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
const toolSchemas = agent.tools
|
|
41
|
+
.filter((tool) => tool.allowExecutionRequests === true)
|
|
42
|
+
.map((tool) => ({
|
|
43
|
+
name: tool.name,
|
|
44
|
+
description: tool.description,
|
|
45
|
+
inputParams: zodSchemaToParams(tool.input),
|
|
46
|
+
}));
|
|
47
|
+
|
|
38
48
|
// Invoke browser task via socket
|
|
39
|
-
const result = await invokeBrowserTask(
|
|
49
|
+
const result = await invokeBrowserTask(
|
|
50
|
+
sessionId,
|
|
51
|
+
cdpUrl,
|
|
52
|
+
prompt,
|
|
53
|
+
keepAlive,
|
|
54
|
+
hooks,
|
|
55
|
+
browserTaskNode.onPrem,
|
|
56
|
+
toolSchemas,
|
|
57
|
+
outputSchema,
|
|
58
|
+
);
|
|
40
59
|
|
|
41
60
|
logger.debug({
|
|
42
61
|
msg: 'Browser task completed',
|
|
@@ -51,6 +51,8 @@ export enum mindedConnectionSocketMessageType {
|
|
|
51
51
|
INTERRUPT_SESSION_DEQUEUE = 'interrupt-session-dequeue',
|
|
52
52
|
INTERRUPT_SESSION_HAS_MESSAGES = 'interrupt-session-has-messages',
|
|
53
53
|
INTERRUPT_SESSION_GET_MESSAGES = 'interrupt-session-get-messages',
|
|
54
|
+
// Tool execution
|
|
55
|
+
EXECUTE_TOOL = 'execute-tool',
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export type mindedConnectionSocketMessageTypeMap = {
|
|
@@ -91,6 +93,7 @@ export type mindedConnectionSocketMessageTypeMap = {
|
|
|
91
93
|
[mindedConnectionSocketMessageType.INTERRUPT_SESSION_DEQUEUE]: InterruptSessionDequeueRequest;
|
|
92
94
|
[mindedConnectionSocketMessageType.INTERRUPT_SESSION_HAS_MESSAGES]: InterruptSessionHasMessagesRequest;
|
|
93
95
|
[mindedConnectionSocketMessageType.INTERRUPT_SESSION_GET_MESSAGES]: InterruptSessionGetMessagesRequest;
|
|
96
|
+
[mindedConnectionSocketMessageType.EXECUTE_TOOL]: ExecuteToolRequest;
|
|
94
97
|
};
|
|
95
98
|
|
|
96
99
|
export interface BasemindedConnectionSocketMessage {
|
|
@@ -441,6 +444,7 @@ export interface UpdateStateRequest extends BasemindedConnectionSocketMessage {
|
|
|
441
444
|
export interface CreateBrowserSessionRequest extends BasemindedConnectionSocketMessage {
|
|
442
445
|
type: mindedConnectionSocketMessageType.CREATE_BROWSER_SESSION;
|
|
443
446
|
proxy?: string; // 2-digit country code like 'IL'
|
|
447
|
+
onPrem?: boolean;
|
|
444
448
|
}
|
|
445
449
|
|
|
446
450
|
export interface CreateBrowserSessionResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
|
|
@@ -455,7 +459,19 @@ export interface InvokeBrowserTaskRequest extends BasemindedConnectionSocketMess
|
|
|
455
459
|
task: string;
|
|
456
460
|
sessionId: string;
|
|
457
461
|
keepAlive?: boolean;
|
|
458
|
-
hooks?: {
|
|
462
|
+
hooks?: {
|
|
463
|
+
name: string;
|
|
464
|
+
lifecycle_phases?: string[];
|
|
465
|
+
config?: Record<string, any>;
|
|
466
|
+
}[]; // Array of hooks to be passed to the browser-use lambda
|
|
467
|
+
onPrem?: boolean;
|
|
468
|
+
toolSchemas?: any[];
|
|
469
|
+
outputSchema?: {
|
|
470
|
+
name: string;
|
|
471
|
+
type: 'string' | 'number';
|
|
472
|
+
description?: string;
|
|
473
|
+
required?: boolean;
|
|
474
|
+
}[];
|
|
459
475
|
}
|
|
460
476
|
|
|
461
477
|
export interface InvokeBrowserTaskResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
|
|
@@ -463,3 +479,19 @@ export interface InvokeBrowserTaskResponse extends BaseSdkConnectionSocketMessag
|
|
|
463
479
|
steps?: any[];
|
|
464
480
|
recordings?: any[];
|
|
465
481
|
}
|
|
482
|
+
|
|
483
|
+
export interface ExecuteToolRequest extends BasemindedConnectionSocketMessage {
|
|
484
|
+
type: mindedConnectionSocketMessageType.EXECUTE_TOOL;
|
|
485
|
+
toolName: string;
|
|
486
|
+
toolParams: any;
|
|
487
|
+
sessionId: string;
|
|
488
|
+
requestId: string;
|
|
489
|
+
error?: string;
|
|
490
|
+
cdpUrl?: string; // Optional CDP URL for browser context
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export interface ExecuteToolResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
|
|
494
|
+
requestId: string;
|
|
495
|
+
result?: any;
|
|
496
|
+
state?: any;
|
|
497
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Tool } from '../types/Tools.types';
|
|
2
|
+
import { Agent } from '../agent';
|
|
3
|
+
import { logger } from '../utils/logger';
|
|
4
|
+
import extractToolStateResponse from '../utils/extractStateMemoryResponse';
|
|
5
|
+
import { ToolMessage } from '@langchain/core/messages';
|
|
6
|
+
|
|
7
|
+
export interface ToolExecutionRequest {
|
|
8
|
+
toolName: string;
|
|
9
|
+
toolParams: any;
|
|
10
|
+
sessionId: string;
|
|
11
|
+
requestId: string;
|
|
12
|
+
cdpUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ToolExecutionResponse {
|
|
16
|
+
result?: any;
|
|
17
|
+
state?: any;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class ToolExecutor {
|
|
22
|
+
private tools: Map<string, Tool<any, any>> = new Map();
|
|
23
|
+
|
|
24
|
+
constructor(private agent: Agent) {}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Register tools for standalone execution
|
|
28
|
+
*/
|
|
29
|
+
registerTools(tools: Tool<any, any>[]) {
|
|
30
|
+
tools.forEach((tool) => {
|
|
31
|
+
if (tool.allowExecutionRequests === true) {
|
|
32
|
+
this.tools.set(tool.name, tool);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Execute a tool by name with given parameters
|
|
39
|
+
* This is called when browser-use requests tool execution via socket
|
|
40
|
+
*/
|
|
41
|
+
async executeTool(request: ToolExecutionRequest): Promise<ToolExecutionResponse> {
|
|
42
|
+
const { toolName, toolParams, sessionId, cdpUrl } = request;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// Find the tool
|
|
46
|
+
const tool = this.tools.get(toolName);
|
|
47
|
+
if (!tool) {
|
|
48
|
+
throw new Error(`Tool not found: ${toolName}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// We only allow to execute tools that are marked as allowed to be executed
|
|
52
|
+
|
|
53
|
+
logger.debug({
|
|
54
|
+
msg: '[ToolExecutor] Executing tool',
|
|
55
|
+
toolName,
|
|
56
|
+
sessionId,
|
|
57
|
+
hasCdpUrl: !!cdpUrl,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Get the current state for the session
|
|
61
|
+
const state = await this.agent.getState(sessionId);
|
|
62
|
+
if (!state) {
|
|
63
|
+
throw new Error(`Session state not found: ${sessionId}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Execute the tool
|
|
67
|
+
const startTime = Date.now();
|
|
68
|
+
|
|
69
|
+
if (cdpUrl) {
|
|
70
|
+
state.cdpUrl = cdpUrl;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const response = await tool.execute({
|
|
74
|
+
input: toolParams,
|
|
75
|
+
state,
|
|
76
|
+
agent: this.agent,
|
|
77
|
+
});
|
|
78
|
+
const endTime = Date.now();
|
|
79
|
+
|
|
80
|
+
logger.debug({
|
|
81
|
+
msg: '[ToolExecutor] Tool execution completed',
|
|
82
|
+
toolName,
|
|
83
|
+
executionTimeMs: endTime - startTime,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Extract state updates from the response
|
|
87
|
+
let stateUpdate = {};
|
|
88
|
+
let result = response;
|
|
89
|
+
|
|
90
|
+
// If the response is a ToolMessage, extract state updates
|
|
91
|
+
if (response && typeof response === 'object' && 'content' in response) {
|
|
92
|
+
const toolMessage = response as ToolMessage;
|
|
93
|
+
stateUpdate = extractToolStateResponse(toolMessage);
|
|
94
|
+
// Extract the content as the result
|
|
95
|
+
result = { result: toolMessage.content };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Update the session state if there are state changes
|
|
99
|
+
if (Object.keys(stateUpdate).length > 0) {
|
|
100
|
+
await this.agent.updateState({ sessionId, state: stateUpdate });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
result,
|
|
105
|
+
};
|
|
106
|
+
} catch (error) {
|
|
107
|
+
logger.error({
|
|
108
|
+
msg: '[ToolExecutor] Error executing tool',
|
|
109
|
+
toolName,
|
|
110
|
+
error: error instanceof Error ? error.message : String(error),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
error: error instanceof Error ? error.message : String(error),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|