@minded-ai/mindedjs 1.0.120 → 1.0.122-beta-1
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 +4 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +70 -10
- package/dist/agent.js.map +1 -1
- package/dist/browserTask/README.md +419 -0
- package/dist/browserTask/browserAgent.py +632 -0
- package/dist/browserTask/captcha_isolated.png +0 -0
- package/dist/browserTask/executeBrowserTask.ts +79 -0
- package/dist/browserTask/requirements.txt +8 -0
- package/dist/browserTask/setup.sh +144 -0
- package/dist/cli/index.js +14 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/edges/createLogicalRouter.js +1 -1
- package/dist/edges/createLogicalRouter.js.map +1 -1
- package/dist/edges/createPromptRouter.d.ts.map +1 -1
- package/dist/edges/createPromptRouter.js +0 -7
- package/dist/edges/createPromptRouter.js.map +1 -1
- package/dist/edges/edgeFactory.js +2 -2
- package/dist/edges/edgeFactory.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/internalTools/retell.js +17 -7
- package/dist/internalTools/retell.js.map +1 -1
- package/dist/internalTools/sendPlaceholderMessage.js +17 -7
- package/dist/internalTools/sendPlaceholderMessage.js.map +1 -1
- package/dist/internalTools/voice/escalateVoiceCall.d.ts +2 -0
- package/dist/internalTools/voice/escalateVoiceCall.d.ts.map +1 -0
- package/dist/internalTools/voice/escalateVoiceCall.js +42 -0
- package/dist/internalTools/voice/escalateVoiceCall.js.map +1 -0
- package/dist/internalTools/voice/retell.d.ts +12 -0
- package/dist/internalTools/voice/retell.d.ts.map +1 -0
- package/dist/internalTools/voice/retell.js +44 -0
- package/dist/internalTools/voice/retell.js.map +1 -0
- package/dist/internalTools/voice/sendPlaceholderMessage.d.ts +14 -0
- package/dist/internalTools/voice/sendPlaceholderMessage.d.ts.map +1 -0
- package/dist/internalTools/voice/sendPlaceholderMessage.js +51 -0
- package/dist/internalTools/voice/sendPlaceholderMessage.js.map +1 -0
- package/dist/interrupts/BaseInterruptSessionManager.d.ts +52 -0
- package/dist/interrupts/BaseInterruptSessionManager.d.ts.map +1 -0
- package/dist/interrupts/BaseInterruptSessionManager.js +40 -0
- package/dist/interrupts/BaseInterruptSessionManager.js.map +1 -0
- package/dist/interrupts/MemoryInterruptSessionManager.d.ts +14 -0
- package/dist/interrupts/MemoryInterruptSessionManager.d.ts.map +1 -0
- package/dist/interrupts/MemoryInterruptSessionManager.js +60 -0
- package/dist/interrupts/MemoryInterruptSessionManager.js.map +1 -0
- package/dist/interrupts/MindedInterruptSessionManager.d.ts +13 -0
- package/dist/interrupts/MindedInterruptSessionManager.d.ts.map +1 -0
- package/dist/interrupts/MindedInterruptSessionManager.js +151 -0
- package/dist/interrupts/MindedInterruptSessionManager.js.map +1 -0
- package/dist/interrupts/interruptSessionManagerFactory.d.ts +3 -0
- package/dist/interrupts/interruptSessionManagerFactory.d.ts.map +1 -0
- package/dist/interrupts/interruptSessionManagerFactory.js +46 -0
- package/dist/interrupts/interruptSessionManagerFactory.js.map +1 -0
- package/dist/nodes/addAppToolNode.d.ts.map +1 -1
- package/dist/nodes/addAppToolNode.js +7 -13
- package/dist/nodes/addAppToolNode.js.map +1 -1
- package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -1
- package/dist/nodes/addBrowserTaskNode.js +7 -74
- package/dist/nodes/addBrowserTaskNode.js.map +1 -1
- package/dist/nodes/addHumanInTheLoopNode.d.ts.map +1 -1
- package/dist/nodes/addHumanInTheLoopNode.js +2 -1
- package/dist/nodes/addHumanInTheLoopNode.js.map +1 -1
- package/dist/nodes/addJumpToNode.js +2 -2
- package/dist/nodes/addJumpToNode.js.map +1 -1
- package/dist/nodes/addPromptNode.d.ts.map +1 -1
- package/dist/nodes/addPromptNode.js +96 -13
- package/dist/nodes/addPromptNode.js.map +1 -1
- package/dist/nodes/addToolNode.d.ts.map +1 -1
- package/dist/nodes/addToolNode.js +12 -13
- package/dist/nodes/addToolNode.js.map +1 -1
- package/dist/nodes/addToolRunNode.d.ts.map +1 -1
- package/dist/nodes/addToolRunNode.js +4 -0
- package/dist/nodes/addToolRunNode.js.map +1 -1
- package/dist/nodes/compilePrompt.d.ts +5 -0
- package/dist/nodes/compilePrompt.d.ts.map +1 -0
- package/dist/nodes/compilePrompt.js +64 -0
- package/dist/nodes/compilePrompt.js.map +1 -0
- package/dist/platform/mindedConnection.js +12 -12
- package/dist/platform/mindedConnection.js.map +1 -1
- package/dist/platform/mindedConnectionTypes.d.ts +151 -1
- package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
- package/dist/platform/mindedConnectionTypes.js +9 -0
- package/dist/platform/mindedConnectionTypes.js.map +1 -1
- package/dist/playbooks/playbooks.d.ts +2 -2
- package/dist/playbooks/playbooks.d.ts.map +1 -1
- package/dist/playbooks/playbooks.js +37 -45
- package/dist/playbooks/playbooks.js.map +1 -1
- package/dist/types/Agent.types.d.ts +2 -0
- package/dist/types/Agent.types.d.ts.map +1 -1
- package/dist/types/Agent.types.js.map +1 -1
- package/dist/types/LangGraph.types.d.ts +2 -2
- package/dist/types/LangGraph.types.d.ts.map +1 -1
- package/dist/types/LangGraph.types.js +3 -1
- package/dist/types/LangGraph.types.js.map +1 -1
- package/dist/voice/voiceSession.d.ts +0 -1
- package/dist/voice/voiceSession.d.ts.map +1 -1
- package/dist/voice/voiceSession.js +9 -13
- package/dist/voice/voiceSession.js.map +1 -1
- package/docs/low-code-editor/nodes.md +21 -12
- package/docs/low-code-editor/playbooks.md +50 -32
- package/package.json +2 -2
- package/src/agent.ts +87 -13
- package/src/cli/index.ts +14 -14
- package/src/edges/createLogicalRouter.ts +1 -1
- package/src/edges/createPromptRouter.ts +5 -12
- package/src/edges/edgeFactory.ts +2 -2
- package/src/index.ts +4 -3
- package/src/internalTools/voice/escalateVoiceCall.ts +15 -0
- package/src/internalTools/{retell.ts → voice/retell.ts} +2 -2
- package/src/internalTools/{sendPlaceholderMessage.ts → voice/sendPlaceholderMessage.ts} +2 -2
- package/src/interrupts/BaseInterruptSessionManager.ts +96 -0
- package/src/interrupts/MemoryInterruptSessionManager.ts +63 -0
- package/src/interrupts/MindedInterruptSessionManager.ts +162 -0
- package/src/interrupts/interruptSessionManagerFactory.ts +20 -0
- package/src/nodes/addAppToolNode.ts +10 -13
- package/src/nodes/addBrowserTaskNode.ts +7 -56
- package/src/nodes/addHumanInTheLoopNode.ts +2 -1
- package/src/nodes/addJumpToNode.ts +2 -2
- package/src/nodes/addPromptNode.ts +104 -18
- package/src/nodes/addToolNode.ts +12 -14
- package/src/nodes/addToolRunNode.ts +4 -1
- package/src/nodes/compilePrompt.ts +41 -0
- package/src/platform/mindedConnection.ts +12 -12
- package/src/platform/mindedConnectionTypes.ts +187 -0
- package/src/playbooks/playbooks.ts +38 -48
- package/src/types/Agent.types.ts +2 -0
- package/src/types/LangGraph.types.ts +3 -1
- package/src/voice/voiceSession.ts +9 -14
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { BaseInterruptSessionManager, QueuedMessage, QUEUE_INTERRUPT_DETECTED_BEFORE_SPEECH } from './BaseInterruptSessionManager';
|
|
2
|
+
import * as mindedConnection from '../platform/mindedConnection';
|
|
3
|
+
import {
|
|
4
|
+
mindedConnectionSocketMessageType,
|
|
5
|
+
InterruptSessionIsProcessedRequest,
|
|
6
|
+
InterruptSessionIsProcessedResponse,
|
|
7
|
+
InterruptSessionLockRequest,
|
|
8
|
+
InterruptSessionLockResponse,
|
|
9
|
+
InterruptSessionReleaseRequest,
|
|
10
|
+
InterruptSessionReleaseResponse,
|
|
11
|
+
InterruptSessionEnqueueRequest,
|
|
12
|
+
InterruptSessionEnqueueResponse,
|
|
13
|
+
InterruptSessionDequeueAllRequest,
|
|
14
|
+
InterruptSessionDequeueAllResponse,
|
|
15
|
+
InterruptSessionDequeueRequest,
|
|
16
|
+
InterruptSessionDequeueResponse,
|
|
17
|
+
InterruptSessionHasMessagesRequest,
|
|
18
|
+
InterruptSessionHasMessagesResponse,
|
|
19
|
+
InterruptSessionGetMessagesRequest,
|
|
20
|
+
InterruptSessionGetMessagesResponse,
|
|
21
|
+
} from '../platform/mindedConnectionTypes';
|
|
22
|
+
|
|
23
|
+
export class MindedInterruptSessionManager extends BaseInterruptSessionManager {
|
|
24
|
+
constructor() {
|
|
25
|
+
super();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async isProcessed(sessionId: string): Promise<boolean> {
|
|
29
|
+
try {
|
|
30
|
+
const response = await mindedConnection.awaitEmit<InterruptSessionIsProcessedRequest, InterruptSessionIsProcessedResponse>(
|
|
31
|
+
mindedConnectionSocketMessageType.INTERRUPT_SESSION_IS_PROCESSED,
|
|
32
|
+
{
|
|
33
|
+
type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_IS_PROCESSED,
|
|
34
|
+
sessionId,
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
return response.isProcessed ?? false;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('Error checking if session is processed:', error);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async lock(sessionId: string): Promise<boolean> {
|
|
45
|
+
try {
|
|
46
|
+
const response = await mindedConnection.awaitEmit<InterruptSessionLockRequest, InterruptSessionLockResponse>(
|
|
47
|
+
mindedConnectionSocketMessageType.INTERRUPT_SESSION_LOCK,
|
|
48
|
+
{
|
|
49
|
+
type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_LOCK,
|
|
50
|
+
sessionId,
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
return response.lockAcquired ?? false;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('Error locking session:', error);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async release(sessionId: string): Promise<void> {
|
|
61
|
+
try {
|
|
62
|
+
await mindedConnection.awaitEmit<InterruptSessionReleaseRequest, InterruptSessionReleaseResponse>(
|
|
63
|
+
mindedConnectionSocketMessageType.INTERRUPT_SESSION_RELEASE,
|
|
64
|
+
{
|
|
65
|
+
type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_RELEASE,
|
|
66
|
+
sessionId,
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error('Error releasing session:', error);
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async enqueueMessage(sessionId: string, message: QueuedMessage): Promise<void> {
|
|
76
|
+
try {
|
|
77
|
+
await mindedConnection.awaitEmit<InterruptSessionEnqueueRequest, InterruptSessionEnqueueResponse>(
|
|
78
|
+
mindedConnectionSocketMessageType.INTERRUPT_SESSION_ENQUEUE,
|
|
79
|
+
{
|
|
80
|
+
type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_ENQUEUE,
|
|
81
|
+
sessionId,
|
|
82
|
+
message,
|
|
83
|
+
},
|
|
84
|
+
);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('Error enqueuing message:', error);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async dequeueAll(sessionId: string): Promise<QueuedMessage[]> {
|
|
92
|
+
try {
|
|
93
|
+
const response = await mindedConnection.awaitEmit<InterruptSessionDequeueAllRequest, InterruptSessionDequeueAllResponse>(
|
|
94
|
+
mindedConnectionSocketMessageType.INTERRUPT_SESSION_DEQUEUE_ALL,
|
|
95
|
+
{
|
|
96
|
+
type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_DEQUEUE_ALL,
|
|
97
|
+
sessionId,
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
return response.messages ?? [];
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('Error dequeuing all messages:', error);
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async dequeue(sessionId: string): Promise<QueuedMessage | null> {
|
|
108
|
+
try {
|
|
109
|
+
const response = await mindedConnection.awaitEmit<InterruptSessionDequeueRequest, InterruptSessionDequeueResponse>(
|
|
110
|
+
mindedConnectionSocketMessageType.INTERRUPT_SESSION_DEQUEUE,
|
|
111
|
+
{
|
|
112
|
+
type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_DEQUEUE,
|
|
113
|
+
sessionId,
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
const message = response.message ?? null;
|
|
117
|
+
|
|
118
|
+
// If the dequeued message has the special trigger name, recursively dequeue the next one
|
|
119
|
+
if (message && message.triggerName === QUEUE_INTERRUPT_DETECTED_BEFORE_SPEECH) {
|
|
120
|
+
return this.dequeue(sessionId);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return message;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Error dequeuing message:', error);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Implementation of abstract methods from BaseInterruptSessionManager
|
|
131
|
+
protected async hasQueuedMessages(sessionId: string): Promise<boolean> {
|
|
132
|
+
try {
|
|
133
|
+
const response = await mindedConnection.awaitEmit<InterruptSessionHasMessagesRequest, InterruptSessionHasMessagesResponse>(
|
|
134
|
+
mindedConnectionSocketMessageType.INTERRUPT_SESSION_HAS_MESSAGES,
|
|
135
|
+
{
|
|
136
|
+
type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_HAS_MESSAGES,
|
|
137
|
+
sessionId,
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
return response.hasMessages ?? false;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error('Error checking if session has messages:', error);
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
protected async getQueuedMessages(sessionId: string): Promise<QueuedMessage[]> {
|
|
148
|
+
try {
|
|
149
|
+
const response = await mindedConnection.awaitEmit<InterruptSessionGetMessagesRequest, InterruptSessionGetMessagesResponse>(
|
|
150
|
+
mindedConnectionSocketMessageType.INTERRUPT_SESSION_GET_MESSAGES,
|
|
151
|
+
{
|
|
152
|
+
type: mindedConnectionSocketMessageType.INTERRUPT_SESSION_GET_MESSAGES,
|
|
153
|
+
sessionId,
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
return response.messages ?? [];
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error('Error getting queued messages:', error);
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { InterruptSessionManager } from './BaseInterruptSessionManager';
|
|
2
|
+
import { MemoryInterruptSessionManager } from './MemoryInterruptSessionManager';
|
|
3
|
+
import { MindedInterruptSessionManager } from './MindedInterruptSessionManager';
|
|
4
|
+
import * as mindedConnection from '../platform/mindedConnection';
|
|
5
|
+
import { getConfig } from '../platform/config';
|
|
6
|
+
import { logger } from '../utils/logger';
|
|
7
|
+
|
|
8
|
+
export function createInterruptSessionManager(): InterruptSessionManager {
|
|
9
|
+
const { runLocally } = getConfig();
|
|
10
|
+
if (runLocally) {
|
|
11
|
+
logger.info({ msg: 'Using memory interrupt session manager' });
|
|
12
|
+
return new MemoryInterruptSessionManager();
|
|
13
|
+
} else {
|
|
14
|
+
if (!mindedConnection.isConnected()) {
|
|
15
|
+
throw new Error('MindedConnection is required for platform interrupt session manager');
|
|
16
|
+
}
|
|
17
|
+
logger.info({ msg: 'Using Minded interrupt session manager' });
|
|
18
|
+
return new MindedInterruptSessionManager();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -8,9 +8,10 @@ import { LLMProviders } from '../types/LLM.types';
|
|
|
8
8
|
import { AppActionInvocationHistoryStep } from '../types/Agent.types';
|
|
9
9
|
import { Agent } from '../agent';
|
|
10
10
|
import { logger } from '../utils/logger';
|
|
11
|
-
import { compilePlaybooks } from '../playbooks/playbooks';
|
|
12
11
|
import { createHistoryStep } from '../utils/history';
|
|
13
12
|
import { Tool } from '../types/Tools.types';
|
|
13
|
+
import { combinePlaybooks } from '../playbooks/playbooks';
|
|
14
|
+
import { compilePrompt } from './compilePrompt';
|
|
14
15
|
|
|
15
16
|
export const addAppToolNode = async ({
|
|
16
17
|
graph,
|
|
@@ -51,14 +52,10 @@ export const addAppToolNode = async ({
|
|
|
51
52
|
description: appRunnerTool.description,
|
|
52
53
|
schema: appRunnerTool.input,
|
|
53
54
|
});
|
|
54
|
-
// Get compiled playbooks with proper parameters
|
|
55
|
-
const playbookParams = {
|
|
56
|
-
...state.memory, // Spread memory fields at the top level
|
|
57
|
-
currentTime: new Date().toISOString(),
|
|
58
|
-
};
|
|
59
|
-
const compiledPlaybooks = compilePlaybooks(agent.playbooks, playbookParams) || '';
|
|
60
55
|
|
|
61
|
-
const
|
|
56
|
+
const combinedPlaybooks = combinePlaybooks(agent.playbooks) || '';
|
|
57
|
+
|
|
58
|
+
const message = `${combinedPlaybooks ? combinedPlaybooks + '\n\n' : ''}
|
|
62
59
|
Additional context:
|
|
63
60
|
previous messages are available for context.
|
|
64
61
|
Your goal is execute the tool with the correct parameters, some of them already chosen by the user and the rest should be generated.
|
|
@@ -70,15 +67,15 @@ export const addAppToolNode = async ({
|
|
|
70
67
|
Parameters manually configured by the user are:
|
|
71
68
|
${JSON.stringify(cleanedParameters)}
|
|
72
69
|
User instructions for choosing tool parameters are:
|
|
73
|
-
${node.prompt ? `${node.prompt}` : 'no instructions set by the user'}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
${node.prompt ? `${node.prompt}` : 'no instructions set by the user'}`;
|
|
71
|
+
|
|
72
|
+
const compiledPrompt = compilePrompt(message, { memory: state.memory, system: { currentTime: new Date().toISOString() } });
|
|
73
|
+
|
|
77
74
|
const AIToolCallMessage = await llm
|
|
78
75
|
.bindTools([tool], {
|
|
79
76
|
tool_choice: tool.name,
|
|
80
77
|
})
|
|
81
|
-
.invoke([...state.messages, new SystemMessage(
|
|
78
|
+
.invoke([...state.messages, new SystemMessage(compiledPrompt)]);
|
|
82
79
|
AIToolCallMessage.tool_calls[0].args = {
|
|
83
80
|
...AIToolCallMessage.tool_calls[0].args,
|
|
84
81
|
...cleanedParameters, //user set parameters have priority over ai generated parameters
|
|
@@ -11,46 +11,8 @@ import { createBrowserSession } from '../browserTask/executeBrowserTask';
|
|
|
11
11
|
import { tool as langchainTool } from '@langchain/core/tools';
|
|
12
12
|
import { z } from 'zod';
|
|
13
13
|
import { LLMProviders } from '../types/LLM.types';
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
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
|
-
}
|
|
14
|
+
import { compilePrompt } from './compilePrompt';
|
|
15
|
+
import { combinePlaybooks } from '../playbooks/playbooks';
|
|
54
16
|
|
|
55
17
|
type AddBrowserTaskNodeParams = {
|
|
56
18
|
graph: PreCompiledGraph;
|
|
@@ -98,17 +60,8 @@ export const addBrowserTaskNode = async ({ graph, node, agent, llm }: AddBrowser
|
|
|
98
60
|
schema: zodSchema,
|
|
99
61
|
});
|
|
100
62
|
|
|
101
|
-
|
|
102
|
-
const
|
|
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)}`;
|
|
63
|
+
const combinedPlaybooks = combinePlaybooks(agent.playbooks) || '';
|
|
64
|
+
const systemPrompt = combinedPlaybooks ? compilePrompt(combinedPlaybooks, { state, currentTime: new Date().toISOString() }) : '';
|
|
112
65
|
|
|
113
66
|
try {
|
|
114
67
|
// Use LLM to generate tool call
|
|
@@ -128,8 +81,8 @@ Additional context:
|
|
|
128
81
|
// Prepare parameters for prompt compilation
|
|
129
82
|
const promptParams = {
|
|
130
83
|
input: inputParams,
|
|
131
|
-
state,
|
|
132
|
-
currentTime: new Date().toISOString(),
|
|
84
|
+
memory: state.memory,
|
|
85
|
+
system: { currentTime: new Date().toISOString() },
|
|
133
86
|
};
|
|
134
87
|
|
|
135
88
|
// Compile the prompt with parameters
|
|
@@ -142,9 +95,7 @@ Follow the instructions. Any retrieved data should be printed as string and not
|
|
|
142
95
|
# Task instructions:
|
|
143
96
|
${compiledPrompt}
|
|
144
97
|
|
|
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
|
-
`;
|
|
98
|
+
${Object.keys(inputParams).length > 0 ? `# Input parameters:\n${JSON.stringify(inputParams, null, 2)}\n\n` : ''}`;
|
|
148
99
|
|
|
149
100
|
// Create browser session using socket
|
|
150
101
|
const session = await createBrowserSession(node.proxy);
|
|
@@ -3,6 +3,7 @@ import { PreCompiledGraph, stateAnnotation } from '../types/LangGraph.types';
|
|
|
3
3
|
import { RunnableLike } from '@langchain/core/runnables';
|
|
4
4
|
import { logger } from '../utils/logger';
|
|
5
5
|
import { internalNodesSuffix } from '../types/Flows.types';
|
|
6
|
+
import { InterruptType } from '../interrupts/BaseInterruptSessionManager';
|
|
6
7
|
|
|
7
8
|
type AddHumanInTheLoopNodeParams = {
|
|
8
9
|
graph: PreCompiledGraph;
|
|
@@ -16,7 +17,7 @@ export const addHumanInTheLoopNode = async ({ graph, attachedToNodeName }: AddHu
|
|
|
16
17
|
logger.debug({ msg: `[Node] Waiting for human input`, node: attachedToNodeName });
|
|
17
18
|
|
|
18
19
|
if (state.messages[state.messages.length - 1].getType() === 'ai') {
|
|
19
|
-
const value = interrupt(
|
|
20
|
+
const value = interrupt({ type: InterruptType.HUMAN_IN_THE_LOOP });
|
|
20
21
|
return value;
|
|
21
22
|
}
|
|
22
23
|
};
|
|
@@ -7,10 +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(`Executing jump node ${node.displayName} – jumping to ${node.targetNodeId}`);
|
|
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:
|
|
13
|
+
goto: node.targetNodeId,
|
|
14
14
|
history: createHistoryStep<HistoryStep>(state.history, {
|
|
15
15
|
type: NodeType.JUMP_TO_NODE,
|
|
16
16
|
nodeId: node.name,
|
|
@@ -12,9 +12,10 @@ import { createLlmInstance } from '../llm/createLlmInstance';
|
|
|
12
12
|
import extractToolStateResponse from '../utils/extractStateMemoryResponse';
|
|
13
13
|
import { Agent } from '../agent';
|
|
14
14
|
import { logger } from '../utils/logger';
|
|
15
|
-
import {
|
|
15
|
+
import { combinePlaybooks } from '../playbooks/playbooks';
|
|
16
16
|
import { createHistoryStep } from '../utils/history';
|
|
17
|
-
|
|
17
|
+
import { compilePrompt } from './compilePrompt';
|
|
18
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
18
19
|
type AddPromptNodeParams = {
|
|
19
20
|
graph: PreCompiledGraph;
|
|
20
21
|
node: PromptNode;
|
|
@@ -26,7 +27,8 @@ type AddPromptNodeParams = {
|
|
|
26
27
|
|
|
27
28
|
export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: AddPromptNodeParams) => {
|
|
28
29
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
29
|
-
|
|
30
|
+
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
31
|
+
logger.info({ msg: `[Node] Executing prompt node`, node: node.displayName });
|
|
30
32
|
const llmToUse = node.llmConfig ? createLlmInstance(node.llmConfig) : llm;
|
|
31
33
|
|
|
32
34
|
const globalTools = tools
|
|
@@ -39,20 +41,19 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
39
41
|
}),
|
|
40
42
|
);
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
const playbookParams = {
|
|
44
|
-
...state.memory, // Spread memory fields at the top level
|
|
45
|
-
};
|
|
46
|
-
const compiledPlaybooks = compilePlaybooks(agent.playbooks, playbookParams) || '';
|
|
47
|
-
|
|
48
|
-
const message = `
|
|
49
|
-
${node.prompt ? `# Task instructions:\n${node.prompt}\n\n` : ''}
|
|
50
|
-
${state.memory ? `# Task context:\n${JSON.stringify(state.memory)}\n\n` : ''}
|
|
51
|
-
${compiledPlaybooks ? `# General guidelines:\n${compiledPlaybooks}\n\n` : ''}
|
|
52
|
-
`;
|
|
44
|
+
const combinedPlaybooks = combinePlaybooks(agent.playbooks) || '';
|
|
53
45
|
|
|
54
|
-
|
|
46
|
+
// Get edges for the current node and format them
|
|
47
|
+
const edges = agent.flows?.flatMap((flow: any) => flow.edges) || [];
|
|
48
|
+
const nodeEdges = edges.filter((edge: any) => edge.source === node.name);
|
|
49
|
+
const currentPromptNode = getCurrentPromptNode(node, nodeEdges);
|
|
50
|
+
const systemMessage = combinedPlaybooks + '\n\n' + currentPromptNode;
|
|
51
|
+
const compiledPrompt = compilePrompt(systemMessage, { memory: state.memory, system: { currentTime: new Date().toISOString() } });
|
|
55
52
|
|
|
53
|
+
const startTime = Date.now();
|
|
54
|
+
const result: AIMessage = await llmToUse.bindTools(globalTools).invoke([new SystemMessage(compiledPrompt), ...state.messages]);
|
|
55
|
+
const endTime = Date.now();
|
|
56
|
+
logger.debug({ msg: '[Model] Model execution time', executionTimeMs: endTime - startTime });
|
|
56
57
|
// Check if the result contains tool calls
|
|
57
58
|
if (result.tool_calls && result.tool_calls.length > 0) {
|
|
58
59
|
// Execute the tools
|
|
@@ -65,8 +66,33 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
65
66
|
if (matchedTool) {
|
|
66
67
|
try {
|
|
67
68
|
// Invoke the LangChain tool directly
|
|
69
|
+
const startTime = Date.now();
|
|
68
70
|
const toolResult = await matchedTool.invoke(toolCall);
|
|
69
|
-
|
|
71
|
+
const endTime = Date.now();
|
|
72
|
+
logger.debug({ msg: `[Tool] Tool result`, tool: matchedTool?.name, result: toolResult, executionTimeMs: endTime - startTime });
|
|
73
|
+
//check for queue after tool call
|
|
74
|
+
const systemMessageId = uuidv4();
|
|
75
|
+
|
|
76
|
+
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId, {
|
|
77
|
+
messages: [
|
|
78
|
+
result,
|
|
79
|
+
toolResult,
|
|
80
|
+
new SystemMessage({
|
|
81
|
+
id: systemMessageId,
|
|
82
|
+
content:
|
|
83
|
+
'you called tool when the user send a new message, Consider calling the function again after user message is processed',
|
|
84
|
+
}),
|
|
85
|
+
],
|
|
86
|
+
history: [
|
|
87
|
+
createHistoryStep<HistoryStep>(state.history, {
|
|
88
|
+
type: NodeType.TOOL,
|
|
89
|
+
nodeId: node.name,
|
|
90
|
+
nodeDisplayName: node.displayName,
|
|
91
|
+
raw: toolResult,
|
|
92
|
+
messageIds: [toolResult.id!, systemMessageId],
|
|
93
|
+
}),
|
|
94
|
+
],
|
|
95
|
+
});
|
|
70
96
|
const toolStateUpdate = extractToolStateResponse(toolResult);
|
|
71
97
|
// Properly merge memory and other state updates
|
|
72
98
|
stateUpdates = {
|
|
@@ -75,7 +101,8 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
75
101
|
memory: { ...(stateUpdates as any).memory, ...(toolStateUpdate as any).memory },
|
|
76
102
|
};
|
|
77
103
|
toolResults.push(toolResult);
|
|
78
|
-
} catch (error) {
|
|
104
|
+
} catch (error: any) {
|
|
105
|
+
if (error?.name === 'GraphInterrupt') throw error;
|
|
79
106
|
logger.error({ msg: `[Tool] Error executing tool`, tool: toolCall.name, error });
|
|
80
107
|
const errorMessage = new ToolMessage({
|
|
81
108
|
content: JSON.stringify({ error: error instanceof Error ? error.message : String(error) }),
|
|
@@ -88,10 +115,30 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
88
115
|
}
|
|
89
116
|
}
|
|
90
117
|
|
|
118
|
+
// await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
119
|
+
|
|
91
120
|
// Return the tool call message and tool results with state updates spread at top level
|
|
92
121
|
return {
|
|
93
122
|
...stateUpdates,
|
|
94
123
|
messages: [result, ...toolResults],
|
|
124
|
+
history: [
|
|
125
|
+
createHistoryStep<HistoryStep>(state.history, {
|
|
126
|
+
type: NodeType.TOOL,
|
|
127
|
+
nodeId: node.name,
|
|
128
|
+
nodeDisplayName: node.displayName,
|
|
129
|
+
raw: result,
|
|
130
|
+
messageIds: [result.id!],
|
|
131
|
+
}),
|
|
132
|
+
...toolResults.map((toolResult) =>
|
|
133
|
+
createHistoryStep<HistoryStep>(state.history, {
|
|
134
|
+
type: NodeType.TOOL,
|
|
135
|
+
nodeId: node.name,
|
|
136
|
+
nodeDisplayName: node.displayName,
|
|
137
|
+
raw: toolResult,
|
|
138
|
+
messageIds: [toolResult.id!],
|
|
139
|
+
}),
|
|
140
|
+
),
|
|
141
|
+
],
|
|
95
142
|
};
|
|
96
143
|
}
|
|
97
144
|
|
|
@@ -102,7 +149,6 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
102
149
|
});
|
|
103
150
|
logger.info({ msg: `[Model] Response`, content: result.content });
|
|
104
151
|
}
|
|
105
|
-
|
|
106
152
|
return {
|
|
107
153
|
goto: null,
|
|
108
154
|
history: createHistoryStep<HistoryStep>(state.history, {
|
|
@@ -117,3 +163,43 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
|
|
|
117
163
|
};
|
|
118
164
|
graph.addNode(node.name, callback);
|
|
119
165
|
};
|
|
166
|
+
|
|
167
|
+
function getCurrentPromptNode(node: PromptNode, nodeEdges: any[]) {
|
|
168
|
+
// Format edges for display
|
|
169
|
+
let nextEdges = '';
|
|
170
|
+
if (node.canStayOnNode !== false) {
|
|
171
|
+
nextEdges = `0. Stay in the current step. step title: ${node.displayName}\n`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let counter = node.canStayOnNode !== false ? 0 : -1;
|
|
175
|
+
const promptConditionEdges = nodeEdges.filter((edge: any) => edge.type === 'PROMPT_CONDITION');
|
|
176
|
+
promptConditionEdges.forEach((edge: any) => {
|
|
177
|
+
counter++;
|
|
178
|
+
nextEdges += `${counter}. ${edge.prompt || edge.condition || `Go to ${edge.target}`}\n`;
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
return `
|
|
182
|
+
# Current Node Instructions
|
|
183
|
+
|
|
184
|
+
The flow of the conversation is built upon nodes. each conversation turn you
|
|
185
|
+
will be given just with the current node prompt.
|
|
186
|
+
|
|
187
|
+
Always follow the guidelines of "Current node prompt"
|
|
188
|
+
|
|
189
|
+
Current node title: ${node.displayName}
|
|
190
|
+
|
|
191
|
+
Current node prompt:
|
|
192
|
+
${node.prompt}
|
|
193
|
+
|
|
194
|
+
# Next nodes
|
|
195
|
+
|
|
196
|
+
After handling current node you can stay in the same node or move to the next
|
|
197
|
+
node based on the condition.
|
|
198
|
+
|
|
199
|
+
The next nodes will run automatically by condition runner later, no need to
|
|
200
|
+
worry about it now.
|
|
201
|
+
|
|
202
|
+
Here are possible next nodes and their conditions, never share this
|
|
203
|
+
information with the user:
|
|
204
|
+
${nextEdges}`;
|
|
205
|
+
}
|
package/src/nodes/addToolNode.ts
CHANGED
|
@@ -7,9 +7,10 @@ import { RunnableLike } from '@langchain/core/runnables';
|
|
|
7
7
|
import { LLMProviders } from '../types/LLM.types';
|
|
8
8
|
import { logger } from '../utils/logger';
|
|
9
9
|
import { Agent } from '../agent';
|
|
10
|
-
import { compilePlaybooks } from '../playbooks/playbooks';
|
|
11
10
|
import { createHistoryStep } from '../utils/history';
|
|
12
11
|
import { HistoryStep } from '../types/Agent.types';
|
|
12
|
+
import { combinePlaybooks } from '../playbooks/playbooks';
|
|
13
|
+
import { compilePrompt } from './compilePrompt';
|
|
13
14
|
|
|
14
15
|
export const addToolNode = async ({
|
|
15
16
|
graph,
|
|
@@ -30,6 +31,7 @@ export const addToolNode = async ({
|
|
|
30
31
|
throw new Error(`Tool not found: ${toolNode.toolName} in node ${node.name}`);
|
|
31
32
|
}
|
|
32
33
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
34
|
+
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
33
35
|
logger.debug({ msg: `[Node] Executing tool node`, node: toolNode.displayName });
|
|
34
36
|
|
|
35
37
|
const tool = langchainTool(() => {}, {
|
|
@@ -38,24 +40,20 @@ export const addToolNode = async ({
|
|
|
38
40
|
schema: matchedTool.input,
|
|
39
41
|
});
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Add any other common parameters that playbooks might need
|
|
46
|
-
};
|
|
47
|
-
const compiledPlaybooks = compilePlaybooks(agent.playbooks, playbookParams) || '';
|
|
43
|
+
const combinedPlaybooks = combinePlaybooks(agent.playbooks) || '';
|
|
44
|
+
const systemPrompt = combinedPlaybooks
|
|
45
|
+
? compilePrompt(combinedPlaybooks, { memory: state.memory, system: { currentTime: new Date().toISOString() } })
|
|
46
|
+
: '';
|
|
48
47
|
|
|
49
|
-
const
|
|
50
|
-
Additional context:
|
|
51
|
-
workflow memory: ${JSON.stringify(state.memory)}
|
|
52
|
-
`;
|
|
48
|
+
const startTime = Date.now();
|
|
53
49
|
const AIToolCallMessage: AIMessage = await llm
|
|
54
50
|
.bindTools([tool], {
|
|
55
51
|
tool_choice: tool.name,
|
|
56
52
|
})
|
|
57
|
-
.invoke([...state.messages, new SystemMessage(
|
|
58
|
-
|
|
53
|
+
.invoke([...state.messages, new SystemMessage(systemPrompt)]);
|
|
54
|
+
const endTime = Date.now();
|
|
55
|
+
logger.debug({ msg: '[Tool] Model execution time', tool: matchedTool.name, executionTimeMs: endTime - startTime });
|
|
56
|
+
await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
|
|
59
57
|
return {
|
|
60
58
|
goto: null,
|
|
61
59
|
messages: [AIToolCallMessage],
|
|
@@ -23,6 +23,7 @@ type AddToolRunNodeParams = {
|
|
|
23
23
|
|
|
24
24
|
export const buildToolRunNodeName = (nodeName: string) => `${nodeName}${internalNodesSuffix.TOOL_RUN}`;
|
|
25
25
|
|
|
26
|
+
//you never want to interrupt here because of new triggers, as this node depends on the last message to be the tool call from the addToolNode, interrupting will add human message here
|
|
26
27
|
export const addToolRunNode = async ({ graph, tools, toolNode, attachedToNodeName, agent }: AddToolRunNodeParams) => {
|
|
27
28
|
const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
|
|
28
29
|
const matchedTool = tools.find((tool) => tool.name === toolNode.toolName);
|
|
@@ -32,7 +33,10 @@ export const addToolRunNode = async ({ graph, tools, toolNode, attachedToNodeNam
|
|
|
32
33
|
|
|
33
34
|
const executeWrapper = async (input: z.infer<typeof matchedTool.input>) => {
|
|
34
35
|
try {
|
|
36
|
+
const startTime = Date.now();
|
|
35
37
|
const response = await matchedTool.execute({ input, state, agent });
|
|
38
|
+
const endTime = Date.now();
|
|
39
|
+
logger.debug({ msg: '[Tool] Tool execution time', tool: matchedTool.name, executionTimeMs: endTime - startTime });
|
|
36
40
|
return response || {};
|
|
37
41
|
} catch (error) {
|
|
38
42
|
logger.error({ msg: '[Tool] Error executing tool', error, node: toolNode.displayName });
|
|
@@ -54,7 +58,6 @@ export const addToolRunNode = async ({ graph, tools, toolNode, attachedToNodeNam
|
|
|
54
58
|
|
|
55
59
|
// Push the toolCallMessage into the messages array from toolStateUpdate
|
|
56
60
|
const updatedMessages = [toolCallMessage, ...((toolStateUpdate as any).messages || [])];
|
|
57
|
-
|
|
58
61
|
// Return the full state update from the tool with the updated messages
|
|
59
62
|
|
|
60
63
|
return {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as ejs from 'ejs';
|
|
2
|
+
import { logger } from '../utils/logger';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Compile prompt with parameters using EJS and placeholder replacement
|
|
6
|
+
*/
|
|
7
|
+
export function compilePrompt(prompt: string, params: Record<string, any> = {}): string {
|
|
8
|
+
try {
|
|
9
|
+
// First, render with EJS
|
|
10
|
+
let compiledPrompt = ejs.render(prompt, params);
|
|
11
|
+
|
|
12
|
+
// Then, replace placeholders in {} format
|
|
13
|
+
compiledPrompt = replacePlaceholders(compiledPrompt, params);
|
|
14
|
+
|
|
15
|
+
return compiledPrompt;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
logger.error({ message: 'Error compiling prompt', error });
|
|
18
|
+
return prompt; // Return uncompiled if there's an error
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Replace placeholders in {key} format
|
|
24
|
+
*/
|
|
25
|
+
function replacePlaceholders(text: string, params: Record<string, any>): string {
|
|
26
|
+
return text.replace(/\{([^}]+)\}/g, (match, key) => {
|
|
27
|
+
const keys = key.split('.');
|
|
28
|
+
let value: any = params;
|
|
29
|
+
|
|
30
|
+
for (const k of keys) {
|
|
31
|
+
if (value && typeof value === 'object' && k in value) {
|
|
32
|
+
value = value[k];
|
|
33
|
+
} else {
|
|
34
|
+
logger.warn({ message: `Placeholder {${key}} in prompt not found in memory. It will remain as placeholder.` });
|
|
35
|
+
return match; // Return original if key not found
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return String(value);
|
|
40
|
+
});
|
|
41
|
+
}
|