n8n-nodes-tembory 1.0.47 → 1.0.48

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.
@@ -1238,10 +1238,11 @@ const applyOperationalPreset = (advanced = {}) => {
1238
1238
  includeConnectedModelSummary: true,
1239
1239
  includeActiveSummary: true,
1240
1240
  persistActiveSummary: true,
1241
- activeSummaryMaxChars: 1800,
1241
+ activeSummaryMaxChars: 1200,
1242
1242
  activeSummaryRetentionDays: 30,
1243
1243
  enableTransientSummaryCache: true,
1244
1244
  transientSummaryCacheTTLSeconds: 300,
1245
+ compactForAgent: true,
1245
1246
  compactStateSections: true,
1246
1247
  useVectorMemory: false,
1247
1248
  persistBackendMemories: true,
@@ -1271,9 +1272,9 @@ const applyOperationalPreset = (advanced = {}) => {
1271
1272
  toolHistoryLastN: 15,
1272
1273
  recentMessagesLastN: 50,
1273
1274
  vectorMemoryMaxChars: 220,
1274
- contextMaxChars: 9000,
1275
- connectedModelSummaryMaxChars: 1200,
1276
- connectedModelSummaryInputMaxChars: 4200,
1275
+ contextMaxChars: 6000,
1276
+ connectedModelSummaryMaxChars: 900,
1277
+ connectedModelSummaryInputMaxChars: 3600,
1277
1278
  },
1278
1279
  diagnostic: {
1279
1280
  summarySource: 'auto',
@@ -1310,6 +1311,7 @@ const applyOperationalPreset = (advanced = {}) => {
1310
1311
  activeSummaryRetentionDays: 30,
1311
1312
  enableTransientSummaryCache: true,
1312
1313
  transientSummaryCacheTTLSeconds: 300,
1314
+ compactForAgent: true,
1313
1315
  compactStateSections: true,
1314
1316
  includeContextHeader: true,
1315
1317
  includeSummary: true,
@@ -1347,6 +1349,7 @@ const applyOperationalPreset = (advanced = {}) => {
1347
1349
  activeSummaryRetentionDays: 30,
1348
1350
  enableTransientSummaryCache: true,
1349
1351
  transientSummaryCacheTTLSeconds: 300,
1352
+ compactForAgent: true,
1350
1353
  compactStateSections: true,
1351
1354
  includeContextHeader: true,
1352
1355
  includeSummary: false,
@@ -1623,13 +1626,8 @@ const buildConversationFrame = ({ query = '', recentMessages = [] }) => {
1623
1626
  const frame = cleanContextValue({
1624
1627
  current_user_message: currentUser ? truncate(currentUser.content, 500) : truncate(query, 500),
1625
1628
  conversation_history_chronological: chronological,
1626
- recent_messages_chronological: chronological,
1627
1629
  all_user_messages_chronological: userMessagesChronological,
1628
- recent_user_messages: users
1629
- .filter((msg) => normalizeIntentText(msg.content).trim() !== normalizedQuery)
1630
- .slice(0, 5)
1631
- .map((msg) => ({ role: msg.role, content: truncate(msg.content, 500), at: msg.at })),
1632
- instruction: 'This is the authoritative short-term conversation frame. If the user asks about current/previous/last client messages or what they already said, answer from conversation_history_chronological/all_user_messages_chronological before using vector memories, summaries, operational state, or tool history. For the last message before the current one, use the user message immediately before current_user_message in all_user_messages_chronological.',
1630
+ instruction: 'Authoritative short-term transcript. For recall questions, answer from conversation_history_chronological/all_user_messages_chronological before summaries or tool history.',
1633
1631
  });
1634
1632
  return frame;
1635
1633
  };
@@ -1916,7 +1914,26 @@ const contextMemoryText = (memory, max = 700) => {
1916
1914
  return truncate(text, max);
1917
1915
  };
1918
1916
  const approxTokenCount = (text) => Math.ceil(String(text || '').length / 4);
1919
- const importantJsonFields = ['id', 'status', 'state', 'next_step', 'action', 'intent', 'tool', 'input', 'output', 'result', 'error', 'message', 'reason', 'customer_id', 'user_id', 'lead_id', 'ticket_id', 'charge_id'];
1917
+ const noisyToolFields = new Set(['requested_from', 'thread', 'thread_id', 'run_id', 'dedupe_key', 'args_hash', 'result_hash', 'source']);
1918
+ const importantJsonFields = ['id', 'status', 'state', 'next_step', 'action', 'intent', 'tool', 'input', 'output', 'result', 'error', 'message', 'reason', 'customer_id', 'user_id', 'lead_id', 'ticket_id', 'charge_id', 'reservation_id', 'confirmation_id', 'selected_from_message', 'available_slots', 'timezone', 'name', 'phone', 'segmento', 'platform', 'plataforma', 'lifecycle_stage', 'provider', 'sku', 'product', 'stock', 'queue', 'priority'];
1919
+ const stripNoisyToolFields = (value, depth = 0) => {
1920
+ if (depth > 8)
1921
+ return undefined;
1922
+ if (Array.isArray(value))
1923
+ return value.map((item) => stripNoisyToolFields(item, depth + 1)).filter((item) => item !== undefined);
1924
+ if (!value || typeof value !== 'object')
1925
+ return value;
1926
+ const out = {};
1927
+ for (const [key, item] of Object.entries(value)) {
1928
+ if (noisyToolFields.has(String(key)))
1929
+ continue;
1930
+ const cleaned = stripNoisyToolFields(item, depth + 1);
1931
+ if (cleaned === undefined)
1932
+ continue;
1933
+ out[key] = cleaned;
1934
+ }
1935
+ return out;
1936
+ };
1920
1937
  const pickImportantFields = (value) => {
1921
1938
  if (value === null || value === undefined)
1922
1939
  return {};
@@ -1929,7 +1946,7 @@ const pickImportantFields = (value) => {
1929
1946
  return;
1930
1947
  }
1931
1948
  for (const key of importantJsonFields) {
1932
- if (item[key] !== undefined && out[key] === undefined)
1949
+ if (!noisyToolFields.has(key) && item[key] !== undefined && out[key] === undefined)
1933
1950
  out[key] = item[key];
1934
1951
  }
1935
1952
  if (item.args)
@@ -1945,12 +1962,15 @@ const compactToolResult = (result, max = 360) => {
1945
1962
  if (!text.trim())
1946
1963
  return undefined;
1947
1964
  try {
1948
- const parsed = JSON.parse(text);
1949
- return truncate(safeStringify(parsed), max);
1965
+ const parsed = stripNoisyToolFields(JSON.parse(text));
1966
+ const picked = pickImportantFields(parsed);
1967
+ return truncate(safeStringify(Object.keys(picked).length ? picked : parsed), max);
1950
1968
  }
1951
1969
  catch { }
1952
1970
  const picked = {};
1953
1971
  for (const key of importantJsonFields) {
1972
+ if (noisyToolFields.has(key))
1973
+ continue;
1954
1974
  const re = new RegExp(`["']?${key}["']?\\s*[:=]\\s*["']?([^"',}\\]]+)`, 'i');
1955
1975
  const match = re.exec(text);
1956
1976
  if (match)
@@ -1961,7 +1981,6 @@ const compactToolResult = (result, max = 360) => {
1961
1981
  return truncate(text, max);
1962
1982
  };
1963
1983
  const compactToolHistoryForAgent = (toolHistory = [], maxItems = 6, includeResults = true) => pruneByLimit(toolHistory || [], maxItems).map((tool) => ({
1964
- id: tool.call_id || tool.id,
1965
1984
  name: tool.name,
1966
1985
  status: tool.ok === false ? 'failed' : 'ok',
1967
1986
  at: tool.at,
@@ -2045,7 +2064,6 @@ const compactMemoryCompressionForAgent = (compression = {}) => ({
2045
2064
  active_memory_count: ((compression.workflow_summary || {}).active_memory_count) || 0,
2046
2065
  });
2047
2066
  const compactActionLedgerForAgent = (ledger = [], maxItems = 6, includeResults = true) => pruneByLimit(ledger || [], maxItems).map((item) => cleanContextValue({
2048
- action_id: item.action_id,
2049
2067
  kind: item.kind,
2050
2068
  tool: item.tool || item.name,
2051
2069
  status: item.status,
@@ -2312,32 +2330,20 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
2312
2330
  sections.push({ section: 'summary', title: 'Summary', value: summary.length ? summary : null, why_null: summary.length ? undefined : 'no non-tool vector memories to summarize' });
2313
2331
  }
2314
2332
  if (connectedModelSummary && adv.includeConnectedModelSummary !== false) {
2315
- sections.push({ section: 'connected_model_summary', title: 'SLM summary', value: connectedModelSummary });
2333
+ sections.push({ section: 'connected_model_summary', title: 'SLM summary', value: truncate(connectedModelSummary, Number(adv.connectedModelSummaryMaxChars || 900)) });
2316
2334
  }
2317
2335
  else if (activeSummary && adv.includeActiveSummary !== false) {
2318
- sections.push({ section: 'active_summary', title: 'Active summary', value: activeSummary });
2336
+ sections.push({ section: 'active_summary', title: 'Active summary', value: truncate(activeSummary, Number(adv.activeSummaryMaxChars || 900)) });
2319
2337
  }
2320
2338
  sections.push({
2321
2339
  section: 'working_memory',
2322
2340
  title: 'Working memory',
2323
- value: adv.includeWorkingMemory === false ? null : (workingMemory || {}),
2341
+ value: adv.includeWorkingMemory === false ? null : compactWorkingMemoryForAgent(workingMemory || {}),
2324
2342
  why_null: adv.includeWorkingMemory === false ? 'working memory disabled' : undefined,
2325
2343
  });
2326
2344
  sections.push({
2327
- section: 'decision_state',
2328
- title: 'Decision state',
2329
- value: adv.includeDecisionState === false ? null : (decisionState || {}),
2330
- why_null: adv.includeDecisionState === false ? 'decision state disabled' : undefined,
2331
- });
2332
- sections.push({
2333
- section: 'operational_state',
2334
- title: 'Operational state',
2335
- value: adv.includeOperationalState === false ? null : compactOperationalStateForAgent(operationalState || {}),
2336
- why_null: adv.includeOperationalState === false ? 'operational state disabled' : undefined,
2337
- });
2338
- sections.push({
2339
- section: 'tool_history',
2340
- title: 'Tool history',
2345
+ section: 'tool_ledger',
2346
+ title: 'Tool ledger',
2341
2347
  value: {
2342
2348
  enabled: adv.includeToolHistory !== false,
2343
2349
  items: adv.includeToolHistory === false ? [] : compactToolHistoryForAgent(toolHistory, adv.toolHistoryLastN || 6, adv.includeToolResults !== false),
@@ -2350,22 +2356,15 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
2350
2356
  why_null: adv.includeProfileFacts === false ? 'profile facts disabled' : undefined,
2351
2357
  });
2352
2358
  sections.push({
2353
- section: 'memory_compression',
2354
- title: 'Memory compression',
2355
- value: adv.includeMemoryCompression === false ? null : compactMemoryCompressionForAgent(memoryCompression || {}),
2356
- why_null: adv.includeMemoryCompression === false ? 'memory compression disabled' : undefined,
2359
+ section: 'next_action',
2360
+ title: 'Next action',
2361
+ value: cleanContextValue({
2362
+ current_intent: (decisionState || {}).current_intent || workingMemory.last_user_intent,
2363
+ latest_tool: ((decisionState || {}).latest_tool || (operationalState || {}).last_tool || undefined),
2364
+ do_not_repeat_tools: ((decisionState || {}).do_not_repeat_tools || []).slice(0, 12),
2365
+ instruction: actionDirective || workingMemory.next_expected_action || 'Continue according to the agent prompt.',
2366
+ }),
2357
2367
  });
2358
- if (adv.includeRecentMessages !== false || currentTurnFocus) {
2359
- sections.push({
2360
- section: 'recent_messages',
2361
- title: 'Recent messages',
2362
- value: pruneByLimit(recentMessages || [], adv.recentMessagesLastN || 4).map((message) => cleanContextValue({
2363
- role: message.role,
2364
- content: truncate(message.content, 260),
2365
- at: message.at,
2366
- })),
2367
- });
2368
- }
2369
2368
  const audit = {
2370
2369
  kind: 'tembory.context.v1',
2371
2370
  meta: { user_id: userId, payloadFormat, query, compact_for_agent: true },
@@ -2385,7 +2384,18 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
2385
2384
  return [{ role: 'system', content: JSON.stringify(audit, null, 2) }];
2386
2385
  if (payloadFormat === 'auditBlocks')
2387
2386
  return sections.map((section) => ({ role: 'system', content: renderCompactSection(section) }));
2388
- return [{ role: 'system', content: truncate(sections.map(renderCompactSection).join('\n\n'), Number(adv.contextMaxChars || 6000)) }];
2387
+ const renderableSections = sections.filter((section) => {
2388
+ if (section.section === 'summary' && !section.value)
2389
+ return false;
2390
+ if (section.value === null || section.value === undefined)
2391
+ return false;
2392
+ if (Array.isArray(section.value) && section.value.length === 0)
2393
+ return false;
2394
+ if (typeof section.value === 'object' && !Array.isArray(section.value) && Object.keys(section.value).length === 0)
2395
+ return false;
2396
+ return true;
2397
+ });
2398
+ return [{ role: 'system', content: truncate(renderableSections.map(renderCompactSection).join('\n\n'), Number(adv.contextMaxChars || 6000)) }];
2389
2399
  }
2390
2400
  if (includeSummary) {
2391
2401
  const summary = compactStateSections
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.47",
3
+ "version": "1.0.48",
4
4
  "description": "Tembory node for n8n AI Agents with profile, tools, timeline, graph and semantic memory",
5
5
  "license": "MIT",
6
6
  "homepage": "https://tembory.com",