@minded-ai/mindedjs 1.0.103-beta-1 → 1.0.103-beta-2
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 +29 -16
- 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.js +1 -1
- package/dist/interrupts/BaseInterruptSessionManager.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 +8 -18
- package/dist/nodes/addPromptNode.js.map +1 -1
- package/dist/nodes/addToolNode.js +2 -4
- 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/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.js +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/voice/voiceSession.d.ts.map +1 -1
- package/dist/voice/voiceSession.js +16 -17
- 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 +30 -18
- 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 +1 -1
- 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 -19
- package/src/nodes/addToolNode.ts +4 -4
- 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/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 -1
- package/src/voice/voiceSession.ts +16 -17
- package/src/platform/mindedChatOpenAI.ts +0 -19
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
|
|
|
@@ -67,7 +67,7 @@ export abstract class BaseInterruptSessionManager implements InterruptSessionMan
|
|
|
67
67
|
// Common implementation of checkQueueAndInterrupt
|
|
68
68
|
async checkQueueAndInterrupt(sessionId: string, updateStateObject?: Partial<State>): Promise<boolean> {
|
|
69
69
|
if (await this.hasQueuedMessages(sessionId)) {
|
|
70
|
-
logger.trace({
|
|
70
|
+
logger.trace({ msg: 'graph has queued messagess, interrupting graph', sessionId });
|
|
71
71
|
|
|
72
72
|
// Interrupt the graph with NEW_TRIGGERS flag and optional updateStateObject
|
|
73
73
|
const interruptPayload: InterruptPayload = { type: InterruptType.NEW_TRIGGERS };
|
|
@@ -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
|
};
|
|
@@ -26,14 +26,14 @@ export const addAppToolNode = async ({
|
|
|
26
26
|
const cleanedParameters = Object.fromEntries(Object.entries(node.parameters || {}).filter(([, value]) => value !== ''));
|
|
27
27
|
const appRunnerTool = getAppActionRunnerTool(node.displayName!);
|
|
28
28
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
29
|
-
logger.
|
|
29
|
+
logger.debug({ msg: `[Node] Executing tool node`, node: appRunnerTool.name });
|
|
30
30
|
|
|
31
31
|
const executeWrapper = async (input: z.infer<typeof appRunnerTool.input>) => {
|
|
32
32
|
try {
|
|
33
33
|
const response = await appRunnerTool.execute({ input, state, agent });
|
|
34
34
|
return response || {};
|
|
35
35
|
} catch (error) {
|
|
36
|
-
logger.error({ msg:
|
|
36
|
+
logger.error({ msg: `[Node] Error executing tool`, error, node: node.name });
|
|
37
37
|
throw error;
|
|
38
38
|
}
|
|
39
39
|
};
|
|
@@ -75,11 +75,12 @@ export const addAppToolNode = async ({
|
|
|
75
75
|
};
|
|
76
76
|
const toolCallMessage = await tool.invoke(AIToolCallMessage.tool_calls[0]);
|
|
77
77
|
AIToolCallMessage.additional_kwargs = {
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
mindedMetadata: {
|
|
79
|
+
nodeType: NodeType.APP_TOOL,
|
|
80
80
|
},
|
|
81
81
|
};
|
|
82
82
|
return {
|
|
83
|
+
goto: null,
|
|
83
84
|
messages: [AIToolCallMessage, toolCallMessage],
|
|
84
85
|
history: createHistoryStep<AppActionInvocationHistoryStep>(state.history, {
|
|
85
86
|
type: NodeType.APP_TOOL,
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { RunnableLike } from '@langchain/core/runnables';
|
|
2
|
+
import { BrowserTaskNode, NodeType } from '../types/Flows.types';
|
|
3
|
+
import { PreCompiledGraph, stateAnnotation } from '../types/LangGraph.types';
|
|
4
|
+
import { HistoryStep } from '../types/Agent.types';
|
|
5
|
+
import { logger } from '../utils/logger';
|
|
6
|
+
import { createHistoryStep } from '../utils/history';
|
|
7
|
+
import { AIMessage, SystemMessage } from '@langchain/core/messages';
|
|
8
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
9
|
+
import { Agent } from '../agent';
|
|
10
|
+
import { createCloudTask, waitForLiveUrl } from '../browserTask/executeBrowserTask';
|
|
11
|
+
import { tool as langchainTool } from '@langchain/core/tools';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { LLMProviders } from '../types/LLM.types';
|
|
14
|
+
import { compilePlaybooks } from '../playbooks/playbooks';
|
|
15
|
+
import * as ejs from 'ejs';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Compile prompt with parameters using EJS and placeholder replacement
|
|
19
|
+
*/
|
|
20
|
+
function compilePrompt(prompt: string, params: Record<string, any> = {}): string {
|
|
21
|
+
try {
|
|
22
|
+
// First, render with EJS
|
|
23
|
+
let compiledPrompt = ejs.render(prompt, params);
|
|
24
|
+
|
|
25
|
+
// Then, replace placeholders in {} format
|
|
26
|
+
compiledPrompt = replacePlaceholders(compiledPrompt, params);
|
|
27
|
+
|
|
28
|
+
return compiledPrompt;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
logger.error({ message: 'Error compiling prompt', error });
|
|
31
|
+
return prompt; // Return uncompiled if there's an error
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Replace placeholders in {key} format
|
|
37
|
+
*/
|
|
38
|
+
function replacePlaceholders(text: string, params: Record<string, any>): string {
|
|
39
|
+
return text.replace(/\{([^}]+)\}/g, (match, key) => {
|
|
40
|
+
const keys = key.split('.');
|
|
41
|
+
let value: any = params;
|
|
42
|
+
|
|
43
|
+
for (const k of keys) {
|
|
44
|
+
if (value && typeof value === 'object' && k in value) {
|
|
45
|
+
value = value[k];
|
|
46
|
+
} else {
|
|
47
|
+
return match; // Return original if key not found
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return String(value);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type AddBrowserTaskNodeParams = {
|
|
56
|
+
graph: PreCompiledGraph;
|
|
57
|
+
node: BrowserTaskNode;
|
|
58
|
+
agent: Agent;
|
|
59
|
+
llm: (typeof LLMProviders)[keyof typeof LLMProviders];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const addBrowserTaskNode = async ({ graph, node, agent, llm }: AddBrowserTaskNodeParams) => {
|
|
63
|
+
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
64
|
+
logger.info({ msg: `Executing browser task node ${node.displayName}`, prompt: node.prompt });
|
|
65
|
+
|
|
66
|
+
// Create Zod schema from inputSchema
|
|
67
|
+
const schemaFields: Record<string, z.ZodTypeAny> = {};
|
|
68
|
+
if (node.inputSchema) {
|
|
69
|
+
for (const field of node.inputSchema) {
|
|
70
|
+
let fieldSchema: z.ZodTypeAny;
|
|
71
|
+
|
|
72
|
+
if (field.type === 'string') {
|
|
73
|
+
fieldSchema = z.string();
|
|
74
|
+
} else if (field.type === 'number') {
|
|
75
|
+
fieldSchema = z.number();
|
|
76
|
+
} else {
|
|
77
|
+
fieldSchema = z.string(); // Default to string
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (field.description) {
|
|
81
|
+
fieldSchema = fieldSchema.describe(field.description);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (field.required === false) {
|
|
85
|
+
fieldSchema = fieldSchema.optional();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
schemaFields[field.name] = fieldSchema;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const zodSchema = z.object(schemaFields);
|
|
93
|
+
|
|
94
|
+
// Create langchain tool
|
|
95
|
+
const tool = langchainTool(() => {}, {
|
|
96
|
+
name: 'browser-task',
|
|
97
|
+
description: node.prompt,
|
|
98
|
+
schema: zodSchema,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Get compiled playbooks
|
|
102
|
+
const playbookParams = {
|
|
103
|
+
...state.memory,
|
|
104
|
+
state,
|
|
105
|
+
currentTime: new Date().toISOString(),
|
|
106
|
+
};
|
|
107
|
+
const compiledPlaybooks = compilePlaybooks(agent.playbooks, playbookParams) || '';
|
|
108
|
+
|
|
109
|
+
const systemPrompt = `${compiledPlaybooks ? compiledPlaybooks + '\n\n' : ''}
|
|
110
|
+
Additional context:
|
|
111
|
+
- workflow memory: ${JSON.stringify(state.memory)}`;
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
// Use LLM to generate tool call
|
|
115
|
+
const AIToolCallMessage: AIMessage = await llm
|
|
116
|
+
.bindTools([tool], {
|
|
117
|
+
tool_choice: tool.name,
|
|
118
|
+
})
|
|
119
|
+
.invoke([...state.messages, new SystemMessage(systemPrompt)]);
|
|
120
|
+
|
|
121
|
+
if (!AIToolCallMessage.tool_calls || AIToolCallMessage.tool_calls.length === 0) {
|
|
122
|
+
throw new Error('No tool calls generated by LLM');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const toolCall = AIToolCallMessage.tool_calls[0];
|
|
126
|
+
const inputParams = toolCall.args || {};
|
|
127
|
+
|
|
128
|
+
// Prepare parameters for prompt compilation
|
|
129
|
+
const promptParams = {
|
|
130
|
+
input: inputParams,
|
|
131
|
+
state,
|
|
132
|
+
currentTime: new Date().toISOString(),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Compile the prompt with parameters
|
|
136
|
+
const compiledPrompt = compilePrompt(node.prompt, promptParams);
|
|
137
|
+
|
|
138
|
+
// Build the full prompt with compiled content
|
|
139
|
+
const fullPrompt = `
|
|
140
|
+
Follow the instructions. Any retrieved data should be printed as string and not saved to a file.
|
|
141
|
+
|
|
142
|
+
# Task instructions:
|
|
143
|
+
${compiledPrompt}
|
|
144
|
+
|
|
145
|
+
${Object.keys(inputParams).length > 0 ? `# Input parameters:\n${JSON.stringify(inputParams, null, 2)}\n\n` : ''}
|
|
146
|
+
${state.memory ? `# Task context:\n${JSON.stringify(state.memory)}\n\n` : ''}
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
// Create the browser task in the cloud
|
|
150
|
+
const taskId = await createCloudTask(fullPrompt, node.model);
|
|
151
|
+
logger.debug({ msg: 'Browser task created', taskId });
|
|
152
|
+
|
|
153
|
+
// Wait for live_url to become available
|
|
154
|
+
const taskDetails = await waitForLiveUrl(taskId);
|
|
155
|
+
logger.debug({ msg: 'Live URL available', taskId, liveUrl: taskDetails.live_url });
|
|
156
|
+
|
|
157
|
+
// Update the tool call with taskId and other metadata
|
|
158
|
+
const updatedToolCall = {
|
|
159
|
+
...toolCall,
|
|
160
|
+
args: {
|
|
161
|
+
...inputParams,
|
|
162
|
+
taskId,
|
|
163
|
+
prompt: fullPrompt,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const toolCallingMessage = new AIMessage({
|
|
168
|
+
id: AIToolCallMessage.id,
|
|
169
|
+
content: AIToolCallMessage.content,
|
|
170
|
+
tool_calls: [updatedToolCall],
|
|
171
|
+
additional_kwargs: {
|
|
172
|
+
mindedMetadata: {
|
|
173
|
+
nodeType: NodeType.BROWSER_TASK,
|
|
174
|
+
nodeDisplayName: node.displayName,
|
|
175
|
+
taskId,
|
|
176
|
+
liveUrl: taskDetails.live_url,
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
history: createHistoryStep<HistoryStep>(state.history, {
|
|
183
|
+
type: NodeType.BROWSER_TASK,
|
|
184
|
+
nodeId: node.name,
|
|
185
|
+
nodeDisplayName: node.displayName,
|
|
186
|
+
raw: { taskId, liveUrl: taskDetails.live_url, inputParams },
|
|
187
|
+
messageIds: [toolCallingMessage.id!],
|
|
188
|
+
}),
|
|
189
|
+
messages: [toolCallingMessage],
|
|
190
|
+
};
|
|
191
|
+
} catch (error: any) {
|
|
192
|
+
logger.error(`Error creating browser task node ${node.displayName}: ${error}`);
|
|
193
|
+
|
|
194
|
+
const errorMessageId = uuidv4();
|
|
195
|
+
const errorToolCallId = uuidv4();
|
|
196
|
+
|
|
197
|
+
const toolCallingMessage = new AIMessage({
|
|
198
|
+
id: errorMessageId,
|
|
199
|
+
content: '',
|
|
200
|
+
tool_calls: [
|
|
201
|
+
{
|
|
202
|
+
id: errorToolCallId,
|
|
203
|
+
name: 'browser-task',
|
|
204
|
+
args: {
|
|
205
|
+
error: error.message,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
additional_kwargs: {
|
|
210
|
+
mindedMetadata: {
|
|
211
|
+
nodeType: NodeType.BROWSER_TASK,
|
|
212
|
+
nodeDisplayName: node.displayName,
|
|
213
|
+
error: error.message,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
history: createHistoryStep<HistoryStep>(state.history, {
|
|
220
|
+
type: NodeType.BROWSER_TASK,
|
|
221
|
+
nodeId: node.name,
|
|
222
|
+
nodeDisplayName: node.displayName,
|
|
223
|
+
raw: error,
|
|
224
|
+
messageIds: [errorMessageId],
|
|
225
|
+
}),
|
|
226
|
+
messages: [toolCallingMessage],
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
graph.addNode(node.name, callback);
|
|
231
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { PreCompiledGraph, stateAnnotation } from '../types/LangGraph.types';
|
|
2
|
+
import { RunnableLike } from '@langchain/core/runnables';
|
|
3
|
+
import { internalNodesSuffix, NodeType, BrowserTaskNode } from '../types/Flows.types';
|
|
4
|
+
import { ToolMessage, AIMessage } from '@langchain/core/messages';
|
|
5
|
+
import { Agent } from '../agent';
|
|
6
|
+
import { logger } from '../utils/logger';
|
|
7
|
+
import { createHistoryStep } from '../utils/history';
|
|
8
|
+
import { HistoryStep } from '../types/Agent.types';
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
+
import { waitForCompletion } from '../browserTask/executeBrowserTask';
|
|
11
|
+
|
|
12
|
+
type AddBrowserTaskRunNodeParams = {
|
|
13
|
+
graph: PreCompiledGraph;
|
|
14
|
+
browserTaskNode: BrowserTaskNode;
|
|
15
|
+
attachedToNodeName: string;
|
|
16
|
+
agent: Agent;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const buildBrowserTaskRunNodeName = (nodeName: string) => `${nodeName}${internalNodesSuffix.BROWSER_TASK_RUN}`;
|
|
20
|
+
|
|
21
|
+
export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedToNodeName }: AddBrowserTaskRunNodeParams) => {
|
|
22
|
+
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
23
|
+
logger.info(`Executing browser task run node for ${browserTaskNode.displayName}`);
|
|
24
|
+
|
|
25
|
+
const toolCallObj = state.messages[state.messages.length - 1] as any;
|
|
26
|
+
if (!toolCallObj.tool_calls) {
|
|
27
|
+
throw new Error('Tool call not found');
|
|
28
|
+
}
|
|
29
|
+
const toolCall = toolCallObj.tool_calls[0];
|
|
30
|
+
const { taskId, ...inputParams } = toolCall.args;
|
|
31
|
+
try {
|
|
32
|
+
if (!taskId) {
|
|
33
|
+
throw new Error('Task ID not found in tool call arguments');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Wait for task completion
|
|
37
|
+
const completedTask = await waitForCompletion(taskId);
|
|
38
|
+
logger.debug({ msg: 'Browser task completed', taskId, output: completedTask.output });
|
|
39
|
+
|
|
40
|
+
// Create tool message with the result
|
|
41
|
+
const toolMessage = new ToolMessage({
|
|
42
|
+
id: uuidv4(),
|
|
43
|
+
content: JSON.stringify({
|
|
44
|
+
result: completedTask.output || 'Task completed successfully',
|
|
45
|
+
steps: completedTask.steps || [],
|
|
46
|
+
inputParams: inputParams,
|
|
47
|
+
}),
|
|
48
|
+
name: 'browser-task',
|
|
49
|
+
tool_call_id: toolCall.id,
|
|
50
|
+
status: 'success',
|
|
51
|
+
additional_kwargs: {
|
|
52
|
+
mindedMetadata: {
|
|
53
|
+
nodeType: NodeType.BROWSER_TASK,
|
|
54
|
+
nodeDisplayName: browserTaskNode.displayName,
|
|
55
|
+
taskId,
|
|
56
|
+
steps: completedTask.steps,
|
|
57
|
+
inputParams: inputParams,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Update the AI message with steps using the message reducer pattern
|
|
63
|
+
const updatedAIMessage = new AIMessage({
|
|
64
|
+
id: toolCallObj.id,
|
|
65
|
+
content: toolCallObj.content,
|
|
66
|
+
tool_calls: toolCallObj.tool_calls,
|
|
67
|
+
additional_kwargs: {
|
|
68
|
+
...toolCallObj.additional_kwargs,
|
|
69
|
+
mindedMetadata: {
|
|
70
|
+
...toolCallObj.additional_kwargs?.mindedMetadata,
|
|
71
|
+
nodeDisplayName: browserTaskNode.displayName,
|
|
72
|
+
steps: completedTask.steps,
|
|
73
|
+
status: 'completed',
|
|
74
|
+
},
|
|
75
|
+
update: true, // This triggers the message reducer to update the existing message
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
messages: [toolMessage, updatedAIMessage],
|
|
81
|
+
history: createHistoryStep<HistoryStep>(state.history, {
|
|
82
|
+
type: NodeType.BROWSER_TASK,
|
|
83
|
+
nodeId: browserTaskNode.name,
|
|
84
|
+
nodeDisplayName: browserTaskNode.displayName,
|
|
85
|
+
raw: completedTask,
|
|
86
|
+
messageIds: [],
|
|
87
|
+
}),
|
|
88
|
+
};
|
|
89
|
+
} catch (error: any) {
|
|
90
|
+
logger.error({ msg: 'Error executing browser task run node', error });
|
|
91
|
+
|
|
92
|
+
const errorToolMessage = new ToolMessage({
|
|
93
|
+
id: uuidv4(),
|
|
94
|
+
content: JSON.stringify({
|
|
95
|
+
error: error instanceof Error ? error.message : error.toString(),
|
|
96
|
+
inputParams: inputParams,
|
|
97
|
+
}),
|
|
98
|
+
status: 'error',
|
|
99
|
+
name: 'browser-task',
|
|
100
|
+
tool_call_id: toolCall.id,
|
|
101
|
+
additional_kwargs: {
|
|
102
|
+
mindedMetadata: {
|
|
103
|
+
nodeType: NodeType.BROWSER_TASK,
|
|
104
|
+
nodeDisplayName: browserTaskNode.displayName,
|
|
105
|
+
taskId,
|
|
106
|
+
error: error.message,
|
|
107
|
+
inputParams: inputParams,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Update the AI message with error status
|
|
113
|
+
const updatedAIMessage = new AIMessage({
|
|
114
|
+
id: toolCallObj.id,
|
|
115
|
+
content: toolCallObj.content,
|
|
116
|
+
tool_calls: toolCallObj.tool_calls,
|
|
117
|
+
additional_kwargs: {
|
|
118
|
+
...toolCallObj.additional_kwargs,
|
|
119
|
+
mindedMetadata: {
|
|
120
|
+
...toolCallObj.additional_kwargs?.mindedMetadata,
|
|
121
|
+
nodeDisplayName: browserTaskNode.displayName,
|
|
122
|
+
status: 'failed',
|
|
123
|
+
error: error.message,
|
|
124
|
+
},
|
|
125
|
+
update: true,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
messages: [errorToolMessage, updatedAIMessage],
|
|
131
|
+
history: createHistoryStep<HistoryStep>(state.history, {
|
|
132
|
+
type: NodeType.BROWSER_TASK,
|
|
133
|
+
nodeId: browserTaskNode.name,
|
|
134
|
+
nodeDisplayName: browserTaskNode.displayName,
|
|
135
|
+
raw: error,
|
|
136
|
+
messageIds: [],
|
|
137
|
+
}),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
graph.addNode(buildBrowserTaskRunNodeName(attachedToNodeName), callback);
|
|
143
|
+
graph.addEdge(attachedToNodeName as any, buildBrowserTaskRunNodeName(attachedToNodeName) as any);
|
|
144
|
+
};
|
|
@@ -14,7 +14,8 @@ export const buildHumanInTheLoopNodeName = (nodeName: string) => `${nodeName}${i
|
|
|
14
14
|
|
|
15
15
|
export const addHumanInTheLoopNode = async ({ graph, attachedToNodeName }: AddHumanInTheLoopNodeParams) => {
|
|
16
16
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
17
|
-
logger.
|
|
17
|
+
logger.debug({ msg: `[Node] Waiting for human input`, node: attachedToNodeName });
|
|
18
|
+
|
|
18
19
|
if (state.messages[state.messages.length - 1].getType() === 'ai') {
|
|
19
20
|
const value = interrupt({ type: InterruptType.HUMAN_IN_THE_LOOP });
|
|
20
21
|
return value;
|
|
@@ -7,9 +7,10 @@ import { createHistoryStep } from '../utils/history';
|
|
|
7
7
|
|
|
8
8
|
export const addJumpToNode = async ({ graph, node }: { graph: PreCompiledGraph; node: JumpToNode }) => {
|
|
9
9
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
10
|
-
logger.info({
|
|
10
|
+
logger.info({ msg: `Executing jump node ${node.displayName} – jumping to ${node.targetNodeId}` });
|
|
11
11
|
// No state modifications are necessary; control flow is handled via edges.
|
|
12
12
|
return {
|
|
13
|
+
goto: null,
|
|
13
14
|
history: createHistoryStep<HistoryStep>(state.history, {
|
|
14
15
|
type: NodeType.JUMP_TO_NODE,
|
|
15
16
|
nodeId: node.name,
|
|
@@ -7,6 +7,7 @@ import { HistoryStep } from '../types/Agent.types';
|
|
|
7
7
|
export const addJunctionNode = ({ graph, node }: { graph: PreCompiledGraph; node: JunctionNode }) => {
|
|
8
8
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
9
9
|
return {
|
|
10
|
+
goto: null,
|
|
10
11
|
history: createHistoryStep<HistoryStep>(state.history, {
|
|
11
12
|
type: NodeType.JUNCTION,
|
|
12
13
|
nodeId: node.name,
|
|
@@ -14,10 +14,7 @@ import { Agent } from '../agent';
|
|
|
14
14
|
import { logger } from '../utils/logger';
|
|
15
15
|
import { compilePlaybooks } from '../playbooks/playbooks';
|
|
16
16
|
import { createHistoryStep } from '../utils/history';
|
|
17
|
-
import { wait } from '../utils/wait';
|
|
18
|
-
import { sendPlaceholderMessage } from '../internalTools/sendPlaceholderMessage';
|
|
19
17
|
import { v4 as uuidv4 } from 'uuid';
|
|
20
|
-
|
|
21
18
|
type AddPromptNodeParams = {
|
|
22
19
|
graph: PreCompiledGraph;
|
|
23
20
|
node: PromptNode;
|
|
@@ -26,12 +23,11 @@ type AddPromptNodeParams = {
|
|
|
26
23
|
emit: EmitSignature<any, keyof AgentEventRequestPayloads<any>>;
|
|
27
24
|
agent: Agent;
|
|
28
25
|
};
|
|
29
|
-
let shouldWait = true;
|
|
30
26
|
|
|
31
27
|
export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: AddPromptNodeParams) => {
|
|
32
28
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
33
29
|
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
34
|
-
logger.info({
|
|
30
|
+
logger.info({ msg: `[Node] Executing prompt node`, node: node.displayName });
|
|
35
31
|
const llmToUse = node.llmConfig ? createLlmInstance(node.llmConfig) : llm;
|
|
36
32
|
|
|
37
33
|
const globalTools = tools
|
|
@@ -55,16 +51,7 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
55
51
|
${state.memory ? `# Task context:\n${JSON.stringify(state.memory)}\n\n` : ''}
|
|
56
52
|
${compiledPlaybooks ? `# General guidelines:\n${compiledPlaybooks}\n\n` : ''}
|
|
57
53
|
`;
|
|
58
|
-
|
|
59
|
-
logger.info({ msg: `waiting 15 seconds` });
|
|
60
|
-
shouldWait = false;
|
|
61
|
-
|
|
62
|
-
await sendPlaceholderMessage({ sessionId: state.sessionId, message: 'just a moment please... ' });
|
|
63
|
-
await wait(10000);
|
|
64
|
-
logger.info({ msg: `done waiting 15 seconds` });
|
|
65
|
-
} else {
|
|
66
|
-
logger.info({ msg: `not waiting` });
|
|
67
|
-
}
|
|
54
|
+
// await wait(5000);
|
|
68
55
|
const result: AIMessage = await llmToUse.bindTools(globalTools).invoke([...state.messages, new SystemMessage(message)]);
|
|
69
56
|
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
70
57
|
// Check if the result contains tool calls
|
|
@@ -75,11 +62,12 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
75
62
|
|
|
76
63
|
for (const toolCall of result.tool_calls) {
|
|
77
64
|
const matchedTool = globalTools.find((t) => t.name === toolCall.name);
|
|
78
|
-
logger.info({ msg: `Model
|
|
65
|
+
logger.info({ msg: `[Model] Calling tool`, tool: matchedTool?.name });
|
|
79
66
|
if (matchedTool) {
|
|
80
67
|
try {
|
|
81
68
|
// Invoke the LangChain tool directly
|
|
82
69
|
const toolResult = await matchedTool.invoke(toolCall);
|
|
70
|
+
logger.debug({ msg: `[Tool] Tool result`, tool: matchedTool?.name, result: toolResult });
|
|
83
71
|
//check for queue after tool call
|
|
84
72
|
const systemMessageId = uuidv4();
|
|
85
73
|
|
|
@@ -113,7 +101,7 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
113
101
|
toolResults.push(toolResult);
|
|
114
102
|
} catch (error: any) {
|
|
115
103
|
if (error?.name === 'GraphInterrupt') throw error;
|
|
116
|
-
logger.error({ msg: `Error executing tool
|
|
104
|
+
logger.error({ msg: `[Tool] Error executing tool`, tool: toolCall.name, error });
|
|
117
105
|
const errorMessage = new ToolMessage({
|
|
118
106
|
content: JSON.stringify({ error: error instanceof Error ? error.message : String(error) }),
|
|
119
107
|
tool_call_id: toolCall.id!,
|
|
@@ -121,7 +109,7 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
121
109
|
toolResults.push(errorMessage);
|
|
122
110
|
}
|
|
123
111
|
} else {
|
|
124
|
-
logger.error({ msg: `Model
|
|
112
|
+
logger.error({ msg: `[Tool] Model called tool but it was not found`, tool: toolCall.name });
|
|
125
113
|
}
|
|
126
114
|
}
|
|
127
115
|
|
|
@@ -157,9 +145,10 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
157
145
|
message: result.content as string,
|
|
158
146
|
state,
|
|
159
147
|
});
|
|
160
|
-
|
|
148
|
+
logger.info({ msg: `[Model] Response`, content: result.content });
|
|
161
149
|
}
|
|
162
150
|
return {
|
|
151
|
+
goto: null,
|
|
163
152
|
history: createHistoryStep<HistoryStep>(state.history, {
|
|
164
153
|
type: NodeType.PROMPT_NODE,
|
|
165
154
|
nodeId: node.name,
|
package/src/nodes/addToolNode.ts
CHANGED
|
@@ -30,8 +30,8 @@ export const addToolNode = async ({
|
|
|
30
30
|
throw new Error(`Tool not found: ${toolNode.toolName} in node ${node.name}`);
|
|
31
31
|
}
|
|
32
32
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
logger.debug({ msg: `[Node] Executing tool node`, node: toolNode.displayName });
|
|
34
|
+
|
|
35
35
|
const tool = langchainTool(() => {}, {
|
|
36
36
|
name: matchedTool.name,
|
|
37
37
|
description: matchedTool.description,
|
|
@@ -56,9 +56,9 @@ export const addToolNode = async ({
|
|
|
56
56
|
tool_choice: tool.name,
|
|
57
57
|
})
|
|
58
58
|
.invoke([...state.messages, new SystemMessage(prompt)]);
|
|
59
|
-
|
|
60
|
-
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
59
|
+
|
|
61
60
|
return {
|
|
61
|
+
goto: null,
|
|
62
62
|
messages: [AIToolCallMessage],
|
|
63
63
|
history: createHistoryStep<HistoryStep>(state.history, {
|
|
64
64
|
type: NodeType.TOOL,
|
|
@@ -36,7 +36,7 @@ export const addToolRunNode = async ({ graph, tools, toolNode, attachedToNodeNam
|
|
|
36
36
|
const response = await matchedTool.execute({ input, state, agent });
|
|
37
37
|
return response || {};
|
|
38
38
|
} catch (error) {
|
|
39
|
-
logger.error({ msg: 'Error executing tool', error });
|
|
39
|
+
logger.error({ msg: '[Tool] Error executing tool', error, node: toolNode.displayName });
|
|
40
40
|
throw error;
|
|
41
41
|
}
|
|
42
42
|
};
|
|
@@ -56,7 +56,9 @@ export const addToolRunNode = async ({ graph, tools, toolNode, attachedToNodeNam
|
|
|
56
56
|
// Push the toolCallMessage into the messages array from toolStateUpdate
|
|
57
57
|
const updatedMessages = [toolCallMessage, ...((toolStateUpdate as any).messages || [])];
|
|
58
58
|
// Return the full state update from the tool with the updated messages
|
|
59
|
+
|
|
59
60
|
return {
|
|
61
|
+
goto: null,
|
|
60
62
|
...toolStateUpdate,
|
|
61
63
|
messages: updatedMessages,
|
|
62
64
|
history: createHistoryStep<HistoryStep>(state.history, {
|
|
@@ -7,9 +7,10 @@ import { createHistoryStep } from '../utils/history';
|
|
|
7
7
|
|
|
8
8
|
export const addTriggerNode = async ({ graph, node }: { graph: PreCompiledGraph; node: TriggerNode }) => {
|
|
9
9
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
10
|
-
logger.
|
|
10
|
+
logger.debug({ msg: `[Trigger] Executing trigger node`, node: node.displayName });
|
|
11
11
|
if (node.triggerType === TriggerType.MANUAL) {
|
|
12
12
|
return {
|
|
13
|
+
goto: null,
|
|
13
14
|
history: createHistoryStep<HistoryStep>(state.history, {
|
|
14
15
|
type: NodeType.TRIGGER,
|
|
15
16
|
nodeId: node.name,
|