n8n-nodes-tembory 1.0.21 → 1.0.23
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 +93 -4
- 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.23`.
|
|
6
|
+
|
|
7
|
+
## 1.0.23
|
|
8
|
+
|
|
9
|
+
- Corrige o frame de conversa para nao repetir a mensagem atual em `previous_user_message` quando ainda nao existe mensagem anterior real.
|
|
10
|
+
- Mantem `previous_user_message: null` explicitamente em perguntas de recall no primeiro turno, evitando respostas erradas sobre "ultima mensagem".
|
|
11
|
+
|
|
12
|
+
## 1.0.22
|
|
13
|
+
|
|
14
|
+
- Corrige persistencia do transcript quando ha embedding conectado: mensagens recentes tambem sao gravadas como markers estruturados em `/v1/memories/`.
|
|
15
|
+
- Persiste tool history estruturado por padrao quando `includeToolHistory` esta ativo, mesmo sem `persistToolFactsToMem0`.
|
|
16
|
+
- Resolve falha real em n8n onde cada execucao carregava apenas a mensagem atual no `Conversation frame`.
|
|
6
17
|
|
|
7
18
|
## 1.0.21
|
|
8
19
|
|
|
@@ -1177,19 +1177,30 @@ const previousUserMessageForQuery = (query = '', recentMessages = []) => {
|
|
|
1177
1177
|
return users[1] || null;
|
|
1178
1178
|
return users[0] || null;
|
|
1179
1179
|
};
|
|
1180
|
+
const previousUserFallbackFromWorkingMemory = (query = '', workingMemory = {}) => {
|
|
1181
|
+
const candidate = workingMemory === null || workingMemory === void 0 ? void 0 : workingMemory.last_user_message;
|
|
1182
|
+
if (!candidate)
|
|
1183
|
+
return null;
|
|
1184
|
+
const normalizedQuery = normalizeIntentText(query).trim();
|
|
1185
|
+
const normalizedCandidate = normalizeIntentText(candidate).trim();
|
|
1186
|
+
if (normalizedQuery && normalizedCandidate === normalizedQuery)
|
|
1187
|
+
return null;
|
|
1188
|
+
return candidate;
|
|
1189
|
+
};
|
|
1180
1190
|
const buildConversationFrame = ({ query = '', recentMessages = [], workingMemory = {} }) => {
|
|
1181
1191
|
const normalizedQuery = normalizeIntentText(query).trim();
|
|
1182
1192
|
const users = recentUserMessages(recentMessages);
|
|
1183
1193
|
const currentUser = users.find((msg) => normalizeIntentText(msg.content).trim() === normalizedQuery) || (query ? { role: 'user', content: query, at: nowIso() } : null);
|
|
1184
1194
|
const previousUser = previousUserMessageForQuery(query, recentMessages);
|
|
1195
|
+
const previousUserMessage = previousUser ? truncate(previousUser.content, 500) : previousUserFallbackFromWorkingMemory(query, workingMemory);
|
|
1185
1196
|
const chronological = pruneByLimit(recentMessages || [], 10).map((msg) => ({
|
|
1186
1197
|
role: msg.role,
|
|
1187
1198
|
content: truncate(msg.content, 500),
|
|
1188
1199
|
at: msg.at,
|
|
1189
1200
|
}));
|
|
1190
|
-
|
|
1201
|
+
const frame = cleanContextValue({
|
|
1191
1202
|
current_user_message: currentUser ? truncate(currentUser.content, 500) : truncate(query, 500),
|
|
1192
|
-
previous_user_message:
|
|
1203
|
+
previous_user_message: previousUserMessage,
|
|
1193
1204
|
recent_messages_chronological: chronological,
|
|
1194
1205
|
recent_user_messages: users
|
|
1195
1206
|
.filter((msg) => normalizeIntentText(msg.content).trim() !== normalizedQuery)
|
|
@@ -1197,6 +1208,9 @@ const buildConversationFrame = ({ query = '', recentMessages = [], workingMemory
|
|
|
1197
1208
|
.map((msg) => ({ role: msg.role, content: truncate(msg.content, 500), at: msg.at })),
|
|
1198
1209
|
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
1210
|
});
|
|
1211
|
+
if (!previousUserMessage)
|
|
1212
|
+
frame.previous_user_message = null;
|
|
1213
|
+
return frame;
|
|
1200
1214
|
};
|
|
1201
1215
|
const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalState = {}, workingMemory = {} }) => {
|
|
1202
1216
|
const recall = isConversationRecallQuery(query);
|
|
@@ -1209,10 +1223,11 @@ const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalSta
|
|
|
1209
1223
|
.slice(0, 3)
|
|
1210
1224
|
.map((msg) => ({ role: msg.role, content: truncate(msg.content, 500), at: msg.at }));
|
|
1211
1225
|
const agenda = (operationalState || {}).agenda_state || {};
|
|
1212
|
-
|
|
1226
|
+
const previousUserMessage = previousUser ? truncate(previousUser.content, 500) : previousUserFallbackFromWorkingMemory(query, workingMemory);
|
|
1227
|
+
const focus = cleanContextValue({
|
|
1213
1228
|
current_user_request: truncate(query, 500),
|
|
1214
1229
|
intent: recall ? 'conversation_recall' : 'agenda_status_question',
|
|
1215
|
-
previous_user_message:
|
|
1230
|
+
previous_user_message: previousUserMessage,
|
|
1216
1231
|
recent_user_messages: users,
|
|
1217
1232
|
agenda_status: agendaStatus ? {
|
|
1218
1233
|
reservation_status: agenda.has_confirmation && !agenda.has_pending_pre_reservation
|
|
@@ -1232,6 +1247,9 @@ const buildCurrentTurnFocus = ({ query = '', recentMessages = [], operationalSta
|
|
|
1232
1247
|
? '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
1248
|
: '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
1249
|
});
|
|
1250
|
+
if (!previousUserMessage)
|
|
1251
|
+
focus.previous_user_message = null;
|
|
1252
|
+
return focus;
|
|
1235
1253
|
};
|
|
1236
1254
|
const inferToolGuard = ({ query, recentMessages, toolHistory, vectorMemories }) => {
|
|
1237
1255
|
const text = normalizeIntentText(query);
|
|
@@ -2738,6 +2756,51 @@ class Mem0Memory {
|
|
|
2738
2756
|
}
|
|
2739
2757
|
}
|
|
2740
2758
|
await saveClientVectorMemories(this, clientMemories, ids);
|
|
2759
|
+
if (adv.includeRecentMessages !== false && recentForMem0.length) {
|
|
2760
|
+
for (const recent of recentForMem0) {
|
|
2761
|
+
await GenericFunctions_1.mem0ApiRequest.call(this, 'POST', '/v1/memories/', {
|
|
2762
|
+
messages: [{ role: 'system', content: encodeRecentMessage(recent, threadId) }],
|
|
2763
|
+
infer: false,
|
|
2764
|
+
user_id: body.user_id,
|
|
2765
|
+
agent_id: body.agent_id,
|
|
2766
|
+
run_id: body.run_id,
|
|
2767
|
+
metadata: {
|
|
2768
|
+
kind: 'recent_message',
|
|
2769
|
+
role: recent.role,
|
|
2770
|
+
content: recent.content,
|
|
2771
|
+
at: recent.at,
|
|
2772
|
+
thread_id: threadId,
|
|
2773
|
+
project: project || undefined,
|
|
2774
|
+
source: 'tembory_transcript',
|
|
2775
|
+
},
|
|
2776
|
+
});
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
if (adv.includeToolHistory !== false && toolCalls.length) {
|
|
2780
|
+
for (const tool of toolCalls) {
|
|
2781
|
+
await GenericFunctions_1.mem0ApiRequest.call(this, 'POST', '/v1/memories/', {
|
|
2782
|
+
messages: [{ role: 'system', content: encodeToolCall(tool, threadId) }],
|
|
2783
|
+
infer: false,
|
|
2784
|
+
user_id: body.user_id,
|
|
2785
|
+
agent_id: body.agent_id,
|
|
2786
|
+
run_id: body.run_id,
|
|
2787
|
+
metadata: {
|
|
2788
|
+
kind: 'tool_history',
|
|
2789
|
+
id: tool.id,
|
|
2790
|
+
sequence: tool.sequence,
|
|
2791
|
+
turn_id: tool.turnId,
|
|
2792
|
+
name: tool.name,
|
|
2793
|
+
input: tool.input,
|
|
2794
|
+
ok: tool.ok,
|
|
2795
|
+
result: tool.result,
|
|
2796
|
+
at: tool.at,
|
|
2797
|
+
source: tool.source || 'tembory_transcript',
|
|
2798
|
+
thread_id: threadId,
|
|
2799
|
+
project: project || undefined,
|
|
2800
|
+
},
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2741
2804
|
return;
|
|
2742
2805
|
}
|
|
2743
2806
|
await GenericFunctions_1.mem0ApiRequest.call(this, 'POST', '/v1/memories/', body);
|
|
@@ -2760,6 +2823,31 @@ class Mem0Memory {
|
|
|
2760
2823
|
});
|
|
2761
2824
|
}
|
|
2762
2825
|
}
|
|
2826
|
+
if (adv.includeToolHistory !== false && !adv.persistToolFactsToMem0 && toolCalls.length) {
|
|
2827
|
+
for (const tool of toolCalls) {
|
|
2828
|
+
await GenericFunctions_1.mem0ApiRequest.call(this, 'POST', '/v1/memories/', {
|
|
2829
|
+
messages: [{ role: 'system', content: encodeToolCall(tool, threadId) }],
|
|
2830
|
+
infer: false,
|
|
2831
|
+
user_id: body.user_id,
|
|
2832
|
+
agent_id: body.agent_id,
|
|
2833
|
+
run_id: body.run_id,
|
|
2834
|
+
metadata: {
|
|
2835
|
+
kind: 'tool_history',
|
|
2836
|
+
id: tool.id,
|
|
2837
|
+
sequence: tool.sequence,
|
|
2838
|
+
turn_id: tool.turnId,
|
|
2839
|
+
name: tool.name,
|
|
2840
|
+
input: tool.input,
|
|
2841
|
+
ok: tool.ok,
|
|
2842
|
+
result: tool.result,
|
|
2843
|
+
at: tool.at,
|
|
2844
|
+
source: tool.source || 'tembory_transcript',
|
|
2845
|
+
thread_id: threadId,
|
|
2846
|
+
project: project || undefined,
|
|
2847
|
+
},
|
|
2848
|
+
});
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2763
2851
|
if (adv.persistToolFactsToMem0 && toolCalls.length) {
|
|
2764
2852
|
const facts = toolCalls.map((tool) => `Tool ${tool.name} input=${tool.input}${tool.result ? ` result=${tool.result}` : ''}`).join('\n');
|
|
2765
2853
|
await GenericFunctions_1.mem0ApiRequest.call(this, 'POST', '/v1/memories/', {
|
|
@@ -3417,6 +3505,7 @@ exports.__private = {
|
|
|
3417
3505
|
explicitToolHistoryItemsFromMemory,
|
|
3418
3506
|
toolHistoryFromMemory,
|
|
3419
3507
|
recentMessageFromMemory,
|
|
3508
|
+
previousUserFallbackFromWorkingMemory,
|
|
3420
3509
|
dedupeToolHistory,
|
|
3421
3510
|
applyToolHistoryWindow,
|
|
3422
3511
|
dedupeRecentMessages,
|
package/package.json
CHANGED