@@ -30,7 +30,7 @@ class Mem0_Memory implements INode {
30
30
constructor ( ) {
31
31
this . label = 'Mem0'
32
32
this . name = 'mem0'
33
- this . version = 1.0
33
+ this . version = 1.1
34
34
this . type = 'Mem0'
35
35
this . icon = 'mem0.svg'
36
36
this . category = 'Memory'
@@ -49,9 +49,18 @@ class Mem0_Memory implements INode {
49
49
label : 'User ID' ,
50
50
name : 'user_id' ,
51
51
type : 'string' ,
52
- description : 'Unique identifier for the user' ,
52
+ description : 'Unique identifier for the user. Required only if "Use Flowise Chat ID" is OFF. ' ,
53
53
default : 'flowise-default-user' ,
54
- optional : false
54
+ optional : true
55
+ } ,
56
+ // Added toggle to use Flowise chat ID
57
+ {
58
+ label : 'Use Flowise Chat ID' ,
59
+ name : 'useFlowiseChatId' ,
60
+ type : 'boolean' ,
61
+ description : 'Use the Flowise internal Chat ID as the Mem0 User ID, overriding the "User ID" field above.' ,
62
+ default : false ,
63
+ optional : true
55
64
} ,
56
65
{
57
66
label : 'Search Only' ,
@@ -140,9 +149,11 @@ class Mem0_Memory implements INode {
140
149
}
141
150
142
151
const initializeMem0 = async ( nodeData : INodeData , options : ICommonObject ) : Promise < BaseMem0Memory > => {
143
- const userId = nodeData . inputs ?. user_id as string
144
- if ( ! userId ) {
145
- throw new Error ( 'user_id is required for Mem0Memory' )
152
+ const initialUserId = nodeData . inputs ?. user_id as string
153
+ const useFlowiseChatId = nodeData . inputs ?. useFlowiseChatId as boolean
154
+
155
+ if ( ! useFlowiseChatId && ! initialUserId ) {
156
+ throw new Error ( 'User ID field cannot be empty when "Use Flowise Chat ID" is OFF.' )
146
157
}
147
158
148
159
const credentialData = await getCredentialData ( nodeData . credential ?? '' , options )
@@ -155,8 +166,12 @@ const initializeMem0 = async (nodeData: INodeData, options: ICommonObject): Prom
155
166
projectId : nodeData . inputs ?. project_id as string
156
167
}
157
168
169
+ const memOptionsUserId = initialUserId
170
+
171
+ const constructorSessionId = initialUserId || ( useFlowiseChatId ? 'flowise-chat-id-placeholder' : '' )
172
+
158
173
const memoryOptions : MemoryOptions & SearchOptions = {
159
- user_id : userId ,
174
+ user_id : memOptionsUserId ,
160
175
run_id : ( nodeData . inputs ?. run_id as string ) || undefined ,
161
176
agent_id : ( nodeData . inputs ?. agent_id as string ) || undefined ,
162
177
app_id : ( nodeData . inputs ?. app_id as string ) || undefined ,
@@ -168,69 +183,106 @@ const initializeMem0 = async (nodeData: INodeData, options: ICommonObject): Prom
168
183
filters : ( nodeData . inputs ?. filters as Record < string , any > ) || { }
169
184
}
170
185
171
- const obj : Mem0MemoryInput & Mem0MemoryExtendedInput & BufferMemoryExtendedInput & { searchOnly : boolean } = {
172
- apiKey : apiKey ,
173
- humanPrefix : nodeData . inputs ?. humanPrefix as string ,
174
- aiPrefix : nodeData . inputs ?. aiPrefix as string ,
175
- inputKey : nodeData . inputs ?. inputKey as string ,
176
- sessionId : nodeData . inputs ?. user_id as string ,
177
- mem0Options : mem0Options ,
178
- memoryOptions : memoryOptions ,
179
- separateMessages : false ,
180
- returnMessages : false ,
181
- appDataSource : options . appDataSource as DataSource ,
182
- databaseEntities : options . databaseEntities as IDatabaseEntity ,
183
- chatflowid : options . chatflowid as string ,
184
- searchOnly : ( nodeData . inputs ?. searchOnly as boolean ) || false
185
- }
186
+ const obj : Mem0MemoryInput & Mem0MemoryExtendedInput & BufferMemoryExtendedInput & { searchOnly : boolean ; useFlowiseChatId : boolean } =
187
+ {
188
+ apiKey : apiKey ,
189
+ humanPrefix : nodeData . inputs ?. humanPrefix as string ,
190
+ aiPrefix : nodeData . inputs ?. aiPrefix as string ,
191
+ inputKey : nodeData . inputs ?. inputKey as string ,
192
+ sessionId : constructorSessionId ,
193
+ mem0Options : mem0Options ,
194
+ memoryOptions : memoryOptions ,
195
+ separateMessages : false ,
196
+ returnMessages : false ,
197
+ appDataSource : options . appDataSource as DataSource ,
198
+ databaseEntities : options . databaseEntities as IDatabaseEntity ,
199
+ chatflowid : options . chatflowid as string ,
200
+ searchOnly : ( nodeData . inputs ?. searchOnly as boolean ) || false ,
201
+ useFlowiseChatId : useFlowiseChatId
202
+ }
186
203
187
204
return new Mem0MemoryExtended ( obj )
188
205
}
189
206
190
207
interface Mem0MemoryExtendedInput extends Mem0MemoryInput {
191
208
memoryOptions ?: MemoryOptions | SearchOptions
209
+ useFlowiseChatId : boolean
192
210
}
193
211
194
212
class Mem0MemoryExtended extends BaseMem0Memory implements MemoryMethods {
213
+ initialUserId : string
195
214
userId : string
196
215
memoryKey : string
197
216
inputKey : string
198
217
appDataSource : DataSource
199
218
databaseEntities : IDatabaseEntity
200
219
chatflowid : string
201
220
searchOnly : boolean
221
+ useFlowiseChatId : boolean
202
222
203
- constructor ( fields : Mem0MemoryInput & Mem0MemoryExtendedInput & BufferMemoryExtendedInput & { searchOnly : boolean } ) {
223
+ constructor (
224
+ fields : Mem0MemoryInput & Mem0MemoryExtendedInput & BufferMemoryExtendedInput & { searchOnly : boolean ; useFlowiseChatId : boolean }
225
+ ) {
204
226
super ( fields )
205
- this . userId = fields . memoryOptions ?. user_id ?? ''
227
+ this . initialUserId = fields . memoryOptions ?. user_id ?? ''
228
+ this . userId = this . initialUserId
206
229
this . memoryKey = 'history'
207
230
this . inputKey = fields . inputKey ?? 'input'
208
231
this . appDataSource = fields . appDataSource
209
232
this . databaseEntities = fields . databaseEntities
210
233
this . chatflowid = fields . chatflowid
211
234
this . searchOnly = fields . searchOnly
235
+ this . useFlowiseChatId = fields . useFlowiseChatId
236
+ }
237
+
238
+ // Selects Mem0 user_id based on toggle state (Flowise chat ID or input field)
239
+ private getEffectiveUserId ( overrideUserId ?: string ) : string {
240
+ let effectiveUserId : string | undefined
241
+
242
+ if ( this . useFlowiseChatId ) {
243
+ if ( overrideUserId ) {
244
+ effectiveUserId = overrideUserId
245
+ } else {
246
+ throw new Error ( 'Mem0: "Use Flowise Chat ID" is ON, but no runtime chat ID (overrideUserId) was provided.' )
247
+ }
248
+ } else {
249
+ // If toggle is OFF, ALWAYS use the ID from the input field.
250
+ effectiveUserId = this . initialUserId
251
+ }
252
+
253
+ // This check is now primarily for the case where the toggle is OFF and the initialUserId was somehow empty (should be caught by init validation).
254
+ if ( ! effectiveUserId ) {
255
+ throw new Error ( 'Mem0: Could not determine a valid User ID for the operation. Check User ID input field.' )
256
+ }
257
+ return effectiveUserId
212
258
}
213
259
214
260
async loadMemoryVariables ( values : InputValues , overrideUserId = '' ) : Promise < MemoryVariables > {
215
- if ( overrideUserId ) {
216
- this . userId = overrideUserId
261
+ const effectiveUserId = this . getEffectiveUserId ( overrideUserId )
262
+ this . userId = effectiveUserId
263
+ if ( this . memoryOptions ) {
264
+ this . memoryOptions . user_id = effectiveUserId
217
265
}
218
266
return super . loadMemoryVariables ( values )
219
267
}
220
268
221
269
async saveContext ( inputValues : InputValues , outputValues : OutputValues , overrideUserId = '' ) : Promise < void > {
222
- if ( overrideUserId ) {
223
- this . userId = overrideUserId
224
- }
225
270
if ( this . searchOnly ) {
226
271
return
227
272
}
273
+ const effectiveUserId = this . getEffectiveUserId ( overrideUserId )
274
+ this . userId = effectiveUserId
275
+ if ( this . memoryOptions ) {
276
+ this . memoryOptions . user_id = effectiveUserId
277
+ }
228
278
return super . saveContext ( inputValues , outputValues )
229
279
}
230
280
231
281
async clear ( overrideUserId = '' ) : Promise < void > {
232
- if ( overrideUserId ) {
233
- this . userId = overrideUserId
282
+ const effectiveUserId = this . getEffectiveUserId ( overrideUserId )
283
+ this . userId = effectiveUserId
284
+ if ( this . memoryOptions ) {
285
+ this . memoryOptions . user_id = effectiveUserId
234
286
}
235
287
return super . clear ( )
236
288
}
@@ -240,63 +292,83 @@ class Mem0MemoryExtended extends BaseMem0Memory implements MemoryMethods {
240
292
returnBaseMessages = false ,
241
293
prependMessages ?: IMessage [ ]
242
294
) : Promise < IMessage [ ] | BaseMessage [ ] > {
243
- const id = overrideUserId ? overrideUserId : this . userId
244
- if ( ! id ) return [ ]
295
+ const flowiseSessionId = overrideUserId
296
+ if ( ! flowiseSessionId ) {
297
+ console . warn ( 'Mem0: getChatMessages called without overrideUserId (Flowise Session ID). Cannot fetch DB messages.' )
298
+ return [ ]
299
+ }
245
300
246
301
let chatMessage = await this . appDataSource . getRepository ( this . databaseEntities [ 'ChatMessage' ] ) . find ( {
247
302
where : {
248
- sessionId : id ,
303
+ sessionId : flowiseSessionId ,
249
304
chatflowid : this . chatflowid
250
305
} ,
251
306
order : {
252
307
createdDate : 'DESC'
253
308
} ,
254
309
take : 10
255
310
} )
256
-
257
311
chatMessage = chatMessage . reverse ( )
258
312
259
- let returnIMessages : IMessage [ ] = [ ]
260
- for ( const m of chatMessage ) {
261
- returnIMessages . push ( {
262
- message : m . content as string ,
263
- type : m . role
264
- } )
265
- }
313
+ let returnIMessages : IMessage [ ] = chatMessage . map ( ( m ) => ( {
314
+ message : m . content as string ,
315
+ type : m . role as MessageType
316
+ } ) )
266
317
267
318
if ( prependMessages ?. length ) {
268
- chatMessage . unshift ( ...prependMessages )
319
+ returnIMessages . unshift ( ...prependMessages )
320
+ // Reverted to original simpler unshift
321
+ chatMessage . unshift ( ...( prependMessages as any ) ) // Cast as any
269
322
}
270
323
271
324
if ( returnBaseMessages ) {
272
- const memoryVariables = await this . loadMemoryVariables ( { } , id )
273
- let baseMessages = memoryVariables [ this . memoryKey ]
325
+ const memoryVariables = await this . loadMemoryVariables ( { } , overrideUserId )
326
+ const mem0History = memoryVariables [ this . memoryKey ]
274
327
275
- const systemMessage = { ...chatMessage [ 0 ] }
276
- systemMessage . content = baseMessages
277
- systemMessage . id = uuidv4 ( )
278
- systemMessage . role = 'apiMessage'
328
+ if ( mem0History && typeof mem0History === 'string' ) {
329
+ const systemMessage = {
330
+ role : 'apiMessage' as MessageType ,
331
+ content : mem0History ,
332
+ id : uuidv4 ( )
333
+ }
334
+ // Ensure Mem0 history message also conforms structurally if mapChatMessageToBaseMessage is strict
335
+ chatMessage . unshift ( systemMessage as any ) // Cast needed if mixing structures
336
+ } else if ( mem0History ) {
337
+ console . warn ( 'Mem0 history is not a string, cannot prepend directly.' )
338
+ }
279
339
280
- chatMessage . unshift ( systemMessage )
281
340
return await mapChatMessageToBaseMessage ( chatMessage )
282
341
}
283
342
284
343
return returnIMessages
285
344
}
286
345
287
346
async addChatMessages ( msgArray : { text : string ; type : MessageType } [ ] , overrideUserId = '' ) : Promise < void > {
288
- const id = overrideUserId ? overrideUserId : this . userId
347
+ const effectiveUserId = this . getEffectiveUserId ( overrideUserId )
289
348
const input = msgArray . find ( ( msg ) => msg . type === 'userMessage' )
290
349
const output = msgArray . find ( ( msg ) => msg . type === 'apiMessage' )
291
- const inputValues = { [ this . inputKey ?? 'input' ] : input ?. text }
292
- const outputValues = { output : output ?. text }
293
350
294
- await this . saveContext ( inputValues , outputValues , id )
351
+ if ( input && output ) {
352
+ const inputValues = { [ this . inputKey ?? 'input' ] : input . text }
353
+ const outputValues = { output : output . text }
354
+ await this . saveContext ( inputValues , outputValues , effectiveUserId )
355
+ } else {
356
+ console . warn ( 'Mem0: Could not find both input and output messages to save context.' )
357
+ }
295
358
}
296
359
297
360
async clearChatMessages ( overrideUserId = '' ) : Promise < void > {
298
- const id = overrideUserId ? overrideUserId : this . userId
299
- await this . clear ( id )
361
+ const effectiveUserId = this . getEffectiveUserId ( overrideUserId )
362
+ await this . clear ( effectiveUserId )
363
+
364
+ const flowiseSessionId = overrideUserId
365
+ if ( flowiseSessionId ) {
366
+ await this . appDataSource
367
+ . getRepository ( this . databaseEntities [ 'ChatMessage' ] )
368
+ . delete ( { sessionId : flowiseSessionId , chatflowid : this . chatflowid } )
369
+ } else {
370
+ console . warn ( 'Mem0: clearChatMessages called without overrideUserId (Flowise Session ID). Cannot clear DB messages.' )
371
+ }
300
372
}
301
373
}
302
374
0 commit comments