n8n-nodes-tembory 1.0.28 → 1.0.29

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.28`.
5
+ Versao atual: `1.0.29`.
6
+
7
+ ## 1.0.29
8
+
9
+ - Considera disponibilidade recente no transcript como contexto operacional valido quando `tool_history` ainda nao foi recuperado no turno.
10
+ - Evita repetir `agenda_consultar_disponibilidade` apos o agente ja ter respondido vagas no historico recente.
11
+ - Direciona selecao de horario como "quero dia 13" para `agenda_pre_reservar_horario` quando ha vagas recentes, mesmo sem marker estruturado no contexto atual.
6
12
 
7
13
  ## 1.0.28
8
14
 
@@ -408,11 +408,32 @@ const safeParseToolPayload = (value) => {
408
408
  const compactToolPayload = (value) => truncate(typeof value === 'string' ? value : safeStringify(value), 900);
409
409
  const maybeToolResult = (tool, includeResults = true) => includeResults === false ? undefined : compactToolPayload(safeParseToolPayload(tool === null || tool === void 0 ? void 0 : tool.result));
410
410
  const containsSelectedSlot = (text = '') => /\b(?:às|as|das|para)?\s*\d{1,2}(?::\d{2}|h\d{0,2})?\b/i.test(String(text || '')) || /\b\d{1,2}\/\d{1,2}(?:\/\d{2,4})?\b/.test(String(text || ''));
411
+ const availabilityFromRecentMessages = (recentMessages = []) => {
412
+ const messages = Array.isArray(recentMessages) ? recentMessages : [];
413
+ const candidates = [...messages].reverse().filter((message) => {
414
+ const role = String(message.role || '').toLowerCase();
415
+ const text = String(message.content || message.text || message.memory || '');
416
+ if (role && role !== 'assistant' && role !== 'ai' && role !== 'system')
417
+ return false;
418
+ return /\b(?:tem|tenho|há|ha)\s+vagas?\b|\bop[cç][oõ]es?\s+dispon[ií]veis\b|\bavailable_slots\b/i.test(text)
419
+ && (/\b\d{1,2}\/\d{1,2}(?:\/\d{2,4})?\b/.test(text) || /\b\d{1,2}:\d{2}\b/.test(text));
420
+ });
421
+ const latest = candidates[0];
422
+ if (!latest)
423
+ return null;
424
+ return {
425
+ text: truncate(String(latest.content || latest.text || latest.memory || ''), 900),
426
+ at: latest.at || latest.created_at || latest.createdAt || nowIso(),
427
+ source: latest.source || 'recent_message',
428
+ };
429
+ };
411
430
  const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessages = [], includeResults = true) => {
412
431
  const tools = Array.isArray(toolHistory) ? toolHistory : [];
413
432
  const successfulTools = tools.filter((tool) => tool.ok !== false);
414
433
  const byName = (name) => successfulTools.filter((tool) => tool.name === name);
415
434
  const availability = byName('agenda_consultar_disponibilidade');
435
+ const recentAvailability = availability.length ? null : availabilityFromRecentMessages(recentMessages);
436
+ const hasAvailability = availability.length > 0 || Boolean(recentAvailability);
416
437
  const reservations = byName('agenda_pre_reservar_horario');
417
438
  const confirmations = byName('agenda_confirmar_agendamento');
418
439
  const lastTool = tools[tools.length - 1] || null;
@@ -420,18 +441,18 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
420
441
  const lastConfirmation = confirmations[confirmations.length - 1] || null;
421
442
  const hasPendingReservation = Boolean(lastReservation && (!lastConfirmation || String(lastReservation.at || '') > String(lastConfirmation.at || '')));
422
443
  const blockedWithoutContext = [];
423
- if (!availability.length)
444
+ if (!hasAvailability)
424
445
  blockedWithoutContext.push('agenda_pre_reservar_horario');
425
446
  if (!reservations.length)
426
447
  blockedWithoutContext.push('agenda_confirmar_agendamento');
427
448
  const guidance = [];
428
- if (!availability.length)
449
+ if (!hasAvailability)
429
450
  guidance.push('No availability result is known for this session; consult availability before reserving or confirming.');
430
451
  else if (hasPendingReservation)
431
452
  guidance.push('A pre-reservation exists after the latest confirmation; confirmation can use the latest pre-reservation context.');
432
453
  else if (lastConfirmation)
433
454
  guidance.push('The latest reservation appears confirmed; do not confirm again unless the user explicitly asks to repeat or change it.');
434
- else if (availability.length)
455
+ else if (hasAvailability)
435
456
  guidance.push('Availability is known; if the user chooses one listed slot, reserve without repeating availability.');
436
457
  return {
437
458
  profile_complete: Boolean(profileFacts && profileFacts.name && profileFacts.company && profileFacts.email && profileFacts.phone),
@@ -445,11 +466,12 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
445
466
  agenda_confirmar_agendamento: confirmations.length,
446
467
  },
447
468
  agenda_state: {
448
- has_availability: availability.length > 0,
469
+ has_availability: hasAvailability,
449
470
  has_pre_reservation: reservations.length > 0,
450
471
  has_confirmation: confirmations.length > 0,
451
472
  has_pending_pre_reservation: hasPendingReservation,
452
- latest_availability_result: availability.length ? maybeToolResult(availability[availability.length - 1], includeResults) : null,
473
+ latest_availability_result: availability.length ? maybeToolResult(availability[availability.length - 1], includeResults) : (recentAvailability && includeResults !== false ? recentAvailability.text : null),
474
+ latest_availability_source: availability.length ? 'tool_history' : (recentAvailability ? recentAvailability.source : null),
453
475
  latest_pre_reservation_result: lastReservation ? maybeToolResult(lastReservation, includeResults) : null,
454
476
  latest_confirmation_result: lastConfirmation ? maybeToolResult(lastConfirmation, includeResults) : null,
455
477
  },
@@ -3638,6 +3660,7 @@ exports.__private = {
3638
3660
  explicitToolHistoryItemsFromMemory,
3639
3661
  toolHistoryFromMemory,
3640
3662
  cleanAssistantTranscriptText,
3663
+ availabilityFromRecentMessages,
3641
3664
  recentMessageFromMemory,
3642
3665
  previousUserFallbackFromWorkingMemory,
3643
3666
  firstUserMessageFromConversation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tembory",
3
- "version": "1.0.28",
3
+ "version": "1.0.29",
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",