@minded-ai/mindedjs 2.0.0 → 2.0.1-beta-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/agent.js +2 -2
  2. package/dist/agent.js.map +1 -1
  3. package/dist/browserTask/README.md +419 -0
  4. package/dist/browserTask/browserAgent.py +632 -0
  5. package/dist/browserTask/captcha_isolated.png +0 -0
  6. package/dist/browserTask/executeBrowserTask.ts +79 -0
  7. package/dist/browserTask/requirements.txt +8 -0
  8. package/dist/browserTask/setup.sh +144 -0
  9. package/dist/internalTools/retell.d.ts +12 -0
  10. package/dist/internalTools/retell.d.ts.map +1 -0
  11. package/dist/internalTools/retell.js +54 -0
  12. package/dist/internalTools/retell.js.map +1 -0
  13. package/dist/internalTools/sendPlaceholderMessage.d.ts +14 -0
  14. package/dist/internalTools/sendPlaceholderMessage.d.ts.map +1 -0
  15. package/dist/internalTools/sendPlaceholderMessage.js +61 -0
  16. package/dist/internalTools/sendPlaceholderMessage.js.map +1 -0
  17. package/dist/interrupts/BaseInterruptSessionManager.d.ts +1 -1
  18. package/dist/interrupts/BaseInterruptSessionManager.d.ts.map +1 -1
  19. package/dist/nodes/addPromptNode.d.ts.map +1 -1
  20. package/dist/nodes/addPromptNode.js +251 -94
  21. package/dist/nodes/addPromptNode.js.map +1 -1
  22. package/dist/types/Tools.types.d.ts +1 -0
  23. package/dist/types/Tools.types.d.ts.map +1 -1
  24. package/dist/utils/extractStateMemoryResponse.d.ts +5 -0
  25. package/dist/utils/extractStateMemoryResponse.d.ts.map +1 -0
  26. package/dist/utils/extractStateMemoryResponse.js +91 -0
  27. package/dist/utils/extractStateMemoryResponse.js.map +1 -0
  28. package/docs/low-code-editor/tools.md +37 -43
  29. package/docs/sdk/events.md +40 -38
  30. package/docs/sdk/memory.md +27 -24
  31. package/package.json +1 -1
  32. package/src/agent.ts +2 -2
  33. package/src/interrupts/BaseInterruptSessionManager.ts +1 -1
  34. package/src/nodes/addPromptNode.ts +284 -95
  35. package/src/types/Tools.types.ts +1 -0
@@ -12,18 +12,18 @@ interface Tool<Input extends z.ZodSchema, Memory> {
12
12
  description: string; // What the tool does (used by LLM)
13
13
  input: Input; // Zod schema for input validation
14
14
  isGlobal?: boolean; // Optional: available across all LLM calls
15
- execute: ({ input, state, agent }) => Promise<{ state?; result? }>;
15
+ execute: ({ input, state, agent }) => Promise<{ result? }>;
16
16
  }
17
17
  ```
18
18
 
19
19
  ## Execute Function Signature
20
20
 
21
- The `execute` function is the core of every tool. It receives validated input from the LLM, current state (including memory), and the agent instance, then returns updated state and/or result.
21
+ The `execute` function is the core of every tool. It receives validated input from the LLM, current state (including memory), and the agent instance, then modifies state by reference and returns an optional result.
22
22
 
23
23
  ### Parameters
24
24
 
25
25
  ```ts
