n8n-nodes-tembory 1.3.4 → 1.3.6

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,7 +2,22 @@
2
2
 
3
3
  Node de memoria operacional da Tembory para agentes de IA no n8n.
4
4
 
5
- Versao atual: `1.3.4`.
5
+ Versao atual: `1.3.6`.
6
+
7
+ ## 1.3.6
8
+
9
+ - Fortalece o default recomendado para agentes mini/SLM em workflows reais.
10
+ - `Memoria Inteligente (Recomendado)` agora usa `productionBalanced` com contexto de 20000 caracteres, entrada do SLM em 12000 caracteres, resumo SLM em 3000 caracteres e active summary em 3500 caracteres.
11
+ - Mantem 30 tools recentes no contexto operacional e TTL de tool history em 86400 segundos.
12
+ - Alinha os defaults visiveis em `Ajustes Tecnicos` para nao mostrar configuracao mais fraca quando o usuario abre os grupos.
13
+ - Esclarece que o cache tecnico SLM usa segundos; 300 segundos equivalem a 5 minutos.
14
+
15
+ ## 1.3.5
16
+
17
+ - Atualiza o `Tembory Agent Memory` para usuarios leigos: o padrao agora e `Modo da Memoria -> Memoria Inteligente (Recomendado)`.
18
+ - Esse modo aplica `productionBalanced` sem exigir que a pessoa abra ajustes tecnicos: contexto estruturado, active summary, tool history/results, action ledger, decision state, operational state e mensagens recentes ficam ligados por padrao.
19
+ - Renomeia campos visiveis para linguagem operacional: `Tamanho do Contexto`, `Mensagens Recentes`, `Mostrar Evidencias no Output` e `Mostrar Ajustes Tecnicos`.
20
+ - Mantem os controles brutos escondidos em `Ajustes Tecnicos Tembory`, para debug e casos avancados, sem tornar isso obrigatorio para o usuario comum.
6
21
 
7
22
  ## 1.3.4
8
23
 
@@ -213,13 +228,18 @@ No modo simples, o node aplica automaticamente:
213
228
 
214
229
  - `Modo de Recuperacao`: operacional estruturado.
215
230
  - `Formato do Contexto`: producao estruturado.
216
- - `Preset Operacional`: producao rapida.
217
- - `Fonte do Resumo do SLM`: contexto ativo.
231
+ - `Preset Operacional`: producao balanceada.
232
+ - `Fonte do Resumo do SLM`: automatica.
233
+ - `Maximo de Caracteres do Contexto`: 20000.
234
+ - `Maximo de Caracteres de Entrada do SLM`: 12000.
235
+ - `Maximo de Caracteres do Resumo do SLM`: 3000.
236
+ - `Maximo de Caracteres do Active Summary`: 3500.
218
237
  - Tool history, resultados de tools, action ledger, working memory, decision state, operational state e memory compression ligados.
219
238
  - Persistencia no backend e active summary ligados.
220
239
  - Diagnostico pesado, scores, semantic fallback e tool facts desligados.
221
- - TTL de tool history em 36000 segundos.
222
- - Ultimas tools mantidas no contexto compacto: 50.
240
+ - Cache tecnico do SLM em 300 segundos.
241
+ - TTL de tool history em 86400 segundos.
242
+ - Ultimas tools mantidas no contexto compacto: 30.
223
243
 
224
244
  ## Uso com `$fromAI()`
225
245
 
