n8n-nodes-tembory 1.0.37 → 1.0.39

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.
@@ -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 = String(value === undefined || value === null ? '' : value).trim();
856
- if (text === '""' || text === "''")
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 text;
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
  };
@@ -1041,8 +1113,50 @@ const userKeyFrom = (threadId, adv, project = '') => {
1041
1113
  return namespace ? `${namespace}::${base}` : base;
1042
1114
  };
1043
1115
  const applyOperationalPreset = (advanced = {}) => {
1044
- const preset = String(advanced.operationPreset || 'productionBalanced');
1116
+ const preset = String(advanced.operationPreset || 'productionFast');
1045
1117
  const presets = {
1118
+ productionFast: {
1119
+ summarySource: 'activeContext',
1120
+ includeConnectedModelSummary: true,
1121
+ includeActiveSummary: true,
1122
+ persistActiveSummary: true,
1123
+ activeSummaryMaxChars: 1800,
1124
+ activeSummaryRetentionDays: 30,
1125
+ enableTransientSummaryCache: true,
1126
+ transientSummaryCacheTTLSeconds: 300,
1127
+ compactStateSections: true,
1128
+ useVectorMemory: false,
1129
+ persistBackendMemories: false,
1130
+ includeRecentMessageProbe: false,
1131
+ includeToolLedgerProbe: false,
1132
+ includeContextHeader: true,
1133
+ includeSummary: true,
1134
+ includeScores: false,
1135
+ includeDiagnostics: false,
1136
+ includeRelations: false,
1137
+ includeToolHistory: true,
1138
+ includeToolResults: true,
1139
+ persistToolFactsToMem0: false,
1140
+ includeToolHistorySemanticFallback: false,
1141
+ includeProfileFacts: true,
1142
+ includeOperationalState: true,
1143
+ includeActionLedger: true,
1144
+ includeEntityTimeline: false,
1145
+ includeWorkingMemory: true,
1146
+ includeDecisionState: true,
1147
+ includeMemoryCompression: true,
1148
+ includeRecentMessages: true,
1149
+ includeRecentHighlights: false,
1150
+ topK: 0,
1151
+ lastN: 0,
1152
+ maxReturn: 0,
1153
+ toolHistoryLastN: 15,
1154
+ recentMessagesLastN: 50,
1155
+ vectorMemoryMaxChars: 220,
1156
+ contextMaxChars: 9000,
1157
+ connectedModelSummaryMaxChars: 1200,
1158
+ connectedModelSummaryInputMaxChars: 4200,
1159
+ },
1046
1160
  diagnostic: {
1047
1161
  summarySource: 'auto',
1048
1162
  includeConnectedModelSummary: true,
@@ -1617,13 +1731,13 @@ const deriveContextHealth = ({ userId = '', project = '', vectorMemories = [], r
1617
1731
  namespace_stable: Boolean(userId && !/^mcp-session-\d+$/i.test(String(userId))),
1618
1732
  has_recent_messages: Array.isArray(recentMessages) && recentMessages.length > 0,
1619
1733
  has_tool_history: Array.isArray(toolHistory) && toolHistory.length > 0,
1620
- has_vector_memories: Array.isArray(vectorMemories) && vectorMemories.length > 0,
1734
+ has_vector_memories: diagnostics.vectorMemoryEnabled === false ? true : Array.isArray(vectorMemories) && vectorMemories.length > 0,
1621
1735
  has_working_memory: Boolean(workingMemory && Object.keys(workingMemory).length),
1622
1736
  has_decision_state: Boolean(decisionState && Object.keys(decisionState).length),
1623
1737
  has_memory_compression: Boolean(memoryCompression && Object.keys(memoryCompression).length),
1624
1738
  has_operational_state: Boolean(operationalState && Object.keys(operationalState).length),
1625
1739
  connected_language_model: Boolean(diagnostics.connectedAi && diagnostics.connectedAi.languageModel),
1626
- connected_embedding: Boolean(diagnostics.connectedAi && diagnostics.connectedAi.embedding),
1740
+ connected_embedding: diagnostics.vectorMemoryEnabled === false ? true : Boolean(diagnostics.connectedAi && diagnostics.connectedAi.embedding),
1627
1741
  no_connected_ai_errors: !((diagnostics.connectedAi && diagnostics.connectedAi.errors) || []).length,
1628
1742
  };
1629
1743
  const weights = {
@@ -1824,9 +1938,20 @@ const compactEntityTimelineForAgent = (timeline = [], maxItems = 8) => pruneByLi
1824
1938
  at: item.at,
1825
1939
  source: item.source_type || item.source,
1826
1940
  }));
1941
+ const isConversationEchoMemory = (memory) => {
1942
+ const meta = metadataOf(memory);
1943
+ const kind = String(meta.kind || meta.type || '').toLowerCase();
1944
+ if (/^(recent_message|conversation_ledger|conversation_message)$/i.test(kind))
1945
+ return true;
1946
+ const raw = memoryText(memory);
1947
+ if (parseRecentMessageMarker(raw) || parseConversationLedgerMarker(raw).length)
1948
+ return true;
1949
+ return /__tembory_conversation_ledger_v1__/.test(String(raw || ''));
1950
+ };
1827
1951
  const compactVectorMemoriesForAgent = (vectorMemories = [], toolHistory = [], maxItems = 3) => {
1828
1952
  const hasStructuredTools = Array.isArray(toolHistory) && toolHistory.length > 0;
1829
1953
  return (vectorMemories || [])
1954
+ .filter((memory) => !isConversationEchoMemory(memory))
1830
1955
  .map((memory) => contextMemoryText(memory, 220))
1831
1956
  .filter(Boolean)
1832
1957
  .filter((text) => !/^\[recent_message\]/i.test(text))
@@ -2202,7 +2327,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
2202
2327
  sections.push({
2203
2328
  section: 'vector',
2204
2329
  title: 'Vector memories',
2205
- value: compactStateSections ? compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.maxReturn || adv.topK || 4)) : vectorMemories.map((m) => {
2330
+ value: compactStateSections ? compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.maxReturn || adv.topK || 4)) : vectorMemories.filter((m) => !isConversationEchoMemory(m)).map((m) => {
2206
2331
  const scoreMeta = scoreMetaOf(m);
2207
2332
  const rawScore = scoreOf(m);
2208
2333
  return {
@@ -2440,12 +2565,13 @@ class Mem0Memory {
2440
2565
  options: [
2441
2566
  { name: 'Custom', value: 'custom' },
2442
2567
  { name: 'Diagnóstico Completo', value: 'diagnostic' },
2568
+ { name: 'Produção Rápida (Thread + SLM)', value: 'productionFast' },
2443
2569
  { name: 'Produção Balanceada', value: 'productionBalanced' },
2444
2570
  { name: 'Produção Econômica', value: 'productionCheap' },
2445
2571
  { name: 'Produção Nano/SLM', value: 'productionNano' },
2446
2572
  { name: 'Auditoria', value: 'audit' },
2447
2573
  ],
2448
- default: 'productionBalanced',
2574
+ default: 'productionFast',
2449
2575
  description: 'Preenche defaults seguros para contexto, historico de tools e memoria ativa.',
2450
2576
  },
2451
2577
  { displayName: 'Incluir Cabeçalho de Contexto', name: 'includeContextHeader', type: 'boolean', default: true },
@@ -2472,6 +2598,10 @@ class Mem0Memory {
2472
2598
  { displayName: 'Máximo de Relações', name: 'maxRelations', type: 'number', default: 10 },
2473
2599
  { displayName: 'Incluir Action Ledger', name: 'includeActionLedger', type: 'boolean', default: true },
2474
2600
  { displayName: 'Incluir Entity Timeline', name: 'includeEntityTimeline', type: 'boolean', default: true },
2601
+ { displayName: 'Usar Memória Vetorial no Caminho Quente', name: 'useVectorMemory', type: 'boolean', default: false },
2602
+ { displayName: 'Persistir Memórias no Backend', name: 'persistBackendMemories', type: 'boolean', default: false },
2603
+ { displayName: 'Probe Vetorial de Mensagens Recentes', name: 'includeRecentMessageProbe', type: 'boolean', default: false },
2604
+ { displayName: 'Probe Vetorial de Tool Ledger', name: 'includeToolLedgerProbe', type: 'boolean', default: false },
2475
2605
  ],
2476
2606
  },
2477
2607
  {
@@ -2552,18 +2682,21 @@ class Mem0Memory {
2552
2682
  options: [
2553
2683
  { name: 'Custom', value: 'custom' },
2554
2684
  { name: 'Diagnóstico Completo', value: 'diagnostic' },
2685
+ { name: 'Produção Rápida (Thread + SLM)', value: 'productionFast' },
2555
2686
  { name: 'Produção Balanceada', value: 'productionBalanced' },
2556
2687
  { name: 'Produção Econômica', value: 'productionCheap' },
2557
2688
  { name: 'Produção Nano/SLM', value: 'productionNano' },
2558
2689
  { name: 'Auditoria', value: 'audit' },
2559
2690
  ],
2560
- default: 'productionBalanced',
2691
+ default: 'productionFast',
2561
2692
  description: 'Preenche defaults seguros para contexto, diagnostico, historico de tools e mensagens recentes. Valores definidos manualmente continuam tendo prioridade.',
2562
2693
  },
2563
2694
  { displayName: 'Agent ID', name: 'agentId', type: 'string', default: '' },
2564
2695
  { displayName: 'App ID', name: 'appId', type: 'string', default: '' },
2565
2696
  { displayName: 'Run ID', name: 'runId', type: 'string', default: '' },
2566
2697
  { displayName: 'Top K', name: 'topK', type: 'number', typeOptions: { minValue: 1 }, default: 25, description: 'Quantidade de memórias a recuperar (modos semânticos e limites de recentes)' },
2698
+ { displayName: 'Usar Memória Vetorial no Caminho Quente', name: 'useVectorMemory', type: 'boolean', default: false, description: 'Quando desligado, o padrão usa thread estruturada, tools e SLM sem buscar/vetorizar a cada turno.' },
2699
+ { displayName: 'Persistir Memórias no Backend', name: 'persistBackendMemories', type: 'boolean', default: false, description: 'Quando desligado, mantém o estado no workflow/static data para reduzir latência.' },
2567
2700
  { displayName: 'Rerank', name: 'rerank', type: 'boolean', default: true, description: 'Reordenação por relevância (modos semânticos)', displayOptions: { show: { '/retrievalMode': ['semantic', 'semanticV2', 'hybrid'] } } },
2568
2701
  { displayName: 'Fields (lista separada por vírgula)', name: 'fields', type: 'string', default: '', description: 'Campos específicos a retornar da API (modos semânticos)', displayOptions: { show: { '/retrievalMode': ['semantic', 'semanticV2', 'hybrid'] } } },
2569
2702
  { displayName: 'Filters (JSON)', name: 'filters', type: 'json', default: '{}', description: 'Objeto de filtros avançados para busca v2', displayOptions: { show: { '/retrievalMode': ['semanticV2', 'hybrid'] } } },
@@ -2634,6 +2767,18 @@ class Mem0Memory {
2634
2767
  const memoryKey = this.getNodeParameter('memoryKey', itemIndex);
2635
2768
  let currentMessages = [];
2636
2769
  const loadCache = new Map();
2770
+ const recordMemoryEvent = (action, payload = {}, error) => {
2771
+ const { index } = this.addInputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, [
2772
+ [{ json: { action, ...(payload.input !== undefined ? { input: payload.input } : {}), ...(payload.values !== undefined ? { values: payload.values } : {}) } }],
2773
+ ]);
2774
+ if (error) {
2775
+ this.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, error);
2776
+ return;
2777
+ }
2778
+ this.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, [
2779
+ [{ json: { action, ...payload } }],
2780
+ ]);
2781
+ };
2637
2782
  const memory = {
2638
2783
  memoryKeys: [memoryKey],
2639
2784
  inputKey: 'input',
@@ -2643,21 +2788,25 @@ class Mem0Memory {
2643
2788
  getMessages: async () => currentMessages,
2644
2789
  addMessage: async (message) => {
2645
2790
  currentMessages.push(message);
2646
- await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [message]);
2791
+ const saved = await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [message]);
2792
+ recordMemoryEvent('chatHistory.addMessage', { saved: Boolean(saved && saved.saved), toolCalls: (saved && saved.toolCalls) || [], messages: 1 });
2647
2793
  },
2648
2794
  addUserMessage: async (message) => {
2649
2795
  const baseMessage = toBaseMessage({ role: 'user', content: message });
2650
2796
  currentMessages.push(baseMessage);
2651
- await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [baseMessage]);
2797
+ const saved = await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [baseMessage]);
2798
+ recordMemoryEvent('chatHistory.addUserMessage', { saved: Boolean(saved && saved.saved), toolCalls: (saved && saved.toolCalls) || [], messages: 1 });
2652
2799
  },
2653
2800
  addAIChatMessage: async (message) => {
2654
2801
  const baseMessage = toBaseMessage({ role: 'assistant', content: message });
2655
2802
  currentMessages.push(baseMessage);
2656
- await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [baseMessage]);
2803
+ const saved = await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, [baseMessage]);
2804
+ recordMemoryEvent('chatHistory.addAIChatMessage', { saved: Boolean(saved && saved.saved), toolCalls: (saved && saved.toolCalls) || [], messages: 1 });
2657
2805
  },
