### What problem does this PR solve? Feat: Let system variables appear in operator prompts #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.1
| @@ -1,14 +1,6 @@ | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { Form, Slider } from 'antd'; | |||
| import { useFormContext } from 'react-hook-form'; | |||
| import { SingleFormSlider } from './ui/dual-range-slider'; | |||
| import { | |||
| FormControl, | |||
| FormField, | |||
| FormItem, | |||
| FormLabel, | |||
| FormMessage, | |||
| } from './ui/form'; | |||
| import { SliderInputFormField } from './slider-input-form-field'; | |||
| type FieldType = { | |||
| top_n?: number; | |||
| @@ -41,22 +33,14 @@ interface SimilaritySliderFormFieldProps { | |||
| } | |||
| export function TopNFormField({ max = 30 }: SimilaritySliderFormFieldProps) { | |||
| const form = useFormContext(); | |||
| const { t } = useTranslate('chat'); | |||
| return ( | |||
| <FormField | |||
| control={form.control} | |||
| <SliderInputFormField | |||
| name={'top_n'} | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel tooltip={t('topNTip')}>{t('topN')}</FormLabel> | |||
| <FormControl> | |||
| <SingleFormSlider {...field} max={max}></SingleFormSlider> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| label={t('topN')} | |||
| max={max} | |||
| tooltip={t('topNTip')} | |||
| ></SliderInputFormField> | |||
| ); | |||
| } | |||
| @@ -20,3 +20,10 @@ async function main(args) { | |||
| module.exports = { main }; | |||
| `, | |||
| }; | |||
| export enum AgentGlobals { | |||
| SysQuery = 'sys.query', | |||
| SysUserId = 'sys.user_id', | |||
| SysConversationTurns = 'sys.conversation_turns', | |||
| SysFiles = 'sys.files', | |||
| } | |||
| @@ -1,3 +1,4 @@ | |||
| import { AgentGlobals } from '@/constants/agent'; | |||
| import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow'; | |||
| import i18n from '@/locales/config'; | |||
| import { BeginId } from '@/pages/agent/constant'; | |||
| @@ -61,10 +62,10 @@ export const EmptyDsl = { | |||
| history: [], | |||
| path: [], | |||
| globals: { | |||
| 'sys.query': '', | |||
| 'sys.user_id': '', | |||
| 'sys.conversation_turns': 0, | |||
| 'sys.files': [], | |||
| [AgentGlobals.SysQuery]: '', | |||
| [AgentGlobals.SysUserId]: '', | |||
| [AgentGlobals.SysConversationTurns]: 0, | |||
| [AgentGlobals.SysFiles]: [], | |||
| }, | |||
| }; | |||
| @@ -12,6 +12,7 @@ export interface DSL { | |||
| messages: Message[]; | |||
| reference: IReference[]; | |||
| globals: Record<string, any>; | |||
| retrieval: IReference[]; | |||
| } | |||
| export interface IOperator { | |||
| @@ -16,7 +16,8 @@ import { | |||
| } from '../hooks'; | |||
| import { useAddNode } from '../hooks/use-add-node'; | |||
| import { useBeforeDelete } from '../hooks/use-before-delete'; | |||
| import { useShowDrawer } from '../hooks/use-show-drawer'; | |||
| import { useShowDrawer, useShowLogSheet } from '../hooks/use-show-drawer'; | |||
| import { LogSheet } from '../log-sheet'; | |||
| import RunSheet from '../run-sheet'; | |||
| import { ButtonEdge } from './edge'; | |||
| import styles from './index.less'; | |||
| @@ -100,6 +101,8 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) { | |||
| hideDrawer, | |||
| }); | |||
| const { showLogSheet, logSheetVisible, hideLogSheet } = useShowLogSheet(); | |||
| const { handleBeforeDelete } = useBeforeDelete(); | |||
| useWatchNodeFormDataChange(); | |||
| @@ -178,13 +181,15 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) { | |||
| hideModal={hideRunOrChatDrawer} | |||
| ></ChatSheet> | |||
| )} | |||
| {runVisible && ( | |||
| <RunSheet | |||
| hideModal={hideRunOrChatDrawer} | |||
| showModal={showChatModal} | |||
| ></RunSheet> | |||
| )} | |||
| {logSheetVisible && ( | |||
| <LogSheet hideModal={hideLogSheet} showModal={showLogSheet}></LogSheet> | |||
| )} | |||
| </div> | |||
| ); | |||
| } | |||
| @@ -35,7 +35,7 @@ const AgentChatBox = () => { | |||
| return ( | |||
| <> | |||
| <section className="flex flex-1 flex-col pl-5 h-[90vh]"> | |||
| <div className="flex-1 "> | |||
| <div className="flex-1 overflow-auto"> | |||
| <div> | |||
| <Spin spinning={loading}> | |||
| {derivedMessages?.map((message, i) => { | |||
| @@ -27,7 +27,7 @@ const antMessage = message; | |||
| export const useSelectNextMessages = () => { | |||
| const { data: flowDetail, loading } = useFetchAgent(); | |||
| const reference = flowDetail.dsl.reference; | |||
| const reference = flowDetail.dsl.retrieval; | |||
| const { | |||
| derivedMessages, | |||
| ref, | |||
| @@ -134,11 +134,6 @@ export const useSendNextMessage = () => { | |||
| addNewestAnswer({ | |||
| answer: content, | |||
| id: id, | |||
| reference: { | |||
| chunks: [], | |||
| doc_aggs: [], | |||
| total: 0, | |||
| }, | |||
| }); | |||
| } | |||
| }, [answerList, addNewestAnswer]); | |||
| @@ -161,11 +156,6 @@ export const useSendNextMessage = () => { | |||
| if (prologue) { | |||
| addNewestAnswer({ | |||
| answer: prologue, | |||
| reference: { | |||
| chunks: [], | |||
| doc_aggs: [], | |||
| total: 0, | |||
| }, | |||
| }); | |||
| } | |||
| }, [addNewestAnswer, prologue]); | |||
| @@ -31,7 +31,11 @@ import { | |||
| initialKeywordsSimilarityWeightValue, | |||
| initialSimilarityThresholdValue, | |||
| } from '@/components/similarity-slider'; | |||
| import { CodeTemplateStrMap, ProgrammingLanguage } from '@/constants/agent'; | |||
| import { | |||
| AgentGlobals, | |||
| CodeTemplateStrMap, | |||
| ProgrammingLanguage, | |||
| } from '@/constants/agent'; | |||
| export enum AgentDialogueMode { | |||
| Conversational = 'conversational', | |||
| @@ -52,6 +56,11 @@ export enum Channel { | |||
| News = 'news', | |||
| } | |||
| export enum PromptRole { | |||
| User = 'user', | |||
| Assistant = 'assistant', | |||
| } | |||
| import { | |||
| BranchesOutlined, | |||
| DatabaseOutlined, | |||
| @@ -707,7 +716,7 @@ export const initialWaitingDialogueValues = {}; | |||
| export const initialAgentValues = { | |||
| ...initialLlmBaseValues, | |||
| sys_prompt: ``, | |||
| prompts: [], | |||
| prompts: [{ role: PromptRole.User, content: `{${AgentGlobals.SysQuery}}` }], | |||
| message_history_window_size: 12, | |||
| tools: [], | |||
| outputs: { | |||
| @@ -1,4 +0,0 @@ | |||
| export enum PromptRole { | |||
| User = 'user', | |||
| Assistant = 'assistant', | |||
| } | |||
| @@ -11,8 +11,8 @@ import { X } from 'lucide-react'; | |||
| import { memo } from 'react'; | |||
| import { useFieldArray, useFormContext } from 'react-hook-form'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { PromptRole } from '../../constant'; | |||
| import { PromptEditor } from '../components/prompt-editor'; | |||
| import { PromptRole } from './constant'; | |||
| const options = [ | |||
| { label: 'User', value: PromptRole.User }, | |||
| @@ -1,7 +1,7 @@ | |||
| import { useEffect } from 'react'; | |||
| import { UseFormReturn, useWatch } from 'react-hook-form'; | |||
| import { PromptRole } from '../../constant'; | |||
| import useGraphStore from '../../store'; | |||
| import { PromptRole } from './constant'; | |||
| export function useWatchFormChange(id?: string, form?: UseFormReturn) { | |||
| let values = useWatch({ control: form?.control }); | |||
| @@ -20,19 +20,12 @@ import { | |||
| $isRangeSelection, | |||
| TextNode, | |||
| } from 'lexical'; | |||
| import React, { | |||
| ReactElement, | |||
| useCallback, | |||
| useContext, | |||
| useEffect, | |||
| useRef, | |||
| } from 'react'; | |||
| import React, { ReactElement, useCallback, useEffect, useRef } from 'react'; | |||
| import * as ReactDOM from 'react-dom'; | |||
| import { $createVariableNode } from './variable-node'; | |||
| import { AgentFormContext } from '@/pages/agent/context'; | |||
| import { useBuildComponentIdSelectOptions } from '@/pages/agent/hooks/use-get-begin-query'; | |||
| import { useBuildQueryVariableOptions } from '@/pages/agent/hooks/use-get-begin-query'; | |||
| import { ProgrammaticTag } from './constant'; | |||
| import './index.css'; | |||
| class VariableInnerOption extends MenuOption { | |||
| @@ -109,15 +102,13 @@ export default function VariablePickerMenuPlugin({ | |||
| const [editor] = useLexicalComposerContext(); | |||
| const isFirstRender = useRef(true); | |||
| const node = useContext(AgentFormContext); | |||
| const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('/', { | |||
| minLength: 0, | |||
| }); | |||
| const [queryString, setQueryString] = React.useState<string | null>(''); | |||
| const options = useBuildComponentIdSelectOptions(node?.id, node?.parentId); | |||
| const options = useBuildQueryVariableOptions(); | |||
| const buildNextOptions = useCallback(() => { | |||
| let filteredOptions = options; | |||
| @@ -6,31 +6,15 @@ import { | |||
| FormLabel, | |||
| FormMessage, | |||
| } from '@/components/ui/form'; | |||
| import { useFetchAgent } from '@/hooks/use-agent-request'; | |||
| import { useContext, useMemo } from 'react'; | |||
| import { useFormContext } from 'react-hook-form'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { AgentFormContext } from '../../context'; | |||
| import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query'; | |||
| import { useBuildQueryVariableOptions } from '../../hooks/use-get-begin-query'; | |||
| export function QueryVariable() { | |||
| const { t } = useTranslation(); | |||
| const form = useFormContext(); | |||
| const { data } = useFetchAgent(); | |||
| const node = useContext(AgentFormContext); | |||
| const options = useBuildComponentIdSelectOptions(node?.id, node?.parentId); | |||
| const nextOptions = useMemo(() => { | |||
| const globalOptions = Object.keys(data?.dsl?.globals ?? {}).map((x) => ({ | |||
| label: x, | |||
| value: x, | |||
| })); | |||
| return [ | |||
| { ...options[0], options: [...options[0]?.options, ...globalOptions] }, | |||
| ...options.slice(1), | |||
| ]; | |||
| }, [data.dsl.globals, options]); | |||
| const nextOptions = useBuildQueryVariableOptions(); | |||
| return ( | |||
| <FormField | |||
| @@ -1,10 +1,12 @@ | |||
| import { useFetchAgent } from '@/hooks/use-agent-request'; | |||
| import { RAGFlowNodeType } from '@/interfaces/database/flow'; | |||
| import { Edge } from '@xyflow/react'; | |||
| import { DefaultOptionType } from 'antd/es/select'; | |||
| import { isEmpty } from 'lodash'; | |||
| import get from 'lodash/get'; | |||
| import { useCallback, useEffect, useMemo, useState } from 'react'; | |||
| import { useCallback, useContext, useEffect, useMemo, useState } from 'react'; | |||
| import { BeginId, Operator } from '../constant'; | |||
| import { AgentFormContext } from '../context'; | |||
| import { buildBeginInputListFromObject } from '../form/begin-form/utils'; | |||
| import { BeginQuery } from '../interface'; | |||
| import useGraphStore from '../store'; | |||
| @@ -173,3 +175,22 @@ export const useGetComponentLabelByValue = (nodeId: string) => { | |||
| ); | |||
| return getLabel; | |||
| }; | |||
| export function useBuildQueryVariableOptions() { | |||
| const { data } = useFetchAgent(); | |||
| const node = useContext(AgentFormContext); | |||
| const options = useBuildComponentIdSelectOptions(node?.id, node?.parentId); | |||
| const nextOptions = useMemo(() => { | |||
| const globalOptions = Object.keys(data?.dsl?.globals ?? {}).map((x) => ({ | |||
| label: x, | |||
| value: x, | |||
| })); | |||
| return [ | |||
| { ...options[0], options: [...options[0]?.options, ...globalOptions] }, | |||
| ...options.slice(1), | |||
| ]; | |||
| }, [data.dsl.globals, options]); | |||
| return nextOptions; | |||
| } | |||
| @@ -151,3 +151,13 @@ export function useShowDrawer({ | |||
| showChatModal, | |||
| }; | |||
| } | |||
| export function useShowLogSheet() { | |||
| const { visible, showModal, hideModal } = useSetModalState(); | |||
| return { | |||
| logSheetVisible: visible, | |||
| hideLogSheet: hideModal, | |||
| showLogSheet: showModal, | |||
| }; | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| import { | |||
| Sheet, | |||
| SheetContent, | |||
| SheetDescription, | |||
| SheetHeader, | |||
| SheetTitle, | |||
| } from '@/components/ui/sheet'; | |||
| import { IModalProps } from '@/interfaces/common'; | |||
| export function LogSheet({ hideModal }: IModalProps<any>) { | |||
| return ( | |||
| <Sheet open onOpenChange={hideModal}> | |||
| <SheetContent> | |||
| <SheetHeader> | |||
| <SheetTitle>Are you absolutely sure?</SheetTitle> | |||
| <SheetDescription> | |||
| This action cannot be undone. This will permanently delete your | |||
| account and remove your data from our servers. | |||
| </SheetDescription> | |||
| </SheetHeader> | |||
| </SheetContent> | |||
| </Sheet> | |||
| ); | |||
| } | |||
| @@ -29,9 +29,9 @@ export const buildMessageItemReference = ( | |||
| conversation: { message: IMessage[]; reference: IReference[] }, | |||
| message: IMessage, | |||
| ) => { | |||
| const assistantMessages = conversation.message | |||
| ?.filter((x) => x.role === MessageType.Assistant) | |||
| .slice(1); | |||
| const assistantMessages = conversation.message?.filter( | |||
| (x) => x.role === MessageType.Assistant, | |||
| ); | |||
| const referenceIndex = assistantMessages.findIndex( | |||
| (x) => x.id === message.id, | |||
| ); | |||