@n8n/n8n-nodes-langchain 1.113.1 → 1.114.0
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/nodes/agents/Agent/Agent.node.js +4 -1
- package/dist/nodes/agents/Agent/Agent.node.js.map +1 -1
- package/dist/nodes/agents/Agent/V2/AgentV2.node.js +1 -1
- package/dist/nodes/agents/Agent/V2/AgentV2.node.js.map +1 -1
- package/dist/nodes/agents/Agent/V3/AgentV3.node.js +126 -0
- package/dist/nodes/agents/Agent/V3/AgentV3.node.js.map +1 -0
- package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/description.js +45 -0
- package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/description.js.map +1 -0
- package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/execute.js +407 -0
- package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/execute.js.map +1 -0
- package/dist/nodes/agents/Agent/utils.js +92 -0
- package/dist/nodes/agents/Agent/utils.js.map +1 -0
- package/dist/nodes/vector_store/shared/MemoryManager/MemoryVectorStoreManager.js.map +1 -1
- package/dist/types/nodes.json +1 -0
- package/dist/utils/logWrapper.js +2 -1
- package/dist/utils/logWrapper.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var execute_exports = {};
|
|
30
|
+
__export(execute_exports, {
|
|
31
|
+
toolsAgentExecute: () => toolsAgentExecute
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(execute_exports);
|
|
34
|
+
var import_messages = require("@langchain/core/messages");
|
|
35
|
+
var import_runnables = require("@langchain/core/runnables");
|
|
36
|
+
var import_helpers = require("../../../../../../utils/helpers");
|
|
37
|
+
var import_N8nOutputParser = require("../../../../../../utils/output_parsers/N8nOutputParser");
|
|
38
|
+
var import_agents = require("langchain/agents");
|
|
39
|
+
var import_omit = __toESM(require("lodash/omit"));
|
|
40
|
+
var import_n8n_workflow = require("n8n-workflow");
|
|
41
|
+
var import_node_assert = __toESM(require("node:assert"));
|
|
42
|
+
var import_common = require("../common");
|
|
43
|
+
var import_prompt = require("../prompt");
|
|
44
|
+
function createEngineRequests(ctx, toolCalls, itemIndex) {
|
|
45
|
+
const connectedSubnodes = ctx.getParentNodes(ctx.getNode().name, {
|
|
46
|
+
connectionType: import_n8n_workflow.NodeConnectionTypes.AiTool,
|
|
47
|
+
depth: 1
|
|
48
|
+
});
|
|
49
|
+
return toolCalls.map((toolCall) => ({
|
|
50
|
+
nodeName: connectedSubnodes.find(
|
|
51
|
+
(node) => (0, import_n8n_workflow.nodeNameToToolName)(node.name) === toolCall.tool
|
|
52
|
+
)?.name ?? toolCall.tool,
|
|
53
|
+
input: toolCall.toolInput,
|
|
54
|
+
type: import_n8n_workflow.NodeConnectionTypes.AiTool,
|
|
55
|
+
id: toolCall.toolCallId,
|
|
56
|
+
metadata: {
|
|
57
|
+
itemIndex
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
function createAgentSequence(model, tools, prompt, _options, outputParser, memory, fallbackModel) {
|
|
62
|
+
const agent = (0, import_agents.createToolCallingAgent)({
|
|
63
|
+
llm: model,
|
|
64
|
+
tools,
|
|
65
|
+
prompt,
|
|
66
|
+
streamRunnable: false
|
|
67
|
+
});
|
|
68
|
+
let fallbackAgent;
|
|
69
|
+
if (fallbackModel) {
|
|
70
|
+
fallbackAgent = (0, import_agents.createToolCallingAgent)({
|
|
71
|
+
llm: fallbackModel,
|
|
72
|
+
tools,
|
|
73
|
+
prompt,
|
|
74
|
+
streamRunnable: false
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const runnableAgent = import_runnables.RunnableSequence.from([
|
|
78
|
+
fallbackAgent ? agent.withFallbacks([fallbackAgent]) : agent,
|
|
79
|
+
(0, import_common.getAgentStepsParser)(outputParser, memory),
|
|
80
|
+
import_common.fixEmptyContentMessage
|
|
81
|
+
]);
|
|
82
|
+
runnableAgent.singleAction = true;
|
|
83
|
+
runnableAgent.streamRunnable = false;
|
|
84
|
+
return runnableAgent;
|
|
85
|
+
}
|
|
86
|
+
async function processEventStream(ctx, eventStream, itemIndex, returnIntermediateSteps = false, memory, input) {
|
|
87
|
+
const agentResult = {
|
|
88
|
+
output: ""
|
|
89
|
+
};
|
|
90
|
+
if (returnIntermediateSteps) {
|
|
91
|
+
agentResult.intermediateSteps = [];
|
|
92
|
+
}
|
|
93
|
+
const toolCalls = [];
|
|
94
|
+
ctx.sendChunk("begin", itemIndex);
|
|
95
|
+
for await (const event of eventStream) {
|
|
96
|
+
switch (event.event) {
|
|
97
|
+
case "on_chat_model_stream":
|
|
98
|
+
const chunk = event.data?.chunk;
|
|
99
|
+
if (chunk?.content) {
|
|
100
|
+
const chunkContent = chunk.content;
|
|
101
|
+
let chunkText = "";
|
|
102
|
+
if (Array.isArray(chunkContent)) {
|
|
103
|
+
for (const message of chunkContent) {
|
|
104
|
+
if (message?.type === "text") {
|
|
105
|
+
chunkText += message?.text;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} else if (typeof chunkContent === "string") {
|
|
109
|
+
chunkText = chunkContent;
|
|
110
|
+
}
|
|
111
|
+
ctx.sendChunk("item", itemIndex, chunkText);
|
|
112
|
+
agentResult.output += chunkText;
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
case "on_chat_model_end":
|
|
116
|
+
if (event.data) {
|
|
117
|
+
const chatModelData = event.data;
|
|
118
|
+
const output = chatModelData.output;
|
|
119
|
+
if (output?.tool_calls && output.tool_calls.length > 0) {
|
|
120
|
+
for (const toolCall of output.tool_calls) {
|
|
121
|
+
toolCalls.push({
|
|
122
|
+
tool: toolCall.name,
|
|
123
|
+
toolInput: toolCall.args,
|
|
124
|
+
toolCallId: toolCall.id || "unknown",
|
|
125
|
+
type: toolCall.type || "tool_call",
|
|
126
|
+
log: output.content || `Calling ${toolCall.name} with input: ${JSON.stringify(toolCall.args)}`,
|
|
127
|
+
messageLog: [output]
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
if (returnIntermediateSteps) {
|
|
131
|
+
for (const toolCall of output.tool_calls) {
|
|
132
|
+
agentResult.intermediateSteps.push({
|
|
133
|
+
action: {
|
|
134
|
+
tool: toolCall.name,
|
|
135
|
+
toolInput: toolCall.args,
|
|
136
|
+
log: output.content || `Calling ${toolCall.name} with input: ${JSON.stringify(toolCall.args)}`,
|
|
137
|
+
messageLog: [output],
|
|
138
|
+
// Include the full LLM response
|
|
139
|
+
toolCallId: toolCall.id || "unknown",
|
|
140
|
+
type: toolCall.type || "tool_call"
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
case "on_tool_end":
|
|
149
|
+
if (returnIntermediateSteps && event.data && agentResult.intermediateSteps.length > 0) {
|
|
150
|
+
const toolData = event.data;
|
|
151
|
+
const matchingStep = agentResult.intermediateSteps.find(
|
|
152
|
+
(step) => !step.observation && step.action.tool === event.name
|
|
153
|
+
);
|
|
154
|
+
if (matchingStep) {
|
|
155
|
+
matchingStep.observation = toolData.output || "";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
ctx.sendChunk("end", itemIndex);
|
|
164
|
+
if (memory && input && agentResult.output) {
|
|
165
|
+
await memory.saveContext({ input }, { output: agentResult.output });
|
|
166
|
+
}
|
|
167
|
+
if (toolCalls.length > 0) {
|
|
168
|
+
agentResult.toolCalls = toolCalls;
|
|
169
|
+
}
|
|
170
|
+
return agentResult;
|
|
171
|
+
}
|
|
172
|
+
function buildSteps(response, itemIndex) {
|
|
173
|
+
const steps = [];
|
|
174
|
+
if (response) {
|
|
175
|
+
const responses = response?.actionResponses ?? [];
|
|
176
|
+
for (const tool of responses) {
|
|
177
|
+
if (tool.action?.metadata?.itemIndex !== itemIndex) continue;
|
|
178
|
+
const toolInput = {
|
|
179
|
+
...tool.action.input,
|
|
180
|
+
id: tool.action.id
|
|
181
|
+
};
|
|
182
|
+
if (!toolInput || !tool.data) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const step = steps.find((step2) => step2.action.toolCallId === toolInput.id);
|
|
186
|
+
if (step) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const syntheticAIMessage = new import_messages.AIMessage({
|
|
190
|
+
content: `Calling ${tool.action.nodeName} with input: ${JSON.stringify(toolInput)}`,
|
|
191
|
+
tool_calls: [
|
|
192
|
+
{
|
|
193
|
+
id: toolInput?.id ?? "reconstructed_call",
|
|
194
|
+
name: (0, import_n8n_workflow.nodeNameToToolName)(tool.action.nodeName),
|
|
195
|
+
args: toolInput,
|
|
196
|
+
type: "tool_call"
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
});
|
|
200
|
+
const toolResult = {
|
|
201
|
+
action: {
|
|
202
|
+
tool: (0, import_n8n_workflow.nodeNameToToolName)(tool.action.nodeName),
|
|
203
|
+
toolInput: toolInput.input || {},
|
|
204
|
+
log: toolInput.log || syntheticAIMessage.content,
|
|
205
|
+
messageLog: [syntheticAIMessage],
|
|
206
|
+
toolCallId: toolInput?.id,
|
|
207
|
+
type: toolInput.type || "tool_call"
|
|
208
|
+
},
|
|
209
|
+
observation: JSON.stringify(tool.data)
|
|
210
|
+
};
|
|
211
|
+
steps.push(toolResult);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return steps;
|
|
215
|
+
}
|
|
216
|
+
async function toolsAgentExecute(response) {
|
|
217
|
+
this.logger.debug("Executing Tools Agent V3");
|
|
218
|
+
const returnData = [];
|
|
219
|
+
let request = void 0;
|
|
220
|
+
const items = this.getInputData();
|
|
221
|
+
const batchSize = this.getNodeParameter("options.batching.batchSize", 0, 1);
|
|
222
|
+
const delayBetweenBatches = this.getNodeParameter(
|
|
223
|
+
"options.batching.delayBetweenBatches",
|
|
224
|
+
0,
|
|
225
|
+
0
|
|
226
|
+
);
|
|
227
|
+
const needsFallback = this.getNodeParameter("needsFallback", 0, false);
|
|
228
|
+
const memory = await (0, import_common.getOptionalMemory)(this);
|
|
229
|
+
const model = await (0, import_common.getChatModel)(this, 0);
|
|
230
|
+
(0, import_node_assert.default)(model, "Please connect a model to the Chat Model input");
|
|
231
|
+
const fallbackModel = needsFallback ? await (0, import_common.getChatModel)(this, 1) : null;
|
|
232
|
+
if (needsFallback && !fallbackModel) {
|
|
233
|
+
throw new import_n8n_workflow.NodeOperationError(
|
|
234
|
+
this.getNode(),
|
|
235
|
+
"Please connect a model to the Fallback Model input or disable the fallback option"
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
239
|
+
const batch = items.slice(i, i + batchSize);
|
|
240
|
+
const batchPromises = batch.map(async (_item, batchItemIndex) => {
|
|
241
|
+
const itemIndex = i + batchItemIndex;
|
|
242
|
+
if (response && response?.metadata?.itemIndex === itemIndex) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
const steps = buildSteps(response, itemIndex);
|
|
246
|
+
const input = (0, import_helpers.getPromptInputByType)({
|
|
247
|
+
ctx: this,
|
|
248
|
+
i: itemIndex,
|
|
249
|
+
inputKey: "text",
|
|
250
|
+
promptTypeKey: "promptType"
|
|
251
|
+
});
|
|
252
|
+
if (input === void 0) {
|
|
253
|
+
throw new import_n8n_workflow.NodeOperationError(this.getNode(), 'The "text" parameter is empty.');
|
|
254
|
+
}
|
|
255
|
+
const outputParser2 = await (0, import_N8nOutputParser.getOptionalOutputParser)(this, itemIndex);
|
|
256
|
+
const tools = await (0, import_common.getTools)(this, outputParser2);
|
|
257
|
+
const options = this.getNodeParameter("options", itemIndex, { enableStreaming: true });
|
|
258
|
+
const messages = await (0, import_common.prepareMessages)(this, itemIndex, {
|
|
259
|
+
systemMessage: options.systemMessage,
|
|
260
|
+
passthroughBinaryImages: options.passthroughBinaryImages ?? true,
|
|
261
|
+
outputParser: outputParser2
|
|
262
|
+
});
|
|
263
|
+
const prompt = (0, import_common.preparePrompt)(messages);
|
|
264
|
+
const executor = createAgentSequence(
|
|
265
|
+
model,
|
|
266
|
+
tools,
|
|
267
|
+
prompt,
|
|
268
|
+
options,
|
|
269
|
+
outputParser2,
|
|
270
|
+
memory,
|
|
271
|
+
fallbackModel
|
|
272
|
+
);
|
|
273
|
+
const invokeParams = {
|
|
274
|
+
steps,
|
|
275
|
+
input,
|
|
276
|
+
system_message: options.systemMessage ?? import_prompt.SYSTEM_MESSAGE,
|
|
277
|
+
formatting_instructions: "IMPORTANT: For your response to user, you MUST use the `format_final_json_response` tool with your complete answer formatted according to the required schema. Do not attempt to format the JSON manually - always use this tool. Your response will be rejected if it is not properly formatted through this tool. Only use this tool once you are ready to provide your final answer."
|
|
278
|
+
};
|
|
279
|
+
const executeOptions = { signal: this.getExecutionCancelSignal() };
|
|
280
|
+
const isStreamingAvailable = "isStreaming" in this ? this.isStreaming?.() : void 0;
|
|
281
|
+
if ("isStreaming" in this && options.enableStreaming && isStreamingAvailable && this.getNode().typeVersion >= 2.1) {
|
|
282
|
+
let chatHistory = void 0;
|
|
283
|
+
if (memory) {
|
|
284
|
+
const memoryVariables = await memory.loadMemoryVariables({});
|
|
285
|
+
chatHistory = memoryVariables["chat_history"];
|
|
286
|
+
}
|
|
287
|
+
const eventStream = executor.streamEvents(
|
|
288
|
+
{
|
|
289
|
+
...invokeParams,
|
|
290
|
+
chat_history: chatHistory
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
version: "v2",
|
|
294
|
+
...executeOptions
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
const result = await processEventStream(
|
|
298
|
+
this,
|
|
299
|
+
eventStream,
|
|
300
|
+
itemIndex,
|
|
301
|
+
options.returnIntermediateSteps,
|
|
302
|
+
memory,
|
|
303
|
+
input
|
|
304
|
+
);
|
|
305
|
+
if (result.toolCalls && result.toolCalls.length > 0) {
|
|
306
|
+
const actions = createEngineRequests(this, result.toolCalls, itemIndex);
|
|
307
|
+
return {
|
|
308
|
+
actions,
|
|
309
|
+
metadata: { previousRequests: buildSteps(response, itemIndex) }
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
return result;
|
|
313
|
+
} else {
|
|
314
|
+
let chatHistory = void 0;
|
|
315
|
+
if (memory) {
|
|
316
|
+
const memoryVariables = await memory.loadMemoryVariables({});
|
|
317
|
+
chatHistory = memoryVariables["chat_history"];
|
|
318
|
+
}
|
|
319
|
+
const response2 = await executor.invoke({
|
|
320
|
+
...invokeParams,
|
|
321
|
+
chat_history: chatHistory
|
|
322
|
+
});
|
|
323
|
+
if ("returnValues" in response2) {
|
|
324
|
+
if (memory && input && response2.returnValues.output) {
|
|
325
|
+
let fullOutput = response2.returnValues.output;
|
|
326
|
+
if (steps.length > 0) {
|
|
327
|
+
const toolContext = steps.map(
|
|
328
|
+
(step) => `Tool: ${step.action.tool}, Input: ${JSON.stringify(step.action.toolInput)}, Result: ${step.observation}`
|
|
329
|
+
).join("; ");
|
|
330
|
+
fullOutput = `[Used tools: ${toolContext}] ${fullOutput}`;
|
|
331
|
+
}
|
|
332
|
+
await memory.saveContext({ input }, { output: fullOutput });
|
|
333
|
+
}
|
|
334
|
+
const result = { ...response2.returnValues };
|
|
335
|
+
if (options.returnIntermediateSteps && steps.length > 0) {
|
|
336
|
+
result.intermediateSteps = steps;
|
|
337
|
+
}
|
|
338
|
+
return result;
|
|
339
|
+
}
|
|
340
|
+
const actions = createEngineRequests(this, response2, itemIndex);
|
|
341
|
+
return {
|
|
342
|
+
actions,
|
|
343
|
+
metadata: { previousRequests: buildSteps(response2, itemIndex) }
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
const batchResults = await Promise.allSettled(batchPromises);
|
|
348
|
+
const outputParser = await (0, import_N8nOutputParser.getOptionalOutputParser)(this, 0);
|
|
349
|
+
batchResults.forEach((result, index) => {
|
|
350
|
+
const itemIndex = i + index;
|
|
351
|
+
if (result.status === "rejected") {
|
|
352
|
+
const error = result.reason;
|
|
353
|
+
if (this.continueOnFail()) {
|
|
354
|
+
returnData.push({
|
|
355
|
+
json: { error: error.message },
|
|
356
|
+
pairedItem: { item: itemIndex }
|
|
357
|
+
});
|
|
358
|
+
return;
|
|
359
|
+
} else {
|
|
360
|
+
throw new import_n8n_workflow.NodeOperationError(this.getNode(), error);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const response2 = result.value;
|
|
364
|
+
if ("actions" in response2) {
|
|
365
|
+
if (!request) {
|
|
366
|
+
request = {
|
|
367
|
+
actions: response2.actions,
|
|
368
|
+
metadata: response2.metadata
|
|
369
|
+
};
|
|
370
|
+
} else {
|
|
371
|
+
request.actions.push(...response2.actions);
|
|
372
|
+
}
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (memory && outputParser) {
|
|
376
|
+
const parsedOutput = (0, import_n8n_workflow.jsonParse)(
|
|
377
|
+
response2.output
|
|
378
|
+
);
|
|
379
|
+
response2.output = parsedOutput?.output ?? parsedOutput;
|
|
380
|
+
}
|
|
381
|
+
const itemResult = {
|
|
382
|
+
json: (0, import_omit.default)(
|
|
383
|
+
response2,
|
|
384
|
+
"system_message",
|
|
385
|
+
"formatting_instructions",
|
|
386
|
+
"input",
|
|
387
|
+
"chat_history",
|
|
388
|
+
"agent_scratchpad"
|
|
389
|
+
),
|
|
390
|
+
pairedItem: { item: itemIndex }
|
|
391
|
+
};
|
|
392
|
+
returnData.push(itemResult);
|
|
393
|
+
});
|
|
394
|
+
if (i + batchSize < items.length && delayBetweenBatches > 0) {
|
|
395
|
+
await (0, import_n8n_workflow.sleep)(delayBetweenBatches);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (request) {
|
|
399
|
+
return request;
|
|
400
|
+
}
|
|
401
|
+
return [returnData];
|
|
402
|
+
}
|
|
403
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
404
|
+
0 && (module.exports = {
|
|
405
|
+
toolsAgentExecute
|
|
406
|
+
});
|
|
407
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../nodes/agents/Agent/agents/ToolsAgent/V3/execute.ts"],"sourcesContent":["import type { StreamEvent } from '@langchain/core/dist/tracers/event_stream';\nimport type { IterableReadableStream } from '@langchain/core/dist/utils/stream';\nimport type { BaseChatModel } from '@langchain/core/language_models/chat_models';\nimport type { AIMessageChunk, MessageContentText } from '@langchain/core/messages';\nimport { AIMessage } from '@langchain/core/messages';\nimport type { ChatPromptTemplate } from '@langchain/core/prompts';\nimport { RunnableSequence } from '@langchain/core/runnables';\nimport { getPromptInputByType } from '@utils/helpers';\nimport {\n\tgetOptionalOutputParser,\n\ttype N8nOutputParser,\n} from '@utils/output_parsers/N8nOutputParser';\nimport { type AgentRunnableSequence, createToolCallingAgent } from 'langchain/agents';\nimport type { BaseChatMemory } from 'langchain/memory';\nimport type { DynamicStructuredTool, Tool } from 'langchain/tools';\nimport omit from 'lodash/omit';\nimport {\n\tjsonParse,\n\tNodeConnectionTypes,\n\tnodeNameToToolName,\n\tNodeOperationError,\n\tsleep,\n} from 'n8n-workflow';\nimport type {\n\tEngineRequest,\n\tGenericValue,\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tISupplyDataFunctions,\n\tEngineResponse,\n} from 'n8n-workflow';\nimport assert from 'node:assert';\n\nimport {\n\tfixEmptyContentMessage,\n\tgetAgentStepsParser,\n\tgetChatModel,\n\tgetOptionalMemory,\n\tgetTools,\n\tprepareMessages,\n\tpreparePrompt,\n} from '../common';\nimport { SYSTEM_MESSAGE } from '../prompt';\nimport type { ToolCall } from '@langchain/core/messages/tool';\n\ntype ToolCallRequest = {\n\ttool: string;\n\ttoolInput: Record<string, unknown>;\n\ttoolCallId: string;\n\ttype?: string;\n\tlog?: string;\n\tmessageLog?: unknown[];\n};\n\nfunction createEngineRequests(\n\tctx: IExecuteFunctions | ISupplyDataFunctions,\n\ttoolCalls: ToolCallRequest[],\n\titemIndex: number,\n) {\n\tconst connectedSubnodes = ctx.getParentNodes(ctx.getNode().name, {\n\t\tconnectionType: NodeConnectionTypes.AiTool,\n\t\tdepth: 1,\n\t});\n\treturn toolCalls.map((toolCall) => ({\n\t\tnodeName:\n\t\t\tconnectedSubnodes.find(\n\t\t\t\t(node: { name: string }) => nodeNameToToolName(node.name) === toolCall.tool,\n\t\t\t)?.name ?? toolCall.tool,\n\t\tinput: toolCall.toolInput,\n\t\ttype: NodeConnectionTypes.AiTool,\n\t\tid: toolCall.toolCallId,\n\t\tmetadata: {\n\t\t\titemIndex,\n\t\t},\n\t}));\n}\n\n/**\n * Creates an agent executor with the given configuration\n */\nfunction createAgentSequence(\n\tmodel: BaseChatModel,\n\ttools: Array<DynamicStructuredTool | Tool>,\n\tprompt: ChatPromptTemplate,\n\t_options: { maxIterations?: number; returnIntermediateSteps?: boolean },\n\toutputParser?: N8nOutputParser,\n\tmemory?: BaseChatMemory,\n\tfallbackModel?: BaseChatModel | null,\n) {\n\tconst agent = createToolCallingAgent({\n\t\tllm: model,\n\t\ttools,\n\t\tprompt,\n\t\tstreamRunnable: false,\n\t});\n\n\tlet fallbackAgent: AgentRunnableSequence | undefined;\n\tif (fallbackModel) {\n\t\tfallbackAgent = createToolCallingAgent({\n\t\t\tllm: fallbackModel,\n\t\t\ttools,\n\t\t\tprompt,\n\t\t\tstreamRunnable: false,\n\t\t});\n\t}\n\tconst runnableAgent = RunnableSequence.from([\n\t\tfallbackAgent ? agent.withFallbacks([fallbackAgent]) : agent,\n\t\tgetAgentStepsParser(outputParser, memory),\n\t\tfixEmptyContentMessage,\n\t]) as AgentRunnableSequence;\n\n\trunnableAgent.singleAction = true;\n\trunnableAgent.streamRunnable = false;\n\n\treturn runnableAgent;\n}\n\ntype IntermediateStep = {\n\taction: {\n\t\ttool: string;\n\t\ttoolInput: Record<string, unknown>;\n\t\tlog: string;\n\t\tmessageLog: unknown[];\n\t\ttoolCallId: string;\n\t\ttype: string;\n\t};\n\tobservation?: string;\n};\n\ntype AgentResult = {\n\toutput: string;\n\tintermediateSteps?: IntermediateStep[];\n\ttoolCalls?: ToolCallRequest[];\n};\n\nasync function processEventStream(\n\tctx: IExecuteFunctions,\n\teventStream: IterableReadableStream<StreamEvent>,\n\titemIndex: number,\n\treturnIntermediateSteps: boolean = false,\n\tmemory?: BaseChatMemory,\n\tinput?: string,\n): Promise<AgentResult> {\n\tconst agentResult: AgentResult = {\n\t\toutput: '',\n\t};\n\n\tif (returnIntermediateSteps) {\n\t\tagentResult.intermediateSteps = [];\n\t}\n\n\tconst toolCalls: ToolCallRequest[] = [];\n\n\tctx.sendChunk('begin', itemIndex);\n\tfor await (const event of eventStream) {\n\t\t// Stream chat model tokens as they come in\n\t\tswitch (event.event) {\n\t\t\tcase 'on_chat_model_stream':\n\t\t\t\tconst chunk = event.data?.chunk as AIMessageChunk;\n\t\t\t\tif (chunk?.content) {\n\t\t\t\t\tconst chunkContent = chunk.content;\n\t\t\t\t\tlet chunkText = '';\n\t\t\t\t\tif (Array.isArray(chunkContent)) {\n\t\t\t\t\t\tfor (const message of chunkContent) {\n\t\t\t\t\t\t\tif (message?.type === 'text') {\n\t\t\t\t\t\t\t\tchunkText += (message as MessageContentText)?.text;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (typeof chunkContent === 'string') {\n\t\t\t\t\t\tchunkText = chunkContent;\n\t\t\t\t\t}\n\t\t\t\t\tctx.sendChunk('item', itemIndex, chunkText);\n\n\t\t\t\t\tagentResult.output += chunkText;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'on_chat_model_end':\n\t\t\t\t// Capture full LLM response with tool calls for intermediate steps\n\t\t\t\tif (event.data) {\n\t\t\t\t\tconst chatModelData = event.data as {\n\t\t\t\t\t\toutput?: { tool_calls?: ToolCall[]; content?: string };\n\t\t\t\t\t};\n\t\t\t\t\tconst output = chatModelData.output;\n\n\t\t\t\t\t// Check if this LLM response contains tool calls\n\t\t\t\t\tif (output?.tool_calls && output.tool_calls.length > 0) {\n\t\t\t\t\t\t// Collect tool calls for request building\n\t\t\t\t\t\tfor (const toolCall of output.tool_calls) {\n\t\t\t\t\t\t\ttoolCalls.push({\n\t\t\t\t\t\t\t\ttool: toolCall.name,\n\t\t\t\t\t\t\t\ttoolInput: toolCall.args,\n\t\t\t\t\t\t\t\ttoolCallId: toolCall.id || 'unknown',\n\t\t\t\t\t\t\t\ttype: toolCall.type || 'tool_call',\n\t\t\t\t\t\t\t\tlog:\n\t\t\t\t\t\t\t\t\toutput.content ||\n\t\t\t\t\t\t\t\t\t`Calling ${toolCall.name} with input: ${JSON.stringify(toolCall.args)}`,\n\t\t\t\t\t\t\t\tmessageLog: [output],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Also add to intermediate steps if needed\n\t\t\t\t\t\tif (returnIntermediateSteps) {\n\t\t\t\t\t\t\tfor (const toolCall of output.tool_calls) {\n\t\t\t\t\t\t\t\tagentResult.intermediateSteps!.push({\n\t\t\t\t\t\t\t\t\taction: {\n\t\t\t\t\t\t\t\t\t\ttool: toolCall.name,\n\t\t\t\t\t\t\t\t\t\ttoolInput: toolCall.args,\n\t\t\t\t\t\t\t\t\t\tlog:\n\t\t\t\t\t\t\t\t\t\t\toutput.content ||\n\t\t\t\t\t\t\t\t\t\t\t`Calling ${toolCall.name} with input: ${JSON.stringify(toolCall.args)}`,\n\t\t\t\t\t\t\t\t\t\tmessageLog: [output], // Include the full LLM response\n\t\t\t\t\t\t\t\t\t\ttoolCallId: toolCall.id || 'unknown',\n\t\t\t\t\t\t\t\t\t\ttype: toolCall.type || 'tool_call',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'on_tool_end':\n\t\t\t\t// Capture tool execution results and match with action\n\t\t\t\tif (returnIntermediateSteps && event.data && agentResult.intermediateSteps!.length > 0) {\n\t\t\t\t\tconst toolData = event.data as { output?: string };\n\t\t\t\t\t// Find the matching intermediate step for this tool call\n\t\t\t\t\tconst matchingStep = agentResult.intermediateSteps!.find(\n\t\t\t\t\t\t(step) => !step.observation && step.action.tool === event.name,\n\t\t\t\t\t);\n\t\t\t\t\tif (matchingStep) {\n\t\t\t\t\t\tmatchingStep.observation = toolData.output || '';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tctx.sendChunk('end', itemIndex);\n\n\t// Save conversation to memory if memory is connected\n\tif (memory && input && agentResult.output) {\n\t\tawait memory.saveContext({ input }, { output: agentResult.output });\n\t}\n\n\t// Include collected tool calls in the result\n\tif (toolCalls.length > 0) {\n\t\tagentResult.toolCalls = toolCalls;\n\t}\n\n\treturn agentResult;\n}\n\nexport type RequestResponseMetadata = {\n\titemIndex?: number;\n\tpreviousRequests: ToolCallData[];\n};\n\ntype ToolCallData = {\n\taction: {\n\t\ttool: string;\n\t\ttoolInput: Record<string, unknown>;\n\t\tlog: string | number | true | object;\n\t\ttoolCallId: IDataObject | GenericValue | GenericValue[] | IDataObject[];\n\t\ttype: string | number | true | object;\n\t};\n\tobservation: string;\n};\n\nfunction buildSteps(\n\tresponse: EngineResponse<RequestResponseMetadata> | undefined,\n\titemIndex: number,\n): ToolCallData[] {\n\tconst steps: ToolCallData[] = [];\n\n\tif (response) {\n\t\tconst responses = response?.actionResponses ?? [];\n\t\tfor (const tool of responses) {\n\t\t\tif (tool.action?.metadata?.itemIndex !== itemIndex) continue;\n\t\t\tconst toolInput: IDataObject = {\n\t\t\t\t...tool.action.input,\n\t\t\t\tid: tool.action.id,\n\t\t\t};\n\t\t\tif (!toolInput || !tool.data) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst step = steps.find((step) => step.action.toolCallId === toolInput.id);\n\t\t\tif (step) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Create a synthetic AI message for the messageLog\n\t\t\t// This represents the AI's decision to call the tool\n\t\t\tconst syntheticAIMessage = new AIMessage({\n\t\t\t\tcontent: `Calling ${tool.action.nodeName} with input: ${JSON.stringify(toolInput)}`,\n\t\t\t\ttool_calls: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: (toolInput?.id as string) ?? 'reconstructed_call',\n\t\t\t\t\t\tname: nodeNameToToolName(tool.action.nodeName),\n\t\t\t\t\t\targs: toolInput,\n\t\t\t\t\t\ttype: 'tool_call',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tconst toolResult = {\n\t\t\t\taction: {\n\t\t\t\t\ttool: nodeNameToToolName(tool.action.nodeName),\n\t\t\t\t\ttoolInput: (toolInput.input as IDataObject) || {},\n\t\t\t\t\tlog: toolInput.log || syntheticAIMessage.content,\n\t\t\t\t\tmessageLog: [syntheticAIMessage],\n\t\t\t\t\ttoolCallId: toolInput?.id,\n\t\t\t\t\ttype: toolInput.type || 'tool_call',\n\t\t\t\t},\n\t\t\t\tobservation: JSON.stringify(tool.data),\n\t\t\t};\n\n\t\t\tsteps.push(toolResult);\n\t\t}\n\t}\n\treturn steps;\n}\n\n/* -----------------------------------------------------------\n Main Executor Function\n----------------------------------------------------------- */\n/**\n * The main executor method for the Tools Agent.\n *\n * This function retrieves necessary components (model, memory, tools), prepares the prompt,\n * creates the agent, and processes each input item. The error handling for each item is also\n * managed here based on the node's continueOnFail setting.\n *\n * @param this Execute context. SupplyDataContext is passed when agent is as a tool\n *\n * @returns The array of execution data for all processed items\n */\nexport async function toolsAgentExecute(\n\tthis: IExecuteFunctions | ISupplyDataFunctions,\n\tresponse?: EngineResponse<RequestResponseMetadata>,\n): Promise<INodeExecutionData[][] | EngineRequest<RequestResponseMetadata>> {\n\tthis.logger.debug('Executing Tools Agent V3');\n\n\tconst returnData: INodeExecutionData[] = [];\n\tlet request: EngineRequest<RequestResponseMetadata> | undefined = undefined;\n\n\tconst items = this.getInputData();\n\tconst batchSize = this.getNodeParameter('options.batching.batchSize', 0, 1) as number;\n\tconst delayBetweenBatches = this.getNodeParameter(\n\t\t'options.batching.delayBetweenBatches',\n\t\t0,\n\t\t0,\n\t) as number;\n\tconst needsFallback = this.getNodeParameter('needsFallback', 0, false) as boolean;\n\tconst memory = await getOptionalMemory(this);\n\tconst model = await getChatModel(this, 0);\n\tassert(model, 'Please connect a model to the Chat Model input');\n\tconst fallbackModel = needsFallback ? await getChatModel(this, 1) : null;\n\n\tif (needsFallback && !fallbackModel) {\n\t\tthrow new NodeOperationError(\n\t\t\tthis.getNode(),\n\t\t\t'Please connect a model to the Fallback Model input or disable the fallback option',\n\t\t);\n\t}\n\n\tfor (let i = 0; i < items.length; i += batchSize) {\n\t\tconst batch = items.slice(i, i + batchSize);\n\t\tconst batchPromises = batch.map(async (_item, batchItemIndex) => {\n\t\t\tconst itemIndex = i + batchItemIndex;\n\n\t\t\tif (response && response?.metadata?.itemIndex === itemIndex) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst steps = buildSteps(response, itemIndex);\n\n\t\t\tconst input = getPromptInputByType({\n\t\t\t\tctx: this,\n\t\t\t\ti: itemIndex,\n\t\t\t\tinputKey: 'text',\n\t\t\t\tpromptTypeKey: 'promptType',\n\t\t\t});\n\t\t\tif (input === undefined) {\n\t\t\t\tthrow new NodeOperationError(this.getNode(), 'The \"text\" parameter is empty.');\n\t\t\t}\n\t\t\tconst outputParser = await getOptionalOutputParser(this, itemIndex);\n\t\t\tconst tools = await getTools(this, outputParser);\n\t\t\tconst options = this.getNodeParameter('options', itemIndex, { enableStreaming: true }) as {\n\t\t\t\tsystemMessage?: string;\n\t\t\t\tmaxIterations?: number;\n\t\t\t\treturnIntermediateSteps?: boolean;\n\t\t\t\tpassthroughBinaryImages?: boolean;\n\t\t\t\tenableStreaming?: boolean;\n\t\t\t};\n\n\t\t\t// Prepare the prompt messages and prompt template.\n\t\t\tconst messages = await prepareMessages(this, itemIndex, {\n\t\t\t\tsystemMessage: options.systemMessage,\n\t\t\t\tpassthroughBinaryImages: options.passthroughBinaryImages ?? true,\n\t\t\t\toutputParser,\n\t\t\t});\n\t\t\tconst prompt: ChatPromptTemplate = preparePrompt(messages);\n\n\t\t\t// Create executors for primary and fallback models\n\t\t\tconst executor = createAgentSequence(\n\t\t\t\tmodel,\n\t\t\t\ttools,\n\t\t\t\tprompt,\n\t\t\t\toptions,\n\t\t\t\toutputParser,\n\t\t\t\tmemory,\n\t\t\t\tfallbackModel,\n\t\t\t);\n\t\t\t// Invoke with fallback logic\n\t\t\tconst invokeParams = {\n\t\t\t\tsteps,\n\t\t\t\tinput,\n\t\t\t\tsystem_message: options.systemMessage ?? SYSTEM_MESSAGE,\n\t\t\t\tformatting_instructions:\n\t\t\t\t\t'IMPORTANT: For your response to user, you MUST use the `format_final_json_response` tool with your complete answer formatted according to the required schema. Do not attempt to format the JSON manually - always use this tool. Your response will be rejected if it is not properly formatted through this tool. Only use this tool once you are ready to provide your final answer.',\n\t\t\t};\n\t\t\tconst executeOptions = { signal: this.getExecutionCancelSignal() };\n\n\t\t\t// Check if streaming is actually available\n\t\t\tconst isStreamingAvailable = 'isStreaming' in this ? this.isStreaming?.() : undefined;\n\n\t\t\tif (\n\t\t\t\t'isStreaming' in this &&\n\t\t\t\toptions.enableStreaming &&\n\t\t\t\tisStreamingAvailable &&\n\t\t\t\tthis.getNode().typeVersion >= 2.1\n\t\t\t) {\n\t\t\t\tlet chatHistory = undefined;\n\t\t\t\tif (memory) {\n\t\t\t\t\t// Load memory variables to respect context window length\n\t\t\t\t\tconst memoryVariables = await memory.loadMemoryVariables({});\n\t\t\t\t\tchatHistory = memoryVariables['chat_history'];\n\t\t\t\t}\n\t\t\t\tconst eventStream = executor.streamEvents(\n\t\t\t\t\t{\n\t\t\t\t\t\t...invokeParams,\n\t\t\t\t\t\tchat_history: chatHistory,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tversion: 'v2',\n\t\t\t\t\t\t...executeOptions,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tconst result = await processEventStream(\n\t\t\t\t\tthis,\n\t\t\t\t\teventStream,\n\t\t\t\t\titemIndex,\n\t\t\t\t\toptions.returnIntermediateSteps,\n\t\t\t\t\tmemory,\n\t\t\t\t\tinput,\n\t\t\t\t);\n\n\t\t\t\t// If result contains tool calls, build the request object like the normal flow\n\t\t\t\tif (result.toolCalls && result.toolCalls.length > 0) {\n\t\t\t\t\tconst actions = createEngineRequests(this, result.toolCalls, itemIndex);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tactions,\n\t\t\t\t\t\tmetadata: { previousRequests: buildSteps(response, itemIndex) },\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t} else {\n\t\t\t\t// Handle regular execution\n\t\t\t\tlet chatHistory = undefined;\n\t\t\t\tif (memory) {\n\t\t\t\t\t// Load memory variables to respect context window length\n\t\t\t\t\tconst memoryVariables = await memory.loadMemoryVariables({});\n\t\t\t\t\tchatHistory = memoryVariables['chat_history'];\n\t\t\t\t}\n\t\t\t\tconst response = await executor.invoke({\n\t\t\t\t\t...invokeParams,\n\t\t\t\t\tchat_history: chatHistory,\n\t\t\t\t});\n\n\t\t\t\tif ('returnValues' in response) {\n\t\t\t\t\t// Save conversation to memory including any tool call context\n\t\t\t\t\tif (memory && input && response.returnValues.output) {\n\t\t\t\t\t\t// If there were tool calls in this conversation, include them in the context\n\t\t\t\t\t\tlet fullOutput = response.returnValues.output as string;\n\n\t\t\t\t\t\tif (steps.length > 0) {\n\t\t\t\t\t\t\t// Include tool call information in the conversation context\n\t\t\t\t\t\t\tconst toolContext = steps\n\t\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t\t(step) =>\n\t\t\t\t\t\t\t\t\t\t`Tool: ${step.action.tool}, Input: ${JSON.stringify(step.action.toolInput)}, Result: ${step.observation}`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.join('; ');\n\t\t\t\t\t\t\tfullOutput = `[Used tools: ${toolContext}] ${fullOutput}`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tawait memory.saveContext({ input }, { output: fullOutput });\n\t\t\t\t\t}\n\t\t\t\t\t// Include intermediate steps if requested\n\t\t\t\t\tconst result = { ...response.returnValues };\n\t\t\t\t\tif (options.returnIntermediateSteps && steps.length > 0) {\n\t\t\t\t\t\tresult.intermediateSteps = steps;\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\t// If response contains tool calls, we need to return this in the right format\n\t\t\t\tconst actions = createEngineRequests(this, response, itemIndex);\n\n\t\t\t\treturn {\n\t\t\t\t\tactions,\n\t\t\t\t\tmetadata: { previousRequests: buildSteps(response, itemIndex) },\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\n\t\tconst batchResults = await Promise.allSettled(batchPromises);\n\t\t// This is only used to check if the output parser is connected\n\t\t// so we can parse the output if needed. Actual output parsing is done in the loop above\n\t\tconst outputParser = await getOptionalOutputParser(this, 0);\n\t\tbatchResults.forEach((result, index) => {\n\t\t\tconst itemIndex = i + index;\n\t\t\tif (result.status === 'rejected') {\n\t\t\t\tconst error = result.reason as Error;\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\treturnData.push({\n\t\t\t\t\t\tjson: { error: error.message },\n\t\t\t\t\t\tpairedItem: { item: itemIndex },\n\t\t\t\t\t} as INodeExecutionData);\n\t\t\t\t\treturn;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new NodeOperationError(this.getNode(), error);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst response = result.value;\n\n\t\t\tif ('actions' in response) {\n\t\t\t\tif (!request) {\n\t\t\t\t\trequest = {\n\t\t\t\t\t\tactions: response.actions,\n\t\t\t\t\t\tmetadata: response.metadata,\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\trequest.actions.push(...response.actions);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If memory and outputParser are connected, parse the output.\n\t\t\tif (memory && outputParser) {\n\t\t\t\tconst parsedOutput = jsonParse<{ output: Record<string, unknown> }>(\n\t\t\t\t\tresponse.output as string,\n\t\t\t\t);\n\t\t\t\tresponse.output = parsedOutput?.output ?? parsedOutput;\n\t\t\t}\n\n\t\t\t// Omit internal keys before returning the result.\n\t\t\tconst itemResult: INodeExecutionData = {\n\t\t\t\tjson: omit(\n\t\t\t\t\tresponse,\n\t\t\t\t\t'system_message',\n\t\t\t\t\t'formatting_instructions',\n\t\t\t\t\t'input',\n\t\t\t\t\t'chat_history',\n\t\t\t\t\t'agent_scratchpad',\n\t\t\t\t),\n\t\t\t\tpairedItem: { item: itemIndex },\n\t\t\t};\n\n\t\t\treturnData.push(itemResult);\n\t\t});\n\n\t\tif (i + batchSize < items.length && delayBetweenBatches > 0) {\n\t\t\tawait sleep(delayBetweenBatches);\n\t\t}\n\t}\n\t// Check if we have any Request objects (tool calls)\n\tif (request) {\n\t\treturn request;\n\t}\n\n\t// Otherwise return execution data\n\treturn [returnData];\n}\n"],"mappings":"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","names":["step","assert","outputParser","response","omit"]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var utils_exports = {};
|
|
20
|
+
__export(utils_exports, {
|
|
21
|
+
getInputs: () => getInputs
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(utils_exports);
|
|
24
|
+
function getInputs(hasMainInput, hasOutputParser, needsFallback) {
|
|
25
|
+
const getInputData = (inputs) => {
|
|
26
|
+
return inputs.map(({ type, filter, displayName, required }) => {
|
|
27
|
+
const input = {
|
|
28
|
+
type,
|
|
29
|
+
displayName,
|
|
30
|
+
required,
|
|
31
|
+
maxConnections: ["ai_languageModel", "ai_memory", "ai_outputParser"].includes(type) ? 1 : void 0
|
|
32
|
+
};
|
|
33
|
+
if (filter) {
|
|
34
|
+
input.filter = filter;
|
|
35
|
+
}
|
|
36
|
+
return input;
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
let specialInputs = [
|
|
40
|
+
{
|
|
41
|
+
type: "ai_languageModel",
|
|
42
|
+
displayName: "Chat Model",
|
|
43
|
+
required: true,
|
|
44
|
+
filter: {
|
|
45
|
+
excludedNodes: [
|
|
46
|
+
"@n8n/n8n-nodes-langchain.lmCohere",
|
|
47
|
+
"@n8n/n8n-nodes-langchain.lmOllama",
|
|
48
|
+
"n8n/n8n-nodes-langchain.lmOpenAi",
|
|
49
|
+
"@n8n/n8n-nodes-langchain.lmOpenHuggingFaceInference"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: "ai_languageModel",
|
|
55
|
+
displayName: "Fallback Model",
|
|
56
|
+
required: true,
|
|
57
|
+
filter: {
|
|
58
|
+
excludedNodes: [
|
|
59
|
+
"@n8n/n8n-nodes-langchain.lmCohere",
|
|
60
|
+
"@n8n/n8n-nodes-langchain.lmOllama",
|
|
61
|
+
"n8n/n8n-nodes-langchain.lmOpenAi",
|
|
62
|
+
"@n8n/n8n-nodes-langchain.lmOpenHuggingFaceInference"
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
displayName: "Memory",
|
|
68
|
+
type: "ai_memory"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
displayName: "Tool",
|
|
72
|
+
type: "ai_tool"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
displayName: "Output Parser",
|
|
76
|
+
type: "ai_outputParser"
|
|
77
|
+
}
|
|
78
|
+
];
|
|
79
|
+
if (hasOutputParser === false) {
|
|
80
|
+
specialInputs = specialInputs.filter((input) => input.type !== "ai_outputParser");
|
|
81
|
+
}
|
|
82
|
+
if (needsFallback === false) {
|
|
83
|
+
specialInputs = specialInputs.filter((input) => input.displayName !== "Fallback Model");
|
|
84
|
+
}
|
|
85
|
+
const mainInputs = hasMainInput ? ["main"] : [];
|
|
86
|
+
return [...mainInputs, ...getInputData(specialInputs)];
|
|
87
|
+
}
|
|
88
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
89
|
+
0 && (module.exports = {
|
|
90
|
+
getInputs
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../nodes/agents/Agent/utils.ts"],"sourcesContent":["// Function used in the inputs expression to figure out which inputs to\n\nimport {\n\ttype INodeInputConfiguration,\n\ttype INodeInputFilter,\n\ttype NodeConnectionType,\n} from 'n8n-workflow';\n\n// display based on the agent type\nexport function getInputs(\n\thasMainInput?: boolean,\n\thasOutputParser?: boolean,\n\tneedsFallback?: boolean,\n): Array<NodeConnectionType | INodeInputConfiguration> {\n\tinterface SpecialInput {\n\t\ttype: NodeConnectionType;\n\t\tfilter?: INodeInputFilter;\n\t\tdisplayName: string;\n\t\trequired?: boolean;\n\t}\n\n\tconst getInputData = (\n\t\tinputs: SpecialInput[],\n\t): Array<NodeConnectionType | INodeInputConfiguration> => {\n\t\treturn inputs.map(({ type, filter, displayName, required }) => {\n\t\t\tconst input: INodeInputConfiguration = {\n\t\t\t\ttype,\n\t\t\t\tdisplayName,\n\t\t\t\trequired,\n\t\t\t\tmaxConnections: ['ai_languageModel', 'ai_memory', 'ai_outputParser'].includes(type)\n\t\t\t\t\t? 1\n\t\t\t\t\t: undefined,\n\t\t\t};\n\n\t\t\tif (filter) {\n\t\t\t\tinput.filter = filter;\n\t\t\t}\n\n\t\t\treturn input;\n\t\t});\n\t};\n\n\tlet specialInputs: SpecialInput[] = [\n\t\t{\n\t\t\ttype: 'ai_languageModel',\n\t\t\tdisplayName: 'Chat Model',\n\t\t\trequired: true,\n\t\t\tfilter: {\n\t\t\t\texcludedNodes: [\n\t\t\t\t\t'@n8n/n8n-nodes-langchain.lmCohere',\n\t\t\t\t\t'@n8n/n8n-nodes-langchain.lmOllama',\n\t\t\t\t\t'n8n/n8n-nodes-langchain.lmOpenAi',\n\t\t\t\t\t'@n8n/n8n-nodes-langchain.lmOpenHuggingFaceInference',\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttype: 'ai_languageModel',\n\t\t\tdisplayName: 'Fallback Model',\n\t\t\trequired: true,\n\t\t\tfilter: {\n\t\t\t\texcludedNodes: [\n\t\t\t\t\t'@n8n/n8n-nodes-langchain.lmCohere',\n\t\t\t\t\t'@n8n/n8n-nodes-langchain.lmOllama',\n\t\t\t\t\t'n8n/n8n-nodes-langchain.lmOpenAi',\n\t\t\t\t\t'@n8n/n8n-nodes-langchain.lmOpenHuggingFaceInference',\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Memory',\n\t\t\ttype: 'ai_memory',\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Tool',\n\t\t\ttype: 'ai_tool',\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Output Parser',\n\t\t\ttype: 'ai_outputParser',\n\t\t},\n\t];\n\n\tif (hasOutputParser === false) {\n\t\tspecialInputs = specialInputs.filter((input) => input.type !== 'ai_outputParser');\n\t}\n\tif (needsFallback === false) {\n\t\tspecialInputs = specialInputs.filter((input) => input.displayName !== 'Fallback Model');\n\t}\n\n\t// Note cannot use NodeConnectionType.Main\n\t// otherwise expression won't evaluate correctly on the FE\n\tconst mainInputs = hasMainInput ? ['main' as NodeConnectionType] : [];\n\treturn [...mainInputs, ...getInputData(specialInputs)];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AASO,SAAS,UACf,cACA,iBACA,eACsD;AAQtD,QAAM,eAAe,CACpB,WACyD;AACzD,WAAO,OAAO,IAAI,CAAC,EAAE,MAAM,QAAQ,aAAa,SAAS,MAAM;AAC9D,YAAM,QAAiC;AAAA,QACtC;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAgB,CAAC,oBAAoB,aAAa,iBAAiB,EAAE,SAAS,IAAI,IAC/E,IACA;AAAA,MACJ;AAEA,UAAI,QAAQ;AACX,cAAM,SAAS;AAAA,MAChB;AAEA,aAAO;AAAA,IACR,CAAC;AAAA,EACF;AAEA,MAAI,gBAAgC;AAAA,IACnC;AAAA,MACC,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,MACV,QAAQ;AAAA,QACP,eAAe;AAAA,UACd;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,MACV,QAAQ;AAAA,QACP,eAAe;AAAA,UACd;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,aAAa;AAAA,MACb,MAAM;AAAA,IACP;AAAA,IACA;AAAA,MACC,aAAa;AAAA,MACb,MAAM;AAAA,IACP;AAAA,IACA;AAAA,MACC,aAAa;AAAA,MACb,MAAM;AAAA,IACP;AAAA,EACD;AAEA,MAAI,oBAAoB,OAAO;AAC9B,oBAAgB,cAAc,OAAO,CAAC,UAAU,MAAM,SAAS,iBAAiB;AAAA,EACjF;AACA,MAAI,kBAAkB,OAAO;AAC5B,oBAAgB,cAAc,OAAO,CAAC,UAAU,MAAM,gBAAgB,gBAAgB;AAAA,EACvF;AAIA,QAAM,aAAa,eAAe,CAAC,MAA4B,IAAI,CAAC;AACpE,SAAO,CAAC,GAAG,YAAY,GAAG,aAAa,aAAa,CAAC;AACtD;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../nodes/vector_store/shared/MemoryManager/MemoryVectorStoreManager.ts"],"sourcesContent":["import type { Document } from '@langchain/core/documents';\nimport type { Embeddings } from '@langchain/core/embeddings';\nimport { MemoryVectorStore } from 'langchain/vectorstores/memory';\nimport type { Logger } from 'n8n-workflow';\n\nimport { getConfig, mbToBytes, hoursToMs } from './config';\nimport { MemoryCalculator } from './MemoryCalculator';\nimport { StoreCleanupService } from './StoreCleanupService';\nimport type { VectorStoreMetadata, VectorStoreStats } from './types';\n\n/**\n * Manages in-memory vector stores with memory limits and auto-cleanup\n */\nexport class MemoryVectorStoreManager {\n\tprivate static instance: MemoryVectorStoreManager | null = null;\n\n\t// Storage\n\tprotected vectorStoreBuffer: Map<string, MemoryVectorStore>;\n\n\tprotected storeMetadata: Map<string, VectorStoreMetadata>;\n\n\tprotected memoryUsageBytes: number = 0;\n\n\t// Dependencies\n\tprotected memoryCalculator: MemoryCalculator;\n\n\tprotected cleanupService: StoreCleanupService;\n\n\tprotected static logger: Logger;\n\n\t// Config values\n\tprotected maxMemorySizeBytes: number;\n\n\tprotected inactiveTtlMs: number;\n\n\t// Inactive TTL cleanup timer\n\tprotected ttlCleanupIntervalId: NodeJS.Timeout | null = null;\n\n\tprotected constructor(\n\t\tprotected embeddings: Embeddings,\n\t\tprotected logger: Logger,\n\t) {\n\t\t// Initialize storage\n\t\tthis.vectorStoreBuffer = new Map();\n\t\tthis.storeMetadata = new Map();\n\t\tthis.logger = logger;\n\n\t\tconst config = getConfig();\n\t\tthis.maxMemorySizeBytes = mbToBytes(config.maxMemoryMB);\n\t\tthis.inactiveTtlMs = hoursToMs(config.ttlHours);\n\n\t\t// Initialize services\n\t\tthis.memoryCalculator = new MemoryCalculator();\n\t\tthis.cleanupService = new StoreCleanupService(\n\t\t\tthis.maxMemorySizeBytes,\n\t\t\tthis.inactiveTtlMs,\n\t\t\tthis.vectorStoreBuffer,\n\t\t\tthis.storeMetadata,\n\t\t\tthis.handleCleanup.bind(this),\n\t\t);\n\n\t\tthis.setupTtlCleanup();\n\t}\n\n\t/**\n\t * Get singleton instance\n\t */\n\tstatic getInstance(embeddings: Embeddings, logger: Logger): MemoryVectorStoreManager {\n\t\tif (!MemoryVectorStoreManager.instance) {\n\t\t\tMemoryVectorStoreManager.instance = new MemoryVectorStoreManager(embeddings, logger);\n\t\t} else {\n\t\t\t// We need to update the embeddings in the existing instance.\n\t\t\t// This is important as embeddings instance is wrapped in a logWrapper,\n\t\t\t// which relies on supplyDataFunctions context which changes on each workflow run\n\t\t\tMemoryVectorStoreManager.instance.embeddings = embeddings;\n\t\t\tMemoryVectorStoreManager.instance.vectorStoreBuffer.forEach((vectorStoreInstance) => {\n\t\t\t\tvectorStoreInstance.embeddings = embeddings;\n\t\t\t});\n\t\t}\n\n\t\treturn MemoryVectorStoreManager.instance;\n\t}\n\n\t/**\n\t * Set up timer for TTL-based cleanup\n\t */\n\tprivate setupTtlCleanup(): void {\n\t\t// Skip setup if TTL is disabled\n\t\tif (this.inactiveTtlMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Cleanup check interval (run every hour)\n\t\tconst CLEANUP_INTERVAL_MS = 60 * 60 * 1000;\n\n\t\t// Clear any existing interval\n\t\tif (this.ttlCleanupIntervalId) {\n\t\t\tclearInterval(this.ttlCleanupIntervalId);\n\t\t}\n\n\t\t// Setup new interval for TTL cleanup\n\t\tthis.ttlCleanupIntervalId = setInterval(() => {\n\t\t\tthis.cleanupService.cleanupInactiveStores();\n\t\t}, CLEANUP_INTERVAL_MS);\n\t}\n\n\t/**\n\t * Handle cleanup events from the cleanup service\n\t */\n\tprivate handleCleanup(removedKeys: string[], freedBytes: number, reason: 'ttl' | 'memory'): void {\n\t\t// Update total memory usage\n\t\tthis.memoryUsageBytes -= freedBytes;\n\n\t\t// Log cleanup event\n\t\tif (reason === 'ttl') {\n\t\t\tconst ttlHours = Math.round(this.inactiveTtlMs / (60 * 60 * 1000));\n\t\t\tthis.logger.info(\n\t\t\t\t`TTL cleanup: removed ${removedKeys.length} inactive vector stores (${ttlHours}h TTL) to free ${Math.round(freedBytes / (1024 * 1024))}MB of memory`,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.logger.info(\n\t\t\t\t`Memory cleanup: removed ${removedKeys.length} oldest vector stores to free ${Math.round(freedBytes / (1024 * 1024))}MB of memory`,\n\t\t\t);\n\t\t}\n\t}\n\n\tgetMemoryKeysList(): string[] {\n\t\treturn Array.from(this.vectorStoreBuffer.keys());\n\t}\n\n\t/**\n\t * Get or create a vector store by key\n\t */\n\tasync getVectorStore(memoryKey: string): Promise<MemoryVectorStore> {\n\t\tlet vectorStoreInstance = this.vectorStoreBuffer.get(memoryKey);\n\n\t\tif (!vectorStoreInstance) {\n\t\t\tvectorStoreInstance = await MemoryVectorStore.fromExistingIndex(this.embeddings);\n\t\t\tthis.vectorStoreBuffer.set(memoryKey, vectorStoreInstance);\n\n\t\t\tthis.storeMetadata.set(memoryKey, {\n\t\t\t\tsize: 0,\n\t\t\t\tcreatedAt: new Date(),\n\t\t\t\tlastAccessed: new Date(),\n\t\t\t});\n\t\t} else {\n\t\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\t\tif (metadata) {\n\t\t\t\tmetadata.lastAccessed = new Date();\n\t\t\t}\n\t\t}\n\n\t\treturn vectorStoreInstance;\n\t}\n\n\t/**\n\t * Reset a store's metadata when it's cleared\n\t */\n\tprotected clearStoreMetadata(memoryKey: string): void {\n\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\tif (metadata) {\n\t\t\tthis.memoryUsageBytes -= metadata.size;\n\t\t\tmetadata.size = 0;\n\t\t\tmetadata.lastAccessed = new Date();\n\t\t}\n\t}\n\n\t/**\n\t * Get memory usage in bytes\n\t */\n\tgetMemoryUsage(): number {\n\t\treturn this.memoryUsageBytes;\n\t}\n\n\t/**\n\t * Get memory usage as a formatted string (MB)\n\t */\n\tgetMemoryUsageFormatted(): string {\n\t\treturn `${Math.round(this.memoryUsageBytes / (1024 * 1024))}MB`;\n\t}\n\n\t/**\n\t * Recalculate memory usage from actual vector store contents\n\t * This ensures tracking accuracy for large stores\n\t */\n\trecalculateMemoryUsage(): void {\n\t\tthis.memoryUsageBytes = 0;\n\n\t\t// Recalculate for each store\n\t\tfor (const [key, vectorStore] of this.vectorStoreBuffer.entries()) {\n\t\t\tconst storeSize = this.memoryCalculator.calculateVectorStoreSize(vectorStore);\n\n\t\t\t// Update metadata\n\t\t\tconst metadata = this.storeMetadata.get(key);\n\t\t\tif (metadata) {\n\t\t\t\tmetadata.size = storeSize;\n\t\t\t\tthis.memoryUsageBytes += storeSize;\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.debug(`Recalculated vector store memory: ${this.getMemoryUsageFormatted()}`);\n\t}\n\n\t/**\n\t * Add documents to a vector store\n\t */\n\tasync addDocuments(\n\t\tmemoryKey: string,\n\t\tdocuments: Document[],\n\t\tclearStore?: boolean,\n\t): Promise<void> {\n\t\tif (clearStore) {\n\t\t\tthis.clearStoreMetadata(memoryKey);\n\t\t\tthis.vectorStoreBuffer.delete(memoryKey);\n\t\t}\n\n\t\t// Fast batch estimation instead of per-document calculation\n\t\tconst estimatedAddedSize = this.memoryCalculator.estimateBatchSize(documents);\n\n\t\t// Clean up old stores if necessary\n\t\tthis.cleanupService.cleanupOldestStores(estimatedAddedSize);\n\n\t\tconst vectorStoreInstance = await this.getVectorStore(memoryKey);\n\n\t\t// Get vector count before adding documents\n\t\tconst vectorCountBefore = vectorStoreInstance.memoryVectors?.length || 0;\n\n\t\tawait vectorStoreInstance.addDocuments(documents);\n\n\t\t// Update store metadata and memory tracking\n\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\tif (metadata) {\n\t\t\tmetadata.size += estimatedAddedSize;\n\t\t\tmetadata.lastAccessed = new Date();\n\t\t\tthis.memoryUsageBytes += estimatedAddedSize;\n\t\t}\n\n\t\t// Get updated vector count\n\t\tconst vectorCount = vectorStoreInstance.memoryVectors?.length || 0;\n\n\t\t// Periodically recalculate actual memory usage to avoid drift\n\t\tif (\n\t\t\t(vectorCount > 0 && vectorCount % 100 === 0) ||\n\t\t\tdocuments.length > 20 ||\n\t\t\t(vectorCountBefore === 0 && vectorCount > 0)\n\t\t) {\n\t\t\tthis.recalculateMemoryUsage();\n\t\t}\n\n\t\t// Logging memory usage\n\t\tconst maxMemoryMB =\n\t\t\tthis.maxMemorySizeBytes > 0\n\t\t\t\t? (this.maxMemorySizeBytes / (1024 * 1024)).toFixed(0)\n\t\t\t\t: 'unlimited';\n\n\t\tthis.logger.debug(\n\t\t\t`Vector store memory: ${this.getMemoryUsageFormatted()}/${maxMemoryMB}MB (${vectorCount} vectors in ${this.vectorStoreBuffer.size} stores)`,\n\t\t);\n\t}\n\n\t/**\n\t * Get statistics about the vector store memory usage\n\t */\n\tgetStats(): VectorStoreStats {\n\t\tconst now = Date.now();\n\t\tlet inactiveStoreCount = 0;\n\n\t\t// Always recalculate when getting stats to ensure accuracy\n\t\tthis.recalculateMemoryUsage();\n\n\t\tconst stats: VectorStoreStats = {\n\t\t\ttotalSizeBytes: this.memoryUsageBytes,\n\t\t\ttotalSizeMB: Math.round((this.memoryUsageBytes / (1024 * 1024)) * 100) / 100,\n\t\t\tpercentOfLimit:\n\t\t\t\tthis.maxMemorySizeBytes > 0\n\t\t\t\t\t? Math.round((this.memoryUsageBytes / this.maxMemorySizeBytes) * 100)\n\t\t\t\t\t: 0,\n\t\t\tmaxMemoryMB: this.maxMemorySizeBytes > 0 ? this.maxMemorySizeBytes / (1024 * 1024) : -1, // -1 indicates unlimited\n\t\t\tstoreCount: this.vectorStoreBuffer.size,\n\t\t\tinactiveStoreCount: 0,\n\t\t\tttlHours: this.inactiveTtlMs > 0 ? this.inactiveTtlMs / (60 * 60 * 1000) : -1, // -1 indicates disabled\n\t\t\tstores: {},\n\t\t};\n\n\t\t// Add stats for each store\n\t\tfor (const [key, metadata] of this.storeMetadata.entries()) {\n\t\t\tconst store = this.vectorStoreBuffer.get(key);\n\n\t\t\tif (store) {\n\t\t\t\tconst lastAccessedTime = metadata.lastAccessed.getTime();\n\t\t\t\tconst inactiveTimeMs = now - lastAccessedTime;\n\t\t\t\tconst isInactive = this.cleanupService.isStoreInactive(metadata);\n\n\t\t\t\tif (isInactive) {\n\t\t\t\t\tinactiveStoreCount++;\n\t\t\t\t}\n\n\t\t\t\tstats.stores[key] = {\n\t\t\t\t\tsizeBytes: metadata.size,\n\t\t\t\t\tsizeMB: Math.round((metadata.size / (1024 * 1024)) * 100) / 100,\n\t\t\t\t\tpercentOfTotal: Math.round((metadata.size / this.memoryUsageBytes) * 100) || 0,\n\t\t\t\t\tvectors: store.memoryVectors?.length || 0,\n\t\t\t\t\tcreatedAt: metadata.createdAt.toISOString(),\n\t\t\t\t\tlastAccessed: metadata.lastAccessed.toISOString(),\n\t\t\t\t\tinactive: isInactive,\n\t\t\t\t\tinactiveForHours: Math.round(inactiveTimeMs / (60 * 60 * 1000)),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tstats.inactiveStoreCount = inactiveStoreCount;\n\n\t\treturn stats;\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../nodes/vector_store/shared/MemoryManager/MemoryVectorStoreManager.ts"],"sourcesContent":["import type { Document } from '@langchain/core/documents';\nimport type { Embeddings } from '@langchain/core/embeddings';\nimport type { OpenAIEmbeddings, AzureOpenAIEmbeddings } from '@langchain/openai';\nimport { MemoryVectorStore } from 'langchain/vectorstores/memory';\nimport type { Logger } from 'n8n-workflow';\n\nimport { getConfig, mbToBytes, hoursToMs } from './config';\nimport { MemoryCalculator } from './MemoryCalculator';\nimport { StoreCleanupService } from './StoreCleanupService';\nimport type { VectorStoreMetadata, VectorStoreStats } from './types';\n\n/**\n * Manages in-memory vector stores with memory limits and auto-cleanup\n */\nexport class MemoryVectorStoreManager {\n\tprivate static instance: MemoryVectorStoreManager | null = null;\n\n\t// Storage\n\tprotected vectorStoreBuffer: Map<string, MemoryVectorStore>;\n\n\tprotected storeMetadata: Map<string, VectorStoreMetadata>;\n\n\tprotected memoryUsageBytes: number = 0;\n\n\t// Dependencies\n\tprotected memoryCalculator: MemoryCalculator;\n\n\tprotected cleanupService: StoreCleanupService;\n\n\tprotected static logger: Logger;\n\n\t// Config values\n\tprotected maxMemorySizeBytes: number;\n\n\tprotected inactiveTtlMs: number;\n\n\t// Inactive TTL cleanup timer\n\tprotected ttlCleanupIntervalId: NodeJS.Timeout | null = null;\n\n\tprotected constructor(\n\t\tprotected embeddings: Embeddings | OpenAIEmbeddings | AzureOpenAIEmbeddings,\n\t\tprotected logger: Logger,\n\t) {\n\t\t// Initialize storage\n\t\tthis.vectorStoreBuffer = new Map();\n\t\tthis.storeMetadata = new Map();\n\t\tthis.logger = logger;\n\n\t\tconst config = getConfig();\n\t\tthis.maxMemorySizeBytes = mbToBytes(config.maxMemoryMB);\n\t\tthis.inactiveTtlMs = hoursToMs(config.ttlHours);\n\n\t\t// Initialize services\n\t\tthis.memoryCalculator = new MemoryCalculator();\n\t\tthis.cleanupService = new StoreCleanupService(\n\t\t\tthis.maxMemorySizeBytes,\n\t\t\tthis.inactiveTtlMs,\n\t\t\tthis.vectorStoreBuffer,\n\t\t\tthis.storeMetadata,\n\t\t\tthis.handleCleanup.bind(this),\n\t\t);\n\n\t\tthis.setupTtlCleanup();\n\t}\n\n\t/**\n\t * Get singleton instance\n\t */\n\tstatic getInstance(\n\t\tembeddings: Embeddings | OpenAIEmbeddings | AzureOpenAIEmbeddings,\n\t\tlogger: Logger,\n\t): MemoryVectorStoreManager {\n\t\tif (!MemoryVectorStoreManager.instance) {\n\t\t\tMemoryVectorStoreManager.instance = new MemoryVectorStoreManager(embeddings, logger);\n\t\t} else {\n\t\t\t// We need to update the embeddings in the existing instance.\n\t\t\t// This is important as embeddings instance is wrapped in a logWrapper,\n\t\t\t// which relies on supplyDataFunctions context which changes on each workflow run\n\t\t\tMemoryVectorStoreManager.instance.embeddings = embeddings;\n\t\t\tMemoryVectorStoreManager.instance.vectorStoreBuffer.forEach((vectorStoreInstance) => {\n\t\t\t\tvectorStoreInstance.embeddings = embeddings;\n\t\t\t});\n\t\t}\n\n\t\treturn MemoryVectorStoreManager.instance;\n\t}\n\n\t/**\n\t * Set up timer for TTL-based cleanup\n\t */\n\tprivate setupTtlCleanup(): void {\n\t\t// Skip setup if TTL is disabled\n\t\tif (this.inactiveTtlMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Cleanup check interval (run every hour)\n\t\tconst CLEANUP_INTERVAL_MS = 60 * 60 * 1000;\n\n\t\t// Clear any existing interval\n\t\tif (this.ttlCleanupIntervalId) {\n\t\t\tclearInterval(this.ttlCleanupIntervalId);\n\t\t}\n\n\t\t// Setup new interval for TTL cleanup\n\t\tthis.ttlCleanupIntervalId = setInterval(() => {\n\t\t\tthis.cleanupService.cleanupInactiveStores();\n\t\t}, CLEANUP_INTERVAL_MS);\n\t}\n\n\t/**\n\t * Handle cleanup events from the cleanup service\n\t */\n\tprivate handleCleanup(removedKeys: string[], freedBytes: number, reason: 'ttl' | 'memory'): void {\n\t\t// Update total memory usage\n\t\tthis.memoryUsageBytes -= freedBytes;\n\n\t\t// Log cleanup event\n\t\tif (reason === 'ttl') {\n\t\t\tconst ttlHours = Math.round(this.inactiveTtlMs / (60 * 60 * 1000));\n\t\t\tthis.logger.info(\n\t\t\t\t`TTL cleanup: removed ${removedKeys.length} inactive vector stores (${ttlHours}h TTL) to free ${Math.round(freedBytes / (1024 * 1024))}MB of memory`,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.logger.info(\n\t\t\t\t`Memory cleanup: removed ${removedKeys.length} oldest vector stores to free ${Math.round(freedBytes / (1024 * 1024))}MB of memory`,\n\t\t\t);\n\t\t}\n\t}\n\n\tgetMemoryKeysList(): string[] {\n\t\treturn Array.from(this.vectorStoreBuffer.keys());\n\t}\n\n\t/**\n\t * Get or create a vector store by key\n\t */\n\tasync getVectorStore(memoryKey: string): Promise<MemoryVectorStore> {\n\t\tlet vectorStoreInstance = this.vectorStoreBuffer.get(memoryKey);\n\n\t\tif (!vectorStoreInstance) {\n\t\t\tvectorStoreInstance = await MemoryVectorStore.fromExistingIndex(this.embeddings);\n\t\t\tthis.vectorStoreBuffer.set(memoryKey, vectorStoreInstance);\n\n\t\t\tthis.storeMetadata.set(memoryKey, {\n\t\t\t\tsize: 0,\n\t\t\t\tcreatedAt: new Date(),\n\t\t\t\tlastAccessed: new Date(),\n\t\t\t});\n\t\t} else {\n\t\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\t\tif (metadata) {\n\t\t\t\tmetadata.lastAccessed = new Date();\n\t\t\t}\n\t\t}\n\n\t\treturn vectorStoreInstance;\n\t}\n\n\t/**\n\t * Reset a store's metadata when it's cleared\n\t */\n\tprotected clearStoreMetadata(memoryKey: string): void {\n\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\tif (metadata) {\n\t\t\tthis.memoryUsageBytes -= metadata.size;\n\t\t\tmetadata.size = 0;\n\t\t\tmetadata.lastAccessed = new Date();\n\t\t}\n\t}\n\n\t/**\n\t * Get memory usage in bytes\n\t */\n\tgetMemoryUsage(): number {\n\t\treturn this.memoryUsageBytes;\n\t}\n\n\t/**\n\t * Get memory usage as a formatted string (MB)\n\t */\n\tgetMemoryUsageFormatted(): string {\n\t\treturn `${Math.round(this.memoryUsageBytes / (1024 * 1024))}MB`;\n\t}\n\n\t/**\n\t * Recalculate memory usage from actual vector store contents\n\t * This ensures tracking accuracy for large stores\n\t */\n\trecalculateMemoryUsage(): void {\n\t\tthis.memoryUsageBytes = 0;\n\n\t\t// Recalculate for each store\n\t\tfor (const [key, vectorStore] of this.vectorStoreBuffer.entries()) {\n\t\t\tconst storeSize = this.memoryCalculator.calculateVectorStoreSize(vectorStore);\n\n\t\t\t// Update metadata\n\t\t\tconst metadata = this.storeMetadata.get(key);\n\t\t\tif (metadata) {\n\t\t\t\tmetadata.size = storeSize;\n\t\t\t\tthis.memoryUsageBytes += storeSize;\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.debug(`Recalculated vector store memory: ${this.getMemoryUsageFormatted()}`);\n\t}\n\n\t/**\n\t * Add documents to a vector store\n\t */\n\tasync addDocuments(\n\t\tmemoryKey: string,\n\t\tdocuments: Document[],\n\t\tclearStore?: boolean,\n\t): Promise<void> {\n\t\tif (clearStore) {\n\t\t\tthis.clearStoreMetadata(memoryKey);\n\t\t\tthis.vectorStoreBuffer.delete(memoryKey);\n\t\t}\n\n\t\t// Fast batch estimation instead of per-document calculation\n\t\tconst estimatedAddedSize = this.memoryCalculator.estimateBatchSize(documents);\n\n\t\t// Clean up old stores if necessary\n\t\tthis.cleanupService.cleanupOldestStores(estimatedAddedSize);\n\n\t\tconst vectorStoreInstance = await this.getVectorStore(memoryKey);\n\n\t\t// Get vector count before adding documents\n\t\tconst vectorCountBefore = vectorStoreInstance.memoryVectors?.length || 0;\n\n\t\tawait vectorStoreInstance.addDocuments(documents);\n\n\t\t// Update store metadata and memory tracking\n\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\tif (metadata) {\n\t\t\tmetadata.size += estimatedAddedSize;\n\t\t\tmetadata.lastAccessed = new Date();\n\t\t\tthis.memoryUsageBytes += estimatedAddedSize;\n\t\t}\n\n\t\t// Get updated vector count\n\t\tconst vectorCount = vectorStoreInstance.memoryVectors?.length || 0;\n\n\t\t// Periodically recalculate actual memory usage to avoid drift\n\t\tif (\n\t\t\t(vectorCount > 0 && vectorCount % 100 === 0) ||\n\t\t\tdocuments.length > 20 ||\n\t\t\t(vectorCountBefore === 0 && vectorCount > 0)\n\t\t) {\n\t\t\tthis.recalculateMemoryUsage();\n\t\t}\n\n\t\t// Logging memory usage\n\t\tconst maxMemoryMB =\n\t\t\tthis.maxMemorySizeBytes > 0\n\t\t\t\t? (this.maxMemorySizeBytes / (1024 * 1024)).toFixed(0)\n\t\t\t\t: 'unlimited';\n\n\t\tthis.logger.debug(\n\t\t\t`Vector store memory: ${this.getMemoryUsageFormatted()}/${maxMemoryMB}MB (${vectorCount} vectors in ${this.vectorStoreBuffer.size} stores)`,\n\t\t);\n\t}\n\n\t/**\n\t * Get statistics about the vector store memory usage\n\t */\n\tgetStats(): VectorStoreStats {\n\t\tconst now = Date.now();\n\t\tlet inactiveStoreCount = 0;\n\n\t\t// Always recalculate when getting stats to ensure accuracy\n\t\tthis.recalculateMemoryUsage();\n\n\t\tconst stats: VectorStoreStats = {\n\t\t\ttotalSizeBytes: this.memoryUsageBytes,\n\t\t\ttotalSizeMB: Math.round((this.memoryUsageBytes / (1024 * 1024)) * 100) / 100,\n\t\t\tpercentOfLimit:\n\t\t\t\tthis.maxMemorySizeBytes > 0\n\t\t\t\t\t? Math.round((this.memoryUsageBytes / this.maxMemorySizeBytes) * 100)\n\t\t\t\t\t: 0,\n\t\t\tmaxMemoryMB: this.maxMemorySizeBytes > 0 ? this.maxMemorySizeBytes / (1024 * 1024) : -1, // -1 indicates unlimited\n\t\t\tstoreCount: this.vectorStoreBuffer.size,\n\t\t\tinactiveStoreCount: 0,\n\t\t\tttlHours: this.inactiveTtlMs > 0 ? this.inactiveTtlMs / (60 * 60 * 1000) : -1, // -1 indicates disabled\n\t\t\tstores: {},\n\t\t};\n\n\t\t// Add stats for each store\n\t\tfor (const [key, metadata] of this.storeMetadata.entries()) {\n\t\t\tconst store = this.vectorStoreBuffer.get(key);\n\n\t\t\tif (store) {\n\t\t\t\tconst lastAccessedTime = metadata.lastAccessed.getTime();\n\t\t\t\tconst inactiveTimeMs = now - lastAccessedTime;\n\t\t\t\tconst isInactive = this.cleanupService.isStoreInactive(metadata);\n\n\t\t\t\tif (isInactive) {\n\t\t\t\t\tinactiveStoreCount++;\n\t\t\t\t}\n\n\t\t\t\tstats.stores[key] = {\n\t\t\t\t\tsizeBytes: metadata.size,\n\t\t\t\t\tsizeMB: Math.round((metadata.size / (1024 * 1024)) * 100) / 100,\n\t\t\t\t\tpercentOfTotal: Math.round((metadata.size / this.memoryUsageBytes) * 100) || 0,\n\t\t\t\t\tvectors: store.memoryVectors?.length || 0,\n\t\t\t\t\tcreatedAt: metadata.createdAt.toISOString(),\n\t\t\t\t\tlastAccessed: metadata.lastAccessed.toISOString(),\n\t\t\t\t\tinactive: isInactive,\n\t\t\t\t\tinactiveForHours: Math.round(inactiveTimeMs / (60 * 60 * 1000)),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tstats.inactiveStoreCount = inactiveStoreCount;\n\n\t\treturn stats;\n\t}\n}\n"],"mappings":"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","names":[]}
|