n8n-nodes-tembory 1.0.6 → 1.0.8
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.
|
@@ -928,6 +928,34 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
928
928
|
toolHistoryLastN: 5,
|
|
929
929
|
recentMessagesLastN: 4,
|
|
930
930
|
},
|
|
931
|
+
productionNano: {
|
|
932
|
+
compactForAgent: true,
|
|
933
|
+
includeContextHeader: true,
|
|
934
|
+
includeSummary: true,
|
|
935
|
+
includeScores: false,
|
|
936
|
+
includeDiagnostics: false,
|
|
937
|
+
includeRelations: false,
|
|
938
|
+
includeToolHistory: true,
|
|
939
|
+
includeToolResults: true,
|
|
940
|
+
persistToolFactsToMem0: false,
|
|
941
|
+
includeToolHistorySemanticFallback: false,
|
|
942
|
+
includeProfileFacts: true,
|
|
943
|
+
includeOperationalState: true,
|
|
944
|
+
includeActionLedger: false,
|
|
945
|
+
includeEntityTimeline: false,
|
|
946
|
+
includeWorkingMemory: true,
|
|
947
|
+
includeDecisionState: true,
|
|
948
|
+
includeMemoryCompression: true,
|
|
949
|
+
includeRecentMessages: false,
|
|
950
|
+
includeRecentHighlights: false,
|
|
951
|
+
topK: 4,
|
|
952
|
+
lastN: 4,
|
|
953
|
+
maxReturn: 6,
|
|
954
|
+
toolHistoryLastN: 6,
|
|
955
|
+
recentMessagesLastN: 2,
|
|
956
|
+
vectorMemoryMaxChars: 220,
|
|
957
|
+
contextMaxChars: 6000,
|
|
958
|
+
},
|
|
931
959
|
audit: {
|
|
932
960
|
includeContextHeader: true,
|
|
933
961
|
includeSummary: true,
|
|
@@ -976,6 +1004,16 @@ const dedupeToolHistory = (items) => {
|
|
|
976
1004
|
const key = toolEventKey(item);
|
|
977
1005
|
if (seen.has(key))
|
|
978
1006
|
continue;
|
|
1007
|
+
const atMs = new Date(item.at || 0).getTime();
|
|
1008
|
+
const nearDuplicate = out.some((existing) => {
|
|
1009
|
+
const existingMs = new Date(existing.at || 0).getTime();
|
|
1010
|
+
return Math.abs(atMs - existingMs) < 1000
|
|
1011
|
+
&& String(item.name || '') === String(existing.name || '')
|
|
1012
|
+
&& canonicalToolInput(item.input) === canonicalToolInput(existing.input)
|
|
1013
|
+
&& String(item.result || '') === String(existing.result || '');
|
|
1014
|
+
});
|
|
1015
|
+
if (nearDuplicate)
|
|
1016
|
+
continue;
|
|
979
1017
|
seen.add(key);
|
|
980
1018
|
out.push(item);
|
|
981
1019
|
}
|
|
@@ -1211,7 +1249,7 @@ const deriveMemoryCompression = ({ recentMessages = [], toolHistory = [], profil
|
|
|
1211
1249
|
const lastMessages = pruneByLimit(recentMessages || [], maxItems).map((msg) => `${msg.role || 'message'}: ${truncate(msg.content || '', 160)}`);
|
|
1212
1250
|
const lastTools = pruneByLimit(toolHistory || [], maxItems).map((tool) => `${tool.name || 'tool'}:${tool.ok === false ? 'failed' : 'ok'}${tool.at ? `@${tool.at}` : ''}`);
|
|
1213
1251
|
const profile = renderProfileFacts(profileFacts);
|
|
1214
|
-
const activeMemories = (vectorMemories || []).map(enrichContextMemory).filter((item) => item.status === 'active').slice(0, maxItems);
|
|
1252
|
+
const activeMemories = (vectorMemories || []).map((memory) => ({ ...enrichContextMemory(memory), compact_memory: contextMemoryText(memory, 220) })).filter((item) => item.status === 'active').slice(0, maxItems);
|
|
1215
1253
|
return {
|
|
1216
1254
|
turn_summary: lastMessages.length ? lastMessages : [],
|
|
1217
1255
|
session_summary: {
|
|
@@ -1223,7 +1261,7 @@ const deriveMemoryCompression = ({ recentMessages = [], toolHistory = [], profil
|
|
|
1223
1261
|
workflow_summary: {
|
|
1224
1262
|
active_memory_count: activeMemories.length,
|
|
1225
1263
|
top_active_memories: activeMemories.map((item) => ({
|
|
1226
|
-
memory:
|
|
1264
|
+
memory: item.compact_memory,
|
|
1227
1265
|
confidence: item.confidence,
|
|
1228
1266
|
source: item.source,
|
|
1229
1267
|
})),
|
|
@@ -1298,6 +1336,105 @@ const contextMemoryText = (memory, max = 700) => {
|
|
|
1298
1336
|
}
|
|
1299
1337
|
return truncate(text, max);
|
|
1300
1338
|
};
|
|
1339
|
+
const approxTokenCount = (text) => Math.ceil(String(text || '').length / 4);
|
|
1340
|
+
const importantJsonFields = ['reservation_id', 'confirmation_id', 'selected_from_message', 'status', 'next_step', 'available_slots', 'timezone', 'error'];
|
|
1341
|
+
const pickImportantFields = (value) => {
|
|
1342
|
+
if (value === null || value === undefined)
|
|
1343
|
+
return {};
|
|
1344
|
+
const out = {};
|
|
1345
|
+
const visit = (item) => {
|
|
1346
|
+
if (!item || typeof item !== 'object')
|
|
1347
|
+
return;
|
|
1348
|
+
if (Array.isArray(item)) {
|
|
1349
|
+
item.slice(0, 3).forEach(visit);
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
for (const key of importantJsonFields) {
|
|
1353
|
+
if (item[key] !== undefined && out[key] === undefined)
|
|
1354
|
+
out[key] = item[key];
|
|
1355
|
+
}
|
|
1356
|
+
if (item.args)
|
|
1357
|
+
visit(item.args);
|
|
1358
|
+
if (item.result)
|
|
1359
|
+
visit(item.result);
|
|
1360
|
+
};
|
|
1361
|
+
visit(value);
|
|
1362
|
+
return out;
|
|
1363
|
+
};
|
|
1364
|
+
const compactToolResult = (result, max = 360) => {
|
|
1365
|
+
const text = String(result || '');
|
|
1366
|
+
if (!text.trim())
|
|
1367
|
+
return undefined;
|
|
1368
|
+
try {
|
|
1369
|
+
const parsed = JSON.parse(text);
|
|
1370
|
+
const picked = pickImportantFields(parsed);
|
|
1371
|
+
if (Object.keys(picked).length)
|
|
1372
|
+
return truncate(safeStringify(picked), max);
|
|
1373
|
+
}
|
|
1374
|
+
catch { }
|
|
1375
|
+
const picked = {};
|
|
1376
|
+
for (const key of importantJsonFields) {
|
|
1377
|
+
const re = new RegExp(`["']?${key}["']?\\s*[:=]\\s*["']?([^"',}\\]]+)`, 'i');
|
|
1378
|
+
const match = re.exec(text);
|
|
1379
|
+
if (match)
|
|
1380
|
+
picked[key] = match[1];
|
|
1381
|
+
}
|
|
1382
|
+
if (Object.keys(picked).length)
|
|
1383
|
+
return truncate(safeStringify(picked), max);
|
|
1384
|
+
return truncate(text, max);
|
|
1385
|
+
};
|
|
1386
|
+
const compactToolHistoryForAgent = (toolHistory = [], maxItems = 6, includeResults = true) => pruneByLimit(toolHistory || [], maxItems).map((tool) => ({
|
|
1387
|
+
name: tool.name,
|
|
1388
|
+
status: tool.ok === false ? 'failed' : 'ok',
|
|
1389
|
+
at: tool.at,
|
|
1390
|
+
input: truncate(String(tool.input || ''), 180) || undefined,
|
|
1391
|
+
result: includeResults ? compactToolResult(tool.result, 360) : undefined,
|
|
1392
|
+
}));
|
|
1393
|
+
const compactOperationalStateForAgent = (state = {}) => {
|
|
1394
|
+
const agenda = state.agenda_state || {};
|
|
1395
|
+
return {
|
|
1396
|
+
last_tool: state.last_tool || null,
|
|
1397
|
+
tool_counts: state.tool_counts || {},
|
|
1398
|
+
agenda_state: {
|
|
1399
|
+
has_availability: Boolean(agenda.has_availability),
|
|
1400
|
+
has_pre_reservation: Boolean(agenda.has_pre_reservation),
|
|
1401
|
+
has_confirmation: Boolean(agenda.has_confirmation),
|
|
1402
|
+
has_pending_pre_reservation: Boolean(agenda.has_pending_pre_reservation),
|
|
1403
|
+
latest_availability: compactToolResult(agenda.latest_availability_result),
|
|
1404
|
+
latest_pre_reservation: compactToolResult(agenda.latest_pre_reservation_result),
|
|
1405
|
+
latest_confirmation: compactToolResult(agenda.latest_confirmation_result),
|
|
1406
|
+
},
|
|
1407
|
+
blocked_without_context: state.blocked_without_context || [],
|
|
1408
|
+
guidance: (state.guidance || []).slice(0, 3),
|
|
1409
|
+
};
|
|
1410
|
+
};
|
|
1411
|
+
const compactMemoryCompressionForAgent = (compression = {}) => ({
|
|
1412
|
+
turn_summary: (compression.turn_summary || []).slice(-3),
|
|
1413
|
+
session_tools: (((compression.session_summary || {}).tools) || []).slice(-6),
|
|
1414
|
+
agenda_state: ((compression.session_summary || {}).agenda_state) ? {
|
|
1415
|
+
has_availability: Boolean(compression.session_summary.agenda_state.has_availability),
|
|
1416
|
+
has_pre_reservation: Boolean(compression.session_summary.agenda_state.has_pre_reservation),
|
|
1417
|
+
has_confirmation: Boolean(compression.session_summary.agenda_state.has_confirmation),
|
|
1418
|
+
has_pending_pre_reservation: Boolean(compression.session_summary.agenda_state.has_pending_pre_reservation),
|
|
1419
|
+
} : undefined,
|
|
1420
|
+
active_memory_count: ((compression.workflow_summary || {}).active_memory_count) || 0,
|
|
1421
|
+
});
|
|
1422
|
+
const compactVectorMemoriesForAgent = (vectorMemories = [], toolHistory = [], maxItems = 3) => {
|
|
1423
|
+
const hasStructuredTools = Array.isArray(toolHistory) && toolHistory.length > 0;
|
|
1424
|
+
return (vectorMemories || [])
|
|
1425
|
+
.map((memory) => contextMemoryText(memory, 220))
|
|
1426
|
+
.filter(Boolean)
|
|
1427
|
+
.filter((text) => !hasStructuredTools || !/^\[tool_events_extracted\]/i.test(text))
|
|
1428
|
+
.slice(0, maxItems);
|
|
1429
|
+
};
|
|
1430
|
+
const contextSizeOfMessages = (messages = []) => {
|
|
1431
|
+
const perMessage = (messages || []).map((message, index) => {
|
|
1432
|
+
const content = String(message.content || '');
|
|
1433
|
+
return { index, role: message.role || 'system', chars: content.length, approx_tokens: approxTokenCount(content) };
|
|
1434
|
+
});
|
|
1435
|
+
const chars = perMessage.reduce((sum, item) => sum + item.chars, 0);
|
|
1436
|
+
return { chars, approx_tokens: approxTokenCount((messages || []).map((m) => m.content || '').join('\n')), messages: perMessage };
|
|
1437
|
+
};
|
|
1301
1438
|
const wrapElefaiMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
|
|
1302
1439
|
get(target, prop) {
|
|
1303
1440
|
if (prop === 'loadMemoryVariables') {
|
|
@@ -1367,14 +1504,81 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1367
1504
|
const includeHeader = adv.includeContextHeader !== false;
|
|
1368
1505
|
const includeSummary = adv.includeSummary !== false;
|
|
1369
1506
|
const includeScores = adv.includeScores !== false;
|
|
1507
|
+
const compactForAgent = Boolean(adv.compactForAgent);
|
|
1370
1508
|
const sections = [];
|
|
1371
1509
|
if (includeHeader) {
|
|
1372
1510
|
sections.push({
|
|
1373
1511
|
section: 'context_header',
|
|
1374
1512
|
title: 'Tembory context',
|
|
1375
|
-
value:
|
|
1513
|
+
value: compactForAgent
|
|
1514
|
+
? 'Read-only memory. Follow next_expected_action when present. Before calling downstream tools, verify required prior tool context in tool_history or operational_state. Do not repeat tools listed in do_not_repeat_tools.'
|
|
1515
|
+
: 'Use this context as read-only memory. Prefer it over guessing. Do not mention internal section names to the user. Treat next_expected_action as an instruction, not as a suggestion. If it says to call a tool now, call that tool instead of asking the user the same question again. If the user asks to continue, chooses a slot, says ok/sim, reserve, confirm, update, cancel, or performs any downstream action that depends on a prior tool result, first verify the required prior result in tool_history, recent_messages, or vector memories. If the required prior result is absent, do not call the downstream tool; ask for the missing context or call the appropriate prerequisite tool.',
|
|
1376
1516
|
});
|
|
1377
1517
|
}
|
|
1518
|
+
if (compactForAgent) {
|
|
1519
|
+
if (includeSummary) {
|
|
1520
|
+
const summary = compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.summaryMaxFacts || 3));
|
|
1521
|
+
sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no non-tool vector memories to summarize' });
|
|
1522
|
+
}
|
|
1523
|
+
sections.push({
|
|
1524
|
+
section: 'working_memory',
|
|
1525
|
+
title: 'Working memory',
|
|
1526
|
+
value: adv.includeWorkingMemory === false ? null : (workingMemory || {}),
|
|
1527
|
+
why_null: adv.includeWorkingMemory === false ? 'working memory disabled' : undefined,
|
|
1528
|
+
});
|
|
1529
|
+
sections.push({
|
|
1530
|
+
section: 'decision_state',
|
|
1531
|
+
title: 'Decision state',
|
|
1532
|
+
value: adv.includeDecisionState === false ? null : (decisionState || {}),
|
|
1533
|
+
why_null: adv.includeDecisionState === false ? 'decision state disabled' : undefined,
|
|
1534
|
+
});
|
|
1535
|
+
sections.push({
|
|
1536
|
+
section: 'operational_state',
|
|
1537
|
+
title: 'Operational state',
|
|
1538
|
+
value: adv.includeOperationalState === false ? null : compactOperationalStateForAgent(operationalState || {}),
|
|
1539
|
+
why_null: adv.includeOperationalState === false ? 'operational state disabled' : undefined,
|
|
1540
|
+
});
|
|
1541
|
+
sections.push({
|
|
1542
|
+
section: 'tool_history',
|
|
1543
|
+
title: 'Tool history',
|
|
1544
|
+
value: {
|
|
1545
|
+
enabled: adv.includeToolHistory !== false,
|
|
1546
|
+
items: adv.includeToolHistory === false ? [] : compactToolHistoryForAgent(toolHistory, adv.toolHistoryLastN || 6, adv.includeToolResults !== false),
|
|
1547
|
+
},
|
|
1548
|
+
});
|
|
1549
|
+
sections.push({
|
|
1550
|
+
section: 'profile_facts',
|
|
1551
|
+
title: 'Profile facts',
|
|
1552
|
+
value: adv.includeProfileFacts === false ? null : renderProfileFacts(profileFacts),
|
|
1553
|
+
why_null: adv.includeProfileFacts === false ? 'profile facts disabled' : undefined,
|
|
1554
|
+
});
|
|
1555
|
+
sections.push({
|
|
1556
|
+
section: 'memory_compression',
|
|
1557
|
+
title: 'Memory compression',
|
|
1558
|
+
value: adv.includeMemoryCompression === false ? null : compactMemoryCompressionForAgent(memoryCompression || {}),
|
|
1559
|
+
why_null: adv.includeMemoryCompression === false ? 'memory compression disabled' : undefined,
|
|
1560
|
+
});
|
|
1561
|
+
const audit = {
|
|
1562
|
+
kind: 'elefai.brain.context.v1',
|
|
1563
|
+
meta: { user_id: userId, payloadFormat, query, compact_for_agent: true },
|
|
1564
|
+
sections,
|
|
1565
|
+
diagnostics,
|
|
1566
|
+
};
|
|
1567
|
+
const renderCompactSection = (section) => {
|
|
1568
|
+
if (section.value === null || section.value === undefined)
|
|
1569
|
+
return `## ${section.title}\n${section.why_null || 'empty'}`;
|
|
1570
|
+
if (typeof section.value === 'string')
|
|
1571
|
+
return `## ${section.title}\n${section.value}`;
|
|
1572
|
+
if (Array.isArray(section.value))
|
|
1573
|
+
return `## ${section.title}\n${section.value.length ? section.value.map((item) => typeof item === 'string' ? `- ${item}` : `- ${truncate(safeStringify(item), 420)}`).join('\n') : '(empty)'}`;
|
|
1574
|
+
return `## ${section.title}\n${truncate(safeStringify(section.value), 900)}`;
|
|
1575
|
+
};
|
|
1576
|
+
if (payloadFormat === 'auditJson')
|
|
1577
|
+
return [{ role: 'system', content: JSON.stringify(audit, null, 2) }];
|
|
1578
|
+
if (payloadFormat === 'auditBlocks')
|
|
1579
|
+
return sections.map((section) => ({ role: 'system', content: renderCompactSection(section) }));
|
|
1580
|
+
return [{ role: 'system', content: truncate(sections.map(renderCompactSection).join('\n\n'), Number(adv.contextMaxChars || 6000)) }];
|
|
1581
|
+
}
|
|
1378
1582
|
if (includeSummary) {
|
|
1379
1583
|
const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
|
|
1380
1584
|
sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no vector memories to summarize' });
|
|
@@ -1644,6 +1848,7 @@ class Mem0Memory {
|
|
|
1644
1848
|
{ name: 'Diagnóstico Completo', value: 'diagnostic' },
|
|
1645
1849
|
{ name: 'Produção Balanceada', value: 'productionBalanced' },
|
|
1646
1850
|
{ name: 'Produção Econômica', value: 'productionCheap' },
|
|
1851
|
+
{ name: 'Produção Nano/SLM', value: 'productionNano' },
|
|
1647
1852
|
{ name: 'Auditoria', value: 'audit' },
|
|
1648
1853
|
],
|
|
1649
1854
|
default: 'custom',
|
|
@@ -1663,6 +1868,8 @@ class Mem0Memory {
|
|
|
1663
1868
|
{ displayName: 'MMR (diversidade)', name: 'mmr', type: 'boolean', default: true, description: 'Aplicar diversidade de resultados (Maximal Marginal Relevance)', displayOptions: { show: { '/retrievalMode': ['hybrid'] } } },
|
|
1664
1869
|
{ displayName: 'MMR Lambda', name: 'mmrLambda', type: 'number', typeOptions: { minValue: 0, maxValue: 1, numberPrecision: 2 }, default: 0.5, description: 'Equilíbrio entre relevância e diversidade no MMR', displayOptions: { show: { '/retrievalMode': ['hybrid'] } } },
|
|
1665
1870
|
{ displayName: 'Incluir Cabeçalho de Contexto', name: 'includeContextHeader', type: 'boolean', default: true },
|
|
1871
|
+
{ displayName: 'Compactar Contexto Para Agente', name: 'compactForAgent', type: 'boolean', default: false, description: 'Entrega ao agente apenas o estado acionável: working memory, decisões, estado operacional e histórico de tools compacto. Mantém detalhes completos no audit/debug.' },
|
|
1872
|
+
{ displayName: 'Máximo de Caracteres do Contexto', name: 'contextMaxChars', type: 'number', default: 6000, description: 'Limite final aplicado quando Compactar Contexto Para Agente estiver ativo.' },
|
|
1666
1873
|
{ displayName: 'Incluir Resumo', name: 'includeSummary', type: 'boolean', default: true },
|
|
1667
1874
|
{ displayName: 'Máximo de Fatos no Resumo', name: 'summaryMaxFacts', type: 'number', default: 4 },
|
|
1668
1875
|
{ displayName: 'Incluir Scores', name: 'includeScores', type: 'boolean', default: true },
|
|
@@ -2352,12 +2559,13 @@ class Mem0Memory {
|
|
|
2352
2559
|
diagnostics,
|
|
2353
2560
|
adv,
|
|
2354
2561
|
});
|
|
2562
|
+
diagnostics.contextSize = contextSizeOfMessages(payload);
|
|
2355
2563
|
const normalizedVectorMemories = vectorMemories.map((m) => {
|
|
2356
2564
|
const scoreMeta = scoreMetaOf(m);
|
|
2357
2565
|
const rawScore = scoreOf(m);
|
|
2358
2566
|
const enriched = enrichContextMemory(m);
|
|
2359
2567
|
return {
|
|
2360
|
-
memory:
|
|
2568
|
+
memory: contextMemoryText(m, Number(adv.vectorMemoryMaxChars || 700)),
|
|
2361
2569
|
score: adv.includeScores === false ? undefined : (rawScore !== undefined ? rawScore : scoreMeta.hybridScore ?? scoreMeta.recencyScore ?? 'unavailable'),
|
|
2362
2570
|
semantic_score: adv.includeScores === false ? undefined : scoreMeta.semanticScore,
|
|
2363
2571
|
recency_score: adv.includeScores === false ? undefined : scoreMeta.recencyScore,
|
|
@@ -2372,7 +2580,7 @@ class Mem0Memory {
|
|
|
2372
2580
|
raw: adv.includeDiagnostics ? m : undefined,
|
|
2373
2581
|
};
|
|
2374
2582
|
});
|
|
2375
|
-
const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map(
|
|
2583
|
+
const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
|
|
2376
2584
|
const contextText = payload.map((message) => String(message.content || '')).join('\n\n');
|
|
2377
2585
|
const audit = {
|
|
2378
2586
|
kind: 'elefai.brain.context.v1',
|
|
@@ -2394,6 +2602,7 @@ class Mem0Memory {
|
|
|
2394
2602
|
includeOperationalState: adv.includeOperationalState !== false,
|
|
2395
2603
|
includeActionLedger: adv.includeActionLedger !== false,
|
|
2396
2604
|
includeEntityTimeline: adv.includeEntityTimeline !== false,
|
|
2605
|
+
compactForAgent: Boolean(adv.compactForAgent),
|
|
2397
2606
|
includeWorkingMemory: adv.includeWorkingMemory !== false,
|
|
2398
2607
|
includeDecisionState: adv.includeDecisionState !== false,
|
|
2399
2608
|
includeMemoryCompression: adv.includeMemoryCompression !== false,
|
|
@@ -2577,4 +2786,9 @@ exports.__private = {
|
|
|
2577
2786
|
mergeProfileFacts,
|
|
2578
2787
|
renderProfileFacts,
|
|
2579
2788
|
isNoisyProfileValue,
|
|
2789
|
+
approxTokenCount,
|
|
2790
|
+
contextSizeOfMessages,
|
|
2791
|
+
compactToolResult,
|
|
2792
|
+
compactToolHistoryForAgent,
|
|
2793
|
+
compactOperationalStateForAgent,
|
|
2580
2794
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-tembory",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
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",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"lintfix": "tslint --fix -p tsconfig.json -c tslint.json",
|
|
25
25
|
"test": "node --test test/*.test.js",
|
|
26
26
|
"smoke:n8n:multiturn": "node scripts/smoke-n8n-multiturn-tools.js",
|
|
27
|
-
"
|
|
27
|
+
"simulate:agent-context": "node scripts/simulate-agent-context.js",
|
|
28
|
+
"prepublishOnly": "npm test"
|
|
28
29
|
},
|
|
29
30
|
"files": [
|
|
30
31
|
"dist",
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const Module = require('node:module');
|
|
3
|
+
|
|
4
|
+
const originalLoad = Module._load;
|
|
5
|
+
Module._load = function patchedLoad(request, parent, isMain) {
|
|
6
|
+
if (request === 'n8n-workflow') {
|
|
7
|
+
return {
|
|
8
|
+
NodeConnectionTypes: {
|
|
9
|
+
AiMemory: 'ai_memory',
|
|
10
|
+
AiLanguageModel: 'ai_languageModel',
|
|
11
|
+
AiEmbedding: 'ai_embedding',
|
|
12
|
+
},
|
|
13
|
+
NodeApiError: class NodeApiError extends Error {},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (request === '@langchain/core/messages') {
|
|
17
|
+
return {
|
|
18
|
+
HumanMessage: class HumanMessage { constructor(content) { this.content = content; } _getType() { return 'human'; } },
|
|
19
|
+
AIMessage: class AIMessage { constructor(content) { this.content = content; } _getType() { return 'ai'; } },
|
|
20
|
+
SystemMessage: class SystemMessage { constructor(content) { this.content = content; } _getType() { return 'system'; } },
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return originalLoad.call(this, request, parent, isMain);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const core = require('../dist/nodes/Mem0/Mem0Memory.node.js').__private;
|
|
27
|
+
|
|
28
|
+
const toolHistory = [
|
|
29
|
+
{
|
|
30
|
+
id: 'tool_ry3twg',
|
|
31
|
+
name: 'agenda_consultar_disponibilidade',
|
|
32
|
+
input: '',
|
|
33
|
+
ok: true,
|
|
34
|
+
at: '2026-05-14T05:34:12.460Z',
|
|
35
|
+
source: 'used_tools_text',
|
|
36
|
+
result: '[{"args":{"tool":"agenda_consultar_disponibilidade","available_slots":"2026-05-12T09:00,2026-05-12T14:00,2026-05-13T10:30","timezone":"America/Sao_Paulo","next_step":"escolher_um_horario"}}]',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'tool_mu9qd2',
|
|
40
|
+
name: 'agenda_pre_reservar_horario',
|
|
41
|
+
input: '',
|
|
42
|
+
ok: true,
|
|
43
|
+
at: '2026-05-14T05:34:34.017Z',
|
|
44
|
+
source: 'used_tools_text',
|
|
45
|
+
result: '[{"args":{"tool":"agenda_pre_reservar_horario","reservation_id":"RES-ELEFAI-LAB-001","selected_from_message":"dia 13","status":"pre_reserved","next_step":"confirmar_agendamento"}}]',
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const vectorMemories = [
|
|
50
|
+
{
|
|
51
|
+
memory: '[Used tools: Tool: agenda_pre_reservar_horario, Input: , Result: [{"args":{"tool":"agenda_pre_reservar_horario","reservation_id":"RES-ELEFAI-LAB-001","selected_from_message":"dia 13","status":"pre_reserved","next_step":"confirmar_agendamento"}}]] Calling agenda_pre_reservar_horario with input: {"id":"call_bfHlltcjI1vCagRkav0fj8Ha"}\nPré-reserva feita para o dia 13.\nSe quiser, posso confirmar agora.',
|
|
52
|
+
created_at: '2026-05-14T05:34:35.373020Z',
|
|
53
|
+
elefaiScore: { semanticScore: 0.71, recencyScore: 0.99, hybridScore: 0.81, source: 'semantic' },
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
memory: '[Used tools: Tool: agenda_consultar_disponibilidade, Input: , Result: [{"args":{"tool":"agenda_consultar_disponibilidade","available_slots":"2026-05-12T09:00,2026-05-12T14:00,2026-05-13T10:30","timezone":"America/Sao_Paulo","next_step":"escolher_um_horario"}}]] Temos estes horários vagos:\n- 12/05 às 09:00\n- 12/05 às 14:00\n- 13/05 às 10:30',
|
|
57
|
+
created_at: '2026-05-14T05:34:14.717988Z',
|
|
58
|
+
elefaiScore: { semanticScore: 0.7, recencyScore: 0.99, hybridScore: 0.8, source: 'semantic' },
|
|
59
|
+
},
|
|
60
|
+
{ memory: 'Oi! Como posso ajudar?', created_at: '2026-05-14T05:33:47.194630Z' },
|
|
61
|
+
{ memory: 'oi', created_at: '2026-05-14T05:33:47.194355Z' },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const operationalState = core.deriveOperationalState(toolHistory, {}, [], true);
|
|
65
|
+
const workingMemory = {
|
|
66
|
+
current_goal: 'call agenda_confirmar_agendamento now; do not ask the same confirmation question again',
|
|
67
|
+
current_task: 'call agenda_confirmar_agendamento now; do not ask the same confirmation question again',
|
|
68
|
+
last_user_intent: 'affirm',
|
|
69
|
+
last_user_message: 'ok',
|
|
70
|
+
next_expected_action: 'call agenda_confirmar_agendamento now; do not ask the same confirmation question again',
|
|
71
|
+
};
|
|
72
|
+
const decisionState = core.deriveDecisionState({ query: 'ok', toolHistory, operationalState, workingMemory });
|
|
73
|
+
const memoryCompression = core.deriveMemoryCompression({ toolHistory, operationalState, vectorMemories });
|
|
74
|
+
const common = {
|
|
75
|
+
payloadFormat: 'structured',
|
|
76
|
+
query: 'ok',
|
|
77
|
+
userId: 'd48292bd4c9f4eccb9120092e3acd073',
|
|
78
|
+
profileFacts: {},
|
|
79
|
+
workingMemory,
|
|
80
|
+
decisionState,
|
|
81
|
+
memoryCompression,
|
|
82
|
+
operationalState,
|
|
83
|
+
actionLedger: core.deriveActionLedger(toolHistory, 20, true),
|
|
84
|
+
entityTimeline: core.deriveEntityTimeline({}, [], [], toolHistory),
|
|
85
|
+
vectorMemories,
|
|
86
|
+
recentMessages: [],
|
|
87
|
+
toolHistory,
|
|
88
|
+
highlights: [
|
|
89
|
+
'tool agenda_consultar_disponibilidade: [{"args":{"available_slots":"2026-05-12T09:00,2026-05-12T14:00,2026-05-13T10:30"}}]',
|
|
90
|
+
'tool agenda_pre_reservar_horario: [{"args":{"reservation_id":"RES-ELEFAI-LAB-001","status":"pre_reserved"}}]',
|
|
91
|
+
],
|
|
92
|
+
graph: [],
|
|
93
|
+
diagnostics: {},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const modes = [
|
|
97
|
+
['productionBalanced', core.applyOperationalPreset({ operationPreset: 'productionBalanced' })],
|
|
98
|
+
['productionNano', core.applyOperationalPreset({ operationPreset: 'productionNano' })],
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
for (const [name, adv] of modes) {
|
|
102
|
+
const messages = core.buildContextMessages({ ...common, adv });
|
|
103
|
+
const text = messages.map((message) => message.content).join('\n\n');
|
|
104
|
+
console.log(JSON.stringify({
|
|
105
|
+
mode: name,
|
|
106
|
+
size: core.contextSizeOfMessages(messages),
|
|
107
|
+
has_next_expected_action: /next_expected_action/.test(text),
|
|
108
|
+
has_do_not_repeat_tools: /do_not_repeat_tools/.test(text),
|
|
109
|
+
has_reservation_id: /RES-ELEFAI-LAB-001/.test(text),
|
|
110
|
+
has_available_slots: /available_slots/.test(text),
|
|
111
|
+
has_duplicate_calling_text: /Calling agenda_pre_reservar_horario/.test(text),
|
|
112
|
+
}, null, 2));
|
|
113
|
+
}
|