n8n-nodes-tembory 1.1.28 → 1.1.30

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.
@@ -1839,6 +1839,12 @@ const isOperationalStatusQuery = (value = '') => {
1839
1839
  || /\b(tools?|ferramentas?|apis?|a[cç][oõ]es?|chamadas?|executadas?|usadas?)\b.{0,80}\b(quais?|qual|lista|mostra|resume|status|estado|historico|hist[oó]rico|outputs?|retornos?|resultado|resultados?)\b/.test(text)
1840
1840
  || /\b(ja|ainda|tinha|tenho|foi|esta|ta)\b.{0,60}\b(feito|feita|executad\w*|chamad\w*|concluid\w*|confirm\w*|criad\w*|atualizad\w*|agend\w*|agned\w*|ganed\w*|marc\w*|reserv\w*)\b/.test(text);
1841
1841
  };
1842
+ const hasNoToolRequested = (value = '') => {
1843
+ const text = normalizeIntentText(value);
1844
+ return /\b(nao|nunca|sem)\b.{0,30}\b(chame|chamar|use|usar|execute|executar|rode|rodar)\b.{0,30}\b(tools?|ferramentas?|apis?)\b/.test(text)
1845
+ || /\b(nao|nunca|sem)\b.{0,30}\b(tools?|ferramentas?|apis?)\b/.test(text)
1846
+ || /\b(responda|responder)\b.{0,40}\b(sem)\b.{0,20}\b(tools?|ferramentas?|apis?)\b/.test(text);
1847
+ };
1842
1848
  const recentUserMessages = (recentMessages = []) => [...(recentMessages || [])]
1843
1849
  .filter((msg) => /^(user|human)$/i.test(String(msg.role || '')))
1844
1850
  .reverse();
