n8n-nodes-tembory 1.0.9 → 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 CHANGED
@@ -2,10 +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.1`.
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
+ 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
+
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
+
9
13
  ## Smoke tecnico
10
14
 
11
15
  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', '/elefai/v1/vector-memories', {
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', '/elefai/v1/vector-memories/search', {
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.elefaiScore || m._elefaiScore)) || {};
171
- const withElefaiScore = (m, elefaiScore) => {
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, elefaiScore };
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 = '__elefai_recent_message_v1__';
508
- const TOOL_HISTORY_MARKER = '__elefai_tool_history_v1__';
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.elefaiBrain = data.elefaiBrain || {};
859
- data.elefaiBrain.toolHistory = data.elefaiBrain.toolHistory || {};
860
- data.elefaiBrain.recentMessages = data.elefaiBrain.recentMessages || {};
861
- data.elefaiBrain.profileFacts = data.elefaiBrain.profileFacts || {};
862
- data.elefaiBrain.workingMemory = data.elefaiBrain.workingMemory || {};
863
- data.elefaiBrain.decisionState = data.elefaiBrain.decisionState || {};
864
- data.elefaiBrain.memoryCompression = data.elefaiBrain.memoryCompression || {};
865
- return data.elefaiBrain;
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.__elefaiBrainMemory = global.__elefaiBrainMemory || { toolHistory: {}, recentMessages: {}, profileFacts: {}, workingMemory: {}, decisionState: {}, memoryCompression: {} };
869
- global.__elefaiBrainMemory.workingMemory = global.__elefaiBrainMemory.workingMemory || {};
870
- global.__elefaiBrainMemory.decisionState = global.__elefaiBrainMemory.decisionState || {};
871
- global.__elefaiBrainMemory.memoryCompression = global.__elefaiBrainMemory.memoryCompression || {};
872
- return global.__elefaiBrainMemory;
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, '-');
@@ -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,9 @@ const applyOperationalPreset = (advanced = {}) => {
906
908
  recentMessagesLastN: 8,
907
909
  },
908
910
  productionBalanced: {
911
+ summarySource: 'auto',
912
+ includeConnectedModelSummary: true,
913
+ compactStateSections: true,
909
914
  includeContextHeader: true,
910
915
  includeSummary: true,
911
916
  includeScores: false,
@@ -928,8 +933,15 @@ const applyOperationalPreset = (advanced = {}) => {
928
933
  lastN: 8,
929
934
  toolHistoryLastN: 10,
930
935
  recentMessagesLastN: 6,
936
+ vectorMemoryMaxChars: 360,
937
+ contextMaxChars: 10000,
938
+ connectedModelSummaryMaxChars: 900,
939
+ connectedModelSummaryInputMaxChars: 3200,
931
940
  },
932
941
  productionCheap: {
942
+ summarySource: 'activeContext',
943
+ includeConnectedModelSummary: true,
944
+ compactStateSections: true,
933
945
  includeContextHeader: true,
934
946
  includeSummary: false,
935
947
  includeScores: false,
@@ -952,8 +964,14 @@ const applyOperationalPreset = (advanced = {}) => {
952
964
  lastN: 4,
953
965
  toolHistoryLastN: 5,
954
966
  recentMessagesLastN: 4,
967
+ vectorMemoryMaxChars: 260,
968
+ contextMaxChars: 7000,
969
+ connectedModelSummaryMaxChars: 700,
970
+ connectedModelSummaryInputMaxChars: 2400,
955
971
  },
956
972
  productionNano: {
973
+ summarySource: 'auto',
974
+ includeConnectedModelSummary: true,
957
975
  compactForAgent: true,
958
976
  includeContextHeader: true,
959
977
  includeSummary: true,
@@ -980,8 +998,12 @@ const applyOperationalPreset = (advanced = {}) => {
980
998
  recentMessagesLastN: 2,
981
999
  vectorMemoryMaxChars: 220,
982
1000
  contextMaxChars: 6000,
1001
+ connectedModelSummaryMaxChars: 700,
1002
+ connectedModelSummaryInputMaxChars: 2200,
983
1003
  },
984
1004
  audit: {
1005
+ summarySource: 'auto',
1006
+ includeConnectedModelSummary: true,
985
1007
  includeContextHeader: true,
986
1008
  includeSummary: true,
987
1009
  includeScores: true,
@@ -1328,7 +1350,7 @@ const deriveContextHealth = ({ userId = '', project = '', vectorMemories = [], r
1328
1350
  const missing = Object.entries(checks).filter(([, ok]) => !ok).map(([key]) => key);
1329
1351
  const agenda = operationalState.agenda_state || {};
1330
1352
  return {
1331
- kind: 'elefai.brain.context_health.v1',
1353
+ kind: 'tembory.context_health.v1',
1332
1354
  namespace: userId || null,
1333
1355
  project: project || null,
1334
1356
  quality_score: Math.max(0, Math.min(1000, score)),
@@ -1409,12 +1431,63 @@ const compactToolResult = (result, max = 360) => {
1409
1431
  return truncate(text, max);
1410
1432
  };
1411
1433
  const compactToolHistoryForAgent = (toolHistory = [], maxItems = 6, includeResults = true) => pruneByLimit(toolHistory || [], maxItems).map((tool) => ({
1434
+ id: tool.call_id || tool.id,
1412
1435
  name: tool.name,
1413
1436
  status: tool.ok === false ? 'failed' : 'ok',
1414
1437
  at: tool.at,
1415
1438
  input: truncate(String(tool.input || ''), 180) || undefined,
1416
1439
  result: includeResults ? compactToolResult(tool.result, 360) : undefined,
1417
1440
  }));
1441
+ const cleanContextValue = (value) => {
1442
+ if (Array.isArray(value)) {
1443
+ 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));
1444
+ }
1445
+ if (!value || typeof value !== 'object')
1446
+ return value === '' ? undefined : value;
1447
+ const out = {};
1448
+ for (const [key, item] of Object.entries(value)) {
1449
+ const cleaned = cleanContextValue(item);
1450
+ if (cleaned === undefined || cleaned === null)
1451
+ continue;
1452
+ if (Array.isArray(cleaned) && cleaned.length === 0)
1453
+ continue;
1454
+ if (typeof cleaned === 'object' && !Array.isArray(cleaned) && Object.keys(cleaned).length === 0)
1455
+ continue;
1456
+ out[key] = cleaned;
1457
+ }
1458
+ return out;
1459
+ };
1460
+ const compactWorkingMemoryForAgent = (memory = {}) => cleanContextValue({
1461
+ current_goal: memory.current_goal,
1462
+ current_task: memory.current_task,
1463
+ last_user_intent: memory.last_user_intent,
1464
+ last_user_message: truncate(memory.last_user_message, 220),
1465
+ active_entities: memory.active_entities,
1466
+ open_decisions: memory.open_decisions,
1467
+ last_error: memory.last_error,
1468
+ next_expected_action: memory.next_expected_action,
1469
+ updated_at: memory.updated_at,
1470
+ });
1471
+ const compactDecisionStateForAgent = (state = {}) => cleanContextValue({
1472
+ current_intent: state.current_intent,
1473
+ active_decisions: (state.active_decisions || []).slice(-4).map((decision) => cleanContextValue({
1474
+ id: decision.id,
1475
+ status: decision.status,
1476
+ decision: truncate(decision.decision || decision.summary || decision.reason, 260),
1477
+ tool: decision.tool || decision.next_tool || decision.required_tool,
1478
+ reservation_id: decision.reservation_id,
1479
+ confirmation_id: decision.confirmation_id,
1480
+ at: decision.at || decision.updated_at,
1481
+ })),
1482
+ do_not_repeat_tools: state.do_not_repeat_tools,
1483
+ agenda_decision_state: state.agenda_decision_state,
1484
+ latest_tool: state.latest_tool ? cleanContextValue({
1485
+ name: state.latest_tool.name,
1486
+ status: state.latest_tool.status || (state.latest_tool.ok === false ? 'failed' : 'ok'),
1487
+ at: state.latest_tool.at,
1488
+ }) : undefined,
1489
+ conflict_policy: state.conflict_policy,
1490
+ });
1418
1491
  const compactOperationalStateForAgent = (state = {}) => {
1419
1492
  const agenda = state.agenda_state || {};
1420
1493
  return {
@@ -1444,6 +1517,21 @@ const compactMemoryCompressionForAgent = (compression = {}) => ({
1444
1517
  } : undefined,
1445
1518
  active_memory_count: ((compression.workflow_summary || {}).active_memory_count) || 0,
1446
1519
  });
1520
+ const compactActionLedgerForAgent = (ledger = [], maxItems = 6, includeResults = true) => pruneByLimit(ledger || [], maxItems).map((item) => cleanContextValue({
1521
+ action_id: item.action_id,
1522
+ kind: item.kind,
1523
+ tool: item.tool || item.name,
1524
+ status: item.status,
1525
+ at: item.at,
1526
+ result: includeResults ? compactToolResult(item.result, 260) : undefined,
1527
+ }));
1528
+ const compactEntityTimelineForAgent = (timeline = [], maxItems = 8) => pruneByLimit(timeline || [], maxItems).map((item) => cleanContextValue({
1529
+ entity: item.entity || item.source || item.name,
1530
+ event: truncate(item.event || item.fact || item.relation || item.kind || item.value, 220),
1531
+ target: item.target,
1532
+ at: item.at,
1533
+ source: item.source_type || item.source,
1534
+ }));
1447
1535
  const compactVectorMemoriesForAgent = (vectorMemories = [], toolHistory = [], maxItems = 3) => {
1448
1536
  const hasStructuredTools = Array.isArray(toolHistory) && toolHistory.length > 0;
1449
1537
  return (vectorMemories || [])
@@ -1452,6 +1540,87 @@ const compactVectorMemoriesForAgent = (vectorMemories = [], toolHistory = [], ma
1452
1540
  .filter((text) => !hasStructuredTools || !/^\[tool_events_extracted\]/i.test(text))
1453
1541
  .slice(0, maxItems);
1454
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
+ };
1455
1624
  const contextSizeOfMessages = (messages = []) => {
1456
1625
  const perMessage = (messages || []).map((message, index) => {
1457
1626
  const content = String(message.content || '');
@@ -1460,7 +1629,7 @@ const contextSizeOfMessages = (messages = []) => {
1460
1629
  const chars = perMessage.reduce((sum, item) => sum + item.chars, 0);
1461
1630
  return { chars, approx_tokens: approxTokenCount((messages || []).map((m) => m.content || '').join('\n')), messages: perMessage };
1462
1631
  };
1463
- const wrapElefaiMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
1632
+ const wrapTemboryMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
1464
1633
  get(target, prop) {
1465
1634
  if (prop === 'loadMemoryVariables') {
1466
1635
  return async (values = {}) => {
@@ -1469,7 +1638,7 @@ const wrapElefaiMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
1469
1638
  ]);
1470
1639
  try {
1471
1640
  const response = await target.loadMemoryVariables(values);
1472
- const cacheHit = Boolean(response.elefaiBrainDiagnostics && response.elefaiBrainDiagnostics.cacheHit);
1641
+ const cacheHit = Boolean(response.temboryDiagnostics && response.temboryDiagnostics.cacheHit);
1473
1642
  const chatHistory = cacheHit
1474
1643
  ? [{ cached: true, messages: Array.isArray(response[memoryKey] || response.chatHistory) ? (response[memoryKey] || response.chatHistory).length : 0 }]
1475
1644
  : snapshotJson(response[memoryKey] || response.chatHistory || []);
@@ -1479,23 +1648,23 @@ const wrapElefaiMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
1479
1648
  action: 'loadMemoryVariables',
1480
1649
  cached: cacheHit || undefined,
1481
1650
  chatHistory,
1482
- context: response.elefaiBrainContext,
1483
- contextText: response.elefaiBrainContextText,
1484
- summary: response.elefaiBrainSummary,
1485
- connectedModelSummary: response.elefaiBrainConnectedModelSummary,
1486
- workingMemory: response.elefaiBrainWorkingMemory,
1487
- decisionState: response.elefaiBrainDecisionState,
1488
- memoryCompression: response.elefaiBrainMemoryCompression,
1489
- profileFacts: response.elefaiBrainProfileFacts,
1490
- operationalState: response.elefaiBrainOperationalState,
1491
- actionLedger: response.elefaiBrainActionLedger,
1492
- entityTimeline: response.elefaiBrainEntityTimeline,
1493
- vectorMemories: response.elefaiBrainVectorMemories,
1494
- graph: response.elefaiBrainGraph,
1495
- recentMessages: response.elefaiBrainRecentMessages,
1496
- recentHighlights: response.elefaiBrainRecentHighlights,
1497
- toolHistory: response.elefaiBrainToolHistory,
1498
- diagnostics: response.elefaiBrainDiagnostics,
1651
+ context: response.temboryContext,
1652
+ contextText: response.temboryContextText,
1653
+ summary: response.temborySummary,
1654
+ connectedModelSummary: response.temboryConnectedModelSummary,
1655
+ workingMemory: response.temboryWorkingMemory,
1656
+ decisionState: response.temboryDecisionState,
1657
+ memoryCompression: response.temboryMemoryCompression,
1658
+ profileFacts: response.temboryProfileFacts,
1659
+ operationalState: response.temboryOperationalState,
1660
+ actionLedger: response.temboryActionLedger,
1661
+ entityTimeline: response.temboryEntityTimeline,
1662
+ vectorMemories: response.temboryVectorMemories,
1663
+ graph: response.temboryGraph,
1664
+ recentMessages: response.temboryRecentMessages,
1665
+ recentHighlights: response.temboryRecentHighlights,
1666
+ toolHistory: response.temboryToolHistory,
1667
+ diagnostics: response.temboryDiagnostics,
1499
1668
  },
1500
1669
  }],
1501
1670
  ]);
@@ -1529,17 +1698,18 @@ const wrapElefaiMemory = (memory, ctx, memoryKey) => new Proxy(memory, {
1529
1698
  return target[prop];
1530
1699
  },
1531
1700
  });
1532
- 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 }) => {
1533
1702
  const includeHeader = adv.includeContextHeader !== false;
1534
1703
  const includeSummary = adv.includeSummary !== false;
1535
1704
  const includeScores = adv.includeScores !== false;
1536
1705
  const compactForAgent = Boolean(adv.compactForAgent);
1706
+ const compactStateSections = Boolean(adv.compactStateSections);
1537
1707
  const sections = [];
1538
1708
  if (includeHeader) {
1539
1709
  sections.push({
1540
1710
  section: 'context_header',
1541
1711
  title: 'Tembory context',
1542
- value: compactForAgent
1712
+ value: compactForAgent || compactStateSections
1543
1713
  ? '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
1714
  : '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
1715
  });
@@ -1549,6 +1719,9 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1549
1719
  const summary = compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.summaryMaxFacts || 3));
1550
1720
  sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no non-tool vector memories to summarize' });
1551
1721
  }
1722
+ if (connectedModelSummary && adv.includeConnectedModelSummary !== false) {
1723
+ sections.push({ section: 'connected_model_summary', title: 'SLM summary', value: connectedModelSummary });
1724
+ }
1552
1725
  sections.push({
1553
1726
  section: 'working_memory',
1554
1727
  title: 'Working memory',
@@ -1588,7 +1761,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1588
1761
  why_null: adv.includeMemoryCompression === false ? 'memory compression disabled' : undefined,
1589
1762
  });
1590
1763
  const audit = {
1591
- kind: 'elefai.brain.context.v1',
1764
+ kind: 'tembory.context.v1',
1592
1765
  meta: { user_id: userId, payloadFormat, query, compact_for_agent: true },
1593
1766
  sections,
1594
1767
  diagnostics,
@@ -1609,13 +1782,18 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1609
1782
  return [{ role: 'system', content: truncate(sections.map(renderCompactSection).join('\n\n'), Number(adv.contextMaxChars || 6000)) }];
1610
1783
  }
1611
1784
  if (includeSummary) {
1612
- const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
1785
+ const summary = compactStateSections
1786
+ ? compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.summaryMaxFacts || 4))
1787
+ : vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
1613
1788
  sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no vector memories to summarize' });
1614
1789
  }
1790
+ if (connectedModelSummary && adv.includeConnectedModelSummary !== false) {
1791
+ sections.push({ section: 'connected_model_summary', title: 'SLM summary', value: connectedModelSummary });
1792
+ }
1615
1793
  sections.push({
1616
1794
  section: 'working_memory',
1617
1795
  title: 'Working memory',
1618
- value: adv.includeWorkingMemory === false ? null : (workingMemory || {}),
1796
+ value: adv.includeWorkingMemory === false ? null : (compactStateSections ? compactWorkingMemoryForAgent(workingMemory || {}) : (workingMemory || {})),
1619
1797
  why_null: adv.includeWorkingMemory === false ? 'working memory disabled' : undefined,
1620
1798
  });
1621
1799
  sections.push({
@@ -1639,31 +1817,31 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1639
1817
  sections.push({
1640
1818
  section: 'decision_state',
1641
1819
  title: 'Decision state',
1642
- value: adv.includeDecisionState === false ? null : (decisionState || {}),
1820
+ value: adv.includeDecisionState === false ? null : (compactStateSections ? compactDecisionStateForAgent(decisionState || {}) : (decisionState || {})),
1643
1821
  why_null: adv.includeDecisionState === false ? 'decision state disabled' : undefined,
1644
1822
  });
1645
1823
  sections.push({
1646
1824
  section: 'operational_state',
1647
1825
  title: 'Operational state',
1648
- value: adv.includeOperationalState === false ? null : operationalState,
1826
+ value: adv.includeOperationalState === false ? null : (compactStateSections ? compactOperationalStateForAgent(operationalState || {}) : operationalState),
1649
1827
  why_null: adv.includeOperationalState === false ? 'operational state disabled' : undefined,
1650
1828
  });
1651
1829
  sections.push({
1652
1830
  section: 'action_ledger',
1653
1831
  title: 'Action ledger',
1654
- value: adv.includeActionLedger === false ? null : (actionLedger || []),
1832
+ value: adv.includeActionLedger === false ? null : (compactStateSections ? compactActionLedgerForAgent(actionLedger || [], adv.actionLedgerMaxItems || 6, adv.includeToolResults !== false) : (actionLedger || [])),
1655
1833
  why_null: adv.includeActionLedger === false ? 'action ledger disabled' : undefined,
1656
1834
  });
1657
1835
  sections.push({
1658
1836
  section: 'entity_timeline',
1659
1837
  title: 'Entity timeline',
1660
- value: adv.includeEntityTimeline === false ? null : (entityTimeline || []),
1838
+ value: adv.includeEntityTimeline === false ? null : (compactStateSections ? compactEntityTimelineForAgent(entityTimeline || [], adv.entityTimelineMaxItems || 8) : (entityTimeline || [])),
1661
1839
  why_null: adv.includeEntityTimeline === false ? 'entity timeline disabled' : undefined,
1662
1840
  });
1663
1841
  sections.push({
1664
1842
  section: 'vector',
1665
1843
  title: 'Vector memories',
1666
- value: vectorMemories.map((m) => {
1844
+ value: compactStateSections ? compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.maxReturn || adv.topK || 4)) : vectorMemories.map((m) => {
1667
1845
  const scoreMeta = scoreMetaOf(m);
1668
1846
  const rawScore = scoreOf(m);
1669
1847
  return {
@@ -1681,7 +1859,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1681
1859
  sections.push({
1682
1860
  section: 'memory_compression',
1683
1861
  title: 'Memory compression',
1684
- value: adv.includeMemoryCompression === false ? null : (memoryCompression || {}),
1862
+ value: adv.includeMemoryCompression === false ? null : (compactStateSections ? compactMemoryCompressionForAgent(memoryCompression || {}) : (memoryCompression || {})),
1685
1863
  why_null: adv.includeMemoryCompression === false ? 'memory compression disabled' : undefined,
1686
1864
  });
1687
1865
  sections.push({
@@ -1693,7 +1871,11 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1693
1871
  sections.push({
1694
1872
  section: 'recent_messages',
1695
1873
  title: 'Recent messages',
1696
- value: recentMessages || [],
1874
+ value: compactStateSections ? pruneByLimit(recentMessages || [], adv.recentMessagesLastN || 4).map((message) => cleanContextValue({
1875
+ role: message.role,
1876
+ content: truncate(message.content, 260),
1877
+ at: message.at,
1878
+ })) : recentMessages || [],
1697
1879
  });
1698
1880
  sections.push({
1699
1881
  section: 'recent_highlights',
@@ -1704,18 +1886,18 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1704
1886
  section: 'tool_history',
1705
1887
  title: 'Tool history',
1706
1888
  value: {
1707
- enabled: adv.includeToolHistory !== false,
1708
- items: adv.includeToolHistory === false ? [] : toolHistory.map((tool) => ({
1709
- id: tool.id,
1710
- turnId: tool.turnId,
1711
- sequence: tool.sequence,
1889
+ enabled: adv.includeToolHistory !== false,
1890
+ items: adv.includeToolHistory === false ? [] : (compactStateSections ? compactToolHistoryForAgent(toolHistory, adv.toolHistoryLastN || 8, adv.includeToolResults !== false) : toolHistory.map((tool) => ({
1891
+ id: tool.id,
1892
+ turnId: tool.turnId,
1893
+ sequence: tool.sequence,
1712
1894
  name: tool.name,
1713
1895
  input: tool.input,
1714
1896
  ok: tool.ok,
1715
1897
  at: tool.at,
1716
- source: tool.source,
1717
- result: adv.includeToolResults === false ? undefined : tool.result,
1718
- })),
1898
+ source: tool.source,
1899
+ result: adv.includeToolResults === false ? undefined : tool.result,
1900
+ }))),
1719
1901
  },
1720
1902
  });
1721
1903
  if (adv.includeDiagnostics) {
@@ -1726,7 +1908,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1726
1908
  });
1727
1909
  }
1728
1910
  const audit = {
1729
- kind: 'elefai.brain.context.v1',
1911
+ kind: 'tembory.context.v1',
1730
1912
  meta: { user_id: userId, payloadFormat, query },
1731
1913
  sections,
1732
1914
  diagnostics,
@@ -1740,17 +1922,32 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
1740
1922
  return `## ${section.title}\n${section.value.length ? section.value.map((item) => typeof item === 'string' ? `- ${item}` : `- ${truncate(safeStringify(item), 900)}`).join('\n') : '(empty)'}`;