26
- execute: ({ input, state, agent }) => Promise<{ state?; result? }>;
26
+ execute: ({ input, state, agent }) => Promise<{ result? }>;
27
27
  ```
28
28
 
29
29
  - **`input`**: Validated data matching your Zod schema - contains the parameters the LLM extracted from the conversation
@@ -34,9 +34,10 @@ execute: ({ input, state, agent }) => Promise<{ state?; result? }>;
34
34
 
35
35
  The execute function returns a Promise with an object containing:
36
36
 
37
- - **`state?`** (optional): Updated state object that will be merged with existing state. This is a partial object - you only need to return the parts that changed
38
37
  - **`result?`** (optional): Result that gets sent back to the LLM as the tool's response
39
38
 
39
+ **Important v2.0 Change**: State is now updated by reference directly within the execute function. You no longer return state updates - instead, modify the state object directly.
40
+
40
41
  ## State Object Structure
41
42
 
42
43
  The `state` object contains:
@@ -72,7 +73,7 @@ const refundOrderTool: Tool<typeof schema, Memory> = {
72
73
  // Access current memory
73
74
  const currentMemory = state.memory;
74
75
 
75
- // Use the provided logger
76
+ // Use the provided logger [[memory:4133901]]
76
77
  logger.info('Processing refund', {
77
78
  sessionId: state.sessionId,
78
79
  orderId: input.orderId,
@@ -81,15 +82,13 @@ const refundOrderTool: Tool<typeof schema, Memory> = {
81
82
  // Your business logic here
82
83
  const refundAmount = await processRefundInSystem(input.orderId);
83
84
 
84
- // Return partial state update - only the parts that changed
85
+ // Update state directly by reference (v2.0 change)
86
+ state.memory.orderId = input.orderId;
87
+ state.memory.customerName = input.customerName;
88
+ state.memory.issue = `Refund processed: $${refundAmount}`;
89
+
90
+ // Only return result, no state
85
91
  return {
86
- state: {
87
- memory: {
88
- orderId: input.orderId,
89
- customerName: input.customerName,
90
- issue: `Refund processed: $${refundAmount}`,
91
- },
92
- },
93
92
  result: `Refund processed successfully for order ${input.orderId}`,
94
93
  };
95
94
  },
@@ -168,13 +167,16 @@ const auditLogTool: Tool<typeof auditSchema, Memory> = {
168
167
  details: input.details,
169
168
  timestamp: new Date(),
170
169
  });
170
+
171
+ // No return value needed for tools that don't produce results
172
+ return {};
171
173
  },
172
174
  };
173
175
  ```
174
176
 
175
177
  ## State Management
176
178
 
177
- Tools can read and update state including memory:
179
+ Tools can read and update state including memory by reference:
178
180
 
179
181
  ```ts
180
182
  const updateProfileTool: Tool<typeof profileSchema, Memory> = {
@@ -193,14 +195,11 @@ const updateProfileTool: Tool<typeof profileSchema, Memory> = {
193
195
  [input.field]: input.value,
194
196
  });
195
197
 
196
- // Return partial state update
197
- return {
198
- state: {
199
- memory: {
200
- [`${input.field}Updated`]: true,
201
- },
202
- },
203
- };
198
+ // Update state directly by reference (v2.0 change)
199
+ state.memory[`${input.field}Updated`] = true;
200
+
201
+ // No state in return value
202
+ return {};
204
203
  },
205
204
  };
206
205
  ```
@@ -225,11 +224,11 @@ const paymentTool: Tool<typeof paymentSchema, Memory> = {
225
224
  customerId: state.memory.customerId,
226
225
  });
227
226
 
227
+ // Update state directly by reference
228
+ state.memory.lastPaymentId = result.transactionId;
229
+
228
230
  return {
229
231
  result: `Payment successful: ${result.transactionId}`,
230
- state: {
231
- memory: { lastPaymentId: result.transactionId },
232
- },
233
232
  };
234
233
  } catch (err) {
235
234
  logger.error({
@@ -238,11 +237,11 @@ const paymentTool: Tool<typeof paymentSchema, Memory> = {
238
237
  err,
239
238
  });
240
239
 
240
+ // Update state directly by reference
241
+ state.memory.paymentError = err.message;
242
+
241
243
  return {
242
244
  result: 'Payment failed. Please try again or contact support.',
243
- state: {
244
- memory: { paymentError: err.message },
245
- },
246
245
  };
247
246
  }
248
247
  },
@@ -250,7 +249,7 @@ const paymentTool: Tool<typeof paymentSchema, Memory> = {
250
249
 
251
250
  ## Flow Control with goto
252
251
 
253
- Tools can control the flow by returning a `goto` property in their state update. This allows tools to programmatically jump to a specific node by setting `state.goto` to the target node ID. This is useful for dynamic flow control based on runtime conditions.
252
+ Tools can control the flow by setting the `goto` property directly on the state object. This allows tools to programmatically jump to a specific node by setting `state.goto` to the target node ID. This is useful for dynamic flow control based on runtime conditions.
254
253
 
255
254
  ### Basic goto Usage
256
255
 
@@ -268,14 +267,11 @@ const moveToAnotherRepresentativeTool: Tool<typeof schema, Memory> = {
268
267
  priority: input.priority,
269
268
  });
270
269
 
271
- return {
272
- state: {
273
- goto: 'share-new-representative',
274
- memory: {
275
- orderId: 'share-new-representative',
276
- },
277
- },
278
- };
270
+ // Update state directly by reference (v2.0 change)
271
+ state.goto = 'share-new-representative';
272
+ state.memory.orderId = 'share-new-representative';
273
+
274
+ return {};
279
275
  },
