n8n-nodes-tembory 1.0.42 → 1.0.44

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.
@@ -632,6 +632,36 @@ const encodeToolLedger = (tools = [], threadId) => {
632
632
  })),
633
633
  })}`;
634
634
  };
635
+ const encodeTurnArchive = ({ threadId, messages = [], tools = [], workingMemory = {}, decisionState = {}, memoryCompression = {}, operationalState = {} }) => {
636
+ const chronological = sortConversationChronological(messages || []);
637
+ const orderedTools = sortToolHistory(tools || []);
638
+ return `Tembory long-term turn archive. Use vector search only when short-term SLM state and recent transcript are insufficient. ${safeStringify({
639
+ marker: 'tembory_turn_archive_v1',
640
+ thread_id: threadId,
641
+ generated_at: nowIso(),
642
+ conversation: chronological.map((msg) => ({
643
+ role: msg.role || 'user',
644
+ content: msg.content || '',
645
+ at: msg.at || nowIso(),
646
+ })),
647
+ tools: orderedTools.map((tool, index) => ({
648
+ id: tool.id || tool.callId || tool.call_id || '',
649
+ turn_id: tool.turnId || tool.turn_id || '',
650
+ sequence: tool.sequence || index + 1,
651
+ name: tool.name || tool.tool || tool.toolName || '',
652
+ reason: tool.reason || tool.source || '',
653
+ input: tool.input || '',
654
+ ok: tool.ok !== false,
655
+ output: tool.result || '',
656
+ at: tool.at || nowIso(),
657
+ source: tool.source || 'n8n',
658
+ })),
659
+ working_memory: workingMemory,
660
+ decision_state: decisionState,
661
+ memory_compression: memoryCompression,
662
+ operational_state: operationalState,
663
+ })}`;
664
+ };
635
665
  const parseRecentMessageMarker = (text) => {
636
666
  if (!text || typeof text !== 'string' || !text.startsWith(RECENT_MESSAGE_MARKER))
637
667
  return null;
@@ -1147,9 +1177,9 @@ const applyOperationalPreset = (advanced = {}) => {
1147
1177
  includeMemoryCompression: true,
1148
1178
  includeRecentMessages: true,
1149
1179
  includeRecentHighlights: false,
1150
- topK: 0,
1180
+ topK: 8,
1151
1181
  lastN: 0,
1152
- maxReturn: 0,
1182
+ maxReturn: 20,
1153
1183
  toolHistoryLastN: 15,
1154
1184
  recentMessagesLastN: 50,
1155
1185
  vectorMemoryMaxChars: 220,
@@ -2695,7 +2725,7 @@ class Mem0Memory {
2695
2725
  { displayName: 'App ID', name: 'appId', type: 'string', default: '' },
2696
2726
  { displayName: 'Run ID', name: 'runId', type: 'string', default: '' },
2697
2727
  { 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.' },
2728
+ { displayName: 'Usar Memória Vetorial no Caminho Quente', name: 'useVectorMemory', type: 'boolean', default: false, description: 'Quando ligado, usa busca BYO sob demanda para recuperar histórico longo. O padrão mantém o contexto quente em transcript + SLM e apenas arquiva o turno no vetor.' },
2699
2729
  { displayName: 'Persistir Memórias no Backend', name: 'persistBackendMemories', type: 'boolean', default: true, description: 'Quando desligado, mantém o estado no workflow/static data para reduzir latência.' },
2700
2730
  { displayName: 'Rerank', name: 'rerank', type: 'boolean', default: true, description: 'Reordenação por relevância (modos semânticos)', displayOptions: { show: { '/retrievalMode': ['semantic', 'semanticV2', 'hybrid'] } } },
2701
2731
  { 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'] } } },
@@ -3009,69 +3039,27 @@ class Mem0Memory {
3009
3039
  const connectedEmbedding = await getConnectedEmbedding(this, itemIndex);
3010
3040
  if (connectedEmbedding) {
3011
3041
  const ids = { user_id: body.user_id, agent_id: body.agent_id, run_id: body.run_id };
3012
- const clientMemories = [];
3013
- for (const message of messages) {
3014
- clientMemories.push(await createClientVectorMemory(connectedEmbedding, message.content, {
3015
- kind: 'conversation_message',
3016
- role: message.role,
3017
- thread_id: threadId,
3018
- project: project || undefined,
3019
- at: nowIso(),
3020
- source: 'n8n_connected_embedding',
3021
- }, ids));
3022
- }
3023
- if (adv.includeRecentMessages !== false && recentForMem0.length) {
3024
- for (const recent of recentForMem0) {
3025
- clientMemories.push(await createClientVectorMemory(connectedEmbedding, encodeRecentMessage(recent, threadId), {
3026
- kind: 'recent_message',
3027
- role: recent.role,
3028
- content: recent.content,
3029
- at: recent.at,
3030
- thread_id: threadId,
3031
- project: project || undefined,
3032
- source: 'n8n_connected_embedding',
3033
- }, ids));
3034
- }
3035
- clientMemories.push(await createClientVectorMemory(connectedEmbedding, encodeConversationLedger(recentForTurn, threadId), {
3036
- kind: 'conversation_ledger',
3037
- thread_id: threadId,
3038
- project: project || undefined,
3039
- source: 'n8n_connected_embedding',
3040
- generated_at: nowIso(),
3041
- }, ids));
3042
- }
3043
- if (adv.persistToolFactsToMem0 && toolCalls.length) {
3044
- const facts = toolCalls.map((tool) => `Tool ${tool.name} input=${tool.input}${tool.result ? ` result=${tool.result}` : ''}`).join('\n');
3045
- clientMemories.push(await createClientVectorMemory(connectedEmbedding, `Tool facts (read-only):\n${truncate(facts, 2000)}`, {
3046
- kind: 'tool_facts',
3047
- source: 'n8n_connected_embedding',
3048
- }, ids));
3049
- }
3050
- if (adv.includeToolHistory !== false && toolCalls.length) {
3051
- for (const tool of toolCalls) {
3052
- clientMemories.push(await createClientVectorMemory(connectedEmbedding, encodeToolCall(tool, threadId), {
3053
- kind: 'tool_history',
3054
- id: tool.id,
3055
- sequence: tool.sequence,
3056
- turn_id: tool.turnId,
3057
- name: tool.name,
3058
- input: tool.input,
3059
- ok: tool.ok,
3060
- result: tool.result,
3061
- at: tool.at,
3062
- source: tool.source || 'n8n_connected_embedding',
3063
- thread_id: threadId,
3064
- }, ids));
3065
- }
3066
- clientMemories.push(await createClientVectorMemory(connectedEmbedding, encodeToolLedger(toolHistoryForTurn, threadId), {
3067
- kind: 'tool_ledger',
3042
+ const archiveText = encodeTurnArchive({
3043
+ threadId,
3044
+ messages: recentForTurn,
3045
+ tools: toolHistoryForTurn,
3046
+ workingMemory: workingMemoryForTurn,
3047
+ decisionState: decisionStateForTurn,
3048
+ memoryCompression: compressionForTurn,
3049
+ operationalState: operationalStateForTurn,
3050
+ });
3051
+ await saveClientVectorMemories(this, [
3052
+ await createClientVectorMemory(connectedEmbedding, archiveText, {
3053
+ kind: 'turn_archive',
3068
3054
  thread_id: threadId,
3069
3055
  project: project || undefined,
3070
3056
  source: 'n8n_connected_embedding',
3071
3057
  generated_at: nowIso(),
3072
- }, ids));
3073
- }
3074
- await saveClientVectorMemories(this, clientMemories, ids);
3058
+ message_count: recentForTurn.length,
3059
+ tool_count: toolHistoryForTurn.length,
3060
+ latest_tool: toolHistoryForTurn.at(-1)?.name || null,
3061
+ }, ids),
3062
+ ], ids);
3075
3063
  if (adv.includeRecentMessages !== false && recentForMem0.length) {
3076
3064
  for (const recent of recentForMem0) {
3077
3065
  await safePersistLegacyMemory(this, {
@@ -3305,15 +3293,8 @@ class Mem0Memory {
3305
3293
  connectedAi.errors.push(`embedding: ${error.message || String(error)}`);
3306
3294
  }
3307
3295
  }
3308
- if (connectedEmbedding && typeof connectedEmbedding.embedQuery === 'function' && String(query || '').trim()) {
3309
- try {
3310
- await embedQueryCached(connectedEmbedding, String(query));
3311
- connectedAi.embeddingQuery = true;
3312
- }
3313
- catch (error) {
3314
- connectedAi.errors.push(`embedding.embedQuery: ${error.message || String(error)}`);
3315
- }
3316
- }
3296
+ if (connectedEmbedding && typeof connectedEmbedding.embedQuery === 'function' && String(query || '').trim())
3297
+ connectedAi.embeddingQuery = vectorMemoryEnabled;
3317
3298
  try {
3318
3299
  this.logger?.debug('Tembory loading memory variables before model invocation', {
3319
3300
  itemIndex,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.42",
3
+ "version": "1.0.44",
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",