n8n-nodes-tembory 1.1.33 → 1.1.35

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,19 @@
2
2
 
3
3
  Node de memoria operacional da Tembory para agentes de IA no n8n.
4
4
 
5
- Versao atual: `1.1.33`.
5
+ Versao atual: `1.1.35`.
6
+
7
+ ## 1.1.35
8
+
9
+ - Corrige a chave default de memoria do runtime para `chat_history`, que e o placeholder usado pelo AI Agent do n8n.
10
+ - Mantem compatibilidade com `chatHistory`, devolvendo aliases para workflows antigos.
11
+ - Faz o contexto operacional do Tembory entrar no prompt principal do Agent em modo simples.
12
+
13
+ ## 1.1.34
14
+
15
+ - Adiciona `statusAnswerMaterial` no contexto do Agent para perguntas sobre historico operacional.
16
+ - Quando o usuario pergunta quais tools foram chamadas, o Agent recebe um bloco direto com tool count, inputs, outputs, timestamps e action ledger.
17
+ - Instrui explicitamente o Agent a responder desse material e nao dizer que nao tem acesso quando o historico existe.
6
18
 
7
19
  ## 1.1.33
8
20
 
@@ -9,6 +9,7 @@ try {
9
9
  }
10
10
  catch { }
11
11
  const MAX_TEXT = 12000;
12
+ const DEFAULT_MEMORY_KEY = 'chat_history';
12
13
  const nowIso = () => new Date().toISOString();