280
276
  };
281
277
  ```
@@ -290,13 +286,11 @@ const routingTool: Tool<typeof routingSchema, Memory> = {
290
286
  execute: async ({ input, state }) => {
291
287
  // Perform logic to determine routing
292
288
  if (input.condition === 'urgent') {
293
- // Jump to urgent handler node
289
+ // Jump to urgent handler node by updating state directly
290
+ state.goto = 'urgent-handler-node';
291
+
294
292
  return {
295
293
  result: 'Routing to urgent handler',
296
- state: {
297
- ...state,
298
- goto: 'urgent-handler-node',
299
- },
300
294
  };
301
295
  }
302
296
 
@@ -312,7 +306,7 @@ const routingTool: Tool<typeof routingSchema, Memory> = {
312
306
 
313
307
  1. **Clear Descriptions**: Write descriptions that help the LLM understand when to use the tool
314
308
  2. **Input Validation**: Use Zod schemas to validate all inputs
315
- 3. **State Updates**: Return partial state updates - only include the parts that changed
309
+ 3. **State Updates**: Update state directly by reference - modify only the parts that need to change
316
310
  4. **Error Handling**: Always handle errors gracefully and provide meaningful messages
317
311
  5. **Async Operations**: Use async/await for external API calls and database operations
318
312
  6. **Logging**: Use the provided logger for consistent, structured logging with session context
@@ -194,22 +194,18 @@ The `TRIGGER_EVENT` event is emitted when a trigger node is executed. This event
194
194
 
195
195
  ### Handler Return Values
196
196
 
197
- TRIGGER_EVENT handlers **must** return an object that contains, at minimum, an `isQualified: boolean` field. Depending on your needs you may also return `messages`, `memory`, or a `sessionId`.
197
+ TRIGGER_EVENT handlers **must** return an object that contains, at minimum, an `isQualified: boolean` field.
198
+
199
+ **Important v2.0 Change**: Event handlers now update state by reference instead of returning state updates. The handler receives the current state (if it exists) and can modify it directly.
198
200
 
199
201
  The three common patterns are:
200
202
 
201
- #### 1. Provide Initial State & Qualify
203
+ #### 1. Qualify & Modify State
202
204
 
203
205
  ```typescript
204
206
  {
205
207
  isQualified: true, // ✅ The trigger should be processed
206
- messages?: BaseMessage[], // Optional initial conversation messages
207
- memory?: Memory, // Optional initial memory state
208
- history?: HistoryStep[], // Optional history steps to include
209
- sessionId?: string, // Optional session continuity identifier
210
- state?: {
211
- goto?: string, // Optional: jump to a specific node ID
212
- }
208
+ // No state/memory/messages in return - modify state directly in handler
213
209
  }
214
210
  ```
215
211
 
@@ -236,16 +232,19 @@ The three common patterns are:
236
232
  #### Processing User Input
237
233
 
238
234
  ```typescript
239
- agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, sessionId }) => {
235
+ agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, sessionId, state }) => {
240
236
  if (triggerName === 'userMessage') {
241
237
  console.log('Processing trigger for session:', sessionId);
238
+
239
+ // Update state directly by reference (v2.0 change)
240
+ if (state) {
241
+ state.memory.conversationStarted = true;
242
+ state.memory.sessionId = sessionId; // Store session ID in memory if needed
243
+ state.messages.push(new HumanMessage(triggerBody));
244
+ }
245
+
242
246
  return {
243
247
  isQualified: true,
244
- memory: {
245
- conversationStarted: true,
246
- sessionId: sessionId, // Store session ID in memory if needed
247
- },
248
- messages: [new HumanMessage(triggerBody)],
249
248
  };
250
249
  }
251
250
  });
@@ -254,7 +253,7 @@ agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, sessionId }) =
254
253
  #### Trigger Qualification
255
254
 
256
255
  ```typescript
257
- agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
256
+ agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, state }) => {
258
257
  // Validate the trigger input
259
258
  if (!isValidInput(triggerBody)) {
260
259
  return { isQualified: false }; // Disqualify the trigger
@@ -265,10 +264,13 @@ agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
265
264
  return { isQualified: false };
266
265
  }
267
266
 
267
+ // Update state directly by reference (v2.0 change)
268
+ if (state) {
269
+ state.memory.validatedInput = triggerBody;
270
+ }
271
+
268
272
  return {
269
273
  isQualified: true,
270
- memory: { validatedInput: triggerBody },
271
- messages: [],
272
274
  };
273
275
  });
274
276
  ```
