n8n-nodes-tembory 1.0.5 → 1.0.7

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.
@@ -630,17 +630,21 @@ const toolHistoryFromMemory = (item) => {
630
630
  source: meta.source || 'metadata',
631
631
  };
632
632
  };
633
- const toolHistoryItemsFromMemory = (item) => {
633
+ const explicitToolHistoryItemsFromMemory = (item) => {
634
634
  const meta = metadataOf(item);
635
635
  const content = meta.content || item.memory || item.text || item.value || item.content || item.data;
636
636
  const marked = parseToolHistoryMarker(content);
637
637
  if (marked)
638
638
  return [marked];
639
- if (meta.kind === 'recent_message') {
640
- const textCalls = extractToolCallsFromText(content, meta.at || item.created_at || item.createdAt || nowIso());
641
- if (textCalls.length)
642
- return textCalls;
643
- }
639
+ const textCalls = extractToolCallsFromText(content, meta.at || item.created_at || item.createdAt || nowIso());
640
+ return textCalls.length ? textCalls : [];
641
+ };
642
+ const toolHistoryItemsFromMemory = (item) => {
643
+ const meta = metadataOf(item);
644
+ const content = meta.content || item.memory || item.text || item.value || item.content || item.data;
645
+ const explicit = explicitToolHistoryItemsFromMemory(item);
646
+ if (explicit.length)
647
+ return explicit;
644
648
  const single = toolHistoryFromMemory(item);
645
649
  return single ? [single] : [];
646
650
  };
@@ -972,6 +976,16 @@ const dedupeToolHistory = (items) => {
972
976
  const key = toolEventKey(item);
973
977
  if (seen.has(key))
974
978
  continue;
979
+ const atMs = new Date(item.at || 0).getTime();
980
+ const nearDuplicate = out.some((existing) => {
981
+ const existingMs = new Date(existing.at || 0).getTime();
982
+ return Math.abs(atMs - existingMs) < 1000
983
+ && String(item.name || '') === String(existing.name || '')
984
+ && canonicalToolInput(item.input) === canonicalToolInput(existing.input)
985
+ && String(item.result || '') === String(existing.result || '');
986
+ });
987
+ if (nearDuplicate)
988
+ continue;
975
989
  seen.add(key);
976
990
  out.push(item);
977
991
  }
@@ -1207,7 +1221,7 @@ const deriveMemoryCompression = ({ recentMessages = [], toolHistory = [], profil
1207
1221
  const lastMessages = pruneByLimit(recentMessages || [], maxItems).map((msg) => `${msg.role || 'message'}: ${truncate(msg.content || '', 160)}`);
1208
1222
  const lastTools = pruneByLimit(toolHistory || [], maxItems).map((tool) => `${tool.name || 'tool'}:${tool.ok === false ? 'failed' : 'ok'}${tool.at ? `@${tool.at}` : ''}`);
1209
1223
  const profile = renderProfileFacts(profileFacts);
1210
- const activeMemories = (vectorMemories || []).map(enrichContextMemory).filter((item) => item.status === 'active').slice(0, maxItems);
1224
+ const activeMemories = (vectorMemories || []).map((memory) => ({ ...enrichContextMemory(memory), compact_memory: contextMemoryText(memory, 220) })).filter((item) => item.status === 'active').slice(0, maxItems);
1211
1225
  return {
1212
1226
  turn_summary: lastMessages.length ? lastMessages : [],
1213
1227
  session_summary: {
@@ -1219,7 +1233,7 @@ const deriveMemoryCompression = ({ recentMessages = [], toolHistory = [], profil
1219
1233
  workflow_summary: {
1220
1234
  active_memory_count: activeMemories.length,
1221
1235
  top_active_memories: activeMemories.map((item) => ({
1222
- memory: truncate(item.memory, 220),
1236
+ memory: item.compact_memory,
1223
1237
  confidence: item.confidence,
1224
1238
  source: item.source,
1225
1239
  })),
@@ -1283,6 +1297,17 @@ const deriveContextHealth = ({ userId = '', project = '', vectorMemories = [], r
1283
1297
  generated_at: nowIso(),
1284
1298
  };
1285
1299
  };
1300
+ const contextMemoryText = (memory, max = 700) => {
1301
+ const text = memoryText(memory);
1302
+ const tools = explicitToolHistoryItemsFromMemory(memory);
1303
+ if (tools.length) {
1304
+ const names = tools.map((tool) => `${tool.name || 'tool'}:${tool.ok === false ? 'failed' : 'ok'}`).join(', ');
1305
+ const ids = tools.map((tool) => tool.result || tool.input || '').join(' ');
1306
+ const idMatch = /(reservation_id|confirmation_id|id)["':\s]+([A-Za-z0-9_.:-]+)/i.exec(ids);
1307
+ return truncate(`[tool_events_extracted] ${names}${idMatch ? ` ${idMatch[1]}=${idMatch[2]}` : ''}. See Tool history for structured details.`, max);
1308
+ }
1309
+ return truncate(text, max);
1310
+ };
1286
1311
  const wrapElefaiMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
1287
1312
  get(target, prop) {
1288
1313
  if (prop === 'loadMemoryVariables') {
@@ -1361,7 +1386,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1361
1386
  });
1362
1387
  }
1363
1388
  if (includeSummary) {
1364
- const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map(memoryText).filter(Boolean);
1389
+ const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
1365
1390
  sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no vector memories to summarize' });
1366
1391
  }
1367
1392
  sections.push({
@@ -1419,7 +1444,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1419
1444
  const scoreMeta = scoreMetaOf(m);
1420
1445
  const rawScore = scoreOf(m);
1421
1446
  return {
1422
- memory: memoryText(m),
1447
+ memory: contextMemoryText(m, Number(adv.vectorMemoryMaxChars || 700)),
1423
1448
  score: includeScores ? (rawScore !== undefined ? rawScore : scoreMeta.hybridScore ?? scoreMeta.recencyScore ?? 'unavailable') : undefined,
1424
1449
  semantic_score: includeScores ? scoreMeta.semanticScore : undefined,
1425
1450
  recency_score: includeScores ? scoreMeta.recencyScore : undefined,
@@ -2231,8 +2256,9 @@ class Mem0Memory {
2231
2256
  for (const msg of recentMessages)
2232
2257
  toolHistoryFromRecentMessages.push(...extractToolCallsFromText(msg.content, msg.at));
2233
2258
  }
2259
+ const toolHistoryFromVectorMarkers = adv.includeToolHistory === false ? [] : vectorMemories.flatMap(explicitToolHistoryItemsFromMemory);
2234
2260
  const toolHistoryFromVectorMemories = adv.includeToolHistory === false || adv.includeToolHistorySemanticFallback !== true ? [] : vectorMemories.flatMap(toolHistoryItemsFromMemory);
2235
- const toolHistory = adv.includeToolHistory === false ? [] : applyToolHistoryWindow((store.toolHistory[key] || []).concat(persistedToolHistory, toolHistoryFromRecentMessages, toolHistoryFromVectorMemories), adv.toolHistoryTTLSeconds, adv.toolHistoryLastN || 15);
2261
+ const toolHistory = adv.includeToolHistory === false ? [] : applyToolHistoryWindow((store.toolHistory[key] || []).concat(persistedToolHistory, toolHistoryFromRecentMessages, toolHistoryFromVectorMarkers, toolHistoryFromVectorMemories), adv.toolHistoryTTLSeconds, adv.toolHistoryLastN || 15);
2236
2262
  const highlights = adv.includeRecentHighlights === false ? [] : getRecentHighlights(recentMessages, toolHistory, adv.recentHighlightsMaxItems || 6);
2237
2263
  const profileFacts = adv.includeProfileFacts === false ? {} : mergeProfileFacts(store.profileFacts[key], profileFactsFromMessages(allRecentMessages), profileFactsFromMemories(vectorMemories));
2238
2264
  if (adv.includeProfileFacts !== false && Object.keys(profileFacts).length) {
@@ -2246,7 +2272,7 @@ class Mem0Memory {
2246
2272
  let connectedModelSummary = '';
2247
2273
  if (connectedLanguageModel && typeof connectedLanguageModel.invoke === 'function' && (vectorMemories.length || String(query || '').trim()) && adv.includeSummary !== false) {
2248
2274
  try {
2249
- const facts = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map(memoryText).filter(Boolean).join('\n') || '(no vector memories found)';
2275
+ const facts = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 500)).filter(Boolean).join('\n') || '(no vector memories found)';
2250
2276
  if (facts || String(query || '').trim()) {
2251
2277
  const response = await connectedLanguageModel.invoke([
2252
2278
  toBaseMessage({
@@ -2341,7 +2367,7 @@ class Mem0Memory {
2341
2367
  const rawScore = scoreOf(m);
2342
2368
  const enriched = enrichContextMemory(m);
2343
2369
  return {
2344
- memory: memoryText(m),
2370
+ memory: contextMemoryText(m, Number(adv.vectorMemoryMaxChars || 700)),
2345
2371
  score: adv.includeScores === false ? undefined : (rawScore !== undefined ? rawScore : scoreMeta.hybridScore ?? scoreMeta.recencyScore ?? 'unavailable'),
2346
2372
  semantic_score: adv.includeScores === false ? undefined : scoreMeta.semanticScore,
2347
2373
  recency_score: adv.includeScores === false ? undefined : scoreMeta.recencyScore,
@@ -2356,7 +2382,7 @@ class Mem0Memory {
2356
2382
  raw: adv.includeDiagnostics ? m : undefined,
2357
2383
  };
2358
2384
  });
2359
- const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map(memoryText).filter(Boolean);
2385
+ const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
2360
2386
  const contextText = payload.map((message) => String(message.content || '')).join('\n\n');
2361
2387
  const audit = {
2362
2388
  kind: 'elefai.brain.context.v1',
@@ -2530,6 +2556,7 @@ exports.__private = {
2530
2556
  extractToolCallsFromText,
2531
2557
  extractToolCalls,
2532
2558
  toolHistoryItemsFromMemory,
2559
+ explicitToolHistoryItemsFromMemory,
2533
2560
  toolHistoryFromMemory,
2534
2561
  recentMessageFromMemory,
2535
2562
  dedupeToolHistory,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
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",