1741
1923
  return `## ${section.title}\n${truncate(safeStringify(section.value), 1600)}`;
1742
1924
  };
1925
+ const sectionIsEmpty = (section) => {
1926
+ if (!compactStateSections)
1927
+ return false;
1928
+ 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')
1929
+ return false;
1930
+ if (section.value === null || section.value === undefined)
1931
+ return true;
1932
+ if (Array.isArray(section.value) && section.value.length === 0)
1933
+ return true;
1934
+ if (typeof section.value === 'object' && !Array.isArray(section.value) && Object.keys(section.value).length === 0)
1935
+ return true;
1936
+ return false;
1937
+ };
1938
+ const renderableSections = compactStateSections ? sections.filter((section) => !sectionIsEmpty(section)) : sections;
1743
1939
  if (payloadFormat === 'auditJson') {
1744
1940
  return [{ role: 'system', content: JSON.stringify(audit, null, 2) }];
1745
1941
  }
1746
1942
  if (payloadFormat === 'auditBlocks') {
1747
- return sections.map((section) => ({ role: 'system', content: renderSection(section) }));
1943
+ return renderableSections.map((section) => ({ role: 'system', content: renderSection(section) }));
1748
1944
  }
1749
- const text = sections.map(renderSection).join('\n\n');
1945
+ const text = renderableSections.map(renderSection).join('\n\n');
1946
+ const maxChars = Number(adv.contextMaxChars || 16000);
1750
1947
  if (payloadFormat === 'auditText' || payloadFormat === 'singleSystemMessage' || payloadFormat === 'structured') {
1751
- return [{ role: 'system', content: truncate(text, 16000) }];
1948
+ return [{ role: 'system', content: truncate(text, maxChars) }];
1752
1949
  }