@@ -276,18 +278,20 @@ agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
276
278
  #### Input Transformation
277
279
 
278
280
  ```typescript
279
- agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
281
+ agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, state }) => {
280
282
  if (triggerName === 'emailTrigger') {
281
283
  // Transform email data into structured format
282
284
  const parsedEmail = parseEmailContent(triggerBody);
283
285
 
286
+ // Update state directly by reference (v2.0 change)
287
+ if (state) {
288
+ state.memory.emailSubject = parsedEmail.subject;
289
+ state.memory.senderEmail = parsedEmail.from;
290
+ state.messages.push(new HumanMessage(parsedEmail.content));
291
+ }
292
+
284
293
  return {
285
294
  isQualified: true,
286
- memory: {
287
- emailSubject: parsedEmail.subject,
288
- senderEmail: parsedEmail.from,
289
- },
290
- messages: [new HumanMessage(parsedEmail.content)],
291
295
  };
292
296
  }
293
297
  // Disqualify all other triggers handled by this listener
@@ -301,12 +305,13 @@ agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
301
305
  agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, state }) => {
302
306
  // Check condition and jump to specific node
303
307
  if (triggerBody.priority === 'high') {
308
+ // Update state directly by reference (v2.0 change)
309
+ if (state) {
310
+ state.goto = 'high-priority-handler'; // Jump to specific node
311
+ }
312
+
304
313
  return {
305
314
  isQualified: true,
306
- state: {
307
- ...state,
308
- goto: 'high-priority-handler', // Jump to specific node
309
- },
310
315
  };
311
316
  }
312
317
 
@@ -346,13 +351,13 @@ The `ERROR` event is emitted when an error occurs during agent execution. This e
346
351
 
347
352
  ```typescript
348
353
  {
349
- throwError: boolean; // Whether to throw the error onwards and stop the agent run
350
- state?: Partial<State<Memory>>; // Optional state updates to apply
354
+ throwError: boolean; // Whether to throw the error onwards and stop the agent run
351
355
  }
352
356
  ```
353
357
 
354
358
  - **throwError**: When set to `true`, the error will be thrown onwards and the agent run will stop. If `false` or not returned, the error is caught and the agent continues.
355
- - **state**: Optional partial state updates to apply before continuing or throwing
359
+
360
+ **Important v2.0 Change**: State is now updated by reference directly within the handler. You no longer return state updates.
356
361
 
357
362
  ### Usage Example
358
363
 
@@ -384,15 +389,12 @@ agent.on(events.ERROR, async ({ error, state }) => {
384
389
  // Handle recoverable vs non-recoverable errors
385
390
  if (error.message.includes('rate limit')) {
386
391
  // Recoverable error - update state and continue
392
+ // Update state directly by reference (v2.0 change)
393
+ state.memory.errorRecovered = true;
394
+ state.memory.lastError = error.message;
395
+
387
396
  return {
388
397
  throwError: false, // Don't stop the agent
389
- state: {
390
- memory: {
391
- ...state.memory,
392
- errorRecovered: true,
393
- lastError: error.message,
394
- },
395
- },
396
398
  };
397
399
  }
398
400
 
@@ -65,14 +65,16 @@ Memory is typically initialized when a trigger event occurs:
65
65
  ```typescript
66
66
  import { events } from 'mindedjs';
67
67
 
68
- agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
68
+ agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, state }) => {
69
69
  if (triggerName === 'new_order_issue') {
70
+ // Update state directly by reference (v2.0 change)
71
+ if (state) {
72
+ state.memory.user = { id: triggerBody.userId, name: triggerBody.userName };
73
+ state.memory.order = { id: triggerBody.orderId, status: 'pending' };
74
+ }
75
+
70
76
  return {
71
- memory: {
72
- user: { id: triggerBody.userId, name: triggerBody.userName },
73
- order: { id: triggerBody.orderId, status: 'pending' },
74
- },
75
- messages: [],
77
+ isQualified: true,
76
78
  };
77
79
  }
78
80
  });
