@minded-ai/mindedjs 1.0.122 → 1.0.123

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 (78) hide show
  1. package/dist/agent.d.ts +4 -1
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +65 -9
  4. package/dist/agent.js.map +1 -1
  5. package/dist/cli/index.js +14 -14
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/edges/edgeFactory.js +2 -2
  8. package/dist/edges/edgeFactory.js.map +1 -1
  9. package/dist/interrupts/BaseInterruptSessionManager.d.ts +52 -0
  10. package/dist/interrupts/BaseInterruptSessionManager.d.ts.map +1 -0
  11. package/dist/interrupts/BaseInterruptSessionManager.js +40 -0
  12. package/dist/interrupts/BaseInterruptSessionManager.js.map +1 -0
  13. package/dist/interrupts/MemoryInterruptSessionManager.d.ts +14 -0
  14. package/dist/interrupts/MemoryInterruptSessionManager.d.ts.map +1 -0
  15. package/dist/interrupts/MemoryInterruptSessionManager.js +60 -0
  16. package/dist/interrupts/MemoryInterruptSessionManager.js.map +1 -0
  17. package/dist/interrupts/MindedInterruptSessionManager.d.ts +13 -0
  18. package/dist/interrupts/MindedInterruptSessionManager.d.ts.map +1 -0
  19. package/dist/interrupts/MindedInterruptSessionManager.js +151 -0
  20. package/dist/interrupts/MindedInterruptSessionManager.js.map +1 -0
  21. package/dist/interrupts/interruptSessionManagerFactory.d.ts +3 -0
  22. package/dist/interrupts/interruptSessionManagerFactory.d.ts.map +1 -0
  23. package/dist/interrupts/interruptSessionManagerFactory.js +46 -0
  24. package/dist/interrupts/interruptSessionManagerFactory.js.map +1 -0
  25. package/dist/nodes/addBrowserTaskNode.js +2 -0
  26. package/dist/nodes/addBrowserTaskNode.js.map +1 -1
  27. package/dist/nodes/addHumanInTheLoopNode.d.ts.map +1 -1
  28. package/dist/nodes/addHumanInTheLoopNode.js +2 -1
  29. package/dist/nodes/addHumanInTheLoopNode.js.map +1 -1
  30. package/dist/nodes/addJumpToNode.js +1 -1
  31. package/dist/nodes/addJumpToNode.js.map +1 -1
  32. package/dist/nodes/addPromptNode.d.ts.map +1 -1
  33. package/dist/nodes/addPromptNode.js +43 -1
  34. package/dist/nodes/addPromptNode.js.map +1 -1
  35. package/dist/nodes/addToolNode.d.ts.map +1 -1
  36. package/dist/nodes/addToolNode.js +2 -0
  37. package/dist/nodes/addToolNode.js.map +1 -1
  38. package/dist/nodes/addToolRunNode.d.ts.map +1 -1
  39. package/dist/nodes/addToolRunNode.js +1 -0
  40. package/dist/nodes/addToolRunNode.js.map +1 -1
  41. package/dist/platform/mindedConnection.js +12 -12
  42. package/dist/platform/mindedConnection.js.map +1 -1
  43. package/dist/platform/mindedConnectionTypes.d.ts +151 -1
  44. package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
  45. package/dist/platform/mindedConnectionTypes.js +9 -0
  46. package/dist/platform/mindedConnectionTypes.js.map +1 -1
  47. package/dist/playbooks/playbooks.js +5 -5
  48. package/dist/playbooks/playbooks.js.map +1 -1
  49. package/dist/types/Agent.types.d.ts +2 -0
  50. package/dist/types/Agent.types.d.ts.map +1 -1
  51. package/dist/types/Agent.types.js.map +1 -1
  52. package/dist/types/LangGraph.types.d.ts +2 -2
  53. package/dist/types/LangGraph.types.d.ts.map +1 -1
  54. package/dist/types/LangGraph.types.js +3 -1
  55. package/dist/types/LangGraph.types.js.map +1 -1
  56. package/dist/voice/voiceSession.d.ts.map +1 -1
  57. package/dist/voice/voiceSession.js +9 -1
  58. package/dist/voice/voiceSession.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/agent.ts +89 -19
  61. package/src/cli/index.ts +14 -14
  62. package/src/edges/edgeFactory.ts +2 -2
  63. package/src/interrupts/BaseInterruptSessionManager.ts +88 -0
  64. package/src/interrupts/MemoryInterruptSessionManager.ts +63 -0
  65. package/src/interrupts/MindedInterruptSessionManager.ts +162 -0
  66. package/src/interrupts/interruptSessionManagerFactory.ts +20 -0
  67. package/src/nodes/addBrowserTaskNode.ts +2 -2
  68. package/src/nodes/addHumanInTheLoopNode.ts +2 -1
  69. package/src/nodes/addJumpToNode.ts +1 -1
  70. package/src/nodes/addPromptNode.ts +47 -4
  71. package/src/nodes/addToolNode.ts +2 -0
  72. package/src/nodes/addToolRunNode.ts +1 -1
  73. package/src/platform/mindedConnection.ts +12 -12
  74. package/src/platform/mindedConnectionTypes.ts +187 -0
  75. package/src/playbooks/playbooks.ts +5 -5
  76. package/src/types/Agent.types.ts +2 -0
  77. package/src/types/LangGraph.types.ts +3 -1
  78. package/src/voice/voiceSession.ts +9 -1
