@minded-ai/mindedjs 1.0.0-ec2-beta-14 → 1.0.0-ec2-beta-16
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/package.json +1 -1
- package/src/agent.ts +1 -1
- package/src/browserTask/executeBrowserTask.py +5 -5
- package/src/browserTask/executeBrowserTask.ts +19 -9
- package/src/edges/createPromptRouter.ts +4 -1
- package/src/internalTools/appActionRunnerTool.ts +2 -1
- package/src/nodes/addAppToolNode.ts +4 -3
- package/src/nodes/addBrowserTaskNode.ts +10 -2
- package/src/nodes/addBrowserTaskRunNode.ts +5 -1
- package/src/nodes/addPromptNode.ts +1 -1
- package/src/nodes/addToolNode.ts +1 -1
- package/src/nodes/compilePrompt.ts +3 -6
- package/src/nodes/rpaStepsExecutor.ts +17 -11
- package/src/platform/mindedConnectionTypes.ts +1 -0
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -510,7 +510,7 @@ export class Agent {
|
|
|
510
510
|
// Add playbooks to messages
|
|
511
511
|
const combinedPlaybooks = combinePlaybooks(this.playbooks);
|
|
512
512
|
if (combinedPlaybooks) {
|
|
513
|
-
const compiledPrompt = compilePrompt(combinedPlaybooks, state);
|
|
513
|
+
const compiledPrompt = compilePrompt(combinedPlaybooks, { state: state, memory: state.memory, env: process.env });
|
|
514
514
|
const systemMessage = new SystemMessage(compiledPrompt);
|
|
515
515
|
if (state.messages.length === 0 || state.messages[0].getType() === 'system') {
|
|
516
516
|
state.messages[0] = systemMessage;
|
|
@@ -172,12 +172,11 @@ def create_pydantic_model_from_schema(output_schema: Optional[List[Dict[str, Any
|
|
|
172
172
|
|
|
173
173
|
|
|
174
174
|
async def main(session_id: str, cdp_url: str, task: str, output_schema_json: Optional[str] = None,
|
|
175
|
-
otp_secret: Optional[str] = None, screenshot_config: Optional[Dict[str, Any]] = None):
|
|
175
|
+
otp_secret: Optional[str] = None, screenshot_config: Optional[Dict[str, Any]] = None, folder_path: str = None):
|
|
176
176
|
llm = ChatOpenAI(
|
|
177
177
|
model="gpt-4.1",
|
|
178
178
|
api_key=os.getenv("OPENAI_API_KEY"),
|
|
179
179
|
)
|
|
180
|
-
folder_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), f'downloads_{session_id}')
|
|
181
180
|
|
|
182
181
|
# Create folder if it doesn't exist
|
|
183
182
|
os.makedirs(folder_path, exist_ok=True)
|
|
@@ -299,11 +298,12 @@ if __name__ == '__main__':
|
|
|
299
298
|
output_schema = payload.get('outputSchema')
|
|
300
299
|
otp_secret = payload.get('otpSecret')
|
|
301
300
|
screenshot_config = payload.get('screenshotConfig')
|
|
301
|
+
folder_path = payload.get('folderPath')
|
|
302
302
|
|
|
303
|
-
if not session_id or not cdp_url or not task:
|
|
304
|
-
raise SystemExit("Missing required fields in JSON payload: sessionId, cdpUrl, task")
|
|
303
|
+
if not session_id or not cdp_url or not task or not folder_path:
|
|
304
|
+
raise SystemExit("Missing required fields in JSON payload: sessionId, cdpUrl, task, folderPath")
|
|
305
305
|
|
|
306
306
|
output_schema_json = json.dumps(output_schema) if output_schema is not None else None
|
|
307
|
-
asyncio.run(main(session_id, cdp_url, task, output_schema_json, otp_secret, screenshot_config))
|
|
307
|
+
asyncio.run(main(session_id, cdp_url, task, output_schema_json, otp_secret, screenshot_config, folder_path))
|
|
308
308
|
else:
|
|
309
309
|
raise SystemExit("Usage: uv run executeBrowserTask.py; send a JSON payload via stdin")
|
|
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { logger } from '../utils/logger';
|
|
3
3
|
import { mindedConnection } from '../platform/mindedConnection';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
import { existsSync, readdirSync } from 'fs';
|
|
5
6
|
import {
|
|
6
7
|
mindedConnectionSocketMessageType,
|
|
7
8
|
CreateBrowserSessionResponse,
|
|
@@ -120,6 +121,9 @@ export const invokeBrowserTask = async (options: InvokeBrowserTaskOptions): Prom
|
|
|
120
121
|
validateLocalOperatorSetup();
|
|
121
122
|
const pythonScriptPath = path.resolve(__dirname, 'executeBrowserTask.py');
|
|
122
123
|
|
|
124
|
+
// Calculate folder path for downloads
|
|
125
|
+
const folderPath = path.join(__dirname, `downloads_${sessionId}`);
|
|
126
|
+
|
|
123
127
|
const args = ['run', pythonScriptPath];
|
|
124
128
|
logger.info({
|
|
125
129
|
message: 'Spawning Python process',
|
|
@@ -146,6 +150,7 @@ export const invokeBrowserTask = async (options: InvokeBrowserTaskOptions): Prom
|
|
|
146
150
|
outputSchema,
|
|
147
151
|
otpSecret: process.env.TOTP_SECRET,
|
|
148
152
|
screenshotConfig,
|
|
153
|
+
folderPath,
|
|
149
154
|
};
|
|
150
155
|
|
|
151
156
|
// Write JSON payload to stdin
|
|
@@ -167,14 +172,11 @@ export const invokeBrowserTask = async (options: InvokeBrowserTaskOptions): Prom
|
|
|
167
172
|
process.stderr.write(text);
|
|
168
173
|
});
|
|
169
174
|
|
|
170
|
-
let wasKilledByUs = false;
|
|
171
|
-
|
|
172
175
|
const interval = setInterval(() => {
|
|
173
176
|
// Check if chromium process stopped running
|
|
174
177
|
if (!isLocalBrowserRunning()) {
|
|
175
178
|
logger.error({ message: 'Local browser process stopped running, killing browser task' });
|
|
176
|
-
|
|
177
|
-
child.kill('SIGTERM');
|
|
179
|
+
child.kill();
|
|
178
180
|
clearInterval(interval);
|
|
179
181
|
}
|
|
180
182
|
}, 1000);
|
|
@@ -191,11 +193,6 @@ export const invokeBrowserTask = async (options: InvokeBrowserTaskOptions): Prom
|
|
|
191
193
|
|
|
192
194
|
clearInterval(interval);
|
|
193
195
|
|
|
194
|
-
if (wasKilledByUs) {
|
|
195
|
-
logger.error({ message: 'Browser task was killed by user', stderr: stderrBuffer });
|
|
196
|
-
throw new Error('Task was stopped by user');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
196
|
if (exitCode !== 0) {
|
|
200
197
|
logger.error({ message: 'Operator failed', exitCode, stderr: stderrBuffer });
|
|
201
198
|
throw new Error(`Local browser task failed with exit code ${exitCode}`);
|
|
@@ -212,10 +209,23 @@ export const invokeBrowserTask = async (options: InvokeBrowserTaskOptions): Prom
|
|
|
212
209
|
}
|
|
213
210
|
}
|
|
214
211
|
|
|
212
|
+
// Read downloaded files from the folder
|
|
213
|
+
let downloadedFiles: string[] = [];
|
|
214
|
+
if (existsSync(folderPath)) {
|
|
215
|
+
try {
|
|
216
|
+
const files = readdirSync(folderPath);
|
|
217
|
+
downloadedFiles = files.map((file) => path.join(folderPath, file));
|
|
218
|
+
logger.debug({ message: 'Found downloaded files', count: downloadedFiles.length, files: downloadedFiles });
|
|
219
|
+
} catch (error) {
|
|
220
|
+
logger.error({ message: 'Failed to read downloads folder', error });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
215
224
|
return {
|
|
216
225
|
result,
|
|
217
226
|
steps: [],
|
|
218
227
|
recordings: [],
|
|
228
|
+
downloadedFiles,
|
|
219
229
|
};
|
|
220
230
|
}
|
|
221
231
|
|
|
@@ -107,9 +107,12 @@ export const createPromptRouter = ({
|
|
|
107
107
|
const promptTemplate = includeReasoning ? ROUTER_PROMPT : ROUTER_PROMPT_WITHOUT_REASONING;
|
|
108
108
|
|
|
109
109
|
// Compile prompt with EJS and parameters
|
|
110
|
-
const routerPrompt = compilePrompt(promptTemplate,
|
|
110
|
+
const routerPrompt = compilePrompt(promptTemplate, {
|
|
111
111
|
steps: stepsStr,
|
|
112
112
|
messages: messagesStr,
|
|
113
|
+
memory: state.memory,
|
|
114
|
+
state: state,
|
|
115
|
+
env: process.env,
|
|
113
116
|
});
|
|
114
117
|
|
|
115
118
|
// Define response schema
|
|
@@ -47,7 +47,7 @@ const appActionRunnerToolCreator = (schema: ActionInputParam[], nodeTitle: strin
|
|
|
47
47
|
name: nodeTitle,
|
|
48
48
|
description,
|
|
49
49
|
input: zodSchema,
|
|
50
|
-
execute: async ({ input }: ToolExecuteInput<typeof zodSchema>) => {
|
|
50
|
+
execute: async ({ input, state }: ToolExecuteInput<typeof zodSchema>) => {
|
|
51
51
|
const response = await mindedConnection.awaitEmit(
|
|
52
52
|
mindedConnectionSocketMessageType.OnAppAction,
|
|
53
53
|
{
|
|
@@ -57,6 +57,7 @@ const appActionRunnerToolCreator = (schema: ActionInputParam[], nodeTitle: strin
|
|
|
57
57
|
20000,
|
|
58
58
|
);
|
|
59
59
|
return {
|
|
60
|
+
state,
|
|
60
61
|
result: response as { result?: any },
|
|
61
62
|
};
|
|
62
63
|
},
|
|
@@ -39,12 +39,13 @@ export const addAppToolNode = async ({
|
|
|
39
39
|
|
|
40
40
|
// Compile parameters with variable injection support
|
|
41
41
|
const compiledParameters: Record<string, any> = {};
|
|
42
|
+
const compileContext = { state, memory: state.memory, env: process.env };
|
|
42
43
|
|
|
43
44
|
for (const [key, value] of Object.entries(node.parameters || {})) {
|
|
44
45
|
if (value !== '') {
|
|
45
46
|
// If the value is a string, compile it to allow variable injection
|
|
46
47
|
if (typeof value === 'string') {
|
|
47
|
-
compiledParameters[key] = compilePrompt(value,
|
|
48
|
+
compiledParameters[key] = compilePrompt(value, compileContext);
|
|
48
49
|
} else {
|
|
49
50
|
compiledParameters[key] = value;
|
|
50
51
|
}
|
|
@@ -69,7 +70,7 @@ export const addAppToolNode = async ({
|
|
|
69
70
|
const combinedPlaybooks = combinePlaybooks(agent.playbooks) || '';
|
|
70
71
|
|
|
71
72
|
// Compile the prompt if it exists to allow variable injection
|
|
72
|
-
const compiledNodePrompt = node.prompt ? compilePrompt(node.prompt,
|
|
73
|
+
const compiledNodePrompt = node.prompt ? compilePrompt(node.prompt, compileContext) : null;
|
|
73
74
|
|
|
74
75
|
// Check if any compiled parameter is too long (>1000 characters)
|
|
75
76
|
const hasLongParameters = Object.values(compiledParameters).some((value) => typeof value === 'string' && value.length > 1000);
|
|
@@ -106,7 +107,7 @@ export const addAppToolNode = async ({
|
|
|
106
107
|
User instructions for choosing tool parameters are:
|
|
107
108
|
${compiledNodePrompt ? compiledNodePrompt : 'no instructions set by the user'}`;
|
|
108
109
|
|
|
109
|
-
const compiledPrompt = compilePrompt(message, state);
|
|
110
|
+
const compiledPrompt = compilePrompt(message, { state: state, memory: state.memory, env: process.env });
|
|
110
111
|
const systemMessage = new SystemMessage(compiledPrompt);
|
|
111
112
|
if (state.messages.length === 0 || state.messages[0].getType() === 'system') {
|
|
112
113
|
state.messages[0] = systemMessage;
|
|
@@ -39,7 +39,7 @@ export const addBrowserTaskNode = async ({ graph, node, agent, llm }: AddBrowser
|
|
|
39
39
|
|
|
40
40
|
const combinedPlaybooks = combinePlaybooks(agent.playbooks);
|
|
41
41
|
if (combinedPlaybooks) {
|
|
42
|
-
const compiledPrompt = compilePrompt(combinedPlaybooks, state);
|
|
42
|
+
const compiledPrompt = compilePrompt(combinedPlaybooks, { state: state, memory: state.memory });
|
|
43
43
|
const systemMessage = new SystemMessage(compiledPrompt);
|
|
44
44
|
if (state.messages.length === 0 || state.messages[0].getType() === 'system') {
|
|
45
45
|
state.messages[0] = systemMessage;
|
|
@@ -59,8 +59,16 @@ export const addBrowserTaskNode = async ({ graph, node, agent, llm }: AddBrowser
|
|
|
59
59
|
const toolCall = AIToolCallMessage.tool_calls[0];
|
|
60
60
|
const inputParams = toolCall.args || {};
|
|
61
61
|
|
|
62
|
+
// Prepare parameters for prompt compilation
|
|
63
|
+
const promptParams = {
|
|
64
|
+
input: inputParams,
|
|
65
|
+
memory: state.memory,
|
|
66
|
+
state: state,
|
|
67
|
+
system: { currentTime: new Date().toISOString() },
|
|
68
|
+
};
|
|
69
|
+
|
|
62
70
|
// Compile the prompt with parameters
|
|
63
|
-
const compiledPrompt = compilePrompt(node.prompt,
|
|
71
|
+
const compiledPrompt = compilePrompt(node.prompt, { ...promptParams });
|
|
64
72
|
|
|
65
73
|
// Build the full prompt with compiled content
|
|
66
74
|
const fullPrompt = `
|
|
@@ -53,7 +53,7 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
|
|
|
53
53
|
}));
|
|
54
54
|
|
|
55
55
|
// We compile the env variables to avoid having to pass them to the platform in the tool input
|
|
56
|
-
const promptCompiledWithEnv = compilePrompt(prompt,
|
|
56
|
+
const promptCompiledWithEnv = compilePrompt(prompt, { env: process.env });
|
|
57
57
|
|
|
58
58
|
const { browserTaskMode } = getConfig();
|
|
59
59
|
|
|
@@ -111,6 +111,7 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
|
|
|
111
111
|
hasResult: !!result.result,
|
|
112
112
|
stepCount: result.steps?.length || 0,
|
|
113
113
|
recordingCount: result.recordings?.length || 0,
|
|
114
|
+
downloadedFilesCount: result.downloadedFiles?.length || 0,
|
|
114
115
|
});
|
|
115
116
|
|
|
116
117
|
// Create tool message with the result
|
|
@@ -121,6 +122,7 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
|
|
|
121
122
|
steps: result.steps || [],
|
|
122
123
|
recordings: result.recordings || [],
|
|
123
124
|
inputParams: inputParams,
|
|
125
|
+
downloadedFiles: result.downloadedFiles || [],
|
|
124
126
|
}),
|
|
125
127
|
name: 'browser-task',
|
|
126
128
|
tool_call_id: toolCall.id,
|
|
@@ -133,6 +135,7 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
|
|
|
133
135
|
steps: result.steps,
|
|
134
136
|
recordings: result.recordings,
|
|
135
137
|
inputParams: inputParams,
|
|
138
|
+
downloadedFiles: result.downloadedFiles || [],
|
|
136
139
|
},
|
|
137
140
|
},
|
|
138
141
|
});
|
|
@@ -149,6 +152,7 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
|
|
|
149
152
|
nodeDisplayName: browserTaskNode.displayName,
|
|
150
153
|
steps: result.steps,
|
|
151
154
|
recordings: result.recordings,
|
|
155
|
+
downloadedFiles: result.downloadedFiles || [],
|
|
152
156
|
status: 'completed',
|
|
153
157
|
},
|
|
154
158
|
update: true, // This triggers the message reducer to update the existing message
|
|
@@ -51,7 +51,7 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
51
51
|
if (combinedPlaybooks) {
|
|
52
52
|
finalMessage = combinedPlaybooks + '\n\n' + currentPromptNode;
|
|
53
53
|
}
|
|
54
|
-
const compiledPrompt = compilePrompt(finalMessage, state);
|
|
54
|
+
const compiledPrompt = compilePrompt(finalMessage, { state: state, memory: state.memory, env: process.env });
|
|
55
55
|
const systemMessage = new SystemMessage(compiledPrompt);
|
|
56
56
|
if (state.messages.length === 0 || state.messages[0].getType() === 'system') {
|
|
57
57
|
state.messages[0] = systemMessage;
|
package/src/nodes/addToolNode.ts
CHANGED
|
@@ -52,7 +52,7 @@ export const addToolNode = async ({
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
if (finalMessage) {
|
|
55
|
-
const compiledPrompt = compilePrompt(finalMessage, state);
|
|
55
|
+
const compiledPrompt = compilePrompt(finalMessage, { state: state, memory: state.memory, env: process.env });
|
|
56
56
|
const systemMessage = new SystemMessage(compiledPrompt);
|
|
57
57
|
if (state.messages.length === 0 || state.messages[0].getType() === 'system') {
|
|
58
58
|
state.messages[0] = systemMessage;
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import * as ejs from 'ejs';
|
|
2
2
|
import { logger } from '../utils/logger';
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
/**
|
|
5
5
|
* Compile prompt with parameters using EJS and placeholder replacement
|
|
6
6
|
*/
|
|
7
|
-
export function compilePrompt(prompt: string,
|
|
7
|
+
export function compilePrompt(prompt: string, params: Record<string, any> = {}): string {
|
|
8
8
|
try {
|
|
9
|
-
//
|
|
9
|
+
// Define system parameters
|
|
10
10
|
params.system = { currentTime: new Date().toISOString() };
|
|
11
|
-
params.env = process.env;
|
|
12
|
-
params.state = state;
|
|
13
|
-
params.memory = state.memory;
|
|
14
11
|
|
|
15
12
|
// First, render with EJS
|
|
16
13
|
let compiledPrompt = ejs.render(prompt, params);
|
|
@@ -15,11 +15,17 @@ export async function executeRpaStep(
|
|
|
15
15
|
state: typeof stateAnnotation.State,
|
|
16
16
|
llm: (typeof LLMProviders)[keyof typeof LLMProviders],
|
|
17
17
|
): Promise<any> {
|
|
18
|
+
// Create params object with memory and secrets
|
|
19
|
+
const params = {
|
|
20
|
+
env: process.env,
|
|
21
|
+
state: state,
|
|
22
|
+
};
|
|
23
|
+
|
|
18
24
|
switch (step.type) {
|
|
19
25
|
case RpaActionType.CLICK: {
|
|
20
26
|
// Compile selectors in case they contain placeholders
|
|
21
|
-
const compiledXpath = step.xpath ? compilePrompt(step.xpath,
|
|
22
|
-
const compiledSelector = step.selector ? compilePrompt(step.selector,
|
|
27
|
+
const compiledXpath = step.xpath ? compilePrompt(step.xpath, params) : undefined;
|
|
28
|
+
const compiledSelector = step.selector ? compilePrompt(step.selector, params) : undefined;
|
|
23
29
|
|
|
24
30
|
if (compiledXpath) {
|
|
25
31
|
await page.locator(`xpath=${compiledXpath}`).click({ timeout: 15000 });
|
|
@@ -31,9 +37,9 @@ export async function executeRpaStep(
|
|
|
31
37
|
|
|
32
38
|
case RpaActionType.TYPE: {
|
|
33
39
|
// Compile text and selectors
|
|
34
|
-
const compiledText = step.text ? compilePrompt(step.text,
|
|
35
|
-
const compiledTypeXpath = step.xpath ? compilePrompt(step.xpath,
|
|
36
|
-
const compiledTypeSelector = step.selector ? compilePrompt(step.selector,
|
|
40
|
+
const compiledText = step.text ? compilePrompt(step.text, params) : '';
|
|
41
|
+
const compiledTypeXpath = step.xpath ? compilePrompt(step.xpath, params) : undefined;
|
|
42
|
+
const compiledTypeSelector = step.selector ? compilePrompt(step.selector, params) : undefined;
|
|
37
43
|
|
|
38
44
|
if (step.shouldReplaceExistingText) {
|
|
39
45
|
if (compiledTypeXpath) {
|
|
@@ -57,23 +63,23 @@ export async function executeRpaStep(
|
|
|
57
63
|
|
|
58
64
|
case RpaActionType.GOTO: {
|
|
59
65
|
// Compile URL
|
|
60
|
-
const compiledUrl = step.url ? compilePrompt(step.url,
|
|
66
|
+
const compiledUrl = step.url ? compilePrompt(step.url, params) : '';
|
|
61
67
|
await page.goto(compiledUrl, { waitUntil: 'load', timeout: 15000 });
|
|
62
68
|
return { action: 'navigated', url: compiledUrl };
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
case RpaActionType.PRESS: {
|
|
66
72
|
// Compile key
|
|
67
|
-
const compiledKey = step.key ? compilePrompt(step.key,
|
|
73
|
+
const compiledKey = step.key ? compilePrompt(step.key, params) : 'Enter';
|
|
68
74
|
await page.keyboard.press(compiledKey);
|
|
69
75
|
return { action: 'pressed', key: compiledKey };
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
case RpaActionType.SELECT: {
|
|
73
79
|
// Compile value and selectors
|
|
74
|
-
const compiledValue = step.value ? compilePrompt(step.value,
|
|
75
|
-
const compiledSelectXpath = step.xpath ? compilePrompt(step.xpath,
|
|
76
|
-
const compiledSelectSelector = step.selector ? compilePrompt(step.selector,
|
|
80
|
+
const compiledValue = step.value ? compilePrompt(step.value, params) : '';
|
|
81
|
+
const compiledSelectXpath = step.xpath ? compilePrompt(step.xpath, params) : undefined;
|
|
82
|
+
const compiledSelectSelector = step.selector ? compilePrompt(step.selector, params) : undefined;
|
|
77
83
|
|
|
78
84
|
if (compiledSelectXpath) {
|
|
79
85
|
await page.locator(`xpath=${compiledSelectXpath}`).selectOption(compiledValue, { timeout: 15000 });
|
|
@@ -86,7 +92,7 @@ export async function executeRpaStep(
|
|
|
86
92
|
case RpaActionType.SCREENSHOT: {
|
|
87
93
|
const screenshot = await page.screenshot({ type: 'png' });
|
|
88
94
|
// Compile description if provided
|
|
89
|
-
const compiledDescription = step.description ? compilePrompt(step.description,
|
|
95
|
+
const compiledDescription = step.description ? compilePrompt(step.description, params) : undefined;
|
|
90
96
|
return {
|
|
91
97
|
action: 'screenshot',
|
|
92
98
|
description: compiledDescription,
|
|
@@ -471,6 +471,7 @@ export interface InvokeBrowserTaskResponse extends BaseSdkConnectionSocketMessag
|
|
|
471
471
|
result?: any;
|
|
472
472
|
steps?: any[];
|
|
473
473
|
recordings?: any[];
|
|
474
|
+
downloadedFiles?: string[];
|
|
474
475
|
}
|
|
475
476
|
|
|
476
477
|
export interface ExecuteToolRequest extends BasemindedConnectionSocketMessage {
|