diff --git a/locales/en-US/setting.json b/locales/en-US/setting.json index cc6dd10a4a..0f743fd214 100644 --- a/locales/en-US/setting.json +++ b/locales/en-US/setting.json @@ -1018,6 +1018,7 @@ "tools.activation.pinned": "Pinned", "tools.activation.pinned.desc": "Always On", "tools.add": "Add Skill", + "tools.addSkillOrConnector": "Add Skills / Connector", "tools.builtins.configure": "Configure", "tools.builtins.find-skills.description": "Helps users discover and install agent skills when they ask \"how do I do X\", \"find a skill for X\", or want to extend capabilities", "tools.builtins.find-skills.title": "Find Skills", diff --git a/locales/zh-CN/setting.json b/locales/zh-CN/setting.json index 2f0cc87d3b..2b637eea87 100644 --- a/locales/zh-CN/setting.json +++ b/locales/zh-CN/setting.json @@ -1019,6 +1019,7 @@ "tools.activation.pinned": "固定启用", "tools.activation.pinned.desc": "始终注入", "tools.add": "集成技能", + "tools.addSkillOrConnector": "添加技能 / 连接器", "tools.builtins.configure": "配置", "tools.builtins.find-skills.description": "当用户询问“我该如何做 X”、“帮我找一个能做 X 的技能”或希望扩展能力时,帮助用户发现并安装助手技能", "tools.builtins.find-skills.title": "查找技能", diff --git a/src/features/ChatInput/ActionBar/Tools/PopoverContent.tsx b/src/features/ChatInput/ActionBar/Tools/PopoverContent.tsx index caae6e3cea..0702c0e232 100644 --- a/src/features/ChatInput/ActionBar/Tools/PopoverContent.tsx +++ b/src/features/ChatInput/ActionBar/Tools/PopoverContent.tsx @@ -1,18 +1,23 @@ import { type ItemType } from '@lobehub/ui'; import { Flexbox, Icon, SearchBar, stopPropagation, usePopoverContext } from '@lobehub/ui'; import { createStaticStyles, cssVar } from 'antd-style'; -import { ChevronRight, ExternalLink, Settings, Store } from 'lucide-react'; +import { Pin, Settings, Store, Zap } from 'lucide-react'; import { memo, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { ScrollSignalProvider } from './ScrollSignalContext'; import SkillActivateMode from './SkillActivateMode'; -import ToolsList, { toolsListStyles } from './ToolsList'; +import ToolsList from './ToolsList'; const styles = createStaticStyles(({ css }) => ({ footer: css` - padding: 4px; + display: flex; + gap: 14px; + align-items: center; + + padding-block: 6px; + padding-inline: 12px; border-block-start: 1px solid ${cssVar.colorFill}; `, header: css` @@ -20,8 +25,67 @@ const styles = createStaticStyles(({ css }) => ({ padding-inline: 8px; border-block-end: 1px solid ${cssVar.colorFill}; `, - trailingIcon: css` - opacity: 0.5; + iconButton: css` + cursor: pointer; + + display: inline-flex; + flex: none; + align-items: center; + justify-content: center; + + width: 28px; + height: 28px; + border: 0; + border-radius: 6px; + + color: ${cssVar.colorTextTertiary}; + + background: transparent; + + transition: + color 0.2s, + background 0.2s; + + &:hover { + color: ${cssVar.colorTextSecondary}; + background: ${cssVar.colorFillTertiary}; + } + `, + statsItem: css` + display: inline-flex; + gap: 5px; + align-items: center; + + font-size: 12px; + line-height: 18px; + color: ${cssVar.colorTextTertiary}; + `, + storeButton: css` + cursor: pointer; + + display: inline-flex; + flex: none; + gap: 4px; + align-items: center; + + height: 28px; + padding-inline: 8px; + border: 0; + border-radius: 6px; + + font-size: 13px; + color: ${cssVar.colorTextSecondary}; + + background: transparent; + + transition: + color 0.2s, + background 0.2s; + + &:hover { + color: ${cssVar.colorText}; + background: ${cssVar.colorFillTertiary}; + } `, })); @@ -51,80 +115,86 @@ const filterItems = (items: ItemType[], keyword: string): ItemType[] => { }; interface PopoverContentProps { + autoCount: number; items: ItemType[]; onOpenStore: () => void; + pinnedCount: number; } -const PopoverContent = memo(({ items, onOpenStore }) => { - const { t } = useTranslation('setting'); - const navigate = useNavigate(); - const [searchKeyword, setSearchKeyword] = useState(''); +const PopoverContent = memo( + ({ autoCount, items, onOpenStore, pinnedCount }) => { + const { t } = useTranslation('setting'); + const navigate = useNavigate(); + const [searchKeyword, setSearchKeyword] = useState(''); - const { close: closePopover } = usePopoverContext(); + const { close: closePopover } = usePopoverContext(); - const filteredItems = useMemo( - () => (searchKeyword ? filterItems(items, searchKeyword) : items), - [items, searchKeyword], - ); + const filteredItems = useMemo( + () => (searchKeyword ? filterItems(items, searchKeyword) : items), + [items, searchKeyword], + ); - return ( - - - setSearchKeyword(e.target.value)} - onKeyDown={stopPropagation} - /> - + return ( + + + setSearchKeyword(e.target.value)} + onKeyDown={stopPropagation} + /> + + + + + +
+ + + {pinnedCount} + + + + {autoCount} + + + + + +
- - - -
-
{ - closePopover(); - onOpenStore(); - }} - > -
- -
-
{t('skillStore.title')}
- -
-
{ - closePopover(); - navigate('/settings/skill'); - }} - > -
- -
-
{t('tools.plugins.management')}
- -
-
-
- ); -}); + ); + }, +); PopoverContent.displayName = 'PopoverContent'; diff --git a/src/features/ChatInput/ActionBar/Tools/index.tsx b/src/features/ChatInput/ActionBar/Tools/index.tsx index 88db7c4a91..41e9581183 100644 --- a/src/features/ChatInput/ActionBar/Tools/index.tsx +++ b/src/features/ChatInput/ActionBar/Tools/index.tsx @@ -14,7 +14,7 @@ import { useControls } from './useControls'; const Tools = memo(() => { const { t } = useTranslation('setting'); - const { marketItems, editPluginDrawer } = useControls(); + const { marketItems, editPluginDrawer, pinnedCount, autoCount } = useControls(); const agentId = useAgentId(); const model = useAgentStore((s) => agentByIdSelectors.getAgentModelById(agentId)(s)); @@ -36,7 +36,14 @@ const Tools = memo(() => { showTooltip={false} title={t('tools.title')} popover={{ - content: , + content: ( + + ), maxWidth: 320, minWidth: 320, styles: { diff --git a/src/features/ChatInput/ActionBar/Tools/useControls.tsx b/src/features/ChatInput/ActionBar/Tools/useControls.tsx index 20d6f5a530..d73112326e 100644 --- a/src/features/ChatInput/ActionBar/Tools/useControls.tsx +++ b/src/features/ChatInput/ActionBar/Tools/useControls.tsx @@ -317,6 +317,12 @@ const styles = createStaticStyles(({ css }) => ({ width: 100%; min-width: 0; `, + toolTrailing: css` + display: inline-flex; + flex: none; + gap: 8px; + align-items: center; + `, typeTag: css` display: inline-flex; flex: none; @@ -614,9 +620,11 @@ export const useControls = ({ closeDropdown }: { closeDropdown?: () => void } = {icon} {label} {extraTag} - {badge && {badge}} - {action} + + {badge && {badge}} + {action} + ), [openSkillPolicyMenu], @@ -1000,15 +1008,17 @@ export const useControls = ({ closeDropdown }: { closeDropdown?: () => void } = {icon} {title} {officialTag} + + + + + + + - - - - - ), popoverContent, diff --git a/src/locales/default/setting.ts b/src/locales/default/setting.ts index 4f5a87f21c..7649c49717 100644 --- a/src/locales/default/setting.ts +++ b/src/locales/default/setting.ts @@ -1170,6 +1170,7 @@ When I am ___, I need ___ 'tab.uploadZip.desc': 'Upload a local .zip or .skill file', 'tab.usage': 'Usage', 'tools.add': 'Add Skill', + 'tools.addSkillOrConnector': 'Add Skills / Connector', 'tools.builtins.groupName': 'Built-ins', 'tools.builtins.install': 'Install', 'tools.builtins.installed': 'Installed', diff --git a/src/server/services/aiAgent/__tests__/execAgent.connectorOverlap.test.ts b/src/server/services/aiAgent/__tests__/execAgent.connectorOverlap.test.ts index f6e3cb291e..503aa5b30c 100644 --- a/src/server/services/aiAgent/__tests__/execAgent.connectorOverlap.test.ts +++ b/src/server/services/aiAgent/__tests__/execAgent.connectorOverlap.test.ts @@ -116,6 +116,10 @@ vi.mock('@/server/services/deviceGateway', () => ({ deviceGateway: { isConfigured: false, queryDeviceList: vi.fn().mockResolvedValue([]) }, })); +vi.mock('@/server/services/deviceGateway', () => ({ + deviceGateway: { isConfigured: false, queryDeviceList: vi.fn().mockResolvedValue([]) }, +})); + vi.mock('@/server/modules/ModelRuntime', () => ({ initModelRuntimeFromDB: vi.fn() })); vi.mock('model-bank', async (importOriginal) => {