n8n-nodes-tembory 1.0.9 → 1.0.11
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 +196 -101
- package/package.json +1 -1
- package/scripts/simulate-agent-context.js +6 -6
package/README.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
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.11`.
|
|
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
|
+
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
|
+
|
|
9
11
|
## Smoke tecnico
|
|
10
12
|
|
|
11
13
|
Antes de publicar uma versao, rode:
|
|
@@ -27,7 +27,7 @@ const snapshotJson = (value) => {
|
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
const truncate = (value, max = MAX_TEXT) => {
|
|
30
|
-
const text = typeof value === 'string' ? value : safeStringify(value);
|
|
30
|
+
const text = value === undefined || value === null ? '' : (typeof value === 'string' ? value : safeStringify(value));
|
|
31
31
|
if (text.length <= max)
|
|
32
32
|
return text;
|
|
33
33
|
return `${text.slice(0, max)}\n... [truncated ${text.length - max} chars]`;
|
|
@@ -53,7 +53,7 @@ const saveClientVectorMemories = async (ctx, memories, ids = {}) => {
|
|
|
53
53
|
const valid = memories.filter((memory) => String(memory === null || memory === void 0 ? void 0 : memory.text || '').trim());
|
|
54
54
|
if (!valid.length)
|
|
55
55
|
return null;
|
|
56
|
-
return GenericFunctions_1.mem0ApiRequest.call(ctx, 'POST', '/
|
|
56
|
+
return GenericFunctions_1.mem0ApiRequest.call(ctx, 'POST', '/tembory/v1/vector-memories', {
|
|
57
57
|
memories: valid,
|
|
58
58
|
user_id: ids.user_id,
|
|
59
59
|
agent_id: ids.agent_id,
|
|
@@ -64,7 +64,7 @@ const searchClientVectorMemories = async (ctx, embedding, query, body = {}) => {
|
|
|
64
64
|
const text = String(query || '').trim();
|
|
65
65
|
if (!text)
|
|
66
66
|
return { results: [] };
|
|
67
|
-
return GenericFunctions_1.mem0ApiRequest.call(ctx, 'POST', '/
|
|
67
|
+
return GenericFunctions_1.mem0ApiRequest.call(ctx, 'POST', '/tembory/v1/vector-memories/search', {
|
|
68
68
|
...body,
|
|
69
69
|
query: text,
|
|
70
70
|
embedding: await embedQueryCached(embedding, text),
|
|
@@ -167,11 +167,11 @@ const scoreOf = (m) => {
|
|
|
167
167
|
var _a, _b, _c, _d;
|
|
168
168
|
return (_d = (_c = (_b = (_a = m === null || m === void 0 ? void 0 : m.score) !== null && _a !== void 0 ? _a : m === null || m === void 0 ? void 0 : m.similarity) !== null && _b !== void 0 ? _b : m === null || m === void 0 ? void 0 : m.relevance) !== null && _c !== void 0 ? _c : m === null || m === void 0 ? void 0 : m.distance) !== null && _d !== void 0 ? _d : undefined;
|
|
169
169
|
};
|
|
170
|
-
const scoreMetaOf = (m) => (m && typeof m === 'object' && (m.
|
|
171
|
-
const
|
|
170
|
+
const scoreMetaOf = (m) => (m && typeof m === 'object' && (m.temboryScore || m._temboryScore)) || {};
|
|
171
|
+
const withTemboryScore = (m, temboryScore) => {
|
|
172
172
|
if (!m || typeof m !== 'object')
|
|
173
173
|
return m;
|
|
174
|
-
return { ...m,
|
|
174
|
+
return { ...m, temboryScore };
|
|
175
175
|
};
|
|
176
176
|
const normalizeFactValue = (value) => String(value || '').replace(/\*\*/g, '').replace(/\s+/g, ' ').replace(/[.,;:]+$/g, '').trim();
|
|
177
177
|
const profileSourceRank = (source = '') => {
|
|
@@ -504,8 +504,8 @@ const deriveEntityTimeline = (profileFacts = {}, graph = [], recentMessages = []
|
|
|
504
504
|
}
|
|
505
505
|
return pruneByLimit(deduped.sort((a, b) => String(a.at || '').localeCompare(String(b.at || ''))), maxItems || 24);
|
|
506
506
|
};
|
|
507
|
-
const RECENT_MESSAGE_MARKER = '
|
|
508
|
-
const TOOL_HISTORY_MARKER = '
|
|
507
|
+
const RECENT_MESSAGE_MARKER = '__tembory_recent_message_v1__';
|
|
508
|
+
const TOOL_HISTORY_MARKER = '__tembory_tool_history_v1__';
|
|
509
509
|
const encodeRecentMessage = (recent, threadId) => `${RECENT_MESSAGE_MARKER}${safeStringify({
|
|
510
510
|
role: recent.role || 'user',
|
|
511
511
|
content: recent.content || '',
|
|
@@ -855,21 +855,21 @@ const extractToolCalls = (outputValues = {}) => {
|
|
|
855
855
|
const getMemoryStore = (ctx) => {
|
|
856
856
|
try {
|
|
857
857
|
const data = ctx.getWorkflowStaticData('global');
|
|
858
|
-
data.
|
|
859
|
-
data.
|
|
860
|
-
data.
|
|
861
|
-
data.
|
|
862
|
-
data.
|
|
863
|
-
data.
|
|
864
|
-
data.
|
|
865
|
-
return data.
|
|
858
|
+
data.tembory = data.tembory || {};
|
|
859
|
+
data.tembory.toolHistory = data.tembory.toolHistory || {};
|
|
860
|
+
data.tembory.recentMessages = data.tembory.recentMessages || {};
|
|
861
|
+
data.tembory.profileFacts = data.tembory.profileFacts || {};
|
|
862
|
+
data.tembory.workingMemory = data.tembory.workingMemory || {};
|
|
863
|
+
data.tembory.decisionState = data.tembory.decisionState || {};
|
|
864
|
+
data.tembory.memoryCompression = data.tembory.memoryCompression || {};
|
|
865
|
+
return data.tembory;
|
|
866
866
|
}
|
|
867
867
|
catch {
|
|
868
|
-
global.
|
|
869
|
-
global.
|
|
870
|
-
global.
|
|
871
|
-
global.
|
|
872
|
-
return global.
|
|
868
|
+
global.__temboryMemory = global.__temboryMemory || { toolHistory: {}, recentMessages: {}, profileFacts: {}, workingMemory: {}, decisionState: {}, memoryCompression: {} };
|
|
869
|
+
global.__temboryMemory.workingMemory = global.__temboryMemory.workingMemory || {};
|
|
870
|
+
global.__temboryMemory.decisionState = global.__temboryMemory.decisionState || {};
|
|
871
|
+
global.__temboryMemory.memoryCompression = global.__temboryMemory.memoryCompression || {};
|
|
872
|
+
return global.__temboryMemory;
|
|
873
873
|
}
|
|
874
874
|
};
|
|
875
875
|
const namespacePart = (value) => String(value || '').trim().replace(/\s+/g, '_').replace(/[:|]+/g, '-');
|
|
@@ -906,6 +906,7 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
906
906
|
recentMessagesLastN: 8,
|
|
907
907
|
},
|
|
908
908
|
productionBalanced: {
|
|
909
|
+
compactStateSections: true,
|
|
909
910
|
includeContextHeader: true,
|
|
910
911
|
includeSummary: true,
|
|
911
912
|
includeScores: false,
|
|
@@ -928,8 +929,11 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
928
929
|
lastN: 8,
|
|
929
930
|
toolHistoryLastN: 10,
|
|
930
931
|
recentMessagesLastN: 6,
|
|
932
|
+
vectorMemoryMaxChars: 360,
|
|
933
|
+
contextMaxChars: 10000,
|
|
931
934
|
},
|
|
932
935
|
productionCheap: {
|
|
936
|
+
compactStateSections: true,
|
|
933
937
|
includeContextHeader: true,
|
|
934
938
|
includeSummary: false,
|
|
935
939
|
includeScores: false,
|
|
@@ -952,6 +956,8 @@ const applyOperationalPreset = (advanced = {}) => {
|
|
|
952
956
|
lastN: 4,
|
|
953
957
|
toolHistoryLastN: 5,
|
|
954
958
|
recentMessagesLastN: 4,
|
|
959
|
+
vectorMemoryMaxChars: 260,
|
|
960
|
+
contextMaxChars: 7000,
|
|
955
961
|
},
|
|
956
962
|
productionNano: {
|
|
957
963
|
compactForAgent: true,
|
|
@@ -1328,7 +1334,7 @@ const deriveContextHealth = ({ userId = '', project = '', vectorMemories = [], r
|
|
|
1328
1334
|
const missing = Object.entries(checks).filter(([, ok]) => !ok).map(([key]) => key);
|
|
1329
1335
|
const agenda = operationalState.agenda_state || {};
|
|
1330
1336
|
return {
|
|
1331
|
-
kind: '
|
|
1337
|
+
kind: 'tembory.context_health.v1',
|
|
1332
1338
|
namespace: userId || null,
|
|
1333
1339
|
project: project || null,
|
|
1334
1340
|
quality_score: Math.max(0, Math.min(1000, score)),
|
|
@@ -1409,12 +1415,63 @@ const compactToolResult = (result, max = 360) => {
|
|
|
1409
1415
|
return truncate(text, max);
|
|
1410
1416
|
};
|
|
1411
1417
|
const compactToolHistoryForAgent = (toolHistory = [], maxItems = 6, includeResults = true) => pruneByLimit(toolHistory || [], maxItems).map((tool) => ({
|
|
1418
|
+
id: tool.call_id || tool.id,
|
|
1412
1419
|
name: tool.name,
|
|
1413
1420
|
status: tool.ok === false ? 'failed' : 'ok',
|
|
1414
1421
|
at: tool.at,
|
|
1415
1422
|
input: truncate(String(tool.input || ''), 180) || undefined,
|
|
1416
1423
|
result: includeResults ? compactToolResult(tool.result, 360) : undefined,
|
|
1417
1424
|
}));
|
|
1425
|
+
const cleanContextValue = (value) => {
|
|
1426
|
+
if (Array.isArray(value)) {
|
|
1427
|
+
return value.map(cleanContextValue).filter((item) => item !== undefined && item !== null && !(Array.isArray(item) && item.length === 0) && !(typeof item === 'object' && !Array.isArray(item) && Object.keys(item).length === 0));
|
|
1428
|
+
}
|
|
1429
|
+
if (!value || typeof value !== 'object')
|
|
1430
|
+
return value === '' ? undefined : value;
|
|
1431
|
+
const out = {};
|
|
1432
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1433
|
+
const cleaned = cleanContextValue(item);
|
|
1434
|
+
if (cleaned === undefined || cleaned === null)
|
|
1435
|
+
continue;
|
|
1436
|
+
if (Array.isArray(cleaned) && cleaned.length === 0)
|
|
1437
|
+
continue;
|
|
1438
|
+
if (typeof cleaned === 'object' && !Array.isArray(cleaned) && Object.keys(cleaned).length === 0)
|
|
1439
|
+
continue;
|
|
1440
|
+
out[key] = cleaned;
|
|
1441
|
+
}
|
|
1442
|
+
return out;
|
|
1443
|
+
};
|
|
1444
|
+
const compactWorkingMemoryForAgent = (memory = {}) => cleanContextValue({
|
|
1445
|
+
current_goal: memory.current_goal,
|
|
1446
|
+
current_task: memory.current_task,
|
|
1447
|
+
last_user_intent: memory.last_user_intent,
|
|
1448
|
+
last_user_message: truncate(memory.last_user_message, 220),
|
|
1449
|
+
active_entities: memory.active_entities,
|
|
1450
|
+
open_decisions: memory.open_decisions,
|
|
1451
|
+
last_error: memory.last_error,
|
|
1452
|
+
next_expected_action: memory.next_expected_action,
|
|
1453
|
+
updated_at: memory.updated_at,
|
|
1454
|
+
});
|
|
1455
|
+
const compactDecisionStateForAgent = (state = {}) => cleanContextValue({
|
|
1456
|
+
current_intent: state.current_intent,
|
|
1457
|
+
active_decisions: (state.active_decisions || []).slice(-4).map((decision) => cleanContextValue({
|
|
1458
|
+
id: decision.id,
|
|
1459
|
+
status: decision.status,
|
|
1460
|
+
decision: truncate(decision.decision || decision.summary || decision.reason, 260),
|
|
1461
|
+
tool: decision.tool || decision.next_tool || decision.required_tool,
|
|
1462
|
+
reservation_id: decision.reservation_id,
|
|
1463
|
+
confirmation_id: decision.confirmation_id,
|
|
1464
|
+
at: decision.at || decision.updated_at,
|
|
1465
|
+
})),
|
|
1466
|
+
do_not_repeat_tools: state.do_not_repeat_tools,
|
|
1467
|
+
agenda_decision_state: state.agenda_decision_state,
|
|
1468
|
+
latest_tool: state.latest_tool ? cleanContextValue({
|
|
1469
|
+
name: state.latest_tool.name,
|
|
1470
|
+
status: state.latest_tool.status || (state.latest_tool.ok === false ? 'failed' : 'ok'),
|
|
1471
|
+
at: state.latest_tool.at,
|
|
1472
|
+
}) : undefined,
|
|
1473
|
+
conflict_policy: state.conflict_policy,
|
|
1474
|
+
});
|
|
1418
1475
|
const compactOperationalStateForAgent = (state = {}) => {
|
|
1419
1476
|
const agenda = state.agenda_state || {};
|
|
1420
1477
|
return {
|
|
@@ -1444,6 +1501,21 @@ const compactMemoryCompressionForAgent = (compression = {}) => ({
|
|
|
1444
1501
|
} : undefined,
|
|
1445
1502
|
active_memory_count: ((compression.workflow_summary || {}).active_memory_count) || 0,
|
|
1446
1503
|
});
|
|
1504
|
+
const compactActionLedgerForAgent = (ledger = [], maxItems = 6, includeResults = true) => pruneByLimit(ledger || [], maxItems).map((item) => cleanContextValue({
|
|
1505
|
+
action_id: item.action_id,
|
|
1506
|
+
kind: item.kind,
|
|
1507
|
+
tool: item.tool || item.name,
|
|
1508
|
+
status: item.status,
|
|
1509
|
+
at: item.at,
|
|
1510
|
+
result: includeResults ? compactToolResult(item.result, 260) : undefined,
|
|
1511
|
+
}));
|
|
1512
|
+
const compactEntityTimelineForAgent = (timeline = [], maxItems = 8) => pruneByLimit(timeline || [], maxItems).map((item) => cleanContextValue({
|
|
1513
|
+
entity: item.entity || item.source || item.name,
|
|
1514
|
+
event: truncate(item.event || item.fact || item.relation || item.kind || item.value, 220),
|
|
1515
|
+
target: item.target,
|
|
1516
|
+
at: item.at,
|
|
1517
|
+
source: item.source_type || item.source,
|
|
1518
|
+
}));
|
|
1447
1519
|
const compactVectorMemoriesForAgent = (vectorMemories = [], toolHistory = [], maxItems = 3) => {
|
|
1448
1520
|
const hasStructuredTools = Array.isArray(toolHistory) && toolHistory.length > 0;
|
|
1449
1521
|
return (vectorMemories || [])
|
|
@@ -1460,7 +1532,7 @@ const contextSizeOfMessages = (messages = []) => {
|
|
|
1460
1532
|
const chars = perMessage.reduce((sum, item) => sum + item.chars, 0);
|
|
1461
1533
|
return { chars, approx_tokens: approxTokenCount((messages || []).map((m) => m.content || '').join('\n')), messages: perMessage };
|
|
1462
1534
|
};
|
|
1463
|
-
const
|
|
1535
|
+
const wrapTemboryMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
|
|
1464
1536
|
get(target, prop) {
|
|
1465
1537
|
if (prop === 'loadMemoryVariables') {
|
|
1466
1538
|
return async (values = {}) => {
|
|
@@ -1469,7 +1541,7 @@ const wrapElefaiMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
|
|
|
1469
1541
|
]);
|
|
1470
1542
|
try {
|
|
1471
1543
|
const response = await target.loadMemoryVariables(values);
|
|
1472
|
-
const cacheHit = Boolean(response.
|
|
1544
|
+
const cacheHit = Boolean(response.temboryDiagnostics && response.temboryDiagnostics.cacheHit);
|
|
1473
1545
|
const chatHistory = cacheHit
|
|
1474
1546
|
? [{ cached: true, messages: Array.isArray(response[memoryKey] || response.chatHistory) ? (response[memoryKey] || response.chatHistory).length : 0 }]
|
|
1475
1547
|
: snapshotJson(response[memoryKey] || response.chatHistory || []);
|
|
@@ -1479,23 +1551,23 @@ const wrapElefaiMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
|
|
|
1479
1551
|
action: 'loadMemoryVariables',
|
|
1480
1552
|
cached: cacheHit || undefined,
|
|
1481
1553
|
chatHistory,
|
|
1482
|
-
context: response.
|
|
1483
|
-
contextText: response.
|
|
1484
|
-
summary: response.
|
|
1485
|
-
connectedModelSummary: response.
|
|
1486
|
-
workingMemory: response.
|
|
1487
|
-
decisionState: response.
|
|
1488
|
-
memoryCompression: response.
|
|
1489
|
-
profileFacts: response.
|
|
1490
|
-
operationalState: response.
|
|
1491
|
-
actionLedger: response.
|
|
1492
|
-
entityTimeline: response.
|
|
1493
|
-
vectorMemories: response.
|
|
1494
|
-
graph: response.
|
|
1495
|
-
recentMessages: response.
|
|
1496
|
-
recentHighlights: response.
|
|
1497
|
-
toolHistory: response.
|
|
1498
|
-
diagnostics: response.
|
|
1554
|
+
context: response.temboryContext,
|
|
1555
|
+
contextText: response.temboryContextText,
|
|
1556
|
+
summary: response.temborySummary,
|
|
1557
|
+
connectedModelSummary: response.temboryConnectedModelSummary,
|
|
1558
|
+
workingMemory: response.temboryWorkingMemory,
|
|
1559
|
+
decisionState: response.temboryDecisionState,
|
|
1560
|
+
memoryCompression: response.temboryMemoryCompression,
|
|
1561
|
+
profileFacts: response.temboryProfileFacts,
|
|
1562
|
+
operationalState: response.temboryOperationalState,
|
|
1563
|
+
actionLedger: response.temboryActionLedger,
|
|
1564
|
+
entityTimeline: response.temboryEntityTimeline,
|
|
1565
|
+
vectorMemories: response.temboryVectorMemories,
|
|
1566
|
+
graph: response.temboryGraph,
|
|
1567
|
+
recentMessages: response.temboryRecentMessages,
|
|
1568
|
+
recentHighlights: response.temboryRecentHighlights,
|
|
1569
|
+
toolHistory: response.temboryToolHistory,
|
|
1570
|
+
diagnostics: response.temboryDiagnostics,
|
|
1499
1571
|
},
|
|
1500
1572
|
}],
|
|
1501
1573
|
]);
|
|
@@ -1534,12 +1606,13 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1534
1606
|
const includeSummary = adv.includeSummary !== false;
|
|
1535
1607
|
const includeScores = adv.includeScores !== false;
|
|
1536
1608
|
const compactForAgent = Boolean(adv.compactForAgent);
|
|
1609
|
+
const compactStateSections = Boolean(adv.compactStateSections);
|
|
1537
1610
|
const sections = [];
|
|
1538
1611
|
if (includeHeader) {
|
|
1539
1612
|
sections.push({
|
|
1540
1613
|
section: 'context_header',
|
|
1541
1614
|
title: 'Tembory context',
|
|
1542
|
-
value: compactForAgent
|
|
1615
|
+
value: compactForAgent || compactStateSections
|
|
1543
1616
|
? '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.'
|
|
1544
1617
|
: '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.',
|
|
1545
1618
|
});
|
|
@@ -1588,7 +1661,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1588
1661
|
why_null: adv.includeMemoryCompression === false ? 'memory compression disabled' : undefined,
|
|
1589
1662
|
});
|
|
1590
1663
|
const audit = {
|
|
1591
|
-
kind: '
|
|
1664
|
+
kind: 'tembory.context.v1',
|
|
1592
1665
|
meta: { user_id: userId, payloadFormat, query, compact_for_agent: true },
|
|
1593
1666
|
sections,
|
|
1594
1667
|
diagnostics,
|
|
@@ -1609,13 +1682,15 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1609
1682
|
return [{ role: 'system', content: truncate(sections.map(renderCompactSection).join('\n\n'), Number(adv.contextMaxChars || 6000)) }];
|
|
1610
1683
|
}
|
|
1611
1684
|
if (includeSummary) {
|
|
1612
|
-
const summary =
|
|
1685
|
+
const summary = compactStateSections
|
|
1686
|
+
? compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.summaryMaxFacts || 4))
|
|
1687
|
+
: vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
|
|
1613
1688
|
sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no vector memories to summarize' });
|
|
1614
1689
|
}
|
|
1615
1690
|
sections.push({
|
|
1616
1691
|
section: 'working_memory',
|
|
1617
1692
|
title: 'Working memory',
|
|
1618
|
-
value: adv.includeWorkingMemory === false ? null : (workingMemory || {}),
|
|
1693
|
+
value: adv.includeWorkingMemory === false ? null : (compactStateSections ? compactWorkingMemoryForAgent(workingMemory || {}) : (workingMemory || {})),
|
|
1619
1694
|
why_null: adv.includeWorkingMemory === false ? 'working memory disabled' : undefined,
|
|
1620
1695
|
});
|
|
1621
1696
|
sections.push({
|
|
@@ -1639,31 +1714,31 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1639
1714
|
sections.push({
|
|
1640
1715
|
section: 'decision_state',
|
|
1641
1716
|
title: 'Decision state',
|
|
1642
|
-
value: adv.includeDecisionState === false ? null : (decisionState || {}),
|
|
1717
|
+
value: adv.includeDecisionState === false ? null : (compactStateSections ? compactDecisionStateForAgent(decisionState || {}) : (decisionState || {})),
|
|
1643
1718
|
why_null: adv.includeDecisionState === false ? 'decision state disabled' : undefined,
|
|
1644
1719
|
});
|
|
1645
1720
|
sections.push({
|
|
1646
1721
|
section: 'operational_state',
|
|
1647
1722
|
title: 'Operational state',
|
|
1648
|
-
value: adv.includeOperationalState === false ? null : operationalState,
|
|
1723
|
+
value: adv.includeOperationalState === false ? null : (compactStateSections ? compactOperationalStateForAgent(operationalState || {}) : operationalState),
|
|
1649
1724
|
why_null: adv.includeOperationalState === false ? 'operational state disabled' : undefined,
|
|
1650
1725
|
});
|
|
1651
1726
|
sections.push({
|
|
1652
1727
|
section: 'action_ledger',
|
|
1653
1728
|
title: 'Action ledger',
|
|
1654
|
-
value: adv.includeActionLedger === false ? null : (actionLedger || []),
|
|
1729
|
+
value: adv.includeActionLedger === false ? null : (compactStateSections ? compactActionLedgerForAgent(actionLedger || [], adv.actionLedgerMaxItems || 6, adv.includeToolResults !== false) : (actionLedger || [])),
|
|
1655
1730
|
why_null: adv.includeActionLedger === false ? 'action ledger disabled' : undefined,
|
|
1656
1731
|
});
|
|
1657
1732
|
sections.push({
|
|
1658
1733
|
section: 'entity_timeline',
|
|
1659
1734
|
title: 'Entity timeline',
|
|
1660
|
-
value: adv.includeEntityTimeline === false ? null : (entityTimeline || []),
|
|
1735
|
+
value: adv.includeEntityTimeline === false ? null : (compactStateSections ? compactEntityTimelineForAgent(entityTimeline || [], adv.entityTimelineMaxItems || 8) : (entityTimeline || [])),
|
|
1661
1736
|
why_null: adv.includeEntityTimeline === false ? 'entity timeline disabled' : undefined,
|
|
1662
1737
|
});
|
|
1663
1738
|
sections.push({
|
|
1664
1739
|
section: 'vector',
|
|
1665
1740
|
title: 'Vector memories',
|
|
1666
|
-
value: vectorMemories.map((m) => {
|
|
1741
|
+
value: compactStateSections ? compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.maxReturn || adv.topK || 4)) : vectorMemories.map((m) => {
|
|
1667
1742
|
const scoreMeta = scoreMetaOf(m);
|
|
1668
1743
|
const rawScore = scoreOf(m);
|
|
1669
1744
|
return {
|
|
@@ -1681,7 +1756,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1681
1756
|
sections.push({
|
|
1682
1757
|
section: 'memory_compression',
|
|
1683
1758
|
title: 'Memory compression',
|
|
1684
|
-
value: adv.includeMemoryCompression === false ? null : (memoryCompression || {}),
|
|
1759
|
+
value: adv.includeMemoryCompression === false ? null : (compactStateSections ? compactMemoryCompressionForAgent(memoryCompression || {}) : (memoryCompression || {})),
|
|
1685
1760
|
why_null: adv.includeMemoryCompression === false ? 'memory compression disabled' : undefined,
|
|
1686
1761
|
});
|
|
1687
1762
|
sections.push({
|
|
@@ -1693,7 +1768,11 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1693
1768
|
sections.push({
|
|
1694
1769
|
section: 'recent_messages',
|
|
1695
1770
|
title: 'Recent messages',
|
|
1696
|
-
value: recentMessages || [],
|
|
1771
|
+
value: compactStateSections ? pruneByLimit(recentMessages || [], adv.recentMessagesLastN || 4).map((message) => cleanContextValue({
|
|
1772
|
+
role: message.role,
|
|
1773
|
+
content: truncate(message.content, 260),
|
|
1774
|
+
at: message.at,
|
|
1775
|
+
})) : recentMessages || [],
|
|
1697
1776
|
});
|
|
1698
1777
|
sections.push({
|
|
1699
1778
|
section: 'recent_highlights',
|
|
@@ -1704,18 +1783,18 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1704
1783
|
section: 'tool_history',
|
|
1705
1784
|
title: 'Tool history',
|
|
1706
1785
|
value: {
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1786
|
+
enabled: adv.includeToolHistory !== false,
|
|
1787
|
+
items: adv.includeToolHistory === false ? [] : (compactStateSections ? compactToolHistoryForAgent(toolHistory, adv.toolHistoryLastN || 8, adv.includeToolResults !== false) : toolHistory.map((tool) => ({
|
|
1788
|
+
id: tool.id,
|
|
1789
|
+
turnId: tool.turnId,
|
|
1790
|
+
sequence: tool.sequence,
|
|
1712
1791
|
name: tool.name,
|
|
1713
1792
|
input: tool.input,
|
|
1714
1793
|
ok: tool.ok,
|
|
1715
1794
|
at: tool.at,
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
})),
|
|
1795
|
+
source: tool.source,
|
|
1796
|
+
result: adv.includeToolResults === false ? undefined : tool.result,
|
|
1797
|
+
}))),
|
|
1719
1798
|
},
|
|
1720
1799
|
});
|
|
1721
1800
|
if (adv.includeDiagnostics) {
|
|
@@ -1726,7 +1805,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1726
1805
|
});
|
|
1727
1806
|
}
|
|
1728
1807
|
const audit = {
|
|
1729
|
-
kind: '
|
|
1808
|
+
kind: 'tembory.context.v1',
|
|
1730
1809
|
meta: { user_id: userId, payloadFormat, query },
|
|
1731
1810
|
sections,
|
|
1732
1811
|
diagnostics,
|
|
@@ -1740,17 +1819,32 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1740
1819
|
return `## ${section.title}\n${section.value.length ? section.value.map((item) => typeof item === 'string' ? `- ${item}` : `- ${truncate(safeStringify(item), 900)}`).join('\n') : '(empty)'}`;
|
|
1741
1820
|
return `## ${section.title}\n${truncate(safeStringify(section.value), 1600)}`;
|
|
1742
1821
|
};
|
|
1822
|
+
const sectionIsEmpty = (section) => {
|
|
1823
|
+
if (!compactStateSections)
|
|
1824
|
+
return false;
|
|
1825
|
+
if (section.section === 'context_header' || section.section === 'tool_guard' || section.section === 'working_memory' || section.section === 'decision_state' || section.section === 'operational_state' || section.section === 'tool_history')
|
|
1826
|
+
return false;
|
|
1827
|
+
if (section.value === null || section.value === undefined)
|
|
1828
|
+
return true;
|
|
1829
|
+
if (Array.isArray(section.value) && section.value.length === 0)
|
|
1830
|
+
return true;
|
|
1831
|
+
if (typeof section.value === 'object' && !Array.isArray(section.value) && Object.keys(section.value).length === 0)
|
|
1832
|
+
return true;
|
|
1833
|
+
return false;
|
|
1834
|
+
};
|
|
1835
|
+
const renderableSections = compactStateSections ? sections.filter((section) => !sectionIsEmpty(section)) : sections;
|
|
1743
1836
|
if (payloadFormat === 'auditJson') {
|
|
1744
1837
|
return [{ role: 'system', content: JSON.stringify(audit, null, 2) }];
|
|
1745
1838
|
}
|
|
1746
1839
|
if (payloadFormat === 'auditBlocks') {
|
|
1747
|
-
return
|
|
1840
|
+
return renderableSections.map((section) => ({ role: 'system', content: renderSection(section) }));
|
|
1748
1841
|
}
|
|
1749
|
-
const text =
|
|
1842
|
+
const text = renderableSections.map(renderSection).join('\n\n');
|
|
1843
|
+
const maxChars = Number(adv.contextMaxChars || 16000);
|
|
1750
1844
|
if (payloadFormat === 'auditText' || payloadFormat === 'singleSystemMessage' || payloadFormat === 'structured') {
|
|
1751
|
-
return [{ role: 'system', content: truncate(text,
|
|
1845
|
+
return [{ role: 'system', content: truncate(text, maxChars) }];
|
|
1752
1846
|
}
|
|
1753
|
-
return [{ role: 'system', content: truncate(text,
|
|
1847
|
+
return [{ role: 'system', content: truncate(text, maxChars) }];
|
|
1754
1848
|
};
|
|
1755
1849
|
class Mem0Memory {
|
|
1756
1850
|
constructor() {
|
|
@@ -1898,7 +1992,8 @@ class Mem0Memory {
|
|
|
1898
1992
|
{ 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'] } } },
|
|
1899
1993
|
{ displayName: 'Incluir Cabeçalho de Contexto', name: 'includeContextHeader', type: 'boolean', default: true },
|
|
1900
1994
|
{ 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.' },
|
|
1901
|
-
{ displayName: '
|
|
1995
|
+
{ 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
|
+
{ 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.' },
|
|
1902
1997
|
{ displayName: 'Incluir Resumo', name: 'includeSummary', type: 'boolean', default: true },
|
|
1903
1998
|
{ displayName: 'Máximo de Fatos no Resumo', name: 'summaryMaxFacts', type: 'number', default: 4 },
|
|
1904
1999
|
{ displayName: 'Incluir Scores', name: 'includeScores', type: 'boolean', default: true },
|
|
@@ -1968,24 +2063,24 @@ class Mem0Memory {
|
|
|
1968
2063
|
if (loadCache.has(cacheKey)) {
|
|
1969
2064
|
result = snapshotJson(loadCache.get(cacheKey));
|
|
1970
2065
|
result.response = result.response || {};
|
|
1971
|
-
result.response.
|
|
1972
|
-
...(result.response.
|
|
2066
|
+
result.response.temboryDiagnostics = {
|
|
2067
|
+
...(result.response.temboryDiagnostics || {}),
|
|
1973
2068
|
cacheHit: true,
|
|
1974
2069
|
cacheScope: 'supplyData.loadMemoryVariables',
|
|
1975
2070
|
};
|
|
1976
|
-
if (result.response.
|
|
1977
|
-
result.response.
|
|
1978
|
-
kind: result.response.
|
|
1979
|
-
userId: result.response.
|
|
1980
|
-
project: result.response.
|
|
1981
|
-
query: result.response.
|
|
1982
|
-
retrievalMode: result.response.
|
|
1983
|
-
payloadFormat: result.response.
|
|
1984
|
-
contextQualityScore: result.response.
|
|
2071
|
+
if (result.response.temboryContext) {
|
|
2072
|
+
result.response.temboryContext = {
|
|
2073
|
+
kind: result.response.temboryContext.kind,
|
|
2074
|
+
userId: result.response.temboryContext.userId,
|
|
2075
|
+
project: result.response.temboryContext.project,
|
|
2076
|
+
query: result.response.temboryContext.query,
|
|
2077
|
+
retrievalMode: result.response.temboryContext.retrievalMode,
|
|
2078
|
+
payloadFormat: result.response.temboryContext.payloadFormat,
|
|
2079
|
+
contextQualityScore: result.response.temboryContext.contextQualityScore,
|
|
1985
2080
|
cacheHit: true,
|
|
1986
2081
|
};
|
|
1987
2082
|
}
|
|
1988
|
-
delete result.response.
|
|
2083
|
+
delete result.response.temboryContextText;
|
|
1989
2084
|
}
|
|
1990
2085
|
else {
|
|
1991
2086
|
result = await Mem0Memory.prototype.loadMemoryVariablesForItem.call(this, itemIndex, inputValues);
|
|
@@ -2016,7 +2111,7 @@ class Mem0Memory {
|
|
|
2016
2111
|
await Mem0Memory.prototype.saveContextForItem.call(this, itemIndex, inputValues, outputValues);
|
|
2017
2112
|
},
|
|
2018
2113
|
};
|
|
2019
|
-
return { response:
|
|
2114
|
+
return { response: wrapTemboryMemory(memory, this, memoryKey) };
|
|
2020
2115
|
}
|
|
2021
2116
|
async saveMessagesForItem(itemIndex, messages = []) {
|
|
2022
2117
|
const inputValues = {};
|
|
@@ -2427,7 +2522,7 @@ class Mem0Memory {
|
|
|
2427
2522
|
}
|
|
2428
2523
|
ranked = selected;
|
|
2429
2524
|
}
|
|
2430
|
-
const finalMemories = ranked.slice(0, maxReturn).map((r) =>
|
|
2525
|
+
const finalMemories = ranked.slice(0, maxReturn).map((r) => withTemboryScore(r.m, {
|
|
2431
2526
|
semanticScore: r.semanticScore,
|
|
2432
2527
|
recencyScore: r.recencyScore,
|
|
2433
2528
|
hybridScore: r.hybrid,
|
|
@@ -2437,7 +2532,7 @@ class Mem0Memory {
|
|
|
2437
2532
|
payload = finalMemories.map((m) => { var _a, _b; return ({ role: 'system', content: (_b = (_a = m.memory) !== null && _a !== void 0 ? _a : m.text) !== null && _b !== void 0 ? _b : JSON.stringify(m) }); });
|
|
2438
2533
|
}
|
|
2439
2534
|
else {
|
|
2440
|
-
vectorMemories = semMemories.map((m) =>
|
|
2535
|
+
vectorMemories = semMemories.map((m) => withTemboryScore(m, {
|
|
2441
2536
|
semanticScore: scoreOf(m),
|
|
2442
2537
|
source: 'semantic',
|
|
2443
2538
|
}));
|
|
@@ -2645,7 +2740,7 @@ class Mem0Memory {
|
|
|
2645
2740
|
const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
|
|
2646
2741
|
const contextText = payload.map((message) => String(message.content || '')).join('\n\n');
|
|
2647
2742
|
const audit = {
|
|
2648
|
-
kind: '
|
|
2743
|
+
kind: 'tembory.context.v1',
|
|
2649
2744
|
userId: key,
|
|
2650
2745
|
project: project || undefined,
|
|
2651
2746
|
query,
|
|
@@ -2716,25 +2811,25 @@ class Mem0Memory {
|
|
|
2716
2811
|
return {
|
|
2717
2812
|
response: {
|
|
2718
2813
|
[memoryKey]: payload,
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2814
|
+
temboryContext: audit,
|
|
2815
|
+
temboryContextText: contextText,
|
|
2816
|
+
temborySummary: summary,
|
|
2817
|
+
temboryConnectedModelSummary: connectedModelSummary,
|
|
2818
|
+
temboryContextHealth: contextHealth,
|
|
2819
|
+
temboryContextQualityScore: contextHealth.quality_score,
|
|
2820
|
+
temboryWorkingMemory: workingMemory,
|
|
2821
|
+
temboryDecisionState: decisionState,
|
|
2822
|
+
temboryMemoryCompression: memoryCompression,
|
|
2823
|
+
temboryProfileFacts: renderProfileFacts(profileFacts),
|
|
2824
|
+
temboryOperationalState: operationalState,
|
|
2825
|
+
temboryActionLedger: actionLedger,
|
|
2826
|
+
temboryEntityTimeline: entityTimeline,
|
|
2827
|
+
temboryVectorMemories: normalizedVectorMemories,
|
|
2828
|
+
temboryGraph: graph,
|
|
2829
|
+
temboryRecentMessages: recentMessages,
|
|
2830
|
+
temboryRecentHighlights: highlights,
|
|
2831
|
+
temboryToolHistory: audit.toolHistory,
|
|
2832
|
+
temboryDiagnostics: diagnostics,
|
|
2738
2833
|
},
|
|
2739
2834
|
};
|
|
2740
2835
|
}
|
package/package.json
CHANGED
|
@@ -42,20 +42,20 @@ const toolHistory = [
|
|
|
42
42
|
ok: true,
|
|
43
43
|
at: '2026-05-14T05:34:34.017Z',
|
|
44
44
|
source: 'used_tools_text',
|
|
45
|
-
result: '[{"args":{"tool":"agenda_pre_reservar_horario","reservation_id":"RES-
|
|
45
|
+
result: '[{"args":{"tool":"agenda_pre_reservar_horario","reservation_id":"RES-TEMBORY-LAB-001","selected_from_message":"dia 13","status":"pre_reserved","next_step":"confirmar_agendamento"}}]',
|
|
46
46
|
},
|
|
47
47
|
];
|
|
48
48
|
|
|
49
49
|
const vectorMemories = [
|
|
50
50
|
{
|
|
51
|
-
memory: '[Used tools: Tool: agenda_pre_reservar_horario, Input: , Result: [{"args":{"tool":"agenda_pre_reservar_horario","reservation_id":"RES-
|
|
51
|
+
memory: '[Used tools: Tool: agenda_pre_reservar_horario, Input: , Result: [{"args":{"tool":"agenda_pre_reservar_horario","reservation_id":"RES-TEMBORY-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
52
|
created_at: '2026-05-14T05:34:35.373020Z',
|
|
53
|
-
|
|
53
|
+
temboryScore: { semanticScore: 0.71, recencyScore: 0.99, hybridScore: 0.81, source: 'semantic' },
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
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
57
|
created_at: '2026-05-14T05:34:14.717988Z',
|
|
58
|
-
|
|
58
|
+
temboryScore: { semanticScore: 0.7, recencyScore: 0.99, hybridScore: 0.8, source: 'semantic' },
|
|
59
59
|
},
|
|
60
60
|
{ memory: 'Oi! Como posso ajudar?', created_at: '2026-05-14T05:33:47.194630Z' },
|
|
61
61
|
{ memory: 'oi', created_at: '2026-05-14T05:33:47.194355Z' },
|
|
@@ -87,7 +87,7 @@ const common = {
|
|
|
87
87
|
toolHistory,
|
|
88
88
|
highlights: [
|
|
89
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-
|
|
90
|
+
'tool agenda_pre_reservar_horario: [{"args":{"reservation_id":"RES-TEMBORY-LAB-001","status":"pre_reserved"}}]',
|
|
91
91
|
],
|
|
92
92
|
graph: [],
|
|
93
93
|
diagnostics: {},
|
|
@@ -106,7 +106,7 @@ for (const [name, adv] of modes) {
|
|
|
106
106
|
size: core.contextSizeOfMessages(messages),
|
|
107
107
|
has_next_expected_action: /next_expected_action/.test(text),
|
|
108
108
|
has_do_not_repeat_tools: /do_not_repeat_tools/.test(text),
|
|
109
|
-
has_reservation_id: /RES-
|
|
109
|
+
has_reservation_id: /RES-TEMBORY-LAB-001/.test(text),
|
|
110
110
|
has_available_slots: /available_slots/.test(text),
|
|
111
111
|
has_duplicate_calling_text: /Calling agenda_pre_reservar_horario/.test(text),
|
|
112
112
|
}, null, 2));
|