Feature/Add prepend messages to memory (#2410)

add prepend messages to memory
This commit is contained in:
Henry Heng 2024-05-20 17:08:34 +01:00 committed by GitHub
parent 816436f8fa
commit 8caca472ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 219 additions and 55 deletions

View File

@ -190,6 +190,7 @@ const prepareAgent = async (
const systemMessage = nodeData.inputs?.systemMessage as string const systemMessage = nodeData.inputs?.systemMessage as string
const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history'
const inputKey = memory.inputKey ? memory.inputKey : 'input' const inputKey = memory.inputKey ? memory.inputKey : 'input'
const prependMessages = options?.prependMessages
const outputParser = ChatConversationalAgent.getDefaultOutputParser({ const outputParser = ChatConversationalAgent.getDefaultOutputParser({
llm: model, llm: model,
@ -240,7 +241,7 @@ const prepareAgent = async (
[inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input,
agent_scratchpad: async (i: { input: string; steps: AgentStep[] }) => await constructScratchPad(i.steps), agent_scratchpad: async (i: { input: string; steps: AgentStep[] }) => await constructScratchPad(i.steps),
[memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => {
const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[]
return messages ?? [] return messages ?? []
} }
}, },

View File

@ -84,7 +84,7 @@ class ConversationalRetrievalAgent_Agents implements INode {
} }
async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> { async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {
return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
} }
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | object> { async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | object> {
@ -102,7 +102,7 @@ class ConversationalRetrievalAgent_Agents implements INode {
} }
} }
const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) const executor = prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
const loggerHandler = new ConsoleCallbackHandler(options.logger) const loggerHandler = new ConsoleCallbackHandler(options.logger)
const callbacks = await additionalCallbacks(nodeData, options) const callbacks = await additionalCallbacks(nodeData, options)
@ -134,7 +134,7 @@ class ConversationalRetrievalAgent_Agents implements INode {
} }
} }
const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const prepareAgent = (nodeData: INodeData, options: ICommonObject, flowObj: { sessionId?: string; chatId?: string; input?: string }) => {
const model = nodeData.inputs?.model as ChatOpenAI const model = nodeData.inputs?.model as ChatOpenAI
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
const systemMessage = nodeData.inputs?.systemMessage as string const systemMessage = nodeData.inputs?.systemMessage as string
@ -143,6 +143,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId
tools = flatten(tools) tools = flatten(tools)
const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history'
const inputKey = memory.inputKey ? memory.inputKey : 'input' const inputKey = memory.inputKey ? memory.inputKey : 'input'
const prependMessages = options?.prependMessages
const prompt = ChatPromptTemplate.fromMessages([ const prompt = ChatPromptTemplate.fromMessages([
['ai', systemMessage ? systemMessage : defaultMessage], ['ai', systemMessage ? systemMessage : defaultMessage],
@ -160,7 +161,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId
[inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input,
agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps), agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps),
[memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => {
const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[]
return messages ?? [] return messages ?? []
} }
}, },

View File

@ -82,7 +82,7 @@ class MistralAIToolAgent_Agents implements INode {
} }
async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> { async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {
return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
} }
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> { async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> {
@ -100,7 +100,7 @@ class MistralAIToolAgent_Agents implements INode {
} }
} }
const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) const executor = prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
const loggerHandler = new ConsoleCallbackHandler(options.logger) const loggerHandler = new ConsoleCallbackHandler(options.logger)
const callbacks = await additionalCallbacks(nodeData, options) const callbacks = await additionalCallbacks(nodeData, options)
@ -161,7 +161,7 @@ class MistralAIToolAgent_Agents implements INode {
} }
} }
const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const prepareAgent = (nodeData: INodeData, options: ICommonObject, flowObj: { sessionId?: string; chatId?: string; input?: string }) => {
const model = nodeData.inputs?.model as ChatOpenAI const model = nodeData.inputs?.model as ChatOpenAI
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
const maxIterations = nodeData.inputs?.maxIterations as string const maxIterations = nodeData.inputs?.maxIterations as string
@ -170,6 +170,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId
tools = flatten(tools) tools = flatten(tools)
const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history'
const inputKey = memory.inputKey ? memory.inputKey : 'input' const inputKey = memory.inputKey ? memory.inputKey : 'input'
const prependMessages = options?.prependMessages
const prompt = ChatPromptTemplate.fromMessages([ const prompt = ChatPromptTemplate.fromMessages([
['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`], ['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`],
@ -187,7 +188,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId
[inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input,
agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps), agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps),
[memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => {
const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[]
return messages ?? [] return messages ?? []
} }
}, },

View File

@ -81,7 +81,7 @@ class OpenAIFunctionAgent_Agents implements INode {
} }
async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> { async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {
return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
} }
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> { async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> {
@ -99,7 +99,7 @@ class OpenAIFunctionAgent_Agents implements INode {
} }
} }
const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) const executor = prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
const loggerHandler = new ConsoleCallbackHandler(options.logger) const loggerHandler = new ConsoleCallbackHandler(options.logger)
const callbacks = await additionalCallbacks(nodeData, options) const callbacks = await additionalCallbacks(nodeData, options)
@ -160,7 +160,7 @@ class OpenAIFunctionAgent_Agents implements INode {
} }
} }
const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const prepareAgent = (nodeData: INodeData, options: ICommonObject, flowObj: { sessionId?: string; chatId?: string; input?: string }) => {
const model = nodeData.inputs?.model as ChatOpenAI const model = nodeData.inputs?.model as ChatOpenAI
const maxIterations = nodeData.inputs?.maxIterations as string const maxIterations = nodeData.inputs?.maxIterations as string
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
@ -169,6 +169,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId
tools = flatten(tools) tools = flatten(tools)
const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history'
const inputKey = memory.inputKey ? memory.inputKey : 'input' const inputKey = memory.inputKey ? memory.inputKey : 'input'
const prependMessages = options?.prependMessages
const prompt = ChatPromptTemplate.fromMessages([ const prompt = ChatPromptTemplate.fromMessages([
['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`], ['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`],
@ -186,7 +187,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId
[inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input,
agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps), agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps),
[memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => {
const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[]
return messages ?? [] return messages ?? []
} }
}, },

View File

@ -82,7 +82,7 @@ class OpenAIToolAgent_Agents implements INode {
} }
async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> { async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {
return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
} }
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> { async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> {
@ -100,7 +100,7 @@ class OpenAIToolAgent_Agents implements INode {
} }
} }
const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) const executor = prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
const loggerHandler = new ConsoleCallbackHandler(options.logger) const loggerHandler = new ConsoleCallbackHandler(options.logger)
const callbacks = await additionalCallbacks(nodeData, options) const callbacks = await additionalCallbacks(nodeData, options)
@ -161,7 +161,7 @@ class OpenAIToolAgent_Agents implements INode {
} }
} }
const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const prepareAgent = (nodeData: INodeData, options: ICommonObject, flowObj: { sessionId?: string; chatId?: string; input?: string }) => {
const model = nodeData.inputs?.model as ChatOpenAI const model = nodeData.inputs?.model as ChatOpenAI
const maxIterations = nodeData.inputs?.maxIterations as string const maxIterations = nodeData.inputs?.maxIterations as string
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
@ -170,6 +170,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId
tools = flatten(tools) tools = flatten(tools)
const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history'
const inputKey = memory.inputKey ? memory.inputKey : 'input' const inputKey = memory.inputKey ? memory.inputKey : 'input'
const prependMessages = options?.prependMessages
const prompt = ChatPromptTemplate.fromMessages([ const prompt = ChatPromptTemplate.fromMessages([
['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`], ['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`],
@ -185,7 +186,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId
[inputKey]: (i: { input: string; steps: ToolsAgentStep[] }) => i.input, [inputKey]: (i: { input: string; steps: ToolsAgentStep[] }) => i.input,
agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) => formatToOpenAIToolMessages(i.steps), agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) => formatToOpenAIToolMessages(i.steps),
[memoryKey]: async (_: { input: string; steps: ToolsAgentStep[] }) => { [memoryKey]: async (_: { input: string; steps: ToolsAgentStep[] }) => {
const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[]
return messages ?? [] return messages ?? []
} }
}, },

View File

@ -61,10 +61,12 @@ class OpenAIFunctionAgent_LlamaIndex_Agents implements INode {
return null return null
} }
async run(nodeData: INodeData, input: string): Promise<string | ICommonObject> { async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> {
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
const model = nodeData.inputs?.model as OpenAI const model = nodeData.inputs?.model as OpenAI
const systemMessage = nodeData.inputs?.systemMessage as string const systemMessage = nodeData.inputs?.systemMessage as string
const prependMessages = options?.prependMessages
let tools = nodeData.inputs?.tools let tools = nodeData.inputs?.tools
tools = flatten(tools) tools = flatten(tools)
@ -77,7 +79,7 @@ class OpenAIFunctionAgent_LlamaIndex_Agents implements INode {
}) })
} }
const msgs = (await memory.getChatMessages(this.sessionId, false)) as IMessage[] const msgs = (await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[]
for (const message of msgs) { for (const message of msgs) {
if (message.type === 'apiMessage') { if (message.type === 'apiMessage') {
chatHistory.push({ chatHistory.push({

View File

@ -80,6 +80,7 @@ class ReActAgentChat_Agents implements INode {
const model = nodeData.inputs?.model as BaseChatModel const model = nodeData.inputs?.model as BaseChatModel
let tools = nodeData.inputs?.tools as Tool[] let tools = nodeData.inputs?.tools as Tool[]
const moderations = nodeData.inputs?.inputModeration as Moderation[] const moderations = nodeData.inputs?.inputModeration as Moderation[]
const prependMessages = options?.prependMessages
if (moderations && moderations.length > 0) { if (moderations && moderations.length > 0) {
try { try {
@ -134,7 +135,7 @@ class ReActAgentChat_Agents implements INode {
const callbacks = await additionalCallbacks(nodeData, options) const callbacks = await additionalCallbacks(nodeData, options)
const chatHistory = ((await memory.getChatMessages(this.sessionId, false)) as IMessage[]) ?? [] const chatHistory = ((await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[]) ?? []
const chatHistoryString = chatHistory.map((hist) => hist.message).join('\\n') const chatHistoryString = chatHistory.map((hist) => hist.message).join('\\n')
const result = await executor.invoke({ input, chat_history: chatHistoryString }, { callbacks }) const result = await executor.invoke({ input, chat_history: chatHistoryString }, { callbacks })

View File

@ -191,6 +191,7 @@ const prepareAgent = async (
tools = flatten(tools) tools = flatten(tools)
const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history'
const inputKey = memory.inputKey ? memory.inputKey : 'input' const inputKey = memory.inputKey ? memory.inputKey : 'input'
const prependMessages = options?.prependMessages
const prompt = ChatPromptTemplate.fromMessages([ const prompt = ChatPromptTemplate.fromMessages([
['system', systemMessage], ['system', systemMessage],
@ -239,7 +240,7 @@ const prepareAgent = async (
[inputKey]: (i: { input: string; steps: ToolsAgentStep[] }) => i.input, [inputKey]: (i: { input: string; steps: ToolsAgentStep[] }) => i.input,
agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) => formatToOpenAIToolMessages(i.steps), agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) => formatToOpenAIToolMessages(i.steps),
[memoryKey]: async (_: { input: string; steps: ToolsAgentStep[] }) => { [memoryKey]: async (_: { input: string; steps: ToolsAgentStep[] }) => {
const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[]
return messages ?? [] return messages ?? []
} }
}, },

View File

@ -122,7 +122,7 @@ class XMLAgent_Agents implements INode {
return formatResponse(e.message) return formatResponse(e.message)
} }
} }
const executor = await prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) const executor = await prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input })
const loggerHandler = new ConsoleCallbackHandler(options.logger) const loggerHandler = new ConsoleCallbackHandler(options.logger)
const callbacks = await additionalCallbacks(nodeData, options) const callbacks = await additionalCallbacks(nodeData, options)
@ -183,7 +183,11 @@ class XMLAgent_Agents implements INode {
} }
} }
const prepareAgent = async (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const prepareAgent = async (
nodeData: INodeData,
options: ICommonObject,
flowObj: { sessionId?: string; chatId?: string; input?: string }
) => {
const model = nodeData.inputs?.model as BaseChatModel const model = nodeData.inputs?.model as BaseChatModel
const maxIterations = nodeData.inputs?.maxIterations as string const maxIterations = nodeData.inputs?.maxIterations as string
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
@ -192,6 +196,7 @@ const prepareAgent = async (nodeData: INodeData, flowObj: { sessionId?: string;
tools = flatten(tools) tools = flatten(tools)
const inputKey = memory.inputKey ? memory.inputKey : 'input' const inputKey = memory.inputKey ? memory.inputKey : 'input'
const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history'
const prependMessages = options?.prependMessages
let promptMessage = systemMessage ? systemMessage : defaultSystemMessage let promptMessage = systemMessage ? systemMessage : defaultSystemMessage
if (memory.memoryKey) promptMessage = promptMessage.replaceAll('{chat_history}', `{${memory.memoryKey}}`) if (memory.memoryKey) promptMessage = promptMessage.replaceAll('{chat_history}', `{${memory.memoryKey}}`)
@ -210,7 +215,7 @@ const prepareAgent = async (nodeData: INodeData, flowObj: { sessionId?: string;
const llmWithStop = model.bind({ stop: ['</tool_input>', '</final_answer>'] }) const llmWithStop = model.bind({ stop: ['</tool_input>', '</final_answer>'] })
const messages = (await memory.getChatMessages(flowObj.sessionId, false)) as IMessage[] const messages = (await memory.getChatMessages(flowObj.sessionId, false, prependMessages)) as IMessage[]
let chatHistoryMsgTxt = '' let chatHistoryMsgTxt = ''
for (const message of messages) { for (const message of messages) {
if (message.type === 'apiMessage') { if (message.type === 'apiMessage') {

View File

@ -220,6 +220,7 @@ const prepareChain = async (nodeData: INodeData, options: ICommonObject, session
let model = nodeData.inputs?.model as BaseChatModel let model = nodeData.inputs?.model as BaseChatModel
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
const memoryKey = memory.memoryKey ?? 'chat_history' const memoryKey = memory.memoryKey ?? 'chat_history'
const prependMessages = options?.prependMessages
let messageContent: MessageContentImageUrl[] = [] let messageContent: MessageContentImageUrl[] = []
if (llmSupportsVision(model)) { if (llmSupportsVision(model)) {
@ -252,7 +253,7 @@ const prepareChain = async (nodeData: INodeData, options: ICommonObject, session
{ {
[inputKey]: (input: { input: string }) => input.input, [inputKey]: (input: { input: string }) => input.input,
[memoryKey]: async () => { [memoryKey]: async () => {
const history = await memory.getChatMessages(sessionId, true) const history = await memory.getChatMessages(sessionId, true, prependMessages)
return history return history
}, },
...promptVariables ...promptVariables

View File

@ -175,6 +175,7 @@ class ConversationalRetrievalQAChain_Chains implements INode {
const rephrasePrompt = nodeData.inputs?.rephrasePrompt as string const rephrasePrompt = nodeData.inputs?.rephrasePrompt as string
const responsePrompt = nodeData.inputs?.responsePrompt as string const responsePrompt = nodeData.inputs?.responsePrompt as string
const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean
const prependMessages = options?.prependMessages
const appDataSource = options.appDataSource as DataSource const appDataSource = options.appDataSource as DataSource
const databaseEntities = options.databaseEntities as IDatabaseEntity const databaseEntities = options.databaseEntities as IDatabaseEntity
@ -210,7 +211,7 @@ class ConversationalRetrievalQAChain_Chains implements INode {
} }
const answerChain = createChain(model, vectorStoreRetriever, rephrasePrompt, customResponsePrompt) const answerChain = createChain(model, vectorStoreRetriever, rephrasePrompt, customResponsePrompt)
const history = ((await memory.getChatMessages(this.sessionId, false)) as IMessage[]) ?? [] const history = ((await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[]) ?? []
const loggerHandler = new ConsoleCallbackHandler(options.logger) const loggerHandler = new ConsoleCallbackHandler(options.logger)
const additionalCallback = await additionalCallbacks(nodeData, options) const additionalCallback = await additionalCallbacks(nodeData, options)
@ -401,7 +402,11 @@ class BufferMemory extends FlowiseMemory implements MemoryMethods {
this.chatflowid = fields.chatflowid this.chatflowid = fields.chatflowid
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
if (!overrideSessionId) return [] if (!overrideSessionId) return []
const chatMessage = await this.appDataSource.getRepository(this.databaseEntities['ChatMessage']).find({ const chatMessage = await this.appDataSource.getRepository(this.databaseEntities['ChatMessage']).find({
@ -414,6 +419,10 @@ class BufferMemory extends FlowiseMemory implements MemoryMethods {
} }
}) })
if (prependMessages?.length) {
chatMessage.unshift(...prependMessages)
}
if (returnBaseMessages) { if (returnBaseMessages) {
return mapChatMessageToBaseMessage(chatMessage) return mapChatMessageToBaseMessage(chatMessage)
} }

View File

@ -71,6 +71,7 @@ class ContextChatEngine_LlamaIndex implements INode {
const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt as string const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt as string
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean
const prependMessages = options?.prependMessages
const chatHistory = [] as ChatMessage[] const chatHistory = [] as ChatMessage[]
@ -83,7 +84,7 @@ class ContextChatEngine_LlamaIndex implements INode {
const chatEngine = new ContextChatEngine({ chatModel: model, retriever: vectorStoreRetriever }) const chatEngine = new ContextChatEngine({ chatModel: model, retriever: vectorStoreRetriever })
const msgs = (await memory.getChatMessages(this.sessionId, false)) as IMessage[] const msgs = (await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[]
for (const message of msgs) { for (const message of msgs) {
if (message.type === 'apiMessage') { if (message.type === 'apiMessage') {
chatHistory.push({ chatHistory.push({

View File

@ -56,6 +56,7 @@ class SimpleChatEngine_LlamaIndex implements INode {
const model = nodeData.inputs?.model as LLM const model = nodeData.inputs?.model as LLM
const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt as string const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt as string
const memory = nodeData.inputs?.memory as FlowiseMemory const memory = nodeData.inputs?.memory as FlowiseMemory
const prependMessages = options?.prependMessages
const chatHistory = [] as ChatMessage[] const chatHistory = [] as ChatMessage[]
@ -68,7 +69,7 @@ class SimpleChatEngine_LlamaIndex implements INode {
const chatEngine = new SimpleChatEngine({ llm: model }) const chatEngine = new SimpleChatEngine({ llm: model })
const msgs = (await memory.getChatMessages(this.sessionId, false)) as IMessage[] const msgs = (await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[]
for (const message of msgs) { for (const message of msgs) {
if (message.type === 'apiMessage') { if (message.type === 'apiMessage') {
chatHistory.push({ chatHistory.push({

View File

@ -94,7 +94,11 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
this.chatflowid = fields.chatflowid this.chatflowid = fields.chatflowid
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
if (!id) return [] if (!id) return []
@ -108,6 +112,10 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
} }
}) })
if (prependMessages?.length) {
chatMessage.unshift(...prependMessages)
}
if (returnBaseMessages) { if (returnBaseMessages) {
return mapChatMessageToBaseMessage(chatMessage) return mapChatMessageToBaseMessage(chatMessage)
} }

View File

@ -105,7 +105,11 @@ class BufferWindowMemoryExtended extends FlowiseWindowMemory implements MemoryMe
this.chatflowid = fields.chatflowid this.chatflowid = fields.chatflowid
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
if (!id) return [] if (!id) return []
@ -123,6 +127,10 @@ class BufferWindowMemoryExtended extends FlowiseWindowMemory implements MemoryMe
// reverse the order of human and ai messages // reverse the order of human and ai messages
if (chatMessage.length) chatMessage.reverse() if (chatMessage.length) chatMessage.reverse()
if (prependMessages?.length) {
chatMessage.unshift(...prependMessages)
}
if (returnBaseMessages) { if (returnBaseMessages) {
return mapChatMessageToBaseMessage(chatMessage) return mapChatMessageToBaseMessage(chatMessage)
} }

View File

@ -114,7 +114,11 @@ class ConversationSummaryBufferMemoryExtended extends FlowiseSummaryBufferMemory
this.chatflowid = fields.chatflowid this.chatflowid = fields.chatflowid
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
if (!id) return [] if (!id) return []
@ -128,6 +132,10 @@ class ConversationSummaryBufferMemoryExtended extends FlowiseSummaryBufferMemory
} }
}) })
if (prependMessages?.length) {
chatMessage.unshift(...prependMessages)
}
let baseMessages = mapChatMessageToBaseMessage(chatMessage) let baseMessages = mapChatMessageToBaseMessage(chatMessage)
// Prune baseMessages if it exceeds max token limit // Prune baseMessages if it exceeds max token limit

View File

@ -104,7 +104,11 @@ class ConversationSummaryMemoryExtended extends FlowiseSummaryMemory implements
this.chatflowid = fields.chatflowid this.chatflowid = fields.chatflowid
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
if (!id) return [] if (!id) return []
@ -119,6 +123,10 @@ class ConversationSummaryMemoryExtended extends FlowiseSummaryMemory implements
} }
}) })
if (prependMessages?.length) {
chatMessage.unshift(...prependMessages)
}
const baseMessages = mapChatMessageToBaseMessage(chatMessage) const baseMessages = mapChatMessageToBaseMessage(chatMessage)
// Get summary // Get summary

View File

@ -12,7 +12,13 @@ import {
import { DynamoDBChatMessageHistory } from '@langchain/community/stores/message/dynamodb' import { DynamoDBChatMessageHistory } from '@langchain/community/stores/message/dynamodb'
import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, StoredMessage, BaseMessage } from '@langchain/core/messages' import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, StoredMessage, BaseMessage } from '@langchain/core/messages'
import { BufferMemory, BufferMemoryInput } from 'langchain/memory' import { BufferMemory, BufferMemoryInput } from 'langchain/memory'
import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import {
convertBaseMessagetoIMessage,
getBaseClasses,
getCredentialData,
getCredentialParam,
mapChatMessageToBaseMessage
} from '../../../src/utils'
import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface'
class DynamoDb_Memory implements INode { class DynamoDb_Memory implements INode {
@ -219,7 +225,11 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
await client.send(new UpdateItemCommand(params)) await client.send(new UpdateItemCommand(params))
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
if (!this.dynamodbClient) return [] if (!this.dynamodbClient) return []
const dynamoKey = overrideSessionId ? this.overrideDynamoKey(overrideSessionId) : this.dynamoKey const dynamoKey = overrideSessionId ? this.overrideDynamoKey(overrideSessionId) : this.dynamoKey
@ -243,6 +253,9 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
})) }))
.filter((x): x is StoredMessage => x.type !== undefined && x.data.content !== undefined) .filter((x): x is StoredMessage => x.type !== undefined && x.data.content !== undefined)
const baseMessages = messages.map(mapStoredMessageToChatMessage) const baseMessages = messages.map(mapStoredMessageToChatMessage)
if (prependMessages?.length) {
baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages))
}
return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages)
} }

View File

@ -2,7 +2,13 @@ import { MongoClient, Collection, Document } from 'mongodb'
import { MongoDBChatMessageHistory } from '@langchain/mongodb' import { MongoDBChatMessageHistory } from '@langchain/mongodb'
import { BufferMemory, BufferMemoryInput } from 'langchain/memory' import { BufferMemory, BufferMemoryInput } from 'langchain/memory'
import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, BaseMessage } from '@langchain/core/messages' import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, BaseMessage } from '@langchain/core/messages'
import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import {
convertBaseMessagetoIMessage,
getBaseClasses,
getCredentialData,
getCredentialParam,
mapChatMessageToBaseMessage
} from '../../../src/utils'
import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface'
let mongoClientSingleton: MongoClient let mongoClientSingleton: MongoClient
@ -151,13 +157,20 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
this.collection = fields.collection this.collection = fields.collection
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
if (!this.collection) return [] if (!this.collection) return []
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
const document = await this.collection.findOne({ sessionId: id }) const document = await this.collection.findOne({ sessionId: id })
const messages = document?.messages || [] const messages = document?.messages || []
const baseMessages = messages.map(mapStoredMessageToChatMessage) const baseMessages = messages.map(mapStoredMessageToChatMessage)
if (prependMessages?.length) {
baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages))
}
return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages)
} }

View File

@ -4,7 +4,13 @@ import { BufferMemory, BufferMemoryInput } from 'langchain/memory'
import { RedisChatMessageHistory, RedisChatMessageHistoryInput } from '@langchain/community/stores/message/ioredis' import { RedisChatMessageHistory, RedisChatMessageHistoryInput } from '@langchain/community/stores/message/ioredis'
import { mapStoredMessageToChatMessage, BaseMessage, AIMessage, HumanMessage } from '@langchain/core/messages' import { mapStoredMessageToChatMessage, BaseMessage, AIMessage, HumanMessage } from '@langchain/core/messages'
import { INode, INodeData, INodeParams, ICommonObject, MessageType, IMessage, MemoryMethods, FlowiseMemory } from '../../../src/Interface' import { INode, INodeData, INodeParams, ICommonObject, MessageType, IMessage, MemoryMethods, FlowiseMemory } from '../../../src/Interface'
import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import {
convertBaseMessagetoIMessage,
getBaseClasses,
getCredentialData,
getCredentialParam,
mapChatMessageToBaseMessage
} from '../../../src/utils'
let redisClientSingleton: Redis let redisClientSingleton: Redis
let redisClientOption: RedisOptions let redisClientOption: RedisOptions
@ -190,13 +196,20 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
this.sessionTTL = fields.sessionTTL this.sessionTTL = fields.sessionTTL
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
if (!this.redisClient) return [] if (!this.redisClient) return []
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
const rawStoredMessages = await this.redisClient.lrange(id, this.windowSize ? this.windowSize * -1 : 0, -1) const rawStoredMessages = await this.redisClient.lrange(id, this.windowSize ? this.windowSize * -1 : 0, -1)
const orderedMessages = rawStoredMessages.reverse().map((message) => JSON.parse(message)) const orderedMessages = rawStoredMessages.reverse().map((message) => JSON.parse(message))
const baseMessages = orderedMessages.map(mapStoredMessageToChatMessage) const baseMessages = orderedMessages.map(mapStoredMessageToChatMessage)
if (prependMessages?.length) {
baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages))
}
return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages)
} }

View File

@ -4,7 +4,13 @@ import { BufferMemory, BufferMemoryInput } from 'langchain/memory'
import { UpstashRedisChatMessageHistory } from '@langchain/community/stores/message/upstash_redis' import { UpstashRedisChatMessageHistory } from '@langchain/community/stores/message/upstash_redis'
import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, StoredMessage, BaseMessage } from '@langchain/core/messages' import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, StoredMessage, BaseMessage } from '@langchain/core/messages'
import { FlowiseMemory, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' import { FlowiseMemory, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface'
import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import {
convertBaseMessagetoIMessage,
getBaseClasses,
getCredentialData,
getCredentialParam,
mapChatMessageToBaseMessage
} from '../../../src/utils'
import { ICommonObject } from '../../../src/Interface' import { ICommonObject } from '../../../src/Interface'
let redisClientSingleton: Redis let redisClientSingleton: Redis
@ -143,7 +149,11 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
this.sessionTTL = fields.sessionTTL this.sessionTTL = fields.sessionTTL
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
if (!this.redisClient) return [] if (!this.redisClient) return []
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
@ -151,6 +161,9 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
const orderedMessages = rawStoredMessages.reverse() const orderedMessages = rawStoredMessages.reverse()
const previousMessages = orderedMessages.filter((x): x is StoredMessage => x.type !== undefined && x.data.content !== undefined) const previousMessages = orderedMessages.filter((x): x is StoredMessage => x.type !== undefined && x.data.content !== undefined)
const baseMessages = previousMessages.map(mapStoredMessageToChatMessage) const baseMessages = previousMessages.map(mapStoredMessageToChatMessage)
if (prependMessages?.length) {
baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages))
}
return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages)
} }

View File

@ -2,7 +2,13 @@ import { ZepMemory, ZepMemoryInput } from '@langchain/community/memory/zep'
import { BaseMessage } from '@langchain/core/messages' import { BaseMessage } from '@langchain/core/messages'
import { InputValues, MemoryVariables, OutputValues } from 'langchain/memory' import { InputValues, MemoryVariables, OutputValues } from 'langchain/memory'
import { IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType, ICommonObject } from '../../../src/Interface' import { IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType, ICommonObject } from '../../../src/Interface'
import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import {
convertBaseMessagetoIMessage,
getBaseClasses,
getCredentialData,
getCredentialParam,
mapChatMessageToBaseMessage
} from '../../../src/utils'
class ZepMemory_Memory implements INode { class ZepMemory_Memory implements INode {
label: string label: string
@ -161,10 +167,17 @@ class ZepMemoryExtended extends ZepMemory implements MemoryMethods {
return super.clear() return super.clear()
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
const memoryVariables = await this.loadMemoryVariables({}, id) const memoryVariables = await this.loadMemoryVariables({}, id)
const baseMessages = memoryVariables[this.memoryKey] const baseMessages = memoryVariables[this.memoryKey]
if (prependMessages?.length) {
baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages))
}
return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages)
} }

View File

@ -1,5 +1,11 @@
import { IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' import { IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface'
import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import {
convertBaseMessagetoIMessage,
getBaseClasses,
getCredentialData,
getCredentialParam,
mapChatMessageToBaseMessage
} from '../../../src/utils'
import { ZepMemory, ZepMemoryInput } from '@getzep/zep-cloud/langchain' import { ZepMemory, ZepMemoryInput } from '@getzep/zep-cloud/langchain'
import { ICommonObject } from '../../../src' import { ICommonObject } from '../../../src'
@ -155,10 +161,17 @@ class ZepMemoryExtended extends ZepMemory implements MemoryMethods {
return super.clear() return super.clear()
} }
async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise<IMessage[] | BaseMessage[]> { async getChatMessages(
overrideSessionId = '',
returnBaseMessages = false,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]> {
const id = overrideSessionId ? overrideSessionId : this.sessionId const id = overrideSessionId ? overrideSessionId : this.sessionId
const memoryVariables = await this.loadMemoryVariables({}, id) const memoryVariables = await this.loadMemoryVariables({}, id)
const baseMessages = memoryVariables[this.memoryKey] const baseMessages = memoryVariables[this.memoryKey]
if (prependMessages?.length) {
baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages))
}
return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages)
} }

View File

@ -243,31 +243,51 @@ import { BaseMessage } from '@langchain/core/messages'
import { BufferMemory, BufferWindowMemory, ConversationSummaryMemory, ConversationSummaryBufferMemory } from 'langchain/memory' import { BufferMemory, BufferWindowMemory, ConversationSummaryMemory, ConversationSummaryBufferMemory } from 'langchain/memory'
export interface MemoryMethods { export interface MemoryMethods {
getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise<IMessage[] | BaseMessage[]> getChatMessages(
overrideSessionId?: string,
returnBaseMessages?: boolean,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]>
addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void> addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void>
clearChatMessages(overrideSessionId?: string): Promise<void> clearChatMessages(overrideSessionId?: string): Promise<void>
} }
export abstract class FlowiseMemory extends BufferMemory implements MemoryMethods { export abstract class FlowiseMemory extends BufferMemory implements MemoryMethods {
abstract getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise<IMessage[] | BaseMessage[]> abstract getChatMessages(
overrideSessionId?: string,
returnBaseMessages?: boolean,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]>
abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void> abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void>
abstract clearChatMessages(overrideSessionId?: string): Promise<void> abstract clearChatMessages(overrideSessionId?: string): Promise<void>
} }
export abstract class FlowiseWindowMemory extends BufferWindowMemory implements MemoryMethods { export abstract class FlowiseWindowMemory extends BufferWindowMemory implements MemoryMethods {
abstract getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise<IMessage[] | BaseMessage[]> abstract getChatMessages(
overrideSessionId?: string,
returnBaseMessages?: boolean,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]>
abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void> abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void>
abstract clearChatMessages(overrideSessionId?: string): Promise<void> abstract clearChatMessages(overrideSessionId?: string): Promise<void>
} }
export abstract class FlowiseSummaryMemory extends ConversationSummaryMemory implements MemoryMethods { export abstract class FlowiseSummaryMemory extends ConversationSummaryMemory implements MemoryMethods {
abstract getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise<IMessage[] | BaseMessage[]> abstract getChatMessages(
overrideSessionId?: string,
returnBaseMessages?: boolean,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]>
abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void> abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void>
abstract clearChatMessages(overrideSessionId?: string): Promise<void> abstract clearChatMessages(overrideSessionId?: string): Promise<void>
} }
export abstract class FlowiseSummaryBufferMemory extends ConversationSummaryBufferMemory implements MemoryMethods { export abstract class FlowiseSummaryBufferMemory extends ConversationSummaryBufferMemory implements MemoryMethods {
abstract getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise<IMessage[] | BaseMessage[]> abstract getChatMessages(
overrideSessionId?: string,
returnBaseMessages?: boolean,
prependMessages?: IMessage[]
): Promise<IMessage[] | BaseMessage[]>
abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void> abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise<void>
abstract clearChatMessages(overrideSessionId?: string): Promise<void> abstract clearChatMessages(overrideSessionId?: string): Promise<void>
} }

View File

@ -212,6 +212,7 @@ export interface IncomingInput {
stopNodeId?: string stopNodeId?: string
uploads?: IFileUpload[] uploads?: IFileUpload[]
leadEmail?: string leadEmail?: string
history?: IMessage[]
} }
export interface IActiveChatflows { export interface IActiveChatflows {

View File

@ -145,6 +145,9 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
const memoryType = memoryNode?.data.label const memoryType = memoryNode?.data.label
let sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal) let sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal)
// Get prepend messages
const prependMessages = incomingInput.history
/* Reuse the flow without having to rebuild (to avoid duplicated upsert, recomputation, reinitialization of memory) when all these conditions met: /* Reuse the flow without having to rebuild (to avoid duplicated upsert, recomputation, reinitialization of memory) when all these conditions met:
* - Node Data already exists in pool * - Node Data already exists in pool
* - Still in sync (i.e the flow has not been modified since) * - Still in sync (i.e the flow has not been modified since)
@ -226,7 +229,8 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
appServer.nodesPool.componentNodes, appServer.nodesPool.componentNodes,
appServer.AppDataSource, appServer.AppDataSource,
databaseEntities, databaseEntities,
logger logger,
prependMessages
) )
} }
@ -301,7 +305,8 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
analytic: chatflow.analytic, analytic: chatflow.analytic,
uploads: incomingInput.uploads, uploads: incomingInput.uploads,
socketIO, socketIO,
socketIOClientId: incomingInput.socketIOClientId socketIOClientId: incomingInput.socketIOClientId,
prependMessages
}) })
: await nodeInstance.run(nodeToExecuteData, incomingInput.question, { : await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatId, chatId,
@ -310,7 +315,8 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
appDataSource: appServer.AppDataSource, appDataSource: appServer.AppDataSource,
databaseEntities, databaseEntities,
analytic: chatflow.analytic, analytic: chatflow.analytic,
uploads: incomingInput.uploads uploads: incomingInput.uploads,
prependMessages
}) })
result = typeof result === 'string' ? { text: result } : result result = typeof result === 'string' ? { text: result } : result

View File

@ -1306,7 +1306,8 @@ export const getSessionChatHistory = async (
componentNodes: IComponentNodes, componentNodes: IComponentNodes,
appDataSource: DataSource, appDataSource: DataSource,
databaseEntities: IDatabaseEntity, databaseEntities: IDatabaseEntity,
logger: any logger: any,
prependMessages?: IMessage[]
): Promise<IMessage[]> => { ): Promise<IMessage[]> => {
const nodeInstanceFilePath = componentNodes[memoryNode.data.name].filePath as string const nodeInstanceFilePath = componentNodes[memoryNode.data.name].filePath as string
const nodeModule = await import(nodeInstanceFilePath) const nodeModule = await import(nodeInstanceFilePath)
@ -1324,7 +1325,7 @@ export const getSessionChatHistory = async (
logger logger
}) })
return (await initializedInstance.getChatMessages(sessionId)) as IMessage[] return (await initializedInstance.getChatMessages(sessionId, undefined, prependMessages)) as IMessage[]
} }
/** /**