@@ -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('input from human in the loop');
20
+ const value = interrupt({ type: InterruptType.HUMAN_IN_THE_LOOP });
20
21
  return value;
21
22
  }
22
23
  };
@@ -7,7 +7,7 @@ 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
13
  goto: node.targetNodeId,
@@ -15,7 +15,7 @@ import { logger } from '../utils/logger';
15
15
  import { combinePlaybooks } from '../playbooks/playbooks';
16
16
  import { createHistoryStep } from '../utils/history';
17
17
  import { compilePrompt } from './compilePrompt';
18
-
18
+ import { v4 as uuidv4 } from 'uuid';
19
19
  type AddPromptNodeParams = {
20
20
  graph: PreCompiledGraph;
21
21
  node: PromptNode;
@@ -27,7 +27,8 @@ type AddPromptNodeParams = {
27
27
 
28
28
  export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: AddPromptNodeParams) => {
29
29
  const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
30
- logger.debug({ msg: `[Node] Executing prompt node`, node: node.displayName });
30
+ await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
31
+ logger.info({ msg: `[Node] Executing prompt node`, node: node.displayName });
31
32
  const llmToUse = node.llmConfig ? createLlmInstance(node.llmConfig) : llm;
32
33
 
33
34
  const globalTools = tools
@@ -51,6 +52,7 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
51
52
 
52
53
  const startTime = Date.now();
53
54
  const result: AIMessage = await llmToUse.bindTools(globalTools).invoke([new SystemMessage(compiledPrompt), ...state.messages]);
55
+ await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
54
56
  const endTime = Date.now();
55
57
  logger.debug({ msg: '[Model] Model execution time', executionTimeMs: endTime - startTime });
56
58
  // Check if the result contains tool calls
@@ -69,6 +71,29 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
69
71
  const toolResult = await matchedTool.invoke(toolCall);
70
72
  const endTime = Date.now();
71
73
  logger.debug({ msg: `[Tool] Tool result`, tool: matchedTool?.name, result: toolResult, executionTimeMs: endTime - startTime });
74
+ //check for queue after tool call
75
+ const systemMessageId = uuidv4();
76
+
77
+ await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId, {
78
+ messages: [
79
+ result,
80
+ toolResult,
81
+ new SystemMessage({
82
+ id: systemMessageId,
83
+ content:
84
+ 'you called tool when the user send a new message, Consider calling the function again after user message is processed',
85
+ }),
86
+ ],
87
+ history: [
88
+ createHistoryStep<HistoryStep>(state.history, {
89
+ type: NodeType.TOOL,
90
+ nodeId: node.name,
91
+ nodeDisplayName: node.displayName,
92
+ raw: toolResult,
93
+ messageIds: [toolResult.id!, systemMessageId],
94
+ }),
95
+ ],
96
+ });
72
97
  const toolStateUpdate = extractToolStateResponse(toolResult);
73
98
  // Properly merge memory and other state updates
74
99
  stateUpdates = {
@@ -77,7 +102,8 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
77
102
  memory: { ...(stateUpdates as any).memory, ...(toolStateUpdate as any).memory },
78
103
  };
79
104
  toolResults.push(toolResult);
80
- } catch (error) {
105
+ } catch (error: any) {
106
+ if (error?.name === 'GraphInterrupt') throw error;
81
107
  logger.error({ msg: `[Tool] Error executing tool`, tool: toolCall.name, error });
82
108
  const errorMessage = new ToolMessage({
83
109
  content: JSON.stringify({ error: error instanceof Error ? error.message : String(error) }),
@@ -94,6 +120,24 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
94
120
  return {
95
121
  ...stateUpdates,
96
122
  messages: [result, ...toolResults],
123
+ history: [
124
+ createHistoryStep<HistoryStep>(state.history, {
125
+ type: NodeType.TOOL,
126
+ nodeId: node.name,
127
+ nodeDisplayName: node.displayName,
128
+ raw: result,
129
+ messageIds: [result.id!],
130
+ }),
131
+ ...toolResults.map((toolResult) =>
132
+ createHistoryStep<HistoryStep>(state.history, {
133
+ type: NodeType.TOOL,
134
+ nodeId: node.name,
135
+ nodeDisplayName: node.displayName,
136
+ raw: toolResult,
137
+ messageIds: [toolResult.id!],
138
+ }),
139
+ ),
140
+ ],
97
141
  };
98
142
  }
99
143
 
@@ -104,7 +148,6 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
104
148
  });
