@minded-ai/mindedjs 1.0.115 → 1.0.117

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 (34) hide show
  1. package/dist/agent.d.ts +31 -158
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +39 -160
  4. package/dist/agent.js.map +1 -1
  5. package/dist/events/AgentEvents.d.ts +1 -0
  6. package/dist/events/AgentEvents.d.ts.map +1 -1
  7. package/dist/platform/mindedConnection.d.ts.map +1 -1
  8. package/dist/platform/mindedConnection.js +34 -0
  9. package/dist/platform/mindedConnection.js.map +1 -1
  10. package/dist/platform/mindedConnectionTypes.d.ts +8 -1
  11. package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
  12. package/dist/platform/mindedConnectionTypes.js +1 -0
  13. package/dist/platform/mindedConnectionTypes.js.map +1 -1
  14. package/dist/toolsLibrary/classifier.d.ts +82 -0
  15. package/dist/toolsLibrary/classifier.d.ts.map +1 -0
  16. package/dist/toolsLibrary/classifier.js +223 -0
  17. package/dist/toolsLibrary/classifier.js.map +1 -0
  18. package/dist/toolsLibrary/index.d.ts +2 -0
  19. package/dist/toolsLibrary/index.d.ts.map +1 -1
  20. package/dist/toolsLibrary/index.js +2 -0
  21. package/dist/toolsLibrary/index.js.map +1 -1
  22. package/dist/types/Flows.types.d.ts +6 -0
  23. package/dist/types/Flows.types.d.ts.map +1 -1
  24. package/dist/types/Flows.types.js.map +1 -1
  25. package/docs/SUMMARY.md +1 -0
  26. package/docs/tooling/classifier.md +217 -0
  27. package/package.json +2 -2
  28. package/src/agent.ts +42 -160
  29. package/src/events/AgentEvents.ts +1 -0
  30. package/src/platform/mindedConnection.ts +14 -13
  31. package/src/platform/mindedConnectionTypes.ts +8 -2
  32. package/src/toolsLibrary/classifier.ts +273 -0
  33. package/src/toolsLibrary/index.ts +2 -0
  34. package/src/types/Flows.types.ts +6 -0
@@ -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
  };
@@ -67,6 +67,10 @@ export interface WebhookTriggerNode extends BaseTriggerNode {
67
67
  export interface InterfaceTriggerNode extends BaseTriggerNode {
68
68
  triggerType: TriggerType.INTERFACE;
69
69
  parameters: Record<string, any>;
70
+ appName: string;
71
+ appImgSrc: string;
72
+ actionName: string;
73
+ actionKey: string;
70
74
  }
71
75
 
72
76
  export interface VoiceTriggerNode extends BaseTriggerNode {
@@ -106,6 +110,8 @@ export interface BrowserTaskNode extends BaseNode {
106
110
  description?: string;
107
111
  required?: boolean;
108
112
  }[];
113
+ autoTrigger?: boolean;
114
+ defaultPayload?: string;
109
115
  }
110
116
 
111
117
  export type TriggerNode = AppTriggerNode | WebhookTriggerNode | ManualTriggerNode | VoiceTriggerNode | InterfaceTriggerNode;