### What problem does this PR solve? Feat: Make the agent dialog window exposed to the outside world fill in the begin form #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.20.0
| @@ -20,7 +20,7 @@ const LLMLabel = ({ value }: IProps) => { | |||
| height={20} | |||
| size={'small'} | |||
| /> | |||
| {llmName} | |||
| <span className="flex-1 truncate"> {llmName}</span> | |||
| </div> | |||
| ); | |||
| }; | |||
| @@ -143,6 +143,7 @@ export function NextMessageInput({ | |||
| size="icon" | |||
| variant="ghost" | |||
| className="size-7 rounded-sm" | |||
| disabled={isUploading || sendLoading} | |||
| > | |||
| <Paperclip className="size-3.5" /> | |||
| <span className="sr-only">Attach file</span> | |||
| @@ -10,6 +10,7 @@ import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow'; | |||
| import { IDebugSingleRequestBody } from '@/interfaces/request/agent'; | |||
| import i18n from '@/locales/config'; | |||
| import { BeginId } from '@/pages/agent/constant'; | |||
| import { BeginQuery } from '@/pages/agent/interface'; | |||
| import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks'; | |||
| import agentService, { | |||
| fetchAgentLogsByCanvasId, | |||
| @@ -46,6 +47,7 @@ export const enum AgentApiAction { | |||
| FetchVersionList = 'fetchVersionList', | |||
| FetchVersion = 'fetchVersion', | |||
| FetchAgentAvatar = 'fetchAgentAvatar', | |||
| FetchExternalAgentInputs = 'fetchExternalAgentInputs', | |||
| } | |||
| export const EmptyDsl = { | |||
| @@ -584,3 +586,28 @@ export const useFetchAgentLog = (searchParams: IAgentLogsRequest) => { | |||
| return { data, loading }; | |||
| }; | |||
| export const useFetchExternalAgentInputs = () => { | |||
| const { sharedId } = useGetSharedChatSearchParams(); | |||
| const { | |||
| data, | |||
| isFetching: loading, | |||
| refetch, | |||
| } = useQuery<Record<string, BeginQuery>>({ | |||
| queryKey: [AgentApiAction.FetchExternalAgentInputs], | |||
| initialData: {} as Record<string, BeginQuery>, | |||
| refetchOnReconnect: false, | |||
| refetchOnMount: false, | |||
| refetchOnWindowFocus: false, | |||
| gcTime: 0, | |||
| enabled: !!sharedId, | |||
| queryFn: async () => { | |||
| const { data } = await agentService.fetchExternalAgentInputs(sharedId!); | |||
| return data?.data ?? {}; | |||
| }, | |||
| }); | |||
| return { data, loading, refetch }; | |||
| }; | |||
| @@ -176,6 +176,7 @@ export function useSetUploadResponseData() { | |||
| export const useSendAgentMessage = ( | |||
| url?: string, | |||
| addEventList?: (data: IEventList, messageId: string) => void, | |||
| beginParams?: any[], | |||
| ) => { | |||
| const { id: agentId } = useParams(); | |||
| const { handleInputChange, value, setValue } = useHandleMessageInputChange(); | |||
| @@ -226,7 +227,9 @@ export const useSendAgentMessage = ( | |||
| params.query = message.content; | |||
| // params.message_id = message.id; | |||
| params.inputs = transferInputsArrayToObject(query); // begin operator inputs | |||
| params.inputs = transferInputsArrayToObject( | |||
| beginParams ? beginParams : query, | |||
| ); // begin operator inputs | |||
| params.files = uploadResponseList; | |||
| @@ -248,13 +251,14 @@ export const useSendAgentMessage = ( | |||
| }, | |||
| [ | |||
| agentId, | |||
| sessionId, | |||
| send, | |||
| clearUploadResponseList, | |||
| inputs, | |||
| beginParams, | |||
| uploadResponseList, | |||
| sessionId, | |||
| setValue, | |||
| removeLatestMessage, | |||
| clearUploadResponseList, | |||
| ], | |||
| ); | |||
| @@ -487,6 +487,16 @@ export const initialExeSqlValues = { | |||
| port: 3306, | |||
| password: '', | |||
| max_records: 1024, | |||
| outputs: { | |||
| formalized_content: { | |||
| value: '', | |||
| type: 'string', | |||
| }, | |||
| json: { | |||
| value: [], | |||
| type: 'Array<Object>', | |||
| }, | |||
| }, | |||
| }; | |||
| export const initialSwitchValues = { | |||
| @@ -20,10 +20,14 @@ import { useFormValues } from '../../hooks/use-form-values'; | |||
| import { useWatchFormChange } from '../../hooks/use-watch-form-change'; | |||
| import { INextOperatorForm } from '../../interface'; | |||
| import { ExeSQLOptions } from '../../options'; | |||
| import { buildOutputList } from '../../utils/build-output-list'; | |||
| import { FormWrapper } from '../components/form-wrapper'; | |||
| import { Output } from '../components/output'; | |||
| import { QueryVariable } from '../components/query-variable'; | |||
| import { FormSchema, useSubmitForm } from './use-submit-form'; | |||
| const outputList = buildOutputList(initialExeSqlValues.outputs); | |||
| export function ExeSQLFormWidgets({ loading }: { loading: boolean }) { | |||
| const form = useFormContext(); | |||
| const { t } = useTranslate('flow'); | |||
| @@ -153,6 +157,9 @@ function ExeSQLForm({ node }: INextOperatorForm) { | |||
| <QueryVariable name="sql"></QueryVariable> | |||
| <ExeSQLFormWidgets loading={loading}></ExeSQLFormWidgets> | |||
| </FormWrapper> | |||
| <div className="p-5"> | |||
| <Output list={outputList}></Output> | |||
| </div> | |||
| </Form> | |||
| ); | |||
| } | |||
| @@ -18,7 +18,6 @@ import { | |||
| import { SharedFrom } from '@/constants/chat'; | |||
| import { useSetModalState } from '@/hooks/common-hooks'; | |||
| import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; | |||
| import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; | |||
| import { ReactFlowProvider } from '@xyflow/react'; | |||
| import { | |||
| ChevronDown, | |||
| @@ -37,10 +36,7 @@ import AgentCanvas from './canvas'; | |||
| import EmbedDialog from './embed-dialog'; | |||
| import { useHandleExportOrImportJsonFile } from './hooks/use-export-json'; | |||
| import { useFetchDataOnMount } from './hooks/use-fetch-data'; | |||
| import { | |||
| useGetBeginNodeDataInputs, | |||
| useGetBeginNodeDataQueryIsSafe, | |||
| } from './hooks/use-get-begin-query'; | |||
| import { useGetBeginNodeDataInputs } from './hooks/use-get-begin-query'; | |||
| import { | |||
| useSaveGraph, | |||
| useSaveGraphBeforeOpeningDebugDrawer, | |||
| @@ -69,7 +65,6 @@ export default function Agent() { | |||
| showModal: showChatDrawer, | |||
| } = useSetModalState(); | |||
| const { t } = useTranslation(); | |||
| const { data: userInfo } = useFetchUserInfo(); | |||
| // const openDocument = useOpenDocument(); | |||
| const { | |||
| @@ -99,7 +94,6 @@ export default function Agent() { | |||
| const { showEmbedModal, hideEmbedModal, embedVisible, beta } = | |||
| useShowEmbedModal(); | |||
| const { navigateToAgentLogs } = useNavigatePage(); | |||
| const isBeginNodeDataQuerySafe = useGetBeginNodeDataQueryIsSafe(); | |||
| return ( | |||
| <section className="h-full"> | |||
| @@ -165,13 +159,7 @@ export default function Agent() { | |||
| {location.hostname !== 'demo.ragflow.io' && ( | |||
| <> | |||
| <DropdownMenuSeparator /> | |||
| <AgentDropdownMenuItem | |||
| onClick={showEmbedModal} | |||
| disabled={ | |||
| !isBeginNodeDataQuerySafe || | |||
| userInfo.nickname !== agentDetail.nickname | |||
| } | |||
| > | |||
| <AgentDropdownMenuItem onClick={showEmbedModal}> | |||
| <ScreenShare /> | |||
| {t('common.embedIntoSite')} | |||
| </AgentDropdownMenuItem> | |||
| @@ -1,7 +1,9 @@ | |||
| import { SharedFrom } from '@/constants/chat'; | |||
| import { useSetModalState } from '@/hooks/common-hooks'; | |||
| import { IEventList } from '@/hooks/use-send-message'; | |||
| import { useSendAgentMessage } from '@/pages/agent/chat/use-send-agent-message'; | |||
| import trim from 'lodash/trim'; | |||
| import { useCallback, useState } from 'react'; | |||
| import { useSearchParams } from 'umi'; | |||
| export const useSendButtonDisabled = (value: string) => { | |||
| @@ -34,10 +36,30 @@ export const useSendNextSharedMessage = ( | |||
| const { from, sharedId: conversationId } = useGetSharedChatSearchParams(); | |||
| const url = `/api/v1/${from === SharedFrom.Agent ? 'agentbots' : 'chatbots'}/${conversationId}/completions`; | |||
| const ret = useSendAgentMessage(url, addEventList); | |||
| const [params, setParams] = useState<any[]>([]); | |||
| const { | |||
| visible: parameterDialogVisible, | |||
| hideModal: hideParameterDialog, | |||
| showModal: showParameterDialog, | |||
| } = useSetModalState(); | |||
| const ret = useSendAgentMessage(url, addEventList, params); | |||
| const ok = useCallback( | |||
| (params: any[]) => { | |||
| setParams(params); | |||
| hideParameterDialog(); | |||
| }, | |||
| [hideParameterDialog], | |||
| ); | |||
| return { | |||
| ...ret, | |||
| hasError: false, | |||
| parameterDialogVisible, | |||
| hideParameterDialog, | |||
| showParameterDialog, | |||
| ok, | |||
| }; | |||
| }; | |||
| @@ -3,10 +3,9 @@ import { NextMessageInput } from '@/components/message-input/next'; | |||
| import MessageItem from '@/components/next-message-item'; | |||
| import PdfDrawer from '@/components/pdf-drawer'; | |||
| import { useClickDrawer } from '@/components/pdf-drawer/hooks'; | |||
| import { MessageType, SharedFrom } from '@/constants/chat'; | |||
| import { useFetchNextConversationSSE } from '@/hooks/chat-hooks'; | |||
| import { MessageType } from '@/constants/chat'; | |||
| import { | |||
| useFetchAgentAvatar, | |||
| useFetchExternalAgentInputs, | |||
| useUploadCanvasFileWithProgress, | |||
| } from '@/hooks/use-agent-request'; | |||
| import { cn } from '@/lib/utils'; | |||
| @@ -14,11 +13,13 @@ import i18n from '@/locales/config'; | |||
| import { useCacheChatLog } from '@/pages/agent/hooks/use-cache-chat-log'; | |||
| import { useSendButtonDisabled } from '@/pages/chat/hooks'; | |||
| import { buildMessageUuidWithRole } from '@/utils/chat'; | |||
| import React, { forwardRef, useCallback, useMemo } from 'react'; | |||
| import { isEmpty } from 'lodash'; | |||
| import React, { forwardRef, useCallback } from 'react'; | |||
| import { | |||
| useGetSharedChatSearchParams, | |||
| useSendNextSharedMessage, | |||
| } from '../hooks/use-send-shared-message'; | |||
| import { ParameterDialog } from './parameter-dialog'; | |||
| const ChatContainer = () => { | |||
| const { | |||
| @@ -48,8 +49,13 @@ const ChatContainer = () => { | |||
| stopOutputMessage, | |||
| findReferenceByMessageId, | |||
| appendUploadResponseList, | |||
| parameterDialogVisible, | |||
| hideParameterDialog, | |||
| showParameterDialog, | |||
| ok, | |||
| } = useSendNextSharedMessage(addEventList); | |||
| const { data } = useFetchExternalAgentInputs(); | |||
| const sendDisabled = useSendButtonDisabled(value); | |||
| // useEffect(() => { | |||
| @@ -64,12 +70,6 @@ const ChatContainer = () => { | |||
| // } | |||
| // }, [derivedMessages, setCurrentMessageId]); | |||
| const useFetchAvatar = useMemo(() => { | |||
| return from === SharedFrom.Agent | |||
| ? useFetchAgentAvatar | |||
| : useFetchNextConversationSSE; | |||
| }, [from]); | |||
| const handleUploadFile: NonNullable<FileUploadProps['onUpload']> = | |||
| useCallback( | |||
| async (files, options) => { | |||
| @@ -84,12 +84,16 @@ const ChatContainer = () => { | |||
| i18n.changeLanguage(locale); | |||
| } | |||
| }, [locale, visibleAvatar]); | |||
| const { data: avatarData } = useFetchAvatar(); | |||
| React.useEffect(() => { | |||
| if (!isEmpty(data)) { | |||
| showParameterDialog(); | |||
| } | |||
| }, [data, showParameterDialog]); | |||
| if (!conversationId) { | |||
| return <div>empty</div>; | |||
| } | |||
| return ( | |||
| <section className="h-[100vh] flex justify-center items-center"> | |||
| <div className=" w-[80vw]"> | |||
| @@ -108,7 +112,6 @@ const ChatContainer = () => { | |||
| } | |||
| setCurrentMessageId={setCurrentMessageId} | |||
| key={buildMessageUuidWithRole(message)} | |||
| avatarDialog={avatarData.avatar} | |||
| item={message} | |||
| nickname="You" | |||
| reference={findReferenceByMessageId(message.id)} | |||
| @@ -156,6 +159,12 @@ const ChatContainer = () => { | |||
| chunk={selectedChunk} | |||
| ></PdfDrawer> | |||
| )} | |||
| {parameterDialogVisible && ( | |||
| <ParameterDialog | |||
| hideModal={hideParameterDialog} | |||
| ok={ok} | |||
| ></ParameterDialog> | |||
| )} | |||
| </section> | |||
| ); | |||
| }; | |||
| @@ -0,0 +1,33 @@ | |||
| import { | |||
| Dialog, | |||
| DialogContent, | |||
| DialogHeader, | |||
| DialogTitle, | |||
| } from '@/components/ui/dialog'; | |||
| import { useFetchExternalAgentInputs } from '@/hooks/use-agent-request'; | |||
| import { IModalProps } from '@/interfaces/common'; | |||
| import DebugContent from '@/pages/agent/debug-content'; | |||
| import { buildBeginInputListFromObject } from '@/pages/agent/form/begin-form/utils'; | |||
| interface IProps extends IModalProps<any> { | |||
| ok(parameters: any[]): void; | |||
| } | |||
| export function ParameterDialog({ hideModal, ok }: IProps) { | |||
| const { data } = useFetchExternalAgentInputs(); | |||
| return ( | |||
| <Dialog open onOpenChange={hideModal}> | |||
| <DialogContent> | |||
| <DialogHeader> | |||
| <DialogTitle>Parameter</DialogTitle> | |||
| </DialogHeader> | |||
| <DebugContent | |||
| parameters={buildBeginInputListFromObject(data)} | |||
| ok={ok} | |||
| isNext={false} | |||
| btnText={'Submit'} | |||
| ></DebugContent> | |||
| </DialogContent> | |||
| </Dialog> | |||
| ); | |||
| } | |||
| @@ -24,6 +24,7 @@ const { | |||
| fetchCanvas, | |||
| fetchAgentAvatar, | |||
| fetchAgentLogs, | |||
| fetchExternalAgentInputs, | |||
| } = api; | |||
| const methods = { | |||
| @@ -107,6 +108,10 @@ const methods = { | |||
| url: fetchAgentLogs, | |||
| method: 'get', | |||
| }, | |||
| fetchExternalAgentInputs: { | |||
| url: fetchExternalAgentInputs, | |||
| method: 'get', | |||
| }, | |||
| } as const; | |||
| const agentService = registerNextServer<keyof typeof methods>(methods); | |||
| @@ -1,4 +1,5 @@ | |||
| let api_host = `/v1`; | |||
| const ExternalApi = `/api`; | |||
| export { api_host }; | |||
| @@ -155,6 +156,8 @@ export default { | |||
| uploadAgentFile: (id?: string) => `${api_host}/canvas/upload/${id}`, | |||
| fetchAgentLogs: (canvasId: string) => | |||
| `${api_host}/canvas/${canvasId}/sessions`, | |||
| fetchExternalAgentInputs: (canvasId: string) => | |||
| `${ExternalApi}${api_host}/agentbots/${canvasId}/inputs`, | |||
| // mcp server | |||
| listMcpServer: `${api_host}/mcp_server/list`, | |||