n8n-nodes-tembory 1.0.23 → 1.0.25

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/README.md CHANGED
@@ -2,7 +2,19 @@
2
2
 
3
3
  Node de memoria operacional da Tembory para agentes de IA no n8n.
4
4
 
5
- Versao atual: `1.0.23`.
5
+ Versao atual: `1.0.25`.
6
+
7
+ ## 1.0.25
8
+
9
+ - Carrega a janela recente tambem a partir de memorias vetoriais com `kind=recent_message`.
10
+ - Adiciona uma busca auxiliar de transcript recente no modo BYO-AI para perguntas como "qual foi minha ultima mensagem" e "o que eu ja disse".
11
+ - Evita depender do endpoint legado `/v1/memories/` para reconstruir conversa curta.
12
+
13
+ ## 1.0.24
14
+
15
+ - Corrige falha `409 Backend LLM/embedder is disabled` no `saveContext` quando o node usa embeddings conectados pelo n8n.
16
+ - Writes legados de transcript/tool markers agora sao best-effort no modo BYO-AI, sem derrubar a execucao do agente.
17
+ - Remove o prefixo tecnico `THREAD:<id>` usado em testes MCP antes de montar query/contexto de memoria.
6
18
 
7
19
  ## 1.0.23
8
20
 
@@ -70,6 +70,22 @@ const searchClientVectorMemories = async (ctx, embedding, query, body = {}) => {
70
70
  embedding: await embedQueryCached(embedding, text),
71
71
  });
72
72
  };
