@minded-ai/mindedjs 2.0.9-beta.3 → 2.0.10
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.js +1 -1
- package/dist/agent.js.map +1 -1
- package/dist/browserTask/executeBrowserTask.d.ts.map +1 -1
- package/dist/browserTask/executeBrowserTask.js +47 -18
- package/dist/browserTask/executeBrowserTask.js.map +1 -1
- package/dist/browserTask/executeBrowserTask.py +76 -7
- package/dist/cli/index.js +0 -0
- package/dist/edges/createPromptRouter.d.ts.map +1 -1
- package/dist/edges/createPromptRouter.js +2 -0
- package/dist/edges/createPromptRouter.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/nodes/addAppToolNode.js +1 -1
- package/dist/nodes/addAppToolNode.js.map +1 -1
- package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -1
- package/dist/nodes/addBrowserTaskNode.js +6 -26
- package/dist/nodes/addBrowserTaskNode.js.map +1 -1
- package/dist/nodes/addPromptNode.js +1 -1
- package/dist/nodes/addPromptNode.js.map +1 -1
- package/dist/nodes/addRpaNode.d.ts +18 -0
- package/dist/nodes/addRpaNode.d.ts.map +1 -0
- package/dist/nodes/addRpaNode.js +162 -0
- package/dist/nodes/addRpaNode.js.map +1 -0
- package/dist/nodes/addToolNode.js +1 -1
- package/dist/nodes/addToolNode.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/nodes/rpaStepsExecutor.d.ts +5 -0
- package/dist/nodes/rpaStepsExecutor.d.ts.map +1 -0
- package/dist/nodes/rpaStepsExecutor.js +156 -0
- package/dist/nodes/rpaStepsExecutor.js.map +1 -0
- package/dist/types/Flows.types.d.ts +41 -2
- package/dist/types/Flows.types.d.ts.map +1 -1
- package/dist/types/Flows.types.js +13 -1
- package/dist/types/Flows.types.js.map +1 -1
- package/dist/utils/schemaUtils.d.ts +15 -0
- package/dist/utils/schemaUtils.d.ts.map +1 -0
- package/dist/utils/schemaUtils.js +56 -0
- package/dist/utils/schemaUtils.js.map +1 -0
- package/package.json +2 -2
- package/src/agent.ts +1 -1
- package/src/browserTask/executeBrowserTask.py +76 -7
- package/src/browserTask/executeBrowserTask.ts +56 -16
- package/src/edges/createPromptRouter.ts +7 -5
- package/src/index.ts +3 -0
- package/src/nodes/addAppToolNode.ts +1 -1
- package/src/nodes/addBrowserTaskNode.ts +7 -30
- package/src/nodes/addPromptNode.ts +1 -1
- package/src/nodes/addRpaNode.ts +199 -0
- package/src/nodes/addToolNode.ts +1 -1
- package/src/nodes/nodeFactory.ts +4 -0
- package/src/nodes/rpaStepsExecutor.ts +175 -0
- package/src/types/Flows.types.ts +43 -1
- package/src/utils/schemaUtils.ts +68 -0
- package/dist/browserTask/cdp.d.ts +0 -23
- package/dist/browserTask/cdp.d.ts.map +0 -1
- package/dist/browserTask/cdp.js +0 -162
- package/dist/browserTask/cdp.js.map +0 -1
- package/dist/guidelines/guidelinesManager.d.ts +0 -37
- package/dist/guidelines/guidelinesManager.d.ts.map +0 -1
- package/dist/guidelines/guidelinesManager.js +0 -172
- package/dist/guidelines/guidelinesManager.js.map +0 -1
- package/dist/internalTools/retell.d.ts +0 -12
- package/dist/internalTools/retell.d.ts.map +0 -1
- package/dist/internalTools/retell.js +0 -54
- package/dist/internalTools/retell.js.map +0 -1
- package/dist/internalTools/sendPlaceholderMessage.d.ts +0 -14
- package/dist/internalTools/sendPlaceholderMessage.d.ts.map +0 -1
- package/dist/internalTools/sendPlaceholderMessage.js +0 -61
- package/dist/internalTools/sendPlaceholderMessage.js.map +0 -1
- package/dist/platform/mindedChatOpenAI.d.ts +0 -5
- package/dist/platform/mindedChatOpenAI.d.ts.map +0 -1
- package/dist/platform/mindedChatOpenAI.js +0 -23
- package/dist/platform/mindedChatOpenAI.js.map +0 -1
- package/dist/utils/extractStateMemoryResponse.d.ts +0 -5
- package/dist/utils/extractStateMemoryResponse.d.ts.map +0 -1
- package/dist/utils/extractStateMemoryResponse.js +0 -91
- package/dist/utils/extractStateMemoryResponse.js.map +0 -1
- package/dist/utils/extractToolMemoryResponse.d.ts +0 -4
- package/dist/utils/extractToolMemoryResponse.d.ts.map +0 -1
- package/dist/utils/extractToolMemoryResponse.js +0 -16
- package/dist/utils/extractToolMemoryResponse.js.map +0 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export interface SchemaField {
|
|
3
|
+
name: string;
|
|
4
|
+
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
5
|
+
description?: string;
|
|
6
|
+
required?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Converts an array of schema field definitions to a Zod object schema
|
|
10
|
+
* @param fields Array of field definitions
|
|
11
|
+
* @param defaultSchema Optional default schema to use if no fields are provided
|
|
12
|
+
* @returns Zod object schema
|
|
13
|
+
*/
|
|
14
|
+
export declare function createZodSchemaFromFields(fields?: SchemaField[], defaultSchema?: Record<string, z.ZodTypeAny>): z.ZodObject<Record<string, z.ZodTypeAny>>;
|
|
15
|
+
//# sourceMappingURL=schemaUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaUtils.d.ts","sourceRoot":"","sources":["../../src/utils/schemaUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,CAAC,EAAE,WAAW,EAAE,EACtB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,GAC3C,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAiD3C"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createZodSchemaFromFields = createZodSchemaFromFields;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Converts an array of schema field definitions to a Zod object schema
|
|
7
|
+
* @param fields Array of field definitions
|
|
8
|
+
* @param defaultSchema Optional default schema to use if no fields are provided
|
|
9
|
+
* @returns Zod object schema
|
|
10
|
+
*/
|
|
11
|
+
function createZodSchemaFromFields(fields, defaultSchema) {
|
|
12
|
+
const schemaFields = {};
|
|
13
|
+
if (fields && fields.length > 0) {
|
|
14
|
+
for (const field of fields) {
|
|
15
|
+
let fieldSchema;
|
|
16
|
+
// Create appropriate Zod type based on field type
|
|
17
|
+
switch (field.type) {
|
|
18
|
+
case 'string':
|
|
19
|
+
fieldSchema = zod_1.z.string();
|
|
20
|
+
break;
|
|
21
|
+
case 'number':
|
|
22
|
+
fieldSchema = zod_1.z.number();
|
|
23
|
+
break;
|
|
24
|
+
case 'boolean':
|
|
25
|
+
fieldSchema = zod_1.z.boolean();
|
|
26
|
+
break;
|
|
27
|
+
case 'array':
|
|
28
|
+
// For arrays, we'll default to array of any unless more specific
|
|
29
|
+
fieldSchema = zod_1.z.array(zod_1.z.any());
|
|
30
|
+
break;
|
|
31
|
+
case 'object':
|
|
32
|
+
// For objects, we'll default to record of any unless more specific
|
|
33
|
+
fieldSchema = zod_1.z.record(zod_1.z.any());
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
// Default to string for unknown types
|
|
37
|
+
fieldSchema = zod_1.z.string();
|
|
38
|
+
}
|
|
39
|
+
// Add description if available
|
|
40
|
+
if (field.description) {
|
|
41
|
+
fieldSchema = fieldSchema.describe(field.description);
|
|
42
|
+
}
|
|
43
|
+
// Handle optional fields
|
|
44
|
+
if (field.required === false) {
|
|
45
|
+
fieldSchema = fieldSchema.optional();
|
|
46
|
+
}
|
|
47
|
+
schemaFields[field.name] = fieldSchema;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (defaultSchema) {
|
|
51
|
+
// Use default schema if no fields provided
|
|
52
|
+
return zod_1.z.object(defaultSchema);
|
|
53
|
+
}
|
|
54
|
+
return zod_1.z.object(schemaFields);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=schemaUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaUtils.js","sourceRoot":"","sources":["../../src/utils/schemaUtils.ts"],"names":[],"mappings":";;AAeA,8DAoDC;AAnED,6BAAwB;AASxB;;;;;GAKG;AACH,SAAgB,yBAAyB,CACvC,MAAsB,EACtB,aAA4C;IAE5C,MAAM,YAAY,GAAiC,EAAE,CAAC;IAEtD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,WAAyB,CAAC;YAE9B,kDAAkD;YAClD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;gBACnB,KAAK,QAAQ;oBACX,WAAW,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC;oBACzB,MAAM;gBACR,KAAK,QAAQ;oBACX,WAAW,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC;oBACzB,MAAM;gBACR,KAAK,SAAS;oBACZ,WAAW,GAAG,OAAC,CAAC,OAAO,EAAE,CAAC;oBAC1B,MAAM;gBACR,KAAK,OAAO;oBACV,iEAAiE;oBACjE,WAAW,GAAG,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC;oBAC/B,MAAM;gBACR,KAAK,QAAQ;oBACX,mEAAmE;oBACnE,WAAW,GAAG,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC;oBAChC,MAAM;gBACR;oBACE,sCAAsC;oBACtC,WAAW,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC;YAC7B,CAAC;YAED,+BAA+B;YAC/B,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;gBACtB,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACxD,CAAC;YAED,yBAAyB;YACzB,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;gBAC7B,WAAW,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC;YACvC,CAAC;YAED,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC;QACzC,CAAC;IACH,CAAC;SAAM,IAAI,aAAa,EAAE,CAAC;QACzB,2CAA2C;QAC3C,OAAO,OAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,OAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;AAChC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minded-ai/mindedjs",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"description": "MindedJS is a TypeScript library for building agents.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -70,4 +70,4 @@
|
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"playwright": "^1.55.0"
|
|
72
72
|
}
|
|
73
|
-
}
|
|
73
|
+
}
|
package/src/agent.ts
CHANGED
|
@@ -465,7 +465,7 @@ export class Agent {
|
|
|
465
465
|
// Add playbooks to messages
|
|
466
466
|
const combinedPlaybooks = combinePlaybooks(this.playbooks);
|
|
467
467
|
if (combinedPlaybooks) {
|
|
468
|
-
const compiledPrompt = compilePrompt(combinedPlaybooks, { memory: state.memory });
|
|
468
|
+
const compiledPrompt = compilePrompt(combinedPlaybooks, { state: state, memory: state.memory, env: process.env });
|
|
469
469
|
const systemMessage = new SystemMessage(compiledPrompt);
|
|
470
470
|
if (state.messages.length === 0 || state.messages[0].getType() === 'system') {
|
|
471
471
|
state.messages[0] = systemMessage;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
|
|
2
|
+
import json
|
|
3
|
+
from typing import List, Optional, Dict, Any, TypedDict
|
|
4
|
+
from pydantic import BaseModel, create_model, Field
|
|
5
|
+
from browser_use import Agent, Controller
|
|
6
|
+
from browser_use.browser import BrowserProfile, BrowserSession
|
|
3
7
|
from browser_use.llm import ChatOpenAI
|
|
4
8
|
import os
|
|
5
9
|
import sys
|
|
@@ -7,7 +11,39 @@ from dotenv import load_dotenv
|
|
|
7
11
|
|
|
8
12
|
load_dotenv()
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
class OutputSchemaItemRequired(TypedDict):
|
|
15
|
+
name: str
|
|
16
|
+
type: str # 'string' | 'number'
|
|
17
|
+
|
|
18
|
+
class OutputSchemaItem(OutputSchemaItemRequired, total=False):
|
|
19
|
+
description: str
|
|
20
|
+
required: bool
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def create_pydantic_model_from_schema(output_schema: Optional[List[Dict[str, Any]]]) -> Optional[type[BaseModel]]:
|
|
24
|
+
if not output_schema:
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
field_definitions: Dict[str, Any] = {}
|
|
28
|
+
for item in output_schema:
|
|
29
|
+
type_mapping = {
|
|
30
|
+
'string': str,
|
|
31
|
+
'number': float,
|
|
32
|
+
}
|
|
33
|
+
field_type = type_mapping.get(item.get('type'), str)
|
|
34
|
+
description = item.get('description', '')
|
|
35
|
+
is_required = item.get('required', True)
|
|
36
|
+
if is_required:
|
|
37
|
+
field_definitions[item['name']] = (field_type, Field(description=description))
|
|
38
|
+
else:
|
|
39
|
+
field_definitions[item['name']] = (Optional[field_type], Field(default=None, description=description))
|
|
40
|
+
|
|
41
|
+
if field_definitions:
|
|
42
|
+
return create_model('DynamicOutputModel', **field_definitions)
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def main(session_id: str, cdp_url: str, task: str, output_schema_json: Optional[str] = None):
|
|
11
47
|
llm = ChatOpenAI(
|
|
12
48
|
model="gpt-4.1",
|
|
13
49
|
api_key=os.getenv("OPENAI_API_KEY"),
|
|
@@ -24,19 +60,52 @@ async def main(session_id: str, cdp_url: str, task: str):
|
|
|
24
60
|
browser_profile=BrowserProfile(downloads_path=folder_path),
|
|
25
61
|
cdp_url=cdp_url
|
|
26
62
|
)
|
|
63
|
+
|
|
64
|
+
output_schema = None
|
|
65
|
+
if output_schema_json:
|
|
66
|
+
try:
|
|
67
|
+
output_schema = json.loads(output_schema_json)
|
|
68
|
+
except Exception:
|
|
69
|
+
output_schema = None
|
|
70
|
+
|
|
71
|
+
output_model = create_pydantic_model_from_schema(output_schema)
|
|
72
|
+
|
|
27
73
|
agent = Agent(
|
|
28
74
|
task=task,
|
|
29
75
|
llm=llm,
|
|
76
|
+
controller=Controller(output_model=output_model) if output_model is not None else Controller(),
|
|
30
77
|
available_file_paths=available_files,
|
|
31
|
-
|
|
78
|
+
browser_session=browser_session,
|
|
32
79
|
)
|
|
33
80
|
history = await agent.run()
|
|
34
|
-
|
|
81
|
+
final_result = history.final_result()
|
|
82
|
+
|
|
83
|
+
# Parse result with output model if provided
|
|
84
|
+
parsed_result = None
|
|
85
|
+
if output_model and final_result:
|
|
86
|
+
try:
|
|
87
|
+
# Validate and parse the result using the Pydantic model
|
|
88
|
+
parsed_result = output_model.model_validate_json(final_result)
|
|
89
|
+
# Convert to dict for JSON serialization
|
|
90
|
+
parsed_result = parsed_result.model_dump()
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f"Failed to parse result with output model: {e}")
|
|
93
|
+
# Fall back to raw result
|
|
94
|
+
parsed_result = final_result
|
|
95
|
+
else:
|
|
96
|
+
parsed_result = final_result
|
|
97
|
+
|
|
98
|
+
print("___RESULT___")
|
|
99
|
+
if parsed_result:
|
|
100
|
+
print(json.dumps(parsed_result, indent=2))
|
|
101
|
+
else:
|
|
102
|
+
print(final_result)
|
|
35
103
|
|
|
36
104
|
if __name__ == '__main__':
|
|
37
|
-
if len(sys.argv) <
|
|
38
|
-
raise SystemExit("Usage: uv run
|
|
105
|
+
if len(sys.argv) < 4:
|
|
106
|
+
raise SystemExit("Usage: uv run executeBrowserTask.py <session_id> <cdp_url> <task> [output_schema_json]")
|
|
39
107
|
session_id = sys.argv[1]
|
|
40
108
|
cdp_url = sys.argv[2]
|
|
41
109
|
task = sys.argv[3]
|
|
42
|
-
|
|
110
|
+
output_schema_json = sys.argv[4] if len(sys.argv) > 4 else None
|
|
111
|
+
asyncio.run(main(session_id, cdp_url, task, output_schema_json))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
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';
|
|
@@ -11,9 +11,7 @@ import {
|
|
|
11
11
|
DestroyBrowserSessionRequest,
|
|
12
12
|
DestroyBrowserSessionResponse,
|
|
13
13
|
} from '../platform/mindedConnectionTypes';
|
|
14
|
-
import { promisify } from 'node:util';
|
|
15
14
|
import { kill, getOrStartLocalCDP } from './localBrowserTask';
|
|
16
|
-
const exec = promisify(execCb);
|
|
17
15
|
|
|
18
16
|
// Socket-based browser task functions
|
|
19
17
|
export const createBrowserSession = async ({ sessionId, proxy, onPrem, localRun }: { sessionId: string, proxy?: string, onPrem?: boolean, localRun?: boolean }): Promise<CreateBrowserSessionResponse> => {
|
|
@@ -96,30 +94,72 @@ export const invokeBrowserTask = async (
|
|
|
96
94
|
required?: boolean;
|
|
97
95
|
}[],
|
|
98
96
|
): Promise<InvokeBrowserTaskResponse> => {
|
|
99
|
-
logger.debug({
|
|
100
|
-
msg: 'Invoking browser task via socket',
|
|
101
|
-
sessionId,
|
|
102
|
-
taskLength: task.length,
|
|
103
|
-
keepAlive,
|
|
104
|
-
hooksCount: hooks?.length || 0,
|
|
105
|
-
onPrem,
|
|
106
|
-
outputSchemaFields: outputSchema?.length || 0,
|
|
107
|
-
});
|
|
108
97
|
|
|
109
98
|
try {
|
|
110
99
|
|
|
111
100
|
if (localRun) {
|
|
112
101
|
const pythonScriptPath = path.resolve(__dirname, 'executeBrowserTask.py');
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
const outputSchemaArg = JSON.stringify(outputSchema || []);
|
|
103
|
+
|
|
104
|
+
const args = ['run', pythonScriptPath, sessionId, cdpUrl, task, outputSchemaArg];
|
|
105
|
+
|
|
106
|
+
logger.info({ message: 'Spawning Python process', args });
|
|
107
|
+
|
|
108
|
+
const child = spawn('uv', args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
109
|
+
|
|
110
|
+
let stdoutBuffer = '';
|
|
111
|
+
let stderrBuffer = '';
|
|
112
|
+
|
|
113
|
+
child.stdout.on('data', (data) => {
|
|
114
|
+
const text = data.toString();
|
|
115
|
+
stdoutBuffer += text;
|
|
116
|
+
process.stdout.write(text);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
child.stderr.on('data', (data) => {
|
|
120
|
+
const text = data.toString();
|
|
121
|
+
stderrBuffer += text;
|
|
122
|
+
process.stderr.write(text);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const exitCode: number = await new Promise((resolve, reject) => {
|
|
126
|
+
child.on('error', (err) => reject(err));
|
|
127
|
+
child.on('close', (code) => resolve(code ?? 1));
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
if (exitCode !== 0) {
|
|
131
|
+
logger.error({ message: 'Operator failed', exitCode, stderr: stderrBuffer });
|
|
132
|
+
throw new Error(`Local browser task failed with exit code ${exitCode}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
logger.info({ message: 'Operator finished' });
|
|
136
|
+
|
|
137
|
+
let result = stdoutBuffer.split('___RESULT___')[1]?.trim() || stdoutBuffer;
|
|
138
|
+
if (outputSchema?.length) {
|
|
139
|
+
try {
|
|
140
|
+
result = JSON.parse(result);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
logger.debug({ message: 'Failed to parse result', error });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
116
146
|
return {
|
|
117
|
-
result
|
|
147
|
+
result,
|
|
118
148
|
steps: [],
|
|
119
149
|
recordings: [],
|
|
120
150
|
};
|
|
121
151
|
}
|
|
122
152
|
|
|
153
|
+
logger.debug({
|
|
154
|
+
msg: 'Invoking browser task via socket',
|
|
155
|
+
sessionId,
|
|
156
|
+
taskLength: task.length,
|
|
157
|
+
keepAlive,
|
|
158
|
+
hooksCount: hooks?.length || 0,
|
|
159
|
+
onPrem,
|
|
160
|
+
outputSchemaFields: outputSchema?.length || 0,
|
|
161
|
+
});
|
|
162
|
+
|
|
123
163
|
const response = await mindedConnection.awaitEmit<InvokeBrowserTaskRequest, InvokeBrowserTaskResponse>(
|
|
124
164
|
mindedConnectionSocketMessageType.INVOKE_BROWSER_TASK,
|
|
125
165
|
{
|
|
@@ -111,17 +111,19 @@ export const createPromptRouter = ({
|
|
|
111
111
|
steps: stepsStr,
|
|
112
112
|
messages: messagesStr,
|
|
113
113
|
memory: state.memory,
|
|
114
|
+
state: state,
|
|
115
|
+
env: process.env,
|
|
114
116
|
});
|
|
115
117
|
|
|
116
118
|
// Define response schema
|
|
117
119
|
const responseSchema = includeReasoning
|
|
118
120
|
? z.object({
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
nextNodeId: z.string(),
|
|
122
|
+
reasoning: z.string(),
|
|
123
|
+
})
|
|
122
124
|
: z.object({
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
nextNodeId: z.string(),
|
|
126
|
+
});
|
|
125
127
|
|
|
126
128
|
let attempts = 0;
|
|
127
129
|
let lastError: Error | null = null;
|
package/src/index.ts
CHANGED
|
@@ -48,6 +48,8 @@ export type {
|
|
|
48
48
|
VoiceTriggerNode,
|
|
49
49
|
WebhookTriggerNode,
|
|
50
50
|
InterfaceTriggerNode,
|
|
51
|
+
RpaNode,
|
|
52
|
+
RpaStep,
|
|
51
53
|
} from './types/Flows.types';
|
|
52
54
|
export {
|
|
53
55
|
NodeType,
|
|
@@ -57,6 +59,7 @@ export {
|
|
|
57
59
|
AppNodeMetadataType,
|
|
58
60
|
NodeMetadata,
|
|
59
61
|
KnownTriggerNames,
|
|
62
|
+
RpaActionType,
|
|
60
63
|
} from './types/Flows.types';
|
|
61
64
|
export type { Tool, ToolExecuteInput } from './types/Tools.types';
|
|
62
65
|
|
|
@@ -70,7 +70,7 @@ export const addAppToolNode = async ({
|
|
|
70
70
|
User instructions for choosing tool parameters are:
|
|
71
71
|
${node.prompt ? `${node.prompt}` : 'no instructions set by the user'}`;
|
|
72
72
|
|
|
73
|
-
const compiledPrompt = compilePrompt(message, { memory: state.memory });
|
|
73
|
+
const compiledPrompt = compilePrompt(message, { state: state, memory: state.memory, env: process.env });
|
|
74
74
|
const systemMessage = new SystemMessage(compiledPrompt);
|
|
75
75
|
if (state.messages.length === 0 || state.messages[0].getType() === 'system') {
|
|
76
76
|
state.messages[0] = systemMessage;
|
|
@@ -9,10 +9,10 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
9
9
|
import { Agent } from '../agent';
|
|
10
10
|
import { createBrowserSession } from '../browserTask/executeBrowserTask';
|
|
11
11
|
import { tool as langchainTool } from '@langchain/core/tools';
|
|
12
|
-
import { z } from 'zod';
|
|
13
12
|
import { LLMProviders } from '../types/LLM.types';
|
|
14
13
|
import { compilePrompt } from './compilePrompt';
|
|
15
14
|
import { combinePlaybooks } from '../playbooks/playbooks';
|
|
15
|
+
import { createZodSchemaFromFields } from '../utils/schemaUtils';
|
|
16
16
|
|
|
17
17
|
type AddBrowserTaskNodeParams = {
|
|
18
18
|
graph: PreCompiledGraph;
|
|
@@ -26,35 +26,10 @@ export const addBrowserTaskNode = async ({ graph, node, agent, llm }: AddBrowser
|
|
|
26
26
|
logger.info({ msg: `Executing browser task node ${node.displayName}`, prompt: node.prompt });
|
|
27
27
|
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
28
28
|
// Create Zod schema from inputSchema
|
|
29
|
-
const
|
|
30
|
-
if (node.inputSchema) {
|
|
31
|
-
for (const field of node.inputSchema) {
|
|
32
|
-
let fieldSchema: z.ZodTypeAny;
|
|
33
|
-
|
|
34
|
-
if (field.type === 'string') {
|
|
35
|
-
fieldSchema = z.string();
|
|
36
|
-
} else if (field.type === 'number') {
|
|
37
|
-
fieldSchema = z.number();
|
|
38
|
-
} else {
|
|
39
|
-
fieldSchema = z.string(); // Default to string
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (field.description) {
|
|
43
|
-
fieldSchema = fieldSchema.describe(field.description);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (field.required === false) {
|
|
47
|
-
fieldSchema = fieldSchema.optional();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
schemaFields[field.name] = fieldSchema;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const zodSchema = z.object(schemaFields);
|
|
29
|
+
const zodSchema = createZodSchemaFromFields(node.inputSchema);
|
|
55
30
|
|
|
56
31
|
// Create langchain tool
|
|
57
|
-
const tool = langchainTool(() => {
|
|
32
|
+
const tool = langchainTool(() => {}, {
|
|
58
33
|
name: 'browser-task',
|
|
59
34
|
description: node.prompt,
|
|
60
35
|
schema: zodSchema,
|
|
@@ -62,7 +37,7 @@ export const addBrowserTaskNode = async ({ graph, node, agent, llm }: AddBrowser
|
|
|
62
37
|
|
|
63
38
|
const combinedPlaybooks = combinePlaybooks(agent.playbooks);
|
|
64
39
|
if (combinedPlaybooks) {
|
|
65
|
-
const compiledPrompt = compilePrompt(combinedPlaybooks, { memory: state.memory });
|
|
40
|
+
const compiledPrompt = compilePrompt(combinedPlaybooks, { state: state, memory: state.memory, env: process.env });
|
|
66
41
|
const systemMessage = new SystemMessage(compiledPrompt);
|
|
67
42
|
if (state.messages.length === 0 || state.messages[0].getType() === 'system') {
|
|
68
43
|
state.messages[0] = systemMessage;
|
|
@@ -86,11 +61,12 @@ export const addBrowserTaskNode = async ({ graph, node, agent, llm }: AddBrowser
|
|
|
86
61
|
const promptParams = {
|
|
87
62
|
input: inputParams,
|
|
88
63
|
memory: state.memory,
|
|
64
|
+
state: state,
|
|
89
65
|
system: { currentTime: new Date().toISOString() },
|
|
90
66
|
};
|
|
91
67
|
|
|
92
68
|
// Compile the prompt with parameters
|
|
93
|
-
const compiledPrompt = compilePrompt(node.prompt, promptParams);
|
|
69
|
+
const compiledPrompt = compilePrompt(node.prompt, { ...promptParams, env: process.env });
|
|
94
70
|
|
|
95
71
|
// Build the full prompt with compiled content
|
|
96
72
|
const fullPrompt = `
|
|
@@ -145,6 +121,7 @@ ${Object.keys(inputParams).length > 0 ? `# Input parameters:\n${JSON.stringify(i
|
|
|
145
121
|
keepAlive,
|
|
146
122
|
hooks: node.hooks || [],
|
|
147
123
|
onPrem: node.onPrem,
|
|
124
|
+
localRun: node.localRun,
|
|
148
125
|
outputSchema: node.outputSchema,
|
|
149
126
|
},
|
|
150
127
|
},
|
|
@@ -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, { memory: state.memory });
|
|
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;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { RunnableLike } from '@langchain/core/runnables';
|
|
2
|
+
import { NodeType, RpaNode, RpaActionType } from '../types/Flows.types';
|
|
3
|
+
import { PreCompiledGraph, stateAnnotation } from '../types/LangGraph.types';
|
|
4
|
+
import { Tool } from '../types/Tools.types';
|
|
5
|
+
import { AgentEventRequestPayloads } from '../events/AgentEvents';
|
|
6
|
+
import { EmitSignature, HistoryStep } from '../types/Agent.types';
|
|
7
|
+
import { Agent } from '../agent';
|
|
8
|
+
import { logger } from '../utils/logger';
|
|
9
|
+
import { createHistoryStep } from '../utils/history';
|
|
10
|
+
import { chromium, Browser, Page } from 'playwright';
|
|
11
|
+
import { LLMProviders } from '../types/LLM.types';
|
|
12
|
+
import { AIMessage, ToolMessage } from '@langchain/core/messages';
|
|
13
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
14
|
+
import { executeRpaStep } from './rpaStepsExecutor';
|
|
15
|
+
|
|
16
|
+
type AddRpaNodeParams = {
|
|
17
|
+
graph: PreCompiledGraph;
|
|
18
|
+
node: RpaNode;
|
|
19
|
+
tools: Tool<any, any>[];
|
|
20
|
+
emit: EmitSignature<any, keyof AgentEventRequestPayloads<any>>;
|
|
21
|
+
agent: Agent;
|
|
22
|
+
llm: (typeof LLMProviders)[keyof typeof LLMProviders];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const addRpaNode = async ({ graph, node, agent, llm }: AddRpaNodeParams) => {
|
|
26
|
+
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
27
|
+
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
28
|
+
logger.info({ msg: `[Node] Executing RPA node`, node: node.displayName, sessionId: state.sessionId });
|
|
29
|
+
|
|
30
|
+
let browser: Browser | null = null;
|
|
31
|
+
let page: Page | null = null;
|
|
32
|
+
|
|
33
|
+
// Create tool call for RPA execution
|
|
34
|
+
const toolCallId = uuidv4();
|
|
35
|
+
const aiMessageId = uuidv4();
|
|
36
|
+
|
|
37
|
+
// Get CDP URL from state
|
|
38
|
+
const cdpUrl = state.cdpUrl;
|
|
39
|
+
|
|
40
|
+
const toolCall = {
|
|
41
|
+
id: toolCallId,
|
|
42
|
+
name: 'rpa-task',
|
|
43
|
+
args: {
|
|
44
|
+
steps: node.steps,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Create AI message with tool call
|
|
49
|
+
const aiMessage = new AIMessage({
|
|
50
|
+
id: aiMessageId,
|
|
51
|
+
content: '',
|
|
52
|
+
tool_calls: [toolCall],
|
|
53
|
+
additional_kwargs: {
|
|
54
|
+
mindedMetadata: {
|
|
55
|
+
nodeType: NodeType.RPA,
|
|
56
|
+
nodeDisplayName: node.displayName,
|
|
57
|
+
sessionId: state.sessionId,
|
|
58
|
+
cdpUrl: cdpUrl || undefined,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
state.messages.push(aiMessage);
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
if (!cdpUrl) {
|
|
67
|
+
throw new Error('CDP URL not found in state. Make sure a browser session is available.');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
logger.debug({
|
|
71
|
+
msg: '[RPA] Connecting to browser via CDP',
|
|
72
|
+
cdpUrl,
|
|
73
|
+
sessionId: state.sessionId,
|
|
74
|
+
node: node.displayName,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Connect to existing browser via CDP
|
|
78
|
+
browser = await chromium.connectOverCDP(cdpUrl);
|
|
79
|
+
const contexts = browser.contexts();
|
|
80
|
+
if (contexts.length === 0) {
|
|
81
|
+
throw new Error('No browser contexts found');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Get the first page or create a new one
|
|
85
|
+
const pages = contexts[0].pages();
|
|
86
|
+
page = pages.length > 0 ? pages[0] : await contexts[0].newPage();
|
|
87
|
+
|
|
88
|
+
// Execute each step
|
|
89
|
+
const results = []; // Collect all extracted data
|
|
90
|
+
|
|
91
|
+
for (const [index, step] of node.steps.entries()) {
|
|
92
|
+
logger.debug({
|
|
93
|
+
msg: '[RPA] Executing step',
|
|
94
|
+
stepIndex: index + 1,
|
|
95
|
+
stepType: step.type,
|
|
96
|
+
sessionId: state.sessionId,
|
|
97
|
+
node: node.displayName,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const result = await executeRpaStep(page, step, state, llm);
|
|
102
|
+
|
|
103
|
+
// Collect extracted data
|
|
104
|
+
if (step.type === RpaActionType.EXTRACT_DATA && result.data) {
|
|
105
|
+
results.push({
|
|
106
|
+
stepIndex: index + 1,
|
|
107
|
+
url: result.url,
|
|
108
|
+
data: result.data,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
} catch (stepError) {
|
|
112
|
+
logger.error({
|
|
113
|
+
msg: '[RPA] Step execution failed',
|
|
114
|
+
stepIndex: index + 1,
|
|
115
|
+
stepType: step.type,
|
|
116
|
+
error: stepError instanceof Error ? stepError.message : 'Unknown error',
|
|
117
|
+
sessionId: state.sessionId,
|
|
118
|
+
node: node.displayName,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Stop execution on error unless configured otherwise
|
|
122
|
+
throw stepError;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Create tool message with results
|
|
127
|
+
const toolMessage = new ToolMessage({
|
|
128
|
+
id: toolCallId,
|
|
129
|
+
content: JSON.stringify({
|
|
130
|
+
result: results,
|
|
131
|
+
}),
|
|
132
|
+
name: 'rpa-task',
|
|
133
|
+
tool_call_id: toolCallId,
|
|
134
|
+
status: 'success',
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Update messages - remove old AI message and add updated one with tool message
|
|
138
|
+
state.messages.push(toolMessage);
|
|
139
|
+
|
|
140
|
+
// Update history with RPA execution results
|
|
141
|
+
state.history.push(
|
|
142
|
+
createHistoryStep<HistoryStep>(state.history, {
|
|
143
|
+
type: NodeType.RPA,
|
|
144
|
+
nodeId: node.name,
|
|
145
|
+
nodeDisplayName: node.displayName,
|
|
146
|
+
raw: {
|
|
147
|
+
steps: node.steps,
|
|
148
|
+
results,
|
|
149
|
+
},
|
|
150
|
+
messageIds: [aiMessageId, toolMessage.id!],
|
|
151
|
+
}),
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
return state;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
logger.error({
|
|
157
|
+
msg: '[RPA] Error executing RPA node',
|
|
158
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
159
|
+
sessionId: state.sessionId,
|
|
160
|
+
node: node.displayName,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Create error tool message
|
|
164
|
+
const errorToolMessage = new ToolMessage({
|
|
165
|
+
id: uuidv4(),
|
|
166
|
+
content: JSON.stringify({
|
|
167
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
168
|
+
}),
|
|
169
|
+
name: 'rpa-task',
|
|
170
|
+
tool_call_id: toolCallId,
|
|
171
|
+
status: 'error',
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Update messages - remove old AI message and add updated one with error tool message
|
|
175
|
+
state.messages.push(errorToolMessage);
|
|
176
|
+
|
|
177
|
+
// Update history with error
|
|
178
|
+
state.history.push(
|
|
179
|
+
createHistoryStep<HistoryStep>(state.history, {
|
|
180
|
+
type: NodeType.RPA,
|
|
181
|
+
nodeId: node.name,
|
|
182
|
+
nodeDisplayName: node.displayName,
|
|
183
|
+
raw: {
|
|
184
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
185
|
+
steps: node.steps,
|
|
186
|
+
},
|
|
187
|
+
messageIds: [aiMessageId, errorToolMessage.id!],
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
return state;
|
|
192
|
+
} finally {
|
|
193
|
+
// Note: We don't close the browser as it's connected via CDP
|
|
194
|
+
// The browser session should remain active for other operations
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
graph.addNode(node.name, callback);
|
|
199
|
+
};
|
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, { memory: state.memory });
|
|
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;
|