@n8n/n8n-nodes-langchain
Version:
155 lines • 5.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractToolCallId = extractToolCallId;
exports.buildMessagesFromSteps = buildMessagesFromSteps;
exports.buildToolContext = buildToolContext;
exports.cleanupOrphanedMessages = cleanupOrphanedMessages;
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);
if (existingAIMessage) {
messages.push(existingAIMessage);
}
else if (i === 0) {
messages.push(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',
},
],
}));
}
messages.push(new messages_1.ToolMessage({
content: step.observation,
tool_call_id: toolCallId,
name: step.action.tool,
}));
}
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) {
const result = [...chatHistory];
let changed = true;
while (changed && result.length > 0) {
changed = false;
while (result.length > 0 && result[0] instanceof messages_1.ToolMessage) {
result.shift();
changed = true;
}
if (result.length > 0) {
const firstMessage = result[0];
const hasOrphanedAIMessage = firstMessage instanceof messages_1.AIMessage &&
(firstMessage.tool_calls?.length ?? 0) > 0 &&
!(result[1] instanceof messages_1.ToolMessage);
if (hasOrphanedAIMessage) {
result.shift();
changed = true;
}
}
}
changed = true;
while (changed && result.length > 0) {
changed = false;
const lastIdx = result.length - 1;
const lastMessage = result[lastIdx];
if (lastMessage instanceof messages_1.ToolMessage) {
let precedingIdx = lastIdx - 1;
while (precedingIdx >= 0 && result[precedingIdx] instanceof messages_1.ToolMessage) {
precedingIdx--;
}
const precedingMessage = precedingIdx >= 0 ? result[precedingIdx] : undefined;
const isPaired = precedingMessage instanceof messages_1.AIMessage && (precedingMessage.tool_calls?.length ?? 0) > 0;
if (!isPaired) {
result.pop();
changed = true;
}
}
else if (lastMessage instanceof messages_1.AIMessage && (lastMessage.tool_calls?.length ?? 0) > 0) {
result.pop();
changed = true;
}
}
return result;
}
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