n8n-nodes-tembory 1.0.16 → 1.0.18
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 +14 -1
- package/dist/nodes/Mem0/Mem0Memory.node.js +85 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,20 @@
|
|
|
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.18`.
|
|
6
|
+
|
|
7
|
+
## 1.0.18
|
|
8
|
+
|
|
9
|
+
- Corrige perguntas de metaconversa como "qual foi minha ultima mensagem?" para priorizar a mensagem recente exata, mesmo quando existe estado de agenda ativo.
|
|
10
|
+
- Corrige perguntas de status como "eu nao tinha agendado ainda, neh?" para responder se ha reserva/agendamento confirmado ou pendente, em vez de repetir disponibilidade.
|
|
11
|
+
- Inclui um bloco `Current turn focus` no contexto para proteger a intencao atual contra tool state antigo.
|
|
12
|
+
- Adiciona regressao para typos comuns como `agnedamento`/`ganedado` em perguntas de agenda.
|
|
13
|
+
|
|
14
|
+
## 1.0.17
|
|
15
|
+
|
|
16
|
+
- Oculta `Avançado Legado (Compatibilidade)` da interface normal para evitar duplicidade visual com `Configuração Tembory`.
|
|
17
|
+
- Mantem o campo legado no descriptor e no runtime para workflows antigos que ja salvaram parametros em `advanced`.
|
|
18
|
+
- A UI normal passa a mostrar apenas a configuracao agrupada.
|
|
6
19
|
|
|
7
20
|
## 1.0.16
|
|
8
21
|
|
|
@@ -1145,6 +1145,63 @@ const normalizeIntentText = (value = '') => String(value || '')
|
|
|
1145
1145
|
.normalize('NFD')
|
|
1146
1146
|
.replace(/[\u0300-\u036f]/g, '');
|
|
1147
1147
|
const hasConfirmIntent = (value = '') => /\b(confirm\w*|confim\w*|cnfirm\w*|cofnirm\w*|ocnfi\w*|ocnfia\w*|fechar)\b/.test(normalizeIntentText(value));
|
|
1148
|
+
const isConversationRecallQuery = (value = '') => {
|
|
1149
|
+
const text = normalizeIntentText(value);
|
|
1150
|
+
return /\b(minha|qual|quais|o que|oq|voce|vc|lembra|lembrar|sabe|diga|fala)\b.{0,80}\b(ultima|ultimas|mensagem|mensagens|pergunta|perguntei|falei|disse)\b/.test(text)
|
|
1151
|
+
|| /\b(o que|oq)\b.{0,30}\b(eu)\b.{0,30}\b(falei|disse|perguntei|mandei)\b/.test(text)
|
|
1152
|
+
|| /\b(nao|nao)\b.{0,20}\b(lembra|sabe)\b.{0,60}\b(mensagem|pergunta|falei|disse|perguntei)\b/.test(text);
|
|
1153
|
+
};
|
|
1154
|
+
const isAgendaStatusQuery = (value = '') => {
|
|
1155
|
+
const text = normalizeIntentText(value);
|
|
1156
|
+
return /\b(ja|ainda|tinha|tenho|foi|esta|ta)\b.{0,60}\b(agend\w*|agned\w*|ganed\w*|marc\w*|reserv\w*|confirm\w*)\b/.test(text)
|
|
1157
|
+
|| /\b(agend\w*|agned\w*|ganed\w*|marc\w*|reserv\w*|confirm\w*)\b.{0,60}\b(ja|ainda|feito|feita|confirmado|confirmada)\b/.test(text);
|
|
1158
|
+
};
|
|
1159
|
+
const recentUserMessages = (recentMessages = []) => [...(recentMessages || [])]
|
|
1160
|
+
.filter((msg) => /^(user|human)$/i.test(String(msg.role || '')))
|
|
1161
|
+
.reverse();
|
|
1162
|
+
const previousUserMessageForQuery = (query = '', recentMessages = []) => {
|
|
1163
|
+
const users = recentUserMessages(recentMessages);
|
|
1164
|
+
const normalizedQuery = normalizeIntentText(query).trim();
|
|
1165
|
+
const currentIndex = users.findIndex((msg) => normalizeIntentText(msg.content).trim() === normalizedQuery);
|
|
1166
|
+
if (currentIndex === 0)
|
|
1167
|
+
return users[1] || null;
|
|
1168
|
+
return users[0] || null;
|
|
1169
|
+
};
|
|
1170
|
+
const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalState = {}, workingMemory = {} }) => {
|
|
1171
|
+
const recall = isConversationRecallQuery(query);
|
|
1172
|
+
const agendaStatus = isAgendaStatusQuery(query);
|
|
1173
|
+
if (!recall && !agendaStatus)
|
|
1174
|
+
return null;
|
|
1175
|
+
const previousUser = previousUserMessageForQuery(query, recentMessages);
|
|
1176
|
+
const users = recentUserMessages(recentMessages)
|
|
1177
|
+
.filter((msg) => normalizeIntentText(msg.content).trim() !== normalizeIntentText(query).trim())
|
|
1178
|
+
.slice(0, 3)
|
|
1179
|
+
.map((msg) => ({ role: msg.role, content: truncate(msg.content, 500), at: msg.at }));
|
|
1180
|
+
const agenda = (operationalState || {}).agenda_state || {};
|
|
1181
|
+
return cleanContextValue({
|
|
1182
|
+
current_user_request: truncate(query, 500),
|
|
1183
|
+
intent: recall ? 'conversation_recall' : 'agenda_status_question',
|
|
1184
|
+
previous_user_message: previousUser ? truncate(previousUser.content, 500) : (workingMemory === null || workingMemory === void 0 ? void 0 : workingMemory.last_user_message) || null,
|
|
1185
|
+
recent_user_messages: users,
|
|
1186
|
+
agenda_status: agendaStatus ? {
|
|
1187
|
+
reservation_status: agenda.has_confirmation && !agenda.has_pending_pre_reservation
|
|
1188
|
+
? 'confirmed'
|
|
1189
|
+
: agenda.has_pending_pre_reservation
|
|
1190
|
+
? 'pending_pre_reservation'
|
|
1191
|
+
: agenda.has_pre_reservation
|
|
1192
|
+
? 'pre_reserved'
|
|
1193
|
+
: agenda.has_availability
|
|
1194
|
+
? 'availability_known_not_scheduled'
|
|
1195
|
+
: 'none',
|
|
1196
|
+
has_confirmation: Boolean(agenda.has_confirmation && !agenda.has_pending_pre_reservation),
|
|
1197
|
+
has_pending_pre_reservation: Boolean(agenda.has_pending_pre_reservation),
|
|
1198
|
+
has_availability: Boolean(agenda.has_availability),
|
|
1199
|
+
} : undefined,
|
|
1200
|
+
instruction: recall
|
|
1201
|
+
? 'Answer the user meta-question from previous_user_message/recent_user_messages. Do not answer with agenda availability unless the user asks for availability.'
|
|
1202
|
+
: '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.',
|
|
1203
|
+
});
|
|
1204
|
+
};
|
|
1148
1205
|
const inferToolGuard = ({ query, recentMessages, toolHistory, vectorMemories }) => {
|
|
1149
1206
|
const text = normalizeIntentText(query);
|
|
1150
1207
|
const names = new Set((toolHistory || []).map((tool) => String(tool.name || '')));
|
|
@@ -1174,6 +1231,10 @@ const inferUserIntent = (query = '', recentMessages = []) => {
|
|
|
1174
1231
|
const rawText = `${query || ''}\n${latestUser?.content || ''}`;
|
|
1175
1232
|
const text = normalizeIntentText(rawText);
|
|
1176
1233
|
const normalizedQuery = normalizeIntentText(query).trim();
|
|
1234
|
+
if (isConversationRecallQuery(query))
|
|
1235
|
+
return 'conversation_recall';
|
|
1236
|
+
if (isAgendaStatusQuery(query))
|
|
1237
|
+
return 'agenda_status_question';
|
|
1177
1238
|
if (/^(ok|sim|pode|pode sim|isso|isso mesmo|confirmo|confirmar)$/.test(normalizedQuery))
|
|
1178
1239
|
return 'affirm';
|
|
1179
1240
|
if (hasConfirmIntent(text))
|
|
@@ -1222,6 +1283,10 @@ const deriveNextExpectedAction = (intent, operationalState = {}) => {
|
|
|
1222
1283
|
return 'inspect current reservation state before changing or cancelling';
|
|
1223
1284
|
if (intent === 'profile_update')
|
|
1224
1285
|
return 'save stable profile facts and continue the conversation';
|
|
1286
|
+
if (intent === 'conversation_recall')
|
|
1287
|
+
return 'answer directly using recent_messages.previous_user_message; do not call agenda tools';
|
|
1288
|
+
if (intent === 'agenda_status_question')
|
|
1289
|
+
return 'answer whether there is a confirmed or pending reservation using operational_state; do not consult availability unless status is unknown';
|
|
1225
1290
|
return 'answer using retrieved context and avoid unnecessary tool calls';
|
|
1226
1291
|
};
|
|
1227
1292
|
const deriveWorkingMemory = ({ query = '', profileFacts = {}, recentMessages = [], toolHistory = [], operationalState = {}, previous = {} }) => {
|
|
@@ -1789,6 +1854,14 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1789
1854
|
: 'Use this context as read-only memory. Prefer it over guessing. Do not mention internal section names to the user. Treat next_expected_action as an instruction, not as a suggestion. If it says to call a tool now, call that tool instead of asking the user the same question again. If the user asks to continue, chooses a slot, says ok/sim, reserve, confirm, update, cancel, or performs any downstream action that depends on a prior tool result, first verify the required prior result in tool_history, recent_messages, or vector memories. If the required prior result is absent, do not call the downstream tool; ask for the missing context or call the appropriate prerequisite tool.',
|
|
1790
1855
|
});
|
|
1791
1856
|
}
|
|
1857
|
+
const currentTurnFocus = buildCurrentTurnFocus({ query, recentMessages, operationalState, workingMemory });
|
|
1858
|
+
if (currentTurnFocus) {
|
|
1859
|
+
sections.push({
|
|
1860
|
+
section: 'current_turn_focus',
|
|
1861
|
+
title: 'Current turn focus',
|
|
1862
|
+
value: currentTurnFocus,
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1792
1865
|
if (compactForAgent) {
|
|
1793
1866
|
if (includeSummary) {
|
|
1794
1867
|
const summary = compactVectorMemoriesForAgent(vectorMemories, toolHistory, Number(adv.summaryMaxFacts || 3));
|
|
@@ -1838,6 +1911,17 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
1838
1911
|
value: adv.includeMemoryCompression === false ? null : compactMemoryCompressionForAgent(memoryCompression || {}),
|
|
1839
1912
|
why_null: adv.includeMemoryCompression === false ? 'memory compression disabled' : undefined,
|
|
1840
1913
|
});
|
|
1914
|
+
if (adv.includeRecentMessages !== false || currentTurnFocus) {
|
|
1915
|
+
sections.push({
|
|
1916
|
+
section: 'recent_messages',
|
|
1917
|
+
title: 'Recent messages',
|
|
1918
|
+
value: pruneByLimit(recentMessages || [], adv.recentMessagesLastN || 4).map((message) => cleanContextValue({
|
|
1919
|
+
role: message.role,
|
|
1920
|
+
content: truncate(message.content, 260),
|
|
1921
|
+
at: message.at,
|
|
1922
|
+
})),
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1841
1925
|
const audit = {
|
|
1842
1926
|
kind: 'tembory.context.v1',
|
|
1843
1927
|
meta: { user_id: userId, payloadFormat, query, compact_for_agent: true },
|
|
@@ -2261,6 +2345,7 @@ class Mem0Memory {
|
|
|
2261
2345
|
type: 'collection',
|
|
2262
2346
|
placeholder: 'Opções',
|
|
2263
2347
|
default: {},
|
|
2348
|
+
displayOptions: { hide: { '/payloadFormat': ['structured', 'auditText', 'auditJson', 'auditBlocks', 'singleSystemMessage'] } },
|
|
2264
2349
|
description: 'Campos legados preservados para workflows existentes. Para novas configuracoes, use Configuração Tembory.',
|
|
2265
2350
|
options: [
|
|
2266
2351
|
{ displayName: 'User ID', name: 'userId', type: 'string', default: '' },
|
package/package.json
CHANGED