n8n-nodes-tembory 1.0.3 → 1.0.5

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.
@@ -1005,11 +1005,18 @@ const getRecentHighlights = (recentMessages, tools, maxItems = 6) => {
1005
1005
  }
1006
1006
  return pruneByLimit(Array.from(new Set(lines)), maxItems);
1007
1007
  };
1008
+ const normalizeIntentText = (value = '') => String(value || '')
1009
+ .toLowerCase()
1010
+ .normalize('NFD')
1011
+ .replace(/[\u0300-\u036f]/g, '');
1012
+ const hasConfirmIntent = (value = '') => /\b(confirm\w*|confim\w*|cnfirm\w*|cofnirm\w*|ocnfi\w*|ocnfia\w*|fechar)\b/.test(normalizeIntentText(value));
1008
1013
  const inferToolGuard = ({ query, recentMessages, toolHistory, vectorMemories }) => {
1009
- const text = String(query || '').toLowerCase();
1014
+ const text = normalizeIntentText(query);
1010
1015
  const names = new Set((toolHistory || []).map((tool) => String(tool.name || '')));
1011
1016
  const hasRecentContext = (recentMessages || []).some((msg) => /reserva|pré-reserva|pre-reserva|agend|confirm|hor[aá]rio|dispon/i.test(String(msg.content || '')));
1012
1017
  const hasVectorContext = (vectorMemories || []).some((memory) => /reserva|pré-reserva|pre-reserva|agend|confirm|hor[aá]rio|dispon/i.test(memoryText(memory)));
1018
+ const hasAvailabilityTool = names.has('agenda_consultar_disponibilidade');
1019
+ const hasPreReservationTool = names.has('agenda_pre_reservar_horario');
1013
1020
  const hasAnyContext = names.size > 0 || hasRecentContext || hasVectorContext;
1014
1021
  const blocked = [];
1015
1022
  const reasons = [];
@@ -1017,32 +1024,34 @@ const inferToolGuard = ({ query, recentMessages, toolHistory, vectorMemories })
1017
1024
  blocked.push('agenda_pre_reservar_horario', 'agenda_confirmar_agendamento');
1018
1025
  reasons.push('no prior availability or pre-reservation context was found for this session');
1019
1026
  }
1020
- if ((/confirm|confirma|confirmar/.test(text)) && !names.has('agenda_pre_reservar_horario') && !hasRecentContext) {
1027
+ if (hasConfirmIntent(text) && !hasPreReservationTool) {
1021
1028
  blocked.push('agenda_confirmar_agendamento');
1022
- reasons.push('confirmation requested but no prior pre-reservation was found in tool_history or recent_messages');
1029
+ reasons.push('confirmation requested but no structured agenda_pre_reservar_horario tool result was found; assistant text or vector memories are not enough to confirm');
1023
1030
  }
1024
- if ((/pre.?reserv|pré.?reserv|reservar/.test(text)) && !names.has('agenda_consultar_disponibilidade') && !hasRecentContext) {
1031
+ if ((/pre.?reserv|pre.?reserv|reservar/.test(text)) && !hasAvailabilityTool) {
1025
1032
  blocked.push('agenda_pre_reservar_horario');
1026
- reasons.push('reservation requested but no prior availability result was found in tool_history or recent_messages');
1033
+ reasons.push('reservation requested but no structured agenda_consultar_disponibilidade tool result was found');
1027
1034
  }
1028
1035
  return { blockedTools: Array.from(new Set(blocked)), reasons };
1029
1036
  };
1030
1037
  const inferUserIntent = (query = '', recentMessages = []) => {
1031
1038
  const latestUser = [...(recentMessages || [])].reverse().find((msg) => /^(user|human)$/i.test(String(msg.role || '')));
1032
- const text = `${query || ''}\n${latestUser?.content || ''}`.toLowerCase();
1033
- if (/^(ok|sim|pode|pode sim|isso|isso mesmo|confirmo|confirmar)$/i.test(String(query || '').trim()))
1039
+ const rawText = `${query || ''}\n${latestUser?.content || ''}`;
1040
+ const text = normalizeIntentText(rawText);
1041
+ const normalizedQuery = normalizeIntentText(query).trim();
1042
+ if (/^(ok|sim|pode|pode sim|isso|isso mesmo|confirmo|confirmar)$/.test(normalizedQuery))
1034
1043
  return 'affirm';
1035
- if (/\b(confirm|confirma|confirmar|fechar|pode confirmar)\b/.test(text))
1044
+ if (hasConfirmIntent(text))
1036
1045
  return 'confirm';
1037
1046
  if (containsSelectedSlot(text))
1038
1047
  return 'select_slot';
1039
- if (/\b(pre.?reserv|pré.?reserv|reservar|segurar|marcar)\b/.test(text))
1048
+ if (/\b(pre.?reserv|pre.?reserv|reservar|segurar|marcar)\b/.test(text))
1040
1049
  return 'pre_reserve';
1041
- if (/\b(disponibilidade|hor[aá]rios?|agenda|quando pode|tem vaga)\b/.test(text))
1050
+ if (/\b(disponibilidade|horarios?|agenda(?:r|mento)?|quando pode|tem vaga|quero agendar|gostaria de agendar|preciso agendar)\b/.test(text))
1042
1051
  return 'check_availability';
1043
1052
  if (/\b(cancel|desmarcar|remarcar|alterar|mudar)\b/.test(text))
1044
1053
  return 'change_or_cancel';
1045
- if (/\b(meu nome|email|telefone|empresa|prefiro|prefer[eê]ncia)\b/.test(text))
1054
+ if (/\b(meu nome|email|telefone|empresa|prefiro|preferencia)\b/.test(text))
1046
1055
  return 'profile_update';
1047
1056
  if (text.trim())
1048
1057
  return 'general_message';
@@ -1060,7 +1069,7 @@ const deriveNextExpectedAction = (intent, operationalState = {}) => {
1060
1069
  if (intent === 'confirm') {
1061
1070
  if (agenda.has_pending_pre_reservation)
1062
1071
  return 'call agenda_confirmar_agendamento now using the latest pre-reservation context; do not ask again';
1063
- return 'ask for or create a pre-reservation before confirming';
1072
+ 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';
1064
1073
  }
1065
1074
  if (intent === 'select_slot') {
1066
1075
  if (agenda.has_availability)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
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",