@lobehub/lobehub 2.0.0-next.270 → 2.0.0-next.272
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +1 -0
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/e2e/src/features/home/starter.feature +34 -0
- package/e2e/src/steps/community/interactions.steps.ts +37 -14
- package/e2e/src/steps/home/starter.steps.ts +216 -0
- package/package.json +1 -1
- package/src/app/[variants]/(main)/agent/features/Conversation/Header/HeaderActions/useMenu.tsx +7 -17
- package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/AgentTool.tsx +8 -487
- package/src/app/[variants]/(main)/group/profile/features/ProfileEditor/AgentTool.tsx +6 -388
- package/src/features/ChatInput/ActionBar/Tools/KlavisServerItem.tsx +1 -2
- package/src/features/ChatInput/ActionBar/Tools/LobehubSkillServerItem.tsx +0 -1
- package/src/features/ProfileEditor/AgentTool.tsx +549 -0
- package/src/features/ProfileEditor/PluginTag.tsx +213 -0
- package/src/features/ProfileEditor/index.ts +2 -0
- package/src/libs/better-auth/define-config.ts +7 -1
- package/src/store/home/slices/homeInput/action.ts +6 -3
- package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/PluginTag.tsx +0 -195
- package/src/app/[variants]/(main)/group/profile/features/ProfileEditor/PluginTag.tsx +0 -180
|
@@ -1,494 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { Avatar, Button, Flexbox, Icon, type ItemType, Segmented } from '@lobehub/ui';
|
|
5
|
-
import { createStaticStyles, cssVar } from 'antd-style';
|
|
6
|
-
import isEqual from 'fast-deep-equal';
|
|
7
|
-
import { ArrowRight, PlusIcon, Store, ToyBrick } from 'lucide-react';
|
|
8
|
-
import Image from 'next/image';
|
|
9
|
-
import React, { Suspense, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
10
|
-
import { useTranslation } from 'react-i18next';
|
|
11
|
-
|
|
12
|
-
import PluginAvatar from '@/components/Plugins/PluginAvatar';
|
|
13
|
-
import KlavisServerItem from '@/features/ChatInput/ActionBar/Tools/KlavisServerItem';
|
|
14
|
-
import ToolItem from '@/features/ChatInput/ActionBar/Tools/ToolItem';
|
|
15
|
-
import ActionDropdown from '@/features/ChatInput/ActionBar/components/ActionDropdown';
|
|
16
|
-
import PluginStore from '@/features/PluginStore';
|
|
17
|
-
import { useCheckPluginsIsInstalled } from '@/hooks/useCheckPluginsIsInstalled';
|
|
18
|
-
import { useFetchInstalledPlugins } from '@/hooks/useFetchInstalledPlugins';
|
|
19
|
-
import { useAgentStore } from '@/store/agent';
|
|
20
|
-
import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/selectors';
|
|
21
|
-
import { serverConfigSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
22
|
-
import { useToolStore } from '@/store/tool';
|
|
23
|
-
import {
|
|
24
|
-
builtinToolSelectors,
|
|
25
|
-
klavisStoreSelectors,
|
|
26
|
-
pluginSelectors,
|
|
27
|
-
} from '@/store/tool/selectors';
|
|
28
|
-
|
|
29
|
-
import PluginTag from './PluginTag';
|
|
30
|
-
|
|
31
|
-
const WEB_BROWSING_IDENTIFIER = 'lobe-web-browsing';
|
|
32
|
-
|
|
33
|
-
type TabType = 'all' | 'installed';
|
|
34
|
-
|
|
35
|
-
const prefixCls = 'ant';
|
|
36
|
-
|
|
37
|
-
const styles = createStaticStyles(({ css }) => ({
|
|
38
|
-
dropdown: css`
|
|
39
|
-
overflow: hidden;
|
|
40
|
-
|
|
41
|
-
width: 100%;
|
|
42
|
-
border: 1px solid ${cssVar.colorBorderSecondary};
|
|
43
|
-
border-radius: ${cssVar.borderRadiusLG};
|
|
44
|
-
|
|
45
|
-
background: ${cssVar.colorBgElevated};
|
|
46
|
-
box-shadow: ${cssVar.boxShadowSecondary};
|
|
47
|
-
|
|
48
|
-
.${prefixCls}-dropdown-menu {
|
|
49
|
-
border-radius: 0 !important;
|
|
50
|
-
background: transparent !important;
|
|
51
|
-
box-shadow: none !important;
|
|
52
|
-
}
|
|
53
|
-
`,
|
|
54
|
-
header: css`
|
|
55
|
-
padding: ${cssVar.paddingXS};
|
|
56
|
-
border-block-end: 1px solid ${cssVar.colorBorderSecondary};
|
|
57
|
-
background: transparent;
|
|
58
|
-
`,
|
|
59
|
-
scroller: css`
|
|
60
|
-
overflow: hidden auto;
|
|
61
|
-
`,
|
|
62
|
-
}));
|
|
3
|
+
import { AgentTool as SharedAgentTool } from '@/features/ProfileEditor';
|
|
63
4
|
|
|
64
5
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
6
|
+
* AgentTool for agent profile editor
|
|
7
|
+
* - showWebBrowsing: Agent profile supports web browsing toggle
|
|
8
|
+
* - filterAvailableInWeb: Filter out desktop-only tools in web version
|
|
9
|
+
* - useAllMetaList: Use allMetaList to include hidden tools
|
|
68
10
|
*/
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
<Image alt={label} height={18} src={icon} style={{ flex: 'none' }} unoptimized width={18} />
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// 使用主题色填充,在深色模式下自动适应
|
|
77
|
-
return <Icon fill={cssVar.colorText} icon={icon} size={18} />;
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const AgentTool = memo(() => {
|
|
81
|
-
const { t } = useTranslation('setting');
|
|
82
|
-
const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
|
|
83
|
-
|
|
84
|
-
// Plugin state management
|
|
85
|
-
const plugins = config?.plugins || [];
|
|
86
|
-
|
|
87
|
-
const toggleAgentPlugin = useAgentStore((s) => s.toggleAgentPlugin);
|
|
88
|
-
const updateAgentChatConfig = useAgentStore((s) => s.updateAgentChatConfig);
|
|
89
|
-
const installedPluginList = useToolStore(pluginSelectors.installedPluginMetaList, isEqual);
|
|
90
|
-
const builtinList = useToolStore(builtinToolSelectors.allMetaList, isEqual);
|
|
91
|
-
|
|
92
|
-
// Web browsing uses searchMode instead of plugins array
|
|
93
|
-
const isSearchEnabled = useAgentStore(agentChatConfigSelectors.isAgentEnableSearch);
|
|
94
|
-
|
|
95
|
-
// Klavis 相关状态
|
|
96
|
-
const allKlavisServers = useToolStore(klavisStoreSelectors.getServers, isEqual);
|
|
97
|
-
const isKlavisEnabledInEnv = useServerConfigStore(serverConfigSelectors.enableKlavis);
|
|
98
|
-
|
|
99
|
-
// Plugin store modal state
|
|
100
|
-
const [modalOpen, setModalOpen] = useState(false);
|
|
101
|
-
const [updating, setUpdating] = useState(false);
|
|
102
|
-
|
|
103
|
-
// Tab state for dual-column layout
|
|
104
|
-
const [activeTab, setActiveTab] = useState<TabType | null>(null);
|
|
105
|
-
const isInitializedRef = useRef(false);
|
|
106
|
-
|
|
107
|
-
// Fetch plugins
|
|
108
|
-
const [useFetchPluginStore, useFetchUserKlavisServers] = useToolStore((s) => [
|
|
109
|
-
s.useFetchPluginStore,
|
|
110
|
-
s.useFetchUserKlavisServers,
|
|
111
|
-
]);
|
|
112
|
-
useFetchPluginStore();
|
|
113
|
-
useFetchInstalledPlugins();
|
|
114
|
-
useCheckPluginsIsInstalled(plugins);
|
|
115
|
-
|
|
116
|
-
// 使用 SWR 加载用户的 Klavis 集成(从数据库)
|
|
117
|
-
useFetchUserKlavisServers(isKlavisEnabledInEnv);
|
|
118
|
-
|
|
119
|
-
// Toggle web browsing via searchMode
|
|
120
|
-
const toggleWebBrowsing = useCallback(async () => {
|
|
121
|
-
const nextMode = isSearchEnabled ? 'off' : 'auto';
|
|
122
|
-
await updateAgentChatConfig({ searchMode: nextMode });
|
|
123
|
-
}, [isSearchEnabled, updateAgentChatConfig]);
|
|
124
|
-
|
|
125
|
-
// Check if a tool is enabled (handles web browsing specially)
|
|
126
|
-
const isToolEnabled = useCallback(
|
|
127
|
-
(identifier: string) => {
|
|
128
|
-
if (identifier === WEB_BROWSING_IDENTIFIER) {
|
|
129
|
-
return isSearchEnabled;
|
|
130
|
-
}
|
|
131
|
-
return plugins.includes(identifier);
|
|
132
|
-
},
|
|
133
|
-
[plugins, isSearchEnabled],
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
// Toggle a tool (handles web browsing specially)
|
|
137
|
-
const handleToggleTool = useCallback(
|
|
138
|
-
async (identifier: string) => {
|
|
139
|
-
if (identifier === WEB_BROWSING_IDENTIFIER) {
|
|
140
|
-
await toggleWebBrowsing();
|
|
141
|
-
} else {
|
|
142
|
-
await toggleAgentPlugin(identifier);
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
[toggleWebBrowsing, toggleAgentPlugin],
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
// Set default tab based on installed plugins (only on first load)
|
|
149
|
-
useEffect(() => {
|
|
150
|
-
if (!isInitializedRef.current && plugins.length >= 0) {
|
|
151
|
-
isInitializedRef.current = true;
|
|
152
|
-
setActiveTab(plugins.length > 0 ? 'installed' : 'all');
|
|
153
|
-
}
|
|
154
|
-
}, [plugins.length]);
|
|
155
|
-
|
|
156
|
-
// 根据 identifier 获取已连接的服务器
|
|
157
|
-
const getServerByName = (identifier: string) => {
|
|
158
|
-
return allKlavisServers.find((server) => server.identifier === identifier);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// 获取所有 Klavis 服务器类型的 identifier 集合(用于过滤 builtinList)
|
|
162
|
-
const allKlavisTypeIdentifiers = useMemo(
|
|
163
|
-
() => new Set(KLAVIS_SERVER_TYPES.map((type) => type.identifier)),
|
|
164
|
-
[],
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
// 过滤掉 builtinList 中的 klavis 工具(它们会单独显示在 Klavis 区域)
|
|
168
|
-
// 同时过滤掉 availableInWeb: false 的工具(如 LocalSystem 仅桌面版可用)
|
|
169
|
-
const filteredBuiltinList = useMemo(
|
|
170
|
-
() =>
|
|
171
|
-
builtinList
|
|
172
|
-
.filter((item) => item.availableInWeb)
|
|
173
|
-
.filter((item) =>
|
|
174
|
-
isKlavisEnabledInEnv ? !allKlavisTypeIdentifiers.has(item.identifier) : true,
|
|
175
|
-
),
|
|
176
|
-
[builtinList, allKlavisTypeIdentifiers, isKlavisEnabledInEnv],
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
// Klavis 服务器列表项
|
|
180
|
-
const klavisServerItems = useMemo(
|
|
181
|
-
() =>
|
|
182
|
-
isKlavisEnabledInEnv
|
|
183
|
-
? KLAVIS_SERVER_TYPES.map((type) => ({
|
|
184
|
-
icon: <KlavisIcon icon={type.icon} label={type.label} />,
|
|
185
|
-
key: type.identifier,
|
|
186
|
-
label: (
|
|
187
|
-
<KlavisServerItem
|
|
188
|
-
identifier={type.identifier}
|
|
189
|
-
label={type.label}
|
|
190
|
-
server={getServerByName(type.identifier)}
|
|
191
|
-
serverName={type.serverName}
|
|
192
|
-
/>
|
|
193
|
-
),
|
|
194
|
-
}))
|
|
195
|
-
: [],
|
|
196
|
-
[isKlavisEnabledInEnv, allKlavisServers],
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
// Handle plugin remove via Tag close
|
|
200
|
-
const handleRemovePlugin =
|
|
201
|
-
(pluginId: string | { enabled: boolean; identifier: string; settings: Record<string, any> }) =>
|
|
202
|
-
async (e: React.MouseEvent) => {
|
|
203
|
-
e.preventDefault();
|
|
204
|
-
e.stopPropagation();
|
|
205
|
-
const identifier = typeof pluginId === 'string' ? pluginId : pluginId?.identifier;
|
|
206
|
-
if (identifier === WEB_BROWSING_IDENTIFIER) {
|
|
207
|
-
await updateAgentChatConfig({ searchMode: 'off' });
|
|
208
|
-
} else {
|
|
209
|
-
toggleAgentPlugin(identifier, false);
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
// Build dropdown menu items (adapted from useControls)
|
|
214
|
-
const enablePluginCount = plugins.filter(
|
|
215
|
-
(id) => !builtinList.some((b) => b.identifier === id),
|
|
216
|
-
).length;
|
|
217
|
-
|
|
218
|
-
// 合并 builtin 工具和 Klavis 服务器
|
|
219
|
-
const builtinItems = useMemo(
|
|
220
|
-
() => [
|
|
221
|
-
// 原有的 builtin 工具
|
|
222
|
-
...filteredBuiltinList.map((item) => ({
|
|
223
|
-
icon: <Avatar avatar={item.meta.avatar} size={20} style={{ flex: 'none' }} />,
|
|
224
|
-
key: item.identifier,
|
|
225
|
-
label: (
|
|
226
|
-
<ToolItem
|
|
227
|
-
checked={isToolEnabled(item.identifier)}
|
|
228
|
-
id={item.identifier}
|
|
229
|
-
label={item.meta?.title}
|
|
230
|
-
onUpdate={async () => {
|
|
231
|
-
setUpdating(true);
|
|
232
|
-
await handleToggleTool(item.identifier);
|
|
233
|
-
setUpdating(false);
|
|
234
|
-
}}
|
|
235
|
-
/>
|
|
236
|
-
),
|
|
237
|
-
})),
|
|
238
|
-
// Klavis 服务器
|
|
239
|
-
...klavisServerItems,
|
|
240
|
-
],
|
|
241
|
-
[filteredBuiltinList, klavisServerItems, isToolEnabled, handleToggleTool],
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// Plugin items for dropdown
|
|
245
|
-
const pluginItems = useMemo(
|
|
246
|
-
() =>
|
|
247
|
-
installedPluginList.map((item) => ({
|
|
248
|
-
icon: item?.avatar ? (
|
|
249
|
-
<PluginAvatar avatar={item.avatar} size={20} />
|
|
250
|
-
) : (
|
|
251
|
-
<Icon icon={ToyBrick} size={20} />
|
|
252
|
-
),
|
|
253
|
-
key: item.identifier,
|
|
254
|
-
label: (
|
|
255
|
-
<ToolItem
|
|
256
|
-
checked={plugins.includes(item.identifier)}
|
|
257
|
-
id={item.identifier}
|
|
258
|
-
label={item.title}
|
|
259
|
-
onUpdate={async () => {
|
|
260
|
-
setUpdating(true);
|
|
261
|
-
await toggleAgentPlugin(item.identifier);
|
|
262
|
-
setUpdating(false);
|
|
263
|
-
}}
|
|
264
|
-
/>
|
|
265
|
-
),
|
|
266
|
-
})),
|
|
267
|
-
[installedPluginList, plugins, toggleAgentPlugin],
|
|
268
|
-
);
|
|
269
|
-
|
|
270
|
-
// All tab items (市场 tab)
|
|
271
|
-
const allTabItems: ItemType[] = useMemo(
|
|
272
|
-
() => [
|
|
273
|
-
{
|
|
274
|
-
children: builtinItems,
|
|
275
|
-
key: 'builtins',
|
|
276
|
-
label: t('tools.builtins.groupName'),
|
|
277
|
-
type: 'group',
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
children: pluginItems,
|
|
281
|
-
key: 'plugins',
|
|
282
|
-
label: (
|
|
283
|
-
<Flexbox align={'center'} gap={40} horizontal justify={'space-between'}>
|
|
284
|
-
{t('tools.plugins.groupName')}
|
|
285
|
-
{enablePluginCount === 0 ? null : (
|
|
286
|
-
<div style={{ fontSize: 12, marginInlineEnd: 4 }}>
|
|
287
|
-
{t('tools.plugins.enabled', { num: enablePluginCount })}
|
|
288
|
-
</div>
|
|
289
|
-
)}
|
|
290
|
-
</Flexbox>
|
|
291
|
-
),
|
|
292
|
-
type: 'group',
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
type: 'divider',
|
|
296
|
-
},
|
|
297
|
-
{
|
|
298
|
-
extra: <Icon icon={ArrowRight} />,
|
|
299
|
-
icon: Store,
|
|
300
|
-
key: 'plugin-store',
|
|
301
|
-
label: t('tools.plugins.store'),
|
|
302
|
-
onClick: () => {
|
|
303
|
-
setModalOpen(true);
|
|
304
|
-
},
|
|
305
|
-
},
|
|
306
|
-
],
|
|
307
|
-
[builtinItems, pluginItems, enablePluginCount, t],
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
// Installed tab items - 只显示已启用的
|
|
311
|
-
const installedTabItems: ItemType[] = useMemo(() => {
|
|
312
|
-
const items: ItemType[] = [];
|
|
313
|
-
|
|
314
|
-
// 已启用的 builtin 工具
|
|
315
|
-
const enabledBuiltinItems = filteredBuiltinList
|
|
316
|
-
.filter((item) => isToolEnabled(item.identifier))
|
|
317
|
-
.map((item) => ({
|
|
318
|
-
icon: <Avatar avatar={item.meta.avatar} size={20} style={{ flex: 'none' }} />,
|
|
319
|
-
key: item.identifier,
|
|
320
|
-
label: (
|
|
321
|
-
<ToolItem
|
|
322
|
-
checked={true}
|
|
323
|
-
id={item.identifier}
|
|
324
|
-
label={item.meta?.title}
|
|
325
|
-
onUpdate={async () => {
|
|
326
|
-
setUpdating(true);
|
|
327
|
-
await handleToggleTool(item.identifier);
|
|
328
|
-
setUpdating(false);
|
|
329
|
-
}}
|
|
330
|
-
/>
|
|
331
|
-
),
|
|
332
|
-
}));
|
|
333
|
-
|
|
334
|
-
// 已连接且已启用的 Klavis 服务器
|
|
335
|
-
const connectedKlavisItems = klavisServerItems.filter((item) =>
|
|
336
|
-
plugins.includes(item.key as string),
|
|
337
|
-
);
|
|
338
|
-
|
|
339
|
-
// 合并 builtin 和 Klavis
|
|
340
|
-
const allBuiltinItems = [...enabledBuiltinItems, ...connectedKlavisItems];
|
|
341
|
-
|
|
342
|
-
if (allBuiltinItems.length > 0) {
|
|
343
|
-
items.push({
|
|
344
|
-
children: allBuiltinItems,
|
|
345
|
-
key: 'installed-builtins',
|
|
346
|
-
label: t('tools.builtins.groupName'),
|
|
347
|
-
type: 'group',
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// 已启用的插件
|
|
352
|
-
const installedPlugins = installedPluginList
|
|
353
|
-
.filter((item) => plugins.includes(item.identifier))
|
|
354
|
-
.map((item) => ({
|
|
355
|
-
icon: item?.avatar ? (
|
|
356
|
-
<PluginAvatar avatar={item.avatar} size={20} />
|
|
357
|
-
) : (
|
|
358
|
-
<Icon icon={ToyBrick} size={20} />
|
|
359
|
-
),
|
|
360
|
-
key: item.identifier,
|
|
361
|
-
label: (
|
|
362
|
-
<ToolItem
|
|
363
|
-
checked={true}
|
|
364
|
-
id={item.identifier}
|
|
365
|
-
label={item.title}
|
|
366
|
-
onUpdate={async () => {
|
|
367
|
-
setUpdating(true);
|
|
368
|
-
await toggleAgentPlugin(item.identifier);
|
|
369
|
-
setUpdating(false);
|
|
370
|
-
}}
|
|
371
|
-
/>
|
|
372
|
-
),
|
|
373
|
-
}));
|
|
374
|
-
|
|
375
|
-
if (installedPlugins.length > 0) {
|
|
376
|
-
items.push({
|
|
377
|
-
children: installedPlugins,
|
|
378
|
-
key: 'installed-plugins',
|
|
379
|
-
label: t('tools.plugins.groupName'),
|
|
380
|
-
type: 'group',
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
return items;
|
|
385
|
-
}, [
|
|
386
|
-
filteredBuiltinList,
|
|
387
|
-
klavisServerItems,
|
|
388
|
-
installedPluginList,
|
|
389
|
-
plugins,
|
|
390
|
-
isToolEnabled,
|
|
391
|
-
handleToggleTool,
|
|
392
|
-
toggleAgentPlugin,
|
|
393
|
-
t,
|
|
394
|
-
]);
|
|
395
|
-
|
|
396
|
-
// Use effective tab for display (default to all while initializing)
|
|
397
|
-
const effectiveTab = activeTab ?? 'all';
|
|
398
|
-
const currentItems = effectiveTab === 'all' ? allTabItems : installedTabItems;
|
|
399
|
-
|
|
400
|
-
const button = (
|
|
401
|
-
<Button
|
|
402
|
-
icon={PlusIcon}
|
|
403
|
-
loading={updating}
|
|
404
|
-
size={'small'}
|
|
405
|
-
style={{ color: cssVar.colorTextSecondary }}
|
|
406
|
-
type={'text'}
|
|
407
|
-
>
|
|
408
|
-
{t('tools.add', { defaultValue: 'Add' })}
|
|
409
|
-
</Button>
|
|
410
|
-
);
|
|
411
|
-
|
|
412
|
-
// Combine plugins and web browsing for display
|
|
413
|
-
const allEnabledTools = useMemo(() => {
|
|
414
|
-
const tools = [...plugins];
|
|
415
|
-
// Add web browsing if enabled (it's not in plugins array)
|
|
416
|
-
if (isSearchEnabled && !tools.includes(WEB_BROWSING_IDENTIFIER)) {
|
|
417
|
-
tools.unshift(WEB_BROWSING_IDENTIFIER);
|
|
418
|
-
}
|
|
419
|
-
return tools;
|
|
420
|
-
}, [plugins, isSearchEnabled]);
|
|
421
|
-
|
|
422
|
-
return (
|
|
423
|
-
<>
|
|
424
|
-
{/* Plugin Selector and Tags */}
|
|
425
|
-
<Flexbox align="center" gap={8} horizontal wrap={'wrap'}>
|
|
426
|
-
{/* Second Row: Selected Plugins as Tags */}
|
|
427
|
-
{allEnabledTools.map((pluginId) => {
|
|
428
|
-
return (
|
|
429
|
-
<PluginTag key={pluginId} onRemove={handleRemovePlugin(pluginId)} pluginId={pluginId} />
|
|
430
|
-
);
|
|
431
|
-
})}
|
|
432
|
-
{/* Plugin Selector Dropdown - Using Action component pattern */}
|
|
433
|
-
|
|
434
|
-
<Suspense fallback={button}>
|
|
435
|
-
<ActionDropdown
|
|
436
|
-
maxHeight={500}
|
|
437
|
-
maxWidth={480}
|
|
438
|
-
menu={{
|
|
439
|
-
items: currentItems,
|
|
440
|
-
style: {
|
|
441
|
-
// let only the custom scroller scroll
|
|
442
|
-
maxHeight: 'unset',
|
|
443
|
-
overflowY: 'visible',
|
|
444
|
-
},
|
|
445
|
-
}}
|
|
446
|
-
minHeight={isKlavisEnabledInEnv ? 500 : undefined}
|
|
447
|
-
minWidth={320}
|
|
448
|
-
placement={'bottomLeft'}
|
|
449
|
-
popupRender={(menu) => (
|
|
450
|
-
<div className={styles.dropdown}>
|
|
451
|
-
{/* stopPropagation prevents dropdown's onClick from calling preventDefault on Segmented */}
|
|
452
|
-
<div className={styles.header} onClick={(e) => e.stopPropagation()}>
|
|
453
|
-
<Segmented
|
|
454
|
-
block
|
|
455
|
-
onChange={(v) => setActiveTab(v as TabType)}
|
|
456
|
-
options={[
|
|
457
|
-
{
|
|
458
|
-
label: t('tools.tabs.all', { defaultValue: 'All' }),
|
|
459
|
-
value: 'all',
|
|
460
|
-
},
|
|
461
|
-
{
|
|
462
|
-
label: t('tools.tabs.installed', { defaultValue: 'Installed' }),
|
|
463
|
-
value: 'installed',
|
|
464
|
-
},
|
|
465
|
-
]}
|
|
466
|
-
size="small"
|
|
467
|
-
value={effectiveTab}
|
|
468
|
-
/>
|
|
469
|
-
</div>
|
|
470
|
-
<div
|
|
471
|
-
className={styles.scroller}
|
|
472
|
-
style={{
|
|
473
|
-
maxHeight: 500,
|
|
474
|
-
minHeight: isKlavisEnabledInEnv ? 500 : undefined,
|
|
475
|
-
}}
|
|
476
|
-
>
|
|
477
|
-
{menu}
|
|
478
|
-
</div>
|
|
479
|
-
</div>
|
|
480
|
-
)}
|
|
481
|
-
trigger={['click']}
|
|
482
|
-
>
|
|
483
|
-
{button}
|
|
484
|
-
</ActionDropdown>
|
|
485
|
-
</Suspense>
|
|
486
|
-
</Flexbox>
|
|
487
|
-
|
|
488
|
-
{/* PluginStore Modal - rendered outside Flexbox to avoid event interference */}
|
|
489
|
-
{modalOpen && <PluginStore open={modalOpen} setOpen={setModalOpen} />}
|
|
490
|
-
</>
|
|
491
|
-
);
|
|
492
|
-
});
|
|
11
|
+
const AgentTool = () => {
|
|
12
|
+
return <SharedAgentTool filterAvailableInWeb showWebBrowsing useAllMetaList />;
|
|
13
|
+
};
|
|
493
14
|
|
|
494
15
|
export default AgentTool;
|