@@ -89,20 +91,19 @@ const updateOrderStatus = {
89
91
  inputSchema: z.object({
90
92
  newStatus: z.string(),
91
93
  }),
92
- execute: async ({ input, memory }) => {
94
+ execute: async ({ input, state }) => {
93
95
  // Read from memory
94
- const currentOrder = memory.order;
96
+ const currentOrder = state.memory.order;
97
+
98
+ // Update state directly by reference (v2.0 change)
99
+ state.memory.order = {
100
+ ...currentOrder,
101
+ status: input.newStatus,
102
+ lastUpdated: new Date().toISOString(),
103
+ };
95
104
 
96
- // Return updated memory (merges with existing)
97
105
  return {
98
106
  result: `Order status updated to ${input.newStatus}`,
99
- memory: {
100
- order: {
101
- ...currentOrder,
102
- status: input.newStatus,
103
- lastUpdated: new Date().toISOString(),
104
- },
105
- },
106
107
  };
107
108
  },
108
109
  };
@@ -112,12 +113,14 @@ const updateOrderStatus = {
112
113
 
113
114
  1. **Initialization**: Memory starts empty `{}` and gets populated during trigger events
114
115
  2. **Persistence**: Automatically persisted between conversation turns
115
- 3. **Updates**: Memory updates are merged when tools return a memory object
116
+ 3. **Updates**: Memory is updated by reference in tools and event handlers (v2.0 change)
116
117
  4. **Validation**: All updates are validated against your schema
117
118
 
118
119
  ```typescript
119
120
  // Current memory: { userId: "123", userName: "John" }
120
- // Tool returns: { memory: { userName: "John Doe", email: "john@example.com" } }
121
+ // Tool updates state directly:
122
+ // state.memory.userName = "John Doe";
123
+ // state.memory.email = "john@example.com";
121
124
  // Result: { userId: "123", userName: "John Doe", email: "john@example.com" }
122
125
  ```
123
126
 
@@ -242,8 +245,8 @@ await agent.updateMemory(sessionId, memoryUpdate);
242
245
  await agent.updateMemory('session-123', {
243
246
  order: {
244
247
  status: 'shipped',
245
- trackingNumber: 'TRK-456789'
246
- }
248
+ trackingNumber: 'TRK-456789',
249
+ },
247
250
  });
248
251
 
249
252
  // Update multiple fields
@@ -251,12 +254,12 @@ await agent.updateMemory('session-123', {
251
254
  user: {
252
255
  preferences: {
253
256
  language: 'es',
254
- timezone: 'America/Mexico_City'
255
- }
257
+ timezone: 'America/Mexico_City',
258
+ },
256
259
  },
257
260
  conversation: {
258
- urgency: 'high'
259
- }
261
+ urgency: 'high',
262
+ },
260
263
  });
261
264
  ```
262
265
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minded-ai/mindedjs",
3
- "version": "2.0.0",
3
+ "version": "2.0.1-beta-2",
4
4
  "description": "MindedJS is a TypeScript library for building agents.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/agent.ts CHANGED
@@ -424,7 +424,7 @@ export class Agent {
424
424
  // Try to acquire lock atomically (unless bypassing session check)
425
425
  if (!bypassSessionCheck && !(await this.interruptSessionManager.lock(sessionId))) {
426
426
  // Could not acquire lock, session is being processed - enqueue the message
427
- logger.info({ msg: 'Enqueuing message', sessionId, triggerBody, triggerName, appName });
427
+ logger.debug({ msg: 'Enqueuing message', sessionId, triggerBody, triggerName, appName });
428
428
  await this.interruptSessionManager.enqueueMessage(sessionId, {
429
429
  triggerBody,
430
430
  triggerName,
@@ -560,7 +560,7 @@ export class Agent {
560
560
  if (nextMessage.appName) {
561
561
  invokeParams.appName = nextMessage.appName;
562
562
  }
563
- logger.info({ msg: 'Invoking next message in the queue', invokeParams });
563
+ logger.debug({ msg: 'Invoking next message in the queue', invokeParams });
564
564
  return await this.invoke(invokeParams);
565
565
  }
566
566
 
@@ -32,7 +32,7 @@ export interface InterruptSessionManager {
32
32
  enqueueMessage(sessionId: string, message: QueuedMessage): void | Promise<void>;
33
33
  dequeueAll(sessionId: string): QueuedMessage[] | Promise<QueuedMessage[]>;
34
34
  dequeue(sessionId: string): QueuedMessage | null | Promise<QueuedMessage | null>;
35
- checkQueueAndInterrupt(sessionId: string, updateStateObject?: Partial<State>): Promise<boolean>;
35
+ checkQueueAndInterrupt(sessionId: string, updateStateObject?: State): Promise<boolean>;
36
36
  }
37
37
 
38
38
  export abstract class BaseInterruptSessionManager implements InterruptSessionManager {