73
+ const safePersistLegacyMemory = async (ctx, body, diagnostics = {}) => {
74
+ try {
75
+ return await GenericFunctions_1.mem0ApiRequest.call(ctx, 'POST', '/v1/memories/', body);
76
+ }
77
+ catch (error) {
78
+ try {
79
+ ctx.logger?.warn('Tembory skipped legacy memory write after BYO-AI vector persistence', {
80
+ ...diagnostics,
81
+ message: error.message || String(error),
82
+ });
83
+ }
84
+ catch { }
85
+ return null;
86
+ }
87
+ };
88
+ const stripThreadTestPrefix = (value = '') => String(value || '').replace(/^THREAD:[A-Za-z0-9_-]+\s+/, '');
73
89
  const stableStringify = (value) => {
74
90
  if (value === null || typeof value !== 'object')
75
91
  return JSON.stringify(value);
@@ -2616,7 +2632,7 @@ class Mem0Memory {
2616
2632
  const adv = applyOperationalPreset(readAdvancedOptions(this, itemIndex));
2617
2633
  const store = getMemoryStore(this);
2618
2634
  const key = userKeyFrom(threadId, adv, project);
2619
- const input = pickText(inputValues, ['input', 'chatInput', 'text', 'query', 'question']);
2635
+ const input = stripThreadTestPrefix(pickText(inputValues, ['input', 'chatInput', 'text', 'query', 'question']));
2620
2636
  const output = pickText(outputValues, ['output', 'response', 'text', 'answer']);
2621
2637
  const toolCalls = extractToolCalls(outputValues);
2622
2638
  const recentForMem0 = [];
@@ -2758,7 +2774,7 @@ class Mem0Memory {
2758
2774
  await saveClientVectorMemories(this, clientMemories, ids);
2759
2775
  if (adv.includeRecentMessages !== false && recentForMem0.length) {
2760
2776
  for (const recent of recentForMem0) {
2761
- await GenericFunctions_1.mem0ApiRequest.call(this, 'POST', '/v1/memories/', {
2777
+ await safePersistLegacyMemory(this, {
2762
2778
  messages: [{ role: 'system', content: encodeRecentMessage(recent, threadId) }],
2763
2779
  infer: false,
2764
2780
  user_id: body.user_id,
@@ -2773,12 +2789,15 @@ class Mem0Memory {
2773
2789
  project: project || undefined,
2774
2790
  source: 'tembory_transcript',
2775
2791
  },
2792
+ }, {
2793
+ kind: 'recent_message',
2794
+ user_id: body.user_id,
2776
2795
  });
2777
2796
  }
2778
2797
  }
2779
2798
  if (adv.includeToolHistory !== false && toolCalls.length) {
2780
2799
  for (const tool of toolCalls) {
2781
- await GenericFunctions_1.mem0ApiRequest.call(this, 'POST', '/v1/memories/', {
2800
+ await safePersistLegacyMemory(this, {
2782
2801
  messages: [{ role: 'system', content: encodeToolCall(tool, threadId) }],
2783
2802
  infer: false,
2784
2803
  user_id: body.user_id,
@@ -2798,6 +2817,10 @@ class Mem0Memory {
2798
2817
  thread_id: threadId,
2799
2818
  project: project || undefined,
2800
2819
  },
2820
+ }, {
2821
+ kind: 'tool_history',
2822
+ user_id: body.user_id,
2823
+ tool: tool.name,
2801
2824
  });
2802
2825
  }
2803
2826
  }
@@ -2892,7 +2915,7 @@ class Mem0Memory {
2892
2915
  const store = getMemoryStore(this);
2893
2916
  const key = userKeyFrom(threadId, adv, project);
2894
2917
  const queryParam = this.getNodeParameter('query', itemIndex, '');
2895
- const query = asSearchQuery(queryParam) || asSearchQuery(inputValues.query) || asSearchQuery(inputValues.input) || asSearchQuery(inputValues.chatInput);
2918
+ const query = stripThreadTestPrefix(asSearchQuery(queryParam) || asSearchQuery(inputValues.query) || asSearchQuery(inputValues.input) || asSearchQuery(inputValues.chatInput));
2896
2919
  let connectedLanguageModel;
2897
2920
  let connectedEmbedding;
2898
2921
  const connectedAi = {
@@ -3109,6 +3132,41 @@ class Mem0Memory {
3109
3132
  connectedAi.errors.push(`graph.relations: ${error.message || String(error)}`);
3110
3133
  }
3111
3134
  }
3135
+ if (connectedEmbedding && adv.includeRecentMessages !== false) {
3136
+ try {
3137
+ const transcriptProbe = [
3138
+ 'recent conversation transcript',
3139
+ 'last user messages previous message',
3140
+ query,
3141
+ ].filter(Boolean).join('\n');
3142
+ const transcriptBody = {
3143
+ user_id: key,
3144
+ agent_id: adv.agentId ? String(adv.agentId) : undefined,
3145
+ run_id: adv.runId ? String(adv.runId) : undefined,
3146
+ top_k: Math.max(Number(adv.recentMessagesLastN || 8) * 3, 20),
3147
+ filters: { kind: 'recent_message' },
3148
+ };
3149
+ const transcriptRes = await searchClientVectorMemories(this, connectedEmbedding, transcriptProbe, transcriptBody);
3150
+ const transcriptMemories = normalizeResults(transcriptRes).map((memory) => withTemboryScore(memory, {
3151
+ semanticScore: scoreOf(memory),
3152
+ source: 'recent_message_probe',
3153
+ }));
3154
+ if (transcriptMemories.length) {
3155
+ const seen = new Set(vectorMemories.map((memory) => stableHash(memoryText(memory) || safeStringify(memory))));
3156
+ for (const memory of transcriptMemories) {
3157
+ const hash = stableHash(memoryText(memory) || safeStringify(memory));
3158
+ if (!seen.has(hash)) {
3159
+ seen.add(hash);
3160
+ vectorMemories.push(memory);
3161
+ }
3162
+ }
3163
+ connectedAi.recentMessageProbe = true;
3164
+ }
3165
+ }
3166
+ catch (error) {
3167
+ connectedAi.errors.push(`recentMessageProbe: ${error.message || String(error)}`);
3168
+ }
3169
+ }
3112
3170
  let persistedRecentMessages = [];
3113
3171
  let persistedToolHistory = [];
3114
3172
  let persistedMemoryItems = [];
@@ -3132,12 +3190,16 @@ class Mem0Memory {
3132
3190
  .filter(Boolean)
3133
3191
  .sort((a, b) => new Date(a.at || 0).getTime() - new Date(b.at || 0).getTime());
3134
3192
  }
3193
+ const vectorRecentMessages = adv.includeRecentMessages === false ? [] : vectorMemories
3194
+ .map(recentMessageFromMemory)
3195
+ .filter(Boolean)
3196
+ .sort((a, b) => new Date(a.at || 0).getTime() - new Date(b.at || 0).getTime());
3135
3197
  if (adv.includeToolHistory !== false) {
3136
3198
  persistedToolHistory = persistedMemoryItems
3137
3199
  .flatMap(toolHistoryItemsFromMemory)
3138
3200
  .sort((a, b) => new Date(a.at || 0).getTime() - new Date(b.at || 0).getTime());
3139
3201
  }
3140
- const storedRecentMessages = adv.includeRecentMessages === false ? [] : (store.recentMessages[key] || []).concat(persistedRecentMessages);
3202
+ const storedRecentMessages = adv.includeRecentMessages === false ? [] : (store.recentMessages[key] || []).concat(persistedRecentMessages, vectorRecentMessages);
3141
3203
  const allRecentMessages = dedupeRecentMessages(appendCurrentUserMessage(storedRecentMessages, query));
3142
3204
  const recentMessages = pruneByLimit(allRecentMessages, Math.max(Number(adv.recentMessagesLastN || 8), 8));
3143
3205
  const toolHistoryFromRecentMessages = [];
@@ -3517,6 +3579,8 @@ exports.__private = {
3517
3579
  applyOperationalPreset,
3518
3580
  flattenAdvancedGroups,
3519
3581
  asSearchQuery,
3582
+ safePersistLegacyMemory,
3583
+ stripThreadTestPrefix,
3520
3584
  canonicalToolInput,
3521
3585
  buildContextMessages,
3522
3586
  inferToolGuard,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
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",