1753
- return [{ role: 'system', content: truncate(text, 16000) }];
1950
+ return [{ role: 'system', content: truncate(text, maxChars) }];
1754
1951
  };
1755
1952
  class Mem0Memory {
1756
1953
  constructor() {
@@ -1898,8 +2095,25 @@ class Mem0Memory {
1898
2095
  { 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
2096
  { displayName: 'Incluir Cabeçalho de Contexto', name: 'includeContextHeader', type: 'boolean', default: true },
1900
2097
  { 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: 'Máximo de Caracteres do Contexto', name: 'contextMaxChars', type: 'number', default: 6000, description: 'Limite final aplicado quando Compactar Contexto Para Agente estiver ativo.' },
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.' },
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.' },
1902
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 },
1903
2117
  { displayName: 'Máximo de Fatos no Resumo', name: 'summaryMaxFacts', type: 'number', default: 4 },
1904
2118
  { displayName: 'Incluir Scores', name: 'includeScores', type: 'boolean', default: true },
1905
2119
  { displayName: 'Incluir Diagnóstico', name: 'includeDiagnostics', type: 'boolean', default: false },
@@ -1968,24 +2182,24 @@ class Mem0Memory {
1968
2182
  if (loadCache.has(cacheKey)) {
1969
2183
  result = snapshotJson(loadCache.get(cacheKey));
1970
2184
  result.response = result.response || {};
1971
- result.response.elefaiBrainDiagnostics = {
1972
- ...(result.response.elefaiBrainDiagnostics || {}),
2185
+ result.response.temboryDiagnostics = {
2186
+ ...(result.response.temboryDiagnostics || {}),
1973
2187
  cacheHit: true,
1974
2188
  cacheScope: 'supplyData.loadMemoryVariables',
1975
2189
  };
1976
- if (result.response.elefaiBrainContext) {
1977
- result.response.elefaiBrainContext = {
1978
- kind: result.response.elefaiBrainContext.kind,
1979
- userId: result.response.elefaiBrainContext.userId,
1980
- project: result.response.elefaiBrainContext.project,
1981
- query: result.response.elefaiBrainContext.query,
1982
- retrievalMode: result.response.elefaiBrainContext.retrievalMode,
1983
- payloadFormat: result.response.elefaiBrainContext.payloadFormat,
1984
- contextQualityScore: result.response.elefaiBrainContext.contextQualityScore,
2190
+ if (result.response.temboryContext) {
2191
+ result.response.temboryContext = {
2192
+ kind: result.response.temboryContext.kind,
2193
+ userId: result.response.temboryContext.userId,
2194
+ project: result.response.temboryContext.project,
2195
+ query: result.response.temboryContext.query,
2196
+ retrievalMode: result.response.temboryContext.retrievalMode,
2197
+ payloadFormat: result.response.temboryContext.payloadFormat,
2198
+ contextQualityScore: result.response.temboryContext.contextQualityScore,
1985
2199
  cacheHit: true,
1986
2200
  };
1987
2201
  }
1988
- delete result.response.elefaiBrainContextText;
2202
+ delete result.response.temboryContextText;
1989
2203
  }
1990
2204
  else {
1991
2205
  result = await Mem0Memory.prototype.loadMemoryVariablesForItem.call(this, itemIndex, inputValues);
@@ -2016,7 +2230,7 @@ class Mem0Memory {
2016
2230
  await Mem0Memory.prototype.saveContextForItem.call(this, itemIndex, inputValues, outputValues);
2017
2231
  },
2018
2232
  };
2019
- return { response: wrapElefaiMemory(memory, this, memoryKey) };
2233
+ return { response: wrapTemboryMemory(memory, this, memoryKey) };
2020
2234
  }
2021
2235
  async saveMessagesForItem(itemIndex, messages = []) {
2022
2236
  const inputValues = {};
@@ -2427,7 +2641,7 @@ class Mem0Memory {
2427
2641
  }
2428
2642
  ranked = selected;
2429
2643
  }
2430
- const finalMemories = ranked.slice(0, maxReturn).map((r) => withElefaiScore(r.m, {
2644
+ const finalMemories = ranked.slice(0, maxReturn).map((r) => withTemboryScore(r.m, {
2431
2645
  semanticScore: r.semanticScore,
2432
2646
  recencyScore: r.recencyScore,
2433
2647
  hybridScore: r.hybrid,
@@ -2437,7 +2651,7 @@ class Mem0Memory {
2437
2651
  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
2652
  }
2439
2653
  else {
2440
- vectorMemories = semMemories.map((m) => withElefaiScore(m, {
2654
+ vectorMemories = semMemories.map((m) => withTemboryScore(m, {
2441
2655
  semanticScore: scoreOf(m),
2442
2656
  source: 'semantic',
2443
2657
  }));
@@ -2528,34 +2742,6 @@ class Mem0Memory {
2528
2742
  }
2529
2743
  catch { }
2530
2744
  }
2531
- let connectedModelSummary = '';
2532
- if (connectedLanguageModel && typeof connectedLanguageModel.invoke === 'function' && vectorMemories.length && adv.includeSummary !== false) {
2533
- try {
2534
- const facts = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 500)).filter(Boolean).join('\n') || '(no vector memories found)';
2535
- if (facts) {
2536
- const response = await connectedLanguageModel.invoke([
2537
- toBaseMessage({
2538
- role: 'user',
2539
- 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)}`,
2540
- }),
2541
- ]);
2542
- connectedModelSummary = truncate(response?.content || response?.text || String(response || ''), 1200);
2543
- connectedAi.languageModelSummary = true;
2544
- }
2545
- }
2546
- catch (error) {
2547
- connectedAi.errors.push(`languageModel.invoke: ${error.message || String(error)}`);
2548
- }
2549
- }
2550
- const diagnostics = {
2551
- vectorMemories: vectorMemories.length,
2552
- recentMessages: recentMessages.length,
2553
- toolHistory: toolHistory.length,
2554
- graph: graph.length,
2555
- project: project || null,
2556
- memoryNamespace: key,
2557
- connectedAi,
2558
- };
2559
2745
  const includeToolResults = adv.includeToolResults !== false;
2560
2746
  const operationalState = deriveOperationalState(toolHistory, renderProfileFacts(profileFacts), recentMessages, includeToolResults);
2561
2747
  const actionLedger = deriveActionLedger(toolHistory, adv.actionLedgerMaxItems || adv.toolHistoryLastN || 20, includeToolResults);
@@ -2582,6 +2768,38 @@ class Mem0Memory {
2582
2768
  vectorMemories,
2583
2769
  maxItems: adv.compressionMaxItems || 6,
2584
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
+ };
2585
2803
  const contextHealth = deriveContextHealth({
2586
2804
  userId: key,
2587
2805
  project,
@@ -2619,6 +2837,7 @@ class Mem0Memory {
2619
2837
  highlights,
2620
2838
  graph,
2621
2839
  diagnostics,
2840
+ connectedModelSummary,
2622
2841
  adv,
2623
2842
  });
2624
2843
  diagnostics.contextSize = contextSizeOfMessages(payload);
@@ -2645,7 +2864,7 @@ class Mem0Memory {
2645
2864
  const summary = vectorMemories.slice(0, Number(adv.summaryMaxFacts || 4)).map((memory) => contextMemoryText(memory, 360)).filter(Boolean);
2646
2865
  const contextText = payload.map((message) => String(message.content || '')).join('\n\n');
2647
2866
  const audit = {
2648
- kind: 'elefai.brain.context.v1',
2867
+ kind: 'tembory.context.v1',
2649
2868
  userId: key,
2650
2869
  project: project || undefined,
2651
2870
  query,
@@ -2716,25 +2935,25 @@ class Mem0Memory {
2716
2935
  return {
2717
2936
  response: {
2718
2937
  [memoryKey]: payload,
2719
- elefaiBrainContext: audit,
2720
- elefaiBrainContextText: contextText,
2721
- elefaiBrainSummary: summary,
2722
- elefaiBrainConnectedModelSummary: connectedModelSummary,
2723
- elefaiBrainContextHealth: contextHealth,
2724
- elefaiBrainContextQualityScore: contextHealth.quality_score,
2725
- elefaiBrainWorkingMemory: workingMemory,
2726
- elefaiBrainDecisionState: decisionState,
2727
- elefaiBrainMemoryCompression: memoryCompression,
2728
- elefaiBrainProfileFacts: renderProfileFacts(profileFacts),
2729
- elefaiBrainOperationalState: operationalState,
2730
- elefaiBrainActionLedger: actionLedger,
2731
- elefaiBrainEntityTimeline: entityTimeline,
2732
- elefaiBrainVectorMemories: normalizedVectorMemories,
2733
- elefaiBrainGraph: graph,
2734
- elefaiBrainRecentMessages: recentMessages,
2735
- elefaiBrainRecentHighlights: highlights,
2736
- elefaiBrainToolHistory: audit.toolHistory,
2737
- elefaiBrainDiagnostics: diagnostics,
2938
+ temboryContext: audit,
2939
+ temboryContextText: contextText,
2940
+ temborySummary: summary,
2941
+ temboryConnectedModelSummary: connectedModelSummary,
2942
+ temboryContextHealth: contextHealth,
2943
+ temboryContextQualityScore: contextHealth.quality_score,
2944
+ temboryWorkingMemory: workingMemory,
2945
+ temboryDecisionState: decisionState,
2946
+ temboryMemoryCompression: memoryCompression,
2947
+ temboryProfileFacts: renderProfileFacts(profileFacts),
2948
+ temboryOperationalState: operationalState,
2949
+ temboryActionLedger: actionLedger,
2950
+ temboryEntityTimeline: entityTimeline,
2951
+ temboryVectorMemories: normalizedVectorMemories,
2952
+ temboryGraph: graph,
2953
+ temboryRecentMessages: recentMessages,
2954
+ temboryRecentHighlights: highlights,
2955
+ temboryToolHistory: audit.toolHistory,
2956
+ temboryDiagnostics: diagnostics,
2738
2957
  },
2739
2958
  };
2740
2959
  }
@@ -2854,4 +3073,7 @@ exports.__private = {
2854
3073
  compactToolResult,
2855
3074
  compactToolHistoryForAgent,
2856
3075
  compactOperationalStateForAgent,
3076
+ buildConnectedModelSummaryInput,
3077
+ cleanModelSummaryText,
3078
+ invokeConnectedModelSummary,
2857
3079
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.9",
3
+ "version": "1.0.12",
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",
@@ -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-ELEFAI-LAB-001","selected_from_message":"dia 13","status":"pre_reserved","next_step":"confirmar_agendamento"}}]',
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-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.',
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
- elefaiScore: { semanticScore: 0.71, recencyScore: 0.99, hybridScore: 0.81, source: 'semantic' },
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
- elefaiScore: { semanticScore: 0.7, recencyScore: 0.99, hybridScore: 0.8, source: 'semantic' },
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-ELEFAI-LAB-001","status":"pre_reserved"}}]',
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-ELEFAI-LAB-001/.test(text),
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));