@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.
- package/dist/agent.d.ts +31 -158
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +56 -167
- package/dist/agent.js.map +1 -1
- package/dist/browserTask/README.md +419 -0
- package/dist/browserTask/browserAgent.py +632 -0
- package/dist/browserTask/captcha_isolated.png +0 -0
- package/dist/browserTask/executeBrowserTask.d.ts +3 -0
- package/dist/browserTask/executeBrowserTask.d.ts.map +1 -1
- package/dist/browserTask/executeBrowserTask.js +62 -1
- package/dist/browserTask/executeBrowserTask.js.map +1 -1
- package/dist/browserTask/executeBrowserTask.ts +79 -0
- package/dist/browserTask/requirements.txt +8 -0
- package/dist/browserTask/setup.sh +144 -0
- package/dist/checkpointer/checkpointSaverFactory.js +17 -7
- package/dist/checkpointer/checkpointSaverFactory.js.map +1 -1
- package/dist/cli/index.js +17 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/lambdaHandlerTemplate.d.ts.map +1 -1
- package/dist/edges/createDirectEdge.d.ts.map +1 -1
- package/dist/edges/createLogicalRouter.d.ts.map +1 -1
- package/dist/edges/createLogicalRouter.js +17 -7
- package/dist/edges/createLogicalRouter.js.map +1 -1
- package/dist/edges/createPromptRouter.d.ts.map +1 -1
- package/dist/edges/edgeFactory.d.ts.map +1 -1
- package/dist/events/AgentEvents.d.ts +1 -0
- package/dist/events/AgentEvents.d.ts.map +1 -1
- package/dist/index.js +17 -7
- package/dist/index.js.map +1 -1
- package/dist/interfaces/zendesk.js +17 -7
- package/dist/interfaces/zendesk.js.map +1 -1
- package/dist/internalTools/appActionRunnerTool.d.ts.map +1 -1
- package/dist/internalTools/appActionRunnerTool.js +17 -7
- package/dist/internalTools/appActionRunnerTool.js.map +1 -1
- package/dist/internalTools/documentExtraction/documentExtraction.js +17 -7
- package/dist/internalTools/documentExtraction/documentExtraction.js.map +1 -1
- package/dist/internalTools/libraryActionRunnerTool.d.ts.map +1 -1
- package/dist/internalTools/retell.js +17 -7
- package/dist/internalTools/retell.js.map +1 -1
- package/dist/internalTools/sendPlaceholderMessage.js +17 -7
- package/dist/internalTools/sendPlaceholderMessage.js.map +1 -1
- package/dist/internalTools/timer.js +17 -7
- package/dist/internalTools/timer.js.map +1 -1
- package/dist/llm/createLlmInstance.d.ts.map +1 -1
- package/dist/nodes/addAppToolNode.d.ts.map +1 -1
- package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -1
- package/dist/nodes/addBrowserTaskNode.js +37 -18
- package/dist/nodes/addBrowserTaskNode.js.map +1 -1
- package/dist/nodes/addBrowserTaskRunNode.d.ts.map +1 -1
- package/dist/nodes/addBrowserTaskRunNode.js +27 -16
- package/dist/nodes/addBrowserTaskRunNode.js.map +1 -1
- package/dist/nodes/addHumanInTheLoopNode.d.ts.map +1 -1
- package/dist/nodes/addJumpToNode.d.ts.map +1 -1
- package/dist/nodes/addJunctionNode.d.ts.map +1 -1
- package/dist/nodes/addPromptNode.d.ts.map +1 -1
- package/dist/nodes/addToolNode.d.ts.map +1 -1
- package/dist/nodes/addToolRunNode.d.ts.map +1 -1
- package/dist/nodes/addTriggerNode.d.ts.map +1 -1
- package/dist/nodes/nodeFactory.d.ts.map +1 -1
- package/dist/platform/mindedCheckpointSaver.js +17 -7
- package/dist/platform/mindedCheckpointSaver.js.map +1 -1
- package/dist/platform/mindedConnection.d.ts.map +1 -1
- package/dist/platform/mindedConnection.js +44 -0
- package/dist/platform/mindedConnection.js.map +1 -1
- package/dist/platform/mindedConnectionTypes.d.ts +33 -1
- package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
- package/dist/platform/mindedConnectionTypes.js +3 -0
- package/dist/platform/mindedConnectionTypes.js.map +1 -1
- package/dist/platform/piiGateway/gateway.js +17 -7
- package/dist/platform/piiGateway/gateway.js.map +1 -1
- package/dist/platform/utils/parseAttachments.d.ts.map +1 -1
- package/dist/playbooks/playbooks.js +17 -7
- package/dist/playbooks/playbooks.js.map +1 -1
- package/dist/toolsLibrary/classifier.d.ts +82 -0
- package/dist/toolsLibrary/classifier.d.ts.map +1 -0
- package/dist/toolsLibrary/classifier.js +223 -0
- package/dist/toolsLibrary/classifier.js.map +1 -0
- package/dist/toolsLibrary/index.d.ts +2 -0
- package/dist/toolsLibrary/index.d.ts.map +1 -1
- package/dist/toolsLibrary/index.js +19 -7
- package/dist/toolsLibrary/index.js.map +1 -1
- package/dist/toolsLibrary/parseDocument.d.ts +3 -3
- package/dist/types/Flows.types.d.ts +5 -0
- package/dist/types/Flows.types.d.ts.map +1 -1
- package/dist/types/Flows.types.js.map +1 -1
- package/dist/types/LangGraph.types.d.ts.map +1 -1
- package/dist/utils/extractStateMemoryResponse.d.ts.map +1 -1
- package/dist/utils/history.d.ts.map +1 -1
- package/dist/utils/wait.d.ts.map +1 -1
- package/dist/voice/voiceSession.js +17 -7
- package/dist/voice/voiceSession.js.map +1 -1
- package/docs/SUMMARY.md +1 -0
- package/docs/tooling/classifier.md +217 -0
- package/package.json +2 -2
- package/src/agent.ts +42 -160
- package/src/browserTask/executeBrowserTask.ts +84 -0
- package/src/events/AgentEvents.ts +1 -0
- package/src/nodes/addBrowserTaskNode.ts +23 -12
- package/src/nodes/addBrowserTaskRunNode.ts +26 -14
- package/src/platform/mindedConnection.ts +14 -13
- package/src/platform/mindedConnectionTypes.ts +38 -2
- package/src/toolsLibrary/classifier.ts +273 -0
- package/src/toolsLibrary/index.ts +2 -0
- 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 {
|
|
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 {
|
|
31
|
+
const { prompt, ...inputParams } = toolCall.args;
|
|
32
|
+
const { sessionId, cdpUrl, keepAlive } = toolCallMindedMetadata;
|
|
31
33
|
try {
|
|
32
|
-
if (!
|
|
33
|
-
throw new Error('
|
|
34
|
+
if (!sessionId || !cdpUrl || !prompt) {
|
|
35
|
+
throw new Error('Missing required parameters: sessionId, cdpUrl, or prompt');
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
//
|
|
37
|
-
const
|
|
38
|
-
|
|
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:
|
|
45
|
-
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
|
-
|
|
56
|
-
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:
|
|
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:
|
|
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
|
-
|
|
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
|
+
}
|
package/src/types/Flows.types.ts
CHANGED
|
@@ -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;
|