### What problem does this PR solve? Feat: Use the message_id returned by the interface as the id of the reply message #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.20.0
| @@ -334,6 +334,20 @@ export const useSelectDerivedMessages = () => { | |||
| [], | |||
| ); | |||
| const addNewestOneQuestion = useCallback((message: Message) => { | |||
| setDerivedMessages((pre) => { | |||
| return [ | |||
| ...pre, | |||
| { | |||
| ...message, | |||
| id: buildMessageUuid(message), // The message id is generated on the front end, | |||
| // and the message id returned by the back end is the same as the question id, | |||
| // so that the pair of messages can be deleted together when deleting the message | |||
| }, | |||
| ]; | |||
| }); | |||
| }, []); | |||
| // Add the streaming message to the last item in the message list | |||
| const addNewestAnswer = useCallback((answer: IAnswer) => { | |||
| setDerivedMessages((pre) => { | |||
| @@ -355,6 +369,38 @@ export const useSelectDerivedMessages = () => { | |||
| }); | |||
| }, []); | |||
| // Add the streaming message to the last item in the message list | |||
| const addNewestOneAnswer = useCallback((answer: IAnswer) => { | |||
| setDerivedMessages((pre) => { | |||
| const idx = pre.findIndex((x) => x.id === answer.id); | |||
| if (idx !== -1) { | |||
| return pre.map((x) => { | |||
| if (x.id === answer.id) { | |||
| return { ...x, content: answer.answer }; | |||
| } | |||
| return x; | |||
| }); | |||
| } | |||
| return [ | |||
| ...(pre ?? []), | |||
| { | |||
| role: MessageType.Assistant, | |||
| content: answer.answer, | |||
| reference: answer.reference, | |||
| id: buildMessageUuid({ | |||
| id: answer.id, | |||
| role: MessageType.Assistant, | |||
| }), | |||
| prompt: answer.prompt, | |||
| audio_binary: answer.audio_binary, | |||
| ...omit(answer, 'reference'), | |||
| }, | |||
| ]; | |||
| }); | |||
| }, []); | |||
| const removeLatestMessage = useCallback(() => { | |||
| setDerivedMessages((pre) => { | |||
| const nextMessages = pre?.slice(0, -2) ?? []; | |||
| @@ -406,6 +452,8 @@ export const useSelectDerivedMessages = () => { | |||
| addNewestAnswer, | |||
| removeLatestMessage, | |||
| removeMessageById, | |||
| addNewestOneQuestion, | |||
| addNewestOneAnswer, | |||
| removeMessagesAfterCurrentMessage, | |||
| }; | |||
| }; | |||
| @@ -93,7 +93,9 @@ function AccordionOperators() { | |||
| <AccordionItem value="item-5"> | |||
| <AccordionTrigger className="text-xl">Tools</AccordionTrigger> | |||
| <AccordionContent className="flex flex-col gap-4 text-balance"> | |||
| <OperatorItemList operators={[Operator.Tavily]}></OperatorItemList> | |||
| <OperatorItemList | |||
| operators={[Operator.TavilySearch]} | |||
| ></OperatorItemList> | |||
| </AccordionContent> | |||
| </AccordionItem> | |||
| </Accordion> | |||
| @@ -37,6 +37,8 @@ export const useSelectNextMessages = () => { | |||
| removeLatestMessage, | |||
| removeMessageById, | |||
| removeMessagesAfterCurrentMessage, | |||
| addNewestOneQuestion, | |||
| addNewestOneAnswer, | |||
| } = useSelectDerivedMessages(); | |||
| return { | |||
| @@ -48,6 +50,8 @@ export const useSelectNextMessages = () => { | |||
| addNewestAnswer, | |||
| removeLatestMessage, | |||
| removeMessageById, | |||
| addNewestOneQuestion, | |||
| addNewestOneAnswer, | |||
| removeMessagesAfterCurrentMessage, | |||
| }; | |||
| }; | |||
| @@ -57,7 +61,7 @@ function findMessageFromList(eventList: IEventList) { | |||
| (x) => x.event === MessageEventType.Message, | |||
| ) as IMessageEvent[]; | |||
| return { | |||
| id: messageEventList[0]?.message_id, | |||
| id: eventList[0]?.message_id, | |||
| content: messageEventList.map((x) => x.data.content).join(''), | |||
| }; | |||
| } | |||
| @@ -83,6 +87,8 @@ export const useSendNextMessage = () => { | |||
| addNewestAnswer, | |||
| removeLatestMessage, | |||
| removeMessageById, | |||
| addNewestOneQuestion, | |||
| addNewestOneAnswer, | |||
| } = useSelectNextMessages(); | |||
| const { id: agentId } = useParams(); | |||
| const { handleInputChange, value, setValue } = useHandleMessageInputChange(); | |||
| @@ -132,13 +138,13 @@ export const useSendNextMessage = () => { | |||
| useEffect(() => { | |||
| const { content, id } = findMessageFromList(answerList); | |||
| if (content) { | |||
| addNewestAnswer({ | |||
| if (answerList.length > 0) { | |||
| addNewestOneAnswer({ | |||
| answer: content, | |||
| id: id, | |||
| }); | |||
| } | |||
| }, [answerList, addNewestAnswer]); | |||
| }, [answerList, addNewestOneAnswer]); | |||
| const handlePressEnter = useCallback(() => { | |||
| if (trim(value) === '') return; | |||
| @@ -147,20 +153,20 @@ export const useSendNextMessage = () => { | |||
| setValue(''); | |||
| handleSendMessage({ id, content: value.trim(), role: MessageType.User }); | |||
| } | |||
| addNewestQuestion({ | |||
| addNewestOneQuestion({ | |||
| content: value, | |||
| id, | |||
| role: MessageType.User, | |||
| }); | |||
| }, [addNewestQuestion, handleSendMessage, done, setValue, value]); | |||
| }, [value, done, addNewestOneQuestion, setValue, handleSendMessage]); | |||
| useEffect(() => { | |||
| if (prologue) { | |||
| addNewestAnswer({ | |||
| addNewestOneAnswer({ | |||
| answer: prologue, | |||
| }); | |||
| } | |||
| }, [addNewestAnswer, prologue]); | |||
| }, [addNewestOneAnswer, prologue]); | |||
| useEffect(() => { | |||
| addEventList(answerList); | |||
| @@ -85,7 +85,7 @@ export enum Operator { | |||
| WaitingDialogue = 'WaitingDialogue', | |||
| Agent = 'Agent', | |||
| Tool = 'Tool', | |||
| Tavily = 'Tavily', | |||
| TavilySearch = 'TavilySearch', | |||
| } | |||
| export const SwitchLogicOperatorOptions = ['and', 'or']; | |||
| @@ -250,7 +250,7 @@ export const operatorMap: Record< | |||
| [Operator.Code]: { backgroundColor: '#4c5458' }, | |||
| [Operator.WaitingDialogue]: { backgroundColor: '#a5d65c' }, | |||
| [Operator.Agent]: { backgroundColor: '#a5d65c' }, | |||
| [Operator.Tavily]: { backgroundColor: '#a5d65c' }, | |||
| [Operator.TavilySearch]: { backgroundColor: '#a5d65c' }, | |||
| }; | |||
| export const componentMenuList = [ | |||
| @@ -805,6 +805,7 @@ export const RestrictedUpstreamMap = { | |||
| [Operator.Code]: [Operator.Begin], | |||
| [Operator.WaitingDialogue]: [Operator.Begin], | |||
| [Operator.Agent]: [Operator.Begin], | |||
| [Operator.TavilySearch]: [Operator.Begin], | |||
| }; | |||
| export const NodeMap = { | |||
| @@ -848,7 +849,7 @@ export const NodeMap = { | |||
| [Operator.WaitingDialogue]: 'ragNode', | |||
| [Operator.Agent]: 'agentNode', | |||
| [Operator.Tool]: 'toolNode', | |||
| [Operator.Tavily]: 'ragNode', | |||
| [Operator.TavilySearch]: 'ragNode', | |||
| }; | |||
| export const LanguageOptions = [ | |||
| @@ -43,7 +43,7 @@ const FormSheet = ({ | |||
| const currentFormMap = FormConfigMap[operatorName]; | |||
| const OperatorForm = currentFormMap.component ?? EmptyContent; | |||
| const OperatorForm = currentFormMap?.component ?? EmptyContent; | |||
| const { name, handleNameBlur, handleNameChange } = useHandleNodeNameChange({ | |||
| id: node?.id, | |||
| @@ -376,7 +376,7 @@ export function useFormConfigMap() { | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Tavily]: { | |||
| [Operator.TavilySearch]: { | |||
| component: TavilyForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| @@ -16,7 +16,7 @@ const Menus = [ | |||
| { | |||
| label: 'Search', | |||
| list: [ | |||
| Operator.Tavily, | |||
| Operator.TavilySearch, | |||
| Operator.Google, | |||
| Operator.Bing, | |||
| Operator.DuckDuckGo, | |||
| @@ -34,5 +34,5 @@ export const ToolFormConfigMap = { | |||
| [Operator.YahooFinance]: YahooFinanceForm, | |||
| [Operator.Crawler]: CrawlerForm, | |||
| [Operator.Email]: EmailForm, | |||
| [Operator.Tavily]: TavilyForm, | |||
| [Operator.TavilySearch]: TavilyForm, | |||
| }; | |||
| @@ -150,7 +150,7 @@ export const useInitializeOperatorParams = () => { | |||
| [Operator.Code]: initialCodeValues, | |||
| [Operator.WaitingDialogue]: initialWaitingDialogueValues, | |||
| [Operator.Agent]: { ...initialAgentValues, llm_id: llmId }, | |||
| [Operator.Tavily]: initialTavilyValues, | |||
| [Operator.TavilySearch]: initialTavilyValues, | |||
| }; | |||
| }, [llmId]); | |||
| @@ -105,7 +105,7 @@ export const useInitializeOperatorParams = () => { | |||
| [Operator.WaitingDialogue]: initialWaitingDialogueValues, | |||
| [Operator.Agent]: { ...initialAgentValues, llm_id: llmId }, | |||
| [Operator.Tool]: {}, | |||
| [Operator.Tavily]: initialTavilyValues, | |||
| [Operator.TavilySearch]: initialTavilyValues, | |||
| }; | |||
| }, [llmId]); | |||
| @@ -94,9 +94,20 @@ const buildComponentDownstreamOrUpstream = ( | |||
| edges: Edge[], | |||
| nodeId: string, | |||
| isBuildDownstream = true, | |||
| nodes: Node[], | |||
| ) => { | |||
| return edges | |||
| .filter((y) => y[isBuildDownstream ? 'source' : 'target'] === nodeId) | |||
| .filter((y) => { | |||
| const node = nodes.find((x) => x.id === nodeId); | |||
| let isNotUpstreamTool = true; | |||
| if (isBuildDownstream && node?.data.label === Operator.Agent) { | |||
| isNotUpstreamTool = !y.target.startsWith(Operator.Tool); // Exclude the tool operator downstream of the agent operator | |||
| } | |||
| return ( | |||
| y[isBuildDownstream ? 'source' : 'target'] === nodeId && | |||
| isNotUpstreamTool | |||
| ); | |||
| }) | |||
| .map((y) => y[isBuildDownstream ? 'target' : 'source']); | |||
| }; | |||
| @@ -125,6 +136,8 @@ const buildOperatorParams = (operatorName: string) => | |||
| // initializeOperatorParams(operatorName), // Final processing, for guarantee | |||
| ); | |||
| const ExcludeOperators = [Operator.Note, Operator.Tool]; | |||
| // construct a dsl based on the node information of the graph | |||
| export const buildDslComponentsByGraph = ( | |||
| nodes: RAGFlowNodeType[], | |||
| @@ -134,7 +147,7 @@ export const buildDslComponentsByGraph = ( | |||
| const components: DSLComponents = {}; | |||
| nodes | |||
| ?.filter((x) => x.data.label !== Operator.Note) | |||
| ?.filter((x) => !ExcludeOperators.some((y) => y === x.data.label)) | |||
| .forEach((x) => { | |||
| const id = x.id; | |||
| const operatorName = x.data.label; | |||
| @@ -147,8 +160,8 @@ export const buildDslComponentsByGraph = ( | |||
| x.data.form as Record<string, unknown>, | |||
| ) ?? {}, | |||
| }, | |||
| downstream: buildComponentDownstreamOrUpstream(edges, id, true), | |||
| upstream: buildComponentDownstreamOrUpstream(edges, id, false), | |||
| downstream: buildComponentDownstreamOrUpstream(edges, id, true, nodes), | |||
| upstream: buildComponentDownstreamOrUpstream(edges, id, false, nodes), | |||
| parent_id: x?.parentId, | |||
| }; | |||
| }); | |||