n8n-nodes-tembory 1.0.29 → 1.0.31
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 +13 -1
- package/dist/nodes/Mem0/Mem0Memory.node.js +68 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Node de memoria operacional da Tembory para agentes de IA no n8n.
|
|
4
4
|
|
|
5
|
-
Versao atual: `1.0.
|
|
5
|
+
Versao atual: `1.0.31`.
|
|
6
|
+
|
|
7
|
+
## 1.0.31
|
|
8
|
+
|
|
9
|
+
- Considera pre-reserva recente no transcript como estado operacional valido quando `tool_history` ainda nao foi recuperado no turno.
|
|
10
|
+
- Evita chamar `agenda_pre_reservar_horario` novamente antes de confirmar quando a mensagem recente ja diz que houve pre-reserva.
|
|
11
|
+
- Direciona confirmacoes como "pode confirmar" direto para `agenda_confirmar_agendamento` quando existe pre-reserva recente pendente.
|
|
12
|
+
|
|
13
|
+
## 1.0.30
|
|
14
|
+
|
|
15
|
+
- Adiciona `Action directive` quando a memoria conclui que uma tool deve ser chamada no turno atual.
|
|
16
|
+
- Torna `next_expected_action` mais coercitivo para agenda: usa `MUST call ...` e proibe respostas como "se quiser/posso" no lugar da tool obrigatoria.
|
|
17
|
+
- Reduz o peso instrucional de `first_user_message`; o foco passa a ser mensagem atual, mensagem anterior e transcript cronologico recente.
|
|
6
18
|
|
|
7
19
|
## 1.0.29
|
|
8
20
|
|
|
@@ -427,6 +427,25 @@ const availabilityFromRecentMessages = (recentMessages = []) => {
|
|
|
427
427
|
source: latest.source || 'recent_message',
|
|
428
428
|
};
|
|
429
429
|
};
|
|
430
|
+
const preReservationFromRecentMessages = (recentMessages = []) => {
|
|
431
|
+
const messages = Array.isArray(recentMessages) ? recentMessages : [];
|
|
432
|
+
const candidates = [...messages].reverse().filter((message) => {
|
|
433
|
+
const role = String(message.role || '').toLowerCase();
|
|
434
|
+
const text = String(message.content || message.text || message.memory || '');
|
|
435
|
+
if (role && role !== 'assistant' && role !== 'ai' && role !== 'system')
|
|
436
|
+
return false;
|
|
437
|
+
return /\b(pr[eé][-\s]?reservad[oa]|pre[-\s]?reservad[oa]|reservation_id|RES-[A-Z0-9-]+)\b/i.test(text)
|
|
438
|
+
&& !/\b(confirmad[oa]|confirmation_id|CONF-[A-Z0-9-]+)\b/i.test(text);
|
|
439
|
+
});
|
|
440
|
+
const latest = candidates[0];
|
|
441
|
+
if (!latest)
|
|
442
|
+
return null;
|
|
443
|
+
return {
|
|
444
|
+
text: truncate(String(latest.content || latest.text || latest.memory || ''), 900),
|
|
445
|
+
at: latest.at || latest.created_at || latest.createdAt || nowIso(),
|
|
446
|
+
source: latest.source || 'recent_message',
|
|
447
|
+
};
|
|
448
|
+
};
|
|
430
449
|
const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessages = [], includeResults = true) => {
|
|
431
450
|
const tools = Array.isArray(toolHistory) ? toolHistory : [];
|
|
432
451
|
const successfulTools = tools.filter((tool) => tool.ok !== false);
|
|
@@ -435,15 +454,17 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
435
454
|
const recentAvailability = availability.length ? null : availabilityFromRecentMessages(recentMessages);
|
|
436
455
|
const hasAvailability = availability.length > 0 || Boolean(recentAvailability);
|
|
437
456
|
const reservations = byName('agenda_pre_reservar_horario');
|
|
457
|
+
const recentPreReservation = reservations.length ? null : preReservationFromRecentMessages(recentMessages);
|
|
458
|
+
const hasPreReservation = reservations.length > 0 || Boolean(recentPreReservation);
|
|
438
459
|
const confirmations = byName('agenda_confirmar_agendamento');
|
|
439
460
|
const lastTool = tools[tools.length - 1] || null;
|
|
440
461
|
const lastReservation = reservations[reservations.length - 1] || null;
|
|
441
462
|
const lastConfirmation = confirmations[confirmations.length - 1] || null;
|
|
442
|
-
const hasPendingReservation = Boolean(lastReservation && (!lastConfirmation || String(lastReservation.at || '') > String(lastConfirmation.at || '')));
|
|
463
|
+
const hasPendingReservation = Boolean((lastReservation && (!lastConfirmation || String(lastReservation.at || '') > String(lastConfirmation.at || ''))) || (recentPreReservation && !lastConfirmation));
|
|
443
464
|
const blockedWithoutContext = [];
|
|
444
465
|
if (!hasAvailability)
|
|
445
466
|
blockedWithoutContext.push('agenda_pre_reservar_horario');
|
|
446
|
-
if (!
|
|
467
|
+
if (!hasPreReservation)
|
|
447
468
|
blockedWithoutContext.push('agenda_confirmar_agendamento');
|
|
448
469
|
const guidance = [];
|
|
449
470
|
if (!hasAvailability)
|
|
@@ -467,12 +488,13 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
467
488
|
},
|
|
468
489
|
agenda_state: {
|
|
469
490
|
has_availability: hasAvailability,
|
|
470
|
-
has_pre_reservation:
|
|
491
|
+
has_pre_reservation: hasPreReservation,
|
|
471
492
|
has_confirmation: confirmations.length > 0,
|
|
472
493
|
has_pending_pre_reservation: hasPendingReservation,
|
|
473
494
|
latest_availability_result: availability.length ? maybeToolResult(availability[availability.length - 1], includeResults) : (recentAvailability && includeResults !== false ? recentAvailability.text : null),
|
|
474
495
|
latest_availability_source: availability.length ? 'tool_history' : (recentAvailability ? recentAvailability.source : null),
|
|
475
|
-
latest_pre_reservation_result: lastReservation ? maybeToolResult(lastReservation, includeResults) : null,
|
|
496
|
+
latest_pre_reservation_result: lastReservation ? maybeToolResult(lastReservation, includeResults) : (recentPreReservation && includeResults !== false ? recentPreReservation.text : null),
|
|
497
|
+
latest_pre_reservation_source: lastReservation ? 'tool_history' : (recentPreReservation ? recentPreReservation.source : null),
|
|
476
498
|
latest_confirmation_result: lastConfirmation ? maybeToolResult(lastConfirmation, includeResults) : null,
|
|
477
499
|
},
|
|
478
500
|
blocked_without_context: Array.from(new Set(blockedWithoutContext)),
|
|
@@ -1306,7 +1328,7 @@ const buildConversationFrame = ({ query = '', recentMessages = [], workingMemory
|
|
|
1306
1328
|
.filter((msg) => normalizeIntentText(msg.content).trim() !== normalizedQuery)
|
|
1307
1329
|
.slice(0, 5)
|
|
1308
1330
|
.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
|
|
1331
|
+
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
1332
|
});
|
|
1311
1333
|
if (!previousUserMessage)
|
|
1312
1334
|
frame.previous_user_message = null;
|
|
@@ -1346,13 +1368,33 @@ const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalSta
|
|
|
1346
1368
|
has_availability: Boolean(agenda.has_availability),
|
|
1347
1369
|
} : undefined,
|
|
1348
1370
|
instruction: recall
|
|
1349
|
-
? 'Answer the user meta-question from
|
|
1371
|
+
? '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
1372
|
: '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
1373
|
});
|
|
1352
1374
|
if (!previousUserMessage)
|
|
1353
1375
|
focus.previous_user_message = null;
|
|
1354
1376
|
return focus;
|
|
1355
1377
|
};
|
|
1378
|
+
const buildActionDirective = ({ workingMemory = {}, operationalState = {} }) => {
|
|
1379
|
+
const next = String((workingMemory || {}).next_expected_action || '');
|
|
1380
|
+
const match = /\bagenda_(consultar_disponibilidade|pre_reservar_horario|confirmar_agendamento)\b/.exec(next);
|
|
1381
|
+
if (!match || !/\bcall\b|\bMUST\b/i.test(next))
|
|
1382
|
+
return null;
|
|
1383
|
+
const tool = match[0];
|
|
1384
|
+
const agenda = (operationalState || {}).agenda_state || {};
|
|
1385
|
+
return cleanContextValue({
|
|
1386
|
+
required_tool: tool,
|
|
1387
|
+
next_expected_action: next,
|
|
1388
|
+
agenda_state: {
|
|
1389
|
+
has_availability: Boolean(agenda.has_availability),
|
|
1390
|
+
latest_availability_source: agenda.latest_availability_source,
|
|
1391
|
+
has_pre_reservation: Boolean(agenda.has_pre_reservation),
|
|
1392
|
+
has_pending_pre_reservation: Boolean(agenda.has_pending_pre_reservation),
|
|
1393
|
+
has_confirmation: Boolean(agenda.has_confirmation),
|
|
1394
|
+
},
|
|
1395
|
+
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.`,
|
|
1396
|
+
});
|
|
1397
|
+
};
|
|
1356
1398
|
const inferToolGuard = ({ query, recentMessages, toolHistory, vectorMemories }) => {
|
|
1357
1399
|
const text = normalizeIntentText(query);
|
|
1358
1400
|
const names = new Set((toolHistory || []).map((tool) => String(tool.name || '')));
|
|
@@ -1408,24 +1450,26 @@ const deriveNextExpectedAction = (intent, operationalState = {}) => {
|
|
|
1408
1450
|
const agenda = operationalState.agenda_state || {};
|
|
1409
1451
|
if (intent === 'affirm') {
|
|
1410
1452
|
if (agenda.has_pending_pre_reservation)
|
|
1411
|
-
return 'call agenda_confirmar_agendamento now; do not ask the same confirmation question again';
|
|
1453
|
+
return 'MUST call agenda_confirmar_agendamento now; do not ask the same confirmation question again';
|
|
1412
1454
|
if (agenda.has_availability)
|
|
1413
|
-
return 'call agenda_pre_reservar_horario now using the selected or latest discussed slot; do not ask again';
|
|
1455
|
+
return 'MUST call agenda_pre_reservar_horario now using the selected or latest discussed slot; do not ask again';
|
|
1414
1456
|
return 'call agenda_consultar_disponibilidade before reserving';
|
|
1415
1457
|
}
|
|
1416
1458
|
if (intent === 'confirm') {
|
|
1417
1459
|
if (agenda.has_pending_pre_reservation)
|
|
1418
|
-
return 'call agenda_confirmar_agendamento now using the latest pre-reservation context; do not ask again';
|
|
1419
|
-
|
|
1460
|
+
return 'MUST call agenda_confirmar_agendamento now using the latest pre-reservation context; do not ask again';
|
|
1461
|
+
if (agenda.has_availability)
|
|
1462
|
+
return 'MUST call agenda_pre_reservar_horario first using the selected or latest discussed slot; do not ask for permission again';
|
|
1463
|
+
return 'do not call agenda_confirmar_agendamento; call agenda_consultar_disponibilidade first because no availability is known';
|
|
1420
1464
|
}
|
|
1421
1465
|
if (intent === 'select_slot') {
|
|
1422
1466
|
if (agenda.has_availability)
|
|
1423
|
-
return 'call agenda_pre_reservar_horario now using the selected slot; do not ask for confirmation before pre-reserving';
|
|
1467
|
+
return 'MUST call agenda_pre_reservar_horario now using the selected slot; do not ask for confirmation before pre-reserving';
|
|
1424
1468
|
return 'call agenda_consultar_disponibilidade before pre-reserving';
|
|
1425
1469
|
}
|
|
1426
1470
|
if (intent === 'pre_reserve') {
|
|
1427
1471
|
if (agenda.has_availability)
|
|
1428
|
-
return 'call agenda_pre_reservar_horario now using one of the known available slots';
|
|
1472
|
+
return 'MUST call agenda_pre_reservar_horario now using one of the known available slots';
|
|
1429
1473
|
return 'call agenda_consultar_disponibilidade before pre-reserving';
|
|
1430
1474
|
}
|
|
1431
1475
|
if (intent === 'check_availability')
|
|
@@ -2010,8 +2054,8 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
2010
2054
|
sections.push({
|
|
2011
2055
|
section: 'conversation_frame',
|
|
2012
2056
|
title: 'Conversation frame',
|
|
2013
|
-
|
|
2014
|
-
|
|
2057
|
+
value: buildConversationFrame({ query, recentMessages, workingMemory }),
|
|
2058
|
+
});
|
|
2015
2059
|
const currentTurnFocus = buildCurrentTurnFocus({ query, recentMessages, operationalState, workingMemory });
|
|
2016
2060
|
if (currentTurnFocus) {
|
|
2017
2061
|
sections.push({
|
|
@@ -2020,6 +2064,14 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
2020
2064
|
value: currentTurnFocus,
|
|
2021
2065
|
});
|
|
2022
2066
|
}
|
|
2067
|
+
const actionDirective = buildActionDirective({ workingMemory, operationalState });
|
|
2068
|
+
if (actionDirective) {
|
|
2069
|
+
sections.push({
|
|
2070
|
+
section: 'action_directive',
|
|
2071
|
+
title: 'Action directive',
|
|
2072
|
+
value: actionDirective,
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2023
2075
|
if (compactForAgent) {
|
|
2024
2076
|
if (includeSummary) {
|
|
2025
2077
|
const summary = compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.summaryMaxFacts || 3));
|
|
@@ -3661,6 +3713,8 @@ exports.__private = {
|
|
|
3661
3713
|
toolHistoryFromMemory,
|
|
3662
3714
|
cleanAssistantTranscriptText,
|
|
3663
3715
|
availabilityFromRecentMessages,
|
|
3716
|
+
preReservationFromRecentMessages,
|
|
3717
|
+
buildActionDirective,
|
|
3664
3718
|
recentMessageFromMemory,
|
|
3665
3719
|
previousUserFallbackFromWorkingMemory,
|
|
3666
3720
|
firstUserMessageFromConversation,
|
package/package.json
CHANGED