@minded-ai/mindedjs 1.0.108 → 1.0.109-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.
Files changed (112) hide show
  1. package/dist/agent.d.ts +12 -12
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +37 -13
  4. package/dist/agent.js.map +1 -1
  5. package/dist/browserTask/README.md +419 -0
  6. package/dist/browserTask/browserAgent.py +632 -0
  7. package/dist/browserTask/captcha_isolated.png +0 -0
  8. package/dist/browserTask/executeBrowserTask.d.ts +1 -11
  9. package/dist/browserTask/executeBrowserTask.d.ts.map +1 -1
  10. package/dist/browserTask/executeBrowserTask.js +67 -170
  11. package/dist/browserTask/executeBrowserTask.js.map +1 -1
  12. package/dist/browserTask/executeBrowserTask.ts +79 -0
  13. package/dist/browserTask/requirements.txt +8 -0
  14. package/dist/browserTask/setup.sh +144 -0
  15. package/dist/cli/index.js +103 -1
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/edges/createLogicalRouter.d.ts +3 -1
  18. package/dist/edges/createLogicalRouter.d.ts.map +1 -1
  19. package/dist/edges/createLogicalRouter.js +41 -2
  20. package/dist/edges/createLogicalRouter.js.map +1 -1
  21. package/dist/edges/edgeFactory.d.ts.map +1 -1
  22. package/dist/edges/edgeFactory.js +7 -7
  23. package/dist/edges/edgeFactory.js.map +1 -1
  24. package/dist/events/AgentEvents.d.ts +19 -1
  25. package/dist/events/AgentEvents.d.ts.map +1 -1
  26. package/dist/events/AgentEvents.js +2 -0
  27. package/dist/events/AgentEvents.js.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +4 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/internalTools/timer.d.ts +3 -3
  33. package/dist/internalTools/timer.d.ts.map +1 -1
  34. package/dist/internalTools/timer.js +3 -3
  35. package/dist/internalTools/timer.js.map +1 -1
  36. package/dist/nodes/addBrowserTaskNode.d.ts +1 -3
  37. package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -1
  38. package/dist/nodes/addBrowserTaskNode.js +54 -186
  39. package/dist/nodes/addBrowserTaskNode.js.map +1 -1
  40. package/dist/nodes/nodeFactory.js +1 -1
  41. package/dist/nodes/nodeFactory.js.map +1 -1
  42. package/docs/SUMMARY.md +8 -4
  43. package/docs/low-code-editor/edges.md +4 -0
  44. package/docs/sdk/debugging.md +342 -0
  45. package/docs/{platform → sdk}/events.md +168 -1
  46. package/package.json +12 -5
  47. package/dist/nodes/addBrowserTaskRunNode.d.ts +0 -13
  48. package/dist/nodes/addBrowserTaskRunNode.d.ts.map +0 -1
  49. package/dist/nodes/addBrowserTaskRunNode.js +0 -130
  50. package/dist/nodes/addBrowserTaskRunNode.js.map +0 -1
  51. package/src/agent.ts +0 -928
  52. package/src/browserTask/executeBrowserTask.ts +0 -213
  53. package/src/checkpointer/checkpointSaverFactory.ts +0 -18
  54. package/src/cli/index.ts +0 -170
  55. package/src/cli/lambdaHandlerTemplate.ts +0 -45
  56. package/src/edges/createDirectEdge.ts +0 -16
  57. package/src/edges/createLogicalRouter.ts +0 -114
  58. package/src/edges/createPromptRouter.ts +0 -218
  59. package/src/edges/edgeFactory.ts +0 -141
  60. package/src/events/AgentEvents.ts +0 -47
  61. package/src/events/index.ts +0 -3
  62. package/src/index.ts +0 -70
  63. package/src/interfaces/zendesk.ts +0 -157
  64. package/src/internalTools/appActionRunnerTool.ts +0 -68
  65. package/src/internalTools/documentExtraction/documentExtraction.ts +0 -809
  66. package/src/internalTools/documentExtraction/types.ts +0 -59
  67. package/src/internalTools/libraryActionRunnerTool.ts +0 -63
  68. package/src/internalTools/retell.ts +0 -28
  69. package/src/internalTools/sendPlaceholderMessage.ts +0 -27
  70. package/src/internalTools/timer.ts +0 -137
  71. package/src/llm/createLlmInstance.ts +0 -33
  72. package/src/nodes/addAppToolNode.ts +0 -106
  73. package/src/nodes/addBrowserTaskNode.ts +0 -231
  74. package/src/nodes/addBrowserTaskRunNode.ts +0 -144
  75. package/src/nodes/addHumanInTheLoopNode.ts +0 -25
  76. package/src/nodes/addJumpToNode.ts +0 -25
  77. package/src/nodes/addJunctionNode.ts +0 -20
  78. package/src/nodes/addPromptNode.ts +0 -119
  79. package/src/nodes/addToolNode.ts +0 -72
  80. package/src/nodes/addToolRunNode.ts +0 -76
  81. package/src/nodes/addTriggerNode.ts +0 -27
  82. package/src/nodes/nodeFactory.ts +0 -57
  83. package/src/platform/config.ts +0 -77
  84. package/src/platform/mindedCheckpointSaver.ts +0 -146
  85. package/src/platform/mindedConnection.ts +0 -199
  86. package/src/platform/mindedConnectionTypes.ts +0 -220
  87. package/src/platform/models/mindedChatOpenAI.ts +0 -49
  88. package/src/platform/models/parallelWrapper.ts +0 -141
  89. package/src/platform/piiGateway/gateway.ts +0 -103
  90. package/src/platform/piiGateway/index.ts +0 -5
  91. package/src/platform/piiGateway/types.ts +0 -29
  92. package/src/platform/utils/parseAttachments.ts +0 -56
  93. package/src/playbooks/playbooks.ts +0 -209
  94. package/src/toolsLibrary/index.ts +0 -6
  95. package/src/toolsLibrary/parseDocument.ts +0 -136
  96. package/src/triggers/triggerTypeToDefaultMessage.ts +0 -9
  97. package/src/types/Agent.types.ts +0 -67
  98. package/src/types/Flows.types.ts +0 -200
  99. package/src/types/LLM.types.ts +0 -15
  100. package/src/types/LangGraph.types.ts +0 -53
  101. package/src/types/Platform.types.ts +0 -1
  102. package/src/types/Tools.types.ts +0 -31
  103. package/src/types/Voice.types.ts +0 -4
  104. package/src/utils/extractStateMemoryResponse.ts +0 -16
  105. package/src/utils/history.ts +0 -9
  106. package/src/utils/logger.ts +0 -22
  107. package/src/utils/wait.ts +0 -1
  108. package/src/voice/elevenLabsUtils.ts +0 -81
  109. package/src/voice/voiceSession.ts +0 -294
  110. /package/docs/{platform → sdk}/logging.md +0 -0
  111. /package/docs/{platform → sdk}/memory.md +0 -0
  112. /package/docs/{platform → sdk}/parallel-llm.md +0 -0
