mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 09:00:52 +03:00
Feature/Add message history to agents (#3031)
add message history to agents
This commit is contained in:
@@ -29,7 +29,8 @@ import {
|
||||
transformObjectPropertyToFunction,
|
||||
restructureMessages,
|
||||
MessagesState,
|
||||
RunnableCallable
|
||||
RunnableCallable,
|
||||
checkMessageHistory
|
||||
} from '../commonUtils'
|
||||
import { END, StateGraph } from '@langchain/langgraph'
|
||||
import { StructuredTool } from '@langchain/core/tools'
|
||||
@@ -149,6 +150,31 @@ const defaultFunc = `const result = $flow.output;
|
||||
return {
|
||||
aggregate: [result.content]
|
||||
};`
|
||||
|
||||
const messageHistoryExample = `const { AIMessage, HumanMessage, ToolMessage } = require('@langchain/core/messages');
|
||||
|
||||
return [
|
||||
new HumanMessage("What is 333382 🦜 1932?"),
|
||||
new AIMessage({
|
||||
content: "",
|
||||
tool_calls: [
|
||||
{
|
||||
id: "12345",
|
||||
name: "calulator",
|
||||
args: {
|
||||
number1: 333382,
|
||||
number2: 1932,
|
||||
operation: "divide",
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
new ToolMessage({
|
||||
tool_call_id: "12345",
|
||||
content: "The answer is 172.558.",
|
||||
}),
|
||||
new AIMessage("The answer is 172.558."),
|
||||
]`
|
||||
const TAB_IDENTIFIER = 'selectedUpdateStateMemoryTab'
|
||||
|
||||
class Agent_SeqAgents implements INode {
|
||||
@@ -168,7 +194,7 @@ class Agent_SeqAgents implements INode {
|
||||
constructor() {
|
||||
this.label = 'Agent'
|
||||
this.name = 'seqAgent'
|
||||
this.version = 2.0
|
||||
this.version = 3.0
|
||||
this.type = 'Agent'
|
||||
this.icon = 'seqAgent.png'
|
||||
this.category = 'Sequential Agents'
|
||||
@@ -199,6 +225,17 @@ class Agent_SeqAgents implements INode {
|
||||
optional: true,
|
||||
additionalParams: true
|
||||
},
|
||||
{
|
||||
label: 'Messages History',
|
||||
name: 'messageHistory',
|
||||
description:
|
||||
'Return a list of messages between System Prompt and Human Prompt. This is useful when you want to provide few shot examples',
|
||||
type: 'code',
|
||||
hideCodeExecute: true,
|
||||
codeExample: messageHistoryExample,
|
||||
optional: true,
|
||||
additionalParams: true
|
||||
},
|
||||
{
|
||||
label: 'Tools',
|
||||
name: 'tools',
|
||||
@@ -426,6 +463,8 @@ class Agent_SeqAgents implements INode {
|
||||
llm,
|
||||
interrupt,
|
||||
agent: await createAgent(
|
||||
nodeData,
|
||||
options,
|
||||
agentName,
|
||||
state,
|
||||
llm,
|
||||
@@ -515,6 +554,8 @@ class Agent_SeqAgents implements INode {
|
||||
}
|
||||
|
||||
async function createAgent(
|
||||
nodeData: INodeData,
|
||||
options: ICommonObject,
|
||||
agentName: string,
|
||||
state: ISeqAgentsState,
|
||||
llm: BaseChatModel,
|
||||
@@ -535,7 +576,8 @@ async function createAgent(
|
||||
if (systemPrompt) promptArrays.unshift(['system', systemPrompt])
|
||||
if (humanPrompt) promptArrays.push(['human', humanPrompt])
|
||||
|
||||
const prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
let prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
prompt = await checkMessageHistory(nodeData, options, prompt, promptArrays, systemPrompt)
|
||||
|
||||
if (multiModalMessageContent.length) {
|
||||
const msg = HumanMessagePromptTemplate.fromTemplate([...multiModalMessageContent])
|
||||
@@ -597,7 +639,9 @@ async function createAgent(
|
||||
if (systemPrompt) promptArrays.unshift(['system', systemPrompt])
|
||||
if (humanPrompt) promptArrays.push(['human', humanPrompt])
|
||||
|
||||
const prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
let prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
prompt = await checkMessageHistory(nodeData, options, prompt, promptArrays, systemPrompt)
|
||||
|
||||
if (multiModalMessageContent.length) {
|
||||
const msg = HumanMessagePromptTemplate.fromTemplate([...multiModalMessageContent])
|
||||
prompt.promptMessages.splice(1, 0, msg)
|
||||
@@ -624,7 +668,8 @@ async function createAgent(
|
||||
if (systemPrompt) promptArrays.unshift(['system', systemPrompt])
|
||||
if (humanPrompt) promptArrays.push(['human', humanPrompt])
|
||||
|
||||
const prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
let prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
prompt = await checkMessageHistory(nodeData, options, prompt, promptArrays, systemPrompt)
|
||||
|
||||
if (multiModalMessageContent.length) {
|
||||
const msg = HumanMessagePromptTemplate.fromTemplate([...multiModalMessageContent])
|
||||
|
||||
@@ -25,7 +25,8 @@ import {
|
||||
getVM,
|
||||
processImageMessage,
|
||||
transformObjectPropertyToFunction,
|
||||
restructureMessages
|
||||
restructureMessages,
|
||||
checkMessageHistory
|
||||
} from '../commonUtils'
|
||||
import { ChatGoogleGenerativeAI } from '../../chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI'
|
||||
|
||||
@@ -130,6 +131,31 @@ return {
|
||||
aggregate: [result.content]
|
||||
};`
|
||||
|
||||
const messageHistoryExample = `const { AIMessage, HumanMessage, ToolMessage } = require('@langchain/core/messages');
|
||||
|
||||
return [
|
||||
new HumanMessage("What is 333382 🦜 1932?"),
|
||||
new AIMessage({
|
||||
content: "",
|
||||
tool_calls: [
|
||||
{
|
||||
id: "12345",
|
||||
name: "calulator",
|
||||
args: {
|
||||
number1: 333382,
|
||||
number2: 1932,
|
||||
operation: "divide",
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
new ToolMessage({
|
||||
tool_call_id: "12345",
|
||||
content: "The answer is 172.558.",
|
||||
}),
|
||||
new AIMessage("The answer is 172.558."),
|
||||
]`
|
||||
|
||||
class LLMNode_SeqAgents implements INode {
|
||||
label: string
|
||||
name: string
|
||||
@@ -147,7 +173,7 @@ class LLMNode_SeqAgents implements INode {
|
||||
constructor() {
|
||||
this.label = 'LLM Node'
|
||||
this.name = 'seqLLMNode'
|
||||
this.version = 2.0
|
||||
this.version = 3.0
|
||||
this.type = 'LLMNode'
|
||||
this.icon = 'llmNode.svg'
|
||||
this.category = 'Sequential Agents'
|
||||
@@ -178,6 +204,17 @@ class LLMNode_SeqAgents implements INode {
|
||||
optional: true,
|
||||
additionalParams: true
|
||||
},
|
||||
{
|
||||
label: 'Messages History',
|
||||
name: 'messageHistory',
|
||||
description:
|
||||
'Return a list of messages between System Prompt and Human Prompt. This is useful when you want to provide few shot examples',
|
||||
type: 'code',
|
||||
hideCodeExecute: true,
|
||||
codeExample: messageHistoryExample,
|
||||
optional: true,
|
||||
additionalParams: true
|
||||
},
|
||||
{
|
||||
label: 'Start | Agent | Condition | LLM | Tool Node',
|
||||
name: 'sequentialNode',
|
||||
@@ -355,6 +392,8 @@ class LLMNode_SeqAgents implements INode {
|
||||
state,
|
||||
llm,
|
||||
agent: await createAgent(
|
||||
nodeData,
|
||||
options,
|
||||
llmNodeName,
|
||||
state,
|
||||
bindModel || llm,
|
||||
@@ -394,6 +433,8 @@ class LLMNode_SeqAgents implements INode {
|
||||
}
|
||||
|
||||
async function createAgent(
|
||||
nodeData: INodeData,
|
||||
options: ICommonObject,
|
||||
llmNodeName: string,
|
||||
state: ISeqAgentsState,
|
||||
llm: BaseChatModel,
|
||||
@@ -438,7 +479,9 @@ async function createAgent(
|
||||
if (systemPrompt) promptArrays.unshift(['system', systemPrompt])
|
||||
if (humanPrompt) promptArrays.push(['human', humanPrompt])
|
||||
|
||||
const prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
let prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
prompt = await checkMessageHistory(nodeData, options, prompt, promptArrays, systemPrompt)
|
||||
|
||||
if (multiModalMessageContent.length) {
|
||||
const msg = HumanMessagePromptTemplate.fromTemplate([...multiModalMessageContent])
|
||||
prompt.promptMessages.splice(1, 0, msg)
|
||||
|
||||
@@ -11,6 +11,7 @@ import { BaseChatModel } from '@langchain/core/language_models/chat_models'
|
||||
import { addImagesToMessages, llmSupportsVision } from '../../src/multiModalUtils'
|
||||
import { ICommonObject, IDatabaseEntity, INodeData, ISeqAgentsState, IVisionChatModal } from '../../src/Interface'
|
||||
import { availableDependencies, defaultAllowBuiltInDep, getVars, prepareSandboxVars } from '../../src/utils'
|
||||
import { ChatPromptTemplate, BaseMessagePromptTemplateLike } from '@langchain/core/prompts'
|
||||
|
||||
export const checkCondition = (input: string | number | undefined, condition: string, value: string | number = ''): boolean => {
|
||||
if (!input && condition === 'Is Empty') return true
|
||||
@@ -344,3 +345,34 @@ export class RunnableCallable<I = unknown, O = unknown> extends Runnable<I, O> {
|
||||
return returnValue
|
||||
}
|
||||
}
|
||||
|
||||
export const checkMessageHistory = async (
|
||||
nodeData: INodeData,
|
||||
options: ICommonObject,
|
||||
prompt: ChatPromptTemplate,
|
||||
promptArrays: BaseMessagePromptTemplateLike[],
|
||||
sysPrompt: string
|
||||
) => {
|
||||
const messageHistory = nodeData.inputs?.messageHistory
|
||||
|
||||
if (messageHistory) {
|
||||
const appDataSource = options.appDataSource as DataSource
|
||||
const databaseEntities = options.databaseEntities as IDatabaseEntity
|
||||
const vm = await getVM(appDataSource, databaseEntities, nodeData, {})
|
||||
try {
|
||||
const response = await vm.run(`module.exports = async function() {${messageHistory}}()`, __dirname)
|
||||
if (!Array.isArray(response)) throw new Error('Returned message history must be an array')
|
||||
if (sysPrompt) {
|
||||
// insert at index 1
|
||||
promptArrays.splice(1, 0, ...response)
|
||||
} else {
|
||||
promptArrays.unshift(...response)
|
||||
}
|
||||
prompt = ChatPromptTemplate.fromMessages(promptArrays)
|
||||
} catch (e) {
|
||||
throw new Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return prompt
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user