perf: tool call check (#4818)

* i18n

* tool call

* fix: mcp create permission;Plugin unauth tip

* fix: mcp create permission;Plugin unauth tip

* fix: Cite modal permission

* remove invalide cite

* perf: prompt

* filter fulltext search

* fix: ts

* fix: ts

* fix: ts
This commit is contained in:
Archer
2025-05-15 15:51:34 +08:00
committed by GitHub
parent a6c80684d1
commit 4e83840c14
48 changed files with 721 additions and 642 deletions

View File

@@ -38,8 +38,8 @@ const DetailLogsModal = ({ appId, chatId, onClose }: Props) => {
const setChatBoxData = useContextSelector(ChatItemContext, (v) => v.setChatBoxData);
const pluginRunTab = useContextSelector(ChatItemContext, (v) => v.pluginRunTab);
const setPluginRunTab = useContextSelector(ChatItemContext, (v) => v.setPluginRunTab);
const quoteData = useContextSelector(ChatItemContext, (v) => v.quoteData);
const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData);
const datasetCiteData = useContextSelector(ChatItemContext, (v) => v.datasetCiteData);
const setCiteModalData = useContextSelector(ChatItemContext, (v) => v.setCiteModalData);
const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
const totalRecordsCount = useContextSelector(ChatRecordContext, (v) => v.totalRecordsCount);
@@ -81,7 +81,7 @@ const DetailLogsModal = ({ appId, chatId, onClose }: Props) => {
right={0}
h={['100%', '96%']}
w={'100%'}
maxW={quoteData ? ['100%', '1080px'] : ['100%', '600px']}
maxW={datasetCiteData ? ['100%', '1080px'] : ['100%', '600px']}
bg={'white'}
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
borderRadius={'md'}
@@ -169,7 +169,7 @@ const DetailLogsModal = ({ appId, chatId, onClose }: Props) => {
)}
</Box>
{quoteData && (
{datasetCiteData && (
<Box
flex={'1 0 0'}
w={0}
@@ -183,9 +183,9 @@ const DetailLogsModal = ({ appId, chatId, onClose }: Props) => {
borderRadius={'md'}
>
<ChatQuoteList
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
rawSearch={datasetCiteData.rawSearch}
metadata={datasetCiteData.metadata}
onClose={() => setCiteModalData(undefined)}
/>
</Box>
)}

View File

@@ -109,6 +109,10 @@ const EditForm = ({
boxShadow:
'0px 4px 4px 0px rgba(19, 51, 107, 0.05), 0px 0px 1px 0px rgba(19, 51, 107, 0.08)'
}}
cursor={'pointer'}
onClick={() => {
setCurrentTool(tool);
}}
>
<Flex alignItems={'center'} py={2} px={3}>
<Box w={'20px'} fontSize={'14px'} color={'myGray.500'} fontWeight={'medium'}>
@@ -157,23 +161,11 @@ const EditForm = ({
hoverBg={'rgba(51, 112, 255, 0.10)'}
hoverBorderColor={'primary.300'}
tip={t('app:MCP_tools_detail')}
onClick={() => {
onClick={(e) => {
e.stopPropagation();
setToolDetail(tool);
}}
/>
<MyIconButton
size={'16px'}
icon={'core/workflow/debug'}
p={2}
border={'1px solid'}
borderColor={'myGray.250'}
hoverBg={'rgba(51, 112, 255, 0.10)'}
hoverBorderColor={'primary.300'}
tip={t('app:MCP_tools_debug')}
onClick={() => {
setCurrentTool(tool);
}}
/>
</Flex>
</MyBox>
);

View File

@@ -26,8 +26,8 @@ const ChatTest = ({ appForm, setRenderEdit }: Props) => {
const { t } = useTranslation();
const { appDetail } = useContextSelector(AppContext, (v) => v);
const quoteData = useContextSelector(ChatItemContext, (v) => v.quoteData);
const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData);
const datasetCiteData = useContextSelector(ChatItemContext, (v) => v.datasetCiteData);
const setCiteModalData = useContextSelector(ChatItemContext, (v) => v.setCiteModalData);
// form2AppWorkflow dependent allDatasets
const isVariableVisible = useContextSelector(ChatItemContext, (v) => v.isVariableVisible);
@@ -42,8 +42,8 @@ const ChatTest = ({ appForm, setRenderEdit }: Props) => {
}, [appForm, setWorkflowData, t]);
useEffect(() => {
setRenderEdit(!quoteData);
}, [quoteData, setRenderEdit]);
setRenderEdit(!datasetCiteData);
}, [datasetCiteData, setRenderEdit]);
const { ChatContainer, restartChat, loading } = useChatTest({
...workflowData,
@@ -89,12 +89,12 @@ const ChatTest = ({ appForm, setRenderEdit }: Props) => {
<ChatContainer />
</Box>
</MyBox>
{quoteData && (
{datasetCiteData && (
<Box flex={'1 0 0'} w={0} maxW={'560px'} {...cardStyles} boxShadow={'3'}>
<ChatQuoteList
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
rawSearch={datasetCiteData.rawSearch}
metadata={datasetCiteData.metadata}
onClose={() => setCiteModalData(undefined)}
/>
</Box>
)}

View File

@@ -17,7 +17,7 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
import ConfigToolModal from './ConfigToolModal';
import { getWebLLMModel } from '@/web/common/system/utils';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import { checkAppUnExistError } from '@fastgpt/global/core/app/utils';
import { formatToolError } from '@fastgpt/global/core/app/utils';
const ToolSelect = ({
appForm,
@@ -65,7 +65,7 @@ const ToolSelect = ({
gridGap={[2, 4]}
>
{appForm.selectedTools.map((item) => {
const hasError = checkAppUnExistError(item.pluginData?.error);
const toolError = formatToolError(item.pluginData?.error);
return (
<MyTooltip key={item.id} label={item.intro}>
@@ -77,10 +77,10 @@ const ToolSelect = ({
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
borderRadius={'md'}
border={theme.borders.base}
borderColor={hasError ? 'red.600' : ''}
borderColor={toolError ? 'red.600' : ''}
_hover={{
...hoverDeleteStyles,
borderColor: hasError ? 'red.600' : 'primary.300'
borderColor: toolError ? 'red.600' : 'primary.300'
}}
cursor={'pointer'}
onClick={() => {
@@ -93,7 +93,7 @@ const ToolSelect = ({
input.renderTypeList.includes(FlowNodeInputTypeEnum.selectLLMModel) ||
input.renderTypeList.includes(FlowNodeInputTypeEnum.fileSelect)
) ||
hasError ||
toolError ||
item.flowNodeType === FlowNodeTypeEnum.tool ||
item.flowNodeType === FlowNodeTypeEnum.toolSet
) {
@@ -113,21 +113,19 @@ const ToolSelect = ({
>
{item.name}
</Box>
{hasError && (
<MyTooltip label={t('app:app.modules.not_found_tips')}>
<Flex
bg={'red.50'}
alignItems={'center'}
h={6}
px={2}
rounded={'6px'}
fontSize={'xs'}
fontWeight={'medium'}
>
<MyIcon name={'common/errorFill'} w={'14px'} mr={1} />
<Box color={'red.600'}>{t('app:app.modules.not_found')}</Box>
</Flex>
</MyTooltip>
{toolError && (
<Flex
bg={'red.50'}
alignItems={'center'}
h={6}
px={2}
rounded={'6px'}
fontSize={'xs'}
fontWeight={'medium'}
>
<MyIcon name={'common/errorFill'} w={'14px'} mr={1} />
<Box color={'red.600'}>{t(toolError as any)}</Box>
</Flex>
)}
<DeleteIcon
ml={2}

View File

@@ -43,8 +43,8 @@ const ChatTest = ({ isOpen, nodes = [], edges = [], onClose }: Props) => {
});
const pluginRunTab = useContextSelector(ChatItemContext, (v) => v.pluginRunTab);
const setPluginRunTab = useContextSelector(ChatItemContext, (v) => v.setPluginRunTab);
const quoteData = useContextSelector(ChatItemContext, (v) => v.quoteData);
const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData);
const datasetCiteData = useContextSelector(ChatItemContext, (v) => v.datasetCiteData);
const setCiteModalData = useContextSelector(ChatItemContext, (v) => v.setCiteModalData);
const isVariableVisible = useContextSelector(ChatItemContext, (v) => v.isVariableVisible);
const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
@@ -60,7 +60,7 @@ const ChatTest = ({ isOpen, nodes = [], edges = [], onClose }: Props) => {
bottom={0}
right={0}
onClick={() => {
setQuoteData(undefined);
setCiteModalData(undefined);
onClose();
}}
/>
@@ -72,7 +72,7 @@ const ChatTest = ({ isOpen, nodes = [], edges = [], onClose }: Props) => {
top={5}
right={0}
h={isOpen ? '95%' : '0'}
w={isOpen ? (quoteData ? ['100%', '960px'] : ['100%', '460px']) : '0'}
w={isOpen ? (datasetCiteData ? ['100%', '960px'] : ['100%', '460px']) : '0'}
bg={'white'}
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
borderRadius={'md'}
@@ -152,7 +152,7 @@ const ChatTest = ({ isOpen, nodes = [], edges = [], onClose }: Props) => {
<ChatContainer />
</Box>
{quoteData && (
{datasetCiteData && (
<Box
flex={'1 0 0'}
w={0}
@@ -166,9 +166,9 @@ const ChatTest = ({ isOpen, nodes = [], edges = [], onClose }: Props) => {
borderRadius={'md'}
>
<ChatQuoteList
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
rawSearch={datasetCiteData.rawSearch}
metadata={datasetCiteData.metadata}
onClose={() => setCiteModalData(undefined)}
/>
</Box>
)}

View File

@@ -35,6 +35,7 @@ import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
import MyTag from '@fastgpt/web/components/common/Tag/index';
import MySelect from '@fastgpt/web/components/common/MySelect';
import { useCreation } from 'ahooks';
import { formatToolError } from '@fastgpt/global/core/app/utils';
type Props = FlowNodeItemType & {
children?: React.ReactNode | React.ReactNode[] | string;
@@ -144,6 +145,7 @@ const NodeCard = (props: Props) => {
/* Node header */
const Header = useMemo(() => {
const showHeader = node?.flowNodeType !== FlowNodeTypeEnum.comment;
const error = formatToolError(node?.pluginData?.error);
return (
<Box position={'relative'}>
@@ -254,23 +256,19 @@ const NodeCard = (props: Props) => {
)}
</UseGuideModal>
)}
{!!node?.pluginData?.error && (
<MyTooltip label={node?.pluginData?.error || t('app:app.modules.not_found_tips')}>
<Flex
bg={'red.50'}
alignItems={'center'}
h={8}
px={2}
rounded={'6px'}
fontSize={'xs'}
fontWeight={'medium'}
>
<MyIcon name={'common/errorFill'} w={'14px'} mr={1} />
<Box color={'red.600'}>
{node?.pluginData?.error || t('app:app.modules.not_found')}
</Box>
</Flex>
</MyTooltip>
{!!error && (
<Flex
bg={'red.50'}
alignItems={'center'}
h={8}
px={2}
rounded={'6px'}
fontSize={'xs'}
fontWeight={'medium'}
>
<MyIcon name={'common/errorFill'} w={'14px'} mr={1} />
<Box color={'red.600'}>{t(error as any)}</Box>
</Flex>
)}
</Flex>
<NodeIntro nodeId={nodeId} intro={intro} />

View File

@@ -3,7 +3,6 @@ import {
type ReactNode,
type SetStateAction,
useCallback,
useEffect,
useMemo,
useState
} from 'react';
@@ -22,7 +21,6 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
import type { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
import { checkAppUnExistError } from '@fastgpt/global/core/app/utils';
import { useToast } from '@fastgpt/web/hooks/useToast';
const InfoModal = dynamic(() => import('./InfoModal'));
@@ -205,16 +203,6 @@ const AppContextProvider = ({ children }: { children: ReactNode }) => {
[appDetail.name, deleteApp, openConfirmDel, t]
);
// check app unExist error
useEffect(() => {
if (appDetail.modules.some((module) => checkAppUnExistError(module.pluginData?.error))) {
toast({
title: t('app:app.error.unExist_app'),
status: 'error'
});
}
}, [appDetail.modules, t, toast]);
const contextValue: AppContextType = useMemo(
() => ({
appId,

View File

@@ -46,7 +46,7 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
const appName = useContextSelector(ChatItemContext, (v) => v.chatBoxData?.app.name);
const appAvatar = useContextSelector(ChatItemContext, (v) => v.chatBoxData?.app.avatar);
const showRouteToAppDetail = useContextSelector(ChatItemContext, (v) => v.showRouteToAppDetail);
const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData);
const setCiteModalData = useContextSelector(ChatItemContext, (v) => v.setCiteModalData);
const concatHistory = useMemo(() => {
const formatHistories: HistoryItemType[] = histories.map((item) => {
@@ -146,7 +146,7 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
overflow={'hidden'}
onClick={() => {
onChangeChatId();
setQuoteData(undefined);
setCiteModalData(undefined);
}}
>
{t('common:core.chat.New Chat')}
@@ -202,7 +202,7 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
: {
onClick: () => {
onChangeChatId(item.id);
setQuoteData(undefined);
setCiteModalData(undefined);
}
})}
{...(i !== concatHistory.length - 1 && {
@@ -274,7 +274,7 @@ const ChatHistorySlider = ({ confirmClearText }: { confirmClearText: string }) =
onDelHistory(item.id);
if (item.id === activeChatId) {
onChangeChatId();
setQuoteData(undefined);
setCiteModalData(undefined);
}
},
type: 'danger'