105
149
  logger.info({ msg: `[Model] Response`, content: result.content });
106
150
  }
107
-
108
151
  return {
109
152
  goto: null,
110
153
  history: createHistoryStep<HistoryStep>(state.history, {
@@ -31,6 +31,7 @@ export const addToolNode = async ({
31
31
  throw new Error(`Tool not found: ${toolNode.toolName} in node ${node.name}`);
32
32
  }
33
33
  const callback: RunnableLike = async (state: typeof stateAnnotation.State) => {
34
+ await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
34
35
  logger.debug({ msg: `[Node] Executing tool node`, node: toolNode.displayName });
35
36
 
36
37
  const tool = langchainTool(() => {}, {
@@ -52,6 +53,7 @@ export const addToolNode = async ({
52
53
  .invoke([...state.messages, new SystemMessage(systemPrompt)]);
53
54
  const endTime = Date.now();
54
55
  logger.debug({ msg: '[Tool] Model execution time', tool: matchedTool.name, executionTimeMs: endTime - startTime });
56
+ await agent.interruptSessionManager.checkQueueAndInterrupt(state.sessionId);
55
57
  return {
56
58
  goto: null,
57
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);
@@ -57,7 +58,6 @@ export const addToolRunNode = async ({ graph, tools, toolNode, attachedToNodeNam
57
58
 
58
59
  // Push the toolCallMessage into the messages array from toolStateUpdate
59
60
  const updatedMessages = [toolCallMessage, ...((toolStateUpdate as any).messages || [])];
60
-
61
61
  // Return the full state update from the tool with the updated messages
62
62
 
63
63
  return {
@@ -100,33 +100,33 @@ const connect = async (token: string): Promise<void> => {
100
100
 
101
101
  const checkReady = () => {
102
102
  if (connected && ready) {
103
- logger.info('\x1b[32mConnection with Minded platform is ready!\x1b[0m');
104
- logger.info('\x1b[32mPress Ctrl+C to exit...');
103
+ logger.info({ msg: '\x1b[32mConnection with Minded platform is ready!\x1b[0m' });
104
+ logger.info({ msg: '\x1b[32mPress Ctrl+C to exit...' });
105
105
  resolve();
106
106
  }
107
107
  };
108
108
 
109
109
  // Connection event handlers
110
110
  socket.on('connect', () => {
111
- logger.info('Socket connected, waiting for server setup...');
111
+ logger.info({ msg: 'Socket connected, waiting for server setup...' });
112
112
  connected = true;
113
113
  checkReady();
114
114
  });
115
115
 
116
116
  // Listen for ready event from server
117
117
  socket.on('sdk-socket-ready', (data: { agentId: string; orgName: string }) => {
118
- logger.info('Server ready signal received', data);
118
+ logger.info({ msg: 'Server ready signal received', data });
119
119
  ready = true;
120
120
  checkReady();
121
121
  });
122
122
 
123
123
  socket.on('connect_error', () => {
124
- logger.error('Failed to connect to minded platform');
124
+ logger.error({ msg: 'Failed to connect to minded platform' });
125
125
  reject(new Error('Failed to connect to minded platform'));
126
126
  });
127
127
 
128
128
  socket.on('disconnect', () => {
129
- logger.info('Disconnected from local debugging socket');
129
+ logger.info({ msg: 'Disconnected from local debugging socket' });
130
130
  connected = false;
131
131
  ready = false;
132
132
  });
@@ -136,7 +136,7 @@ const connect = async (token: string): Promise<void> => {
136
136
  logger.error({ msg: 'Server error:', error });
137
137
 
138
138
  if (error.message.includes('Invalid token')) {
139
- logger.info('Invalid token');
139
+ logger.info({ msg: 'Invalid token' });
140
140
 
141
141
  // Disconnect current socket
142
142
  if (socket?.connected) {
@@ -158,14 +158,14 @@ const connect = async (token: string): Promise<void> => {
158
158
  }
159
159
  });
160
160
  } else {
161
- console.warn({ message: 'No listeners found for event', event });
161
+ console.warn({ msg: 'No listeners found for event', event });
162
162
  }
163
163
  });
164
164
 
165
165
  // Handle process termination
166
166
  process.on('SIGINT', () => {
167
167
  if (socket?.connected) {
168
- logger.info('\nDisconnecting...');
168
+ logger.info({ msg: '\nDisconnecting...' });
169
169
  socket.disconnect();
170
170
  }
171
171
  process.exit(0);
@@ -183,17 +183,17 @@ export const start = async (): Promise<void> => {
183
183
 
184
184
  export const disconnect = () => {
185
185
  if (!socket) {
186
- logger.warn('No socket connection to disconnect');
186
+ logger.warn({ msg: 'No socket connection to disconnect' });
187
187
  return;
188
188
  }
189
189
 
190
190
  if (socket.connected) {
191
- logger.info('Disconnecting from Minded platform...');
191
+ logger.info({ msg: 'Disconnecting from Minded platform...' });
192
192
  socket.disconnect();
193
193
  return;
194
194
  }
195
195
 
196
- logger.warn('Socket is already disconnected');
196
+ logger.warn({ msg: 'Socket is already disconnected' });
197
197
  };
198
198
 
199
199
  export const mindedConnection = {
@@ -42,6 +42,15 @@ export enum mindedConnectionSocketMessageType {
42
42
  SDK_VERSION_MISMATCH = 'sdk-version-mismatch', // Browser Task
43
43
  CREATE_BROWSER_SESSION = 'create-browser-session',
44
44
  INVOKE_BROWSER_TASK = 'invoke-browser-task',
45
+ // Interrupt Session Management
46
+ INTERRUPT_SESSION_IS_PROCESSED = 'interrupt-session-is-processed',
47
+ INTERRUPT_SESSION_LOCK = 'interrupt-session-lock',
48
+ INTERRUPT_SESSION_RELEASE = 'interrupt-session-release',
49
+ INTERRUPT_SESSION_ENQUEUE = 'interrupt-session-enqueue',
50
+ INTERRUPT_SESSION_DEQUEUE_ALL = 'interrupt-session-dequeue-all',
51
+ INTERRUPT_SESSION_DEQUEUE = 'interrupt-session-dequeue',
52
+ INTERRUPT_SESSION_HAS_MESSAGES = 'interrupt-session-has-messages',
53
+ INTERRUPT_SESSION_GET_MESSAGES = 'interrupt-session-get-messages',
45
54
  }
46
55
 
47
56
  export type mindedConnectionSocketMessageTypeMap = {
@@ -73,6 +82,15 @@ export type mindedConnectionSocketMessageTypeMap = {
73
82
  [mindedConnectionSocketMessageType.UPDATE_STATE]: UpdateStateRequest;
74
83
  [mindedConnectionSocketMessageType.CREATE_BROWSER_SESSION]: CreateBrowserSessionRequest;
75
84
  [mindedConnectionSocketMessageType.INVOKE_BROWSER_TASK]: InvokeBrowserTaskRequest;
85
+ // Interrupt Session Management
86
+ [mindedConnectionSocketMessageType.INTERRUPT_SESSION_IS_PROCESSED]: InterruptSessionIsProcessedRequest;
87
+ [mindedConnectionSocketMessageType.INTERRUPT_SESSION_LOCK]: InterruptSessionLockRequest;
88
+ [mindedConnectionSocketMessageType.INTERRUPT_SESSION_RELEASE]: InterruptSessionReleaseRequest;
89
+ [mindedConnectionSocketMessageType.INTERRUPT_SESSION_ENQUEUE]: InterruptSessionEnqueueRequest;
90
+ [mindedConnectionSocketMessageType.INTERRUPT_SESSION_DEQUEUE_ALL]: InterruptSessionDequeueAllRequest;
91
+ [mindedConnectionSocketMessageType.INTERRUPT_SESSION_DEQUEUE]: InterruptSessionDequeueRequest;
92
+ [mindedConnectionSocketMessageType.INTERRUPT_SESSION_HAS_MESSAGES]: InterruptSessionHasMessagesRequest;
93
+ [mindedConnectionSocketMessageType.INTERRUPT_SESSION_GET_MESSAGES]: InterruptSessionGetMessagesRequest;
76
94
  };
77
95
 
78
96
  export interface BasemindedConnectionSocketMessage {
@@ -206,6 +224,175 @@ export interface TimerTriggerRequest extends BasemindedConnectionSocketMessage {
206
224
  eventArgs: Record<string, any>;
207
225
  }
208
226
 
227
+ // Interrupt Session Management Interfaces
228
+ export interface InterruptSessionIsProcessedRequest extends BasemindedConnectionSocketMessage {
229
+ sessionId: string;
230
+ }
231
+
232
+ export interface InterruptSessionIsProcessedResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
233
+ isProcessed?: boolean;
234
+ }
235
+
236
+ export interface InterruptSessionLockRequest extends BasemindedConnectionSocketMessage {
237
+ sessionId: string;
238
+ }
239
+
240
+ export interface InterruptSessionLockResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
241
+ lockAcquired?: boolean;
242
+ }
243
+
244
+ export interface InterruptSessionReleaseRequest extends BasemindedConnectionSocketMessage {
245
+ sessionId: string;
246
+ }
247
+
248
+ export interface InterruptSessionReleaseResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
249
+ success?: boolean;
250
+ }
251
+
252
+ export interface InterruptSessionEnqueueRequest extends BasemindedConnectionSocketMessage {
253
+ sessionId: string;
254
+ message: {
255
+ triggerBody: any;
256
+ triggerName: string;
257
+ appName?: string;
258
+ };
259
+ }
260
+
261
+ export interface InterruptSessionEnqueueResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
262
+ success?: boolean;
263
+ }
264
+
265
+ export interface InterruptSessionDequeueAllRequest extends BasemindedConnectionSocketMessage {
266
+ sessionId: string;
267
+ }
268
+
269
+ export interface InterruptSessionDequeueAllResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
270
+ messages?: Array<{
271
+ triggerBody: any;
272
+ triggerName: string;
273
+ appName?: string;
274
+ }>;
275
+ }
276
+
277
+ export interface InterruptSessionDequeueRequest extends BasemindedConnectionSocketMessage {
278
+ sessionId: string;
279
+ }
280
+
281
+ export interface InterruptSessionDequeueResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
282
+ message?: {
283
+ triggerBody: any;
284
+ triggerName: string;
285
+ appName?: string;
286
+ } | null;
287
+ }
288
+
289
+ export interface InterruptSessionHasMessagesRequest extends BasemindedConnectionSocketMessage {
290
+ sessionId: string;
291
+ }
292
+
293
+ export interface InterruptSessionHasMessagesResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
294
+ hasMessages?: boolean;
295
+ }
296
+
297
+ export interface InterruptSessionGetMessagesRequest extends BasemindedConnectionSocketMessage {
298
+ sessionId: string;
299
+ }
300
+
301
+ export interface InterruptSessionGetMessagesResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
302
+ messages?: Array<{
303
+ triggerBody: any;
304
+ triggerName: string;
305
+ appName?: string;
306
+ }>;
307
+ }
308
+
309
+ // Interrupt Session Management Interfaces
310
+ export interface InterruptSessionIsProcessedRequest extends BasemindedConnectionSocketMessage {
311
+ sessionId: string;
312
+ }
313
+
314
+ export interface InterruptSessionIsProcessedResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
315
+ isProcessed?: boolean;
316
+ }
317
+
318
+ export interface InterruptSessionLockRequest extends BasemindedConnectionSocketMessage {
319
+ sessionId: string;
320
+ }
321
+
322
+ export interface InterruptSessionReleaseRequest extends BasemindedConnectionSocketMessage {
323
+ sessionId: string;
324
+ }
325
+
326
+ export interface InterruptSessionReleaseResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
327
+ success?: boolean;
328
+ }
329
+
330
+ export interface InterruptSessionEnqueueRequest extends BasemindedConnectionSocketMessage {
331
+ sessionId: string;
332
+ message: {
333
+ triggerBody: any;
334
+ triggerName: string;
335
+ appName?: string;
336
+ };
337
+ }
338
+
339
+ export interface InterruptSessionEnqueueResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
340
+ success?: boolean;
341
+ }
342
+
343
+ export interface InterruptSessionDequeueAllRequest extends BasemindedConnectionSocketMessage {
344
+ sessionId: string;
345
+ }
346
+
347
+ export interface InterruptSessionDequeueAllResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
348
+ messages?: Array<{
349
+ triggerBody: any;
350
+ triggerName: string;
351
+ appName?: string;
352
+ }>;
353
+ }
354
+
355
+ export interface InterruptSessionDequeueRequest extends BasemindedConnectionSocketMessage {
356
+ sessionId: string;
357
+ }
358
+
359
+ export interface InterruptSessionDequeueResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
360
+ message?: {
361
+ triggerBody: any;
362
+ triggerName: string;
363
+ appName?: string;
364
+ } | null;
365
+ }
366
+
367
+ export interface InterruptSessionHasMessagesRequest extends BasemindedConnectionSocketMessage {
368
+ sessionId: string;
369
+ }
370
+
371
+ export interface InterruptSessionHasMessagesResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
372
+ hasMessages?: boolean;
373
+ }
374
+
375
+ export interface InterruptSessionGetMessagesRequest extends BasemindedConnectionSocketMessage {
376
+ sessionId: string;
377
+ }
378
+
379
+ export interface InterruptSessionGetMessagesResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
380
+ messages?: Array<{
381
+ triggerBody: any;
382
+ triggerName: string;
383
+ appName?: string;
384
+ }>;
385
+ }
386
+
387
+ export interface RestoreCheckpointRequest extends BasemindedConnectionSocketMessage {
388
+ sessionId: string;
389
+ checkpointId: string;
390
+ }
391
+
392
+ export interface RestoreCheckpointResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
393
+ success?: boolean;
394
+ }
395
+
209
396
  export interface RestoreCheckpointRequest extends BasemindedConnectionSocketMessage {
210
397
  sessionId: string;
211
398
  checkpointId: string;
@@ -93,7 +93,7 @@ function editorJsToMarkdown(blocks: OutputBlockData[]): string {
93
93
  }
94
94
  }
95
95
  } catch (error) {
96
- logger.error({ message: 'Error converting EditorJS blocks to markdown', error, block });
96
+ logger.error({ msg: 'Error converting EditorJS blocks to markdown', error, block });
97
97
  throw error;
98
98
  }
