@minded-ai/mindedjs 1.0.23 → 1.0.25
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 +2 -5
- package/dist/agent.js +41 -25
- package/dist/agent.js.map +1 -1
- package/dist/checkpointer/checkpointSaverFactory.js +1 -1
- package/dist/checkpointer/checkpointSaverFactory.js.map +1 -1
- package/dist/cli/index.js +0 -0
- package/dist/edges/createPromptRouter.js +4 -1
- package/dist/edges/createPromptRouter.js.map +1 -1
- package/dist/events/AgentEvents.d.ts +2 -0
- package/dist/events/AgentEvents.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/internalTools/appActionRunnerTool.d.ts +25 -0
- package/dist/internalTools/appActionRunnerTool.js +30 -0
- package/dist/internalTools/appActionRunnerTool.js.map +1 -0
- package/dist/nodes/actionRunnerTool.d.ts +11 -0
- package/dist/nodes/actionRunnerTool.js +83 -0
- package/dist/nodes/actionRunnerTool.js.map +1 -0
- package/dist/nodes/addAppTool.d.ts +8 -0
- package/dist/nodes/addAppTool.js +12 -0
- package/dist/nodes/addAppTool.js.map +1 -0
- package/dist/nodes/addAppToolNode.d.ts +8 -0
- package/dist/nodes/addAppToolNode.js +14 -0
- package/dist/nodes/addAppToolNode.js.map +1 -0
- package/dist/nodes/addPromptNode.js +4 -1
- package/dist/nodes/addPromptNode.js.map +1 -1
- package/dist/nodes/addToolNode.d.ts +4 -4
- package/dist/nodes/addToolNode.js +6 -3
- package/dist/nodes/addToolNode.js.map +1 -1
- package/dist/nodes/addTriggerNode.js.map +1 -1
- package/dist/nodes/callTool.d.ts +10 -0
- package/dist/nodes/callTool.js +57 -0
- package/dist/nodes/callTool.js.map +1 -0
- package/dist/nodes/nodeFactory.js +1 -1
- package/dist/nodes/nodeFactory.js.map +1 -1
- package/dist/nodes/toolNodeRunner.d.ts +15 -0
- package/dist/nodes/toolNodeRunner.js +79 -0
- package/dist/nodes/toolNodeRunner.js.map +1 -0
- package/dist/platform/mindedConnection.js +1 -0
- package/dist/platform/mindedConnection.js.map +1 -1
- package/dist/platform/mindedConnectionTypes.d.ts +1 -0
- package/dist/tools/appToolRunner.d.ts +30 -0
- package/dist/tools/appToolRunner.js +35 -0
- package/dist/tools/appToolRunner.js.map +1 -0
- package/dist/tools/parser.d.ts +14 -0
- package/dist/tools/parser.js +17 -0
- package/dist/tools/parser.js.map +1 -0
- package/dist/tools/triggerTypeToDefaultMessage.d.ts +3 -0
- package/dist/tools/triggerTypeToDefaultMessage.js +10 -0
- package/dist/tools/triggerTypeToDefaultMessage.js.map +1 -0
- package/dist/triggers/triggerTypeToDefaultMessage.d.ts +3 -0
- package/dist/triggers/triggerTypeToDefaultMessage.js +10 -0
- package/dist/triggers/triggerTypeToDefaultMessage.js.map +1 -0
- package/dist/types/Agent.types.d.ts +12 -0
- package/dist/types/Agent.types.js +6 -0
- package/dist/types/Agent.types.js.map +1 -1
- package/dist/types/Flows.types.d.ts +15 -3
- package/dist/types/LangGraph.types.d.ts +3 -0
- package/dist/types/LangGraph.types.js +8 -0
- package/dist/types/LangGraph.types.js.map +1 -1
- package/dist/types/Tools.types.d.ts +3 -1
- package/docs/SUMMARY.md +11 -10
- package/docs/core-concepts/nodes.md +18 -0
- package/docs/core-concepts/tools.md +21 -1
- package/docs/core-concepts/triggers.md +89 -0
- package/examples/orderRefundAgent/flows/orderRefundFlow.yaml +6 -12
- package/package.json +2 -2
- package/src/agent.ts +37 -26
- package/src/checkpointer/checkpointSaverFactory.ts +1 -1
- package/src/edges/createPromptRouter.ts +13 -7
- package/src/events/AgentEvents.ts +2 -1
- package/src/index.ts +1 -0
- package/src/nodes/addPromptNode.ts +9 -3
- package/src/nodes/addToolNode.ts +15 -12
- package/src/nodes/addTriggerNode.ts +6 -6
- package/src/nodes/nodeFactory.ts +2 -2
- package/src/platform/mindedConnection.ts +1 -0
- package/src/platform/mindedConnectionTypes.ts +1 -0
- package/src/triggers/triggerTypeToDefaultMessage.ts +9 -0
- package/src/types/Agent.types.ts +15 -0
- package/src/types/Flows.types.ts +16 -3
- package/src/types/LangGraph.types.ts +9 -1
- package/src/types/Tools.types.ts +2 -1
- package/test/can-stay-on-node/can-stay-on-node.test.ts +37 -18
- package/test/cannot-stay-on-node/cannot-stay-on-node.test.ts +49 -24
- package/test/human-in-the-loop-node/human-in-the-loop-node.test.ts +13 -6
- package/test/logical-edges/logical-edges.test.ts +13 -4
- package/test/no-human-in-the-loop-node/no-human-in-the-loop-node.test.ts +7 -3
- package/test/prompt-edges/prompt-edges.test.ts +13 -4
- package/test/prompt-node/prompt-node.test.ts +13 -6
- package/test/tool-node/tool-node.test.ts +7 -2
- package/test/trigger/trigger.test.ts +150 -6
- package/dist/types/Triggers.types.d.ts +0 -1
- package/dist/types/Triggers.types.js +0 -3
- package/dist/types/Triggers.types.js.map +0 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Triggers
|
|
2
|
+
|
|
3
|
+
Triggers are the entry points into your agent's flows. They serve as the initial contact point between external systems and your agent, handling incoming events and initializing conversations with appropriate context and memory.
|
|
4
|
+
|
|
5
|
+
## Trigger Types
|
|
6
|
+
|
|
7
|
+
Currently, MindedJS supports a single type of trigger:
|
|
8
|
+
|
|
9
|
+
- **App Triggers**: Triggered by specific applications (e.g., Slack, Zendesk)
|
|
10
|
+
- Each app trigger is identified by a unique `appTriggerId`
|
|
11
|
+
- Triggers can be customized to handle app-specific data formats
|
|
12
|
+
- Supports automatic message conversion for certain apps (e.g., Slack messages)
|
|
13
|
+
|
|
14
|
+
### Trigger Invocation History
|
|
15
|
+
|
|
16
|
+
When a trigger is invoked, it creates a comprehensive record of the event that is:
|
|
17
|
+
|
|
18
|
+
1. Added to the flow history for tracking and debugging
|
|
19
|
+
2. Passed to subsequent tool calls via the `triggerInvocations` parameter
|
|
20
|
+
3. Preserved throughout the flow's execution
|
|
21
|
+
|
|
22
|
+
This history allows tools to:
|
|
23
|
+
|
|
24
|
+
- Access the original trigger context
|
|
25
|
+
- Make decisions based on the triggering event
|
|
26
|
+
- Maintain conversation continuity
|
|
27
|
+
- Debug flow execution
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
const tool: Tool = {
|
|
33
|
+
name: 'myTool',
|
|
34
|
+
execute: async ({ input, triggerInvocations }) => {
|
|
35
|
+
// Access trigger information
|
|
36
|
+
const trigger = triggerInvocations[0];
|
|
37
|
+
console.log(`Triggered by ${trigger.appName}: ${trigger.triggerName}`);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Default Message Behavior
|
|
43
|
+
|
|
44
|
+
MindedJS provides intelligent message handling for different trigger types through the `triggerTypeToDefaultMessage` mapping. This system:
|
|
45
|
+
|
|
46
|
+
- Automatically converts trigger data into appropriate message formats
|
|
47
|
+
- Maintains conversation context without manual intervention
|
|
48
|
+
- Supports different message types for different applications
|
|
49
|
+
|
|
50
|
+
Currently supported default messages:
|
|
51
|
+
|
|
52
|
+
- **Slack**: For "New Direct Message (Instant)" triggers, the message text is automatically converted to a human message
|
|
53
|
+
|
|
54
|
+
Example:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// Slack trigger will automatically add a human message
|
|
58
|
+
const slackResult = await agent.invoke({
|
|
59
|
+
name: 'New Direct Message (Instant)',
|
|
60
|
+
body: { text: 'Hello from Slack' },
|
|
61
|
+
appName: 'Slack',
|
|
62
|
+
// ... other required fields
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Other triggers won't add any messages by default
|
|
66
|
+
const otherResult = await agent.invoke({
|
|
67
|
+
name: 'SomeOtherTrigger',
|
|
68
|
+
body: { text: 'Hello' },
|
|
69
|
+
appName: 'OtherApp',
|
|
70
|
+
// ... other required fields
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Validate Trigger Input
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// ✅ Good - Input validation
|
|
78
|
+
agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
|
|
79
|
+
if (!triggerBody.customerId || !triggerBody.message) {
|
|
80
|
+
return false; // Disqualify invalid triggers
|
|
81
|
+
}
|
|
82
|
+
// Process valid trigger
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// ❌ Avoid - No validation
|
|
86
|
+
agent.on(AgentEvents.TRIGGER_EVENT, async ({ triggerBody }) => {
|
|
87
|
+
// Process without validation
|
|
88
|
+
});
|
|
89
|
+
```
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
name: 'Order refund flow'
|
|
2
2
|
nodes:
|
|
3
|
-
- type: 'trigger'
|
|
4
|
-
triggerType: 'manual'
|
|
5
|
-
name: 'New Direct Message (Instant)'
|
|
6
|
-
- type: 'tool'
|
|
7
|
-
name: 'Refund order'
|
|
8
|
-
toolName: 'refundOrder'
|
|
9
|
-
- type: 'tool'
|
|
10
|
-
name: 'Escalate conversation'
|
|
11
|
-
toolName: 'escalateConversation'
|
|
12
3
|
- type: 'promptNode'
|
|
13
4
|
name: 'Prompt'
|
|
14
5
|
humanInTheLoop: true
|
|
@@ -18,10 +9,13 @@ nodes:
|
|
|
18
9
|
name: 'AzureChatOpenAI'
|
|
19
10
|
properties:
|
|
20
11
|
model: 'gpt-4o'
|
|
12
|
+
- type: 'tool'
|
|
13
|
+
name: 'Refund order'
|
|
14
|
+
toolName: 'refundOrder'
|
|
15
|
+
- type: 'tool'
|
|
16
|
+
name: 'Escalate conversation'
|
|
17
|
+
toolName: 'escalateConversation'
|
|
21
18
|
edges:
|
|
22
|
-
- source: 'New Direct Message (Instant)'
|
|
23
|
-
target: 'Prompt'
|
|
24
|
-
type: 'stepForward'
|
|
25
19
|
- source: 'Prompt'
|
|
26
20
|
target: 'Refund order'
|
|
27
21
|
type: 'promptCondition'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minded-ai/mindedjs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.25",
|
|
4
4
|
"description": "MindedJS is a TypeScript library for building agents.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -49,4 +49,4 @@
|
|
|
49
49
|
"uuid": "^11.1.0",
|
|
50
50
|
"zod": "^3.24.4"
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|
package/src/agent.ts
CHANGED
|
@@ -9,17 +9,18 @@ import { CompiledGraph, PreCompiledGraph, stateAnnotation } from './types/LangGr
|
|
|
9
9
|
import { edgeFactory } from './edges/edgeFactory';
|
|
10
10
|
import { AgentEventRequestPayloads, AgentEventResponsePayloads, AgentEvents } from './events/AgentEvents';
|
|
11
11
|
import { z } from 'zod';
|
|
12
|
-
|
|
13
12
|
import { MindedConnection } from './platform/mindedConnection';
|
|
14
13
|
import { BaseMindedConnectionSocketMessage, MindedConnectionSocketMessageType, OnAppTrigger } from './platform/mindedConnectionTypes';
|
|
15
14
|
import * as fs from 'fs';
|
|
16
15
|
import * as path from 'path';
|
|
17
16
|
import * as yaml from 'js-yaml';
|
|
18
|
-
import { MindedSDKConfig } from './types/Agent.types';
|
|
17
|
+
import { MindedSDKConfig, TriggerInvocationHistory } from './types/Agent.types';
|
|
19
18
|
import { createLlmInstance } from './llm/createLlmInstance';
|
|
20
19
|
import { config } from 'dotenv';
|
|
21
20
|
import { resolve } from 'path';
|
|
22
21
|
import { createCheckpointSaver } from './checkpointer/checkpointSaverFactory';
|
|
22
|
+
import { BaseMessage } from '@langchain/core/messages';
|
|
23
|
+
import triggerTypeToDefaultMessage from './triggers/triggerTypeToDefaultMessage';
|
|
23
24
|
|
|
24
25
|
config({ path: resolve(__dirname, '../.env') });
|
|
25
26
|
|
|
@@ -63,17 +64,12 @@ export class Agent {
|
|
|
63
64
|
this.mindedConnection.start();
|
|
64
65
|
this.mindedConnection.on(MindedConnectionSocketMessageType.OnAppTrigger, async (message: BaseMindedConnectionSocketMessage) => {
|
|
65
66
|
const trigger = message as OnAppTrigger;
|
|
66
|
-
await this.invoke(
|
|
67
|
-
triggerBody: trigger.body,
|
|
68
|
-
triggerName: trigger.name,
|
|
69
|
-
sessionId: trigger.cnvId,
|
|
70
|
-
});
|
|
67
|
+
await this.invoke(trigger);
|
|
71
68
|
});
|
|
72
69
|
}
|
|
73
70
|
this.checkpointer = memorySaver || createCheckpointSaver(this.mindedConnection);
|
|
74
71
|
this.compiledGraph = this.initializeGraph();
|
|
75
72
|
}
|
|
76
|
-
|
|
77
73
|
private loadFlowsFromDirectory(flowsDirectories: string[]): Flow[] {
|
|
78
74
|
const flows: Flow[] = [];
|
|
79
75
|
for (const flowsDirectory of flowsDirectories) {
|
|
@@ -140,11 +136,18 @@ export class Agent {
|
|
|
140
136
|
|
|
141
137
|
// Add edges
|
|
142
138
|
edgeFactory({ graph, edges, nodes: nodesObject, llm: this.llm });
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
139
|
+
|
|
140
|
+
// Add edge from start to first node if no triggers exist
|
|
141
|
+
const hasTrigger = nodes.some((node) => node.type === NodeType.TRIGGER);
|
|
142
|
+
if (!hasTrigger && nodes.length > 0) {
|
|
143
|
+
graph.addEdge('__start__', nodes[0].name as any);
|
|
144
|
+
} else {
|
|
145
|
+
nodes.forEach((node) => {
|
|
146
|
+
if (node.type === NodeType.TRIGGER) {
|
|
147
|
+
graph.addEdge('__start__', node.name as any);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
148
151
|
|
|
149
152
|
// Compile the graph
|
|
150
153
|
return graph.compile({ checkpointer: this.checkpointer }) as CompiledGraph;
|
|
@@ -156,40 +159,48 @@ export class Agent {
|
|
|
156
159
|
memory: {} as z.infer<typeof this.memorySchema>,
|
|
157
160
|
triggerMetadata: null,
|
|
158
161
|
interruptedNode: null,
|
|
162
|
+
history: [],
|
|
163
|
+
triggerInvocations: [] as Array<TriggerInvocationHistory>,
|
|
159
164
|
};
|
|
160
165
|
}
|
|
161
166
|
|
|
162
|
-
public async invoke(
|
|
163
|
-
const session =
|
|
167
|
+
public async invoke(trigger: OnAppTrigger) {
|
|
168
|
+
const session = trigger.cnvId || uuidv4();
|
|
169
|
+
const triggerName = trigger.name;
|
|
170
|
+
const triggerBody = trigger.body;
|
|
171
|
+
const appName = trigger.appName;
|
|
164
172
|
const results = await this.emit(AgentEvents.TRIGGER_EVENT, {
|
|
165
173
|
triggerName,
|
|
166
174
|
triggerBody,
|
|
167
175
|
});
|
|
168
176
|
const handlerResult = results.find((r) => r !== undefined);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
177
|
+
let memoryUpdate = {};
|
|
178
|
+
let messages: Array<BaseMessage> = [];
|
|
179
|
+
if (handlerResult) {
|
|
180
|
+
memoryUpdate = handlerResult.memory || {};
|
|
181
|
+
messages = handlerResult.messages ?? [];
|
|
182
|
+
} else {
|
|
183
|
+
messages = triggerTypeToDefaultMessage[appName]?.[triggerName]?.(triggerBody) ?? [];
|
|
172
184
|
}
|
|
173
|
-
const
|
|
174
|
-
const
|
|
185
|
+
const triggerInvocation = { appName, triggerName, triggerBody };
|
|
186
|
+
const history = [{
|
|
187
|
+
type: 'triggerInvocation',
|
|
188
|
+
...triggerInvocation
|
|
189
|
+
}];
|
|
175
190
|
console.log(`Invoking trigger ${triggerName} with session ${session}`);
|
|
176
191
|
const config = { configurable: { thread_id: session, recursionLimit: 3 } };
|
|
177
|
-
// const triggerNode = this.compiledGraph.builder.nodes[triggerName];
|
|
178
|
-
// if (!triggerNode) {
|
|
179
|
-
// throw new Error(`Trigger node not found: ${triggerName}`);
|
|
180
|
-
// }
|
|
181
192
|
const state = await this.compiledGraph.getState(config);
|
|
182
193
|
// Resume interruption
|
|
183
194
|
if (state.tasks?.[0]?.interrupts?.length > 0) {
|
|
184
195
|
const res = await this.compiledGraph.invoke(
|
|
185
196
|
new Command({
|
|
186
|
-
resume: { memory: memoryUpdate, messages },
|
|
197
|
+
resume: { memory: memoryUpdate, messages, history, triggerInvocations: [triggerInvocation] },
|
|
187
198
|
}),
|
|
188
199
|
config,
|
|
189
200
|
);
|
|
190
201
|
return res;
|
|
191
202
|
} else {
|
|
192
|
-
const res = await this.compiledGraph.invoke({ messages, memory: memoryUpdate }, config);
|
|
203
|
+
const res = await this.compiledGraph.invoke({ messages, memory: memoryUpdate, history, triggerInvocations: [triggerInvocation] }, config);
|
|
193
204
|
return res;
|
|
194
205
|
}
|
|
195
206
|
}
|
|
@@ -13,6 +13,6 @@ export function createCheckpointSaver(mindedConnection: MindedConnection | null)
|
|
|
13
13
|
return new MemorySaver();
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
console.log(`Using remote checkpoint saver
|
|
16
|
+
console.log(`Using remote checkpoint saver`);
|
|
17
17
|
return new MindedCheckpointSaver(mindedConnection);
|
|
18
18
|
}
|
|
@@ -4,9 +4,12 @@ import { PromptConditionEdge } from '../types/Flows.types';
|
|
|
4
4
|
import { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|
5
5
|
import { AIMessage } from '@langchain/core/messages';
|
|
6
6
|
import { stateAnnotation } from '../types/LangGraph.types';
|
|
7
|
+
import { MemorySaver } from '@langchain/langgraph';
|
|
8
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
7
9
|
|
|
8
10
|
export const createPromptRouter = ({ edges, llm }: { edges: PromptConditionEdge[]; llm: BaseLanguageModel }) => {
|
|
9
11
|
const agent = createReactAgent({
|
|
12
|
+
checkpointer: new MemorySaver(),
|
|
10
13
|
llm,
|
|
11
14
|
tools: [],
|
|
12
15
|
responseFormat: z.object({
|
|
@@ -16,10 +19,11 @@ export const createPromptRouter = ({ edges, llm }: { edges: PromptConditionEdge[
|
|
|
16
19
|
});
|
|
17
20
|
return async (state: typeof stateAnnotation.State) => {
|
|
18
21
|
console.log(`Executing prompt router. Edges: ${JSON.stringify(edges)}`);
|
|
19
|
-
const result = await agent.invoke(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
const result = await agent.invoke(
|
|
23
|
+
{
|
|
24
|
+
messages: [
|
|
25
|
+
new AIMessage({
|
|
26
|
+
content: `You are a router that decides which node to take in a flow based on the current memory state, history and available node ids.
|
|
23
27
|
|
|
24
28
|
Your task is to analyze the current memory state, history and available nodes and determine the most appropriate next node in the flow, the returned nodeId should be only the id without the prompt.
|
|
25
29
|
|
|
@@ -35,9 +39,11 @@ ${JSON.stringify(state.messages)}
|
|
|
35
39
|
|
|
36
40
|
Based on the memory state and available nodes, determine the most appropriate next node id.
|
|
37
41
|
`,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
{ configurable: { thread_id: uuidv4() } },
|
|
46
|
+
);
|
|
41
47
|
try {
|
|
42
48
|
const nextNode = result.structuredResponse.nextNodeId;
|
|
43
49
|
console.log(`Next node: ${nextNode}`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseMessage } from '@langchain/core/messages';
|
|
2
|
+
import { FlowHistory } from '../types/Agent.types';
|
|
2
3
|
|
|
3
4
|
export enum AgentEvents {
|
|
4
5
|
AI_MESSAGE = 'AI_MESSAGE',
|
|
@@ -18,5 +19,5 @@ export type AgentEventRequestPayloads<Memory> = {
|
|
|
18
19
|
|
|
19
20
|
export type AgentEventResponsePayloads<Memory> = {
|
|
20
21
|
[AgentEvents.AI_MESSAGE]: void;
|
|
21
|
-
[AgentEvents.TRIGGER_EVENT]: { messages?: BaseMessage[]; memory?: Memory } | false;
|
|
22
|
+
[AgentEvents.TRIGGER_EVENT]: { messages?: BaseMessage[]; memory?: Memory, history?: FlowHistory[] } | false;
|
|
22
23
|
};
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { tool as langchainTool } from '@langchain/core/tools';
|
|
|
10
10
|
import { AgentEventRequestPayloads, AgentEvents } from '../events/AgentEvents';
|
|
11
11
|
import { EmitSignature } from '../types/Agent.types';
|
|
12
12
|
import { createLlmInstance } from '../llm/createLlmInstance';
|
|
13
|
+
import { MemorySaver } from '@langchain/langgraph';
|
|
14
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
13
15
|
|
|
14
16
|
type AddPromptNodeParams = {
|
|
15
17
|
graph: PreCompiledGraph;
|
|
@@ -35,6 +37,7 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit }: AddPrompt
|
|
|
35
37
|
);
|
|
36
38
|
|
|
37
39
|
const agent = createReactAgent({
|
|
40
|
+
checkpointer: new MemorySaver(),
|
|
38
41
|
llm: llmToUse,
|
|
39
42
|
tools: globalTools,
|
|
40
43
|
responseFormat: z.object({
|
|
@@ -48,9 +51,12 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit }: AddPrompt
|
|
|
48
51
|
- Workflow memory: ${JSON.stringify(state.memory)}
|
|
49
52
|
- Conversation history: ${state.messages.map((message) => `${message.getType()}: ${message.content}`).join('\n')}
|
|
50
53
|
`;
|
|
51
|
-
const result = await agent.invoke(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
const result = await agent.invoke(
|
|
55
|
+
{
|
|
56
|
+
messages: [new SystemMessage(message)],
|
|
57
|
+
},
|
|
58
|
+
{ configurable: { thread_id: uuidv4() } },
|
|
59
|
+
);
|
|
54
60
|
const lastMessage = result.messages[result.messages.length - 1];
|
|
55
61
|
if (lastMessage.getType() === 'ai') {
|
|
56
62
|
await emit(AgentEvents.AI_MESSAGE, {
|
package/src/nodes/addToolNode.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { BaseLanguageModel } from
|
|
2
|
-
import { ToolNode } from
|
|
3
|
-
import { Tool } from
|
|
4
|
-
import { tool as langchainTool } from
|
|
5
|
-
import { PreCompiledGraph, stateAnnotation } from
|
|
6
|
-
import { AIMessage, BaseMessage, SystemMessage, ToolMessage } from
|
|
7
|
-
import { createReactAgent } from
|
|
8
|
-
import { RunnableLike } from
|
|
9
|
-
import { z } from
|
|
1
|
+
import { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|
2
|
+
import { ToolNode } from '../types/Flows.types';
|
|
3
|
+
import { Tool } from '../types/Tools.types';
|
|
4
|
+
import { tool as langchainTool } from '@langchain/core/tools';
|
|
5
|
+
import { PreCompiledGraph, stateAnnotation } from '../types/LangGraph.types';
|
|
6
|
+
import { AIMessage, BaseMessage, SystemMessage, ToolMessage } from '@langchain/core/messages';
|
|
7
|
+
import { createReactAgent } from '@langchain/langgraph/prebuilt';
|
|
8
|
+
import { RunnableLike } from '@langchain/core/runnables';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { MemorySaver } from '@langchain/langgraph';
|
|
11
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
12
|
|
|
11
13
|
export const addToolNode = async <Memory>({
|
|
12
14
|
graph,
|
|
@@ -30,7 +32,7 @@ export const addToolNode = async <Memory>({
|
|
|
30
32
|
|
|
31
33
|
const executeWrapper = async (input: z.infer<typeof matchedTool.input>) => {
|
|
32
34
|
try {
|
|
33
|
-
const response = await matchedTool.execute({ input, memory: state.memory });
|
|
35
|
+
const response = await matchedTool.execute({ input, memory: state.memory, triggerInvocations: state.triggerInvocations });
|
|
34
36
|
return response || {};
|
|
35
37
|
} catch (error) {
|
|
36
38
|
console.error('Error executing tool', error);
|
|
@@ -51,17 +53,18 @@ export const addToolNode = async <Memory>({
|
|
|
51
53
|
${toolNode.prompt && `Tool execution instructions: ${toolNode.prompt}`}
|
|
52
54
|
`;
|
|
53
55
|
const toolCallingAgent = createReactAgent({
|
|
56
|
+
checkpointer: new MemorySaver(),
|
|
54
57
|
llm,
|
|
55
58
|
tools: [tool],
|
|
56
59
|
});
|
|
57
|
-
const response = await toolCallingAgent.invoke({ messages: [new SystemMessage(prompt)] });
|
|
60
|
+
const response = await toolCallingAgent.invoke({ messages: [new SystemMessage(prompt)] }, { configurable: { thread_id: uuidv4() } });
|
|
58
61
|
const toolCallMessage = getLastToolCallMessage(response.messages);
|
|
59
62
|
const toolResponseMessage = getLastToolMessage(response.messages);
|
|
60
63
|
if (!toolCallMessage || !toolResponseMessage) {
|
|
61
64
|
throw new Error('Tool call or tool response message not found');
|
|
62
65
|
}
|
|
63
66
|
const toolMemory = extractToolMemoryResponse<Memory>(toolResponseMessage);
|
|
64
|
-
return { memory: toolMemory, messages: [toolCallMessage, toolResponseMessage] };
|
|
67
|
+
return { memory: toolMemory, messages: [toolCallMessage, toolResponseMessage], triggerInvocations: state.triggerInvocations };
|
|
65
68
|
} catch (error) {
|
|
66
69
|
console.error('Error executing tool node', error);
|
|
67
70
|
throw error;
|
|
@@ -3,10 +3,10 @@ import { TriggerNode } from '../types/Flows.types';
|
|
|
3
3
|
import { PreCompiledGraph } from '../types/LangGraph.types';
|
|
4
4
|
|
|
5
5
|
export const addTriggerNode = async ({ graph, node }: { graph: PreCompiledGraph; node: TriggerNode }) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const callback: RunnableLike = async () => {
|
|
7
|
+
console.log(`Executing trigger node ${node.name}`);
|
|
8
|
+
return;
|
|
9
|
+
};
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
};
|
|
11
|
+
graph.addNode(node.name, callback);
|
|
12
|
+
};
|
package/src/nodes/nodeFactory.ts
CHANGED
|
@@ -3,14 +3,14 @@ import { AppToolNode, JunctionNode, Node, NodeType } from '../types/Flows.types'
|
|
|
3
3
|
import { PreCompiledGraph } from '../types/LangGraph.types';
|
|
4
4
|
import { Tool } from '../types/Tools.types';
|
|
5
5
|
import { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|
6
|
-
import { addTriggerNode } from './addTriggerNode';
|
|
7
6
|
import { addToolNode } from './addToolNode';
|
|
8
7
|
import { addPromptNode } from './addPromptNode';
|
|
9
8
|
import { AgentEventRequestPayloads } from '../events/AgentEvents';
|
|
10
9
|
import { EmitSignature } from '../types/Agent.types';
|
|
10
|
+
import { addTriggerNode } from './addTriggerNode';
|
|
11
11
|
|
|
12
12
|
const addJunctionNode = ({ graph, node }: { graph: PreCompiledGraph; node: JunctionNode }) => {
|
|
13
|
-
const callback: RunnableLike = async () => {};
|
|
13
|
+
const callback: RunnableLike = async () => { };
|
|
14
14
|
graph.addNode(node.name, callback);
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -136,6 +136,7 @@ export class MindedConnection {
|
|
|
136
136
|
console.error('Server error:', error.message);
|
|
137
137
|
|
|
138
138
|
if (error.message.includes('Invalid token')) {
|
|
139
|
+
console.log('Invalid token');
|
|
139
140
|
// Delete saved token on connection error
|
|
140
141
|
if (fs.existsSync(this.tokenPath)) {
|
|
141
142
|
fs.unlinkSync(this.tokenPath);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseMessage, HumanMessage } from "@langchain/core/messages";
|
|
2
|
+
|
|
3
|
+
const triggerTypeToDefaultMessage: Record<string, Record<string, (triggerBody: any) => Array<BaseMessage>>> = {
|
|
4
|
+
["Slack"]: {
|
|
5
|
+
"New Direct Message (Instant)": (triggerBody: any) => [new HumanMessage({ content: triggerBody.text })],
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default triggerTypeToDefaultMessage;
|
package/src/types/Agent.types.ts
CHANGED
|
@@ -8,3 +8,18 @@ export type MindedSDKConfig = {
|
|
|
8
8
|
llm: LLMConfig;
|
|
9
9
|
tools: string[];
|
|
10
10
|
}
|
|
11
|
+
|
|
12
|
+
export enum FlowHistoryType {
|
|
13
|
+
TRIGGER_INVOCATION = 'triggerInvocation',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface FlowHistory {
|
|
17
|
+
type: FlowHistoryType;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface TriggerInvocationHistory extends FlowHistory {
|
|
21
|
+
type: FlowHistoryType.TRIGGER_INVOCATION;
|
|
22
|
+
appName?: string;
|
|
23
|
+
triggerName: string;
|
|
24
|
+
triggerBody: any;
|
|
25
|
+
};
|
package/src/types/Flows.types.ts
CHANGED
|
@@ -36,9 +36,19 @@ export interface BaseTriggerNode extends BaseNode {
|
|
|
36
36
|
type: NodeType.TRIGGER;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
export interface
|
|
39
|
+
export interface BaseAppNode {
|
|
40
|
+
appName: string;
|
|
41
|
+
appImgSrc: string;
|
|
42
|
+
account?: string;
|
|
43
|
+
mockDataInstructions?: string;
|
|
44
|
+
textSentToModel?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface AppTriggerNode extends BaseTriggerNode, BaseAppNode {
|
|
40
48
|
triggerType: TriggerType.APP;
|
|
41
49
|
appTriggerId: string;
|
|
50
|
+
appTriggerName: string;
|
|
51
|
+
promptInstructions?: string;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
export interface WebhookTriggerNode extends BaseTriggerNode {
|
|
@@ -67,9 +77,12 @@ export interface ToolNode extends BaseNode {
|
|
|
67
77
|
prompt: string;
|
|
68
78
|
}
|
|
69
79
|
|
|
70
|
-
export interface AppToolNode extends BaseNode {
|
|
80
|
+
export interface AppToolNode extends BaseNode, BaseAppNode {
|
|
71
81
|
type: NodeType.APP_TOOL;
|
|
72
|
-
prompt
|
|
82
|
+
prompt?: string;
|
|
83
|
+
actionName: string;
|
|
84
|
+
actionKey: string;
|
|
85
|
+
parameters?: Record<string, 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null'>;
|
|
73
86
|
}
|
|
74
87
|
|
|
75
88
|
export type Node = TriggerNode | JunctionNode | ToolNode | AppToolNode | PromptNode;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BaseMessage } from '@langchain/core/messages';
|
|
2
2
|
import { Annotation, CompiledStateGraph, StateGraph } from '@langchain/langgraph';
|
|
3
|
+
import { FlowHistory, TriggerInvocationHistory } from './Agent.types';
|
|
3
4
|
|
|
4
5
|
export const stateAnnotation = Annotation.Root({
|
|
5
6
|
messages: Annotation<Array<BaseMessage>>({
|
|
@@ -10,7 +11,10 @@ export const stateAnnotation = Annotation.Root({
|
|
|
10
11
|
default: () => ({}),
|
|
11
12
|
reducer: (a, b) => ({ ...a, ...b }),
|
|
12
13
|
}),
|
|
13
|
-
|
|
14
|
+
triggerInvocations: Annotation<Array<TriggerInvocationHistory>>({
|
|
15
|
+
default: () => [],
|
|
16
|
+
reducer: (a, b) => a.concat(b),
|
|
17
|
+
}),
|
|
14
18
|
triggerMetadata: Annotation<{
|
|
15
19
|
name: string;
|
|
16
20
|
triggerBody: any;
|
|
@@ -19,6 +23,10 @@ export const stateAnnotation = Annotation.Root({
|
|
|
19
23
|
default: () => null,
|
|
20
24
|
reducer: (a, b) => b,
|
|
21
25
|
}),
|
|
26
|
+
history: Annotation<Array<FlowHistory>>({
|
|
27
|
+
default: () => [],
|
|
28
|
+
reducer: (a, b) => a.concat(b),
|
|
29
|
+
}),
|
|
22
30
|
});
|
|
23
31
|
|
|
24
32
|
export type CompiledGraph = CompiledStateGraph<any, any, string>;
|
package/src/types/Tools.types.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { FlowHistory } from './Agent.types';
|
|
2
3
|
|
|
3
4
|
export interface Tool<Input extends z.ZodSchema, Memory> {
|
|
4
5
|
name: string;
|
|
5
6
|
description: string;
|
|
6
7
|
input: Input;
|
|
7
8
|
isGlobal?: boolean;
|
|
8
|
-
execute: ({ input, memory }: { input: z.infer<Input>; memory: Memory }) => Promise<{ memory?: Partial<Memory>, result?: any } | void>;
|
|
9
|
+
execute: ({ input, memory, triggerInvocations }: { input: z.infer<Input>; memory: Memory; triggerInvocations?: Array<FlowHistory> }) => Promise<{ memory?: Partial<Memory>, result?: any } | void>;
|
|
9
10
|
}
|