perf: agent config

This commit is contained in:
archer 2025-11-19 15:54:47 +08:00
parent 7bddef488e
commit 7088543a9f
No known key found for this signature in database
GPG Key ID: 4446499B846D4A9E
24 changed files with 171 additions and 129 deletions

View File

@ -10,7 +10,7 @@ export enum AppTypeEnum {
folder = 'folder',
toolFolder = 'toolFolder',
simple = 'simple',
agent = 'agent',
chatAgent = 'chatAgent',
workflow = 'advanced',
workflowTool = 'plugin',
mcpToolSet = 'toolSet', // 'mcp'
@ -33,7 +33,7 @@ export const ToolTypeList = [
AppTypeEnum.httpToolSet,
AppTypeEnum.workflowTool
];
export const AppTypeList = [AppTypeEnum.simple, AppTypeEnum.agent, AppTypeEnum.workflow];
export const AppTypeList = [AppTypeEnum.simple, AppTypeEnum.chatAgent, AppTypeEnum.workflow];
export const defaultTTSConfig: AppTTSConfigType = { type: 'web' };

View File

@ -45,7 +45,7 @@ import { Output_Template_Error_Message } from '@fastgpt/global/core/workflow/tem
import { splitCombineToolId } from '@fastgpt/global/core/app/tool/utils';
import { getMCPToolRuntimeNode } from '@fastgpt/global/core/app/tool/mcpTool/utils';
import { getHTTPToolRuntimeNode } from '@fastgpt/global/core/app/tool/httpTool/utils';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { AppFolderTypeList, AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { getMCPChildren } from '../mcp';
import { cloneDeep } from 'lodash';
import { UserError } from '@fastgpt/global/common/error/utils';
@ -227,6 +227,7 @@ export async function getChildAppPreviewNode({
if (source === AppToolSourceEnum.personal) {
const item = await MongoApp.findById(pluginId).lean();
if (!item) return Promise.reject(PluginErrEnum.unExist);
if (AppFolderTypeList.includes(item.type)) return Promise.reject(PluginErrEnum.unExist);
const version = await getAppVersionById({ appId: pluginId, versionId, app: item });

View File

@ -42,7 +42,7 @@ export const checkTeamMemberLimit = async (teamId: string, newCount: number) =>
export const checkTeamAppLimit = async (teamId: string, amount = 1) => {
const type = [
AppTypeEnum.agent,
AppTypeEnum.chatAgent,
AppTypeEnum.simple,
AppTypeEnum.workflow,
AppTypeEnum.workflowTool,

View File

@ -13,7 +13,7 @@ import { retryFn } from '@fastgpt/global/common/system/utils';
export function getI18nAppType(type: AppTypeEnum): string {
if (type === AppTypeEnum.folder) return i18nT('account_team:type.Folder');
if (type === AppTypeEnum.simple) return i18nT('app:type.Chat_Agent');
if (type === AppTypeEnum.agent) return 'Agent';
if (type === AppTypeEnum.chatAgent) return 'Agent';
if (type === AppTypeEnum.workflow) return i18nT('account_team:type.Workflow bot');
if (type === AppTypeEnum.workflowTool) return i18nT('app:toolType_workflow');
if (type === AppTypeEnum.httpPlugin) return i18nT('account_team:type.Http plugin');

View File

@ -30,10 +30,9 @@ import { useTranslation } from 'next-i18next';
export type SkillOptionItemType = {
description?: string;
list: SkillItemType[];
onSelect?: (id: string) => Promise<SkillOptionItemType | undefined>;
onClick?: (id: string) => Promise<string | undefined>;
onFolderLoad?: (id: string) => Promise<SkillItemType[] | undefined>;
onFolderLoad?: (id: string) => Promise<SkillItemType[]>;
};
export type SkillItemType = {
@ -41,12 +40,16 @@ export type SkillItemType = {
id: string;
label: string;
icon?: string;
showArrow?: boolean;
canOpen?: boolean;
canUse?: boolean;
canClick: boolean;
// Folder
open?: boolean;
children?: SkillOptionItemType;
isFolder?: boolean;
folderChildren?: SkillItemType[];
// System tool/ model
showArrow?: boolean;
children?: SkillOptionItemType;
};
export default function SkillPickerPlugin({
@ -75,7 +78,6 @@ export default function SkillPickerPlugin({
const [currentColumnIndex, setCurrentColumnIndex] = useState<number>(0);
const [currentRowIndex, setCurrentRowIndex] = useState<number>(0);
const [interactionMode, setInteractionMode] = useState<'mouse' | 'keyboard'>('mouse');
const [loadingFolderIds, setLoadingFolderIds] = useState(new Set());
// Refs for scroll management
const itemRefs = useRef<Map<string, HTMLDivElement>>(new Map());
@ -105,10 +107,6 @@ export default function SkillPickerPlugin({
}
}, []);
const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('@', {
minLength: 0
});
// Recursively collects all visible items including expanded folder children for keyboard navigation
const getFlattenedVisibleItems = useCallback(
(columnIndex: number): SkillItemType[] => {
@ -119,7 +117,7 @@ export default function SkillPickerPlugin({
items.forEach((item) => {
result.push(item);
// Include folder children only if folder is expanded
if (item.canOpen && item.open && item.folderChildren) {
if (item.isFolder && item.open && item.folderChildren) {
result.push(...flatten(item.folderChildren));
}
});
@ -142,7 +140,8 @@ export default function SkillPickerPlugin({
item?: SkillItemType;
option?: SkillOptionItemType;
}) => {
if (!item) return;
if (!item || !option?.onSelect) return;
const buffer = item.children;
if (buffer) {
setSkillOptions((prev) => {
@ -153,7 +152,7 @@ export default function SkillPickerPlugin({
return;
}
const result = await option?.onSelect?.(item.id);
const result = await option.onSelect(item.id);
setSkillOptions((prev) => {
const newOptions = [...prev];
@ -173,11 +172,14 @@ export default function SkillPickerPlugin({
// Handle item click (confirm selection)
const { runAsync: handleItemClick, loading: isItemClickLoading } = useRequest2(
async ({ item, option }: { item: SkillItemType; option?: SkillOptionItemType }) => {
if (!item.canClick || !option?.onClick) return;
// Step 1: Execute async onClick to get skillId (outside editor.update)
const skillId = await option?.onClick?.(item.id);
const skillId = await option.onClick(item.id);
// Step 2: Update editor with the skillId (inside a fresh editor.update)
if (skillId) {
console.log(skillId, 2222);
editor.update(() => {
// Re-acquire selection in this update cycle to avoid stale node references
const selection = $getSelection();
@ -213,7 +215,8 @@ export default function SkillPickerPlugin({
);
// Handle folder toggle
const { runAsync: handleFolderToggle, loading: isFolderLoading } = useRequest2(
const [loadingFolderIds, setLoadingFolderIds] = useState(new Set());
const { runAsync: handleFolderToggle } = useRequest2(
async ({
currentColumnIndex,
item,
@ -223,7 +226,7 @@ export default function SkillPickerPlugin({
item?: SkillItemType;
option?: SkillOptionItemType;
}) => {
if (!item || !item.canOpen) return;
if (!item || !item.isFolder || !option?.onFolderLoad) return;
const currentFolder = item;
// Step 1: Toggle folder open/closed state
@ -260,7 +263,7 @@ export default function SkillPickerPlugin({
});
try {
const result = await option?.onFolderLoad?.(currentFolder.id);
const result = await option.onFolderLoad(currentFolder.id);
setSkillOptions((prev) => {
const newOptions = [...prev];
@ -271,7 +274,7 @@ export default function SkillPickerPlugin({
if (item.id === currentFolder.id) {
return {
...item,
folderChildren: result || []
folderChildren: result
};
}
if (item.folderChildren) {
@ -482,6 +485,9 @@ export default function SkillPickerPlugin({
const removeSpaceCommand = editor.registerCommand(
KEY_SPACE_COMMAND,
(e: KeyboardEvent) => {
e.preventDefault();
e.stopPropagation();
if (!isMenuOpen) return true;
setInteractionMode('keyboard');
@ -490,9 +496,7 @@ export default function SkillPickerPlugin({
const latestItem = flattenedItems[currentRowIndex];
const latestOption = skillOptions[currentColumnIndex];
if (latestItem?.canOpen && !(latestItem.open && latestItem.folderChildren?.length === 0)) {
e.preventDefault();
e.stopPropagation();
if (!(latestItem.open && latestItem.folderChildren?.length === 0)) {
handleFolderToggle({
currentColumnIndex,
item: latestItem,
@ -509,6 +513,9 @@ export default function SkillPickerPlugin({
const removeEnterCommand = editor.registerCommand(
KEY_ENTER_COMMAND,
(e: KeyboardEvent) => {
e.preventDefault();
e.stopPropagation();
if (!isMenuOpen) return true;
setInteractionMode('keyboard');
@ -517,9 +524,7 @@ export default function SkillPickerPlugin({
const latestItem = flattenedItems[currentRowIndex];
const latestOption = skillOptions[currentColumnIndex];
if (latestItem?.canUse && latestOption) {
e.preventDefault();
e.stopPropagation();
if (latestOption?.onClick) {
handleItemClick({ item: latestItem, option: latestOption });
return true;
@ -565,7 +570,6 @@ export default function SkillPickerPlugin({
const result: JSX.Element[] = [];
const activeRowIndex = selectedRowIndex[columnIndex];
let currentFlatIndex = startFlatIndex;
console.log('items', { selectedRowIndex, columnIndex, activeRowIndex });
items.forEach((item) => {
const flatIndex = currentFlatIndex;
@ -596,7 +600,6 @@ export default function SkillPickerPlugin({
color={isSelected ? 'primary.700' : 'myGray.600'}
display={'flex'}
alignItems={'center'}
isLoading={loadingFolderIds.has(item.id)}
size={'sm'}
onMouseDown={(e) => {
e.preventDefault();
@ -609,13 +612,13 @@ export default function SkillPickerPlugin({
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
if (item.canOpen) {
if (item.isFolder) {
handleFolderToggle({
currentColumnIndex: columnIndex,
item,
option: columnData
});
} else if (item.canUse) {
} else {
handleItemClick({
item,
option: columnData
@ -639,18 +642,16 @@ export default function SkillPickerPlugin({
setCurrentRowIndex(flatIndex);
setCurrentColumnIndex(columnIndex);
if (item.canUse) {
handleItemSelect({
currentColumnIndex: columnIndex,
item,
option: columnData
});
}
handleItemSelect({
currentColumnIndex: columnIndex,
item,
option: columnData
});
}}
>
{item.canOpen && !(item.open && item.folderChildren?.length === 0) ? (
{item.isFolder && !(item.open && item.folderChildren?.length === 0) ? (
<MyIcon
name={'core/chat/chevronRight'}
name={loadingFolderIds.has(item.id) ? 'common/loading' : 'core/chat/chevronRight'}
w={4}
color={'myGray.500'}
transform={item.open ? 'rotate(90deg)' : 'none'}
@ -661,9 +662,11 @@ export default function SkillPickerPlugin({
<Box w={3} flexShrink={0} />
) : null}
{item.icon && <Avatar src={item.icon} w={'1.2rem'} borderRadius={'xs'} />}
<Box fontSize={'sm'} fontWeight={'medium'} flex={1}>
{/* Folder content */}
<Box fontSize={'sm'} fontWeight={'medium'} flex={'1 0 0'} className="textEllipsis">
{item.label}
{item.canOpen && item.open && item.folderChildren?.length === 0 && (
{item.isFolder && item.open && item.folderChildren?.length === 0 && (
<Box as="span" color={'myGray.400'} fontSize={'xs'} ml={2}>
{t('app:empty_folder')}
</Box>
@ -676,7 +679,7 @@ export default function SkillPickerPlugin({
);
// render folderChildren
if (item.canOpen && item.open && !!item.folderChildren && item.folderChildren.length > 0) {
if (item.isFolder && item.open && !!item.folderChildren && item.folderChildren.length > 0) {
const { elements, nextFlatIndex } = renderItemList(
item.folderChildren,
columnData,
@ -695,14 +698,14 @@ export default function SkillPickerPlugin({
selectedRowIndex,
currentColumnIndex,
currentRowIndex,
loadingFolderIds,
t,
interactionMode,
handleFolderToggle,
handleItemClick,
handleItemSelect,
interactionMode,
loadingFolderIds
handleItemSelect
]
);
// Render single column
const renderColumn = useCallback(
(columnData: SkillOptionItemType, columnIndex: number) => {
@ -719,7 +722,7 @@ export default function SkillPickerPlugin({
boxShadow={'0 4px 10px 0 rgba(19, 51, 107, 0.10), 0 0 1px 0 rgba(19, 51, 107, 0.10)'}
bg={'white'}
flexShrink={0}
maxH={'300px'}
maxH={'350px'}
overflow={'auto'}
>
{columnData.description && (
@ -785,6 +788,9 @@ export default function SkillPickerPlugin({
},
[editor]
);
const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('@', {
minLength: 0
});
return (
<LexicalTypeaheadMenuPlugin

View File

@ -59,6 +59,7 @@
"auto_save": "Auto save",
"can_select_toolset": "Entire toolset available for selection",
"change_app_type": "Change App Type",
"chat_agent_intro": "AI autonomously plans executable processes",
"chat_debug": "Chat Preview",
"chat_logs": "Logs",
"chat_logs_tips": "Logs will record the online, shared, and API (requires chatId) conversation records of this app.",
@ -254,6 +255,7 @@
"month.unit": "Day",
"move.hint": "After moving, the selected app/folder will inherit the permission settings for the new folder.",
"move_app": "Move Application",
"my_agents": "my agents",
"no_mcp_tools_list": "No data yet, the MCP address needs to be parsed first",
"node_not_intro": "This node is not introduced",
"not_json_file": "Please select a JSON file",
@ -440,6 +442,7 @@
"tts_close": "Close",
"type.All": "All",
"type.Chat_Agent": "Dialogue Agent",
"type.Chat_Agent_v2": "Dialogue Agent V2",
"type.Create http plugin tip": "Batch create plugins through OpenAPI Schema, compatible with GPTs format.",
"type.Create mcp tools tip": "Automatically parse and batch create callable MCP tools by entering the MCP address",
"type.Create one plugin tip": "Customizable input and output workflows, usually used to encapsulate reusable workflows.",

View File

@ -61,6 +61,7 @@
"auto_save": "自动保存",
"can_select_toolset": "可选择整个工具集",
"change_app_type": "更改应用类型",
"chat_agent_intro": "由 AI 自主规划可执行流程",
"chat_debug": "调试预览",
"chat_logs": "对话日志",
"chat_logs_tips": "日志会记录该应用的在线、分享和 API需填写 chatId对话记录",
@ -267,6 +268,7 @@
"month.unit": "号",
"move.hint": "移动后,所选应用/文件夹将继承新文件夹的权限设置。",
"move_app": "移动应用",
"my_agents": "我的 agents",
"no_mcp_tools_list": "暂无数据,需先解析 MCP 地址",
"node_not_intro": "这个节点没有介绍",
"not_json_file": "请选择JSON文件",
@ -457,6 +459,7 @@
"tts_close": "关闭",
"type.All": "全部",
"type.Chat_Agent": "对话 Agent",
"type.Chat_Agent_v2": "对话 Agent V2",
"type.Create http plugin tip": "通过 OpenAPI Schema 批量创建工具兼容GPTs、通过curl或手动创建工具",
"type.Create http toolset tip": "通过 OpenAPI Schema 批量创建工具(兼容GPTs)",
"type.Create mcp tools tip": "通过输入 MCP 地址,自动解析并批量创建可调用的 MCP 工具",

View File

@ -59,6 +59,7 @@
"auto_save": "自動儲存",
"can_select_toolset": "可選擇整個工具集",
"change_app_type": "更改應用程式類型",
"chat_agent_intro": "由 AI 自主規劃可執行流程",
"chat_debug": "聊天預覽",
"chat_logs": "對話紀錄",
"chat_logs_tips": "紀錄會記錄此應用程式的線上、分享和 API需填寫 chatId對話紀錄",
@ -253,6 +254,7 @@
"month.unit": "號",
"move.hint": "移動後,所選應用/文件夾將繼承新文件夾的權限設置。",
"move_app": "移動應用程式",
"my_agents": "我的 agents",
"no_mcp_tools_list": "暫無數據,需先解析 MCP 地址",
"node_not_intro": "這個節點沒有介紹",
"not_json_file": "請選擇 JSON 檔案",
@ -437,6 +439,7 @@
"tts_browser": "瀏覽器自帶 (免費)",
"tts_close": "關閉",
"type.All": "全部",
"type.Chat_Agent_v2": "對話 Agent V2",
"type.Create http plugin tip": "透過 OpenAPI Schema 批次建立外掛,相容 GPTs 格式",
"type.Create mcp tools tip": "通過輸入 MCP 地址,自動解析並批量創建可調用的 MCP 工具",
"type.Create one plugin tip": "可以自訂輸入和輸出的工作流程,通常用於封裝重複使用的工作流程",

View File

@ -2,13 +2,13 @@ import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { i18nT } from '@fastgpt/web/i18n/utils';
export const createAppTypeMap = {
[AppTypeEnum.agent]: {
type: AppTypeEnum.agent,
icon: 'core/app/type/workflowFill',
title: 'Agent',
intro: 'Agent',
description: 'Agent',
imgUrl: '/imgs/app/workflowPreview.svg'
[AppTypeEnum.chatAgent]: {
type: AppTypeEnum.chatAgent,
icon: 'core/app/simpleBot',
title: i18nT('app:type.Chat_Agent_v2'),
intro: i18nT('app:chat_agent_intro'),
description: i18nT('app:chat_agent_intro'),
imgUrl: '/imgs/app/simpleAgentPreview.svg'
},
[AppTypeEnum.workflow]: {
type: AppTypeEnum.workflow,

View File

@ -33,7 +33,7 @@ import { getWebLLMModel } from '@/web/common/system/utils';
import ToolSelect from '../FormComponent/ToolSelector/ToolSelect';
import OptimizerPopover from '@/components/common/PromptEditor/OptimizerPopover';
import type { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node';
import { useSkillManager } from './hooks/useSkillManager';
import { type SelectedToolItemType, useSkillManager } from './hooks/useSkillManager';
import { useMemoEnhance } from '@fastgpt/web/hooks/useMemoEnhance';
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
@ -76,18 +76,36 @@ const EditForm = ({
// Skill picker
const selectedTools = useMemoEnhance(() => appForm.selectedTools, [appForm.selectedTools]);
const setSelectedTools = useCallback(
(tools: FlowNodeTemplateType[]) => {
const onUpdateOrAddTool = useCallback(
(tool: SelectedToolItemType) => {
setAppForm((state) => {
if (state.selectedTools.some((t) => t.id === tool.id)) {
return {
...state,
selectedTools: state.selectedTools.map((t) => (t.id === tool.id ? tool : t))
};
}
return {
...state,
selectedTools: [tool, ...state.selectedTools]
};
});
},
[setAppForm]
);
const onDeleteTool = useCallback(
(id: string) => {
setAppForm((state) => ({
...state,
selectedTools: tools
selectedTools: state.selectedTools.filter((t) => t.id !== id)
}));
},
[setAppForm]
);
const { SkillModal, skillOption, selectedSkills, onClickSkill, onRemoveSkill } = useSkillManager({
selectedTools,
setSelectedTools,
onUpdateOrAddTool,
onDeleteTool,
canSelectFile: appForm.chatConfig?.fileSelectConfig?.canSelectFile,
canSelectImg: appForm.chatConfig?.fileSelectConfig?.canSelectImg
});

View File

@ -24,7 +24,12 @@ import {
getToolPreviewNode,
getTeamAppTemplates
} from '@/web/core/app/api/tool';
import { AppTypeEnum, AppTypeList, ToolTypeList } from '@fastgpt/global/core/app/constants';
import {
AppFolderTypeList,
AppTypeEnum,
AppTypeList,
ToolTypeList
} from '@fastgpt/global/core/app/constants';
const ConfigToolModal = dynamic(() => import('../../component/ConfigToolModal'));
@ -38,16 +43,18 @@ const isSubApp = (flowNodeType: FlowNodeTypeEnum) => {
return !!subAppTypeMap[flowNodeType];
};
type SelectedToolItemType = AppFormEditFormType['selectedTools'][number];
export type SelectedToolItemType = AppFormEditFormType['selectedTools'][number];
export const useSkillManager = ({
selectedTools,
setSelectedTools,
onUpdateOrAddTool,
onDeleteTool,
canSelectFile,
canSelectImg
}: {
selectedTools: SelectedToolItemType[];
setSelectedTools: (tools: SelectedToolItemType[]) => void;
onDeleteTool: (id: string) => void;
onUpdateOrAddTool: (tool: SelectedToolItemType) => void;
canSelectFile?: boolean;
canSelectImg?: boolean;
}) => {
@ -66,7 +73,8 @@ export const useSkillManager = ({
parentId: item.parentId,
label: item.name,
icon: item.avatar,
showArrow: item.isFolder
showArrow: item.isFolder,
canClick: true
};
});
},
@ -83,15 +91,10 @@ export const useSkillManager = ({
[systemTools]
);
/* ===== Team Apps ===== */
const { data: allTeamApps = [] } = useRequest2(
async () => {
return await getTeamAppTemplates({ parentId: null });
},
{
manual: false
}
);
/* ===== Team agents/tools ===== */
const { data: allTeamApps = [] } = useRequest2(() => getTeamAppTemplates({ parentId: null }), {
manual: false
});
const myTools = useMemo(
() =>
allTeamApps
@ -100,12 +103,12 @@ export const useSkillManager = ({
id: item.id,
label: item.name,
icon: item.avatar,
canOpen: item.isFolder ?? false,
canUse: item.appType !== AppTypeEnum.folder && item.appType !== AppTypeEnum.toolFolder
isFolder: item.isFolder ?? false,
canClick: !AppFolderTypeList.includes(item.appType)
})),
[allTeamApps]
);
const agentApps = useMemo(
const myAgents = useMemo(
() =>
allTeamApps
.filter((item) => [AppTypeEnum.folder, ...AppTypeList].includes(item.appType))
@ -113,8 +116,8 @@ export const useSkillManager = ({
id: item.id,
label: item.name,
icon: item.avatar,
canOpen: item.isFolder ?? false,
canUse: item.appType !== AppTypeEnum.folder && item.appType !== AppTypeEnum.toolFolder
isFolder: item.isFolder ?? false,
canClick: !AppFolderTypeList.includes(item.appType)
})),
[allTeamApps]
);
@ -132,16 +135,22 @@ export const useSkillManager = ({
id: item.id,
label: item.name,
icon: item.avatar,
canOpen: item.isFolder ?? false,
canUse: item.appType !== AppTypeEnum.folder && item.appType !== AppTypeEnum.toolFolder
isFolder: item.isFolder ?? false,
canClick: !AppFolderTypeList.includes(item.appType)
};
});
}, []);
/* ===== Workflow tool ===== */
const { runAsync: onAddAppOrTool } = useRequest2(
const onAddAppOrTool = useCallback(
async (appId: string) => {
console.log(appId);
const toolTemplate = await getToolPreviewNode({ appId });
console.log(toolTemplate);
if (!toolTemplate) {
return;
}
const checkRes = validateToolConfiguration({
toolTemplate,
canSelectFile,
@ -171,17 +180,14 @@ export const useSkillManager = ({
};
const hasFormInput = checkNeedsUserConfiguration(tool);
setSelectedTools([
...selectedTools,
{
...tool,
configStatus: hasFormInput ? 'waitingForConfig' : 'active'
}
]);
onUpdateOrAddTool({
...tool,
configStatus: hasFormInput ? 'waitingForConfig' : 'active'
});
return tool.id;
},
{ manual: true }
[canSelectFile, canSelectImg, onUpdateOrAddTool, t, toast]
);
/* ===== Skill option ===== */
@ -199,7 +205,8 @@ export const useSkillManager = ({
onClick: onAddAppOrTool,
list: data.map((item) => ({
id: item.id,
label: item.label
label: item.label,
canClick: true
}))
};
},
@ -215,7 +222,7 @@ export const useSkillManager = ({
} else if (id === 'agent') {
return {
description: t('app:space_to_expand_folder'),
list: agentApps,
list: myAgents,
onFolderLoad: (folderId: string) => onFolderLoadTeamApps(folderId, AppTypeList),
onClick: onAddAppOrTool
};
@ -226,21 +233,24 @@ export const useSkillManager = ({
{
id: 'systemTool',
label: t('app:core.module.template.System Tools'),
icon: 'core/workflow/template/toolCall'
icon: 'core/workflow/template/toolCall',
canClick: false
},
{
id: 'myTools',
label: t('common:navbar.Tools'),
icon: 'core/app/type/pluginFill'
icon: 'core/app/type/pluginFill',
canClick: false
},
{
id: 'agent',
label: 'Agent',
icon: 'core/workflow/template/runApp'
label: t('app:my_agents'),
icon: 'core/workflow/template/runApp',
canClick: false
}
]
};
}, [onAddAppOrTool, onLoadSystemTool, myTools, agentApps, onFolderLoadTeamApps, t]);
}, [onAddAppOrTool, onLoadSystemTool, myTools, myAgents, onFolderLoadTeamApps, t]);
/* ===== Selected skills ===== */
const selectedSkills = useMemoEnhance<SkillLabelItemType[]>(() => {
@ -279,9 +289,9 @@ export const useSkillManager = ({
const onRemoveSkill = useCallback(
(id: string) => {
console.log('onRemoveSkill', id);
setSelectedTools(selectedTools.filter((tool) => tool.id !== id));
onDeleteTool(id);
},
[selectedTools, setSelectedTools]
[onDeleteTool]
);
const SkillModal = useCallback(() => {
@ -292,22 +302,16 @@ export const useSkillManager = ({
configTool={configTool}
onCloseConfigTool={() => setConfigTool(undefined)}
onAddTool={(tool) =>
setSelectedTools(
selectedTools.map((t) =>
t.id === tool.id
? {
...tool,
configStatus: 'active'
}
: t
)
)
onUpdateOrAddTool({
...tool,
configStatus: 'active'
})
}
/>
)}
</>
);
}, [configTool, selectedTools, setSelectedTools]);
}, [configTool, onUpdateOrAddTool]);
return {
skillOption,

View File

@ -1,5 +1,5 @@
import type { AppChatConfigType, AppFormEditFormType } from '@fastgpt/global/core/app/type';
import type { WorkflowType } from '../Agent/utils';
import type { WorkflowType } from '../ChatAgent/utils';
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
export type AppForm2WorkflowFnType = ({

View File

@ -8,7 +8,7 @@ const AppTypeTag = ({ type }: { type: AppTypeEnum }) => {
const { t } = useTranslation();
const map = useRef({
[AppTypeEnum.agent]: {
[AppTypeEnum.chatAgent]: {
label: 'Agent',
icon: 'core/app/type/simple',
bg: '#DBF3FF',

View File

@ -36,7 +36,7 @@ const MyApps = () => {
const map = useMemo(
() => ({
all: t('common:core.module.template.all_team_app'),
[AppTypeEnum.agent]: 'Agent',
[AppTypeEnum.chatAgent]: 'Agent',
[AppTypeEnum.simple]: t('app:type.Chat_Agent'),
[AppTypeEnum.workflow]: t('app:type.Workflow bot'),
[AppTypeEnum.workflowTool]: t('app:toolType_workflow'),

View File

@ -296,7 +296,11 @@ const List = () => {
/>
}
menuList={[
...([AppTypeEnum.simple, AppTypeEnum.workflow].includes(app.type)
...([
AppTypeEnum.simple,
AppTypeEnum.workflow,
AppTypeEnum.chatAgent
].includes(app.type)
? [
{
children: [
@ -500,7 +504,7 @@ const CreateButton = ({ appType }: { appType: AppTypeEnum | 'all' }) => {
const parentId = router.query.parentId;
const createAppType =
createAppTypeMap[appType as CreateAppType]?.type ||
(router.pathname.includes('/agent') ? AppTypeEnum.workflow : AppTypeEnum.workflowTool);
(router.pathname.includes('/agent') ? AppTypeEnum.chatAgent : AppTypeEnum.workflowTool);
const isToolType = ToolTypeList.includes(createAppType);
return (
@ -572,7 +576,7 @@ const ListCreateButton = ({ appType }: { appType: AppTypeEnum | 'all' }) => {
const parentId = router.query.parentId;
const createAppType =
createAppTypeMap[appType as CreateAppType]?.type ||
(router.pathname.includes('/agent') ? AppTypeEnum.workflow : AppTypeEnum.workflowTool);
(router.pathname.includes('/agent') ? AppTypeEnum.chatAgent : AppTypeEnum.workflowTool);
return (
<MyBox

View File

@ -87,7 +87,7 @@ const AppListContextProvider = ({ children }: { children: ReactNode }) => {
// agent page
if (router.pathname.includes('/agent')) {
return !type || type === 'all'
? [AppTypeEnum.folder, AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.agent]
? [AppTypeEnum.folder, AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.chatAgent]
: [AppTypeEnum.folder, type];
}

View File

@ -2,9 +2,9 @@ import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { i18nT } from '@fastgpt/web/i18n/utils';
export const appTypeTagMap = {
[AppTypeEnum.agent]: {
label: 'Agent',
icon: 'core/app/type/mcpTools'
[AppTypeEnum.chatAgent]: {
label: i18nT('app:type.Chat_Agent_v2'),
icon: 'core/app/type/simple'
},
[AppTypeEnum.simple]: {
label: i18nT('app:type.Chat_Agent'),

View File

@ -15,7 +15,7 @@ const SimpleEdit = dynamic(() => import('@/pageComponents/app/detail/Edit/Simple
ssr: false,
loading: () => <Loading fixed={false} />
});
const AgentEdit = dynamic(() => import('@/pageComponents/app/detail/Edit/Agent'), {
const AgentEdit = dynamic(() => import('@/pageComponents/app/detail/Edit/ChatAgent'), {
ssr: false,
loading: () => <Loading fixed={false} />
});
@ -61,7 +61,7 @@ const AppDetail = () => {
) : (
<>
{appDetail.type === AppTypeEnum.simple && <SimpleEdit />}
{appDetail.type === AppTypeEnum.agent && <AgentEdit />}
{appDetail.type === AppTypeEnum.chatAgent && <AgentEdit />}
{appDetail.type === AppTypeEnum.workflow && <Workflow />}
{appDetail.type === AppTypeEnum.workflowTool && <Plugin />}
{appDetail.type === AppTypeEnum.mcpToolSet && <MCPTools />}

View File

@ -56,7 +56,7 @@ type FormType = {
};
export type CreateAppType =
| AppTypeEnum.agent
| AppTypeEnum.chatAgent
| AppTypeEnum.simple
| AppTypeEnum.workflow
| AppTypeEnum.workflowTool
@ -71,7 +71,7 @@ const CreateAppsPage = () => {
const { parentId, appType } = query;
const [selectedAppType, setSelectedAppType] = useState<CreateAppType>(
(appType as CreateAppType) || AppTypeEnum.workflow
(appType as CreateAppType) || AppTypeEnum.chatAgent
);
const [creatingTemplateId, setCreatingTemplateId] = useState<string | null>(null);
const isToolType = ToolTypeList.includes(selectedAppType);

View File

@ -15,7 +15,7 @@ import { i18nT } from '@fastgpt/web/i18n/utils';
// TODO: 需要做一个类型强制约束
export const emptyTemplates = {
[AppTypeEnum.agent]: {
[AppTypeEnum.chatAgent]: {
avatar: 'core/app/type/simpleFill',
name: 'Agent',
nodes: [],