@minded-ai/mindedjs 1.0.116 → 1.0.118-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 (104) hide show
  1. package/dist/agent.d.ts +31 -158
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +56 -167
  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 +3 -0
  9. package/dist/browserTask/executeBrowserTask.d.ts.map +1 -1
  10. package/dist/browserTask/executeBrowserTask.js +62 -1
  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/checkpointer/checkpointSaverFactory.js +17 -7
  16. package/dist/checkpointer/checkpointSaverFactory.js.map +1 -1
  17. package/dist/cli/index.js +17 -7
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/cli/lambdaHandlerTemplate.d.ts.map +1 -1
  20. package/dist/edges/createDirectEdge.d.ts.map +1 -1
  21. package/dist/edges/createLogicalRouter.d.ts.map +1 -1
  22. package/dist/edges/createLogicalRouter.js +17 -7
  23. package/dist/edges/createLogicalRouter.js.map +1 -1
  24. package/dist/edges/createPromptRouter.d.ts.map +1 -1
  25. package/dist/edges/edgeFactory.d.ts.map +1 -1
  26. package/dist/events/AgentEvents.d.ts +1 -0
  27. package/dist/events/AgentEvents.d.ts.map +1 -1
  28. package/dist/index.js +17 -7
  29. package/dist/index.js.map +1 -1
  30. package/dist/interfaces/zendesk.js +17 -7
  31. package/dist/interfaces/zendesk.js.map +1 -1
  32. package/dist/internalTools/appActionRunnerTool.d.ts.map +1 -1
  33. package/dist/internalTools/appActionRunnerTool.js +17 -7
  34. package/dist/internalTools/appActionRunnerTool.js.map +1 -1
  35. package/dist/internalTools/documentExtraction/documentExtraction.js +17 -7
  36. package/dist/internalTools/documentExtraction/documentExtraction.js.map +1 -1
  37. package/dist/internalTools/libraryActionRunnerTool.d.ts.map +1 -1
  38. package/dist/internalTools/retell.js +17 -7
  39. package/dist/internalTools/retell.js.map +1 -1
  40. package/dist/internalTools/sendPlaceholderMessage.js +17 -7
  41. package/dist/internalTools/sendPlaceholderMessage.js.map +1 -1
  42. package/dist/internalTools/timer.js +17 -7
  43. package/dist/internalTools/timer.js.map +1 -1
  44. package/dist/llm/createLlmInstance.d.ts.map +1 -1
  45. package/dist/nodes/addAppToolNode.d.ts.map +1 -1
  46. package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -1
  47. package/dist/nodes/addBrowserTaskNode.js +37 -18
  48. package/dist/nodes/addBrowserTaskNode.js.map +1 -1
  49. package/dist/nodes/addBrowserTaskRunNode.d.ts.map +1 -1
  50. package/dist/nodes/addBrowserTaskRunNode.js +27 -16
  51. package/dist/nodes/addBrowserTaskRunNode.js.map +1 -1
  52. package/dist/nodes/addHumanInTheLoopNode.d.ts.map +1 -1
  53. package/dist/nodes/addJumpToNode.d.ts.map +1 -1
  54. package/dist/nodes/addJunctionNode.d.ts.map +1 -1
  55. package/dist/nodes/addPromptNode.d.ts.map +1 -1
  56. package/dist/nodes/addToolNode.d.ts.map +1 -1
  57. package/dist/nodes/addToolRunNode.d.ts.map +1 -1
  58. package/dist/nodes/addTriggerNode.d.ts.map +1 -1
  59. package/dist/nodes/nodeFactory.d.ts.map +1 -1
  60. package/dist/platform/mindedCheckpointSaver.js +17 -7
  61. package/dist/platform/mindedCheckpointSaver.js.map +1 -1
  62. package/dist/platform/mindedConnection.d.ts.map +1 -1
  63. package/dist/platform/mindedConnection.js +44 -0
  64. package/dist/platform/mindedConnection.js.map +1 -1
  65. package/dist/platform/mindedConnectionTypes.d.ts +33 -1
  66. package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
  67. package/dist/platform/mindedConnectionTypes.js +3 -0
  68. package/dist/platform/mindedConnectionTypes.js.map +1 -1
  69. package/dist/platform/piiGateway/gateway.js +17 -7
  70. package/dist/platform/piiGateway/gateway.js.map +1 -1
  71. package/dist/platform/utils/parseAttachments.d.ts.map +1 -1
  72. package/dist/playbooks/playbooks.js +17 -7
  73. package/dist/playbooks/playbooks.js.map +1 -1
  74. package/dist/toolsLibrary/classifier.d.ts +82 -0
  75. package/dist/toolsLibrary/classifier.d.ts.map +1 -0
  76. package/dist/toolsLibrary/classifier.js +223 -0
  77. package/dist/toolsLibrary/classifier.js.map +1 -0
  78. package/dist/toolsLibrary/index.d.ts +2 -0
  79. package/dist/toolsLibrary/index.d.ts.map +1 -1
  80. package/dist/toolsLibrary/index.js +19 -7
  81. package/dist/toolsLibrary/index.js.map +1 -1
  82. package/dist/toolsLibrary/parseDocument.d.ts +3 -3
  83. package/dist/types/Flows.types.d.ts +5 -0
  84. package/dist/types/Flows.types.d.ts.map +1 -1
  85. package/dist/types/Flows.types.js.map +1 -1
  86. package/dist/types/LangGraph.types.d.ts.map +1 -1
  87. package/dist/utils/extractStateMemoryResponse.d.ts.map +1 -1
  88. package/dist/utils/history.d.ts.map +1 -1
  89. package/dist/utils/wait.d.ts.map +1 -1
  90. package/dist/voice/voiceSession.js +17 -7
  91. package/dist/voice/voiceSession.js.map +1 -1
  92. package/docs/SUMMARY.md +1 -0
  93. package/docs/tooling/classifier.md +217 -0
  94. package/package.json +2 -2
  95. package/src/agent.ts +42 -160
  96. package/src/browserTask/executeBrowserTask.ts +84 -0
  97. package/src/events/AgentEvents.ts +1 -0
  98. package/src/nodes/addBrowserTaskNode.ts +23 -12
  99. package/src/nodes/addBrowserTaskRunNode.ts +26 -14
  100. package/src/platform/mindedConnection.ts +14 -13
  101. package/src/platform/mindedConnectionTypes.ts +38 -2
  102. package/src/toolsLibrary/classifier.ts +273 -0
  103. package/src/toolsLibrary/index.ts +2 -0
  104. package/src/types/Flows.types.ts +5 -0
