n8n-nodes-tembory 1.0.11 → 1.0.12
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 +3 -1
- package/dist/nodes/Mem0/Mem0Memory.node.js +156 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Node de memoria operacional da Tembory para agentes de IA no n8n.
|
|
4
4
|
|
|
5
|
-
Versao atual: `1.0.
|
|
5
|
+
Versao atual: `1.0.12`.
|
|
6
6
|
|
|
7
7
|
O Tembory entrega contexto rico para o AI Agent sem depender apenas do historico textual da conversa. Ele combina memoria semantica, working memory, decision state, fatos estaveis do lead, historico de tools, estado operacional, action ledger, timeline de entidades, compressao de memoria, grafo, mensagens recentes e diagnosticos.
|
|
8
8
|
|
|
9
9
|
Nos presets de producao, o contexto e organizado como um pacote acionavel: secoes vazias sao removidas, evidencias de tools ficam canonicas em `tool_history`/`operational_state`, e blocos como `decision_state`, `working_memory` e `memory_compression` sao compactados sem perder IDs, proximas acoes, slots, reservas, confirmacoes e bloqueios de repeticao.
|
|
10
10
|
|
|
11
|
+
Quando um modelo barato esta conectado ao Tembory, os presets de producao usam esse SLM para gerar um resumo ativo do contexto. Em modo `auto`, ele organiza tanto o estado atual (`working_memory`, `tool_history`, `operational_state`, `decision_state`) quanto memorias vetoriais recuperadas. Assim o primeiro turno ja pode receber highlights uteis mesmo antes de haver resultados do banco vetorial.
|
|
12
|
+
|
|
11
13
|
## Smoke tecnico
|
|
12
14
|
|
|
13
15
|
Antes de publicar uma versao, rode:
|
|
@@ -882,6 +882,8 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
882
882
|
const preset = String(advanced.operationPreset || 'custom');
|
|
883
883
|
const presets = {
|
|
884
884
|
diagnostic: {
|
|
885
|
+
summarySource: 'auto',
|
|
886
|
+
includeConnectedModelSummary: true,
|
|
885
887
|
includeContextHeader: true,
|
|
886
888
|
includeSummary: true,
|
|
887
889
|
includeScores: true,
|
|
@@ -906,6 +908,8 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
906
908
|
recentMessagesLastN: 8,
|
|
907
909
|
},
|
|
908
910
|
productionBalanced: {
|
|
911
|
+
summarySource: 'auto',
|
|
912
|
+
includeConnectedModelSummary: true,
|
|
909
913
|
compactStateSections: true,
|
|
910
914
|
includeContextHeader: true,
|
|
911
915
|
includeSummary: true,
|
|
@@ -931,8 +935,12 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
931
935
|
recentMessagesLastN: 6,
|
|
932
936
|
vectorMemoryMaxChars: 360,
|
|
933
937
|
contextMaxChars: 10000,
|
|
938
|
+
connectedModelSummaryMaxChars: 900,
|
|
939
|
+
connectedModelSummaryInputMaxChars: 3200,
|
|
934
940
|
},
|
|
935
941
|
productionCheap: {
|
|
942
|
+
summarySource: 'activeContext',
|
|
943
|
+
includeConnectedModelSummary: true,
|
|
936
944
|
compactStateSections: true,
|
|
937
945
|
includeContextHeader: true,
|
|
938
946
|
includeSummary: false,
|
|
@@ -958,8 +966,12 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
958
966
|
recentMessagesLastN: 4,
|
|
959
967
|
vectorMemoryMaxChars: 260,
|
|
960
968
|
contextMaxChars: 7000,
|
|
969
|
+
connectedModelSummaryMaxChars: 700,
|
|
970
|
+
connectedModelSummaryInputMaxChars: 2400,
|
|
961
971
|
},
|
|
962
972
|
productionNano: {
|
|
973
|
+
summarySource: 'auto',
|
|
974
|
+
includeConnectedModelSummary: true,
|
|
963
975
|
compactForAgent: true,
|
|
964
976
|
includeContextHeader: true,
|
|
965
977
|
includeSummary: true,
|
|
@@ -986,8 +998,12 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
986
998
|
recentMessagesLastN: 2,
|
|
987
999
|
vectorMemoryMaxChars: 220,
|
|
988
1000
|
contextMaxChars: 6000,
|
|
1001
|
+
connectedModelSummaryMaxChars: 700,
|
|
1002
|
+
connectedModelSummaryInputMaxChars: 2200,
|
|
989
1003
|
},
|
|
990
1004
|
audit: {
|
|
1005
|
+
summarySource: 'auto',
|
|
1006
|
+
includeConnectedModelSummary: true,
|
|
991
1007
|
includeContextHeader: true,
|
|
992
1008
|
includeSummary: true,
|
|
993
1009
|
includeScores: true,
|
|
@@ -1524,6 +1540,87 @@ const compactVectorMemoriesForAgent = (vectorMemories = [], toolHistory = [], ma
|
|
|
1524
1540
|
.filter((text) => !hasStructuredTools || !/^\[tool_events_extracted\]/i.test(text))
|
|
1525
1541
|
.slice(0, maxItems);
|
|
1526
1542
|
};
|
|
1543
|
+
const modelResponseText = (response) => {
|
|
1544
|
+
const content = response === null || response === void 0 ? void 0 : response.content;
|
|
1545
|
+
if (typeof content === 'string')
|
|
1546
|
+
return content;
|
|
1547
|
+
if (Array.isArray(content)) {
|
|
1548
|
+
return content.map((item) => {
|
|
1549
|
+
if (typeof item === 'string')
|
|
1550
|
+
return item;
|
|
1551
|
+
if (item && typeof item === 'object' && typeof item.text === 'string')
|
|
1552
|
+
return item.text;
|
|
1553
|
+
if (item && typeof item === 'object' && typeof item.content === 'string')
|
|
1554
|
+
return item.content;
|
|
1555
|
+
return '';
|
|
1556
|
+
}).filter(Boolean).join('\n');
|
|
1557
|
+
}
|
|
1558
|
+
if (typeof (response === null || response === void 0 ? void 0 : response.text) === 'string')
|
|
1559
|
+
return response.text;
|
|
1560
|
+
return response === undefined || response === null ? '' : String(response);
|
|
1561
|
+
};
|
|
1562
|
+
const cleanModelSummaryText = (value, max = 900) => {
|
|
1563
|
+
let text = modelResponseText(value).trim();
|
|
1564
|
+
if (!text)
|
|
1565
|
+
return '';
|
|
1566
|
+
try {
|
|
1567
|
+
const parsed = JSON.parse(text);
|
|
1568
|
+
text = modelResponseText(parsed) || (Array.isArray(parsed) ? parsed.map(modelResponseText).filter(Boolean).join('\n') : '');
|
|
1569
|
+
if (!text && parsed && typeof parsed === 'object') {
|
|
1570
|
+
const bullets = parsed.highlights || parsed.current_summary || parsed.summary || parsed.facts;
|
|
1571
|
+
if (Array.isArray(bullets))
|
|
1572
|
+
text = bullets.map((item) => `- ${typeof item === 'string' ? item : safeStringify(item)}`).join('\n');
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
catch { }
|
|
1576
|
+
text = text
|
|
1577
|
+
.replace(/^\s*\[\s*\{\s*"type"\s*:\s*"text"\s*,\s*"text"\s*:\s*"/, '')
|
|
1578
|
+
.replace(/"\s*,\s*"annotations"\s*:\s*\[\s*\]\s*\}\s*\]\s*$/, '')
|
|
1579
|
+
.replace(/\\n/g, '\n')
|
|
1580
|
+
.trim();
|
|
1581
|
+
return truncate(text, max);
|
|
1582
|
+
};
|
|
1583
|
+
const buildConnectedModelSummaryInput = ({ query, profileFacts, workingMemory, decisionState, memoryCompression, operationalState, toolHistory, recentMessages, vectorMemories, highlights, adv }) => {
|
|
1584
|
+
const source = String(adv.summarySource || 'auto');
|
|
1585
|
+
if (source === 'off' || source === 'disabled' || adv.includeConnectedModelSummary === false)
|
|
1586
|
+
return '';
|
|
1587
|
+
const includeVectors = source === 'auto' || source === 'vectorOnly' || source === 'vectors';
|
|
1588
|
+
const includeActive = source === 'auto' || source === 'activeContext' || source === 'active';
|
|
1589
|
+
const payload = cleanContextValue({
|
|
1590
|
+
query: String(query || ''),
|
|
1591
|
+
active_context: includeActive ? {
|
|
1592
|
+
profile_facts: renderProfileFacts(profileFacts),
|
|
1593
|
+
working_memory: compactWorkingMemoryForAgent(workingMemory || {}),
|
|
1594
|
+
decision_state: compactDecisionStateForAgent(decisionState || {}),
|
|
1595
|
+
operational_state: compactOperationalStateForAgent(operationalState || {}),
|
|
1596
|
+
memory_compression: compactMemoryCompressionForAgent(memoryCompression || {}),
|
|
1597
|
+
tool_history: compactToolHistoryForAgent(toolHistory || [], adv.summaryToolHistoryLastN || adv.toolHistoryLastN || 6, adv.includeToolResults !== false),
|
|
1598
|
+
recent_messages: pruneByLimit(recentMessages || [], adv.summaryRecentMessagesLastN || 4).map((message) => cleanContextValue({
|
|
1599
|
+
role: message.role,
|
|
1600
|
+
content: truncate(message.content, 240),
|
|
1601
|
+
at: message.at,
|
|
1602
|
+
})),
|
|
1603
|
+
highlights: (highlights || []).slice(0, adv.summaryHighlightsMaxItems || 4),
|
|
1604
|
+
} : undefined,
|
|
1605
|
+
vector_memories: includeVectors ? compactVectorMemoriesForAgent(vectorMemories || [], toolHistory || [], adv.summaryMaxFacts || 4) : undefined,
|
|
1606
|
+
});
|
|
1607
|
+
const hasActiveSignal = includeActive && Boolean((payload.active_context && Object.keys(payload.active_context).length) || payload.query);
|
|
1608
|
+
const hasVectorSignal = includeVectors && Array.isArray(payload.vector_memories) && payload.vector_memories.length > 0;
|
|
1609
|
+
if (!hasActiveSignal && !hasVectorSignal)
|
|
1610
|
+
return '';
|
|
1611
|
+
return truncate(safeStringify(payload), Number(adv.connectedModelSummaryInputMaxChars || 3000));
|
|
1612
|
+
};
|
|
1613
|
+
const invokeConnectedModelSummary = async (connectedLanguageModel, summaryInput, adv = {}) => {
|
|
1614
|
+
if (!connectedLanguageModel || typeof connectedLanguageModel.invoke !== 'function' || !summaryInput)
|
|
1615
|
+
return '';
|
|
1616
|
+
const response = await connectedLanguageModel.invoke([
|
|
1617
|
+
toBaseMessage({
|
|
1618
|
+
role: 'user',
|
|
1619
|
+
content: `Organize the Tembory memory context for the next agent turn. Return concise Portuguese bullets only. Preserve IDs, dates, tool names, next action, do-not-repeat instructions, and contradictions. Do not invent facts.\n\nContext:\n${summaryInput}`,
|
|
1620
|
+
}),
|
|
1621
|
+
]);
|
|
1622
|
+
return cleanModelSummaryText(response, Number(adv.connectedModelSummaryMaxChars || 900));
|
|
1623
|
+
};
|
|
1527
1624
|
const contextSizeOfMessages = (messages = []) => {
|
|
1528
1625
|
const perMessage = (messages || []).map((message, index) => {
|
|
1529
1626
|
const content = String(message.content || '');
|
|
@@ -1601,7 +1698,7 @@ const wrapTemboryMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
|
|
|
1601
1698
|
return target[prop];
|
|
1602
1699
|
},
|
|
1603
1700
|
});
|
|
1604
|
-
const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, workingMemory, decisionState, memoryCompression, operationalState, actionLedger, entityTimeline, vectorMemories, recentMessages, toolHistory, highlights, graph, diagnostics, adv }) => {
|
|
1701
|
+
const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, workingMemory, decisionState, memoryCompression, operationalState, actionLedger, entityTimeline, vectorMemories, recentMessages, toolHistory, highlights, graph, diagnostics, connectedModelSummary, adv }) => {
|
|
1605
1702
|
const includeHeader = adv.includeContextHeader !== false;
|
|
1606
1703
|
const includeSummary = adv.includeSummary !== false;
|
|
1607
1704
|
const includeScores = adv.includeScores !== false;
|
|
@@ -1622,6 +1719,9 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1622
1719
|
const summary = compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.summaryMaxFacts || 3));
|
|
1623
1720
|
sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no non-tool vector memories to summarize' });
|
|
1624
1721
|
}
|
|
1722
|
+
if (connectedModelSummary && adv.includeConnectedModelSummary !== false) {
|
|
1723
|
+
sections.push({ section: 'connected_model_summary', title: 'SLM summary', value: connectedModelSummary });
|
|
1724
|
+
}
|
|
1625
1725
|
sections.push({
|
|
1626
1726
|
section: 'working_memory',
|
|
1627
1727
|
title: 'Working memory',
|
|
@@ -1687,6 +1787,9 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1687
1787
|
: vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
|
|
1688
1788
|
sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no vector memories to summarize' });
|
|
1689
1789
|
}
|
|
1790
|
+
if (connectedModelSummary && adv.includeConnectedModelSummary !== false) {
|
|
1791
|
+
sections.push({ section: 'connected_model_summary', title: 'SLM summary', value: connectedModelSummary });
|
|
1792
|
+
}
|
|
1690
1793
|
sections.push({
|
|
1691
1794
|
section: 'working_memory',
|
|
1692
1795
|
title: 'Working memory',
|
|
@@ -1995,6 +2098,22 @@ class Mem0Memory {
|
|
|
1995
2098
|
{ displayName: 'Organizar Seções de Produção', name: 'compactStateSections', type: 'boolean', default: false, description: 'Renderiza blocos de produção com campos canônicos, remove seções vazias e evita duplicar evidências já presentes em tool_history/operational_state.' },
|
|
1996
2099
|
{ displayName: 'Máximo de Caracteres do Contexto', name: 'contextMaxChars', type: 'number', default: 6000, description: 'Limite final aplicado ao contexto entregue ao agente em modos estruturados de produção.' },
|
|
1997
2100
|
{ displayName: 'Incluir Resumo', name: 'includeSummary', type: 'boolean', default: true },
|
|
2101
|
+
{ displayName: 'Incluir Resumo do SLM', name: 'includeConnectedModelSummary', type: 'boolean', default: true, description: 'Usa o modelo barato conectado ao Tembory para organizar contexto ativo e/ou memórias vetoriais em bullets curtos.' },
|
|
2102
|
+
{
|
|
2103
|
+
displayName: 'Fonte do Resumo do SLM',
|
|
2104
|
+
name: 'summarySource',
|
|
2105
|
+
type: 'options',
|
|
2106
|
+
options: [
|
|
2107
|
+
{ name: 'Automático', value: 'auto' },
|
|
2108
|
+
{ name: 'Contexto Ativo', value: 'activeContext' },
|
|
2109
|
+
{ name: 'Somente Vetores', value: 'vectorOnly' },
|
|
2110
|
+
{ name: 'Desligado', value: 'off' },
|
|
2111
|
+
],
|
|
2112
|
+
default: 'auto',
|
|
2113
|
+
description: 'Define se o SLM resume working memory/tool state, memórias vetoriais, ambos ou nada.',
|
|
2114
|
+
},
|
|
2115
|
+
{ displayName: 'Máximo de Caracteres de Entrada do SLM', name: 'connectedModelSummaryInputMaxChars', type: 'number', default: 3000 },
|
|
2116
|
+
{ displayName: 'Máximo de Caracteres do Resumo do SLM', name: 'connectedModelSummaryMaxChars', type: 'number', default: 900 },
|
|
1998
2117
|
{ displayName: 'Máximo de Fatos no Resumo', name: 'summaryMaxFacts', type: 'number', default: 4 },
|
|
1999
2118
|
{ displayName: 'Incluir Scores', name: 'includeScores', type: 'boolean', default: true },
|
|
2000
2119
|
{ displayName: 'Incluir Diagnóstico', name: 'includeDiagnostics', type: 'boolean', default: false },
|
|
@@ -2623,34 +2742,6 @@ class Mem0Memory {
|
|
|
2623
2742
|
}
|
|
2624
2743
|
catch { }
|
|
2625
2744
|
}
|
|
2626
|
-
let connectedModelSummary = '';
|
|
2627
|
-
if (connectedLanguageModel && typeof connectedLanguageModel.invoke === 'function' && vectorMemories.length && adv.includeSummary !== false) {
|
|
2628
|
-
try {
|
|
2629
|
-
const facts = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 500)).filter(Boolean).join('\n') || '(no vector memories found)';
|
|
2630
|
-
if (facts) {
|
|
2631
|
-
const response = await connectedLanguageModel.invoke([
|
|
2632
|
-
toBaseMessage({
|
|
2633
|
-
role: 'user',
|
|
2634
|
-
content: `Summarize available Tembory context as concise factual bullets. If there are no memories, return exactly "(empty)".\n\nQuery: ${String(query || '')}\n\nMemories:\n${truncate(facts, 3000)}`,
|
|
2635
|
-
}),
|
|
2636
|
-
]);
|
|
2637
|
-
connectedModelSummary = truncate(response?.content || response?.text || String(response || ''), 1200);
|
|
2638
|
-
connectedAi.languageModelSummary = true;
|
|
2639
|
-
}
|
|
2640
|
-
}
|
|
2641
|
-
catch (error) {
|
|
2642
|
-
connectedAi.errors.push(`languageModel.invoke: ${error.message || String(error)}`);
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
const diagnostics = {
|
|
2646
|
-
vectorMemories: vectorMemories.length,
|
|
2647
|
-
recentMessages: recentMessages.length,
|
|
2648
|
-
toolHistory: toolHistory.length,
|
|
2649
|
-
graph: graph.length,
|
|
2650
|
-
project: project || null,
|
|
2651
|
-
memoryNamespace: key,
|
|
2652
|
-
connectedAi,
|
|
2653
|
-
};
|
|
2654
2745
|
const includeToolResults = adv.includeToolResults !== false;
|
|
2655
2746
|
const operationalState = deriveOperationalState(toolHistory, renderProfileFacts(profileFacts), recentMessages, includeToolResults);
|
|
2656
2747
|
const actionLedger = deriveActionLedger(toolHistory, adv.actionLedgerMaxItems || adv.toolHistoryLastN || 20, includeToolResults);
|
|
@@ -2677,6 +2768,38 @@ class Mem0Memory {
|
|
|
2677
2768
|
vectorMemories,
|
|
2678
2769
|
maxItems: adv.compressionMaxItems || 6,
|
|
2679
2770
|
});
|
|
2771
|
+
let connectedModelSummary = '';
|
|
2772
|
+
if (connectedLanguageModel && typeof connectedLanguageModel.invoke === 'function' && adv.includeSummary !== false && adv.includeConnectedModelSummary !== false) {
|
|
2773
|
+
try {
|
|
2774
|
+
const summaryInput = buildConnectedModelSummaryInput({
|
|
2775
|
+
query,
|
|
2776
|
+
profileFacts,
|
|
2777
|
+
workingMemory,
|
|
2778
|
+
decisionState,
|
|
2779
|
+
memoryCompression,
|
|
2780
|
+
operationalState,
|
|
2781
|
+
toolHistory,
|
|
2782
|
+
recentMessages,
|
|
2783
|
+
vectorMemories,
|
|
2784
|
+
highlights,
|
|
2785
|
+
adv,
|
|
2786
|
+
});
|
|
2787
|
+
connectedModelSummary = await invokeConnectedModelSummary(connectedLanguageModel, summaryInput, adv);
|
|
2788
|
+
connectedAi.languageModelSummary = Boolean(connectedModelSummary);
|
|
2789
|
+
}
|
|
2790
|
+
catch (error) {
|
|
2791
|
+
connectedAi.errors.push(`languageModel.invoke: ${error.message || String(error)}`);
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
const diagnostics = {
|
|
2795
|
+
vectorMemories: vectorMemories.length,
|
|
2796
|
+
recentMessages: recentMessages.length,
|
|
2797
|
+
toolHistory: toolHistory.length,
|
|
2798
|
+
graph: graph.length,
|
|
2799
|
+
project: project || null,
|
|
2800
|
+
memoryNamespace: key,
|
|
2801
|
+
connectedAi,
|
|
2802
|
+
};
|
|
2680
2803
|
const contextHealth = deriveContextHealth({
|
|
2681
2804
|
userId: key,
|
|
2682
2805
|
project,
|
|
@@ -2714,6 +2837,7 @@ class Mem0Memory {
|
|
|
2714
2837
|
highlights,
|
|
2715
2838
|
graph,
|
|
2716
2839
|
diagnostics,
|
|
2840
|
+
connectedModelSummary,
|
|
2717
2841
|
adv,
|
|
2718
2842
|
});
|
|
2719
2843
|
diagnostics.contextSize = contextSizeOfMessages(payload);
|
|
@@ -2949,4 +3073,7 @@ exports.__private = {
|
|
|
2949
3073
|
compactToolResult,
|
|
2950
3074
|
compactToolHistoryForAgent,
|
|
2951
3075
|
compactOperationalStateForAgent,
|
|
3076
|
+
buildConnectedModelSummaryInput,
|
|
3077
|
+
cleanModelSummaryText,
|
|
3078
|
+
invokeConnectedModelSummary,
|
|
2952
3079
|
};
|
package/package.json
CHANGED