n8n-nodes-tembory 1.0.12 → 1.0.13
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 +28 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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.13`.
|
|
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
|
|
|
@@ -10,6 +10,8 @@ Nos presets de producao, o contexto e organizado como um pacote acionavel: secoe
|
|
|
10
10
|
|
|
11
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
12
|
|
|
13
|
+
O resumo do SLM usa limites conservadores e cache curto por input para evitar chamadas duplicadas quando o AI Agent carrega a memoria mais de uma vez no mesmo turno.
|
|
14
|
+
|
|
13
15
|
## Smoke tecnico
|
|
14
16
|
|
|
15
17
|
Antes de publicar uma versao, rode:
|
|
@@ -862,13 +862,15 @@ const getMemoryStore = (ctx) => {
|
|
|
862
862
|
data.tembory.workingMemory = data.tembory.workingMemory || {};
|
|
863
863
|
data.tembory.decisionState = data.tembory.decisionState || {};
|
|
864
864
|
data.tembory.memoryCompression = data.tembory.memoryCompression || {};
|
|
865
|
+
data.tembory.connectedModelSummaryCache = data.tembory.connectedModelSummaryCache || {};
|
|
865
866
|
return data.tembory;
|
|
866
867
|
}
|
|
867
868
|
catch {
|
|
868
|
-
global.__temboryMemory = global.__temboryMemory || { toolHistory: {}, recentMessages: {}, profileFacts: {}, workingMemory: {}, decisionState: {}, memoryCompression: {} };
|
|
869
|
+
global.__temboryMemory = global.__temboryMemory || { toolHistory: {}, recentMessages: {}, profileFacts: {}, workingMemory: {}, decisionState: {}, memoryCompression: {}, connectedModelSummaryCache: {} };
|
|
869
870
|
global.__temboryMemory.workingMemory = global.__temboryMemory.workingMemory || {};
|
|
870
871
|
global.__temboryMemory.decisionState = global.__temboryMemory.decisionState || {};
|
|
871
872
|
global.__temboryMemory.memoryCompression = global.__temboryMemory.memoryCompression || {};
|
|
873
|
+
global.__temboryMemory.connectedModelSummaryCache = global.__temboryMemory.connectedModelSummaryCache || {};
|
|
872
874
|
return global.__temboryMemory;
|
|
873
875
|
}
|
|
874
876
|
};
|
|
@@ -998,8 +1000,8 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
998
1000
|
recentMessagesLastN: 2,
|
|
999
1001
|
vectorMemoryMaxChars: 220,
|
|
1000
1002
|
contextMaxChars: 6000,
|
|
1001
|
-
connectedModelSummaryMaxChars:
|
|
1002
|
-
connectedModelSummaryInputMaxChars:
|
|
1003
|
+
connectedModelSummaryMaxChars: 450,
|
|
1004
|
+
connectedModelSummaryInputMaxChars: 1500,
|
|
1003
1005
|
},
|
|
1004
1006
|
audit: {
|
|
1005
1007
|
summarySource: 'auto',
|
|
@@ -1608,7 +1610,7 @@ const buildConnectedModelSummaryInput = ({ query, profileFacts, workingMemory, d
|
|
|
1608
1610
|
const hasVectorSignal = includeVectors && Array.isArray(payload.vector_memories) && payload.vector_memories.length > 0;
|
|
1609
1611
|
if (!hasActiveSignal && !hasVectorSignal)
|
|
1610
1612
|
return '';
|
|
1611
|
-
return truncate(safeStringify(payload), Number(adv.connectedModelSummaryInputMaxChars ||
|
|
1613
|
+
return truncate(safeStringify(payload), Number(adv.connectedModelSummaryInputMaxChars || 2000));
|
|
1612
1614
|
};
|
|
1613
1615
|
const invokeConnectedModelSummary = async (connectedLanguageModel, summaryInput, adv = {}) => {
|
|
1614
1616
|
if (!connectedLanguageModel || typeof connectedLanguageModel.invoke !== 'function' || !summaryInput)
|
|
@@ -1616,10 +1618,10 @@ const invokeConnectedModelSummary = async (connectedLanguageModel, summaryInput,
|
|
|
1616
1618
|
const response = await connectedLanguageModel.invoke([
|
|
1617
1619
|
toBaseMessage({
|
|
1618
1620
|
role: 'user',
|
|
1619
|
-
|
|
1621
|
+
content: `Organize the Tembory memory context for the next agent turn. Return only 3 to 6 short Portuguese bullets. No JSON, no markdown table, no field-by-field dump. Preserve important IDs, dates, tool names, next action, do-not-repeat instructions, and contradictions. Do not invent facts.\n\nContext:\n${summaryInput}`,
|
|
1620
1622
|
}),
|
|
1621
1623
|
]);
|
|
1622
|
-
return cleanModelSummaryText(response, Number(adv.connectedModelSummaryMaxChars ||
|
|
1624
|
+
return cleanModelSummaryText(response, Number(adv.connectedModelSummaryMaxChars || 700));
|
|
1623
1625
|
};
|
|
1624
1626
|
const contextSizeOfMessages = (messages = []) => {
|
|
1625
1627
|
const perMessage = (messages || []).map((message, index) => {
|
|
@@ -2784,7 +2786,26 @@ class Mem0Memory {
|
|
|
2784
2786
|
highlights,
|
|
2785
2787
|
adv,
|
|
2786
2788
|
});
|
|
2787
|
-
|
|
2789
|
+
const cacheKey = summaryInput ? stableHash({
|
|
2790
|
+
key,
|
|
2791
|
+
source: adv.summarySource || 'auto',
|
|
2792
|
+
input: summaryInput,
|
|
2793
|
+
max: adv.connectedModelSummaryMaxChars || 700,
|
|
2794
|
+
}) : '';
|
|
2795
|
+
const cached = cacheKey ? store.connectedModelSummaryCache[cacheKey] : null;
|
|
2796
|
+
if (cached && cached.summary && Date.now() - Number(cached.at || 0) < Number(adv.connectedModelSummaryCacheTTLSeconds || 60) * 1000) {
|
|
2797
|
+
connectedModelSummary = cached.summary;
|
|
2798
|
+
connectedAi.languageModelSummaryCached = true;
|
|
2799
|
+
}
|
|
2800
|
+
else {
|
|
2801
|
+
connectedModelSummary = await invokeConnectedModelSummary(connectedLanguageModel, summaryInput, adv);
|
|
2802
|
+
if (cacheKey && connectedModelSummary) {
|
|
2803
|
+
store.connectedModelSummaryCache[cacheKey] = { summary: connectedModelSummary, at: Date.now() };
|
|
2804
|
+
const keys = Object.keys(store.connectedModelSummaryCache);
|
|
2805
|
+
for (const oldKey of keys.slice(0, Math.max(0, keys.length - Number(adv.connectedModelSummaryCacheMaxItems || 50))))
|
|
2806
|
+
delete store.connectedModelSummaryCache[oldKey];
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2788
2809
|
connectedAi.languageModelSummary = Boolean(connectedModelSummary);
|
|
2789
2810
|
}
|
|
2790
2811
|
catch (error) {
|
package/package.json
CHANGED