n8n-nodes-tembory 1.3.4 → 1.3.5

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,14 @@
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.5`.
6
+
7
+ ## 1.3.5
8
+
9
+ - Atualiza o `Tembory Agent Memory` para usuarios leigos: o padrao agora e `Modo da Memoria -> Memoria Inteligente (Recomendado)`.
10
+ - 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.
11
+ - Renomeia campos visiveis para linguagem operacional: `Tamanho do Contexto`, `Mensagens Recentes`, `Mostrar Evidencias no Output` e `Mostrar Ajustes Tecnicos`.
12
+ - Mantem os controles brutos escondidos em `Ajustes Tecnicos Tembory`, para debug e casos avancados, sem tornar isso obrigatorio para o usuario comum.
6
13
 
7
14
  ## 1.3.4
8
15
 
@@ -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 = {
@@ -1648,6 +1648,7 @@ const readAdvancedOptions = (ctx, itemIndex) => {
1648
1648
  };
1649
1649
  readTopLevelOverride('contextMaxChars');
1650
1650
  readTopLevelOverride('recentMessagesLastN');
1651
+ readTopLevelOverride('operationPreset');
1651
1652
  try {
1652
1653
  const debugVisualOutput = ctx.getNodeParameter('debugVisualOutput', itemIndex, undefined);
1653
1654
  if (debugVisualOutput !== undefined) {
@@ -2054,7 +2055,7 @@ const turnBriefGuidanceForIntent = (intent = '') => {
2054
2055
  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
2056
  if (intent === 'profile_update')
2056
2057
  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.';
2058
+ return 'Continue according to the agent prompt using conversation, tool history and operational state as read-only context.';
2058
2059
  };
2059
2060
  const buildTurnBriefForAgent = ({ query = '', recentMessages = [], toolHistory = [], operationalState = {}, workingMemory = {}, decisionState = {}, diagnostics = {} }) => {
2060
2061
  const currentIntent = (decisionState || {}).current_intent || (workingMemory || {}).last_user_intent || inferUserIntent(query, recentMessages);
@@ -2182,7 +2183,7 @@ const inferUserIntent = (query = '', recentMessages = []) => {
2182
2183
  };
2183
2184
  const deriveNextExpectedAction = (intent, operationalState = {}) => {
2184
2185
  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';
2186
+ 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
2187
  if (intent === 'profile_update')
2187
2188
  return 'save stable profile facts and continue the conversation';
2188
2189
  if (intent === 'conversation_recall')
@@ -2191,7 +2192,7 @@ const deriveNextExpectedAction = (intent, operationalState = {}) => {
2191
2192
  return 'answer status questions from tool_state, tool_history and action_ledger; do not call tools unless the agent prompt requires it';
2192
2193
  return undefined;
2193
2194
  };
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 || ''));
2195
+ 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
2196
  const shouldCarryPreviousGoal = (intent = '', previousGoal = '') => {
2196
2197
  if (!previousGoal || isGenericMemoryNextAction(previousGoal))
2197
2198
  return false;
@@ -3231,14 +3232,6 @@ const buildAgentContextV2 = ({ query = '', userId = '', payloadFormat = 'structu
3231
3232
  memory: cleanContextValue({
3232
3233
  slmSummary: connectedModelSummary ? truncate(connectedModelSummary, Number(adv.connectedModelSummaryMaxChars || 900)) : undefined,
3233
3234
  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
3235
  referenceFacts,
3243
3236
  compression: adv.includeMemoryCompression === false ? undefined : compactMemoryCompressionForAgent(memoryCompression || {}),
3244
3237
  }),
@@ -3360,7 +3353,7 @@ const invokeConnectedModelSummary = async (connectedLanguageModel, summaryInput,
3360
3353
  const response = await connectedLanguageModel.invoke([
3361
3354
  toBaseMessage({
3362
3355
  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}`,
3356
+ 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
3357
  }),
3365
3358
  ]);
3366
3359
  return cleanModelSummaryText(response, Number(adv.connectedModelSummaryMaxChars || 1200));
