n8n-nodes-tembory 1.0.29 → 1.0.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.
package/README.md CHANGED
@@ -2,7 +2,13 @@
2
2
 
3
3
  Node de memoria operacional da Tembory para agentes de IA no n8n.
4
4
 
5
- Versao atual: `1.0.29`.
5
+ Versao atual: `1.0.30`.
6
+
7
+ ## 1.0.30
8
+
9
+ - Adiciona `Action directive` quando a memoria conclui que uma tool deve ser chamada no turno atual.
10
+ - Torna `next_expected_action` mais coercitivo para agenda: usa `MUST call ...` e proibe respostas como "se quiser/posso" no lugar da tool obrigatoria.
11
+ - Reduz o peso instrucional de `first_user_message`; o foco passa a ser mensagem atual, mensagem anterior e transcript cronologico recente.
6
12
 
7
13
  ## 1.0.29
8
14
 
@@ -1306,7 +1306,7 @@ const buildConversationFrame = ({ query = '', recentMessages = [], workingMemory
1306
1306
  .filter((msg) => normalizeIntentText(msg.content).trim() !== normalizedQuery)
1307
1307
  .slice(0, 5)
1308
1308
  .map((msg) => ({ role: msg.role, content: truncate(msg.content, 500), at: msg.at })),
1309
- instruction: 'This is the authoritative short-term conversation frame. If the user asks about first/current/previous/last client messages or what they already said, answer from first_user_message/current_user_message/previous_user_message/conversation_history_chronological/all_user_messages_chronological before using vector memories, summaries, operational state, or tool history.',
1309
+ 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 current_user_message/previous_user_message/conversation_history_chronological/all_user_messages_chronological before using vector memories, summaries, operational state, or tool history.',
1310
1310
  });
1311
1311
  if (!previousUserMessage)
1312
1312
  frame.previous_user_message = null;
@@ -1346,13 +1346,33 @@ const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalSta
1346
1346
  has_availability: Boolean(agenda.has_availability),
1347
1347
  } : undefined,
1348
1348
  instruction: recall
1349
- ? 'Answer the user meta-question from first_user_message/previous_user_message/recent_user_messages. Do not answer with agenda availability unless the user asks for availability.'
1349
+ ? 'Answer the user meta-question from previous_user_message/recent_user_messages and the chronological transcript. Do not answer with agenda availability unless the user asks for availability.'
1350
1350
  : 'Answer whether the appointment/reservation is already scheduled using agenda_status. Do not offer availability as the main answer unless there is no schedule/reservation state.',
1351
1351
  });
1352
1352
  if (!previousUserMessage)
1353
1353
  focus.previous_user_message = null;
1354
1354
  return focus;
1355
1355
  };