99
99
  })
@@ -135,7 +135,7 @@ function loadPlaybooksFromDirectories(directories: string[]): Playbook[] {
135
135
 
136
136
  for (const directory of directories) {
137
137
  if (!fs.existsSync(directory)) {
138
- logger.info(`Playbooks directory does not exist: ${directory}`);
138
+ logger.info({ msg: `Playbooks directory does not exist: ${directory}` });
139
139
  continue;
140
140
  }
141
141
 
@@ -148,12 +148,12 @@ function loadPlaybooksFromDirectories(directories: string[]): Playbook[] {
148
148
 
149
149
  if (playbook && playbook.name && playbook.blocks) {
150
150
  playbooks.push(playbook);
151
- logger.info(`Loaded playbook: ${playbook.name} from ${file}`);
151
+ logger.info({ msg: `Loaded playbook: ${playbook.name} from ${file}` });
152
152
  } else {
153
- logger.warn(`Invalid playbook structure in ${file}`);
153
+ logger.warn({ msg: `Invalid playbook structure in ${file}` });
154
154
  }
155
155
  } catch (error) {
156
- logger.error(`Failed to load playbook file ${file}: ${error}`);
156
+ logger.error({ msg: `Failed to load playbook file ${file}: ${error}` });
157
157
  }
158
158
  }
159
159
  }