@@ -3548,15 +3541,13 @@ const summarizeSaveContextForSideChannel = (input = {}, output = {}, chatHistory
3548
3541
  const toolEvents = compactToolEventsForSideChannel(toolCalls, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX);
3549
3542
  const conversation = conversationDigestFromMessagesForSideChannel(chatHistory);
3550
3543
  const timeline = conversationTimelineFromMessagesForSideChannel(chatHistory, 16);
3544
+ const toolLog = buildToolLogForSideChannel(toolEvents, toolCalls.length, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX);
3551
3545
  return cleanContextValue({
3552
3546
  visualSchema: VISUAL_SCHEMA_VERSION,
3553
- summary: cleanContextValue({
3554
- action: 'saveContext',
3547
+ summary: {
3555
3548
  messagesAfterSave: Array.isArray(chatHistory) ? chatHistory.length : 0,
3556
- userInputPreview: inputMessage ? truncate(String(inputMessage), 220) : undefined,
3557
- assistantOutputPreview: outputMessage ? truncate(String(outputMessage), 260) : undefined,
3558
3549
  toolCallsCaptured: toolCalls.length,
3559
- }),
3550
+ },
3560
3551
  conversation: cleanContextValue({
3561
3552
  ...conversation,
3562
3553
  timeline,
@@ -3568,11 +3559,7 @@ const summarizeSaveContextForSideChannel = (input = {}, output = {}, chatHistory
3568
3559
  tools: cleanContextValue({
3569
3560
  captured: toolCalls.length,
3570
3561
  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',
3562
+ log: toolLog,
3576
3563
  }),
3577
3564
  });
3578
3565
  };
@@ -3597,14 +3584,12 @@ const compactMemoryEventPayload = (payload = {}) => {
3597
3584
  compact[`${key}Chars`] = typeof compact[key] === 'string' ? compact[key].length : safeStringify(compact[key]).length;
3598
3585
  delete compact[key];
3599
3586
  }
3600
- return keepVisibleToolLogArrays(compact);
3587
+ return compact;
3601
3588
  };
3602
3589
  const compactVisualSummaryForMode = (summary = {}, configurationMode = 'advanced') => {
3603
3590
  const compact = { ...(summary || {}) };
3604
3591
  if (String(configurationMode || 'advanced') !== 'simple')
3605
3592
  return compact;
3606
- delete compact.toolNames;
3607
- delete compact.toolEvents;
3608
3593
  delete compact.savedMessages;
3609
3594
  return compact;
3610
3595
  };
@@ -3792,20 +3777,10 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3792
3777
  toolCallsCaptured: parsed.captureHealth?.toolCallsCapturedLastSave,
3793
3778
  captureSources: parsed.captureHealth?.captureSources,
3794
3779
  } : {}));
3795
- const summaryStatus = parsed.memory?.summaryStatus || parsed.diagnostics?.activeSummary || {};
3796
- const slmPreview = parsed.memory?.slmSummary || parsed.memory?.activeSummary || summaryText || '';
3797
3780
  const fullDedupeSummary = parsed.dedupeSummary || parsed.diagnostics?.dedupeSummary || undefined;
3798
3781
  const loadedSections = loadedSectionsForSideChannel(parsed, memoryAudit);
3799
3782
  const agentContextBudget = agentContextBudgetForSideChannel(list, parsed);
3800
3783
  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
3784
  summary.userId = parsed.userId;
3810
3785
  summary.project = parsed.project || undefined;
3811
3786
  summary.retrievalMode = parsed.retrievalMode;
@@ -3813,12 +3788,13 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3813
3788
  summary.intent = parsed.currentTurn?.intentHint || parsed.observations?.inferred_intent?.label || parsed.workingMemory?.last_user_intent || parsed.decisionState?.current_intent || undefined;
3814
3789
  const parsedTurnBrief = parsed.turnBrief || parsed.turn_brief || undefined;
3815
3790
  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;
3791
+ const currentUserMessage = conversation.current_user_message ? truncate(conversation.current_user_message, 180) : undefined;
3792
+ summary.currentUserMessage = undefined;
3817
3793
  summary.recentMessages = chronological.length || undefined;
3818
3794
  summary.conversation = cleanContextValue({
3819
3795
  messages: chronological.length,
3820
3796
  userMessages: allUserMessages.length,
3821
- currentUserMessage: summary.currentUserMessage,
3797
+ currentUserMessage,
3822
3798
  lastUser: lastUser ? {
3823
3799
  at: lastUser.at || lastUser.timestamp || lastUser.created_at || lastUser.createdAt,
3824
3800
  preview: truncate(String(lastUser.content || lastUser.text || lastUser.message || ''), 240),
@@ -3829,26 +3805,32 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3829
3805
  } : undefined,
3830
3806
  timeline: compactConversationTimelineForSideChannel(conversation, 16),
3831
3807
  });
3832
- summary.conversationTimeline = compactConversationTimelineForSideChannel(conversation, 16);
3833
3808
  const visibleToolEvents = compactToolEventsForSideChannel(toolItems, SIDE_CHANNEL_TOOL_EVENT_MAX);
3834
3809
  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
3810
+ const toolNames = toolItems.map((tool) => tool.name || tool.tool_name).filter(Boolean).slice(0, 12);
3811
+ const toolLog = buildToolLogForSideChannel(visibleToolEvents, toolItems.length || summary.toolCount || visibleToolEvents.length, SIDE_CHANNEL_TOOL_EVENT_MAX);
3812
+ const lastTool = tools.last_successful_tool
3839
3813
  ? {
3840
3814
  name: tools.last_successful_tool.name,
3841
3815
  at: tools.last_successful_tool.at,
3842
3816
  }
3843
3817
  : (toolItems.length ? { name: toolItems[toolItems.length - 1].name, at: toolItems[toolItems.length - 1].at } : undefined);
3818
+ summary.tools = cleanContextValue({
3819
+ names: toolNames,
3820
+ last: lastTool,
3821
+ log: toolLog,
3822
+ });
3823
+ summary.memory = cleanContextValue({
3824
+ conversation: summary.conversation,
3825
+ });
3844
3826
  summary.turnBrief = typeof parsedTurnBrief === 'string'
