n8n-nodes-tembory 1.1.40 → 1.1.42

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.40`.
5
+ Versao atual: `1.1.42`.
6
+
7
+ ## 1.1.42
8
+
9
+ - Explicita `conversation` e `conversationTimeline` tambem no payload visual de `saveContext`.
10
+ - Aumenta a timeline visual de conversa do `loadMemoryVariables` para ate 16 mensagens recentes.
11
+ - Parseia resultados de tools de busca vetorial em `outputParsed.documents`, preservando `pageContent`, `metadata`, `id`, `source` e `score` quando existirem.
12
+
13
+ ## 1.1.41
14
+
15
+ - Padroniza a saida visual do node com `visualSchema`, `memorySummary` e `toolLog` tanto no `loadMemoryVariables` quanto no `saveContext`.
16
+ - Mantem `toolEvents` para compatibilidade, mas agora tambem mostra `inputParsed`, `outputParsed`, timestamps e `facts` com IDs operacionais quando existirem.
17
+ - Aumenta a visibilidade do historico recente de tools no resumo visual para evitar esconder eventos importantes no debug humano.
6
18
 
7
19
  ## 1.1.40
8
20
 
@@ -2680,9 +2680,44 @@ const extractToolOperationalFacts = (tool = {}) => {
2680
2680
  const facts = mergeOperationalFactObjects(outputFacts, inputFacts);
2681
2681
  return Object.keys(facts || {}).length ? facts : undefined;
2682
2682
  };
2683
+ const compactVectorDocumentForSideChannel = (value) => {
2684
+ const original = value;
2685
+ let parsed = value;
2686
+ if (typeof parsed === 'string')
2687
+ parsed = tryParseJsonValue(parsed) || parsed;
2688
+ if (parsed && typeof parsed === 'object' && typeof parsed.text === 'string') {
2689
+ const textParsed = tryParseJsonValue(parsed.text);
2690
+ if (textParsed && typeof textParsed === 'object')
2691
+ parsed = { ...parsed, ...textParsed };
2692
+ }
2693
+ if (!parsed || typeof parsed !== 'object')
2694
+ return undefined;
2695
+ const pageContent = parsed.pageContent || parsed.content || parsed.document || (original && original.type === 'text' ? parsed.text : undefined);
2696
+ const rawMetadata = parsed.metadata && typeof parsed.metadata === 'object' ? parsed.metadata : undefined;
2697
+ const metadata = rawMetadata ? stripNoisyToolFields(rawMetadata) : undefined;
2698
+ if (!pageContent && !metadata)
2699
+ return undefined;
2700
+ return cleanContextValue({
2701
+ pageContent: pageContent ? truncate(String(pageContent), 1200) : undefined,
2702
+ metadata,
2703
+ id: parsed.id || metadata?.id,
2704
+ source: parsed.source || rawMetadata?.source,
2705
+ score: parsed.score || metadata?.score,
2706
+ });
2707
+ };
2708
+ const compactVectorDocumentsForSideChannel = (value) => {
2709
+ const items = Array.isArray(value) ? value : [value];
2710
+ return items
2711
+ .map((item) => compactVectorDocumentForSideChannel(item))
2712
+ .filter((item) => item && Object.keys(item).length)
2713
+ .slice(0, 8);
2714
+ };
2683
2715
  const compactParsedToolOutputForSideChannel = (parsed) => {
2684
2716
  if (parsed === undefined || parsed === null)
2685
2717
  return undefined;
2718
+ const vectorDocuments = compactVectorDocumentsForSideChannel(parsed);
2719
+ if (vectorDocuments.length)
2720
+ return cleanContextValue({ documents: vectorDocuments, count: vectorDocuments.length });
2686
2721
  if (Array.isArray(parsed))
2687
2722
  return cleanContextValue(parsed.map((item) => compactParsedToolOutputForSideChannel(item)));
2688
2723
  if (typeof parsed !== 'object')
@@ -3006,6 +3041,16 @@ const invokeConnectedModelSummary = async (connectedLanguageModel, summaryInput,
3006
3041
  ]);
3007
3042
  return cleanModelSummaryText(response, Number(adv.connectedModelSummaryMaxChars || 1200));
3008
3043
  };
3044
+ const VISUAL_SCHEMA_VERSION = 'tembory.visual.v1';
3045
+ const TOOL_LOG_VISUAL_SCHEMA_VERSION = 'tembory.visual.v1.toolLog';
3046
+ const SIDE_CHANNEL_TOOL_EVENT_MAX = 12;
3047
+ const SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX = 20;
3048
+ const compactParsedToolInputForSideChannel = (input) => {
3049
+ const parsed = safeParseToolPayload(input);
3050
+ if (!parsed || typeof parsed !== 'object')
3051
+ return undefined;
3052
+ return cleanContextValue(stripNoisyToolFields(parsed));
3053
+ };
3009
3054
  const compactToolAuditForSideChannel = (tool = {}) => {
3010
3055
  const capturedAt = tool.at || tool.timestamp;
3011
3056
  const rawResult = tool.result !== undefined ? tool.result : tool.output !== undefined ? tool.output : tool.observation;
@@ -3019,10 +3064,36 @@ const compactToolAuditForSideChannel = (tool = {}) => {
3019
3064
  toolTimestamp: toolResultTimestampFromParsed(parsedResult),
3020
3065
  toolStatus: parsedResult && typeof parsedResult === 'object' && !Array.isArray(parsedResult) ? parsedResult.status : undefined,
3021
3066
  input: truncate(String(tool.input || tool.tool_args || tool.normalized_args || ''), 300) || undefined,
3067
+ inputParsed: compactParsedToolInputForSideChannel(tool.input || tool.tool_args || tool.normalized_args),
3022
3068
  output: compactToolResult(rawResult, 800),
3023
3069
  outputParsed: compactParsedToolOutputForSideChannel(parsedResult),
3070
+ facts: extractToolOperationalFacts(tool),
3024
3071
  });
3025
3072
  };
3073
+ const compactToolEventsForSideChannel = (toolItems = [], maxItems = SIDE_CHANNEL_TOOL_EVENT_MAX) => pruneByLimit(toolItems || [], maxItems)
3074
+ .map((tool) => compactToolAuditForSideChannel(tool || {}))
3075
+ .filter((tool) => tool && Object.keys(tool).length);
3076
+ const buildToolLogForSideChannel = (toolEvents = [], totalCount, maxItems = SIDE_CHANNEL_TOOL_EVENT_MAX) => {
3077
+ const events = Array.isArray(toolEvents) ? toolEvents : [];
3078
+ const count = typeof totalCount === 'number' ? totalCount : events.length;
3079
+ return {
3080
+ schema: TOOL_LOG_VISUAL_SCHEMA_VERSION,
3081
+ count,
3082
+ names: events.map((tool) => tool.name).filter(Boolean).slice(0, maxItems),
3083
+ events,
3084
+ truncated: count > events.length,
3085
+ maxEvents: maxItems,
3086
+ };
3087
+ };
3088
+ const keepVisibleToolLogArrays = (payload = {}) => {
3089
+ if (payload.toolLog) {
3090
+ if (!Array.isArray(payload.toolLog.names))
3091
+ payload.toolLog.names = [];
3092
+ if (!Array.isArray(payload.toolLog.events))
3093
+ payload.toolLog.events = [];
3094
+ }
3095
+ return payload;
3096
+ };
3026
3097
  const compactMessageForSideChannel = (message = {}) => {
3027
3098
  const type = messageTypeOf(message) || String(message.role || 'message').toLowerCase();
3028
3099
  const role = type === 'human' ? 'user' : type === 'ai' ? 'assistant' : type || 'message';
@@ -3045,17 +3116,19 @@ const normalizeConversationRoleForSideChannel = (role = '') => {
3045
3116
  return 'tool';
3046
3117
  return normalized || 'message';
3047
3118
  };
3048
- const compactConversationTimelineForSideChannel = (conversation = {}, maxItems = 4, includeFull = false) => {
3119
+ const compactConversationTimelineForSideChannel = (conversation = {}, maxItems = 16, includeFull = false) => {
3049
3120
  const chronological = Array.isArray(conversation.conversation_history_chronological)
3050
3121
  ? conversation.conversation_history_chronological
3051
3122
  : [];
3052
- return pruneByLimit(chronological, maxItems).map((message, index) => {
3123
+ const visible = pruneByLimit(chronological, maxItems);
3124
+ const offset = Math.max(0, chronological.length - visible.length);
3125
+ return visible.map((message, index) => {
3053
3126
  const role = normalizeConversationRoleForSideChannel(message.role || message.type);
3054
3127
  const content = String(message.content || message.text || message.message || '');
3055
3128
  const at = message.at || message.timestamp || message.created_at || message.createdAt;
3056
3129
  const preview = role === 'system' ? '[system context hidden]' : truncate(content, 180);
3057
3130
  return cleanContextValue({
3058
- index,
3131
+ index: offset + index,
3059
3132
  role,
3060
3133
  speaker: role,
3061
3134
  at,
@@ -3070,24 +3143,70 @@ const compactConversationTimelineForSideChannel = (conversation = {}, maxItems =
3070
3143
  });
3071
3144
  });
3072
3145
  };
3146
+ const conversationEntriesFromMessagesForSideChannel = (messages = []) => (Array.isArray(messages) ? messages : [])
3147
+ .map((message) => {
3148
+ const type = messageTypeOf(message) || String(message.role || 'message').toLowerCase();
3149
+ const role = type === 'human' || type === 'user' ? 'user' : type === 'ai' || type === 'assistant' ? 'agent' : type === 'tool' ? 'tool' : type === 'system' ? 'system' : 'message';
3150
+ const content = messageContentOf(message);
3151
+ return {
3152
+ role,
3153
+ speaker: role,
3154
+ at: message.at || message.timestamp || message.created_at || message.createdAt,
3155
+ content,
3156
+ };
3157
+ })
3158
+ .filter((message) => message.role !== 'system' && message.content);
3159
+ const conversationDigestFromMessagesForSideChannel = (messages = []) => {
3160
+ const entries = conversationEntriesFromMessagesForSideChannel(messages);
3161
+ const lastUser = [...entries].reverse().find((message) => message.role === 'user');
3162
+ const lastAgent = [...entries].reverse().find((message) => message.role === 'agent');
3163
+ return cleanContextValue({
3164
+ messages: entries.length,
3165
+ userMessages: entries.filter((message) => message.role === 'user').length,
3166
+ assistantMessages: entries.filter((message) => message.role === 'agent').length,
3167
+ lastUser: lastUser ? {
3168
+ at: lastUser.at,
3169
+ preview: truncate(lastUser.content, 240),
3170
+ } : undefined,
3171
+ lastAgent: lastAgent ? {
3172
+ at: lastAgent.at,
3173
+ preview: truncate(lastAgent.content, 240),
3174
+ } : undefined,
3175
+ });
3176
+ };
3177
+ const conversationTimelineFromMessagesForSideChannel = (messages = [], maxItems = 16) => {
3178
+ const entries = conversationEntriesFromMessagesForSideChannel(messages);
3179
+ const visible = pruneByLimit(entries, maxItems);
3180
+ const offset = Math.max(0, entries.length - visible.length);
3181
+ return visible.map((message, index) => cleanContextValue({
3182
+ index: offset + index,
3183
+ role: message.role,
3184
+ speaker: message.speaker,
3185
+ at: message.at,
3186
+ chars: message.content.length,
3187
+ preview: truncate(message.content, 180),
3188
+ }));
3189
+ };
3073
3190
  const summarizeSaveContextForSideChannel = (input = {}, output = {}, chatHistory = []) => {
3074
3191
  const inputMessage = input?.input || input?.chatInput || input?.query || input?.question || input?.text || input?.message || '';
3075
3192
  const outputMessage = output?.output || output?.response || output?.text || output?.message || output?.answer || '';
3076
- const toolEvents = extractToolCalls(output || {})
3077
- .map((tool) => compactToolAuditForSideChannel(tool || {}))
3078
- .filter((tool) => tool && Object.keys(tool).length)
3079
- .slice(0, 20);
3080
- return cleanContextValue({
3193
+ const toolCalls = extractToolCalls(output || {});
3194
+ const toolEvents = compactToolEventsForSideChannel(toolCalls, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX);
3195
+ return keepVisibleToolLogArrays(cleanContextValue({
3196
+ visualSchema: VISUAL_SCHEMA_VERSION,
3081
3197
  messagesAfterSave: Array.isArray(chatHistory) ? chatHistory.length : 0,
3198
+ conversation: conversationDigestFromMessagesForSideChannel(chatHistory),
3199
+ conversationTimeline: conversationTimelineFromMessagesForSideChannel(chatHistory, 16),
3082
3200
  savedMessages: Array.isArray(chatHistory)
3083
3201
  ? chatHistory.slice(-6).map((message) => compactMessageForSideChannel(message))
3084
3202
  : undefined,
3085
3203
  userInput: inputMessage ? truncate(String(inputMessage), 500) : undefined,
3086
3204
  assistantOutput: outputMessage ? truncate(String(outputMessage), 700) : undefined,
3087
- toolCallsCaptured: toolEvents.length || undefined,
3205
+ toolCallsCaptured: toolCalls.length,
3088
3206
  toolNames: toolEvents.map((tool) => tool.name).filter(Boolean),
3207
+ toolLog: buildToolLogForSideChannel(toolEvents, toolCalls.length, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX),
3089
3208
  toolEvents,
3090
- });
3209
+ }));
3091
3210
  };
3092
3211
  const compactMemoryEventPayload = (payload = {}) => {
3093
3212
  const compact = { ...(payload || {}) };
@@ -3097,18 +3216,20 @@ const compactMemoryEventPayload = (payload = {}) => {
3097
3216
  .map((tool) => (tool && (tool.name || tool.tool_name || tool.tool)) || '')
3098
3217
  .filter(Boolean)
3099
3218
  .slice(0, 12);
3100
- compact.toolEvents = compact.toolCalls
3101
- .map((tool) => compactToolAuditForSideChannel(tool || {}))
3102
- .filter((tool) => tool && Object.keys(tool).length)
3103
- .slice(0, 8);
3219
+ compact.toolEvents = compactToolEventsForSideChannel(compact.toolCalls, SIDE_CHANNEL_TOOL_EVENT_MAX);
3220
+ compact.toolLog = buildToolLogForSideChannel(compact.toolEvents, compact.toolCalls.length, SIDE_CHANNEL_TOOL_EVENT_MAX);
3104
3221
  delete compact.toolCalls;
3105
3222
  }
3223
+ if (!compact.visualSchema)
3224
+ compact.visualSchema = VISUAL_SCHEMA_VERSION;
3225
+ if (Array.isArray(compact.toolEvents) && !compact.toolLog)
3226
+ compact.toolLog = buildToolLogForSideChannel(compact.toolEvents, compact.toolCallsCaptured, SIDE_CHANNEL_TOOL_EVENT_MAX);
3106
3227
  for (const key of ['input', 'output', 'values', 'chatHistory', 'context', 'contextText', 'diagnostics']) {
3107
3228
  if (compact[key] !== undefined)
3108
3229
  compact[`${key}Chars`] = typeof compact[key] === 'string' ? compact[key].length : safeStringify(compact[key]).length;
3109
3230
  delete compact[key];
3110
3231
  }
3111
- return compact;
3232
+ return keepVisibleToolLogArrays(compact);
3112
3233
  };
3113
3234
  const compactLastSaveForSideChannel = (lastSave = {}) => cleanContextValue({
3114
3235
  saved: lastSave.saved,
@@ -3259,6 +3380,7 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3259
3380
  const fullDedupeSummary = parsed.dedupeSummary || parsed.diagnostics?.dedupeSummary || undefined;
3260
3381
  const loadedSections = loadedSectionsForSideChannel(parsed, memoryAudit);
3261
3382
  const agentContextBudget = agentContextBudgetForSideChannel(list, parsed);
3383
+ summary.visualSchema = VISUAL_SCHEMA_VERSION;
3262
3384
  summary.userId = parsed.userId;
3263
3385
  summary.project = parsed.project || undefined;
3264
3386
  summary.retrievalMode = parsed.retrievalMode;
@@ -3281,13 +3403,12 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
3281
3403
  preview: truncate(String(lastAgent.content || lastAgent.text || lastAgent.message || ''), 240),
3282
3404
  } : undefined,
3283
3405
  });
3284
- summary.conversationTimeline = compactConversationTimelineForSideChannel(conversation, 4);
3406
+ summary.conversationTimeline = compactConversationTimelineForSideChannel(conversation, 16);
3407
+ const visibleToolEvents = compactToolEventsForSideChannel(toolItems, SIDE_CHANNEL_TOOL_EVENT_MAX);
3285
3408
  summary.toolCount = toolItems.length || tools.count || parsed.operationalState?.tool_counts?.total || undefined;
3286
3409
  summary.toolNames = toolItems.map((tool) => tool.name || tool.tool_name).filter(Boolean).slice(0, 12);
3287
- summary.toolEvents = toolItems
3288
- .slice(-3)
3289
- .map((tool) => compactToolAuditForSideChannel(tool || {}))
3290
- .filter((tool) => tool && Object.keys(tool).length);
3410
+ summary.toolLog = buildToolLogForSideChannel(visibleToolEvents, toolItems.length || summary.toolCount || visibleToolEvents.length, SIDE_CHANNEL_TOOL_EVENT_MAX);
3411
+ summary.toolEvents = visibleToolEvents;
3291
3412
  summary.lastTool = tools.last_successful_tool
3292
3413
  ? {
3293
3414
  name: tools.last_successful_tool.name,
@@ -3377,7 +3498,7 @@ const wrapTemboryMemory = (memory, ctx, memoryKey, itemIndex = 0) => new Proxy(m
3377
3498
  if (prop === 'loadMemoryVariables') {
3378
3499
  return async (values = {}) => {
3379
3500
  const { index } = ctx.addInputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, [
3380
- [{ json: { action: 'loadMemoryVariables', valuesChars: JSON.stringify(values || {}).length } }],
3501
+ [{ json: { action: 'loadMemoryVariables', visualSchema: VISUAL_SCHEMA_VERSION, valuesChars: JSON.stringify(values || {}).length } }],
3381
3502
  ]);
3382
3503
  try {
3383
3504
  const response = await target.loadMemoryVariables(values);
@@ -3387,6 +3508,7 @@ const wrapTemboryMemory = (memory, ctx, memoryKey, itemIndex = 0) => new Proxy(m
3387
3508
  [{
3388
3509
  json: {
3389
3510
  action: 'loadMemoryVariables',
3511
+ visualSchema: VISUAL_SCHEMA_VERSION,
3390
3512
  messages,
3391
3513
  memorySummary: summarizeMemoryMessagesForSideChannel(memoryMessages),
3392
3514
  },
@@ -4039,14 +4161,15 @@ class TemboryMemory {
4039
4161
  const loadCache = new Map();
4040
4162
  const recordMemoryEvent = (action, payload = {}, error) => {
4041
4163
  const { index } = this.addInputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, [
4042
- [{ json: { action } }],
4164
+ [{ json: { action, visualSchema: VISUAL_SCHEMA_VERSION } }],
4043
4165
  ]);
4044
4166
  if (error) {
4045
4167
  this.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, error);
4046
4168
  return;
4047
4169
  }
4170
+ const compactPayload = compactMemoryEventPayload(payload);
4048
4171
  this.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, [
4049
- [{ json: { action, ...compactMemoryEventPayload(payload) } }],
4172
+ [{ json: { action, visualSchema: VISUAL_SCHEMA_VERSION, memorySummary: compactPayload, ...compactPayload } }],
4050
4173
  ]);
4051
4174
  };
4052
4175
  const memory = {
@@ -5382,6 +5505,7 @@ class TemboryMemory {
5382
5505
  }
5383
5506
  const json = {
5384
5507
  action: 'loadMemoryVariables',
5508
+ visualSchema: VISUAL_SCHEMA_VERSION,
5385
5509
  messages: Array.isArray(payload) ? payload.length : 0,
5386
5510
  memorySummary: summarizeMemoryMessagesForSideChannel(payload),
5387
5511
  };
@@ -5458,6 +5582,9 @@ exports.__private = {
5458
5582
  contextSizeOfMessages,
5459
5583
  embedQueryCached,
5460
5584
  compactToolResult,
5585
+ compactToolAuditForSideChannel,
5586
+ buildToolLogForSideChannel,
5587
+ compactParsedToolOutputForSideChannel,
5461
5588
  compactToolHistoryForAgent,
5462
5589
  compactVectorMemoriesForAgent,
5463
5590
  isConversationEchoMemory,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.1.40",
3
+ "version": "1.1.42",
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",