1356
+ const buildActionDirective = ({ workingMemory = {}, operationalState = {} }) => {
1357
+ const next = String((workingMemory || {}).next_expected_action || '');
1358
+ const match = /\bagenda_(consultar_disponibilidade|pre_reservar_horario|confirmar_agendamento)\b/.exec(next);
1359
+ if (!match || !/\bcall\b|\bMUST\b/i.test(next))
1360
+ return null;
1361
+ const tool = match[0];
1362
+ const agenda = (operationalState || {}).agenda_state || {};
1363
+ return cleanContextValue({
1364
+ required_tool: tool,
1365
+ next_expected_action: next,
1366
+ agenda_state: {
1367
+ has_availability: Boolean(agenda.has_availability),
1368
+ latest_availability_source: agenda.latest_availability_source,
1369
+ has_pre_reservation: Boolean(agenda.has_pre_reservation),
1370
+ has_pending_pre_reservation: Boolean(agenda.has_pending_pre_reservation),
1371
+ has_confirmation: Boolean(agenda.has_confirmation),
1372
+ },
1373
+ instruction: `You MUST call ${tool} now. Do not answer with "posso", "se quiser", "já posso" or ask for the same confirmation instead of calling the required tool. Only skip this tool if it is explicitly blocked in Tool guard.`,
1374
+ });
1375
+ };
1356
1376
  const inferToolGuard = ({ query, recentMessages, toolHistory, vectorMemories }) => {
1357
1377
  const text = normalizeIntentText(query);
1358
1378
  const names = new Set((toolHistory || []).map((tool) => String(tool.name || '')));
@@ -1408,24 +1428,26 @@ const deriveNextExpectedAction = (intent, operationalState = {}) => {
1408
1428
  const agenda = operationalState.agenda_state || {};
1409
1429
  if (intent === 'affirm') {
1410
1430
  if (agenda.has_pending_pre_reservation)
1411
- return 'call agenda_confirmar_agendamento now; do not ask the same confirmation question again';
1431
+ return 'MUST call agenda_confirmar_agendamento now; do not ask the same confirmation question again';
1412
1432
  if (agenda.has_availability)
1413
- return 'call agenda_pre_reservar_horario now using the selected or latest discussed slot; do not ask again';
1433
+ return 'MUST call agenda_pre_reservar_horario now using the selected or latest discussed slot; do not ask again';
1414
1434
  return 'call agenda_consultar_disponibilidade before reserving';
1415
1435
  }
1416
1436
  if (intent === 'confirm') {
1417
1437
  if (agenda.has_pending_pre_reservation)
1418
- return 'call agenda_confirmar_agendamento now using the latest pre-reservation context; do not ask again';
1419
- return 'do not call agenda_confirmar_agendamento; call agenda_pre_reservar_horario first if a selected slot and availability are known, otherwise call agenda_consultar_disponibilidade';
1438
+ return 'MUST call agenda_confirmar_agendamento now using the latest pre-reservation context; do not ask again';
1439
+ if (agenda.has_availability)
1440
+ return 'MUST call agenda_pre_reservar_horario first using the selected or latest discussed slot; do not ask for permission again';
1441
+ return 'do not call agenda_confirmar_agendamento; call agenda_consultar_disponibilidade first because no availability is known';
1420
1442
  }
1421
1443
  if (intent === 'select_slot') {
1422
1444
  if (agenda.has_availability)
1423
- return 'call agenda_pre_reservar_horario now using the selected slot; do not ask for confirmation before pre-reserving';
1445
+ return 'MUST call agenda_pre_reservar_horario now using the selected slot; do not ask for confirmation before pre-reserving';
1424
1446
  return 'call agenda_consultar_disponibilidade before pre-reserving';
1425
1447
  }
1426
1448
  if (intent === 'pre_reserve') {
1427
1449
  if (agenda.has_availability)
1428
- return 'call agenda_pre_reservar_horario now using one of the known available slots';
1450
+ return 'MUST call agenda_pre_reservar_horario now using one of the known available slots';
1429
1451
  return 'call agenda_consultar_disponibilidade before pre-reserving';
1430
1452
  }
1431
1453
  if (intent === 'check_availability')
@@ -2010,8 +2032,8 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
2010
2032
  sections.push({
2011
2033
  section: 'conversation_frame',
2012
2034
  title: 'Conversation frame',
2013
- value: buildConversationFrame({ query, recentMessages, workingMemory }),
2014
- });
2035
+ value: buildConversationFrame({ query, recentMessages, workingMemory }),
2036
+ });
2015
2037
  const currentTurnFocus = buildCurrentTurnFocus({ query, recentMessages, operationalState, workingMemory });
2016
2038
  if (currentTurnFocus) {
2017
2039
  sections.push({
@@ -2020,6 +2042,14 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
2020
2042
  value: currentTurnFocus,
2021
2043
  });
2022
2044
  }
2045
+ const actionDirective = buildActionDirective({ workingMemory, operationalState });
2046
+ if (actionDirective) {
2047
+ sections.push({
2048
+ section: 'action_directive',
2049
+ title: 'Action directive',
2050
+ value: actionDirective,
2051
+ });
2052
+ }
2023
2053
  if (compactForAgent) {
2024
2054
  if (includeSummary) {
2025
2055
  const summary = compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.summaryMaxFacts || 3));
@@ -3661,6 +3691,7 @@ exports.__private = {
3661
3691
  toolHistoryFromMemory,
3662
3692
  cleanAssistantTranscriptText,
3663
3693
  availabilityFromRecentMessages,
3694
+ buildActionDirective,
3664
3695
  recentMessageFromMemory,
3665
3696
  previousUserFallbackFromWorkingMemory,
3666
3697
  firstUserMessageFromConversation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.29",
3
+ "version": "1.0.30",
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",