3845
3827
  ? cleanContextValue({
3846
3828
  brief: parsedTurnBrief,
3847
3829
  intent: summary.intent,
3848
- currentUserMessage: summary.currentUserMessage,
3830
+ currentUserMessage,
3849
3831
  messages: summary.recentMessages,
3850
3832
  toolCount: summary.toolCount,
3851
- lastTool: summary.lastTool,
3833
+ lastTool,
3852
3834
  })
3853
3835
  : parsedTurnBrief;
3854
3836
  summary.counts = cleanContextValue({
@@ -3862,31 +3844,7 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3862
3844
  recentHighlights: Array.isArray(parsed.recentHighlights) ? parsed.recentHighlights.length : undefined,
3863
3845
  });
3864
3846
  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;
3847
+ summary.sentToAgent = agentContextBudget;
3890
3848
  summary.lastSave = Object.keys(lastSave).length ? lastSave : undefined;
3891
3849
  summary.dedupe = fullDedupeSummary ? compactDedupeForSideChannel(fullDedupeSummary) : undefined;
3892
3850
  summary.workingMemory = cleanContextValue({
@@ -3923,6 +3881,10 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3923
3881
  } : undefined),
3924
3882
  });
3925
3883
  summary.quality = parsed.contextHealth?.quality_score || parsed.contextQualityScore || undefined;
3884
+ summary.slm = summaryText ? {
3885
+ status: 'available',
3886
+ preview: truncate(typeof summaryText === 'string' ? summaryText : safeStringify(summaryText), 240),
3887
+ } : undefined;
3926
3888
  summary.debug = includeDebug ? cleanContextValue({
3927
3889
  options: parsed.options,
3928
3890
  loadedSections,
@@ -3931,13 +3893,6 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3931
3893
  dedupeSummary: fullDedupeSummary,
3932
3894
  conversationTimelineFull: compactConversationTimelineForSideChannel(conversation, 12, true),
3933
3895
  }) : 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
3896
  return Object.fromEntries(Object.entries(summary).filter(([, value]) => value !== undefined));
3942
3897
  }
3943
3898
  catch {
@@ -4131,7 +4086,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
4131
4086
  latest_tool: ((decisionState || {}).latest_tool || (operationalState || {}).last_tool || undefined),
4132
4087
  avoid_repeating_tools_unless_needed: ((decisionState || {}).avoid_repeating_tools_unless_needed || []).slice(0, 12),
4133
4088
  do_not_repeat_tools_legacy: ((decisionState || {}).do_not_repeat_tools || []).slice(0, 12),
4134
- instruction: actionDirective || workingMemory.next_expected_action || undefined,
4089
+ instruction: actionDirective || workingMemory.next_expected_action || 'Continue according to the agent prompt.',
4135
4090
  }),
4136
4091
  });
4137
4092
  const audit = {
@@ -4785,7 +4740,6 @@ class TemboryMemory {
4785
4740
  return { saved: false, input: inputValues, output: outputValues, toolCalls: toolContext };
4786
4741
  }
4787
4742
  async saveContextForItem(itemIndex, inputValues = {}, outputValues = {}) {
4788
- await GenericFunctions_1.assertTemboryCredentials(this);
4789
4743
  const threadId = this.getNodeParameter('threadId', itemIndex);
4790
4744
  const project = this.getNodeParameter('project', itemIndex, '');
4791
4745
  const adv = applyOperationalPreset(readAdvancedOptions(this, itemIndex));
@@ -5282,7 +5236,6 @@ class TemboryMemory {
5282
5236
  }
5283
5237
  async loadMemoryVariablesForItem(itemIndex, inputValues = {}) {
5284
5238
  var _a, _b, _c, _d, _e, _f, _g;
5285
- await GenericFunctions_1.assertTemboryCredentials(this);
5286
5239
  const memoryKey = resolveRuntimeMemoryKey(this, itemIndex);
5287
5240
  const requestedRetrievalMode = this.getNodeParameter('retrievalMode', itemIndex, 'basic');
5288
5241
  let payloadFormat = this.getNodeParameter('payloadFormat', itemIndex, 'structured');
@@ -5922,7 +5875,6 @@ class TemboryMemory {
5922
5875
  return { response };
5923
5876
  }
5924
5877
  async execute() {
5925
- await GenericFunctions_1.assertTemboryCredentials(this);
5926
5878
  const items = this.getInputData();
5927
5879
  const returnData = [];
5928
5880
  const count = Math.max(items.length, 1);
@@ -6039,6 +5991,7 @@ exports.__private = {
6039
5991
  currentInputJsonFromContext,
6040
5992
  resolveCurrentTurnQueryWithSource,
6041
5993
  resolveCurrentTurnQuery,
5994
+ readAdvancedOptions,
6042
5995
  safePersistLegacyMemory,
6043
5996
  stripThreadTestPrefix,
6044
5997
  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.5",
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",