@@ -7,7 +7,7 @@ import { logger } from '../utils/logger';
7
7
  import { createHistoryStep } from '../utils/history';
8
8
  import { HistoryStep } from '../types/Agent.types';
9
9
  import { v4 as uuidv4 } from 'uuid';
10
- import { waitForCompletion } from '../browserTask/executeBrowserTask';
10
+ import { invokeBrowserTask } from '../browserTask/executeBrowserTask';
11
11
 
12
12
  type AddBrowserTaskRunNodeParams = {
13
13
  graph: PreCompiledGraph;
@@ -26,23 +26,33 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
26
26
  if (!toolCallObj.tool_calls) {
27
27
  throw new Error('Tool call not found');
28
28
  }
29
+ const toolCallMindedMetadata = toolCallObj.additional_kwargs?.mindedMetadata;
29
30
  const toolCall = toolCallObj.tool_calls[0];
30
- const { taskId, ...inputParams } = toolCall.args;
31
+ const { prompt, ...inputParams } = toolCall.args;
32
+ const { sessionId, cdpUrl, keepAlive } = toolCallMindedMetadata;
31
33
  try {
32
- if (!taskId) {
33
- throw new Error('Task ID not found in tool call arguments');
34
+ if (!sessionId || !cdpUrl || !prompt) {
35
+ throw new Error('Missing required parameters: sessionId, cdpUrl, or prompt');
34
36
  }
35
37
 
36
- // Wait for task completion
37
- const completedTask = await waitForCompletion(taskId);
38
- logger.debug({ msg: 'Browser task completed', taskId, output: completedTask.output });
38
+ // Invoke browser task via socket
39
+ const result = await invokeBrowserTask(sessionId, cdpUrl, prompt, keepAlive);
40
+
41
+ logger.debug({
42
+ msg: 'Browser task completed',
43
+ sessionId,
44
+ hasResult: !!result.result,
45
+ stepCount: result.steps?.length || 0,
46
+ recordingCount: result.recordings?.length || 0,
47
+ });
39
48
 
40
49
  // Create tool message with the result
41
50
  const toolMessage = new ToolMessage({
42
51
  id: uuidv4(),
43
52
  content: JSON.stringify({
44
- result: completedTask.output || 'Task completed successfully',
45
- steps: completedTask.steps || [],
53
+ result: result.result || 'Task completed successfully',
54
+ steps: result.steps || [],
55
+ recordings: result.recordings || [],
46
56
  inputParams: inputParams,
47
57
  }),
48
58
  name: 'browser-task',
@@ -52,8 +62,9 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
52
62
  mindedMetadata: {
53
63
  nodeType: NodeType.BROWSER_TASK,
54
64
  nodeDisplayName: browserTaskNode.displayName,
55
- taskId,
56
- steps: completedTask.steps,
65
+ sessionId,
66
+ steps: result.steps,
67
+ recordings: result.recordings,
57
68
  inputParams: inputParams,
58
69
  },
59
70
  },
@@ -69,7 +80,8 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
69
80
  mindedMetadata: {
70
81
  ...toolCallObj.additional_kwargs?.mindedMetadata,
71
82
  nodeDisplayName: browserTaskNode.displayName,
72
- steps: completedTask.steps,
83
+ steps: result.steps,
84
+ recordings: result.recordings,
73
85
  status: 'completed',
74
86
  },
75
87
  update: true, // This triggers the message reducer to update the existing message
@@ -82,7 +94,7 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
82
94
  type: NodeType.BROWSER_TASK,
83
95
  nodeId: browserTaskNode.name,
84
96
  nodeDisplayName: browserTaskNode.displayName,
85
- raw: completedTask,
97
+ raw: result,
86
98
  messageIds: [],
87
99
  }),
88
100
  };
@@ -102,7 +114,7 @@ export const addBrowserTaskRunNode = async ({ graph, browserTaskNode, attachedTo
102
114
  mindedMetadata: {
103
115
  nodeType: NodeType.BROWSER_TASK,
104
116
  nodeDisplayName: browserTaskNode.displayName,
105
- taskId,
117
+ sessionId,
106
118
  error: error.message,
107
119
  inputParams: inputParams,
108
120
  },
@@ -1,12 +1,10 @@
1
1
  import { io, Socket } from 'socket.io-client';
2
- import {
3
- mindedConnectionSocketMessageType,
4
- mindedConnectionSocketMessageTypeMap,
5
- } from './mindedConnectionTypes';
2
+ import { mindedConnectionSocketMessageType, mindedConnectionSocketMessageTypeMap } from './mindedConnectionTypes';
6
3
  import { stringify } from 'flatted';
7
4
  import { getConfig } from './config';
8
5
  import { logger } from '../utils/logger';
9
6
  import { wait } from '../utils/wait';
7
+ import * as packageJson from '../../package.json';
10
8
 
11
9
  // Module-level singleton state
12
10
  let socket: Socket | null = null;
@@ -28,20 +26,13 @@ export const on = <E extends keyof mindedConnectionSocketMessageTypeMap>(
28
26
  listeners[event].push(callback);
29
27
  };
30
28
 
31
- export const emit = <E extends keyof mindedConnectionSocketMessageTypeMap>(
32
- event: E,
33
- message: mindedConnectionSocketMessageTypeMap[E]
34
- ) => {
29
+ export const emit = <E extends keyof mindedConnectionSocketMessageTypeMap>(event: E, message: mindedConnectionSocketMessageTypeMap[E]) => {
35
30
  if (socket) {
36
31
  socket.emit(event, message);
37
32
  }
38
33
  };
39
34
 
40
- export const awaitEmit = async <T, R>(
41
- event: mindedConnectionSocketMessageType,
42
- message: T,
43
- timeoutMs: number = 5000
44
- ): Promise<R> => {
35
+ export const awaitEmit = async <T, R>(event: mindedConnectionSocketMessageType, message: T, timeoutMs: number = 5000): Promise<R> => {
45
36
  if (!socket) {
46
37
  throw new Error('Socket is not connected');
47
38
  }
@@ -81,6 +72,15 @@ const waitForConnection = async (): Promise<void> => {
81
72
  }
82
73
  };
83
74
 
75
+ const getSdkVersion = (): string => {
76
+ try {
77
+ return packageJson.version;
78
+ } catch {
79
+ logger.warn('Could not determine SDK version');
80
+ return 'unknown';
81
+ }
82
+ };
83
+
84
84
  const connect = async (token: string): Promise<void> => {
85
85
  const { isDeployed, baseUrl } = getConfig();
86
86
  return new Promise<void>((resolve, reject) => {
@@ -89,6 +89,7 @@ const connect = async (token: string): Promise<void> => {
89
89
  query: {
90
90
  isDeployedAgent: isDeployed,
91
91
  token,
92
+ sdkVersion: getSdkVersion(),
92
93
  },
93
94
  });
94
95
 
@@ -39,7 +39,9 @@ export enum mindedConnectionSocketMessageType {
39
39
  TIMER_TRIGGER = 'timer-trigger',
40
40
  RETELL_CALL = 'retell-call',
41
41
  RETELL_GET_CALL = 'retell-get-call',
42
-
42
+ SDK_VERSION_MISMATCH = 'sdk-version-mismatch', // Browser Task
43
+ CREATE_BROWSER_SESSION = 'create-browser-session',
44
+ INVOKE_BROWSER_TASK = 'invoke-browser-task',
43
45
  }
44
46
 
45
47
  export type mindedConnectionSocketMessageTypeMap = {
@@ -67,7 +69,10 @@ export type mindedConnectionSocketMessageTypeMap = {
67
69
  [mindedConnectionSocketMessageType.RESTORE_CHECKPOINT]: RestoreCheckpointRequest;
68
70
  [mindedConnectionSocketMessageType.RETELL_CALL]: RetellCall;
69
71
  [mindedConnectionSocketMessageType.RETELL_GET_CALL]: RetellGetCall;
72
+ [mindedConnectionSocketMessageType.SDK_VERSION_MISMATCH]: SdkVersionMismatchMessage;
70
73
  [mindedConnectionSocketMessageType.UPDATE_STATE]: UpdateStateRequest;
74
+ [mindedConnectionSocketMessageType.CREATE_BROWSER_SESSION]: CreateBrowserSessionRequest;
75
+ [mindedConnectionSocketMessageType.INVOKE_BROWSER_TASK]: InvokeBrowserTaskRequest;
71
76
  };
72
77
 
73
78
  export interface BasemindedConnectionSocketMessage {
@@ -234,7 +239,38 @@ export interface RetellGetCallResponse extends BaseSdkConnectionSocketMessageRes
234
239
  error?: string;
235
240
  }
236
241
 
242
+ export interface SdkVersionMismatchMessage extends BasemindedConnectionSocketMessage {
243
+ type: mindedConnectionSocketMessageType.SDK_VERSION_MISMATCH;
244
+ currentVersion: string;
245
+ requiredVersion: string;
246
+ }
237
247
  export interface UpdateStateRequest extends BasemindedConnectionSocketMessage {
238
248
  sessionId: string;
239
249
  state: Partial<typeof stateAnnotation.State>;
240
- }
250
+ }
251
+
252
+ // Browser Task Messages
253
+ export interface CreateBrowserSessionRequest extends BasemindedConnectionSocketMessage {
254
+ type: mindedConnectionSocketMessageType.CREATE_BROWSER_SESSION;
255
+ proxy?: string; // 2-digit country code like 'IL'
256
+ }
257
+
258
+ export interface CreateBrowserSessionResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
259
+ sessionId?: string;
260
+ cdpUrl?: string;
261
+ liveViewUrl?: string;
262
+ }
263
+
264
+ export interface InvokeBrowserTaskRequest extends BasemindedConnectionSocketMessage {
265
+ type: mindedConnectionSocketMessageType.INVOKE_BROWSER_TASK;
266
+ cdpUrl: string;
267
+ task: string;
268
+ sessionId: string;
269
+ keepAlive?: boolean;
270
+ }
271
+
272
+ export interface InvokeBrowserTaskResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
273
+ result?: any;
274
+ steps?: any[];
275
+ recordings?: any[];
276
+ }
@@ -0,0 +1,273 @@
1
+ import { z } from 'zod';
2
+ import { Tool } from '../types/Tools.types';
3
+ import { logger } from '../utils/logger';
4
+ import { JsonOutputParser } from '@langchain/core/output_parsers';
5
+ import { SystemMessage } from '@langchain/core/messages';
6
+ import { BaseLanguageModel } from '@langchain/core/language_models/base';
7
+
8
+ // Type definitions for classifier configuration
9
+ export interface ClassDefinition {
10
+ name: string;
11
+ description: string;
12
+ }
13
+
14
+ export interface ClassifierConfig {
15
+ classes: ClassDefinition[];
16
+ systemPrompt?: string;
17
+ outputFormat?: 'json' | 'text';
18
+ includeReason?: boolean;
19
+ defaultClass?: string;
20
+ defaultReason?: string;
21
+ }
22
+
23
+ export interface ClassificationResult {
24
+ class: string;
25
+ reason?: string;
26
+ confidence?: number;
27
+ [key: string]: any; // Allow additional fields
28
+ }
29
+
30
+ // Default configuration
31
+ const DEFAULT_CONFIG: Partial<ClassifierConfig> = {
32
+ outputFormat: 'json',
33
+ includeReason: true,
34
+ defaultClass: 'unknown',
35
+ defaultReason: 'Unable to determine classification',
36
+ };
37
+
38
+ /**
39
+ * Generic classifier utility that can be used standalone
40
+ * @param content The content to classify
41
+ * @param config The classifier configuration
42
+ * @param llm The language model to use for classification
43
+ * @returns The classification result
44
+ */
45
+ export async function classify(content: string, config: ClassifierConfig, llm: BaseLanguageModel): Promise<ClassificationResult> {
46
+ const mergedConfig = { ...DEFAULT_CONFIG, ...config };
47
+
48
+ try {
49
+ // Build the classification prompt
50
+ const classesDescription = mergedConfig.classes.map((c) => `${c.name}: ${c.description}`).join('\n');
51
+
52
+ const basePrompt =
53
+ mergedConfig.systemPrompt || 'You are a classifier. Your task is to classify the given content into one of the following categories:';
54
+
55
+ let prompt = `${basePrompt}\n\n${classesDescription}\n\n`;
56
+
57
+ if (mergedConfig.outputFormat === 'json') {
58
+ prompt += `You should output the result in the following JSON format: {
59
+ "class": "<selected class name>",
60
+ ${mergedConfig.includeReason ? '"reason": "<explanation for the classification>",' : ''}
61
+ "confidence": <confidence score between 0 and 1>
62
+ }.\nReturn JSON and nothing more.`;
63
+ } else {
64
+ prompt += 'Return only the class name.';
65
+ }
66
+
67
+ prompt += `\n\nContent to classify:\n${content}`;
68
+
69
+ // Make the classification request
70
+ if (mergedConfig.outputFormat === 'json') {
71
+ const parser = new JsonOutputParser();
72
+ const result = await llm.pipe(parser).invoke([new SystemMessage(prompt)]);
73
+ return result as ClassificationResult;
74
+ } else {
75
+ const result = await llm.invoke([new SystemMessage(prompt)]);
76
+ const classText = typeof result.content === 'string' ? result.content.trim() : '';
77
+ return { class: classText };
78
+ }
79
+ } catch (error) {
80
+ const errorMessage = error instanceof Error ? error.message : String(error);
81
+ logger.error({ message: 'Classification failed, using default', error: errorMessage });
82
+
83
+ // Return default classification on error
84
+ return {
85
+ class: mergedConfig.defaultClass || 'unknown',
86
+ reason: mergedConfig.defaultReason || errorMessage,
87
+ confidence: 0,
88
+ };
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Create a classifier from a simple class list
94
+ * @param classes Array of class names or [name, description] tuples
95
+ * @param options Additional configuration options
96
+ * @returns A configured classify function
97
+ */
98
+ export function createClassifier(classes: string[] | [string, string][], options?: Partial<ClassifierConfig>) {
99
+ const classDefinitions: ClassDefinition[] = classes.map((c) => {
100
+ if (typeof c === 'string') {
101
+ return { name: c, description: '' };
102
+ }
103
+ return { name: c[0], description: c[1] };
104
+ });
105
+
106
+ const config: ClassifierConfig = {
107
+ ...options,
108
+ classes: classDefinitions,
109
+ };
110
+
111
+ return (content: string, llm: BaseLanguageModel) => classify(content, config, llm);
112
+ }
113
+
114
+ // Schema for the classifier tool
115
+ export const schema = z.object({
116
+ content: z.string().describe('The content to classify'),
117
+ classes: z
118
+ .array(
119
+ z.union([
120
+ z.string(),
121
+ z.tuple([z.string(), z.string()]),
122
+ z.object({
123
+ name: z.string(),
124
+ description: z.string(),
125
+ }),
126
+ ]),
127
+ )
128
+ .optional()
129
+ .describe('Classes to classify into. Can be strings, [name, description] tuples, or objects with name and description'),
130
+ systemPrompt: z.string().optional().describe('Custom system prompt for classification'),
131
+ includeReason: z.boolean().optional().default(true).describe('Whether to include reasoning in the response'),
132
+ outputFormat: z.enum(['json', 'text']).optional().default('json').describe('Output format for the classification'),
133
+ defaultClass: z.string().optional().describe('Default class to use if classification fails'),
134
+ defaultReason: z.string().optional().describe('Default reason to use if classification fails'),
135
+ });
136
+
137
+ const classifierTool: Tool<typeof schema, any> = {
138
+ name: 'minded-classifier',
139
+ description:
140
+ 'Classify content into predefined categories using AI. Supports custom classes, system prompts, and various output formats. Can be configured with default fallback values.',
141
+ input: schema,
142
+ isGlobal: false,
143
+ execute: async ({ input, state, agent }) => {
144
+ const { content, classes, systemPrompt, includeReason, outputFormat, defaultClass, defaultReason } = input;
145
+
146
+ logger.info({
147
+ message: 'Classifying content',
148
+ sessionId: state.sessionId,
149
+ contentLength: content.length,
150
+ classCount: classes?.length,
151
+ });
152
+
153
+ // Convert input classes to ClassDefinition format
154
+ let classDefinitions: ClassDefinition[] = [];
155
+ if (classes) {
156
+ classDefinitions = classes.map((c) => {
157
+ if (typeof c === 'string') {
158
+ return { name: c, description: '' };
159
+ } else if (Array.isArray(c)) {
160
+ return { name: c[0], description: c[1] };
161
+ } else {
162
+ return c as ClassDefinition;
163
+ }
164
+ });
165
+ }
166
+
167
+ // If no classes provided, try to get from state memory
168
+ if (classDefinitions.length === 0 && state.memory?.classifierConfig?.classes) {
169
+ classDefinitions = state.memory.classifierConfig.classes;
170
+ }
171
+
172
+ if (classDefinitions.length === 0) {
173
+ throw new Error('No classes provided for classification');
174
+ }
175
+
176
+ const config: ClassifierConfig = {
177
+ classes: classDefinitions,
178
+ systemPrompt,
179
+ includeReason,
180
+ outputFormat,
181
+ defaultClass,
182
+ defaultReason,
183
+ };
184
+
185
+ try {
186
+ const result = await classify(content, config, agent.llm);
187
+
188
+ logger.info({
189
+ message: 'Classification completed',
190
+ sessionId: state.sessionId,
191
+ class: result.class,
192
+ confidence: result.confidence,
193
+ });
194
+
195
+ return {
196
+ result,
197
+ state: {
198
+ memory: {
199
+ lastClassification: {
200
+ content: content.substring(0, 100) + (content.length > 100 ? '...' : ''),
201
+ result,
202
+ timestamp: new Date().toISOString(),
203
+ },
204
+ },
205
+ },
206
+ };
207
+ } catch (error) {
208
+ const errorMessage = error instanceof Error ? error.message : String(error);
209
+ logger.error({
210
+ message: 'Classification failed',
211
+ sessionId: state.sessionId,
212
+ error: errorMessage,
213
+ });
214
+
215
+ throw error;
216
+ }
217
+ },
218
+ };
219
+
220
+ export default classifierTool;
221
+
222
+ // Export utility for multi-label classification
223
+ export async function multiClassify(
224
+ content: string,
225
+ config: ClassifierConfig & { maxClasses?: number },
226
+ llm: BaseLanguageModel,
227
+ ): Promise<ClassificationResult[]> {
228
+ const mergedConfig = { ...DEFAULT_CONFIG, ...config };
229
+ const maxClasses = mergedConfig.maxClasses || 3;
230
+
231
+ try {
232
+ const classesDescription = mergedConfig.classes.map((c) => `${c.name}: ${c.description}`).join('\n');
233
+
234
+ const basePrompt =
235
+ mergedConfig.systemPrompt || 'You are a multi-label classifier. Select all applicable categories for the given content:';
236
+
237
+ const prompt = `${basePrompt}\n\n${classesDescription}\n\n
238
+ You should output the result as a JSON array of up to ${maxClasses} classifications, ordered by relevance:
239
+ [
240
+ {
241
+ "class": "<class name>",
242
+ ${mergedConfig.includeReason ? '"reason": "<explanation>",' : ''}
243
+ "confidence": <confidence score between 0 and 1>
244
+ },
245
+ ...
246
+ ]
247
+ Return JSON and nothing more.
248
+
249
+ Content to classify:
250
+ ${content}`;
251
+
252
+ const parser = new JsonOutputParser();
253
+ const result = await llm.pipe(parser).invoke([new SystemMessage(prompt)]);
254
+
255
+ if (Array.isArray(result)) {
256
+ return result as ClassificationResult[];
257
+ }
258
+
259
+ // If single result returned, wrap in array
260
+ return [result as ClassificationResult];
261
+ } catch (error) {
262
+ const errorMessage = error instanceof Error ? error.message : String(error);
263
+ logger.error({ message: 'Multi-classification failed', error: errorMessage });
264
+
265
+ return [
266
+ {
267
+ class: mergedConfig.defaultClass || 'unknown',
268
+ reason: mergedConfig.defaultReason || errorMessage,
269
+ confidence: 0,
270
+ },
271
+ ];
272
+ }
273
+ }
@@ -1,6 +1,8 @@
1
1
  import * as parseDocument from './parseDocument';
2
+ import * as classifier from './classifier';
2
3
 
3
4
  // Export all tools as a collection for easy discovery
4
5
  export const tools = {
5
6
  'minded-parse-documents': parseDocument,
7
+ 'minded-classifier': classifier,
6
8
  };
@@ -69,6 +69,8 @@ export interface InterfaceTriggerNode extends BaseTriggerNode {
69
69
  parameters: Record<string, any>;
70
70
  appName: string;
71
71
  appImgSrc: string;
72
+ actionName: string;
73
+ actionKey: string;
72
74
  }
73
75
 
74
76
  export interface VoiceTriggerNode extends BaseTriggerNode {
@@ -108,6 +110,9 @@ export interface BrowserTaskNode extends BaseNode {
108
110
  description?: string;
109
111
  required?: boolean;
110
112
  }[];
113
+ autoTrigger?: boolean;
114
+ defaultPayload?: string;
115
+ proxy?: string; // 2-digit country code like 'IL'
111
116
  }
112
117
 
113
118
  export type TriggerNode = AppTriggerNode | WebhookTriggerNode | ManualTriggerNode | VoiceTriggerNode | InterfaceTriggerNode;