2658
2806
  addMessages: async (messages) => {
2659
2807
  currentMessages.push(...messages);
2660
- await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, messages);
2808
+ const saved = await Mem0Memory.prototype.saveMessagesForItem.call(this, itemIndex, messages);
2809
+ recordMemoryEvent('chatHistory.addMessages', { saved: Boolean(saved && saved.saved), toolCalls: (saved && saved.toolCalls) || [], messages: Array.isArray(messages) ? messages.length : 0 });
2661
2810
  },
2662
2811
  clear: async () => {
2663
2812
  currentMessages = [];
@@ -2722,25 +2871,16 @@ class Mem0Memory {
2722
2871
  async saveMessagesForItem(itemIndex, messages = []) {
2723
2872
  const inputValues = {};
2724
2873
  const outputValues = {};
2725
- const toolCalls = [];
2874
+ const toolCalls = extractToolCallsFromMessages(messages);
2726
2875
  const inputParts = [];
2727
2876
  const outputParts = [];
2728
2877
  for (const message of messages || []) {
2729
- const type = typeof (message === null || message === void 0 ? void 0 : message._getType) === 'function' ? message._getType() : String((message === null || message === void 0 ? void 0 : message.role) || '');
2730
- const content = typeof (message === null || message === void 0 ? void 0 : message.content) === 'string' ? message.content : safeStringify(message === null || message === void 0 ? void 0 : message.content);
2878
+ const type = messageTypeOf(message);
2879
+ const content = messageContentOf(message);
2731
2880
  if (type === 'human' || type === 'user')
2732
2881
  inputParts.push(content);
2733
2882
  else if (type === 'ai' || type === 'assistant')
2734
2883
  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
2884
  }
2745
2885
  if (inputParts.length)
2746
2886
  inputValues.input = inputParts.join('\n');
@@ -2751,8 +2891,11 @@ class Mem0Memory {
2751
2891
  outputValues.output = outputParts.join('\n').trim();
2752
2892
  if (toolContext.length)
2753
2893
  outputValues.__temboryToolCalls = toolContext;
2754
- if (inputValues.input || outputValues.output)
2894
+ if (inputValues.input || outputValues.output || toolContext.length) {
2755
2895
  await Mem0Memory.prototype.saveContextForItem.call(this, itemIndex, inputValues, outputValues);
2896
+ return { saved: true, input: inputValues, output: outputValues, toolCalls: toolContext };
2897
+ }
2898
+ return { saved: false, input: inputValues, output: outputValues, toolCalls: toolContext };
2756
2899
  }
2757
2900
  async saveContextForItem(itemIndex, inputValues = {}, outputValues = {}) {
2758
2901
  const threadId = this.getNodeParameter('threadId', itemIndex);
@@ -2764,6 +2907,14 @@ class Mem0Memory {
2764
2907
  const rawOutput = pickText(outputValues, ['output', 'response', 'text', 'answer']);
2765
2908
  const output = cleanAssistantTranscriptText(rawOutput);
2766
2909
  const toolCalls = extractToolCalls(outputValues);
2910
+ store.captureState[key] = {
2911
+ last_save_at: nowIso(),
2912
+ last_save_had_input: Boolean(input),
2913
+ last_save_had_output: Boolean(output),
2914
+ last_save_tool_calls_captured: toolCalls.length,
2915
+ last_save_tool_names: toolCalls.map((tool) => tool.name).filter(Boolean).slice(0, 20),
2916
+ last_save_capture_sources: Array.from(new Set(toolCalls.map((tool) => tool.source).filter(Boolean))),
2917
+ };
2767
2918
  const recentForMem0 = [];
2768
2919
  const profileFromTurn = extractProfileFactsFromText(input, 'user_message', nowIso());
2769
2920
  if (Object.keys(profileFromTurn).length) {
@@ -2851,7 +3002,9 @@ class Mem0Memory {
2851
3002
  body.app_id = String(adv.appId);
2852
3003
  if (adv.runId)
2853
3004
  body.run_id = String(adv.runId);
2854
- const connectedEmbedding = await getConnectedEmbedding(this, itemIndex);
3005
+ if (adv.persistBackendMemories === false)
3006
+ return;
3007
+ const connectedEmbedding = adv.useVectorMemory === false ? null : await getConnectedEmbedding(this, itemIndex);
2855
3008
  if (connectedEmbedding) {
2856
3009
  const ids = { user_id: body.user_id, agent_id: body.agent_id, run_id: body.run_id };
2857
3010
  const clientMemories = [];
@@ -3119,6 +3272,8 @@ class Mem0Memory {
3119
3272
  const project = this.getNodeParameter('project', itemIndex, '');
3120
3273
  const adv = applyOperationalPreset(readAdvancedOptions(this, itemIndex));
3121
3274
  payloadFormat = adv.payloadFormat || payloadFormat;
3275
+ const vectorMemoryEnabled = adv.useVectorMemory !== false;
3276
+ const backendPersistenceEnabled = adv.persistBackendMemories !== false;
3122
3277
  const store = getMemoryStore(this);
3123
3278
  const key = userKeyFrom(threadId, adv, project);
3124
3279
  const queryParam = this.getNodeParameter('query', itemIndex, '');
@@ -3139,12 +3294,14 @@ class Mem0Memory {
3139
3294
  catch (error) {
3140
3295
  connectedAi.errors.push(`languageModel: ${error.message || String(error)}`);
3141
3296
  }
3142
- try {
3143
- connectedEmbedding = await this.getInputConnectionData(n8n_workflow_1.NodeConnectionTypes.AiEmbedding, itemIndex);
3144
- connectedAi.embedding = true;
3145
- }
3146
- catch (error) {
3147
- connectedAi.errors.push(`embedding: ${error.message || String(error)}`);
3297
+ if (vectorMemoryEnabled) {
3298
+ try {
3299
+ connectedEmbedding = await this.getInputConnectionData(n8n_workflow_1.NodeConnectionTypes.AiEmbedding, itemIndex);
3300
+ connectedAi.embedding = true;
3301
+ }
3302
+ catch (error) {
3303
+ connectedAi.errors.push(`embedding: ${error.message || String(error)}`);
3304
+ }
3148
3305
  }
3149
3306
  if (connectedEmbedding && typeof connectedEmbedding.embedQuery === 'function' && String(query || '').trim()) {
3150
3307
  try {
@@ -3166,7 +3323,7 @@ class Mem0Memory {
3166
3323
  catch { }
3167
3324
  let payload;
3168
3325
  let vectorMemories = [];
3169
- if (retrievalMode === 'semantic' || retrievalMode === 'semanticV2' || retrievalMode === 'hybrid') {
3326
+ if (vectorMemoryEnabled && (retrievalMode === 'semantic' || retrievalMode === 'semanticV2' || retrievalMode === 'hybrid')) {
3170
3327
  const body = { query: String(query || '') };
3171
3328
  // IDs
3172
3329
  body.user_id = key;
@@ -3303,7 +3460,7 @@ class Mem0Memory {
3303
3460
  payload = semMemories.map((m) => { var _a, _b; return ({ role: 'system', content: (_b = (_a = m.memory) !== null && _a !== void 0 ? _a : m.text) !== null && _b !== void 0 ? _b : JSON.stringify(m) }); });
3304
3461
  }
3305
3462
  }
3306
- else {
3463
+ else if (backendPersistenceEnabled) {
3307
3464
  const qs = {};
3308
3465
  qs.user_id = key;
3309
3466
  if (adv.agentId)
@@ -3339,7 +3496,7 @@ class Mem0Memory {
3339
3496
  connectedAi.errors.push(`graph.relations: ${error.message || String(error)}`);
3340
3497
  }
3341
3498
  }
3342
- if (connectedEmbedding && adv.includeRecentMessages !== false) {
3499
+ if (vectorMemoryEnabled && connectedEmbedding && adv.includeRecentMessages !== false && adv.includeRecentMessageProbe !== false) {
3343
3500
  try {
3344
3501
  const transcriptProbe = [
3345
3502
  'recent conversation transcript',
@@ -3374,7 +3531,7 @@ class Mem0Memory {
3374
3531
  connectedAi.errors.push(`recentMessageProbe: ${error.message || String(error)}`);
3375
3532
  }
3376
3533
  }
3377
- if (connectedEmbedding && adv.includeToolHistory !== false) {
3534
+ if (vectorMemoryEnabled && connectedEmbedding && adv.includeToolHistory !== false && adv.includeToolLedgerProbe !== false) {
3378
3535
  try {
3379
3536
  const toolProbe = [
3380
3537
  'Tool history ledger',
@@ -3412,7 +3569,7 @@ class Mem0Memory {
3412
3569
  let persistedRecentMessages = [];
3413
3570
  let persistedToolHistory = [];
3414
3571
  let persistedMemoryItems = [];
3415
- if (adv.includeRecentMessages !== false || adv.includeToolHistory !== false) {
3572
+ if (backendPersistenceEnabled && (adv.includeRecentMessages !== false || adv.includeToolHistory !== false)) {
3416
3573
  try {
3417
3574
  const qs = { user_id: key, limit: Math.max(Number(adv.recentMessagesLastN || 50) * 8, Number(adv.toolHistoryLastN || 10) * 12, 200) };
3418
3575
  if (adv.agentId)
@@ -3559,6 +3716,16 @@ class Mem0Memory {
3559
3716
  graph: graph.length,
3560
3717
  project: project || null,
3561
3718
  memoryNamespace: key,
3719
+ vectorMemoryEnabled,
3720
+ backendPersistenceEnabled,
3721
+ captureState: store.captureState[key] || {
3722
+ last_save_at: null,
3723
+ last_save_had_input: false,
3724
+ last_save_had_output: false,
3725
+ last_save_tool_calls_captured: 0,
3726
+ last_save_tool_names: [],
3727
+ last_save_capture_sources: [],
3728
+ },
3562
3729
  connectedAi,
3563
3730
  activeSummary: summaryDiagnostics,
3564
3731
  };
@@ -3803,6 +3970,7 @@ exports.Mem0Memory = Mem0Memory;
3803
3970
  exports.__private = {
3804
3971
  extractToolCallsFromText,
3805
3972
  extractToolCalls,
3973
+ extractToolCallsFromMessages,
3806
3974
  toolHistoryItemsFromMemory,
3807
3975
  explicitToolHistoryItemsFromMemory,
3808
3976
  toolHistoryFromMemory,
@@ -3855,6 +4023,8 @@ exports.__private = {
3855
4023
  embedQueryCached,
3856
4024
  compactToolResult,
3857
4025
  compactToolHistoryForAgent,
4026
+ compactVectorMemoriesForAgent,
4027
+ isConversationEchoMemory,
3858
4028
  compactOperationalStateForAgent,
3859
4029
  activeSummaryIsFresh,
3860
4030
  readActiveSummary,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
4
4
  "description": "Tembory node for n8n AI Agents with profile, tools, timeline, graph and semantic memory",
5
5
  "license": "MIT",
6
6
  "homepage": "https://tembory.com",