@n8n/n8n-nodes-langchain
Version:

129 lines • 4.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractToolCallId = extractToolCallId;
exports.buildMessagesFromSteps = buildMessagesFromSteps;
exports.buildToolContext = buildToolContext;
exports.loadMemory = loadMemory;
exports.saveToMemory = saveToMemory;
const messages_1 = require("@langchain/core/messages");
function extractToolCallId(toolCallId, toolName) {
if (typeof toolCallId === 'string' && toolCallId.length > 0) {
return toolCallId;
}
if (typeof toolCallId === 'object' &&
toolCallId !== null &&
!Array.isArray(toolCallId) &&
'id' in toolCallId) {
const id = toolCallId.id;
if (typeof id === 'string' && id.length > 0) {
return id;
}
}
if (Array.isArray(toolCallId) && toolCallId.length > 0) {
return extractToolCallId(toolCallId[0], toolName);
}
return `synthetic_${toolName}_${Date.now()}`;
}
function buildMessagesFromSteps(steps) {
const messages = [];
for (let i = 0; i < steps.length; i++) {
const step = steps[i];
const existingAIMessage = step.action.messageLog?.[0];
const existingToolCallId = existingAIMessage?.tool_calls?.[0]?.id;
const toolCallId = existingToolCallId ?? extractToolCallId(step.action.toolCallId, step.action.tool);
const aiMessage = existingAIMessage ??
new messages_1.AIMessage({
content: `Calling ${step.action.tool} with input: ${JSON.stringify(step.action.toolInput)}`,
tool_calls: [
{
id: toolCallId,
name: step.action.tool,
args: step.action.toolInput,
type: 'tool_call',
},
],
});
const toolMessage = new messages_1.ToolMessage({
content: step.observation,
tool_call_id: toolCallId,
name: step.action.tool,
});
messages.push(aiMessage);
messages.push(toolMessage);
}
return messages;
}
function buildToolContext(steps) {
return steps
.map((step) => `Tool: ${step.action.tool}, Input: ${JSON.stringify(step.action.toolInput)}, Result: ${step.observation}`)
.join('; ');
}
function cleanupOrphanedMessages(chatHistory) {
let changed = true;
while (changed && chatHistory.length > 0) {
changed = false;
while (chatHistory.length > 0 && chatHistory[0] instanceof messages_1.ToolMessage) {
chatHistory.shift();
changed = true;
}
if (chatHistory.length > 0) {
const firstMessage = chatHistory[0];
const hasOrphanedAIMessage = firstMessage instanceof messages_1.AIMessage &&
(firstMessage.tool_calls?.length ?? 0) > 0 &&
!(chatHistory[1] instanceof messages_1.ToolMessage);
if (hasOrphanedAIMessage) {
chatHistory.shift();
changed = true;
}
}
}
return chatHistory;
}
async function loadMemory(memory, model, maxTokens) {
if (!memory) {
return undefined;
}
const memoryVariables = await memory.loadMemoryVariables({});
let chatHistory = memoryVariables['chat_history'] || [];
chatHistory = cleanupOrphanedMessages(chatHistory);
if (maxTokens && model) {
chatHistory = await (0, messages_1.trimMessages)(chatHistory, {
strategy: 'last',
maxTokens,
tokenCounter: model,
includeSystem: true,
startOn: 'human',
allowPartial: true,
});
chatHistory = cleanupOrphanedMessages(chatHistory);
}
return chatHistory;
}
async function saveToMemory(input, output, memory, steps, previousStepsCount) {
if (!output || !memory) {
return;
}
if (!steps || steps.length === 0) {
await memory.saveContext({ input }, { output });
return;
}
const newSteps = previousStepsCount ? steps.slice(previousStepsCount) : steps;
if (newSteps.length === 0) {
await memory.saveContext({ input }, { output });
return;
}
if (!('addMessages' in memory.chatHistory) ||
typeof memory.chatHistory.addMessages !== 'function') {
const toolContext = buildToolContext(newSteps);
const fullOutput = `[Used tools: ${toolContext}] ${output}`;
await memory.saveContext({ input }, { output: fullOutput });
return;
}
const messages = [];
messages.push(new messages_1.HumanMessage(input));
const toolMessages = buildMessagesFromSteps(newSteps);
messages.push.apply(messages, toolMessages);
messages.push(new messages_1.AIMessage(output));
await memory.chatHistory.addMessages(messages);
}
//# sourceMappingURL=memoryManagement.js.map