mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-15 12:10:16 +00:00
🐛 fix: agent profiles update, agent tools config set, editor placeholder (#11074)
* feat: open the gtd & document tools in normal agent * feat: add getAllbuildintools in agent profles tools settings * fix: slove the tools modal segment not work * feat: support editor placeholder
This commit is contained in:
@@ -215,6 +215,7 @@
|
||||
"settingAgent.name.placeholder": "Enter agent name",
|
||||
"settingAgent.name.title": "Name",
|
||||
"settingAgent.prompt.placeholder": "Enter agent settings, press / to open the command menu",
|
||||
"settingAgent.prompt.templatePlaceholder": "#### Goal\nDescribe the main purpose and objective of this agent.\n\n #### Skills\n- List the key capabilities\n- And specialized knowledge areas\n\n#### Workflow\n1. Step-by-step process\n2. How the agent should approach tasks\n3. Expected interactions with users\n\n#### Constraints\n- Important limitations to follow\n- Guidelines for behavior",
|
||||
"settingAgent.prompt.title": "Agent Profile",
|
||||
"settingAgent.submit": "Update Agent",
|
||||
"settingAgent.tag.desc": "Agent tags will be displayed in the Agent Community",
|
||||
|
||||
@@ -215,6 +215,7 @@
|
||||
"settingAgent.name.placeholder": "请输入助理名称",
|
||||
"settingAgent.name.title": "名称",
|
||||
"settingAgent.prompt.placeholder": "输入助理设定,按 / 打开命令菜单",
|
||||
"settingAgent.prompt.templatePlaceholder": "#### 目标\n描述助理的主要目的和目标。\n\n#### 技能\n- 列出关键能力\n- 以及专业知识领域\n\n#### 工作流程\n1. 逐步处理流程\n2. 助理应如何处理任务\n3. 与用户的预期交互\n\n#### 约束\n- 需要遵循的重要限制\n- 行为准则",
|
||||
"settingAgent.prompt.title": "助理设定",
|
||||
"settingAgent.submit": "更新助理信息",
|
||||
"settingAgent.tag.desc": "助理标签将在助理社区中展示",
|
||||
|
||||
@@ -20,7 +20,7 @@ import { useAgentStore } from '@/store/agent';
|
||||
import { agentSelectors } from '@/store/agent/selectors';
|
||||
|
||||
import { useMentionOptions } from '../ProfileEditor/MentionList';
|
||||
import PROMPT_TEMPLATE from '../ProfileEditor/promptTemplate.json';
|
||||
import { EMPTY_EDITOR_STATE } from '../constants';
|
||||
import { useProfileStore } from '../store';
|
||||
import TypoBar from './TypoBar';
|
||||
import { useSlashItems } from './useSlashItems';
|
||||
@@ -33,7 +33,7 @@ const EditorCanvas = memo(() => {
|
||||
const editorData = config?.editorData;
|
||||
const systemRole = config?.systemRole;
|
||||
const updateConfig = useAgentStore((s) => s.updateAgentConfig);
|
||||
const [initialLoad] = useState(editorData || PROMPT_TEMPLATE);
|
||||
const [initialLoad] = useState(editorData || EMPTY_EDITOR_STATE);
|
||||
const mentionOptions = useMentionOptions();
|
||||
const editor = useProfileStore((s) => s.editor);
|
||||
const handleContentChange = useProfileStore((s) => s.handleContentChange);
|
||||
@@ -90,12 +90,11 @@ const EditorCanvas = memo(() => {
|
||||
if (streamingInProgress) return;
|
||||
try {
|
||||
if (editorData) {
|
||||
editor.setDocument('json', editorData || PROMPT_TEMPLATE);
|
||||
editor.setDocument('json', editorData);
|
||||
} else if (systemRole) {
|
||||
editor.setDocument('markdown', systemRole);
|
||||
} else {
|
||||
editor.setDocument('json', PROMPT_TEMPLATE);
|
||||
}
|
||||
// If no editorData and no systemRole, leave editor empty to show placeholder
|
||||
setContentInit(true);
|
||||
} catch (error) {
|
||||
console.error('[EditorCanvas] Failed to init editor content:', error);
|
||||
@@ -106,7 +105,6 @@ const EditorCanvas = memo(() => {
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
<Editor
|
||||
@@ -116,7 +114,7 @@ const EditorCanvas = memo(() => {
|
||||
mentionOption={mentionOptions}
|
||||
onInit={() => setEditorInit(true)}
|
||||
onTextChange={handleChange}
|
||||
placeholder={t('settingAgent.prompt.placeholder')}
|
||||
placeholder={t('settingAgent.prompt.templatePlaceholder')}
|
||||
plugins={[
|
||||
ReactListPlugin,
|
||||
ReactCodePlugin,
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
import { KLAVIS_SERVER_TYPES, type KlavisServerType } from '@lobechat/const';
|
||||
import { Avatar, Button, Flexbox, Icon, type ItemType, Segmented } from '@lobehub/ui';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { ArrowRight, PlusIcon, Store, ToyBrick } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
import React, { Suspense, memo, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, { Suspense, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import PluginAvatar from '@/components/Plugins/PluginAvatar';
|
||||
@@ -17,7 +17,7 @@ import PluginStore from '@/features/PluginStore';
|
||||
import { useCheckPluginsIsInstalled } from '@/hooks/useCheckPluginsIsInstalled';
|
||||
import { useFetchInstalledPlugins } from '@/hooks/useFetchInstalledPlugins';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { agentSelectors } from '@/store/agent/selectors';
|
||||
import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/selectors';
|
||||
import { serverConfigSelectors, useServerConfigStore } from '@/store/serverConfig';
|
||||
import { useToolStore } from '@/store/tool';
|
||||
import {
|
||||
@@ -28,8 +28,39 @@ import {
|
||||
|
||||
import PluginTag from './PluginTag';
|
||||
|
||||
const WEB_BROWSING_IDENTIFIER = 'lobe-web-browsing';
|
||||
|
||||
type TabType = 'all' | 'installed';
|
||||
|
||||
const prefixCls = 'ant';
|
||||
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
dropdown: css`
|
||||
overflow: hidden;
|
||||
|
||||
width: 100%;
|
||||
border: 1px solid ${cssVar.colorBorderSecondary};
|
||||
border-radius: ${cssVar.borderRadiusLG};
|
||||
|
||||
background: ${cssVar.colorBgElevated};
|
||||
box-shadow: ${cssVar.boxShadowSecondary};
|
||||
|
||||
.${prefixCls}-dropdown-menu {
|
||||
border-radius: 0 !important;
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
`,
|
||||
header: css`
|
||||
padding: ${cssVar.paddingXS};
|
||||
border-block-end: 1px solid ${cssVar.colorBorderSecondary};
|
||||
background: transparent;
|
||||
`,
|
||||
scroller: css`
|
||||
overflow: hidden auto;
|
||||
`,
|
||||
}));
|
||||
|
||||
/**
|
||||
* Klavis 服务器图标组件
|
||||
* 对于 string 类型的 icon,使用 Image 组件渲染
|
||||
@@ -54,8 +85,12 @@ const AgentTool = memo(() => {
|
||||
const plugins = config?.plugins || [];
|
||||
|
||||
const toggleAgentPlugin = useAgentStore((s) => s.toggleAgentPlugin);
|
||||
const updateAgentChatConfig = useAgentStore((s) => s.updateAgentChatConfig);
|
||||
const installedPluginList = useToolStore(pluginSelectors.installedPluginMetaList, isEqual);
|
||||
const builtinList = useToolStore(builtinToolSelectors.metaList, isEqual);
|
||||
const builtinList = useToolStore(builtinToolSelectors.allMetaList, isEqual);
|
||||
|
||||
// Web browsing uses searchMode instead of plugins array
|
||||
const isSearchEnabled = useAgentStore(agentChatConfigSelectors.isAgentEnableSearch);
|
||||
|
||||
// Klavis 相关状态
|
||||
const allKlavisServers = useToolStore(klavisStoreSelectors.getServers, isEqual);
|
||||
@@ -81,6 +116,35 @@ const AgentTool = memo(() => {
|
||||
// 使用 SWR 加载用户的 Klavis 集成(从数据库)
|
||||
useFetchUserKlavisServers(isKlavisEnabledInEnv);
|
||||
|
||||
// Toggle web browsing via searchMode
|
||||
const toggleWebBrowsing = useCallback(async () => {
|
||||
const nextMode = isSearchEnabled ? 'off' : 'auto';
|
||||
await updateAgentChatConfig({ searchMode: nextMode });
|
||||
}, [isSearchEnabled, updateAgentChatConfig]);
|
||||
|
||||
// Check if a tool is enabled (handles web browsing specially)
|
||||
const isToolEnabled = useCallback(
|
||||
(identifier: string) => {
|
||||
if (identifier === WEB_BROWSING_IDENTIFIER) {
|
||||
return isSearchEnabled;
|
||||
}
|
||||
return plugins.includes(identifier);
|
||||
},
|
||||
[plugins, isSearchEnabled],
|
||||
);
|
||||
|
||||
// Toggle a tool (handles web browsing specially)
|
||||
const handleToggleTool = useCallback(
|
||||
async (identifier: string) => {
|
||||
if (identifier === WEB_BROWSING_IDENTIFIER) {
|
||||
await toggleWebBrowsing();
|
||||
} else {
|
||||
await toggleAgentPlugin(identifier);
|
||||
}
|
||||
},
|
||||
[toggleWebBrowsing, toggleAgentPlugin],
|
||||
);
|
||||
|
||||
// Set default tab based on installed plugins (only on first load)
|
||||
useEffect(() => {
|
||||
if (!isInitializedRef.current && plugins.length >= 0) {
|
||||
@@ -101,11 +165,14 @@ const AgentTool = memo(() => {
|
||||
);
|
||||
|
||||
// 过滤掉 builtinList 中的 klavis 工具(它们会单独显示在 Klavis 区域)
|
||||
// 同时过滤掉 availableInWeb: false 的工具(如 LocalSystem 仅桌面版可用)
|
||||
const filteredBuiltinList = useMemo(
|
||||
() =>
|
||||
isKlavisEnabledInEnv
|
||||
? builtinList.filter((item) => !allKlavisTypeIdentifiers.has(item.identifier))
|
||||
: builtinList,
|
||||
builtinList
|
||||
.filter((item) => item.availableInWeb)
|
||||
.filter((item) =>
|
||||
isKlavisEnabledInEnv ? !allKlavisTypeIdentifiers.has(item.identifier) : true,
|
||||
),
|
||||
[builtinList, allKlavisTypeIdentifiers, isKlavisEnabledInEnv],
|
||||
);
|
||||
|
||||
@@ -132,11 +199,15 @@ const AgentTool = memo(() => {
|
||||
// Handle plugin remove via Tag close
|
||||
const handleRemovePlugin =
|
||||
(pluginId: string | { enabled: boolean; identifier: string; settings: Record<string, any> }) =>
|
||||
(e: React.MouseEvent) => {
|
||||
async (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const identifier = typeof pluginId === 'string' ? pluginId : pluginId?.identifier;
|
||||
toggleAgentPlugin(identifier, false);
|
||||
if (identifier === WEB_BROWSING_IDENTIFIER) {
|
||||
await updateAgentChatConfig({ searchMode: 'off' });
|
||||
} else {
|
||||
toggleAgentPlugin(identifier, false);
|
||||
}
|
||||
};
|
||||
|
||||
// Build dropdown menu items (adapted from useControls)
|
||||
@@ -153,12 +224,12 @@ const AgentTool = memo(() => {
|
||||
key: item.identifier,
|
||||
label: (
|
||||
<ToolItem
|
||||
checked={plugins.includes(item.identifier)}
|
||||
checked={isToolEnabled(item.identifier)}
|
||||
id={item.identifier}
|
||||
label={item.meta?.title}
|
||||
onUpdate={async () => {
|
||||
setUpdating(true);
|
||||
await toggleAgentPlugin(item.identifier);
|
||||
await handleToggleTool(item.identifier);
|
||||
setUpdating(false);
|
||||
}}
|
||||
/>
|
||||
@@ -167,7 +238,7 @@ const AgentTool = memo(() => {
|
||||
// Klavis 服务器
|
||||
...klavisServerItems,
|
||||
],
|
||||
[filteredBuiltinList, klavisServerItems, plugins, toggleAgentPlugin],
|
||||
[filteredBuiltinList, klavisServerItems, isToolEnabled, handleToggleTool],
|
||||
);
|
||||
|
||||
// Plugin items for dropdown
|
||||
@@ -242,7 +313,7 @@ const AgentTool = memo(() => {
|
||||
|
||||
// 已启用的 builtin 工具
|
||||
const enabledBuiltinItems = filteredBuiltinList
|
||||
.filter((item) => plugins.includes(item.identifier))
|
||||
.filter((item) => isToolEnabled(item.identifier))
|
||||
.map((item) => ({
|
||||
icon: <Avatar avatar={item.meta.avatar} size={20} style={{ flex: 'none' }} />,
|
||||
key: item.identifier,
|
||||
@@ -253,7 +324,7 @@ const AgentTool = memo(() => {
|
||||
label={item.meta?.title}
|
||||
onUpdate={async () => {
|
||||
setUpdating(true);
|
||||
await toggleAgentPlugin(item.identifier);
|
||||
await handleToggleTool(item.identifier);
|
||||
setUpdating(false);
|
||||
}}
|
||||
/>
|
||||
@@ -311,42 +382,21 @@ const AgentTool = memo(() => {
|
||||
}
|
||||
|
||||
return items;
|
||||
}, [filteredBuiltinList, klavisServerItems, installedPluginList, plugins, toggleAgentPlugin, t]);
|
||||
}, [
|
||||
filteredBuiltinList,
|
||||
klavisServerItems,
|
||||
installedPluginList,
|
||||
plugins,
|
||||
isToolEnabled,
|
||||
handleToggleTool,
|
||||
toggleAgentPlugin,
|
||||
t,
|
||||
]);
|
||||
|
||||
// Use effective tab for display (default to all while initializing)
|
||||
const effectiveTab = activeTab ?? 'all';
|
||||
const currentItems = effectiveTab === 'all' ? allTabItems : installedTabItems;
|
||||
|
||||
// Final menu items with tab segmented control
|
||||
const menuItems: ItemType[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
key: 'tabs',
|
||||
label: (
|
||||
<Segmented
|
||||
block
|
||||
onChange={(v) => setActiveTab(v as TabType)}
|
||||
options={[
|
||||
{
|
||||
label: t('tools.tabs.all', { defaultValue: 'All' }),
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
label: t('tools.tabs.installed', { defaultValue: 'Installed' }),
|
||||
value: 'installed',
|
||||
},
|
||||
]}
|
||||
size="small"
|
||||
value={effectiveTab}
|
||||
/>
|
||||
),
|
||||
type: 'group',
|
||||
},
|
||||
...currentItems,
|
||||
],
|
||||
[currentItems, effectiveTab, t],
|
||||
);
|
||||
|
||||
const button = (
|
||||
<Button
|
||||
icon={PlusIcon}
|
||||
@@ -359,12 +409,22 @@ const AgentTool = memo(() => {
|
||||
</Button>
|
||||
);
|
||||
|
||||
// Combine plugins and web browsing for display
|
||||
const allEnabledTools = useMemo(() => {
|
||||
const tools = [...plugins];
|
||||
// Add web browsing if enabled (it's not in plugins array)
|
||||
if (isSearchEnabled && !tools.includes(WEB_BROWSING_IDENTIFIER)) {
|
||||
tools.unshift(WEB_BROWSING_IDENTIFIER);
|
||||
}
|
||||
return tools;
|
||||
}, [plugins, isSearchEnabled]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Plugin Selector and Tags */}
|
||||
<Flexbox align="center" gap={8} horizontal wrap={'wrap'}>
|
||||
{/* Second Row: Selected Plugins as Tags */}
|
||||
{plugins?.map((pluginId) => {
|
||||
{allEnabledTools.map((pluginId) => {
|
||||
return (
|
||||
<PluginTag key={pluginId} onRemove={handleRemovePlugin(pluginId)} pluginId={pluginId} />
|
||||
);
|
||||
@@ -375,10 +435,49 @@ const AgentTool = memo(() => {
|
||||
<ActionDropdown
|
||||
maxHeight={500}
|
||||
maxWidth={480}
|
||||
menu={{ items: menuItems }}
|
||||
menu={{
|
||||
items: currentItems,
|
||||
style: {
|
||||
// let only the custom scroller scroll
|
||||
maxHeight: 'unset',
|
||||
overflowY: 'visible',
|
||||
},
|
||||
}}
|
||||
minHeight={isKlavisEnabledInEnv ? 500 : undefined}
|
||||
minWidth={320}
|
||||
placement={'bottomLeft'}
|
||||
popupRender={(menu) => (
|
||||
<div className={styles.dropdown}>
|
||||
{/* stopPropagation prevents dropdown's onClick from calling preventDefault on Segmented */}
|
||||
<div className={styles.header} onClick={(e) => e.stopPropagation()}>
|
||||
<Segmented
|
||||
block
|
||||
onChange={(v) => setActiveTab(v as TabType)}
|
||||
options={[
|
||||
{
|
||||
label: t('tools.tabs.all', { defaultValue: 'All' }),
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
label: t('tools.tabs.installed', { defaultValue: 'Installed' }),
|
||||
value: 'installed',
|
||||
},
|
||||
]}
|
||||
size="small"
|
||||
value={effectiveTab}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={styles.scroller}
|
||||
style={{
|
||||
maxHeight: 500,
|
||||
minHeight: isKlavisEnabledInEnv ? 500 : undefined,
|
||||
}}
|
||||
>
|
||||
{menu}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
trigger={['click']}
|
||||
>
|
||||
{button}
|
||||
@@ -386,8 +485,8 @@ const AgentTool = memo(() => {
|
||||
</Suspense>
|
||||
</Flexbox>
|
||||
|
||||
{/* PluginStore Modal */}
|
||||
<PluginStore open={modalOpen} setOpen={setModalOpen} />
|
||||
{/* PluginStore Modal - rendered outside Flexbox to avoid event interference */}
|
||||
{modalOpen && <PluginStore open={modalOpen} setOpen={setModalOpen} />}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -59,8 +59,8 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
// Extract identifier
|
||||
const identifier = typeof pluginId === 'string' ? pluginId : pluginId?.identifier;
|
||||
|
||||
// Get local plugin lists
|
||||
const builtinList = useToolStore(builtinToolSelectors.metaList, isEqual);
|
||||
// Get local plugin lists (use allMetaList to include hidden tools)
|
||||
const builtinList = useToolStore(builtinToolSelectors.allMetaList, isEqual);
|
||||
const installedPluginList = useToolStore(pluginSelectors.installedPluginMetaList, isEqual);
|
||||
|
||||
// Klavis 相关状态
|
||||
@@ -79,6 +79,7 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
// Check if this Klavis server is connected
|
||||
const connectedServer = allKlavisServers.find((s) => s.identifier === identifier);
|
||||
return {
|
||||
availableInWeb: true,
|
||||
icon: klavisType.icon,
|
||||
isInstalled: !!connectedServer,
|
||||
label: klavisType.label,
|
||||
@@ -91,6 +92,7 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
const builtinMeta = builtinList.find((p) => p.identifier === identifier);
|
||||
if (builtinMeta) {
|
||||
return {
|
||||
availableInWeb: builtinMeta.availableInWeb,
|
||||
avatar: builtinMeta.meta.avatar,
|
||||
isInstalled: true,
|
||||
title: builtinMeta.meta.title,
|
||||
@@ -101,6 +103,7 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
const installedMeta = installedPluginList.find((p) => p.identifier === identifier);
|
||||
if (installedMeta) {
|
||||
return {
|
||||
availableInWeb: true,
|
||||
avatar: installedMeta.avatar,
|
||||
isInstalled: true,
|
||||
title: installedMeta.title,
|
||||
@@ -120,6 +123,7 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
|
||||
// Determine final metadata
|
||||
const meta = localMeta || {
|
||||
availableInWeb: true,
|
||||
avatar: remoteData?.avatar,
|
||||
isInstalled: false,
|
||||
title: remoteData?.title || identifier,
|
||||
@@ -127,6 +131,7 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
};
|
||||
|
||||
const displayTitle = isLoading ? 'Loading...' : meta.title;
|
||||
const isDesktopOnly = !meta.availableInWeb;
|
||||
|
||||
// Render icon based on type
|
||||
const renderIcon = () => {
|
||||
@@ -152,6 +157,18 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
// Build display text
|
||||
const getDisplayText = () => {
|
||||
let text = displayTitle;
|
||||
if (isDesktopOnly) {
|
||||
text += ` (${t('tools.desktopOnly', { defaultValue: 'Desktop Only' })})`;
|
||||
}
|
||||
if (!meta.isInstalled) {
|
||||
text += ` (${t('tools.notInstalled', { defaultValue: 'Not Installed' })})`;
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
return (
|
||||
<Tag
|
||||
className={styles.tag}
|
||||
@@ -167,9 +184,7 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
}
|
||||
variant={isDarkMode ? 'filled' : 'outlined'}
|
||||
>
|
||||
{!meta.isInstalled
|
||||
? `${displayTitle} (${t('tools.notInstalled', { defaultValue: 'Not Installed' })})`
|
||||
: displayTitle}
|
||||
{getDisplayText()}
|
||||
</Tag>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -31,7 +31,6 @@ const ProfileEditor = memo(() => {
|
||||
<Flexbox
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
style={{ cursor: 'default', marginBottom: 12 }}
|
||||
>
|
||||
|
||||
@@ -1,277 +0,0 @@
|
||||
{
|
||||
"root": {
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Goal",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": null,
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "heading",
|
||||
"version": 1,
|
||||
"tag": "h4"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Describe the main purpose and objective of this agent.",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "paragraph",
|
||||
"version": 1,
|
||||
"textFormat": 0,
|
||||
"textStyle": ""
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Skills",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": null,
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "heading",
|
||||
"version": 1,
|
||||
"tag": "h4"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "List the key capabilities",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "And specialized knowledge areas",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 2
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "list",
|
||||
"version": 1,
|
||||
"listType": "bullet",
|
||||
"start": 1,
|
||||
"tag": "ul"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Workflow",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": null,
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "heading",
|
||||
"version": 1,
|
||||
"tag": "h4"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Step-by-step process",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "How the agent should approach tasks",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Expected interactions with users",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 3
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "list",
|
||||
"version": 1,
|
||||
"listType": "number",
|
||||
"start": 1,
|
||||
"tag": "ol"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Constraints",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": null,
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "heading",
|
||||
"version": 1,
|
||||
"tag": "h4"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Important limitations to follow",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Guidelines for behavior",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 2
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "list",
|
||||
"version": 1,
|
||||
"listType": "bullet",
|
||||
"start": 1,
|
||||
"tag": "ul"
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "root",
|
||||
"version": 1,
|
||||
"textStyle": "--shiki-dark:var(--color-info);--shiki-light:var(--color-info)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Empty editor state for initializing the editor
|
||||
* This is the minimal JSON structure required by the editor
|
||||
* Must have at least one paragraph with an empty text node
|
||||
*/
|
||||
export const EMPTY_EDITOR_STATE = {
|
||||
root: {
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: '',
|
||||
type: 'text',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: null,
|
||||
format: '',
|
||||
indent: 0,
|
||||
textFormat: 0,
|
||||
textStyle: '',
|
||||
type: 'paragraph',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: null,
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'root',
|
||||
version: 1,
|
||||
},
|
||||
};
|
||||
@@ -20,7 +20,7 @@ import { useAgentGroupStore } from '@/store/agentGroup';
|
||||
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
||||
|
||||
import { useMentionOptions } from '../ProfileEditor/MentionList';
|
||||
import PROMPT_TEMPLATE from '../ProfileEditor/promptTemplate.json';
|
||||
import { EMPTY_EDITOR_STATE } from '../constants';
|
||||
import { useProfileStore } from '../store';
|
||||
import TypoBar from './TypoBar';
|
||||
import { useSlashItems } from './useSlashItems';
|
||||
@@ -41,7 +41,7 @@ const EditorCanvas = memo(() => {
|
||||
|
||||
// For group profile, we don't use editorData - just systemPrompt
|
||||
const editorData = undefined;
|
||||
const [initialLoad] = useState(PROMPT_TEMPLATE);
|
||||
const [initialLoad] = useState(EMPTY_EDITOR_STATE);
|
||||
const mentionOptions = useMentionOptions();
|
||||
const editor = useProfileStore((s) => s.editor);
|
||||
const handleContentChange = useProfileStore((s) => s.handleContentChange);
|
||||
@@ -86,12 +86,11 @@ const EditorCanvas = memo(() => {
|
||||
if (streamingInProgress) return;
|
||||
try {
|
||||
if (editorData) {
|
||||
editor.setDocument('json', editorData || PROMPT_TEMPLATE);
|
||||
editor.setDocument('json', editorData);
|
||||
} else if (systemRole) {
|
||||
editor.setDocument('markdown', systemRole);
|
||||
} else {
|
||||
editor.setDocument('json', PROMPT_TEMPLATE);
|
||||
}
|
||||
// If no editorData and no systemRole, leave editor empty to show placeholder
|
||||
setContentInit(true);
|
||||
} catch (error) {
|
||||
console.error('[EditorCanvas] Failed to init editor content:', error);
|
||||
@@ -102,7 +101,6 @@ const EditorCanvas = memo(() => {
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
<Editor
|
||||
@@ -112,7 +110,7 @@ const EditorCanvas = memo(() => {
|
||||
mentionOption={mentionOptions}
|
||||
onInit={() => setEditorInit(true)}
|
||||
onTextChange={handleChange}
|
||||
placeholder={t('settingAgent.prompt.placeholder')}
|
||||
placeholder={t('settingAgent.prompt.templatePlaceholder')}
|
||||
plugins={[
|
||||
ReactListPlugin,
|
||||
ReactCodePlugin,
|
||||
|
||||
@@ -31,7 +31,6 @@ const ProfileEditor = memo(() => {
|
||||
<Flexbox
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
style={{ cursor: 'default', marginBottom: 12 }}
|
||||
>
|
||||
@@ -48,7 +47,7 @@ const ProfileEditor = memo(() => {
|
||||
<ModelSelect
|
||||
onChange={updateConfig}
|
||||
value={{
|
||||
model: config?.model,
|
||||
model: config?.model,
|
||||
provider: config?.provider,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,277 +0,0 @@
|
||||
{
|
||||
"root": {
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Goal",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": null,
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "heading",
|
||||
"version": 1,
|
||||
"tag": "h4"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Describe the main purpose and objective of this agent.",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "paragraph",
|
||||
"version": 1,
|
||||
"textFormat": 0,
|
||||
"textStyle": ""
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Skills",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": null,
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "heading",
|
||||
"version": 1,
|
||||
"tag": "h4"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "List the key capabilities",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "And specialized knowledge areas",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 2
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "list",
|
||||
"version": 1,
|
||||
"listType": "bullet",
|
||||
"start": 1,
|
||||
"tag": "ul"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Workflow",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": null,
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "heading",
|
||||
"version": 1,
|
||||
"tag": "h4"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Step-by-step process",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "How the agent should approach tasks",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Expected interactions with users",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 3
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "list",
|
||||
"version": 1,
|
||||
"listType": "number",
|
||||
"start": 1,
|
||||
"tag": "ol"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Constraints",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": null,
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "heading",
|
||||
"version": 1,
|
||||
"tag": "h4"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Important limitations to follow",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"detail": 0,
|
||||
"format": 0,
|
||||
"mode": "normal",
|
||||
"style": "",
|
||||
"text": "Guidelines for behavior",
|
||||
"type": "text",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "listitem",
|
||||
"version": 1,
|
||||
"value": 2
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "list",
|
||||
"version": 1,
|
||||
"listType": "bullet",
|
||||
"start": 1,
|
||||
"tag": "ul"
|
||||
}
|
||||
],
|
||||
"direction": "ltr",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"type": "root",
|
||||
"version": 1,
|
||||
"textStyle": "--shiki-dark:var(--color-info);--shiki-light:var(--color-info)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Empty editor state for initializing the editor
|
||||
* This is the minimal JSON structure required by the editor
|
||||
* Must have at least one paragraph with an empty text node
|
||||
*/
|
||||
export const EMPTY_EDITOR_STATE = {
|
||||
root: {
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: '',
|
||||
type: 'text',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: null,
|
||||
format: '',
|
||||
indent: 0,
|
||||
textFormat: 0,
|
||||
textStyle: '',
|
||||
type: 'paragraph',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: null,
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'root',
|
||||
version: 1,
|
||||
},
|
||||
};
|
||||
@@ -237,6 +237,19 @@ export default {
|
||||
'settingAgent.name.placeholder': 'Enter agent name',
|
||||
'settingAgent.name.title': 'Name',
|
||||
'settingAgent.prompt.placeholder': 'Enter agent settings, press / to open the command menu',
|
||||
'settingAgent.prompt.templatePlaceholder':
|
||||
'#### Goal\n' +
|
||||
'Describe the main purpose and objective of this agent.\n\n' +
|
||||
'#### Skills\n' +
|
||||
'- List the key capabilities\n' +
|
||||
'- And specialized knowledge areas\n\n' +
|
||||
'#### Workflow\n' +
|
||||
'1. Step-by-step process\n' +
|
||||
'2. How the agent should approach tasks\n' +
|
||||
'3. Expected interactions with users\n\n' +
|
||||
'#### Constraints\n' +
|
||||
'- Important limitations to follow\n' +
|
||||
'- Guidelines for behavior',
|
||||
'settingAgent.prompt.title': 'Agent Profile',
|
||||
'settingAgent.submit': 'Update Agent',
|
||||
'settingAgent.tag.desc': 'Agent tags will be displayed in the Agent Community',
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
export { builtinToolSelectors } from '../slices/builtin/selectors';
|
||||
export {
|
||||
builtinToolSelectors,
|
||||
type LobeToolMetaWithAvailability,
|
||||
} from '../slices/builtin/selectors';
|
||||
export { customPluginSelectors } from '../slices/customPlugin/selectors';
|
||||
export { klavisStoreSelectors } from '../slices/klavisStore/selectors';
|
||||
export { mcpStoreSelectors } from '../slices/mcpStore/selectors';
|
||||
|
||||
@@ -5,27 +5,30 @@ import { shouldEnableTool } from '@/helpers/toolFilters';
|
||||
import type { ToolStoreState } from '../../initialState';
|
||||
import { KlavisServerStatus } from '../klavisStore';
|
||||
|
||||
const metaList = (s: ToolStoreState): LobeToolMeta[] => {
|
||||
// Get builtin tools meta list
|
||||
const builtinMetas = s.builtinTools
|
||||
.filter((item) => {
|
||||
// Filter hidden tools
|
||||
if (item.hidden) return false;
|
||||
export interface LobeToolMetaWithAvailability extends LobeToolMeta {
|
||||
/**
|
||||
* Whether the tool is available in web environment
|
||||
* e.g., LocalSystem is desktop-only, so availableInWeb is false
|
||||
*/
|
||||
availableInWeb: boolean;
|
||||
}
|
||||
|
||||
// Filter platform-specific tools (e.g., LocalSystem desktop-only)
|
||||
if (!shouldEnableTool(item.identifier)) return false;
|
||||
const toBuiltinMeta = (t: ToolStoreState['builtinTools'][number]): LobeToolMeta => ({
|
||||
author: 'LobeHub',
|
||||
identifier: t.identifier,
|
||||
meta: t.manifest.meta,
|
||||
type: 'builtin' as const,
|
||||
});
|
||||
|
||||
return true;
|
||||
})
|
||||
.map((t) => ({
|
||||
author: 'LobeHub',
|
||||
identifier: t.identifier,
|
||||
meta: t.manifest.meta,
|
||||
type: 'builtin' as const,
|
||||
}));
|
||||
const toBuiltinMetaWithAvailability = (
|
||||
t: ToolStoreState['builtinTools'][number],
|
||||
): LobeToolMetaWithAvailability => ({
|
||||
...toBuiltinMeta(t),
|
||||
availableInWeb: shouldEnableTool(t.identifier),
|
||||
});
|
||||
|
||||
// Get Klavis servers as builtin tools meta
|
||||
const klavisMetas = (s.servers || [])
|
||||
const getKlavisMetas = (s: ToolStoreState): LobeToolMeta[] =>
|
||||
(s.servers || [])
|
||||
.filter((server) => server.status === KlavisServerStatus.CONNECTED && server.tools?.length)
|
||||
.map((server) => ({
|
||||
author: 'Klavis',
|
||||
@@ -41,9 +44,55 @@ const metaList = (s: ToolStoreState): LobeToolMeta[] => {
|
||||
type: 'builtin' as const,
|
||||
}));
|
||||
|
||||
return [...builtinMetas, ...klavisMetas];
|
||||
const getKlavisMetasWithAvailability = (s: ToolStoreState): LobeToolMetaWithAvailability[] =>
|
||||
getKlavisMetas(s).map((meta) => ({ ...meta, availableInWeb: true }));
|
||||
|
||||
/**
|
||||
* Get visible builtin tools meta list (excludes hidden tools)
|
||||
* Used for general tool display in chat input bar
|
||||
*/
|
||||
const metaList = (s: ToolStoreState): LobeToolMeta[] => {
|
||||
const builtinMetas = s.builtinTools
|
||||
.filter((item) => {
|
||||
// Filter hidden tools
|
||||
if (item.hidden) return false;
|
||||
|
||||
// Filter platform-specific tools (e.g., LocalSystem desktop-only)
|
||||
if (!shouldEnableTool(item.identifier)) return false;
|
||||
|
||||
return true;
|
||||
})
|
||||
.map(toBuiltinMeta);
|
||||
|
||||
return [...builtinMetas, ...getKlavisMetas(s)];
|
||||
};
|
||||
|
||||
// Tools that should never be exposed in agent profile configuration
|
||||
const EXCLUDED_TOOLS = new Set([
|
||||
'lobe-agent-builder',
|
||||
'lobe-group-agent-builder',
|
||||
'lobe-group-management',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Get all builtin tools meta list (includes hidden tools and platform-specific tools)
|
||||
* Used for agent profile tool configuration where all tools should be configurable
|
||||
* Returns availability info so UI can show hints for unavailable tools
|
||||
*/
|
||||
const allMetaList = (s: ToolStoreState): LobeToolMetaWithAvailability[] => {
|
||||
const builtinMetas = s.builtinTools
|
||||
.filter((item) => {
|
||||
// Exclude internal tools that should not be user-configurable
|
||||
if (EXCLUDED_TOOLS.has(item.identifier)) return false;
|
||||
|
||||
return true;
|
||||
})
|
||||
.map(toBuiltinMetaWithAvailability);
|
||||
|
||||
return [...builtinMetas, ...getKlavisMetasWithAvailability(s)];
|
||||
};
|
||||
|
||||
export const builtinToolSelectors = {
|
||||
allMetaList,
|
||||
metaList,
|
||||
};
|
||||
|
||||
@@ -73,13 +73,11 @@ export const builtinTools: LobeBuiltinTool[] = [
|
||||
type: 'builtin',
|
||||
},
|
||||
{
|
||||
hidden: true,
|
||||
identifier: GTDManifest.identifier,
|
||||
manifest: GTDManifest,
|
||||
type: 'builtin',
|
||||
},
|
||||
{
|
||||
hidden: true,
|
||||
identifier: NotebookManifest.identifier,
|
||||
manifest: NotebookManifest,
|
||||
type: 'builtin',
|
||||
|
||||
Reference in New Issue
Block a user