n8n-nodes-tembory 1.0.36 → 1.0.38
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/Mem0/Mem0Memory.node.js +170 -23
- package/package.json +1 -1
|
@@ -852,10 +852,13 @@ const makeToolEventId = (tool, sequence = 0) => {
|
|
|
852
852
|
return `tool_${hashString(base)}`;
|
|
853
853
|
};
|
|
854
854
|
const canonicalToolInput = (value) => {
|
|
855
|
-
const text =
|
|
856
|
-
|
|
855
|
+
const text = value === undefined || value === null
|
|
856
|
+
? ''
|
|
857
|
+
: (typeof value === 'string' ? value : stableStringify(value));
|
|
858
|
+
const trimmed = String(text).trim();
|
|
859
|
+
if (trimmed === '""' || trimmed === "''")
|
|
857
860
|
return '';
|
|
858
|
-
return
|
|
861
|
+
return trimmed;
|
|
859
862
|
};
|
|
860
863
|
const normalizeToolCall = (tool, sequence = 0, defaults = {}) => {
|
|
861
864
|
const at = tool.at || defaults.at || nowIso();
|
|
@@ -910,6 +913,73 @@ const readDeep = (value, visitor, seen = new Set()) => {
|
|
|
910
913
|
for (const item of Object.values(value))
|
|
911
914
|
readDeep(item, visitor, seen);
|
|
912
915
|
};
|
|
916
|
+
const messageTypeOf = (message) => {
|
|
917
|
+
if (typeof (message === null || message === void 0 ? void 0 : message._getType) === 'function')
|
|
918
|
+
return String(message._getType() || '');
|
|
919
|
+
return String((message === null || message === void 0 ? void 0 : message.role) || (message === null || message === void 0 ? void 0 : message.type) || (message === null || message === void 0 ? void 0 : message.lc_kwargs && message.lc_kwargs.type) || '').toLowerCase();
|
|
920
|
+
};
|
|
921
|
+
const messageContentOf = (message) => typeof (message === null || message === void 0 ? void 0 : message.content) === 'string' ? message.content : safeStringify(message === null || message === void 0 ? void 0 : message.content);
|
|
922
|
+
const extractToolCallsFromMessages = (messages = []) => {
|
|
923
|
+
const calls = [];
|
|
924
|
+
const toolCallById = new Map();
|
|
925
|
+
const push = (tool, index = calls.length) => {
|
|
926
|
+
if (!tool || !(tool.name || tool.tool || tool.toolName))
|
|
927
|
+
return;
|
|
928
|
+
const normalized = normalizeToolCall({
|
|
929
|
+
id: tool.id || tool.callId || tool.call_id || tool.toolCallId || tool.tool_call_id,
|
|
930
|
+
turnId: tool.turnId || tool.turn_id,
|
|
931
|
+
sequence: tool.sequence || index + 1,
|
|
932
|
+
name: tool.name || tool.tool || tool.toolName,
|
|
933
|
+
input: tool.input !== undefined ? tool.input : tool.args !== undefined ? tool.args : tool.toolInput !== undefined ? tool.toolInput : '',
|
|
934
|
+
ok: tool.ok !== false,
|
|
935
|
+
result: tool.result !== undefined ? tool.result : tool.output !== undefined ? tool.output : tool.observation !== undefined ? tool.observation : '',
|
|
936
|
+
at: tool.at || nowIso(),
|
|
937
|
+
source: tool.source || 'langchain_message',
|
|
938
|
+
}, calls.length + 1);
|
|
939
|
+
calls.push(normalized);
|
|
940
|
+
if (normalized.id)
|
|
941
|
+
toolCallById.set(String(normalized.id), normalized);
|
|
942
|
+
};
|
|
943
|
+
for (const [index, message] of (messages || []).entries()) {
|
|
944
|
+
const type = messageTypeOf(message);
|
|
945
|
+
const additional = (message && (message.additional_kwargs || message.additionalKwargs)) || {};
|
|
946
|
+
const kwargs = (message && message.lc_kwargs) || {};
|
|
947
|
+
const toolCalls = message && (message.tool_calls || message.toolCalls || additional.tool_calls || additional.toolCalls || kwargs.tool_calls || kwargs.toolCalls);
|
|
948
|
+
if (Array.isArray(toolCalls)) {
|
|
949
|
+
for (const tool of toolCalls)
|
|
950
|
+
push({ ...tool, source: 'ai_message_tool_calls' }, index);
|
|
951
|
+
}
|
|
952
|
+
const invalidToolCalls = message && (message.invalid_tool_calls || message.invalidToolCalls || additional.invalid_tool_calls || additional.invalidToolCalls);
|
|
953
|
+
if (Array.isArray(invalidToolCalls)) {
|
|
954
|
+
for (const tool of invalidToolCalls)
|
|
955
|
+
push({ ...tool, ok: false, source: 'ai_message_invalid_tool_calls' }, index);
|
|
956
|
+
}
|
|
957
|
+
if (type === 'tool') {
|
|
958
|
+
const id = message.tool_call_id || message.toolCallId || additional.tool_call_id || additional.toolCallId || message.id;
|
|
959
|
+
const name = message.name || message.toolName || message.tool || additional.name || additional.tool_name || additional.toolName || kwargs.name || 'tool';
|
|
960
|
+
const existing = id ? toolCallById.get(String(id)) : null;
|
|
961
|
+
if (existing) {
|
|
962
|
+
existing.result = summarizeToolResult(messageContentOf(message));
|
|
963
|
+
existing.result_summary = existing.result;
|
|
964
|
+
existing.ok = true;
|
|
965
|
+
existing.status = 'ok';
|
|
966
|
+
existing.result_hash = stableHash(existing.result || '');
|
|
967
|
+
existing.dedupe_key = toolEventKey(existing);
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
push({
|
|
971
|
+
id,
|
|
972
|
+
name,
|
|
973
|
+
input: '',
|
|
974
|
+
result: messageContentOf(message),
|
|
975
|
+
ok: true,
|
|
976
|
+
source: 'tool_message',
|
|
977
|
+
}, index);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return dedupeToolHistory(calls);
|
|
982
|
+
};
|
|
913
983
|
const extractToolCallsFromText = (text, at = nowIso()) => {
|
|
914
984
|
const calls = [];
|
|
915
985
|
const source = String(text || '');
|
|
@@ -1022,15 +1092,17 @@ const getMemoryStore = (ctx) => {
|
|
|
1022
1092
|
data.tembory.memoryCompression = data.tembory.memoryCompression || {};
|
|
1023
1093
|
data.tembory.activeSummary = data.tembory.activeSummary || {};
|
|
1024
1094
|
data.tembory.connectedModelSummaryCache = data.tembory.connectedModelSummaryCache || {};
|
|
1095
|
+
data.tembory.captureState = data.tembory.captureState || {};
|
|
1025
1096
|
return data.tembory;
|
|
1026
1097
|
}
|
|
1027
1098
|
catch {
|
|
1028
|
-
global.__temboryMemory = global.__temboryMemory || { toolHistory: {}, recentMessages: {}, profileFacts: {}, workingMemory: {}, decisionState: {}, memoryCompression: {}, activeSummary: {}, connectedModelSummaryCache: {} };
|
|
1099
|
+
global.__temboryMemory = global.__temboryMemory || { toolHistory: {}, recentMessages: {}, profileFacts: {}, workingMemory: {}, decisionState: {}, memoryCompression: {}, activeSummary: {}, connectedModelSummaryCache: {}, captureState: {} };
|
|
1029
1100
|
global.__temboryMemory.workingMemory = global.__temboryMemory.workingMemory || {};
|
|
1030
1101
|
global.__temboryMemory.decisionState = global.__temboryMemory.decisionState || {};
|
|
1031
1102
|
global.__temboryMemory.memoryCompression = global.__temboryMemory.memoryCompression || {};
|
|
1032
1103
|
global.__temboryMemory.activeSummary = global.__temboryMemory.activeSummary || {};
|
|
1033
1104
|
global.__temboryMemory.connectedModelSummaryCache = global.__temboryMemory.connectedModelSummaryCache || {};
|
|
1105
|
+
global.__temboryMemory.captureState = global.__temboryMemory.captureState || {};
|
|
1034
1106
|
return global.__temboryMemory;
|
|
1035
1107
|
}
|
|
1036
1108
|
};
|
|
@@ -1824,9 +1896,20 @@ const compactEntityTimelineForAgent = (timeline = [], maxItems = 8) => pruneByLi
|
|
|
1824
1896
|
at: item.at,
|
|
1825
1897
|
source: item.source_type || item.source,
|
|
1826
1898
|
}));
|
|
1899
|
+
const isConversationEchoMemory = (memory) => {
|
|
1900
|
+
const meta = metadataOf(memory);
|
|
1901
|
+
const kind = String(meta.kind || meta.type || '').toLowerCase();
|
|
1902
|
+
if (/^(recent_message|conversation_ledger|conversation_message)$/i.test(kind))
|
|
1903
|
+
return true;
|
|
1904
|
+
const raw = memoryText(memory);
|
|
1905
|
+
if (parseRecentMessageMarker(raw) || parseConversationLedgerMarker(raw).length)
|
|
1906
|
+
return true;
|
|
1907
|
+
return /__tembory_conversation_ledger_v1__/.test(String(raw || ''));
|
|
1908
|
+
};
|
|
1827
1909
|
const compactVectorMemoriesForAgent = (vectorMemories = [], toolHistory = [], maxItems = 3) => {
|
|
1828
1910
|
const hasStructuredTools = Array.isArray(toolHistory) && toolHistory.length > 0;
|
|
1829
1911
|
return (vectorMemories || [])
|
|
1912
|
+
.filter((memory) => !isConversationEchoMemory(memory))
|
|
1830
1913
|
.map((memory) => contextMemoryText(memory, 220))
|
|
1831
1914
|
.filter(Boolean)
|
|
1832
1915
|
.filter((text) => !/^\[recent_message\]/i.test(text))
|
|
@@ -2202,7 +2285,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
2202
2285
|
sections.push({
|
|
2203
2286
|
section: 'vector',
|
|
2204
2287
|
title: 'Vector memories',
|
|
2205
|
-
value: compactStateSections ? compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.maxReturn || adv.topK || 4)) : vectorMemories.map((m) => {
|
|
2288
|
+
value: compactStateSections ? compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.maxReturn || adv.topK || 4)) : vectorMemories.filter((m) => !isConversationEchoMemory(m)).map((m) => {
|
|
2206
2289
|
const scoreMeta = scoreMetaOf(m);
|
|
2207
2290
|
const rawScore = scoreOf(m);
|
|
2208
2291
|
return {
|
|
@@ -2634,6 +2717,18 @@ class Mem0Memory {
|
|
|
2634
2717
|
const memoryKey = this.getNodeParameter('memoryKey', itemIndex);
|
|
2635
2718
|
let currentMessages = [];
|
|
2636
2719
|
const loadCache = new Map();
|
|
2720
|
+
const recordMemoryEvent = (action, payload = {}, error) => {
|
|
2721
|
+
const { index } = this.addInputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, [
|
|
2722
|
+
[{ json: { action, ...(payload.input !== undefined ? { input: payload.input } : {}), ...(payload.values !== undefined ? { values: payload.values } : {}) } }],
|
|
2723
|
+
]);
|
|
2724
|
+
if (error) {
|
|
2725
|
+
this.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, error);
|
|
2726
|
+
return;
|
|
2727
|
+
}
|
|
2728
|
+
this.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, [
|
|
2729
|
+
[{ json: { action, ...payload } }],
|
|
2730
|
+
]);
|
|
2731
|
+
};
|
|
2637
2732
|
const memory = {
|
|
2638
2733
|
memoryKeys: [memoryKey],
|
|
2639
2734
|
inputKey: 'input',
|
|
@@ -2643,21 +2738,25 @@ class Mem0Memory {
|
|
|
2643
2738
|
getMessages: async () => currentMessages,
|
|
2644
2739
|
addMessage: async (message) => {
|
|
2645
2740
|
currentMessages.push(message);
|
|
2646
|
-
await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [message]);
|
|
2741
|
+
const saved = await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [message]);
|
|
2742
|
+
recordMemoryEvent('chatHistory.addMessage', { saved: Boolean(saved && saved.saved), toolCalls: (saved && saved.toolCalls) || [], messages: 1 });
|
|
2647
2743
|
},
|
|
2648
2744
|
addUserMessage: async (message) => {
|
|
2649
2745
|
const baseMessage = toBaseMessage({ role: 'user', content: message });
|
|
2650
2746
|
currentMessages.push(baseMessage);
|
|
2651
|
-
await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [baseMessage]);
|
|
2747
|
+
const saved = await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [baseMessage]);
|
|
2748
|
+
recordMemoryEvent('chatHistory.addUserMessage', { saved: Boolean(saved && saved.saved), toolCalls: (saved && saved.toolCalls) || [], messages: 1 });
|
|
2652
2749
|
},
|
|
2653
2750
|
addAIChatMessage: async (message) => {
|
|
2654
2751
|
const baseMessage = toBaseMessage({ role: 'assistant', content: message });
|
|
2655
2752
|
currentMessages.push(baseMessage);
|
|
2656
|
-
await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [baseMessage]);
|
|
2753
|
+
const saved = await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [baseMessage]);
|
|
2754
|
+
recordMemoryEvent('chatHistory.addAIChatMessage', { saved: Boolean(saved && saved.saved), toolCalls: (saved && saved.toolCalls) || [], messages: 1 });
|
|
2657
2755
|
},
|
|
2658
2756
|
addMessages: async (messages) => {
|
|
2659
2757
|
currentMessages.push(...messages);
|
|
2660
|
-
await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, messages);
|
|
2758
|
+
const saved = await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, messages);
|
|
2759
|
+
recordMemoryEvent('chatHistory.addMessages', { saved: Boolean(saved && saved.saved), toolCalls: (saved && saved.toolCalls) || [], messages: Array.isArray(messages) ? messages.length : 0 });
|
|
2661
2760
|
},
|
|
2662
2761
|
clear: async () => {
|
|
2663
2762
|
currentMessages = [];
|
|
@@ -2722,25 +2821,16 @@ class Mem0Memory {
|
|
|
2722
2821
|
async saveMessagesForItem(itemIndex, messages = []) {
|
|
2723
2822
|
const inputValues = {};
|
|
2724
2823
|
const outputValues = {};
|
|
2725
|
-
const toolCalls =
|
|
2824
|
+
const toolCalls = extractToolCallsFromMessages(messages);
|
|
2726
2825
|
const inputParts = [];
|
|
2727
2826
|
const outputParts = [];
|
|
2728
2827
|
for (const message of messages || []) {
|
|
2729
|
-
const type =
|
|
2730
|
-
const content =
|
|
2828
|
+
const type = messageTypeOf(message);
|
|
2829
|
+
const content = messageContentOf(message);
|
|
2731
2830
|
if (type === 'human' || type === 'user')
|
|
2732
2831
|
inputParts.push(content);
|
|
2733
2832
|
else if (type === 'ai' || type === 'assistant')
|
|
2734
2833
|
outputParts.push(content);
|
|
2735
|
-
else if (type === 'tool') {
|
|
2736
|
-
toolCalls.push({
|
|
2737
|
-
name: message.name || message.toolName || message.tool || (message.additional_kwargs && (message.additional_kwargs.name || message.additional_kwargs.tool_name)) || 'tool',
|
|
2738
|
-
input: '',
|
|
2739
|
-
ok: true,
|
|
2740
|
-
result: summarizeToolResult(content),
|
|
2741
|
-
at: nowIso(),
|
|
2742
|
-
});
|
|
2743
|
-
}
|
|
2744
2834
|
}
|
|
2745
2835
|
if (inputParts.length)
|
|
2746
2836
|
inputValues.input = inputParts.join('\n');
|
|
@@ -2751,8 +2841,11 @@ class Mem0Memory {
|
|
|
2751
2841
|
outputValues.output = outputParts.join('\n').trim();
|
|
2752
2842
|
if (toolContext.length)
|
|
2753
2843
|
outputValues.__temboryToolCalls = toolContext;
|
|
2754
|
-
if (inputValues.input || outputValues.output)
|
|
2844
|
+
if (inputValues.input || outputValues.output || toolContext.length) {
|
|
2755
2845
|
await Mem0Memory.prototype.saveContextForItem.call(this, itemIndex, inputValues, outputValues);
|
|
2846
|
+
return { saved: true, input: inputValues, output: outputValues, toolCalls: toolContext };
|
|
2847
|
+
}
|
|
2848
|
+
return { saved: false, input: inputValues, output: outputValues, toolCalls: toolContext };
|
|
2756
2849
|
}
|
|
2757
2850
|
async saveContextForItem(itemIndex, inputValues = {}, outputValues = {}) {
|
|
2758
2851
|
const threadId = this.getNodeParameter('threadId', itemIndex);
|
|
@@ -2764,6 +2857,14 @@ class Mem0Memory {
|
|
|
2764
2857
|
const rawOutput = pickText(outputValues, ['output', 'response', 'text', 'answer']);
|
|
2765
2858
|
const output = cleanAssistantTranscriptText(rawOutput);
|
|
2766
2859
|
const toolCalls = extractToolCalls(outputValues);
|
|
2860
|
+
store.captureState[key] = {
|
|
2861
|
+
last_save_at: nowIso(),
|
|
2862
|
+
last_save_had_input: Boolean(input),
|
|
2863
|
+
last_save_had_output: Boolean(output),
|
|
2864
|
+
last_save_tool_calls_captured: toolCalls.length,
|
|
2865
|
+
last_save_tool_names: toolCalls.map((tool) => tool.name).filter(Boolean).slice(0, 20),
|
|
2866
|
+
last_save_capture_sources: Array.from(new Set(toolCalls.map((tool) => tool.source).filter(Boolean))),
|
|
2867
|
+
};
|
|
2767
2868
|
const recentForMem0 = [];
|
|
2768
2869
|
const profileFromTurn = extractProfileFactsFromText(input, 'user_message', nowIso());
|
|
2769
2870
|
if (Object.keys(profileFromTurn).length) {
|
|
@@ -3374,12 +3475,47 @@ class Mem0Memory {
|
|
|
3374
3475
|
connectedAi.errors.push(`recentMessageProbe: ${error.message || String(error)}`);
|
|
3375
3476
|
}
|
|
3376
3477
|
}
|
|
3478
|
+
if (connectedEmbedding && adv.includeToolHistory !== false) {
|
|
3479
|
+
try {
|
|
3480
|
+
const toolProbe = [
|
|
3481
|
+
'Tool history ledger',
|
|
3482
|
+
'tools called in this thread tool inputs tool outputs tool status tool order action ledger',
|
|
3483
|
+
query,
|
|
3484
|
+
].filter(Boolean).join('\n');
|
|
3485
|
+
const seen = new Set(vectorMemories.map((memory) => stableHash(memoryText(memory) || safeStringify(memory))));
|
|
3486
|
+
for (const kind of ['tool_ledger', 'tool_history']) {
|
|
3487
|
+
const toolBody = {
|
|
3488
|
+
user_id: key,
|
|
3489
|
+
agent_id: adv.agentId ? String(adv.agentId) : undefined,
|
|
3490
|
+
run_id: adv.runId ? String(adv.runId) : undefined,
|
|
3491
|
+
top_k: Math.max(Number(adv.toolHistoryLastN || 10) * 4, 40),
|
|
3492
|
+
filters: { kind },
|
|
3493
|
+
};
|
|
3494
|
+
const toolRes = await searchClientVectorMemories(this, connectedEmbedding, toolProbe, toolBody);
|
|
3495
|
+
const toolMemories = normalizeResults(toolRes).map((memory) => withTemboryScore(memory, {
|
|
3496
|
+
semanticScore: scoreOf(memory),
|
|
3497
|
+
source: `${kind}_probe`,
|
|
3498
|
+
}));
|
|
3499
|
+
for (const memory of toolMemories) {
|
|
3500
|
+
const hash = stableHash(memoryText(memory) || safeStringify(memory));
|
|
3501
|
+
if (!seen.has(hash)) {
|
|
3502
|
+
seen.add(hash);
|
|
3503
|
+
vectorMemories.push(memory);
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
connectedAi.toolLedgerProbe = true;
|
|
3508
|
+
}
|
|
3509
|
+
catch (error) {
|
|
3510
|
+
connectedAi.errors.push(`toolLedgerProbe: ${error.message || String(error)}`);
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3377
3513
|
let persistedRecentMessages = [];
|
|
3378
3514
|
let persistedToolHistory = [];
|
|
3379
3515
|
let persistedMemoryItems = [];
|
|
3380
3516
|
if (adv.includeRecentMessages !== false || adv.includeToolHistory !== false) {
|
|
3381
3517
|
try {
|
|
3382
|
-
const qs = { user_id: key };
|
|
3518
|
+
const qs = { user_id: key, limit: Math.max(Number(adv.recentMessagesLastN || 50) * 8, Number(adv.toolHistoryLastN || 10) * 12, 200) };
|
|
3383
3519
|
if (adv.agentId)
|
|
3384
3520
|
qs.agent_id = String(adv.agentId);
|
|
3385
3521
|
if (adv.runId)
|
|
@@ -3524,6 +3660,14 @@ class Mem0Memory {
|
|
|
3524
3660
|
graph: graph.length,
|
|
3525
3661
|
project: project || null,
|
|
3526
3662
|
memoryNamespace: key,
|
|
3663
|
+
captureState: store.captureState[key] || {
|
|
3664
|
+
last_save_at: null,
|
|
3665
|
+
last_save_had_input: false,
|
|
3666
|
+
last_save_had_output: false,
|
|
3667
|
+
last_save_tool_calls_captured: 0,
|
|
3668
|
+
last_save_tool_names: [],
|
|
3669
|
+
last_save_capture_sources: [],
|
|
3670
|
+
},
|
|
3527
3671
|
connectedAi,
|
|
3528
3672
|
activeSummary: summaryDiagnostics,
|
|
3529
3673
|
};
|
|
@@ -3768,6 +3912,7 @@ exports.Mem0Memory = Mem0Memory;
|
|
|
3768
3912
|
exports.__private = {
|
|
3769
3913
|
extractToolCallsFromText,
|
|
3770
3914
|
extractToolCalls,
|
|
3915
|
+
extractToolCallsFromMessages,
|
|
3771
3916
|
toolHistoryItemsFromMemory,
|
|
3772
3917
|
explicitToolHistoryItemsFromMemory,
|
|
3773
3918
|
toolHistoryFromMemory,
|
|
@@ -3820,6 +3965,8 @@ exports.__private = {
|
|
|
3820
3965
|
embedQueryCached,
|
|
3821
3966
|
compactToolResult,
|
|
3822
3967
|
compactToolHistoryForAgent,
|
|
3968
|
+
compactVectorMemoriesForAgent,
|
|
3969
|
+
isConversationEchoMemory,
|
|
3823
3970
|
compactOperationalStateForAgent,
|
|
3824
3971
|
activeSummaryIsFresh,
|
|
3825
3972
|
readActiveSummary,
|
package/package.json
CHANGED