@@ -29,6 +29,8 @@ export interface AgentInvokeParams {
29
29
  sessionId?: string;
30
30
  /** Optional name of the application triggering the agent in case of an app trigger */
31
31
  appName?: string;
32
+ /** Internal flag to bypass session processing check for recursive calls */
33
+ bypassSessionCheck?: boolean;
32
34
  }
33
35
  export interface HistoryStep {
34
36
  type: NodeType;
@@ -30,7 +30,9 @@ export const createStateAnnotation = <Memory = any>() =>
30
30
  default: () => [],
31
31
  reducer: (a, b) => a.concat(b),
32
32
  }),
33
- sessionId: Annotation<string>(),
33
+ sessionId: Annotation<string>({
34
+ reducer: (a, b) => b || a,
35
+ }),
34
36
  goto: Annotation<string | null | undefined>({
35
37
  default: () => null,
36
38
  reducer: (a, b) => b,
@@ -8,6 +8,7 @@ import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
8
8
  import { v4 as uuidv4 } from 'uuid';
9
9
  import { logger } from '../utils/logger';
10
10
  import { SessionType } from '../types/Agent.types';
11
+ import { QUEUE_INTERRUPT_DETECTED_BEFORE_SPEECH } from '../interrupts/BaseInterruptSessionManager';
11
12
 
12
13
  /**
13
14
  * Voice Conversation class for managing individual ElevenLabs voice conversations
@@ -157,6 +158,12 @@ export class VoiceSession {
157
158
  break;
158
159
  case 'interruption':
159
160
  logger.debug({ msg: '[Voice] Received interruption' });
161
+ if (await this.agent.interruptSessionManager.isProcessed(this.sessionId)) {
162
+ await this.agent.interruptSessionManager.enqueueMessage(this.sessionId, {
163
+ triggerBody: {},
164
+ triggerName: QUEUE_INTERRUPT_DETECTED_BEFORE_SPEECH,
165
+ });
166
+ }
160
167
  this.onInterruptionCallback?.();
161
168
  // Send interruption event to dashboard if connected
162
169
  if (getConfig().dashboardConnected) {
@@ -225,9 +232,10 @@ export class VoiceSession {
225
232
  }
226
233
 
227
234
  private async updateAgentResponse(originalAgentResponse: string, correctedAgentResponse: string): Promise<void> {
235
+ const cleanedOriginalAgentResponse = originalAgentResponse.replace('... ', '');
228
236
  const graphState = await this.agent.compiledGraph.getState(this.agent.getLangraphConfig(this.sessionId));
229
237
  const agentMessage: AIMessage | null = graphState.values.messages.find(
230
- (message: BaseMessage) => message.content === originalAgentResponse && message instanceof AIMessage,
238
+ (message: BaseMessage) => message.content === cleanedOriginalAgentResponse && message instanceof AIMessage,
231
239
  );
232
240
  if (agentMessage) {
233
241
  agentMessage.content = correctedAgentResponse;