package/src/agent.ts DELETED
@@ -1,928 +0,0 @@
1
- import {
2
- Flow,
3
- NodeType,
4
- Node,
5
- EdgeType,
6
- KnownTriggerNames,
7
- TriggerType,
8
- VoiceTriggerNode,
9
- internalNodesSuffix,
10
- AppToolNode,
11
- } from './types/Flows.types';
12
-
13
- import { Tool } from './types/Tools.types';
14
- import { v4 as uuidv4 } from 'uuid';
15
- import { BaseLanguageModel } from '@langchain/core/language_models/base';
16
- import { Command, StateGraph } from '@langchain/langgraph';
17
- import { BaseCheckpointSaver } from '@langchain/langgraph';
18
- import { nodeFactory } from './nodes/nodeFactory';
19
- import { CompiledGraph, PreCompiledGraph, stateAnnotation } from './types/LangGraph.types';
20
- import { edgeFactory } from './edges/edgeFactory';
21
- import { AgentEventRequestPayloads, AgentEventResponsePayloads, AgentEvents } from './events/AgentEvents';
22
- import { z } from 'zod';
23
- import * as mindedConnection from './platform/mindedConnection';
24
- import { InvokeMessage, mindedConnectionSocketMessageType } from './platform/mindedConnectionTypes';
25
- import * as fs from 'fs';
26
- import * as path from 'path';
27
- import * as yaml from 'js-yaml';
28
- import {
29
- AgentInvokeParams,
30
- AppTriggerHistoryStep,
31
- TriggerHistoryStep,
32
- MindedSDKConfig,
33
- SessionType,
34
- HistoryStep,
35
- } from './types/Agent.types';
36
- import { createLlmInstance } from './llm/createLlmInstance';
37
- import { createCheckpointSaver } from './checkpointer/checkpointSaverFactory';
38
- import { getConfig } from './platform/config';
39
- import { BaseMessage, HumanMessage } from '@langchain/core/messages';
40
- import triggerTypeToDefaultMessage from './triggers/triggerTypeToDefaultMessage';
41
- import appActionRunnerToolCreator from './internalTools/appActionRunnerTool';
42
- import libraryActionRunnerToolCreator from './internalTools/libraryActionRunnerTool';
43
- import { VoiceSession } from './voice/voiceSession';
44
- import { BaseVoiceMessage, OnVoiceAudioOut } from './platform/mindedConnectionTypes';
45
- import { PIIGateway, PIIGatewayInstance } from './platform/piiGateway';
46
- import { logger } from './utils/logger';
47
- import { loadPlaybooks, Playbook } from './playbooks/playbooks';
48
- import { createHistoryStep } from './utils/history';
49
- import { timerHandlers } from './internalTools/timer';
50
- import { parseAttachments, combineContentWithAttachments } from './platform/utils/parseAttachments';
51
-
52
- type CreateAgentParams<Memory> = {
53
- memorySchema: z.ZodSchema;
54
- config: MindedSDKConfig;
55
- tools: Tool<any, Memory>[];
56
- platformToken?: string;
57
- memorySaver?: BaseCheckpointSaver;
58
- };
59
-
60
- /**
61
- * The main Agent class that orchestrates flows, tools, and integrations with the Minded platform.
62
- *
63
- * @example
64
- * ```typescript
65
- * const agent = new Agent({
66
- * memorySchema: z.object({
67
- * userName: z.string().optional(),
68
- * preferences: z.record(z.any()).optional()
69
- * }),
70
- * config: {
71
- * flows: ['./src/flows'],
72
- * llm: { provider: 'openai', model: 'gpt-4' }
73
- * },
74
- * tools: [myCustomTool]
75
- * });
76
- * ```
77
- */
78
- export class Agent {
79
- private memorySchema: z.ZodSchema;
80
- private flows!: Flow[];
81
- public tools!: Tool<any, any>[];
82
- /**
83
- * Internal tools
84
- */
85
- public llm!: BaseLanguageModel;
86
- // Remove the mindedConnection property since it's now a singleton module
87
-
88
- // Langgraph memory saver. In memory for local development, Custom for Platform
89
- private checkpointer!: BaseCheckpointSaver;
90
- // Langgraph compiled graph
91
- public compiledGraph!: CompiledGraph;
92
- // Cache for secrets to avoid repeated API calls
93
- private secretsCache: Record<string, string> | null = null;
94
- public config: MindedSDKConfig;
95
-
96
- // PII gateway instance
97
- private _piiGateway: PIIGatewayInstance | null = null;
98
- public playbooks: Playbook[] = [];
99
-
100
- // Getter for PII Gateway that ensures it's available
101
- public get piiGateway(): PIIGatewayInstance {
102
- if (!this._piiGateway) {
103
- throw new Error('PII Gateway is not initialized. Make sure the agent is connected to the Minded platform.');
104
- }
105
- return this._piiGateway;
106
- }
107
-
108
- // Event handlers storage keyed by event name. Handlers can optionally return a value.
109
- private eventHandlers: {
110
- [K in keyof AgentEventRequestPayloads<z.infer<typeof this.memorySchema>>]?: Array<
111
- (payload: AgentEventRequestPayloads<z.infer<typeof this.memorySchema>>[K]) => any | Promise<any>
112
- >;
113
- } = {};
114
-
115
- private initialized = false;
116
- private initPromise: Promise<void> | null = null;
117
- private startingNodeId: string | null = null;
118
- public voiceSessions: Map<string, VoiceSession> = new Map();
119
-
120
- /**
121
- * Create a new Agent instance.
122
- *
123
- * @param params - Configuration parameters for the agent
124
- * @param params.memorySchema - Zod schema defining the structure of the agent's memory
125
- * @param params.config - SDK configuration including flows directory and LLM settings
126
- * @param params.tools - Array of custom tools to be available to the agent
127
- * @param params.platformToken - Optional token for platform authentication
128
- * @param params.memorySaver - Optional custom checkpoint saver for conversation memory
129
- *
130
- * @example
131
- * ```typescript
132
- * const agent = new Agent({
133
- * memorySchema: z.object({
134
- * userName: z.string().optional(),
135
- * conversationHistory: z.array(z.string()).optional()
136
- * }),
137
- * config: {
138
- * flows: ['./src/flows'],
139
- * llm: {
140
- * provider: 'openai',
141
- * model: 'gpt-4-turbo'
142
- * }
143
- * },
144
- * tools: [
145
- * weatherTool,
146
- * databaseTool
147
- * ]
148
- * });
149
- * ```
150
- */
151
- constructor(params: CreateAgentParams<z.infer<typeof this.memorySchema>>) {
152
- const { memorySchema } = params;
153
- this.memorySchema = memorySchema;
154
- this.initPromise = this.init(params);
155
- this.config = params.config;
156
- }
157
-
158
- private async init(params: CreateAgentParams<z.infer<typeof this.memorySchema>>): Promise<void> {
159
- try {
160
- const { config, tools, memorySaver } = params;
161
- const { runLocally } = getConfig();
162
- if (!runLocally) {
163
- await mindedConnection.start();
164
-
165
- // Initialize PII gateway
166
- this._piiGateway = new PIIGateway();
167
-
168
- mindedConnection.on(mindedConnectionSocketMessageType.INVOKE, async (message, callback) => {
169
- const invokeMessage = message as InvokeMessage;
170
- const result = await this.invoke({
171
- triggerBody: invokeMessage.triggerBody,
172
- triggerName: invokeMessage.triggerName,
173
- appName: invokeMessage.appName,
174
- sessionId: invokeMessage.sessionId,
175
- });
176
- callback(result);
177
- });
178
-
179
- mindedConnection.on(mindedConnectionSocketMessageType.RESTORE_CHECKPOINT, async (restoreCheckpointMessage, callback) => {
180
- await this.restoreCheckpoint(restoreCheckpointMessage.sessionId, restoreCheckpointMessage.checkpointId);
181
- callback({ success: true });
182
- });
183
- }
184
-
185
- const [, flows, playbooks] = await Promise.all([this.loadSecrets(), this.loadFlows(config.flows), loadPlaybooks(config.playbooks)]);
186
-
187
- this.playbooks = playbooks;
188
- this.flows = flows;
189
- this.validate();
190
- const appActionsRunnerTools = this.initAppActionsRunnerTools();
191
- const libraryActionsRunnerTools = this.initLibraryActionsRunnerTools();
192
- this.tools = [...tools, ...appActionsRunnerTools, ...libraryActionsRunnerTools];
193
- this.checkpointer = memorySaver || createCheckpointSaver();
194
-
195
- // call here methods that needs environment variables to be loaded
196
- this.llm = createLlmInstance(config.llm);
197
- this.compiledGraph = this.initializeGraph();
198
- this.initialized = true;
199
-
200
- const flowHasVoiceTrigger = this.flows.some((flow) =>
201
- flow.nodes.some((node) => node.type === NodeType.TRIGGER && node.triggerType === TriggerType.VOICE),
202
- );
203
- if (flowHasVoiceTrigger) {
204
- this.setupVoice();
205
- }
206
- } catch (error) {
207
- this.initialized = false;
208
- throw error;
209
- }
210
- }
211
-
212
- private async loadFlows(flowsDirectories: string[]) {
213
- const { env, isDeployed } = getConfig();
214
- if (['sandbox-staging', 'sandbox'].includes(env) && isDeployed) {
215
- const response = await mindedConnection.awaitEmit<object, { flows: Record<string, Flow> }>(
216
- mindedConnectionSocketMessageType.GET_FLOWS,
217
- {},
218
- );
219
- if (!response?.flows) {
220
- throw new Error('Could not load flows from the platform connection');
221
- }
222
- return Object.values(response.flows);
223
- }
224
- return this.loadFlowsFromDirectory(flowsDirectories);
225
- }
226
-
227
- private loadFlowsFromDirectory(flowsDirectories: string[]): Flow[] {
228
- const flows: Flow[] = [];
229
- for (const flowsDirectory of flowsDirectories) {
230
- if (!fs.existsSync(flowsDirectory)) {
231
- throw new Error(`Flows directory does not exist: ${flowsDirectory}`);
232
- }
233
-
234
- const files = fs.readdirSync(flowsDirectory);
235
-
236
- for (const file of files) {
237
- if (file.endsWith('.yaml') || file.endsWith('.yml')) {
238
- const filePath = path.join(flowsDirectory, file);
239
- try {
240
- const fileContent = fs.readFileSync(filePath, 'utf8');
241
- const parsedFlow = yaml.load(fileContent) as Flow;
242
-
243
- // Validate that the parsed flow has the required structure
244
- if (!parsedFlow.name || !parsedFlow.nodes || !parsedFlow.edges) {
245
- throw new Error(`Invalid flow structure in ${file}. Flow must have name, nodes, and edges.`);
246
- }
247
-
248
- flows.push(parsedFlow);
249
- } catch (error) {
250
- throw new Error(`Failed to parse flow file ${file}: ${error}`);
251
- }
252
- }
253
- }
254
-
255
- if (flows.length === 0) {
256
- throw new Error(`No YAML flow files found in directory: ${flowsDirectory}`);
257
- }
258
- }
259
-
260
- return flows;
261
- }
262
-
263
- private validate() {
264
- if (this.flows.length === 0) {
265
- throw new Error('No flows provided');
266
- }
267
- }
268
-
269
- private async waitForInitialization(): Promise<void> {
270
- if (this.initialized) {
271
- return;
272
- }
273
- if (this.initPromise) {
274
- try {
275
- await this.initPromise;
276
- if (!this.initialized) {
277
- throw new Error('Agent initialization failed');
278
- }
279
- } catch (error) {
280
- throw new Error(`Failed to initialize agent: ${error instanceof Error ? error.message : 'Unknown error'}`);
281
- }
282
- } else {
283
- throw new Error('Agent initialization has not started');
284
- }
285
- }
286
-
287
- private initializeGraph(): CompiledGraph {
288
- const nodes = this.flows.flatMap((flow) => flow.nodes);
289
- const edges = this.flows.flatMap((flow) => flow.edges);
290
-
291
- // Initialize the graph
292
- const graph = new StateGraph(stateAnnotation)
293
- .addNode('init', this.initGraphState.bind(this))
294
- .addEdge('__start__', 'init') as PreCompiledGraph;
295
-
296
- // Add nodes and create nodes object
297
- const nodesObject: { [key: string]: Node } = {};
298
- nodes.forEach((node) => {
299
- // Add to nodes object
300
- nodesObject[node.name] = node;
301
- // Add to graph
302
- nodeFactory({
303
- graph,
304
- node,
305
- tools: this.tools,
306
- llm: this.llm,
307
- emit: this.emit.bind(this),
308
- agent: this,
309
- });
310
- });
311
-
312
- // Add edge from start to first node if no triggers exist
313
- const hasTrigger = nodes.some((node) => node.type === NodeType.TRIGGER && node.triggerType !== TriggerType.MANUAL);
314
- if (!hasTrigger) {
315
- // Find the Main flow
316
- const mainFlow = this.flows.find((flow) => flow.name === 'Main flow');
317
- if (mainFlow && mainFlow.nodes.length > 0) {
318
- this.startingNodeId = mainFlow.nodes[0].name;
319
- graph.addEdge('__start__', mainFlow.nodes[0].name as any);
320
- } else if (nodes.length > 0) {
321
- // Fallback to first node if Main flow not found
322
- this.startingNodeId = nodes[0].name;
323
- graph.addEdge('__start__', nodes[0].name as any);
324
- } else {
325
- throw new Error('No starting node found');
326
- }
327
- } else {
328
- nodes.forEach((node) => {
329
- if (node.type === NodeType.TRIGGER && node.triggerType !== TriggerType.MANUAL) {
330
- this.startingNodeId = node.name;
331
- graph.addEdge('__start__', node.name as any);
332
- }
333
- });
334
- }
335
-
336
- // Add edges to __end__ for nodes with no outgoing edges
337
- const sourceNodes = new Set(edges.map((edge) => edge.source));
338
- const lastNodes = Object.keys(nodesObject).filter((nodeName) => !sourceNodes.has(nodeName) && !nodesObject[nodeName].canStayOnNode);
339
- lastNodes.forEach((nodeName) => {
340
- edges.push({
341
- source: nodeName,
342
- target: '__end__',
343
- type: EdgeType.STEP_FORWARD,
344
- });
345
- });
346
-
347
- // Add edges
348
- edgeFactory({ graph, edges, nodes: nodesObject, tools: this.tools, llm: this.llm, agent: this });
349
-
350
- // Compile the graph
351
- return graph.compile({ checkpointer: this.checkpointer }) as CompiledGraph;
352
- }
353
-
354
- private async initGraphState(state: typeof stateAnnotation.State): Promise<typeof stateAnnotation.State> {
355
- // Try to parse empty object through the schema to apply default values
356
- // If parsing fails due to required fields without defaults, use empty object as fallback
357
- const parseResult = this.memorySchema.safeParse({});
358
- const initialMemory = parseResult.success ? parseResult.data : {};
359
-
360
- const initialState = {
361
- messages: [],
362
- memory: initialMemory,
363
- triggerMetadata: null,
364
- history: [],
365
- sessionId: state.sessionId || uuidv4(), // Preserve existing sessionId or generate new one
366
- sessionType: state.sessionType || SessionType.TEXT,
367
- overrideStartFromNodeId: null,
368
- goto: null,
369
- };
370
-
371
- // Emit INIT event with the initial state
372
- await this.emit(AgentEvents.INIT, {
373
- state: initialState,
374
- });
375
-
376
- return initialState;
377
- }
378
-
379
- private createTriggerHistoryStep(
380
- currentHistory: HistoryStep[],
381
- nodeId: string,
382
- messageIds: string[],
383
- triggerName: string,
384
- triggerBody: any,
385
- appName?: string,
386
- ): HistoryStep {
387
- const baseStep = {
388
- nodeId: nodeId,
389
- nodeDisplayName: triggerName,
390
- raw: triggerBody,
391
- messageIds,
392
- } as HistoryStep;
393
-
394
- return appName
395
- ? createHistoryStep<AppTriggerHistoryStep>(currentHistory, {
396
- ...baseStep,
397
- type: NodeType.TRIGGER,
398
- appName,
399
- })
400
- : createHistoryStep<TriggerHistoryStep>(currentHistory, {
401
- ...baseStep,
402
- type: NodeType.TRIGGER,
403
- });
404
- }
405
-
406
- /**
407
- * Invoke a trigger to start agent execution with the specified parameters.
408
- *
409
- * This method processes triggers from external systems or applications, allowing the agent
410
- * to respond to events and execute the appropriate flows based on the trigger type.
411
- *
412
- * @param params - The trigger invocation parameters
413
- * @param params.triggerBody - The payload/data associated with the trigger
414
- * @param params.triggerName - The name/type of the trigger being invoked
415
- * @param params.sessionId - Optional session identifier for conversation continuity
416
- * @param params.appName - Optional name of the application triggering the agent in case of an app trigger
417
- *
418
- * @returns Promise that resolves with the agent's execution result
419
- *
420
- * @throws {Error} When the agent is not properly initialized
421
- *
422
- * @example
423
- * ```typescript
424
- * // Manual invoke with a message trigger
425
- * const result = await agent.invoke({
426
- * triggerName: 'minded.message.in.conversation',
427
- * triggerBody: {
428
- * text: 'Hello, how can you help me?',
429
- * },
430
- * sessionId: 'user-123-session'
431
- * });
432
- * ```
433
- */
434
- public async invoke({ triggerBody, triggerName, sessionId, appName }: AgentInvokeParams) {
435
- sessionId = sessionId ?? uuidv4();
436
- try {
437
- await this.waitForInitialization();
438
- let messages: Array<BaseMessage> = [];
439
- let memoryUpdate = {};
440
- let sessionType: SessionType = SessionType.TEXT;
441
- if (triggerName === KnownTriggerNames.DASHBOARD_MESSAGE || triggerName === KnownTriggerNames.VOICE_MESSAGE) {
442
- // Parse attachments if present
443
- const attachmentsString = parseAttachments(triggerBody);
444
- const finalContent = combineContentWithAttachments(triggerBody.content || '', attachmentsString);
445
- if (finalContent) {
446
- messages = [new HumanMessage({ content: finalContent, id: uuidv4() })];
447
- }
448
- sessionType = triggerName === KnownTriggerNames.VOICE_MESSAGE ? SessionType.VOICE : SessionType.TEXT;
449
- } else {
450
- const results = await this.emit(AgentEvents.TRIGGER_EVENT, {
451
- triggerName,
452
- triggerBody,
453
- sessionId,
454
- });
455
- if (results.length === 0) {
456
- if (appName) {
457
- messages = triggerTypeToDefaultMessage[appName]?.[triggerName]?.(triggerBody) ?? [
458
- new HumanMessage({ content: JSON.stringify(triggerBody), id: uuidv4() }),
459
- ];
460
- } else {
461
- messages = [new HumanMessage({ content: JSON.stringify(triggerBody), id: uuidv4() })];
462
- }
463
- } else {
464
- const handlerResult = results.find((r) => r !== undefined);
465
- if (handlerResult) {
466
- if (!handlerResult.isQualified) {
467
- logger.debug({ msg: '[Trigger] Disqualified', triggerName, triggerBody, sessionId });
468
- return;
469
- }
470
- memoryUpdate = handlerResult.memory || {};
471
- messages = handlerResult.messages ?? [];
472
- sessionId = handlerResult.sessionId ?? sessionId;
473
- }
474
- }
475
- }
476
-
477
- logger.info({ msg: '[Trigger] Received', triggerName, triggerBody, sessionId });
478
- const langraphConfig = this.getLangraphConfig(sessionId || uuidv4());
479
- const state = await this.compiledGraph.getState(langraphConfig);
480
- const suffixes = Object.values(internalNodesSuffix);
481
- let nodeToBeInvoked =
482
- state.next.length > 0
483
- ? state.values.overrideStartFromNodeId
484
- ? state.values.overrideStartFromNodeId
485
- : state.next[0]
486
- : this.startingNodeId;
487
- if (!nodeToBeInvoked) {
488
- throw new Error('No node to be invoked');
489
- }
490
- nodeToBeInvoked = nodeToBeInvoked.replace(new RegExp(suffixes.join('|'), 'g'), '');
491
- const historyStep = this.createTriggerHistoryStep(
492
- state.values.history,
493
- nodeToBeInvoked,
494
- messages.map((m) => m.id!),
495
- triggerName,
496
- triggerBody,
497
- appName,
498
- );
499
-
500
- let res;
501
- // Resume interruption
502
- if (state.tasks?.[0]?.interrupts?.length > 0) {
503
- res = await this.compiledGraph.invoke(
504
- new Command({
505
- resume: { memory: memoryUpdate, messages, history: historyStep, sessionId, sessionType },
506
- }),
507
- langraphConfig,
508
- );
509
- } else if (state.values.overrideStartFromNodeId) {
510
- res = await this.compiledGraph.invoke(
511
- new Command({
512
- update: {
513
- overrideStartFromNodeId: null, //reset the overrideStartFromNodeId
514
- messages,
515
- memory: memoryUpdate,
516
- history: historyStep,
517
- sessionId,
518
- sessionType,
519
- },
520
- goto: state.values.overrideStartFromNodeId,
521
- }),
522
- langraphConfig,
523
- );
524
- } else {
525
- res = await this.compiledGraph.invoke(
526
- { messages, memory: memoryUpdate, history: historyStep, sessionId, sessionType },
527
- langraphConfig,
528
- );
529
- }
530
- return res;
531
- } catch (error: any) {
532
- logger.error({
533
- msg: '[Trigger] Error',
534
- errorMessage: error.message,
535
- stack: error.stack,
536
- sessionId,
537
- });
538
- const state = await this.compiledGraph.getState(this.getLangraphConfig(sessionId));
539
- this.emit(AgentEvents.ERROR, { error: error instanceof Error ? error : new Error(JSON.stringify(error)), state: state.values });
540
- throw error;
541
- }
542
- }
543
-
544
- /**
545
- * Register an event handler for specific agent events.
546
- *
547
- * This method allows you to listen for and respond to various events that occur during
548
- * agent execution, such as trigger events, memory updates, or custom application events.
549
- * Multiple handlers can be registered for the same event type and will be executed in the order they are registered.
550
- *
551
- * ## Available Event Types
552
- *
553
- * ### INIT
554
- * Emitted when the agent's graph state is initialized. This happens when a new session begins
555
- * or when the agent starts processing a new conversation context.
556
- *
557
- * **Input Structure:**
558
- * ```typescript
559
- * {
560
- * state: { // Full initial agent state
561
- * messages: BaseMessage[]; // Empty array - no messages yet
562
- * memory: Memory; // Initial memory state (from your schema defaults)
563
- * triggerInvocations: Array<...>; // Empty array - no triggers invoked yet
564
- * triggerMetadata: null; // No trigger metadata initially
565
- * history: HistoryStep[]; // Empty array - no flow history yet
566
- * sessionId: string; // Session identifier (generated or provided)
567
- * sessionType: SessionType; // Type of session (TEXT, VOICE, etc.)
568
- * }
569
- * }
570
- * ```
571
- *
572
- * **Expected Output:** `void` - Handlers are used for side effects like logging, setup, or initialization tasks
573
- *
574
- * **Common Use Cases:**
575
- * - Session logging and analytics tracking
576
- * - Resource initialization for new sessions
577
- * - State validation and verification
578
- * - External service setup and configuration
579
- * - Session routing and management
580
- * - Debugging and troubleshooting
581
- *
582
- * ### AI_MESSAGE
583
- * Emitted when an AI generates a message that should be sent to the user.
584
- *
585
- * **Input Structure:**
586
- * ```typescript
587
- * {
588
- * message: string; // The AI-generated message content
589
- * state: { // Full agent state
590
- * messages: BaseMessage[]; // Conversation messages
591
- * memory: Memory; // Current memory state (your defined memory schema)
592
- * triggerInvocations: Array<...>; // Trigger invocation history
593
- * triggerMetadata: {...} | null; // Current trigger metadata
594
- * history: HistoryStep[]; // Flow execution history with detailed step information
595
- * sessionId: string; // Session identifier
596
- * }
597
- * }
598
- * ```
599
- *
600
- * **Expected Output:** `void` - Handlers are used for side effects like sending messages to UI
601
- *
602
- * **Common Use Cases:**
603
- * - Real-time chat UI updates with session context
604
- * - Logging AI responses for analytics or debugging
605
- * - Message formatting and transformation
606
- * - Notifications and alerts based on AI responses
607
- * - Session-based message routing
608
- *
609
- * ### TRIGGER_EVENT
610
- * Emitted when a trigger node is executed. Allows you to qualify, transform, and provide
611
- * initial state for trigger inputs before they're processed by the agent.
612
- *
613
- * **Input Structure:**
614
- * ```typescript
615
- * {
616
- * triggerName: string; // Name of the trigger being executed
617
- * triggerBody: any; // The trigger input data (type varies by trigger)
618
- * }
619
- * ```
620
- *
621
- * **Expected Output:** One of three possible return types:
622
- *
623
- * 1. **Provide Initial State:**
624
- * ```typescript
625
- * {
626
- * messages?: BaseMessage[]; // Initial messages for the conversation
627
- * memory?: Memory; // Initial memory state
628
- * sessionId?: string; // Session ID for persistence (resumes existing sessions)
629
- * }
630
- * ```
631
- *
632
- * 2. **Disqualify the Trigger:**
633
- * ```typescript
634
- * false // Rejects/disqualifies the trigger from processing
635
- * ```
636
- *
637
- * 3. **Qualify without Initial State:**
638
- * ```typescript
639
- * void // Qualifies the trigger but provides no initial state
640
- * ```
641
- *
642
- * **Common Use Cases:**
643
- * - Input validation and trigger qualification
644
- * - Data transformation into standardized formats
645
- * - Context setting with initial memory state
646
- * - Access control and business rule enforcement
647
- * - Routing logic for different trigger types
648
- *
649
- * @template E - The event type, constrained to known agent event types
650
- * @param event - The name of the event to listen for
651
- * @param handler - The function to call when the event is emitted
652
- *
653
- * @example
654
- * ```typescript
655
- * // INIT Event Handler
656
- * agent.on('INIT', async ({ state }) => {
657
- * logger.info({ msg: 'Agent initialized for session:', sessionId: state.sessionId });
658
- * logger.info({ msg: 'Session type:', sessionType: state.sessionType });
659
- * logger.info({ msg: 'Initial memory:', memory: state.memory });
660
- *
661
- * // Setup session-specific resources
662
- * await initializeSessionResources(state.sessionId);
663
- *
664
- * // Log session start for analytics
665
- * await logSessionStart({
666
- * sessionId: state.sessionId,
667
- * sessionType: state.sessionType,
668
- * timestamp: new Date(),
669
- * });
670
- * });
671
- *
672
- * // AI_MESSAGE Event Handler
673
- * agent.on('AI_MESSAGE', async ({ message, state }) => {
674
- * logger.info({ msg: 'AI said:', output: message });
675
- * logger.info({ msg: 'Current memory:', output: state.memory });
676
- * logger.info({ msg: 'Session ID:', output: state.sessionId });
677
- *
678
- * // Send to user interface with session context
679
- * await sendMessageToUser(message, state.sessionId);
680
- *
681
- * // Send via WebSocket
682
- * await websocket.send(JSON.stringify({
683
- * type: 'ai_message',
684
- * content: message,
685
- * sessionId: state.sessionId,
686
- * memory: state.memory
687
- * }));
688
- * });
689
- *
690
- * // TRIGGER_EVENT Event Handler - Input Validation
691
- * agent.on('TRIGGER_EVENT', async ({ triggerName, triggerBody }) => {
692
- * // Validate trigger input
693
- * if (!isValidInput(triggerBody)) {
694
- * return false; // Disqualify the trigger
695
- * }
696
- *
697
- * // Business hours check
698
- * if (triggerName === 'supportRequest' && !isBusinessHours()) {
699
- * return false;
700
- * }
701
- *
702
- * return {
703
- * memory: { validatedInput: triggerBody },
704
- * messages: [new HumanMessage('Support request received')],
705
- * sessionId: triggerBody.userId // Resume existing session
706
- * };
707
- * });
708
- *
709
- * // TRIGGER_EVENT Event Handler - Data Transformation
710
- * agent.on('TRIGGER_EVENT', async ({ triggerName, triggerBody }) => {
711
- * if (triggerName === 'emailTrigger') {
712
- * // Transform email data into structured format
713
- * const parsedEmail = parseEmailContent(triggerBody);
714
- *
715
- * return {
716
- * memory: {
717
- * emailSubject: parsedEmail.subject,
718
- * senderEmail: parsedEmail.from
719
- * },
720
- * messages: [new HumanMessage(parsedEmail.content)],
721
- * };
722
- * }
723
- * });
724
- * ```
725
- */
726
- // Public API for registering event listeners
727
- public on<E extends keyof AgentEventRequestPayloads<z.infer<typeof this.memorySchema>>>(
728
- event: E,
729
- handler: (
730
- payload: AgentEventRequestPayloads<z.infer<typeof this.memorySchema>>[E],
731
- ) => Promise<AgentEventResponsePayloads<z.infer<typeof this.memorySchema>>[E] | void>,
732
- ): void {
733
- if (!this.eventHandlers[event]) {
734
- this.eventHandlers[event] = [];
735
- }
736
- // We can safely cast here since we ensured the array exists
737
- (this.eventHandlers[event] as Array<typeof handler>).push(handler);
738
- }
739
-
740
- // Internal method to emit events to the registered listeners
741
- private async emit<E extends keyof AgentEventRequestPayloads<z.infer<typeof this.memorySchema>>>(
742
- event: E,
743
- payload: AgentEventRequestPayloads<z.infer<typeof this.memorySchema>>[E],
744
- ): Promise<AgentEventResponsePayloads<z.infer<typeof this.memorySchema>>[E][]> {
745
- if (!this.eventHandlers[event]) {
746
- return [];
747
- }
748
- const results = await Promise.all(this.eventHandlers[event]!.map(async (handler) => handler(payload)));
749
- return results;
750
- }
751
-
752
- private initAppActionsRunnerTools() {
753
- const { runLocally } = getConfig();
754
- if (!runLocally && !mindedConnection.isConnected() && process.env.NODE_ENV !== 'test') {
755
- throw new Error('Minded connection is mandatory to use run app action tools');
756
- }
757
- return this.flows
758
- .flatMap((flow) =>
759
- flow.nodes.filter((node): node is AppToolNode => node.type === NodeType.APP_TOOL && (node as AppToolNode).appName !== 'Minded'),
760
- )
761
- .map((node) => appActionRunnerToolCreator(node.metadata.schema, node.displayName!));
762
- }
763
-
764
- private initLibraryActionsRunnerTools() {
765
- return this.flows
766
- .flatMap((flow) =>
767
- flow.nodes.filter((node): node is AppToolNode => node.type === NodeType.APP_TOOL && (node as AppToolNode).appName === 'Minded'),
768
- )
769
- .map((node) => libraryActionRunnerToolCreator(node.actionKey, node.displayName!));
770
- }
771
-
772
- // Private method to get secrets from the backend service and load them into environment variables
773
- private async loadSecrets(): Promise<Record<string, string>> {
774
- // Skip secret loading in local development
775
- const { runLocally } = getConfig();
776
- if (runLocally) {
777
- logger.debug({ msg: '[Agent] Secrets loaded from local .env file' });
778
- return {};
779
- }
780
- if (!mindedConnection.isConnected()) {
781
- throw new Error('Minded connection is not established when trying to get secrets');
782
- }
783
-
784
- // Return cached secrets if available
785
- if (this.secretsCache !== null) {
786
- return this.secretsCache;
787
- }
788
-
789
- try {
790
- // Check if mindedConnection is available
791
- if (!mindedConnection.isConnected()) {
792
- throw new Error('Platform is not available');
793
- }
794
-
795
- const response = await mindedConnection.awaitEmit<object, { secrets: Record<string, string> }>(
796
- mindedConnectionSocketMessageType.GET_SECRETS,
797
- {},
798
- );
799
-
800
- // Extract secrets from response
801
- const secrets = response.secrets || {};
802
-
803
- // Load secrets into process.env
804
- Object.entries(secrets).forEach(([key, value]) => {
805
- process.env[key] = value;
806
- });
807
- logger.debug(`[Agent] Loaded ${Object.keys(secrets).length} secrets from platform`);
808
-
809
- // Cache the secrets for future requests
810
- this.secretsCache = secrets;
811
-
812
- return secrets;
813
- } catch (error) {
814
- throw new Error(`Failed to fetch secrets: ${error instanceof Error ? error.message : 'Unknown error'}`);
815
- }
816
- }
817
-
818
- public getLangraphConfig(sessionId: string, checkpointId?: string) {
819
- return { configurable: { thread_id: sessionId, recursionLimit: 3, checkpoint_id: checkpointId } };
820
- }
821
-
822
- private setupVoice(): void {
823
- logger.info('[Voice] Setting up voice');
824
- if (!mindedConnection.isConnected()) {
825
- throw new Error('Minded connection is required');
826
- }
827
-
828
- const connection = mindedConnection;
829
- const { dashboardConnected } = getConfig();
830
-
831
- if (dashboardConnected) {
832
- // Listen for voice session start
833
- connection.on(mindedConnectionSocketMessageType.DASHBOARD_VOICE_SESSION_START, async (message) => {
834
- const sessionStart = message as BaseVoiceMessage;
835
- await this.startVoiceSession({ sessionId: sessionStart.sessionId });
836
- });
837
-
838
- // Listen for incoming audio from the platform
839
- connection.on(mindedConnectionSocketMessageType.DASHBOARD_VOICE_USER_AUDIO, (message) => {
840
- const audioMessage = message as OnVoiceAudioOut;
841
- const voiceSession = this.voiceSessions.get(audioMessage.sessionId);
842
- if (voiceSession) {
843
- voiceSession.sendAudio(audioMessage.audioData);
844
- } else {
845
- logger.trace({
846
- message: '[Voice] Audio received; voice session not found for sessionId',
847
- sessionId: audioMessage.sessionId,
848
- activeSessions: Array.from(this.voiceSessions.keys()),
849
- });
850
- }
851
- });
852
-
853
- // Hangup / end session handler
854
- connection.on(mindedConnectionSocketMessageType.DASHBOARD_VOICE_SESSION_END, (message) => {
855
- const hangup = message as BaseVoiceMessage;
856
- logger.debug({ message: '[Voice] Dashboard eneded voice session', sessionId: hangup.sessionId });
857
- const voiceSession = this.voiceSessions.get(hangup.sessionId);
858
- if (voiceSession) {
859
- voiceSession.hangup();
860
- } else {
861
- logger.trace({
862
- message: '[Voice] Session ended; voice session not found for sessionId',
863
- sessionId: hangup.sessionId,
864
- activeSessions: this.voiceSessions.keys(),
865
- });
866
- }
867
- });
868
- }
869
- }
870
-
871
- /*
872
- To be used by the Lambda wrapper to start voice sessions
873
- */
874
- public async startVoiceSession(params: { sessionId: string }): Promise<VoiceSession> {
875
- await this.waitForInitialization();
876
- const voiceTrigger = this.flows
877
- .flatMap((flow) => flow.nodes)
878
- .find((node) => node.type === NodeType.TRIGGER && node.triggerType === TriggerType.VOICE) as VoiceTriggerNode;
879
- if (!voiceTrigger) {
880
- throw new Error('Voice trigger not found in flows');
881
- }
882
- const voiceSession = new VoiceSession({
883
- agent: this,
884
- sessionId: params.sessionId,
885
- firstMessage: voiceTrigger.firstMessage,
886
- voiceId: voiceTrigger.voiceId,
887
- });
888
- await voiceSession.init();
889
- logger.debug({ message: '[Voice] Voice session initialized', sessionId: params.sessionId });
890
- this.voiceSessions.set(params.sessionId, voiceSession);
891
-
892
- // Emit voice session start event
893
- await this.emit(AgentEvents.VOICE_SESSION_START, {
894
- sessionId: params.sessionId,
895
- });
896
-
897
- return voiceSession;
898
- }
899
-
900
- /*
901
- To be used by the Lambda wrapper to trigger timers
902
- */
903
- public async timerTrigger(params: { sessionId: string; timerName: string; eventArgs: Record<string, any> }): Promise<void> {
904
- const handlers = timerHandlers.get(params.timerName) || [];
905
- for (const { handler } of handlers) {
906
- await handler({
907
- sessionId: params.sessionId,
908
- payload: params.eventArgs,
909
- });
910
- }
911
- }
912
-
913
- /*
914
- To be used by the Lambda wrapper to restore checkpoints
915
- */
916
- public async restoreCheckpoint(sessionId: string, checkpointId: string): Promise<void> {
917
- logger.info({ msg: '[Agent]Restoring checkpoint', sessionId, checkpointId });
918
- const langraphConfig = this.getLangraphConfig(sessionId, checkpointId);
919
- await this.compiledGraph.invoke(
920
- new Command({
921
- resume: {
922
- sessionId,
923
- },
924
- }),
925
- langraphConfig,
926
- );
927
- }
928
- }