### What problem does this PR solve? Fix: Fixed the issue where the error prompt box on the Agent page would be covered #3221 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)tags/v0.20.0
| return f"result: {arg1 + arg2}" | return f"result: {arg1 + arg2}" | ||||
| `, | `, | ||||
| [ProgrammingLanguage.Javascript]: `const axios = require('axios'); | [ProgrammingLanguage.Javascript]: `const axios = require('axios'); | ||||
| async function main(args) { | |||||
| async function main({}) { | |||||
| try { | try { | ||||
| const response = await axios.get('https://github.com/infiniflow/ragflow'); | const response = await axios.get('https://github.com/infiniflow/ragflow'); | ||||
| console.log('Body:', response.data); | |||||
| return 'Body:' + response.data; | |||||
| } catch (error) { | } catch (error) { | ||||
| console.error('Error:', error.message); | |||||
| return 'Error:' + error.message; | |||||
| } | } | ||||
| } | |||||
| module.exports = { main }; | |||||
| `, | |||||
| }`, | |||||
| }; | }; | ||||
| export enum AgentGlobals { | export enum AgentGlobals { |
| import i18n from '@/locales/config'; | import i18n from '@/locales/config'; | ||||
| import { BeginId } from '@/pages/agent/constant'; | import { BeginId } from '@/pages/agent/constant'; | ||||
| import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks'; | import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks'; | ||||
| import flowService from '@/services/flow-service'; | |||||
| import agentService from '@/services/agent-service'; | |||||
| import { buildMessageListWithUuid } from '@/utils/chat'; | import { buildMessageListWithUuid } from '@/utils/chat'; | ||||
| import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; | import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; | ||||
| import { useDebounce } from 'ahooks'; | import { useDebounce } from 'ahooks'; | ||||
| queryKey: [AgentApiAction.FetchAgentTemplates], | queryKey: [AgentApiAction.FetchAgentTemplates], | ||||
| initialData: [], | initialData: [], | ||||
| queryFn: async () => { | queryFn: async () => { | ||||
| const { data } = await flowService.listTemplates(); | |||||
| const { data } = await agentService.listTemplates(); | |||||
| if (Array.isArray(data?.data)) { | if (Array.isArray(data?.data)) { | ||||
| data.data.unshift({ | data.data.unshift({ | ||||
| id: uuid(), | id: uuid(), | ||||
| initialData: { kbs: [], total: 0 }, | initialData: { kbs: [], total: 0 }, | ||||
| gcTime: 0, | gcTime: 0, | ||||
| queryFn: async () => { | queryFn: async () => { | ||||
| const { data } = await flowService.listCanvasTeam({ | |||||
| keywords: debouncedSearchString, | |||||
| page_size: pagination.pageSize, | |||||
| page: pagination.current, | |||||
| }); | |||||
| const { data } = await agentService.listCanvasTeam( | |||||
| { | |||||
| params: { | |||||
| keywords: debouncedSearchString, | |||||
| page_size: pagination.pageSize, | |||||
| page: pagination.current, | |||||
| }, | |||||
| }, | |||||
| true, | |||||
| ); | |||||
| return data?.data ?? []; | return data?.data ?? []; | ||||
| }, | }, | ||||
| } = useMutation({ | } = useMutation({ | ||||
| mutationKey: [AgentApiAction.UpdateAgentSetting], | mutationKey: [AgentApiAction.UpdateAgentSetting], | ||||
| mutationFn: async (params: any) => { | mutationFn: async (params: any) => { | ||||
| const ret = await flowService.settingCanvas(params); | |||||
| const ret = await agentService.settingCanvas(params); | |||||
| if (ret?.data?.code === 0) { | if (ret?.data?.code === 0) { | ||||
| message.success('success'); | message.success('success'); | ||||
| queryClient.invalidateQueries({ | queryClient.invalidateQueries({ | ||||
| } = useMutation({ | } = useMutation({ | ||||
| mutationKey: [AgentApiAction.DeleteAgent], | mutationKey: [AgentApiAction.DeleteAgent], | ||||
| mutationFn: async (canvasIds: string[]) => { | mutationFn: async (canvasIds: string[]) => { | ||||
| const { data } = await flowService.removeCanvas({ canvasIds }); | |||||
| const { data } = await agentService.removeCanvas({ canvasIds }); | |||||
| if (data.code === 0) { | if (data.code === 0) { | ||||
| queryClient.invalidateQueries({ | queryClient.invalidateQueries({ | ||||
| queryKey: [AgentApiAction.FetchAgentList], | queryKey: [AgentApiAction.FetchAgentList], | ||||
| refetchOnWindowFocus: false, | refetchOnWindowFocus: false, | ||||
| gcTime: 0, | gcTime: 0, | ||||
| queryFn: async () => { | queryFn: async () => { | ||||
| const { data } = await flowService.getCanvas({}, sharedId || id); | |||||
| const { data } = await agentService.fetchCanvas(sharedId || id); | |||||
| const messageList = buildMessageListWithUuid( | const messageList = buildMessageListWithUuid( | ||||
| get(data, 'data.dsl.messages', []), | get(data, 'data.dsl.messages', []), | ||||
| } = useMutation({ | } = useMutation({ | ||||
| mutationKey: [AgentApiAction.ResetAgent], | mutationKey: [AgentApiAction.ResetAgent], | ||||
| mutationFn: async () => { | mutationFn: async () => { | ||||
| const { data } = await flowService.resetCanvas({ id }); | |||||
| const { data } = await agentService.resetCanvas({ id }); | |||||
| return data; | return data; | ||||
| }, | }, | ||||
| }); | }); | ||||
| dsl?: DSL; | dsl?: DSL; | ||||
| avatar?: string; | avatar?: string; | ||||
| }) => { | }) => { | ||||
| const { data = {} } = await flowService.setCanvas(params); | |||||
| const { data = {} } = await agentService.setCanvas(params); | |||||
| if (data.code === 0) { | if (data.code === 0) { | ||||
| message.success( | message.success( | ||||
| i18n.t(`message.${params?.id ? 'modified' : 'created'}`), | i18n.t(`message.${params?.id ? 'modified' : 'created'}`), | ||||
| }); | }); | ||||
| } | } | ||||
| const { data } = await flowService.uploadCanvasFile(nextBody); | |||||
| const { data } = await agentService.uploadCanvasFile(nextBody); | |||||
| if (data?.code === 0) { | if (data?.code === 0) { | ||||
| message.success(i18n.t('message.uploaded')); | message.success(i18n.t('message.uploaded')); | ||||
| } | } | ||||
| enabled: !!id && !!messageId, | enabled: !!id && !!messageId, | ||||
| refetchInterval: 3000, | refetchInterval: 3000, | ||||
| queryFn: async () => { | queryFn: async () => { | ||||
| const { data } = await flowService.trace({ | |||||
| const { data } = await agentService.trace({ | |||||
| canvas_id: id, | canvas_id: id, | ||||
| message_id: messageId, | message_id: messageId, | ||||
| }); | }); | ||||
| } = useMutation({ | } = useMutation({ | ||||
| mutationKey: [AgentApiAction.TestDbConnect], | mutationKey: [AgentApiAction.TestDbConnect], | ||||
| mutationFn: async (params: any) => { | mutationFn: async (params: any) => { | ||||
| const ret = await flowService.testDbConnect(params); | |||||
| const ret = await agentService.testDbConnect(params); | |||||
| if (ret?.data?.code === 0) { | if (ret?.data?.code === 0) { | ||||
| message.success(ret?.data?.data); | message.success(ret?.data?.data); | ||||
| } else { | } else { | ||||
| } = useMutation({ | } = useMutation({ | ||||
| mutationKey: [AgentApiAction.FetchInputForm], | mutationKey: [AgentApiAction.FetchInputForm], | ||||
| mutationFn: async (params: IDebugSingleRequestBody) => { | mutationFn: async (params: IDebugSingleRequestBody) => { | ||||
| const ret = await flowService.debugSingle({ id, ...params }); | |||||
| const ret = await agentService.debugSingle({ id, ...params }); | |||||
| if (ret?.data?.code !== 0) { | if (ret?.data?.code !== 0) { | ||||
| message.error(ret?.data?.message); | message.error(ret?.data?.message); | ||||
| } | } | ||||
| initialData: {}, | initialData: {}, | ||||
| enabled: !!id && !!componentId, | enabled: !!id && !!componentId, | ||||
| queryFn: async () => { | queryFn: async () => { | ||||
| const { data } = await flowService.inputForm({ | |||||
| const { data } = await agentService.inputForm({ | |||||
| id, | id, | ||||
| component_id: componentId, | component_id: componentId, | ||||
| }); | }); | ||||
| initialData: [], | initialData: [], | ||||
| gcTime: 0, | gcTime: 0, | ||||
| queryFn: async () => { | queryFn: async () => { | ||||
| const { data } = await flowService.getListVersion({}, id); | |||||
| const { data } = await agentService.fetchVersionList(id); | |||||
| return data?.data ?? []; | return data?.data ?? []; | ||||
| }, | }, | ||||
| queryFn: async () => { | queryFn: async () => { | ||||
| if (!version_id) return undefined; | if (!version_id) return undefined; | ||||
| const { data } = await flowService.getVersion({}, version_id); | |||||
| const { data } = await agentService.fetchVersion(version_id); | |||||
| return data?.data ?? undefined; | return data?.data ?? undefined; | ||||
| }, | }, |
| } from '@/components/ui/form'; | } from '@/components/ui/form'; | ||||
| import { Input, NumberInput } from '@/components/ui/input'; | import { Input, NumberInput } from '@/components/ui/input'; | ||||
| import { RAGFlowSelect } from '@/components/ui/select'; | import { RAGFlowSelect } from '@/components/ui/select'; | ||||
| import { Textarea } from '@/components/ui/textarea'; | |||||
| import { buildOptions } from '@/utils/form'; | import { buildOptions } from '@/utils/form'; | ||||
| import { zodResolver } from '@hookform/resolvers/zod'; | import { zodResolver } from '@hookform/resolvers/zod'; | ||||
| import { memo, useMemo } from 'react'; | import { memo, useMemo } from 'react'; | ||||
| }} | }} | ||||
| > | > | ||||
| <FormContainer> | <FormContainer> | ||||
| {isSubAgent && ( | |||||
| <> | |||||
| <DescriptionField></DescriptionField> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={`user_prompt`} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>Subagent Input</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea {...field}></Textarea> | |||||
| </FormControl> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| </> | |||||
| )} | |||||
| {isSubAgent && <DescriptionField></DescriptionField>} | |||||
| <LargeModelFormField></LargeModelFormField> | <LargeModelFormField></LargeModelFormField> | ||||
| <FormField | <FormField | ||||
| control={form.control} | control={form.control} |
| import api from '@/utils/api'; | |||||
| import { registerNextServer } from '@/utils/register-server'; | |||||
| const { | |||||
| getCanvasSSE, | |||||
| setCanvas, | |||||
| listCanvas, | |||||
| resetCanvas, | |||||
| removeCanvas, | |||||
| runCanvas, | |||||
| listTemplates, | |||||
| testDbConnect, | |||||
| getInputElements, | |||||
| debug, | |||||
| listCanvasTeam, | |||||
| settingCanvas, | |||||
| uploadCanvasFile, | |||||
| trace, | |||||
| inputForm, | |||||
| fetchVersionList, | |||||
| fetchVersion, | |||||
| fetchCanvas, | |||||
| } = api; | |||||
| const methods = { | |||||
| fetchCanvas: { | |||||
| url: fetchCanvas, | |||||
| method: 'get', | |||||
| }, | |||||
| getCanvasSSE: { | |||||
| url: getCanvasSSE, | |||||
| method: 'get', | |||||
| }, | |||||
| setCanvas: { | |||||
| url: setCanvas, | |||||
| method: 'post', | |||||
| }, | |||||
| fetchVersionList: { | |||||
| url: fetchVersionList, | |||||
| method: 'get', | |||||
| }, | |||||
| fetchVersion: { | |||||
| url: fetchVersion, | |||||
| method: 'get', | |||||
| }, | |||||
| listCanvas: { | |||||
| url: listCanvas, | |||||
| method: 'get', | |||||
| }, | |||||
| resetCanvas: { | |||||
| url: resetCanvas, | |||||
| method: 'post', | |||||
| }, | |||||
| removeCanvas: { | |||||
| url: removeCanvas, | |||||
| method: 'post', | |||||
| }, | |||||
| runCanvas: { | |||||
| url: runCanvas, | |||||
| method: 'post', | |||||
| }, | |||||
| listTemplates: { | |||||
| url: listTemplates, | |||||
| method: 'get', | |||||
| }, | |||||
| testDbConnect: { | |||||
| url: testDbConnect, | |||||
| method: 'post', | |||||
| }, | |||||
| getInputElements: { | |||||
| url: getInputElements, | |||||
| method: 'get', | |||||
| }, | |||||
| debugSingle: { | |||||
| url: debug, | |||||
| method: 'post', | |||||
| }, | |||||
| listCanvasTeam: { | |||||
| url: listCanvasTeam, | |||||
| method: 'get', | |||||
| }, | |||||
| settingCanvas: { | |||||
| url: settingCanvas, | |||||
| method: 'post', | |||||
| }, | |||||
| uploadCanvasFile: { | |||||
| url: uploadCanvasFile, | |||||
| method: 'post', | |||||
| }, | |||||
| trace: { | |||||
| url: trace, | |||||
| method: 'get', | |||||
| }, | |||||
| inputForm: { | |||||
| url: inputForm, | |||||
| method: 'get', | |||||
| }, | |||||
| } as const; | |||||
| const agentService = registerNextServer<keyof typeof methods>(methods); | |||||
| export default agentService; |
| trace: `${api_host}/canvas/trace`, | trace: `${api_host}/canvas/trace`, | ||||
| // agent | // agent | ||||
| inputForm: `${api_host}/canvas/input_form`, | inputForm: `${api_host}/canvas/input_form`, | ||||
| fetchVersionList: (id: string) => `${api_host}/canvas/getlistversion/${id}`, | |||||
| fetchVersion: (id: string) => `${api_host}/canvas/getversion/${id}`, | |||||
| fetchCanvas: (id: string) => `${api_host}/canvas/get/${id}`, | |||||
| // mcp server | // mcp server | ||||
| listMcpServer: `${api_host}/mcp_server/list`, | listMcpServer: `${api_host}/mcp_server/list`, |
| import message from '@/components/ui/message'; | |||||
| import { Authorization } from '@/constants/authorization'; | |||||
| import i18n from '@/locales/config'; | |||||
| import authorizationUtil, { | |||||
| getAuthorization, | |||||
| redirectToLogin, | |||||
| } from '@/utils/authorization-util'; | |||||
| import { notification } from 'antd'; | |||||
| import axios from 'axios'; | |||||
| import { convertTheKeysOfTheObjectToSnake } from './common-util'; | |||||
| const FAILED_TO_FETCH = 'Failed to fetch'; | |||||
| export const RetcodeMessage = { | |||||
| 200: i18n.t('message.200'), | |||||
| 201: i18n.t('message.201'), | |||||
| 202: i18n.t('message.202'), | |||||
| 204: i18n.t('message.204'), | |||||
| 400: i18n.t('message.400'), | |||||
| 401: i18n.t('message.401'), | |||||
| 403: i18n.t('message.403'), | |||||
| 404: i18n.t('message.404'), | |||||
| 406: i18n.t('message.406'), | |||||
| 410: i18n.t('message.410'), | |||||
| 413: i18n.t('message.413'), | |||||
| 422: i18n.t('message.422'), | |||||
| 500: i18n.t('message.500'), | |||||
| 502: i18n.t('message.502'), | |||||
| 503: i18n.t('message.503'), | |||||
| 504: i18n.t('message.504'), | |||||
| }; | |||||
| export type ResultCode = | |||||
| | 200 | |||||
| | 201 | |||||
| | 202 | |||||
| | 204 | |||||
| | 400 | |||||
| | 401 | |||||
| | 403 | |||||
| | 404 | |||||
| | 406 | |||||
| | 410 | |||||
| | 413 | |||||
| | 422 | |||||
| | 500 | |||||
| | 502 | |||||
| | 503 | |||||
| | 504; | |||||
| const errorHandler = (error: { | |||||
| response: Response; | |||||
| message: string; | |||||
| }): Response => { | |||||
| const { response } = error; | |||||
| if (error.message === FAILED_TO_FETCH) { | |||||
| notification.error({ | |||||
| description: i18n.t('message.networkAnomalyDescription'), | |||||
| message: i18n.t('message.networkAnomaly'), | |||||
| }); | |||||
| } else { | |||||
| if (response && response.status) { | |||||
| const errorText = | |||||
| RetcodeMessage[response.status as ResultCode] || response.statusText; | |||||
| const { status, url } = response; | |||||
| notification.error({ | |||||
| message: `${i18n.t('message.requestError')} ${status}: ${url}`, | |||||
| description: errorText, | |||||
| }); | |||||
| } | |||||
| } | |||||
| return response ?? { data: { code: 1999 } }; | |||||
| }; | |||||
| const request = axios.create({ | |||||
| // errorHandler, | |||||
| timeout: 300000, | |||||
| // getResponse: true, | |||||
| }); | |||||
| request.interceptors.request.use( | |||||
| (config) => { | |||||
| const data = convertTheKeysOfTheObjectToSnake(config.data); | |||||
| const params = convertTheKeysOfTheObjectToSnake(config.params); | |||||
| const newConfig = { ...config, data, params }; | |||||
| if (!newConfig.skipToken) { | |||||
| newConfig.headers.set(Authorization, getAuthorization()); | |||||
| } | |||||
| return newConfig; | |||||
| }, | |||||
| function (error) { | |||||
| return Promise.reject(error); | |||||
| }, | |||||
| ); | |||||
| request.interceptors.response.use( | |||||
| async (response) => { | |||||
| if (response?.status === 413 || response?.status === 504) { | |||||
| message.error(RetcodeMessage[response?.status as ResultCode]); | |||||
| } | |||||
| if (response.config.responseType === 'blob') { | |||||
| return response; | |||||
| } | |||||
| const data = response?.data; | |||||
| if (data?.code === 100) { | |||||
| message.error(data?.message); | |||||
| } else if (data?.code === 401) { | |||||
| notification.error({ | |||||
| message: data?.message, | |||||
| description: data?.message, | |||||
| duration: 3, | |||||
| }); | |||||
| authorizationUtil.removeAll(); | |||||
| redirectToLogin(); | |||||
| } else if (data?.code !== 0) { | |||||
| notification.error({ | |||||
| message: `${i18n.t('message.hint')} : ${data?.code}`, | |||||
| description: data?.message, | |||||
| duration: 3, | |||||
| }); | |||||
| } | |||||
| return response; | |||||
| }, | |||||
| function (error) { | |||||
| console.log('🚀 ~ error:', error); | |||||
| errorHandler(error); | |||||
| return Promise.reject(error); | |||||
| }, | |||||
| ); | |||||
| export default request; | |||||
| export const get = (url: string) => { | |||||
| return request.get(url); | |||||
| }; | |||||
| export const post = (url: string, body: any) => { | |||||
| return request.post(url, { data: body }); | |||||
| }; | |||||
| export const drop = () => {}; | |||||
| export const put = () => {}; |
| import { AxiosRequestConfig, AxiosResponse } from 'axios'; | |||||
| import { isObject } from 'lodash'; | |||||
| import omit from 'lodash/omit'; | import omit from 'lodash/omit'; | ||||
| import { RequestMethod } from 'umi-request'; | import { RequestMethod } from 'umi-request'; | ||||
| import request from './next-request'; | |||||
| type Service<T extends string> = Record< | type Service<T extends string> = Record< | ||||
| T, | T, | ||||
| }; | }; | ||||
| export default registerServer; | export default registerServer; | ||||
| export function registerNextServer<T extends string>( | |||||
| requestRecord: Record< | |||||
| T, | |||||
| { url: string | ((...args: Array<any>) => string); method: string } | |||||
| >, | |||||
| ) { | |||||
| type Server = Record< | |||||
| T, | |||||
| ( | |||||
| config?: | |||||
| | AxiosRequestConfig<any> | |||||
| | Record<string, any> | |||||
| | string | |||||
| | number | |||||
| | boolean | |||||
| | undefined, | |||||
| useAxiosNativeConfig?: boolean, | |||||
| ) => Promise<AxiosResponse<any, any>> | |||||
| >; | |||||
| const server: Server = {} as Server; | |||||
| for (const name in requestRecord) { | |||||
| if (Object.prototype.hasOwnProperty.call(requestRecord, name)) { | |||||
| const { url, method } = requestRecord[name]; | |||||
| server[name] = (config, useAxiosNativeConfig = false) => { | |||||
| const nextConfig = useAxiosNativeConfig ? config : { data: config }; | |||||
| const finalConfig = isObject(nextConfig) ? nextConfig : {}; | |||||
| const nextUrl = typeof url === 'function' ? url(config) : url; | |||||
| return request({ url: nextUrl, method, ...finalConfig }); | |||||
| }; | |||||
| } | |||||
| } | |||||
| return server; | |||||
| } |