Skip to content

Commit cd90720

Browse files
toi500Yshayy
authored andcommitted
feat(Mem0): Add option to use Flowise Chat ID (FlowiseAI#4257)
* feat(Mem0): Add option to use Flowise Chat ID * refactor(Mem0): Simplify prependMessages handling in getChatMessages
1 parent e984ddf commit cd90720

File tree

1 file changed

+128
-56
lines changed
  • packages/components/nodes/memory/Mem0

1 file changed

+128
-56
lines changed

packages/components/nodes/memory/Mem0/Mem0.ts

Lines changed: 128 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Mem0_Memory implements INode {
3030
constructor() {
3131
this.label = 'Mem0'
3232
this.name = 'mem0'
33-
this.version = 1.0
33+
this.version = 1.1
3434
this.type = 'Mem0'
3535
this.icon = 'mem0.svg'
3636
this.category = 'Memory'
@@ -49,9 +49,18 @@ class Mem0_Memory implements INode {
4949
label: 'User ID',
5050
name: 'user_id',
5151
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.',
5353
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
5564
},
5665
{
5766
label: 'Search Only',
@@ -140,9 +149,11 @@ class Mem0_Memory implements INode {
140149
}
141150

142151
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.')
146157
}
147158

148159
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
@@ -155,8 +166,12 @@ const initializeMem0 = async (nodeData: INodeData, options: ICommonObject): Prom
155166
projectId: nodeData.inputs?.project_id as string
156167
}
157168

169+
const memOptionsUserId = initialUserId
170+
171+
const constructorSessionId = initialUserId || (useFlowiseChatId ? 'flowise-chat-id-placeholder' : '')
172+
158173
const memoryOptions: MemoryOptions & SearchOptions = {
159-
user_id: userId,
174+
user_id: memOptionsUserId,
160175
run_id: (nodeData.inputs?.run_id as string) || undefined,
161176
agent_id: (nodeData.inputs?.agent_id as string) || undefined,
162177
app_id: (nodeData.inputs?.app_id as string) || undefined,
@@ -168,69 +183,106 @@ const initializeMem0 = async (nodeData: INodeData, options: ICommonObject): Prom
168183
filters: (nodeData.inputs?.filters as Record<string, any>) || {}
169184
}
170185

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+
}
186203

187204
return new Mem0MemoryExtended(obj)
188205
}
189206

190207
interface Mem0MemoryExtendedInput extends Mem0MemoryInput {
191208
memoryOptions?: MemoryOptions | SearchOptions
209+
useFlowiseChatId: boolean
192210
}
193211

194212
class Mem0MemoryExtended extends BaseMem0Memory implements MemoryMethods {
213+
initialUserId: string
195214
userId: string
196215
memoryKey: string
197216
inputKey: string
198217
appDataSource: DataSource
199218
databaseEntities: IDatabaseEntity
200219
chatflowid: string
201220
searchOnly: boolean
221+
useFlowiseChatId: boolean
202222

203-
constructor(fields: Mem0MemoryInput & Mem0MemoryExtendedInput & BufferMemoryExtendedInput & { searchOnly: boolean }) {
223+
constructor(
224+
fields: Mem0MemoryInput & Mem0MemoryExtendedInput & BufferMemoryExtendedInput & { searchOnly: boolean; useFlowiseChatId: boolean }
225+
) {
204226
super(fields)
205-
this.userId = fields.memoryOptions?.user_id ?? ''
227+
this.initialUserId = fields.memoryOptions?.user_id ?? ''
228+
this.userId = this.initialUserId
206229
this.memoryKey = 'history'
207230
this.inputKey = fields.inputKey ?? 'input'
208231
this.appDataSource = fields.appDataSource
209232
this.databaseEntities = fields.databaseEntities
210233
this.chatflowid = fields.chatflowid
211234
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
212258
}
213259

214260
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
217265
}
218266
return super.loadMemoryVariables(values)
219267
}
220268

221269
async saveContext(inputValues: InputValues, outputValues: OutputValues, overrideUserId = ''): Promise<void> {
222-
if (overrideUserId) {
223-
this.userId = overrideUserId
224-
}
225270
if (this.searchOnly) {
226271
return
227272
}
273+
const effectiveUserId = this.getEffectiveUserId(overrideUserId)
274+
this.userId = effectiveUserId
275+
if (this.memoryOptions) {
276+
this.memoryOptions.user_id = effectiveUserId
277+
}
228278
return super.saveContext(inputValues, outputValues)
229279
}
230280

231281
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
234286
}
235287
return super.clear()
236288
}
@@ -240,63 +292,83 @@ class Mem0MemoryExtended extends BaseMem0Memory implements MemoryMethods {
240292
returnBaseMessages = false,
241293
prependMessages?: IMessage[]
242294
): 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+
}
245300

246301
let chatMessage = await this.appDataSource.getRepository(this.databaseEntities['ChatMessage']).find({
247302
where: {
248-
sessionId: id,
303+
sessionId: flowiseSessionId,
249304
chatflowid: this.chatflowid
250305
},
251306
order: {
252307
createdDate: 'DESC'
253308
},
254309
take: 10
255310
})
256-
257311
chatMessage = chatMessage.reverse()
258312

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+
}))
266317

267318
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
269322
}
270323

271324
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]
274327

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+
}
279339

280-
chatMessage.unshift(systemMessage)
281340
return await mapChatMessageToBaseMessage(chatMessage)
282341
}
283342

284343
return returnIMessages
285344
}
286345

287346
async addChatMessages(msgArray: { text: string; type: MessageType }[], overrideUserId = ''): Promise<void> {
288-
const id = overrideUserId ? overrideUserId : this.userId
347+
const effectiveUserId = this.getEffectiveUserId(overrideUserId)
289348
const input = msgArray.find((msg) => msg.type === 'userMessage')
290349
const output = msgArray.find((msg) => msg.type === 'apiMessage')
291-
const inputValues = { [this.inputKey ?? 'input']: input?.text }
292-
const outputValues = { output: output?.text }
293350

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+
}
295358
}
296359

297360
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+
}
300372
}
301373
}
302374

0 commit comments

Comments
 (0)