13
14
  const safeStringify = (value) => {
14
15
  try {
@@ -2609,6 +2610,22 @@ const compactSaveAuditForAgent = (capture = {}) => cleanContextValue({
2609
2610
  dedupe: capture.last_save_dedupe_summary,
2610
2611
  },
2611
2612
  });
2613
+ const buildStatusAnswerMaterialForAgent = ({ query, workingMemory = {}, toolHistory = [], actionLedger = [] }) => {
2614
+ const intent = workingMemory.last_user_intent || inferUserIntent(query, []);
2615
+ if (intent !== 'operational_status_question')
2616
+ return undefined;
2617
+ const toolEvents = pruneByLimit(toolHistory || [], 12).map((tool) => compactToolAuditForSideChannel(tool));
2618
+ const ledgerItems = compactActionLedgerForAgent(actionLedger || [], 12, true);
2619
+ return cleanContextValue({
2620
+ instruction: toolEvents.length
2621
+ ? 'The current user is asking about prior tool calls. Answer directly from this material. Do not call tools. Do not say you lack access to tool history, inputs, outputs, or timestamps.'
2622
+ : 'The current user is asking about prior tool calls, but no prior tool events are available in memory. Answer that no prior tool calls are available in this thread unless the current transcript shows otherwise.',
2623
+ current_user_request: truncate(query, 500),
2624
+ tool_count: toolEvents.length,
2625
+ tool_events: toolEvents,
2626
+ action_ledger: ledgerItems,
2627
+ });
2628
+ };
2612
2629
  const compactEntityTimelineForAgent = (timeline = [], maxItems = 8) => pruneByLimit(timeline || [], maxItems).map((item) => cleanContextValue({
2613
2630
  entity: item.entity || item.source || item.name,
2614
2631
  event: truncate(item.event || item.fact || item.relation || item.kind || item.value, 220),
@@ -2885,6 +2902,7 @@ const loadedSectionsForSideChannel = (parsed = {}, memoryAudit = {}) => cleanCon
2885
2902
  memoryCompression: Boolean(parsed.memoryCompression),
2886
2903
  operationalState: Boolean(parsed.operationalState),
2887
2904
  actionLedger: Array.isArray(parsed.actionLedger),
2905
+ statusAnswerMaterial: Boolean(parsed.statusAnswerMaterial || parsed.status_answer_material),
2888
2906
  turnBrief: Boolean(parsed.turnBrief || parsed.turn_brief),
2889
2907
  memoryAudit: Boolean(memoryAudit && Object.keys(memoryAudit).length),
2890
2908
  entityTimeline: Array.isArray(parsed.entityTimeline),
@@ -2923,6 +2941,7 @@ const agentContextBudgetForSideChannel = (messages = [], parsed = {}) => {
2923
2941
  ['conversation', parsed.conversation],
2924
2942
  ['current_turn_focus', parsed.current_turn_focus || parsed.currentTurn || parsed.current_turn],
2925
2943
  ['action_directive', parsed.action_directive],
2944
+ ['status_answer_material', parsed.statusAnswerMaterial || parsed.status_answer_material],
2926
2945
  ['turn_brief', parsed.turnBrief || parsed.turn_brief],
2927
2946
  ['summary', parsed.summary],
2928
2947
  ['working_memory', parsed.workingMemory || parsed.working_memory],
@@ -3095,7 +3114,7 @@ const wrapTemboryMemory = (memory, ctx, memoryKey, itemIndex = 0) => new Proxy(m
3095
3114
  ]);
3096
3115
  try {
3097
3116
  const response = await target.loadMemoryVariables(values);
3098
- const memoryMessages = response[memoryKey] || response.chatHistory || [];
3117
+ const memoryMessages = response[memoryKey] || response.chat_history || response.chatHistory || [];
3099
3118
  const messages = Array.isArray(memoryMessages) ? memoryMessages.length : 0;
3100
3119
  ctx.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, [
3101
3120
  [{
@@ -3174,6 +3193,14 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
3174
3193
  title: 'Turn brief',
3175
3194
  value: turnBrief,
3176
3195
  });
3196
+ const statusAnswerMaterial = buildStatusAnswerMaterialForAgent({ query, workingMemory, toolHistory, actionLedger });
3197
+ if (statusAnswerMaterial) {
3198
+ sections.push({
3199
+ section: 'status_answer_material',
3200
+ title: 'Status answer material',
3201
+ value: statusAnswerMaterial,
3202
+ });
3203
+ }
3177
3204
  const actionDirective = buildActionDirective({ workingMemory, operationalState });
3178
3205
  if (actionDirective) {
3179
3206
  sections.push({
@@ -3289,6 +3316,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
3289
3316
  instruction: focus.instruction,
3290
3317
  }),
3291
3318
  currentTurn: diagnostics?.currentTurn,
3319
+ statusAnswerMaterial: sectionValue('status_answer_material'),
3292
3320
  action_directive: directive ? cleanContextValue({
3293
3321
  required_tool: directive.required_tool,
3294
3322
  next_expected_action: directive.next_expected_action,
@@ -3737,7 +3765,7 @@ class TemboryMemory {
3737
3765
  // For AI connections, n8n reads from supplyData. The AI Agent expects a
3738
3766
  // memory-like object, not raw JSON, so expose the LangChain memory contract.
3739
3767
  async supplyData(itemIndex) {
3740
- const memoryKey = this.getNodeParameter('memoryKey', itemIndex, 'chatHistory');
3768
+ const memoryKey = this.getNodeParameter('memoryKey', itemIndex, DEFAULT_MEMORY_KEY);
3741
3769
  let currentMessages = [];
3742
3770
  const loadCache = new Map();
3743
3771
  const recordMemoryEvent = (action, payload = {}, error) => {
@@ -3753,7 +3781,7 @@ class TemboryMemory {
3753
3781
  ]);
3754
3782
  };
3755
3783
  const memory = {
3756
- memoryKeys: [memoryKey],
3784
+ memoryKeys: Array.from(new Set([memoryKey, DEFAULT_MEMORY_KEY])),
3757
3785
  inputKey: 'input',
3758
3786
  outputKey: 'output',
3759
3787
  returnMessages: true,
@@ -3800,11 +3828,18 @@ class TemboryMemory {
3800
3828
  loadCache.delete(firstKey);
3801
3829
  }
3802
3830
  }
3803
- const chatHistory = (result.response[memoryKey] || []).map(toBaseMessage);
3831
+ const chatHistory = (result.response[memoryKey] || result.response.chat_history || result.response.chatHistory || []).map(toBaseMessage);
3804
3832
  currentMessages = chatHistory;
3805
3833
  const variables = {
3806
3834
  [memoryKey]: chatHistory,
3807
3835
  };
3836
+ if (memoryKey !== DEFAULT_MEMORY_KEY) {
3837
+ Object.defineProperty(variables, DEFAULT_MEMORY_KEY, {
3838
+ value: chatHistory,
3839
+ enumerable: true,
3840
+ configurable: true,
3841
+ });
3842
+ }
3808
3843
  if (memoryKey !== 'chatHistory') {
3809
3844
  Object.defineProperty(variables, 'chatHistory', {
3810
3845
  value: chatHistory,
@@ -4354,7 +4389,7 @@ class TemboryMemory {
4354
4389
  }
4355
4390
  async loadMemoryVariablesForItem(itemIndex, inputValues = {}) {
4356
4391
  var _a, _b, _c, _d, _e, _f, _g;
4357
- const memoryKey = this.getNodeParameter('memoryKey', itemIndex, 'chatHistory');
4392
+ const memoryKey = this.getNodeParameter('memoryKey', itemIndex, DEFAULT_MEMORY_KEY);
4358
4393
  const requestedRetrievalMode = this.getNodeParameter('retrievalMode', itemIndex, 'basic');
4359
4394
  let payloadFormat = this.getNodeParameter('payloadFormat', itemIndex, 'structured');
4360
4395
  const threadId = this.getNodeParameter('threadId', itemIndex);
@@ -4987,6 +5022,7 @@ class TemboryMemory {
4987
5022
  return {
4988
5023
  response: {
4989
5024
  [memoryKey]: payload,
5025
+ chat_history: payload,
4990
5026
  chatHistory: payload,
4991
5027
  },
4992
5028
  };
@@ -4996,7 +5032,7 @@ class TemboryMemory {
4996
5032
  const returnData = [];
4997
5033
  const count = Math.max(items.length, 1);
4998
5034
  for (let i = 0; i < count; i++) {
4999
- const memoryKey = this.getNodeParameter('memoryKey', i, 'chatHistory');
5035
+ const memoryKey = this.getNodeParameter('memoryKey', i, DEFAULT_MEMORY_KEY);
5000
5036
  const requestedRetrievalMode = this.getNodeParameter('retrievalMode', i, 'basic');
5001
5037
  const threadId = this.getNodeParameter('threadId', i);
5002
5038
  const project = this.getNodeParameter('project', i, '');
@@ -5061,6 +5097,8 @@ class TemboryMemory {
5061
5097
  }
5062
5098
  const json = {};
5063
5099
  json[memoryKey] = payload;
5100
+ json.chat_history = payload;
5101
+ json.chatHistory = payload;
5064
5102
  returnData.push({ json });
5065
5103
  }
5066
5104
  return [returnData];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.1.33",
3
+ "version": "1.1.35",
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",