@@ -2079,6 +2085,8 @@ const deriveWorkingMemory = ({ query = '', profileFacts = {}, recentMessages = [
2079
2085
  const currentGoal = carryPreviousGoal ? previous.current_goal : nextExpectedAction;
2080
2086
  const toolNames = Array.from(new Set((toolHistory || []).map((tool) => tool.name || tool.tool_name || tool.tool).filter(Boolean)));
2081
2087
  const currentTurnMayNeedTool = ['affirm', 'commit_or_continue', 'tool_action_candidate', 'selection_or_slot'].includes(intent);
2088
+ const noToolRequested = hasNoToolRequested(query);
2089
+ const recallOnly = intent === 'conversation_recall' || (intent === 'operational_status_question' && noToolRequested);
2082
2090
  return {
2083
2091
  current_goal: currentGoal,
2084
2092
  current_goal_reason: carryPreviousGoal ? 'carried_from_previous_non_generic_goal' : 'derived_from_current_turn_intent',
@@ -2106,8 +2114,9 @@ const deriveWorkingMemory = ({ query = '', profileFacts = {}, recentMessages = [
2106
2114
  failed_by_name: toolState.failed_by_name,
2107
2115
  }),
2108
2116
  turn_flags: cleanContextValue({
2109
- recall_only: intent === 'conversation_recall',
2117
+ recall_only: recallOnly,
2110
2118
  status_question: intent === 'operational_status_question',
2119
+ no_tool_requested: noToolRequested,
2111
2120
  current_turn_may_need_tool: currentTurnMayNeedTool,
2112
2121
  has_prior_tools: Array.isArray(toolHistory) && toolHistory.length > 0,
2113
2122
  has_profile_facts: activeEntities.length > 0,
@@ -2365,6 +2374,67 @@ const compactToolResult = (result, max = 360) => {
2365
2374
  return truncate(safeStringify(picked), max);
2366
2375
  return truncate(text, max);
2367
2376
  };
2377
+ const tryParseJsonValue = (value) => {
2378
+ if (value === undefined || value === null || value === '')
2379
+ return undefined;
2380
+ if (typeof value === 'object')
2381
+ return value;
2382
+ if (typeof value !== 'string')
2383
+ return undefined;
2384
+ try {
2385
+ return JSON.parse(value);
2386
+ }
2387
+ catch {
2388
+ return undefined;
2389
+ }
2390
+ };
2391
+ const normalizeToolResultEnvelope = (value) => {
2392
+ const parsed = tryParseJsonValue(value);
2393
+ if (Array.isArray(parsed)) {
2394
+ const responses = parsed
2395
+ .map((item) => normalizeToolResultEnvelope(item))
2396
+ .filter((item) => item !== undefined && item !== null);
2397
+ if (responses.length === 1)
2398
+ return responses[0];
2399
+ return responses.length ? responses : parsed;
2400
+ }
2401
+ if (!parsed || typeof parsed !== 'object')
2402
+ return parsed;
2403
+ if (typeof parsed.response === 'string') {
2404
+ const nested = normalizeToolResultEnvelope(parsed.response);
2405
+ if (nested !== undefined)
2406
+ return nested;
2407
+ }
2408
+ if (parsed.response && typeof parsed.response === 'object')
2409
+ return normalizeToolResultEnvelope(parsed.response);
2410
+ return parsed;
2411
+ };
2412
+ const compactParsedToolOutputForSideChannel = (parsed) => {
2413
+ if (parsed === undefined || parsed === null)
2414
+ return undefined;
2415
+ if (Array.isArray(parsed))
2416
+ return cleanContextValue(parsed.map((item) => compactParsedToolOutputForSideChannel(item)));
2417
+ if (typeof parsed !== 'object')
2418
+ return parsed;
2419
+ if (parsed.output !== undefined)
2420
+ return cleanContextValue(stripNoisyToolFields(parsed.output));
2421
+ return cleanContextValue(stripNoisyToolFields(parsed));
2422
+ };
2423
+ const toolResultTimestampFromParsed = (parsed) => {
2424
+ if (!parsed)
2425
+ return undefined;
2426
+ if (Array.isArray(parsed)) {
2427
+ for (const item of parsed) {
2428
+ const found = toolResultTimestampFromParsed(item);
2429
+ if (found)
2430
+ return found;
2431
+ }
2432
+ return undefined;
2433
+ }
2434
+ if (typeof parsed !== 'object')
2435
+ return undefined;
2436
+ return parsed.timestamp || parsed.at || parsed.output?.timestamp;
2437
+ };
2368
2438
  const compactToolHistoryForAgent = (toolHistory = [], maxItems = 6, includeResults = true) => pruneByLimit(toolHistory || [], maxItems).map((tool) => ({
2369
2439
  name: tool.name,
2370
2440
  status: tool.ok === false ? 'failed' : 'ok',
@@ -2621,14 +2691,23 @@ const invokeConnectedModelSummary = async (connectedLanguageModel, summaryInput,
2621
2691
  ]);
2622
2692
  return cleanModelSummaryText(response, Number(adv.connectedModelSummaryMaxChars || 1200));
2623
2693
  };
2624
- const compactToolAuditForSideChannel = (tool = {}) => cleanContextValue({
2625
- name: tool.name || tool.tool_name || tool.tool,
2626
- status: tool.status || (tool.ok === false ? 'failed' : 'ok'),
2627
- at: tool.at || tool.timestamp,
2628
- timestamp: tool.timestamp || tool.at,
2629
- input: truncate(String(tool.input || tool.tool_args || tool.normalized_args || ''), 300) || undefined,
2630
- output: compactToolResult(tool.result !== undefined ? tool.result : tool.output !== undefined ? tool.output : tool.observation, 800),
2631
- });
2694
+ const compactToolAuditForSideChannel = (tool = {}) => {
2695
+ const capturedAt = tool.at || tool.timestamp;
2696
+ const rawResult = tool.result !== undefined ? tool.result : tool.output !== undefined ? tool.output : tool.observation;
2697
+ const parsedResult = normalizeToolResultEnvelope(rawResult);
2698
+ return cleanContextValue({
2699
+ name: tool.name || tool.tool_name || tool.tool,
2700
+ status: tool.status || (tool.ok === false ? 'failed' : 'ok'),
2701
+ at: capturedAt,
2702
+ timestamp: capturedAt,
2703
+ capturedAt,
2704
+ toolTimestamp: toolResultTimestampFromParsed(parsedResult),
2705
+ toolStatus: parsedResult && typeof parsedResult === 'object' && !Array.isArray(parsedResult) ? parsedResult.status : undefined,
2706
+ input: truncate(String(tool.input || tool.tool_args || tool.normalized_args || ''), 300) || undefined,
2707
+ output: compactToolResult(rawResult, 800),
2708
+ outputParsed: compactParsedToolOutputForSideChannel(parsedResult),
2709
+ });
2710
+ };
2632
2711
  const compactMessageForSideChannel = (message = {}) => {
2633
2712
  const type = messageTypeOf(message) || String(message.role || 'message').toLowerCase();
2634
2713
  const role = type === 'human' ? 'user' : type === 'ai' ? 'assistant' : type || 'message';
@@ -3584,6 +3663,7 @@ class TemboryMemory {
3584
3663
  if (output)
3585
3664
  currentMessages.push(toBaseMessage({ role: 'assistant', content: output }));
3586
3665
  await TemboryMemory.prototype.saveContextForItem.call(this, itemIndex, inputValues, outputValues);
3666
+ recordMemoryEvent('saveContext', summarizeSaveContextForSideChannel(inputValues, outputValues, currentMessages));
3587
3667
  },
3588
3668
  };
3589
3669
  return { response: wrapTemboryMemory(memory, this, memoryKey, itemIndex) };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.1.28",
3
+ "version": "1.1.30",
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",