@@ -245,8 +265,8 @@ Exemplo de budget:
245
265
  {
246
266
  "agentContextBudget": {
247
267
  "messages": 1,
248
- "chars": 4200,
249
- "approxTokens": 1050,
268
+ "chars": 12000,
269
+ "approxTokens": 3000,
250
270
  "largestSections": [
251
271
  { "section": "tools", "chars": 1600, "approxTokens": 400 }
252
272
  ]
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assertTemboryCredentials = assertTemboryCredentials;
4
3
  exports.temboryApiRequest = temboryApiRequest;
4
+ exports.assertTemboryCredentials = assertTemboryCredentials;
5
5
  const n8n_workflow_1 = require("n8n-workflow");
6
6
  async function getTemboryCredentials(ctx) {
7
7
  try {
@@ -15,14 +15,10 @@ async function getTemboryCredentials(ctx) {
15
15
  throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Credentials for Tembory are not set. Select a Tembory API credential and save the workflow.');
16
16
  }
17
17
  async function assertTemboryCredentials(ctx) {
18
- const credentials = await getTemboryCredentials(ctx);
19
- if (!credentials || !credentials.apiKey) {
20
- throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Tembory API credential is missing an API key. Configure a valid Tembory API credential before using this memory node.');
21
- }
22
- return credentials;
18
+ await getTemboryCredentials(ctx);
23
19
  }
24
20
  async function temboryApiRequest(method, endpoint, body = {}, qs = {}) {
25
- const credentials = await assertTemboryCredentials(this);
21
+ const credentials = await getTemboryCredentials(this);
26
22
  const baseUrl = 'https://api.tembory.com';
27
23
  const operation = resolveGatewayOperation(method, endpoint);
28
24
  const payload = {
@@ -1333,8 +1333,8 @@ const mergeRemoteThreadState = (store, key, state) => {
1333
1333
  store.activeSummary[key] = state.activeSummary;
1334
1334
  };
1335
1335
  const SIMPLE_MODE_OVERRIDES = {
1336
- operationPreset: 'productionFast',
1337
- summarySource: 'activeContext',
1336
+ operationPreset: 'productionBalanced',
1337
+ summarySource: 'auto',
1338
1338
  includeContextHeader: true,
1339
1339
  compactStateSections: true,
1340
1340
  includeSummary: true,
@@ -1357,13 +1357,13 @@ const SIMPLE_MODE_OVERRIDES = {
1357
1357
  includeDiagnostics: false,
1358
1358
  persistToolFactsToTembory: false,
1359
1359
  includeToolHistorySemanticFallback: false,
1360
- contextMaxChars: 10000,
1361
- toolHistoryLastN: 50,
1362
- toolHistoryTTLSeconds: 36000,
1360
+ contextMaxChars: 20000,
1361
+ toolHistoryLastN: 30,
1362
+ toolHistoryTTLSeconds: 86400,
1363
1363
  recentMessagesLastN: 50,
1364
- connectedModelSummaryInputMaxChars: 4200,
1365
- connectedModelSummaryMaxChars: 1200,
1366
- activeSummaryMaxChars: 1800,
1364
+ connectedModelSummaryInputMaxChars: 12000,
1365
+ connectedModelSummaryMaxChars: 3000,
1366
+ activeSummaryMaxChars: 3500,
1367
1367
  activeSummaryRetentionDays: 30,
1368
1368
  };
1369
1369
  const applyOperationalPreset = (advanced = {}) => {
@@ -1445,7 +1445,7 @@ const applyOperationalPreset = (advanced = {}) => {
1445
1445
  includeConnectedModelSummary: true,
1446
1446
  includeActiveSummary: true,
1447
1447
  persistActiveSummary: true,
1448
- activeSummaryMaxChars: 1800,
1448
+ activeSummaryMaxChars: 3500,
1449
1449
  activeSummaryRetentionDays: 30,
1450
1450
  enableTransientSummaryCache: true,
1451
1451
  transientSummaryCacheTTLSeconds: 300,
@@ -1471,12 +1471,14 @@ const applyOperationalPreset = (advanced = {}) => {
1471
1471
  includeRecentHighlights: true,
1472
1472
  topK: 6,
1473
1473
  lastN: 8,
1474
- toolHistoryLastN: 10,
1474
+ toolHistoryLastN: 30,
1475
+ toolHistoryTTLSeconds: 86400,
1475
1476
  recentMessagesLastN: 50,
1476
1477
  vectorMemoryMaxChars: 360,
1477
- contextMaxChars: 10000,
1478
- connectedModelSummaryMaxChars: 1200,
1479
- connectedModelSummaryInputMaxChars: 4200,
1478
+ contextMaxChars: 20000,
1479
+ connectedModelSummaryMaxChars: 3000,
1480
+ connectedModelSummaryInputMaxChars: 12000,
1481
+ summaryMaxFacts: 8,
1480
1482
  },
1481
1483
  productionCheap: {
1482
1484
  summarySource: 'activeContext',
@@ -1648,6 +1650,7 @@ const readAdvancedOptions = (ctx, itemIndex) => {
1648
1650
  };
1649
1651
  readTopLevelOverride('contextMaxChars');
1650
1652
  readTopLevelOverride('recentMessagesLastN');
1653
+ readTopLevelOverride('operationPreset');
1651
1654
  try {
1652
1655
  const debugVisualOutput = ctx.getNodeParameter('debugVisualOutput', itemIndex, undefined);
1653
1656
  if (debugVisualOutput !== undefined) {
@@ -2054,7 +2057,7 @@ const turnBriefGuidanceForIntent = (intent = '') => {
2054
2057
  return 'May require a tool. Use prompt policy. Prior tools are evidence only; do not claim new side effects without a current required tool call.';
2055
2058
  if (intent === 'profile_update')
2056
2059
  return 'Likely stable profile data. Save useful facts and continue; call tools only when prompt requires.';
2057
- return 'No specific memory action inferred for this turn; use conversation, tool history and operational state only as read-only context.';
2060
+ return 'Continue according to the agent prompt using conversation, tool history and operational state as read-only context.';
2058
2061
  };
2059
2062
  const buildTurnBriefForAgent = ({ query = '', recentMessages = [], toolHistory = [], operationalState = {}, workingMemory = {}, decisionState = {}, diagnostics = {} }) => {
2060
2063
  const currentIntent = (decisionState || {}).current_intent || (workingMemory || {}).last_user_intent || inferUserIntent(query, recentMessages);
@@ -2182,7 +2185,7 @@ const inferUserIntent = (query = '', recentMessages = []) => {
2182
2185
  };
2183
2186
  const deriveNextExpectedAction = (intent, operationalState = {}) => {
2184
2187
  if (['affirm', 'commit_or_continue', 'tool_action_candidate', 'selection_or_slot'].includes(intent))
2185
- return 'evaluate whether the current turn needs a tool; reuse conversation_frame, tool_state, tool_history and action_ledger before executing anything new';
2188
+ return 'current turn needs a tool; continue according to the agent prompt using conversation_frame, tool_state, tool_history and action_ledger; do not apply domain-specific memory rules';
2186
2189
  if (intent === 'profile_update')
2187
2190
  return 'save stable profile facts and continue the conversation';
2188
2191
  if (intent === 'conversation_recall')
@@ -2191,7 +2194,7 @@ const deriveNextExpectedAction = (intent, operationalState = {}) => {
2191
2194
  return 'answer status questions from tool_state, tool_history and action_ledger; do not call tools unless the agent prompt requires it';
2192
2195
  return undefined;
2193
2196
  };
2194
- const isGenericMemoryNextAction = (value = '') => /answer using retrieved context and avoid unnecessary tool calls|continue according to the agent prompt using retrieved context|continue according to the agent prompt/i.test(String(value || ''));
2197
+ const isGenericMemoryNextAction = (value = '') => /answer using retrieved context and avoid unnecessary tool calls|continue according to the agent prompt using retrieved context/i.test(String(value || ''));
2195
2198
  const shouldCarryPreviousGoal = (intent = '', previousGoal = '') => {
2196
2199
  if (!previousGoal || isGenericMemoryNextAction(previousGoal))
2197
2200
  return false;
@@ -3231,14 +3234,6 @@ const buildAgentContextV2 = ({ query = '', userId = '', payloadFormat = 'structu
3231
3234
  memory: cleanContextValue({
3232
3235
  slmSummary: connectedModelSummary ? truncate(connectedModelSummary, Number(adv.connectedModelSummaryMaxChars || 900)) : undefined,
3233
3236
  activeSummary: !connectedModelSummary && activeSummary ? truncate(activeSummary, Number(adv.activeSummaryMaxChars || 900)) : undefined,
3234
- summaryStatus: diagnostics?.activeSummary ? cleanContextValue({
3235
- source: diagnostics.activeSummary.source,
3236
- generated: Boolean(connectedModelSummary),
3237
- activeSummaryLoaded: Boolean(diagnostics.activeSummary.activeSummaryLoaded),
3238
- activeSummaryUpdated: Boolean(diagnostics.activeSummary.activeSummaryUpdated),
3239
- transientCacheHit: Boolean(diagnostics.activeSummary.transientCacheHit),
3240
- chars: diagnostics.activeSummary.summaryChars,
3241
- }) : undefined,
3242
3237
  referenceFacts,
3243
3238
  compression: adv.includeMemoryCompression === false ? undefined : compactMemoryCompressionForAgent(memoryCompression || {}),
3244
3239
  }),
@@ -3360,7 +3355,7 @@ const invokeConnectedModelSummary = async (connectedLanguageModel, summaryInput,
3360
3355
  const response = await connectedLanguageModel.invoke([
3361
3356
  toBaseMessage({
3362
3357
  role: 'user',
3363
- content: `Update the Tembory active summary for the next agent turn. Return only concise Portuguese bullets, no JSON and no markdown table. Include what the agent is doing now, the current objective, the next expected action, useful tool evidence, pending confirmations, durable user facts, constraints, contradictions, and do-not-repeat guidance when present. Preserve IDs, dates, tool names, confirmed decisions, explicit pending actions, constraints, contradictions, and do-not-repeat instructions. Prefer durable useful context over raw logs. Do not invent facts. Treat inferred gaps or missing details as read-only observations, not action requirements, unless they are explicitly present in tool_state, action_ledger, working_memory.next_expected_action, or the current user message. Do not convert observations, guesses, or helpful suggestions into blocking pending actions. Do-not-repeat means avoiding duplicate prerequisite lookup calls; it never means a current side-effect action is completed without a successful tool call in the current turn.\n\nContext:\n${summaryInput}`,
3358
+ content: `Update the Tembory active summary for the next agent turn. Return only concise Portuguese bullets, no JSON and no markdown table. Preserve IDs, dates, tool names, confirmed decisions, explicit pending actions, constraints, contradictions, and do-not-repeat instructions. Prefer durable useful context over raw logs. Do not invent facts. Treat inferred gaps or missing details as read-only observations, not action requirements, unless they are explicitly present in tool_state, action_ledger, working_memory.next_expected_action, or the current user message. Do not convert observations, guesses, or helpful suggestions into blocking pending actions. Do-not-repeat means avoiding duplicate prerequisite lookup calls; it never means a current side-effect action is completed without a successful tool call in the current turn.\n\nContext:\n${summaryInput}`,
3364
3359
  }),
3365
3360
  ]);
3366
3361
  return cleanModelSummaryText(response, Number(adv.connectedModelSummaryMaxChars || 1200));
@@ -3548,15 +3543,13 @@ const summarizeSaveContextForSideChannel = (input = {}, output = {}, chatHistory
3548
3543
  const toolEvents = compactToolEventsForSideChannel(toolCalls, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX);
3549
3544
  const conversation = conversationDigestFromMessagesForSideChannel(chatHistory);
3550
3545
  const timeline = conversationTimelineFromMessagesForSideChannel(chatHistory, 16);
3546
+ const toolLog = buildToolLogForSideChannel(toolEvents, toolCalls.length, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX);
3551
3547
  return cleanContextValue({
3552
3548
  visualSchema: VISUAL_SCHEMA_VERSION,
3553
- summary: cleanContextValue({
3554
- action: 'saveContext',
3549
+ summary: {
3555
3550
  messagesAfterSave: Array.isArray(chatHistory) ? chatHistory.length : 0,
3556
- userInputPreview: inputMessage ? truncate(String(inputMessage), 220) : undefined,
3557
- assistantOutputPreview: outputMessage ? truncate(String(outputMessage), 260) : undefined,
3558
3551
  toolCallsCaptured: toolCalls.length,
3559
- }),
3552
+ },
3560
3553
  conversation: cleanContextValue({
3561
3554
  ...conversation,
3562
3555
  timeline,
@@ -3568,11 +3561,7 @@ const summarizeSaveContextForSideChannel = (input = {}, output = {}, chatHistory
3568
3561
  tools: cleanContextValue({
3569
3562
  captured: toolCalls.length,
3570
3563
  capture: summarizeToolCaptureForSideChannel(output, toolCalls),
3571
- log: buildToolLogForSideChannel(toolEvents, toolCalls.length, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX),
3572
- }),
3573
- save: cleanContextValue({
3574
- messagesAfterSave: Array.isArray(chatHistory) ? chatHistory.length : 0,
3575
- status: 'saved_to_memory_contract',
3564
+ log: toolLog,
3576
3565
  }),
3577
3566
  });
3578
3567
  };
@@ -3597,14 +3586,12 @@ const compactMemoryEventPayload = (payload = {}) => {
3597
3586
  compact[`${key}Chars`] = typeof compact[key] === 'string' ? compact[key].length : safeStringify(compact[key]).length;
3598
3587
  delete compact[key];
3599
3588
  }
3600
- return keepVisibleToolLogArrays(compact);
3589
+ return compact;
3601
3590
  };
3602
3591
  const compactVisualSummaryForMode = (summary = {}, configurationMode = 'advanced') => {
3603
3592
  const compact = { ...(summary || {}) };
3604
3593
  if (String(configurationMode || 'advanced') !== 'simple')
3605
3594
  return compact;
3606
- delete compact.toolNames;
3607
- delete compact.toolEvents;
3608
3595
  delete compact.savedMessages;
3609
3596
  return compact;
3610
3597
  };
@@ -3792,20 +3779,10 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3792
3779
  toolCallsCaptured: parsed.captureHealth?.toolCallsCapturedLastSave,
3793
3780
  captureSources: parsed.captureHealth?.captureSources,
3794
3781
  } : {}));
3795
- const summaryStatus = parsed.memory?.summaryStatus || parsed.diagnostics?.activeSummary || {};
3796
- const slmPreview = parsed.memory?.slmSummary || parsed.memory?.activeSummary || summaryText || '';
3797
3782
  const fullDedupeSummary = parsed.dedupeSummary || parsed.diagnostics?.dedupeSummary || undefined;
3798
3783
  const loadedSections = loadedSectionsForSideChannel(parsed, memoryAudit);
3799
3784
  const agentContextBudget = agentContextBudgetForSideChannel(list, parsed);
3800
3785
  summary.visualSchema = VISUAL_SCHEMA_VERSION;
3801
- summary.sentToAgent = cleanContextValue({
3802
- messages: list.length,
3803
- contextKind: parsed.kind,
3804
- schemaVersion: parsed.schemaVersion,
3805
- chars: agentContextBudget.chars,
3806
- approxTokens: agentContextBudget.approxTokens,
3807
- largestSections: agentContextBudget.largestSections,
3808
- });
3809
3786
  summary.userId = parsed.userId;
3810
3787
  summary.project = parsed.project || undefined;
3811
3788
  summary.retrievalMode = parsed.retrievalMode;
@@ -3813,12 +3790,13 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3813
3790
  summary.intent = parsed.currentTurn?.intentHint || parsed.observations?.inferred_intent?.label || parsed.workingMemory?.last_user_intent || parsed.decisionState?.current_intent || undefined;
3814
3791
  const parsedTurnBrief = parsed.turnBrief || parsed.turn_brief || undefined;
3815
3792
  summary.currentTurn = parsed.currentTurn || parsed.current_turn || parsed.diagnostics?.currentTurn || undefined;
3816
- summary.currentUserMessage = conversation.current_user_message ? truncate(conversation.current_user_message, 180) : undefined;
3793
+ const currentUserMessage = conversation.current_user_message ? truncate(conversation.current_user_message, 180) : undefined;
3794
+ summary.currentUserMessage = undefined;
3817
3795
  summary.recentMessages = chronological.length || undefined;
3818
3796
  summary.conversation = cleanContextValue({
3819
3797
  messages: chronological.length,
3820
3798
  userMessages: allUserMessages.length,
3821
- currentUserMessage: summary.currentUserMessage,
3799
+ currentUserMessage,
3822
3800
  lastUser: lastUser ? {
3823
3801
  at: lastUser.at || lastUser.timestamp || lastUser.created_at || lastUser.createdAt,
3824
3802
  preview: truncate(String(lastUser.content || lastUser.text || lastUser.message || ''), 240),
@@ -3829,26 +3807,32 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3829
3807
  } : undefined,
3830
3808
  timeline: compactConversationTimelineForSideChannel(conversation, 16),
3831
3809
  });
3832
- summary.conversationTimeline = compactConversationTimelineForSideChannel(conversation, 16);
3833
3810
  const visibleToolEvents = compactToolEventsForSideChannel(toolItems, SIDE_CHANNEL_TOOL_EVENT_MAX);
3834
3811
  summary.toolCount = toolItems.length || tools.count || parsed.operationalState?.tool_counts?.total || undefined;
3835
- summary.toolNames = toolItems.map((tool) => tool.name || tool.tool_name).filter(Boolean).slice(0, 12);
3836
- summary.toolLog = buildToolLogForSideChannel(visibleToolEvents, toolItems.length || summary.toolCount || visibleToolEvents.length, SIDE_CHANNEL_TOOL_EVENT_MAX);
3837
- summary.toolEvents = visibleToolEvents;
3838
- summary.lastTool = tools.last_successful_tool
3812
+ const toolNames = toolItems.map((tool) => tool.name || tool.tool_name).filter(Boolean).slice(0, 12);
3813
+ const toolLog = buildToolLogForSideChannel(visibleToolEvents, toolItems.length || summary.toolCount || visibleToolEvents.length, SIDE_CHANNEL_TOOL_EVENT_MAX);
3814
+ const lastTool = tools.last_successful_tool
3839
3815
  ? {
3840
3816
  name: tools.last_successful_tool.name,
3841
3817
  at: tools.last_successful_tool.at,
3842
3818
  }
3843
3819
  : (toolItems.length ? { name: toolItems[toolItems.length - 1].name, at: toolItems[toolItems.length - 1].at } : undefined);
3820
+ summary.tools = cleanContextValue({
3821
+ names: toolNames,
3822
+ last: lastTool,
3823
+ log: toolLog,
3824
+ });
3825
+ summary.memory = cleanContextValue({
3826
+ conversation: summary.conversation,
3827
+ });
3844
3828
  summary.turnBrief = typeof parsedTurnBrief === 'string'
3845
3829
  ? cleanContextValue({
3846
3830
  brief: parsedTurnBrief,
3847
3831
  intent: summary.intent,
3848
- currentUserMessage: summary.currentUserMessage,
3832
+ currentUserMessage,
3849
3833
  messages: summary.recentMessages,
3850
3834
  toolCount: summary.toolCount,
3851
- lastTool: summary.lastTool,
3835
+ lastTool,
3852
3836
  })
3853
3837
  : parsedTurnBrief;
3854
3838
  summary.counts = cleanContextValue({
@@ -3862,31 +3846,7 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3862
3846
  recentHighlights: Array.isArray(parsed.recentHighlights) ? parsed.recentHighlights.length : undefined,
3863
3847
  });
3864
3848
  summary.loadedSections = loadedSections;
3865
- summary.agentContextBudget = agentContextBudget;
3866
- summary.slm = cleanContextValue({
3867
- status: slmPreview ? 'available' : 'empty',
3868
- source: summaryStatus.source || (parsed.memory?.slmSummary ? 'slm_summary' : parsed.memory?.activeSummary ? 'active_summary' : 'none'),
3869
- generatedThisLoad: summaryStatus.source === 'fresh_slm',
3870
- activeSummaryLoaded: summaryStatus.activeSummaryLoaded,
3871
- activeSummaryUpdated: summaryStatus.activeSummaryUpdated,
3872
- transientCacheHit: summaryStatus.transientCacheHit,
3873
- chars: summaryStatus.chars || summaryStatus.summaryChars || (slmPreview ? String(slmPreview).length : 0),
3874
- preview: slmPreview ? truncate(String(slmPreview), 500) : undefined,
3875
- });
3876
- summary.memory = cleanContextValue({
3877
- conversation: summary.conversation,
3878
- tools: {
3879
- count: toolItems.length || summary.toolCount || 0,
3880
- names: summary.toolNames,
3881
- last: summary.lastTool,
3882
- log: summary.toolLog,
3883
- },
3884
- compression: parsed.memory?.compression || parsed.memoryCompression,
3885
- referenceFacts: parsed.memory?.referenceFacts,
3886
- canonicalFacts: parsed.canonicalFacts,
3887
- captureHealth: parsed.captureHealth,
3888
- });
3889
- summary.tools = summary.memory?.tools;
3849
+ summary.sentToAgent = agentContextBudget;
3890
3850
  summary.lastSave = Object.keys(lastSave).length ? lastSave : undefined;
3891
3851
  summary.dedupe = fullDedupeSummary ? compactDedupeForSideChannel(fullDedupeSummary) : undefined;
3892
3852
  summary.workingMemory = cleanContextValue({
@@ -3923,6 +3883,10 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3923
3883
  } : undefined),
3924
3884
  });
3925
3885
  summary.quality = parsed.contextHealth?.quality_score || parsed.contextQualityScore || undefined;
3886
+ summary.slm = summaryText ? {
3887
+ status: 'available',
3888
+ preview: truncate(typeof summaryText === 'string' ? summaryText : safeStringify(summaryText), 240),
3889
+ } : undefined;
3926
3890
  summary.debug = includeDebug ? cleanContextValue({
3927
3891
  options: parsed.options,
3928
3892
  loadedSections,
@@ -3931,13 +3895,6 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3931
3895
  dedupeSummary: fullDedupeSummary,
3932
3896
  conversationTimelineFull: compactConversationTimelineForSideChannel(conversation, 12, true),
3933
3897
  }) : undefined;
3934
- delete summary.currentUserMessage;
3935
- delete summary.toolNames;
3936
- delete summary.toolEvents;
3937
- delete summary.toolLog;
3938
- delete summary.lastTool;
3939
- delete summary.agentContextBudget;
3940
- delete summary.conversationTimeline;
3941
3898
  return Object.fromEntries(Object.entries(summary).filter(([, value]) => value !== undefined));
3942
3899
  }
3943
3900
  catch {
@@ -4131,7 +4088,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
4131
4088
  latest_tool: ((decisionState || {}).latest_tool || (operationalState || {}).last_tool || undefined),
4132
4089
  avoid_repeating_tools_unless_needed: ((decisionState || {}).avoid_repeating_tools_unless_needed || []).slice(0, 12),
4133
4090
  do_not_repeat_tools_legacy: ((decisionState || {}).do_not_repeat_tools || []).slice(0, 12),
4134
- instruction: actionDirective || workingMemory.next_expected_action || undefined,
4091
+ instruction: actionDirective || workingMemory.next_expected_action || 'Continue according to the agent prompt.',
4135
4092
  }),
4136
4093
  });
4137
4094
  const audit = {
@@ -4558,18 +4515,18 @@ class TemboryMemory {
4558
4515
  options: [
4559
4516
  { name: 'Custom', value: 'custom' },
4560
4517
  { name: 'Diagnóstico Completo', value: 'diagnostic' },
4561
- { name: 'Produção Rápida (Thread + SLM)', value: 'productionFast' },
4562
- { name: 'Produção Balanceada', value: 'productionBalanced' },
4518
+ { name: 'Produção Balanceada (Recomendado)', value: 'productionBalanced' },
4519
+ { name: 'Produção Rápida (Thread + SLM)', value: 'productionFast' },
4563
4520
  { name: 'Produção Econômica', value: 'productionCheap' },
4564
4521
  { name: 'Produção Nano/SLM', value: 'productionNano' },
4565
4522
  { name: 'Auditoria', value: 'audit' },
4566
4523
  ],
4567
- default: 'productionFast',
4568
- description: 'Preenche defaults seguros para contexto, historico de tools e memoria ativa.',
4569
- },
4524
+ default: 'productionBalanced',
4525
+ description: 'Preenche defaults seguros para contexto, historico de tools e memoria ativa.',
4526
+ },
4570
4527
  { displayName: 'Incluir Cabeçalho de Contexto', name: 'includeContextHeader', type: 'boolean', default: true },
4571
4528
  { displayName: 'Organizar Seções de Produção', name: 'compactStateSections', type: 'boolean', default: true },
4572
- { displayName: 'Máximo de Caracteres do Contexto', name: 'contextMaxChars', type: 'number', default: 10000 },
4529
+ { displayName: 'Máximo de Caracteres do Contexto', name: 'contextMaxChars', type: 'number', default: 20000 },
4573
4530
  { displayName: 'Incluir Tool History', name: 'includeToolHistory', type: 'boolean', default: true },
4574
4531
  { displayName: 'Incluir Resultado Das Tools', name: 'includeToolResults', type: 'boolean', default: true },
4575
4532
  { displayName: 'Incluir Working Memory', name: 'includeWorkingMemory', type: 'boolean', default: true },
@@ -4607,16 +4564,16 @@ class TemboryMemory {
4607
4564
  ],
4608
4565
  default: 'auto',
4609
4566
  },
4610
- { displayName: 'Máximo de Caracteres de Entrada do SLM', name: 'connectedModelSummaryInputMaxChars', type: 'number', default: 4200 },
4611
- { displayName: 'Máximo de Caracteres do Resumo do SLM', name: 'connectedModelSummaryMaxChars', type: 'number', default: 1200 },
4567
+ { displayName: 'Máximo de Caracteres de Entrada do SLM', name: 'connectedModelSummaryInputMaxChars', type: 'number', default: 12000 },
4568
+ { displayName: 'Máximo de Caracteres do Resumo do SLM', name: 'connectedModelSummaryMaxChars', type: 'number', default: 3000 },
4612
4569
  { displayName: 'Incluir Active Summary', name: 'includeActiveSummary', type: 'boolean', default: true },
4613
4570
  { displayName: 'Persistir Active Summary', name: 'persistActiveSummary', type: 'boolean', default: true },
4614
- { displayName: 'Máximo de Caracteres do Active Summary', name: 'activeSummaryMaxChars', type: 'number', default: 1800 },
4571
+ { displayName: 'Máximo de Caracteres do Active Summary', name: 'activeSummaryMaxChars', type: 'number', default: 3500 },
4615
4572
  { displayName: 'Retenção do Active Summary (Dias)', name: 'activeSummaryRetentionDays', type: 'number', default: 30 },
4616
4573
  { displayName: 'Ativar Cache Técnico do Resumo SLM', name: 'enableTransientSummaryCache', type: 'boolean', default: true },
4617
4574
  { displayName: 'TTL do Cache Técnico SLM (Segundos)', name: 'transientSummaryCacheTTLSeconds', type: 'number', default: 300 },
4618
4575
  { displayName: 'Máximo de Itens no Cache Técnico SLM', name: 'transientSummaryCacheMaxItems', type: 'number', default: 50 },
4619
- { displayName: 'Máximo de Fatos no Resumo', name: 'summaryMaxFacts', type: 'number', default: 4 },
4576
+ { displayName: 'Máximo de Fatos no Resumo', name: 'summaryMaxFacts', type: 'number', default: 8 },
4620
4577
  ],
4621
4578
  },
4622
4579
  {
@@ -4625,8 +4582,8 @@ class TemboryMemory {
4625
4582
  values: [
4626
4583
  { displayName: 'Incluir Scores', name: 'includeScores', type: 'boolean', default: false },
4627
4584
  { displayName: 'Incluir Diagnóstico', name: 'includeDiagnostics', type: 'boolean', default: false },
4628
- { displayName: 'Últimas N Tools', name: 'toolHistoryLastN', type: 'number', default: 10 },
4629
- { displayName: 'TTL Das Tools (Segundos)', name: 'toolHistoryTTLSeconds', type: 'number', default: 3600 },
4585
+ { displayName: 'Últimas N Tools Mantidas no Contexto', name: 'toolHistoryLastN', type: 'number', default: 30 },
4586
+ { displayName: 'TTL Das Tools (Segundos)', name: 'toolHistoryTTLSeconds', type: 'number', default: 86400 },
4630
4587
  { displayName: 'Persistir Tool Facts no Backend', name: 'persistToolFactsToTembory', type: 'boolean', default: false },
4631
4588
  { displayName: 'Fallback Semântico Para Tools', name: 'includeToolHistorySemanticFallback', type: 'boolean', default: false },
4632
4589
  ],
@@ -4785,7 +4742,6 @@ class TemboryMemory {
4785
4742
  return { saved: false, input: inputValues, output: outputValues, toolCalls: toolContext };
4786
4743
  }
4787
4744
  async saveContextForItem(itemIndex, inputValues = {}, outputValues = {}) {
4788
- await GenericFunctions_1.assertTemboryCredentials(this);
4789
4745
  const threadId = this.getNodeParameter('threadId', itemIndex);
4790
4746
  const project = this.getNodeParameter('project', itemIndex, '');
4791
4747
  const adv = applyOperationalPreset(readAdvancedOptions(this, itemIndex));
@@ -5282,7 +5238,6 @@ class TemboryMemory {
5282
5238
  }
5283
5239
  async loadMemoryVariablesForItem(itemIndex, inputValues = {}) {
5284
5240
  var _a, _b, _c, _d, _e, _f, _g;
5285
- await GenericFunctions_1.assertTemboryCredentials(this);
5286
5241
  const memoryKey = resolveRuntimeMemoryKey(this, itemIndex);
5287
5242
  const requestedRetrievalMode = this.getNodeParameter('retrievalMode', itemIndex, 'basic');
5288
5243
  let payloadFormat = this.getNodeParameter('payloadFormat', itemIndex, 'structured');
@@ -5922,7 +5877,6 @@ class TemboryMemory {
5922
5877
  return { response };
5923
5878
  }
5924
5879
  async execute() {
5925
- await GenericFunctions_1.assertTemboryCredentials(this);
5926
5880
  const items = this.getInputData();
5927
5881
  const returnData = [];
5928
5882
  const count = Math.max(items.length, 1);
@@ -6039,6 +5993,7 @@ exports.__private = {
6039
5993
  currentInputJsonFromContext,
6040
5994
  resolveCurrentTurnQueryWithSource,
6041
5995
  resolveCurrentTurnQuery,
5996
+ readAdvancedOptions,
6042
5997
  safePersistLegacyMemory,
6043
5998
  stripThreadTestPrefix,
6044
5999
  canonicalToolInput,
@@ -39,8 +39,8 @@ const buildAgentMemoryDescription = () => {
39
39
  const payloadFormat = advancedOnly(cloneProperty(baseProperties, 'payloadFormat'));
40
40
  const advancedGroups = advancedOnly(cloneProperty(baseProperties, 'advancedGroups'));
41
41
  retrievalMode.description = 'Opcional. No v2 recomendado, o Tembory usa contexto operacional estruturado por padrão.';
42
- advancedGroups.displayName = 'Configuração Avançada Tembory';
43
- advancedGroups.description = 'Controles brutos para debug e casos avançados. O uso recomendado já ativa timeline, toolLog, SLM analysis, dedupe e retenção segura.';
42
+ advancedGroups.displayName = 'Ajustes Técnicos Tembory';
43
+ advancedGroups.description = 'Controles brutos para debug e casos avançados. A Memória inteligente já ativa timeline, tool history, tool reuse guard, SLM analysis, dedupe e retenção segura.';
44
44
  return {
45
45
  ...deepClone(base),
46
46
  displayName: 'Tembory Agent Memory',
@@ -63,32 +63,61 @@ const buildAgentMemoryDescription = () => {
63
63
  project,
64
64
  query,
65
65
  {
66
- displayName: 'Context Budget',
66
+ displayName: 'Modo da Memória',
67
+ name: 'operationPreset',
68
+ type: 'options',
69
+ options: [
70
+ {
71
+ name: 'Memória Inteligente (Recomendado)',
72
+ value: 'productionBalanced',
73
+ description: 'Melhor padrão para agentes reais: contexto estruturado, resumo ativo, histórico de tools, evidências e proteção contra repetir ferramentas.',
74
+ },
75
+ {
76
+ name: 'Rápido e Econômico',
77
+ value: 'productionFast',
78
+ description: 'Usa menos contexto. Bom para fluxos simples, mas pode perder parte da inteligência operacional.',
79
+ },
80
+ {
81
+ name: 'Mini/SLM Orientado',
82
+ value: 'productionNano',
83
+ description: 'Compacta o contexto para modelos mini/nano mantendo resumo ativo e histórico de tools.',
84
+ },
85
+ {
86
+ name: 'Auditoria Completa',
87
+ value: 'audit',
88
+ description: 'Mais verboso, com diagnóstico e auditoria. Use para investigação e validação.',
89
+ },
90
+ ],
91
+ default: 'productionBalanced',
92
+ description: 'Escolha como o Tembory prepara o contexto para o agente. O recomendado já vem pronto para usuários leigos.',
93
+ },
94
+ {
95
+ displayName: 'Tamanho do Contexto',
67
96
  name: 'contextMaxChars',
68
97
  type: 'number',
69
98
  default: 20000,
70
- description: 'Máximo aproximado de caracteres do contexto enviado ao agente. No v2 recomendado, isso substitui o toggle avançado equivalente.',
99
+ description: 'Máximo aproximado de caracteres enviados ao agente. O padrão prioriza fluidez sem perder evidências importantes.',
71
100
  },
72
101
  {
73
- displayName: 'Recent Messages',
102
+ displayName: 'Mensagens Recentes',
74
103
  name: 'recentMessagesLastN',
75
104
  type: 'number',
76
- default: 30,
105
+ default: 50,
77
106
  description: 'Quantidade de mensagens recentes consideradas na timeline e no contexto operacional.',
78
107
  },
79
108
  {
80
- displayName: 'Debug Visual Output',
109
+ displayName: 'Mostrar Evidências no Output',
81
110
  name: 'debugVisualOutput',
82
111
  type: 'boolean',
83
112
  default: true,
84
- description: 'Inclui mais material visual e diagnóstico no output de execução. A memória operacional continua preservada independentemente deste valor.',
113
+ description: 'Mostra evidências, tool history e saúde do contexto na execução. Ajuda usuários leigos a entender por que o agente respondeu daquela forma.',
85
114
  },
86
115
  {
87
- displayName: 'Advanced Settings',
116
+ displayName: 'Mostrar Ajustes Técnicos',
88
117
  name: 'showAdvanced',
89
118
  type: 'boolean',
90
119
  default: false,
91
- description: 'Mostra controles brutos de memória, auditoria, TTL e payload. Use apenas para debug ou ajuste fino.',
120
+ description: 'Mostra controles brutos de memória, auditoria, TTL e payload. Normalmente não precisa ativar.',
92
121
  },
93
122
  retrievalMode,
94
123
  memoryKey,
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="iso-8859-1"?>
2
2
  <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
3
- <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
3
+ <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
4
4
  viewBox="0 0 460 460" xml:space="preserve">
5
5
  <g>
6
6
  <path style="fill:#FF926E;" d="M230,203.06h-29.375v50h-31.25v-50H85.04v-30H120V133.1h30v39.96h109.375v50h31.25v-50h84.335v-30
@@ -14,7 +14,7 @@
14
14
  <path style="fill:#FFB76E;" d="M329.01,283.06h-99c0,47.828,33.909,87.729,79,96.979V460h40v-79.961
15
15
  c-6.459,1.325-13.148,2.021-20,2.021V283.06z"/>
16
16
  <rect x="180.04" y="77.06" style="fill:#FFB76E;" width="50" height="30"/>
17
- <polygon style="fill:#FFB76E;" points="150,133.1 120,133.1 120,173.06 85.04,173.06 85.04,203.06 169.375,203.06 169.375,253.06
17
+ <polygon style="fill:#FFB76E;" points="150,133.1 120,133.1 120,173.06 85.04,173.06 85.04,203.06 169.375,203.06 169.375,253.06
18
18
  200.625,253.06 200.625,203.06 230,203.06 230,173.06 150,173.06 "/>
19
19
  <rect x="230.04" y="77.06" style="fill:#FF926E;" width="50" height="30"/>
20
20
  <rect x="363.51" y="223.06" style="fill:#FF926E;" width="30" height="30"/>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "Tembory node for n8n AI Agents with operational memory, tool history and decision state",
5
5
  "license": "MIT",
6
6
  "homepage": "https://tembory.com",