n8n-nodes-tembory 1.0.22 → 1.0.24
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 +12 -1
- package/dist/nodes/Mem0/Mem0Memory.node.js +52 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,18 @@
|
|
|
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.24`.
|
|
6
|
+
|
|
7
|
+
## 1.0.24
|
|
8
|
+
|
|
9
|
+
- Corrige falha `409 Backend LLM/embedder is disabled` no `saveContext` quando o node usa embeddings conectados pelo n8n.
|
|
10
|
+
- Writes legados de transcript/tool markers agora sao best-effort no modo BYO-AI, sem derrubar a execucao do agente.
|
|
11
|
+
- Remove o prefixo tecnico `THREAD:<id>` usado em testes MCP antes de montar query/contexto de memoria.
|
|
12
|
+
|
|
13
|
+
## 1.0.23
|
|
14
|
+
|
|
15
|
+
- Corrige o frame de conversa para nao repetir a mensagem atual em `previous_user_message` quando ainda nao existe mensagem anterior real.
|
|
16
|
+
- Mantem `previous_user_message: null` explicitamente em perguntas de recall no primeiro turno, evitando respostas erradas sobre "ultima mensagem".
|
|
6
17
|
|
|
7
18
|
## 1.0.22
|
|
8
19
|
|
|
@@ -70,6 +70,22 @@ const searchClientVectorMemories = async (ctx, embedding, query, body = {}) => {
|
|
|
70
70
|
embedding: await embedQueryCached(embedding, text),
|
|
71
71
|
});
|
|
72
72
|
};
|
|
73
|
+
const safePersistLegacyMemory = async (ctx, body, diagnostics = {}) => {
|
|
74
|
+
try {
|
|
75
|
+
return await GenericFunctions_1.mem0ApiRequest.call(ctx, 'POST', '/v1/memories/', body);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
try {
|
|
79
|
+
ctx.logger?.warn('Tembory skipped legacy memory write after BYO-AI vector persistence', {
|
|
80
|
+
...diagnostics,
|
|
81
|
+
message: error.message || String(error),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch { }
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const stripThreadTestPrefix = (value = '') => String(value || '').replace(/^THREAD:[A-Za-z0-9_-]+\s+/, '');
|
|
73
89
|
const stableStringify = (value) => {
|
|
74
90
|
if (value === null || typeof value !== 'object')
|
|
75
91
|
return JSON.stringify(value);
|
|
@@ -1177,19 +1193,30 @@ const previousUserMessageForQuery = (query = '', recentMessages = []) => {
|
|
|
1177
1193
|
return users[1] || null;
|
|
1178
1194
|
return users[0] || null;
|
|
1179
1195
|
};
|
|
1196
|
+
const previousUserFallbackFromWorkingMemory = (query = '', workingMemory = {}) => {
|
|
1197
|
+
const candidate = workingMemory === null || workingMemory === void 0 ? void 0 : workingMemory.last_user_message;
|
|
1198
|
+
if (!candidate)
|
|
1199
|
+
return null;
|
|
1200
|
+
const normalizedQuery = normalizeIntentText(query).trim();
|
|
1201
|
+
const normalizedCandidate = normalizeIntentText(candidate).trim();
|
|
1202
|
+
if (normalizedQuery && normalizedCandidate === normalizedQuery)
|
|
1203
|
+
return null;
|
|
1204
|
+
return candidate;
|
|
1205
|
+
};
|
|
1180
1206
|
const buildConversationFrame = ({ query = '', recentMessages = [], workingMemory = {} }) => {
|
|
1181
1207
|
const normalizedQuery = normalizeIntentText(query).trim();
|
|
1182
1208
|
const users = recentUserMessages(recentMessages);
|
|
1183
1209
|
const currentUser = users.find((msg) => normalizeIntentText(msg.content).trim() === normalizedQuery) || (query ? { role: 'user', content: query, at: nowIso() } : null);
|
|
1184
1210
|
const previousUser = previousUserMessageForQuery(query, recentMessages);
|
|
1211
|
+
const previousUserMessage = previousUser ? truncate(previousUser.content, 500) : previousUserFallbackFromWorkingMemory(query, workingMemory);
|
|
1185
1212
|
const chronological = pruneByLimit(recentMessages || [], 10).map((msg) => ({
|
|
1186
1213
|
role: msg.role,
|
|
1187
1214
|
content: truncate(msg.content, 500),
|
|
1188
1215
|
at: msg.at,
|
|
1189
1216
|
}));
|
|
1190
|
-
|
|
1217
|
+
const frame = cleanContextValue({
|
|
1191
1218
|
current_user_message: currentUser ? truncate(currentUser.content, 500) : truncate(query, 500),
|
|
1192
|
-
previous_user_message:
|
|
1219
|
+
previous_user_message: previousUserMessage,
|
|
1193
1220
|
recent_messages_chronological: chronological,
|
|
1194
1221
|
recent_user_messages: users
|
|
1195
1222
|
.filter((msg) => normalizeIntentText(msg.content).trim() !== normalizedQuery)
|
|
@@ -1197,6 +1224,9 @@ const buildConversationFrame = ({ query = '', recentMessages = [], workingMemory
|
|
|
1197
1224
|
.map((msg) => ({ role: msg.role, content: truncate(msg.content, 500), at: msg.at })),
|
|
1198
1225
|
instruction: 'This is the authoritative short-term conversation frame. If the user asks about the last/current/previous client message, answer from previous_user_message/recent_user_messages before using vector memories, summaries, operational state, or tool history.',
|
|
1199
1226
|
});
|
|
1227
|
+
if (!previousUserMessage)
|
|
1228
|
+
frame.previous_user_message = null;
|
|
1229
|
+
return frame;
|
|
1200
1230
|
};
|
|
1201
1231
|
const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalState = {}, workingMemory = {} }) => {
|
|
1202
1232
|
const recall = isConversationRecallQuery(query);
|
|
@@ -1209,10 +1239,11 @@ const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalSta
|
|
|
1209
1239
|
.slice(0, 3)
|
|
1210
1240
|
.map((msg) => ({ role: msg.role, content: truncate(msg.content, 500), at: msg.at }));
|
|
1211
1241
|
const agenda = (operationalState || {}).agenda_state || {};
|
|
1212
|
-
|
|
1242
|
+
const previousUserMessage = previousUser ? truncate(previousUser.content, 500) : previousUserFallbackFromWorkingMemory(query, workingMemory);
|
|
1243
|
+
const focus = cleanContextValue({
|
|
1213
1244
|
current_user_request: truncate(query, 500),
|
|
1214
1245
|
intent: recall ? 'conversation_recall' : 'agenda_status_question',
|
|
1215
|
-
previous_user_message:
|
|
1246
|
+
previous_user_message: previousUserMessage,
|
|
1216
1247
|
recent_user_messages: users,
|
|
1217
1248
|
agenda_status: agendaStatus ? {
|
|
1218
1249
|
reservation_status: agenda.has_confirmation && !agenda.has_pending_pre_reservation
|
|
@@ -1232,6 +1263,9 @@ const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalSta
|
|
|
1232
1263
|
? 'Answer the user meta-question from previous_user_message/recent_user_messages. Do not answer with agenda availability unless the user asks for availability.'
|
|
1233
1264
|
: '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.',
|
|
1234
1265
|
});
|
|
1266
|
+
if (!previousUserMessage)
|
|
1267
|
+
focus.previous_user_message = null;
|
|
1268
|
+
return focus;
|
|
1235
1269
|
};
|
|
1236
1270
|
const inferToolGuard = ({ query, recentMessages, toolHistory, vectorMemories }) => {
|
|
1237
1271
|
const text = normalizeIntentText(query);
|
|
@@ -2598,7 +2632,7 @@ class Mem0Memory {
|
|
|
2598
2632
|
const adv = applyOperationalPreset(readAdvancedOptions(this, itemIndex));
|
|
2599
2633
|
const store = getMemoryStore(this);
|
|
2600
2634
|
const key = userKeyFrom(threadId, adv, project);
|
|
2601
|
-
const input = pickText(inputValues, ['input', 'chatInput', 'text', 'query', 'question']);
|
|
2635
|
+
const input = stripThreadTestPrefix(pickText(inputValues, ['input', 'chatInput', 'text', 'query', 'question']));
|
|
2602
2636
|
const output = pickText(outputValues, ['output', 'response', 'text', 'answer']);
|
|
2603
2637
|
const toolCalls = extractToolCalls(outputValues);
|
|
2604
2638
|
const recentForMem0 = [];
|
|
@@ -2740,7 +2774,7 @@ class Mem0Memory {
|
|
|
2740
2774
|
await saveClientVectorMemories(this, clientMemories, ids);
|
|
2741
2775
|
if (adv.includeRecentMessages !== false && recentForMem0.length) {
|
|
2742
2776
|
for (const recent of recentForMem0) {
|
|
2743
|
-
await
|
|
2777
|
+
await safePersistLegacyMemory(this, {
|
|
2744
2778
|
messages: [{ role: 'system', content: encodeRecentMessage(recent, threadId) }],
|
|
2745
2779
|
infer: false,
|
|
2746
2780
|
user_id: body.user_id,
|
|
@@ -2755,12 +2789,15 @@ class Mem0Memory {
|
|
|
2755
2789
|
project: project || undefined,
|
|
2756
2790
|
source: 'tembory_transcript',
|
|
2757
2791
|
},
|
|
2792
|
+
}, {
|
|
2793
|
+
kind: 'recent_message',
|
|
2794
|
+
user_id: body.user_id,
|
|
2758
2795
|
});
|
|
2759
2796
|
}
|
|
2760
2797
|
}
|
|
2761
2798
|
if (adv.includeToolHistory !== false && toolCalls.length) {
|
|
2762
2799
|
for (const tool of toolCalls) {
|
|
2763
|
-
await
|
|
2800
|
+
await safePersistLegacyMemory(this, {
|
|
2764
2801
|
messages: [{ role: 'system', content: encodeToolCall(tool, threadId) }],
|
|
2765
2802
|
infer: false,
|
|
2766
2803
|
user_id: body.user_id,
|
|
@@ -2780,6 +2817,10 @@ class Mem0Memory {
|
|
|
2780
2817
|
thread_id: threadId,
|
|
2781
2818
|
project: project || undefined,
|
|
2782
2819
|
},
|
|
2820
|
+
}, {
|
|
2821
|
+
kind: 'tool_history',
|
|
2822
|
+
user_id: body.user_id,
|
|
2823
|
+
tool: tool.name,
|
|
2783
2824
|
});
|
|
2784
2825
|
}
|
|
2785
2826
|
}
|
|
@@ -2874,7 +2915,7 @@ class Mem0Memory {
|
|
|
2874
2915
|
const store = getMemoryStore(this);
|
|
2875
2916
|
const key = userKeyFrom(threadId, adv, project);
|
|
2876
2917
|
const queryParam = this.getNodeParameter('query', itemIndex, '');
|
|
2877
|
-
const query = asSearchQuery(queryParam) || asSearchQuery(inputValues.query) || asSearchQuery(inputValues.input) || asSearchQuery(inputValues.chatInput);
|
|
2918
|
+
const query = stripThreadTestPrefix(asSearchQuery(queryParam) || asSearchQuery(inputValues.query) || asSearchQuery(inputValues.input) || asSearchQuery(inputValues.chatInput));
|
|
2878
2919
|
let connectedLanguageModel;
|
|
2879
2920
|
let connectedEmbedding;
|
|
2880
2921
|
const connectedAi = {
|
|
@@ -3487,6 +3528,7 @@ exports.__private = {
|
|
|
3487
3528
|
explicitToolHistoryItemsFromMemory,
|
|
3488
3529
|
toolHistoryFromMemory,
|
|
3489
3530
|
recentMessageFromMemory,
|
|
3531
|
+
previousUserFallbackFromWorkingMemory,
|
|
3490
3532
|
dedupeToolHistory,
|
|
3491
3533
|
applyToolHistoryWindow,
|
|
3492
3534
|
dedupeRecentMessages,
|
|
@@ -3498,6 +3540,8 @@ exports.__private = {
|
|
|
3498
3540
|
applyOperationalPreset,
|
|
3499
3541
|
flattenAdvancedGroups,
|
|
3500
3542
|
asSearchQuery,
|
|
3543
|
+
safePersistLegacyMemory,
|
|
3544
|
+
stripThreadTestPrefix,
|
|
3501
3545
|
canonicalToolInput,
|
|
3502
3546
|
buildContextMessages,
|
|
3503
3547
|
inferToolGuard,
|
package/package.json
CHANGED