@minded-ai/mindedjs 1.0.19
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/.github/workflows/CI.yml +34 -0
- package/.prettierrc +8 -0
- package/README.md +6 -0
- package/dist/agent.d.ts +36 -0
- package/dist/agent.js +199 -0
- package/dist/agent.js.map +1 -0
- package/dist/analytics.d.ts +6 -0
- package/dist/analytics.js +19 -0
- package/dist/analytics.js.map +1 -0
- package/dist/edges/createDirectEdge.d.ts +4 -0
- package/dist/edges/createDirectEdge.js +14 -0
- package/dist/edges/createDirectEdge.js.map +1 -0
- package/dist/edges/createLogicalRouter.d.ts +5 -0
- package/dist/edges/createLogicalRouter.js +18 -0
- package/dist/edges/createLogicalRouter.js.map +1 -0
- package/dist/edges/createPromptRouter.d.ts +7 -0
- package/dist/edges/createPromptRouter.js +54 -0
- package/dist/edges/createPromptRouter.js.map +1 -0
- package/dist/edges/edgeFactory.d.ts +9 -0
- package/dist/edges/edgeFactory.js +65 -0
- package/dist/edges/edgeFactory.js.map +1 -0
- package/dist/events/AgentEvents.d.ts +22 -0
- package/dist/events/AgentEvents.js +9 -0
- package/dist/events/AgentEvents.js.map +1 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +5 -0
- package/dist/events/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure.ts/mindedRequest.d.ts +8 -0
- package/dist/infrastructure.ts/mindedRequest.js +22 -0
- package/dist/infrastructure.ts/mindedRequest.js.map +1 -0
- package/dist/llm/createLlmInstance.d.ts +2 -0
- package/dist/llm/createLlmInstance.js +14 -0
- package/dist/llm/createLlmInstance.js.map +1 -0
- package/dist/nodes/addHumanInTheLoopNode.d.ts +8 -0
- package/dist/nodes/addHumanInTheLoopNode.js +17 -0
- package/dist/nodes/addHumanInTheLoopNode.js.map +1 -0
- package/dist/nodes/addPromptNode.d.ts +15 -0
- package/dist/nodes/addPromptNode.js +52 -0
- package/dist/nodes/addPromptNode.js.map +1 -0
- package/dist/nodes/addToolNode.d.ts +10 -0
- package/dist/nodes/addToolNode.js +82 -0
- package/dist/nodes/addToolNode.js.map +1 -0
- package/dist/nodes/addTriggerNode.d.ts +6 -0
- package/dist/nodes/addTriggerNode.js +12 -0
- package/dist/nodes/addTriggerNode.js.map +1 -0
- package/dist/nodes/nodeFactory.d.ts +13 -0
- package/dist/nodes/nodeFactory.js +41 -0
- package/dist/nodes/nodeFactory.js.map +1 -0
- package/dist/platform/analytics.d.ts +6 -0
- package/dist/platform/analytics.js +19 -0
- package/dist/platform/analytics.js.map +1 -0
- package/dist/platform/mindedCheckpointSaver.d.ts +10 -0
- package/dist/platform/mindedCheckpointSaver.js +49 -0
- package/dist/platform/mindedCheckpointSaver.js.map +1 -0
- package/dist/platform/mindedConnection.d.ts +13 -0
- package/dist/platform/mindedConnection.js +117 -0
- package/dist/platform/mindedConnection.js.map +1 -0
- package/dist/platform/mindedConnectionTypes.d.ts +10 -0
- package/dist/platform/mindedConnectionTypes.js +8 -0
- package/dist/platform/mindedConnectionTypes.js.map +1 -0
- package/dist/platform/mindedRequest.d.ts +8 -0
- package/dist/platform/mindedRequest.js +22 -0
- package/dist/platform/mindedRequest.js.map +1 -0
- package/dist/types/Agent.types.d.ts +8 -0
- package/dist/types/Agent.types.js +3 -0
- package/dist/types/Agent.types.js.map +1 -0
- package/dist/types/Flows.types.d.ts +83 -0
- package/dist/types/Flows.types.js +24 -0
- package/dist/types/Flows.types.js.map +1 -0
- package/dist/types/LLM.types.d.ts +10 -0
- package/dist/types/LLM.types.js +9 -0
- package/dist/types/LLM.types.js.map +1 -0
- package/dist/types/LangGraph.types.d.ts +29 -0
- package/dist/types/LangGraph.types.js +20 -0
- package/dist/types/LangGraph.types.js.map +1 -0
- package/dist/types/Tools.types.d.ts +14 -0
- package/dist/types/Tools.types.js +3 -0
- package/dist/types/Tools.types.js.map +1 -0
- package/dist/types/Triggers.types.d.ts +1 -0
- package/dist/types/Triggers.types.js +3 -0
- package/dist/types/Triggers.types.js.map +1 -0
- package/docs/.gitbook/assets/image.png +0 -0
- package/docs/README.md +51 -0
- package/docs/SUMMARY.md +21 -0
- package/docs/api-reference/.nojekyll +1 -0
- package/docs/api-reference/assets/hierarchy.js +1 -0
- package/docs/api-reference/assets/highlight.css +120 -0
- package/docs/api-reference/assets/icons.js +18 -0
- package/docs/api-reference/assets/icons.svg +1 -0
- package/docs/api-reference/assets/main.js +60 -0
- package/docs/api-reference/assets/navigation.js +1 -0
- package/docs/api-reference/assets/search.js +1 -0
- package/docs/api-reference/assets/style.css +1640 -0
- package/docs/api-reference/classes/index.Agent.html +4 -0
- package/docs/api-reference/enums/index.EdgeType.html +4 -0
- package/docs/api-reference/enums/index.NodeType.html +6 -0
- package/docs/api-reference/enums/index.TriggerType.html +4 -0
- package/docs/api-reference/enums/index.events.html +3 -0
- package/docs/api-reference/hierarchy.html +1 -0
- package/docs/api-reference/index.html +310 -0
- package/docs/api-reference/interfaces/index.AppToolNode.html +5 -0
- package/docs/api-reference/interfaces/index.AppTriggerNode.html +6 -0
- package/docs/api-reference/interfaces/index.Flow.html +4 -0
- package/docs/api-reference/interfaces/index.JunctionNode.html +4 -0
- package/docs/api-reference/interfaces/index.LogicalConditionEdge.html +5 -0
- package/docs/api-reference/interfaces/index.ManualTriggerNode.html +5 -0
- package/docs/api-reference/interfaces/index.PromptConditionEdge.html +5 -0
- package/docs/api-reference/interfaces/index.PromptNode.html +6 -0
- package/docs/api-reference/interfaces/index.StepForwardEdge.html +4 -0
- package/docs/api-reference/interfaces/index.Tool.html +6 -0
- package/docs/api-reference/interfaces/index.ToolNode.html +5 -0
- package/docs/api-reference/modules/index-1.html +1 -0
- package/docs/api-reference/modules/index.html +1 -0
- package/docs/api-reference/modules.html +1 -0
- package/docs/api-reference/types/index.Edge.html +1 -0
- package/docs/api-reference/types/index.Node.html +1 -0
- package/docs/api-reference/types/index.TriggerNode.html +1 -0
- package/docs/core-concepts/edges.md +242 -0
- package/docs/core-concepts/events.md +161 -0
- package/docs/core-concepts/flows.md +74 -0
- package/docs/core-concepts/memory-types.md +208 -0
- package/docs/core-concepts/nodes.md +239 -0
- package/docs/core-concepts/tools.md +205 -0
- package/docs/examples/order-refund-flow.md +560 -0
- package/docs/getting-started/installation.md +34 -0
- package/docs/getting-started/quick-start.md +264 -0
- package/docs-structure.md +144 -0
- package/eslint.config.js +68 -0
- package/examples/orderRefundAgent/flows/orderRefundFlow.yaml +32 -0
- package/examples/orderRefundAgent/minded.json +14 -0
- package/examples/orderRefundAgent/orderRefundAgent.ts +58 -0
- package/examples/orderRefundAgent/schema.ts +7 -0
- package/examples/orderRefundAgent/tools/escalateConversation.ts +28 -0
- package/examples/orderRefundAgent/tools/index.ts +4 -0
- package/examples/orderRefundAgent/tools/refundOrder.ts +27 -0
- package/package.json +46 -0
- package/src/agent.ts +216 -0
- package/src/edges/createDirectEdge.ts +11 -0
- package/src/edges/createLogicalRouter.ts +16 -0
- package/src/edges/createPromptRouter.ts +52 -0
- package/src/edges/edgeFactory.ts +85 -0
- package/src/events/AgentEvents.ts +22 -0
- package/src/events/index.ts +3 -0
- package/src/index.ts +22 -0
- package/src/llm/createLlmInstance.ts +10 -0
- package/src/nodes/addHumanInTheLoopNode.ts +20 -0
- package/src/nodes/addPromptNode.ts +66 -0
- package/src/nodes/addToolNode.ts +95 -0
- package/src/nodes/addTriggerNode.ts +12 -0
- package/src/nodes/nodeFactory.ts +65 -0
- package/src/platform/analytics.ts +16 -0
- package/src/platform/mindedCheckpointSaver.ts +74 -0
- package/src/platform/mindedConnection.ts +106 -0
- package/src/platform/mindedConnectionTypes.ts +15 -0
- package/src/platform/mindedRequest.ts +28 -0
- package/src/types/Agent.types.ts +10 -0
- package/src/types/Flows.types.ts +103 -0
- package/src/types/LLM.types.ts +13 -0
- package/src/types/LangGraph.types.ts +25 -0
- package/src/types/Tools.types.ts +9 -0
- package/test/can-stay-on-node/can-stay-on-node.test.ts +148 -0
- package/test/can-stay-on-node/flows/test-flow.yaml +25 -0
- package/test/cannot-stay-on-node/cannot-stay-on-node.test.ts +201 -0
- package/test/cannot-stay-on-node/flows/test-flow.yaml +34 -0
- package/test/human-in-the-loop-node/flows/test-flow.yaml +23 -0
- package/test/human-in-the-loop-node/human-in-the-loop-node.test.ts +92 -0
- package/test/logical-edges/flows/logical-edge-test-flow.yaml +24 -0
- package/test/logical-edges/logical-edges.test.ts +66 -0
- package/test/no-human-in-the-loop-node/flows/test-flow.yaml +23 -0
- package/test/no-human-in-the-loop-node/no-human-in-the-loop-node.test.ts +80 -0
- package/test/prompt-edges/flows/test-flow.yaml +24 -0
- package/test/prompt-edges/prompt-edges.test.ts +90 -0
- package/test/prompt-node/flows/test-flow.yaml +24 -0
- package/test/prompt-node/prompt-node.test.ts +86 -0
- package/test/setup.ts +5 -0
- package/test/tool-node/flows/test-flow.yaml +14 -0
- package/test/tool-node/tool-node.test.ts +67 -0
- package/test/trigger/flows/test-flow.yaml +7 -0
- package/test/trigger/trigger.test.ts +57 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { RunnableLike } from '@langchain/core/runnables';
|
|
2
|
+
import { AppToolNode, JunctionNode, Node, NodeType } from '../types/Flows.types';
|
|
3
|
+
import { PreCompiledGraph } from '../types/LangGraph.types';
|
|
4
|
+
import { Tool } from '../types/Tools.types';
|
|
5
|
+
import { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|
6
|
+
import { addTriggerNode } from './addTriggerNode';
|
|
7
|
+
import { addToolNode } from './addToolNode';
|
|
8
|
+
import { addPromptNode } from './addPromptNode';
|
|
9
|
+
import { AgentEventRequestPayloads } from '../events/AgentEvents';
|
|
10
|
+
import { EmitSignature } from '../types/Agent.types';
|
|
11
|
+
|
|
12
|
+
const addJunctionNode = ({ graph, node }: { graph: PreCompiledGraph; node: JunctionNode }) => {
|
|
13
|
+
const callback: RunnableLike = async () => {};
|
|
14
|
+
graph.addNode(node.name, callback);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const addAppToolNode = ({
|
|
18
|
+
graph,
|
|
19
|
+
node,
|
|
20
|
+
}: {
|
|
21
|
+
graph: PreCompiledGraph;
|
|
22
|
+
node: AppToolNode;
|
|
23
|
+
tools: Tool<any, any>[];
|
|
24
|
+
llm: BaseLanguageModel;
|
|
25
|
+
}) => {
|
|
26
|
+
const callback: RunnableLike = async () => {
|
|
27
|
+
throw new Error('Not implemented');
|
|
28
|
+
};
|
|
29
|
+
graph.addNode(node.name, callback);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const nodeFactory = ({
|
|
33
|
+
graph,
|
|
34
|
+
node,
|
|
35
|
+
tools,
|
|
36
|
+
llm,
|
|
37
|
+
emit,
|
|
38
|
+
}: {
|
|
39
|
+
graph: PreCompiledGraph;
|
|
40
|
+
node: Node;
|
|
41
|
+
tools: Tool<any, any>[];
|
|
42
|
+
llm: BaseLanguageModel;
|
|
43
|
+
emit: EmitSignature<any, keyof AgentEventRequestPayloads<any>>;
|
|
44
|
+
}) => {
|
|
45
|
+
const nodeType = node.type;
|
|
46
|
+
switch (nodeType) {
|
|
47
|
+
case NodeType.TRIGGER:
|
|
48
|
+
addTriggerNode({ graph, node });
|
|
49
|
+
break;
|
|
50
|
+
case NodeType.TOOL:
|
|
51
|
+
addToolNode({ graph, node, tools, llm });
|
|
52
|
+
break;
|
|
53
|
+
case NodeType.JUNCTION:
|
|
54
|
+
addJunctionNode({ graph, node });
|
|
55
|
+
break;
|
|
56
|
+
case NodeType.APP_TOOL:
|
|
57
|
+
addAppToolNode({ graph, node, tools, llm });
|
|
58
|
+
break;
|
|
59
|
+
case NodeType.PROMPT_NODE:
|
|
60
|
+
addPromptNode({ graph, node, tools, llm, emit });
|
|
61
|
+
break;
|
|
62
|
+
default:
|
|
63
|
+
throw new Error(`Unsupported node type: ${nodeType}`);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { mindedRequest } from './mindedRequest';
|
|
2
|
+
|
|
3
|
+
const track = async <T>({ event, data, token, sessionId }: { event: string; data: T; token: string; sessionId: string }) => {
|
|
4
|
+
await mindedRequest({
|
|
5
|
+
path: '/analytics/events',
|
|
6
|
+
method: 'POST',
|
|
7
|
+
body: { event, data, sessionId },
|
|
8
|
+
token,
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const analyticsFactory = ({ token, sessionId }: { token: string; sessionId: string }) => {
|
|
13
|
+
return {
|
|
14
|
+
track: <T>(event: string, data: T) => track<T>({ event, data, token, sessionId }),
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseCheckpointSaver,
|
|
3
|
+
CheckpointTuple,
|
|
4
|
+
Checkpoint,
|
|
5
|
+
CheckpointMetadata,
|
|
6
|
+
ChannelVersions,
|
|
7
|
+
PendingWrite,
|
|
8
|
+
CheckpointListOptions,
|
|
9
|
+
} from '@langchain/langgraph-checkpoint';
|
|
10
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
11
|
+
import { mindedRequest } from './mindedRequest';
|
|
12
|
+
|
|
13
|
+
export class MindedCheckpointSaver extends BaseCheckpointSaver<number> {
|
|
14
|
+
constructor(private token: string) {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async getTuple(config: RunnableConfig<Record<string, any>>): Promise<CheckpointTuple | undefined> {
|
|
19
|
+
return await mindedRequest<CheckpointTuple | undefined, { config: RunnableConfig<Record<string, any>> }>({
|
|
20
|
+
path: '/checkpoint/get',
|
|
21
|
+
method: 'POST',
|
|
22
|
+
body: { config },
|
|
23
|
+
token: this.token,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async *list(config: RunnableConfig<Record<string, any>>, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple, any, any> {
|
|
28
|
+
const tuples = await mindedRequest<CheckpointTuple[], { config: RunnableConfig<Record<string, any>>; options?: CheckpointListOptions }>(
|
|
29
|
+
{
|
|
30
|
+
path: '/checkpoint/list',
|
|
31
|
+
method: 'POST',
|
|
32
|
+
body: { config, options },
|
|
33
|
+
token: this.token,
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
for (const tuple of tuples) {
|
|
38
|
+
yield tuple;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async put(
|
|
43
|
+
config: RunnableConfig<Record<string, any>>,
|
|
44
|
+
checkpoint: Checkpoint<string, string>,
|
|
45
|
+
metadata: CheckpointMetadata,
|
|
46
|
+
newVersions: ChannelVersions,
|
|
47
|
+
): Promise<RunnableConfig<Record<string, any>>> {
|
|
48
|
+
const newConfig = await mindedRequest<
|
|
49
|
+
RunnableConfig<Record<string, any>>,
|
|
50
|
+
{
|
|
51
|
+
config: RunnableConfig<Record<string, any>>;
|
|
52
|
+
checkpoint: Checkpoint<string, string>;
|
|
53
|
+
metadata: CheckpointMetadata;
|
|
54
|
+
newVersions: ChannelVersions;
|
|
55
|
+
}
|
|
56
|
+
>({
|
|
57
|
+
path: '/checkpoint/put',
|
|
58
|
+
method: 'POST',
|
|
59
|
+
body: { config, checkpoint, metadata, newVersions },
|
|
60
|
+
token: this.token,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return newConfig;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async putWrites(config: RunnableConfig<Record<string, any>>, writes: PendingWrite[], taskId: string): Promise<void> {
|
|
67
|
+
await mindedRequest<void, { config: RunnableConfig<Record<string, any>>; writes: PendingWrite[]; taskId: string }>({
|
|
68
|
+
path: '/checkpoint/put-writes',
|
|
69
|
+
method: 'POST',
|
|
70
|
+
body: { config, writes, taskId },
|
|
71
|
+
token: this.token,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { io, Socket } from 'socket.io-client';
|
|
2
|
+
import * as readline from 'readline';
|
|
3
|
+
import { BaseMindedConnectionSocketMessage, MindedConnectionSocketMessageType } from './mindedConnectionTypes';
|
|
4
|
+
|
|
5
|
+
export class MindedConnection {
|
|
6
|
+
private socket: Socket | null = null;
|
|
7
|
+
private rl: readline.Interface | null = null;
|
|
8
|
+
listeners: {
|
|
9
|
+
[key: string]: ((message: BaseMindedConnectionSocketMessage) => void)[]
|
|
10
|
+
} = {};
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
if (!process.env.MINDED_CONNECTION_TOKEN) {
|
|
14
|
+
this.rl = readline.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private async getMindedToken(): Promise<string> {
|
|
22
|
+
const envToken = process.env.MINDED_CONNECTION_TOKEN;
|
|
23
|
+
|
|
24
|
+
if (envToken) {
|
|
25
|
+
return envToken;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
this.rl!.question('Enter your Minded connection token: ', (token: string) => {
|
|
30
|
+
resolve(token);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public on = (
|
|
36
|
+
event: MindedConnectionSocketMessageType,
|
|
37
|
+
callback: (message: BaseMindedConnectionSocketMessage) => void,
|
|
38
|
+
) => {
|
|
39
|
+
if (!this.listeners[event]) {
|
|
40
|
+
this.listeners[event] = [];
|
|
41
|
+
}
|
|
42
|
+
this.listeners[event].push(callback);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
public emit = (
|
|
47
|
+
event: MindedConnectionSocketMessageType,
|
|
48
|
+
message: BaseMindedConnectionSocketMessage,
|
|
49
|
+
) => {
|
|
50
|
+
if (this.socket) {
|
|
51
|
+
this.socket.emit(event, message);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
public start(): void {
|
|
57
|
+
this.getMindedToken().then(token => {
|
|
58
|
+
this.socket = io('http://localhost:8888', {
|
|
59
|
+
path: '/minded-connect',
|
|
60
|
+
query: {
|
|
61
|
+
token
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Connection event handlers
|
|
66
|
+
this.socket.on('connect', () => {
|
|
67
|
+
console.log('\x1b[32mConnection with Minded platform is live!\x1b[0m');
|
|
68
|
+
console.log('\x1b[36mPress Ctrl+C to exit.\x1b[0m');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
this.socket.on('connect_error', () => {
|
|
72
|
+
console.error('Failed to connect to minded platform');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
this.socket.on('disconnect', () => {
|
|
76
|
+
console.log('Disconnected from local debugging socket');
|
|
77
|
+
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Listen for error messages from the server
|
|
81
|
+
this.socket.on('error', (error: { message: string }) => {
|
|
82
|
+
console.error('Server error:', error.message);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Listen for specific message types
|
|
86
|
+
this.socket.onAny((event, message) => {
|
|
87
|
+
if (this.listeners[event]) {
|
|
88
|
+
this.listeners[event].forEach((listener) => {
|
|
89
|
+
listener(message);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Handle process termination
|
|
95
|
+
process.on('SIGINT', () => {
|
|
96
|
+
if (this.socket?.connected) {
|
|
97
|
+
console.log('\nDisconnecting...');
|
|
98
|
+
this.socket.disconnect();
|
|
99
|
+
}
|
|
100
|
+
process.exit(0);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
export enum MindedConnectionSocketMessageType {
|
|
3
|
+
OnAppTrigger = 'on-app-trigger',
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface BaseMindedConnectionSocketMessage {
|
|
7
|
+
type: MindedConnectionSocketMessageType;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface OnAppTrigger extends BaseMindedConnectionSocketMessage {
|
|
11
|
+
name: string;
|
|
12
|
+
body: Record<string, any>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
const baseUrl = 'https://api.minded.com/sdk';
|
|
3
|
+
|
|
4
|
+
type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
5
|
+
|
|
6
|
+
export const mindedRequest = async <Response, Request = object>({
|
|
7
|
+
path,
|
|
8
|
+
method,
|
|
9
|
+
body,
|
|
10
|
+
token,
|
|
11
|
+
}: {
|
|
12
|
+
path: string;
|
|
13
|
+
method: Method;
|
|
14
|
+
body: Request;
|
|
15
|
+
token: string;
|
|
16
|
+
}): Promise<Response> => {
|
|
17
|
+
const response = await axios({
|
|
18
|
+
method,
|
|
19
|
+
url: `${baseUrl}${path}`,
|
|
20
|
+
data: body,
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
Authorization: `Bearer ${token}`,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return response.data;
|
|
28
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AgentEventRequestPayloads, AgentEventResponsePayloads } from "../events/AgentEvents";
|
|
2
|
+
import { LLMConfig } from "./LLM.types";
|
|
3
|
+
|
|
4
|
+
export type EmitSignature<Memory, E extends keyof AgentEventRequestPayloads<Memory>> = (event: E, payload: AgentEventRequestPayloads<Memory>[E]) => Promise<(AgentEventResponsePayloads<Memory>[E])[]>;
|
|
5
|
+
|
|
6
|
+
export type MindedSDKConfig = {
|
|
7
|
+
flows: string[];
|
|
8
|
+
llm: LLMConfig;
|
|
9
|
+
tools: string[];
|
|
10
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { LLMConfig } from './LLM.types';
|
|
2
|
+
export interface Position {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export enum NodeType {
|
|
8
|
+
TRIGGER = 'trigger',
|
|
9
|
+
JUNCTION = 'junction',
|
|
10
|
+
TOOL = 'tool',
|
|
11
|
+
APP_TOOL = 'appTool',
|
|
12
|
+
PROMPT_NODE = 'promptNode',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export enum EdgeType {
|
|
16
|
+
LOGICAL_CONDITION = 'logicalCondition',
|
|
17
|
+
PROMPT_CONDITION = 'promptCondition',
|
|
18
|
+
STEP_FORWARD = 'stepForward',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface BaseNode {
|
|
22
|
+
name: string;
|
|
23
|
+
type: NodeType;
|
|
24
|
+
position?: Position;
|
|
25
|
+
humanInTheLoop?: boolean;
|
|
26
|
+
canStayOnNode?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export enum TriggerType {
|
|
30
|
+
APP = 'app',
|
|
31
|
+
WEBHOOK = 'webhook',
|
|
32
|
+
MANUAL = 'manual',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface BaseTriggerNode extends BaseNode {
|
|
36
|
+
type: NodeType.TRIGGER;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AppTriggerNode extends BaseTriggerNode {
|
|
40
|
+
triggerType: TriggerType.APP;
|
|
41
|
+
appTriggerId: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface WebhookTriggerNode extends BaseTriggerNode {
|
|
45
|
+
triggerType: TriggerType.WEBHOOK;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ManualTriggerNode extends BaseTriggerNode {
|
|
49
|
+
triggerType: TriggerType.MANUAL;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface PromptNode extends BaseNode {
|
|
53
|
+
type: NodeType.PROMPT_NODE;
|
|
54
|
+
prompt: string;
|
|
55
|
+
llmConfig?: LLMConfig;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type TriggerNode = AppTriggerNode | WebhookTriggerNode | ManualTriggerNode;
|
|
59
|
+
|
|
60
|
+
export interface JunctionNode extends BaseNode {
|
|
61
|
+
type: NodeType.JUNCTION;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ToolNode extends BaseNode {
|
|
65
|
+
type: NodeType.TOOL;
|
|
66
|
+
toolName: string;
|
|
67
|
+
prompt: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface AppToolNode extends BaseNode {
|
|
71
|
+
type: NodeType.APP_TOOL;
|
|
72
|
+
prompt: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type Node = TriggerNode | JunctionNode | ToolNode | AppToolNode | PromptNode;
|
|
76
|
+
|
|
77
|
+
export interface BaseEdge {
|
|
78
|
+
source: string;
|
|
79
|
+
target: string;
|
|
80
|
+
type: EdgeType;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface LogicalConditionEdge extends BaseEdge {
|
|
84
|
+
type: EdgeType.LOGICAL_CONDITION;
|
|
85
|
+
condition: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface PromptConditionEdge extends BaseEdge {
|
|
89
|
+
type: EdgeType.PROMPT_CONDITION;
|
|
90
|
+
prompt: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface StepForwardEdge extends BaseEdge {
|
|
94
|
+
type: EdgeType.STEP_FORWARD;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type Edge = LogicalConditionEdge | PromptConditionEdge | StepForwardEdge;
|
|
98
|
+
|
|
99
|
+
export interface Flow {
|
|
100
|
+
name: string;
|
|
101
|
+
nodes: Node[];
|
|
102
|
+
edges: Edge[];
|
|
103
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';
|
|
2
|
+
|
|
3
|
+
export type LLMConfig = {
|
|
4
|
+
name: string,
|
|
5
|
+
properties: Record<string, any>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type LLMProvider = 'ChatOpenAI' | 'AzureChatOpenAI';
|
|
9
|
+
|
|
10
|
+
export const LLMProviders = {
|
|
11
|
+
ChatOpenAI: ChatOpenAI,
|
|
12
|
+
AzureChatOpenAI: AzureChatOpenAI,
|
|
13
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseMessage } from '@langchain/core/messages';
|
|
2
|
+
import { Annotation, CompiledStateGraph, StateGraph } from '@langchain/langgraph';
|
|
3
|
+
|
|
4
|
+
export const stateAnnotation = Annotation.Root({
|
|
5
|
+
messages: Annotation<Array<BaseMessage>>({
|
|
6
|
+
default: () => [],
|
|
7
|
+
reducer: (a, b) => a.concat(b),
|
|
8
|
+
}),
|
|
9
|
+
memory: Annotation<any>({
|
|
10
|
+
default: () => ({}),
|
|
11
|
+
reducer: (a, b) => ({ ...a, ...b }),
|
|
12
|
+
}),
|
|
13
|
+
|
|
14
|
+
triggerMetadata: Annotation<{
|
|
15
|
+
name: string;
|
|
16
|
+
triggerBody: any;
|
|
17
|
+
} | null>,
|
|
18
|
+
interruptedNode: Annotation<string | null>({
|
|
19
|
+
default: () => null,
|
|
20
|
+
reducer: (a, b) => b,
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export type CompiledGraph = CompiledStateGraph<any, any, string>;
|
|
25
|
+
export type PreCompiledGraph = StateGraph<any, any, string>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export interface Tool<Input extends z.ZodSchema, Memory> {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
input: Input;
|
|
7
|
+
isGlobal?: boolean;
|
|
8
|
+
execute: ({ input, memory }: { input: z.infer<Input>; memory: Memory }) => Promise<{ memory?: Partial<Memory>, result?: any } | void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { Agent } from '../../src/agent';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { AgentEvents } from '../../src/events/AgentEvents';
|
|
7
|
+
import { HumanMessage } from '@langchain/core/messages';
|
|
8
|
+
|
|
9
|
+
const memorySchema = z.object({
|
|
10
|
+
success: z.boolean(),
|
|
11
|
+
stayCount: z.number().optional(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('Can Stay On Node', function () {
|
|
15
|
+
this.timeout(10000); // Set timeout to 10 seconds for all tests in this suite
|
|
16
|
+
|
|
17
|
+
let agent: Agent;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
const flowsPath = path.join(__dirname, 'flows');
|
|
21
|
+
const toolsPath = path.join(__dirname, 'tools');
|
|
22
|
+
agent = new Agent({
|
|
23
|
+
memorySchema,
|
|
24
|
+
config: {
|
|
25
|
+
tools: [toolsPath],
|
|
26
|
+
flows: [flowsPath],
|
|
27
|
+
llm: {
|
|
28
|
+
name: 'ChatOpenAI',
|
|
29
|
+
properties: {
|
|
30
|
+
model: 'gpt-4o-mini',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
tools: [
|
|
35
|
+
{
|
|
36
|
+
name: 'successTool',
|
|
37
|
+
description: 'Success Tool that marks completion',
|
|
38
|
+
input: z.object({
|
|
39
|
+
name: z.string(),
|
|
40
|
+
}),
|
|
41
|
+
execute: async () => ({
|
|
42
|
+
memory: {
|
|
43
|
+
success: true,
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Add trigger event handler
|
|
51
|
+
agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
|
|
52
|
+
if (triggerName === 'Trigger') {
|
|
53
|
+
return {
|
|
54
|
+
memory: {},
|
|
55
|
+
messages: [new HumanMessage(triggerBody.message)],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should stay on the same node multiple times when instructed to stay, then continue', async function () {
|
|
62
|
+
this.timeout(20000); // Set timeout to 40 seconds for this test
|
|
63
|
+
|
|
64
|
+
const sessionId = uuidv4();
|
|
65
|
+
|
|
66
|
+
// First invocation - triggers the flow and reaches the human-in-the-loop pause
|
|
67
|
+
const result1 = await agent.invoke({
|
|
68
|
+
triggerBody: {
|
|
69
|
+
message: 'Initial input for processing',
|
|
70
|
+
},
|
|
71
|
+
triggerName: 'Trigger',
|
|
72
|
+
sessionId,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Should pause at human-in-the-loop, not reach success tool yet
|
|
76
|
+
expect(result1.memory.success).to.not.equal(true);
|
|
77
|
+
expect(result1.messages).to.have.length.greaterThan(0);
|
|
78
|
+
|
|
79
|
+
// Second invocation - provide "stay" instruction
|
|
80
|
+
const result2 = await agent.invoke({
|
|
81
|
+
triggerBody: {
|
|
82
|
+
message: 'stay',
|
|
83
|
+
},
|
|
84
|
+
triggerName: 'Trigger',
|
|
85
|
+
sessionId,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Should stay on the node, pause again, not reach success tool
|
|
89
|
+
expect(result2.memory.success).to.not.equal(true);
|
|
90
|
+
expect(result2.messages).to.have.length.greaterThan(0);
|
|
91
|
+
|
|
92
|
+
// Third invocation - provide another "stay" instruction
|
|
93
|
+
const result3 = await agent.invoke({
|
|
94
|
+
triggerBody: {
|
|
95
|
+
message: 'stay',
|
|
96
|
+
},
|
|
97
|
+
triggerName: 'Trigger',
|
|
98
|
+
sessionId,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Should still stay on the node, pause again
|
|
102
|
+
expect(result3.memory.success).to.not.equal(true);
|
|
103
|
+
expect(result3.messages).to.have.length.greaterThan(0);
|
|
104
|
+
|
|
105
|
+
// Fourth invocation - provide "continue" instruction
|
|
106
|
+
const result4 = await agent.invoke({
|
|
107
|
+
triggerBody: {
|
|
108
|
+
message: 'continue',
|
|
109
|
+
},
|
|
110
|
+
triggerName: 'Trigger',
|
|
111
|
+
sessionId,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Should now move to success tool and complete
|
|
115
|
+
expect(result4.memory.success).to.equal(true);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should move to next node immediately when instructed to continue', async function () {
|
|
119
|
+
this.timeout(20000); // Set timeout to 20 seconds for this test
|
|
120
|
+
|
|
121
|
+
const sessionId = uuidv4();
|
|
122
|
+
|
|
123
|
+
// First invocation - triggers the flow and reaches the human-in-the-loop pause
|
|
124
|
+
const result1 = await agent.invoke({
|
|
125
|
+
triggerBody: {
|
|
126
|
+
message: 'Initial input for processing',
|
|
127
|
+
},
|
|
128
|
+
triggerName: 'Trigger',
|
|
129
|
+
sessionId,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Should pause at human-in-the-loop, not reach success tool yet
|
|
133
|
+
expect(result1.memory.success).to.not.equal(true);
|
|
134
|
+
expect(result1.messages).to.have.length.greaterThan(0);
|
|
135
|
+
|
|
136
|
+
// Second invocation - provide "continue" instruction
|
|
137
|
+
const result2 = await agent.invoke({
|
|
138
|
+
triggerBody: {
|
|
139
|
+
message: 'continue',
|
|
140
|
+
},
|
|
141
|
+
triggerName: 'Trigger',
|
|
142
|
+
sessionId,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Should now move to success tool and complete
|
|
146
|
+
expect(result2.memory.success).to.equal(true);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Can Stay On Node Test Flow
|
|
2
|
+
nodes:
|
|
3
|
+
- type: 'trigger'
|
|
4
|
+
triggerType: 'manual'
|
|
5
|
+
name: 'Trigger'
|
|
6
|
+
|
|
7
|
+
- type: 'promptNode'
|
|
8
|
+
name: 'DecisionNode'
|
|
9
|
+
prompt: 'I have processed your input. Would you like me to continue to the next step, or should I stay on this node for further processing? Please respond with "continue" to move forward or "stay" to remain here for additional analysis.'
|
|
10
|
+
canStayOnNode: true
|
|
11
|
+
humanInTheLoop: true
|
|
12
|
+
|
|
13
|
+
- type: 'tool'
|
|
14
|
+
name: 'Success'
|
|
15
|
+
toolName: 'successTool'
|
|
16
|
+
|
|
17
|
+
edges:
|
|
18
|
+
- source: 'Trigger'
|
|
19
|
+
target: 'DecisionNode'
|
|
20
|
+
type: 'stepForward'
|
|
21
|
+
|
|
22
|
+
- source: 'DecisionNode'
|
|
23
|
+
target: 'Success'
|
|
24
|
+
type: 'promptCondition'
|
|
25
|
+
prompt: 'move to success node if the user wants to continue or if processing is complete'
|