diff --git a/src/renderer/components/QuickPanel/__tests__/defaultStrategies.test.ts b/src/renderer/components/QuickPanel/__tests__/defaultStrategies.test.ts new file mode 100644 index 00000000000..8b5fffe9f1c --- /dev/null +++ b/src/renderer/components/QuickPanel/__tests__/defaultStrategies.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest' + +import { defaultFilterFn } from '../defaultStrategies' +import type { QuickPanelListItem } from '../types' + +const fuzzyRegex = /unused/i + +function matches(item: QuickPanelListItem, searchText: string) { + return defaultFilterFn(item, searchText, fuzzyRegex, new WeakMap()) +} + +describe('default QuickPanel filtering', () => { + it('keeps filterText additive with label, description, and search aliases', () => { + const item: QuickPanelListItem = { + label: 'Visible label', + description: 'Readable description', + filterText: 'explicit-field', + searchAliases: ['Hidden alias'], + icon: 'icon' + } + + expect(matches(item, 'explicit')).toBe(true) + expect(matches(item, 'visible')).toBe(true) + expect(matches(item, 'readable')).toBe(true) + expect(matches(item, 'hidden')).toBe(true) + }) +}) diff --git a/src/renderer/components/QuickPanel/defaultStrategies.ts b/src/renderer/components/QuickPanel/defaultStrategies.ts index 22f46db98dc..f3b4d34fe85 100644 --- a/src/renderer/components/QuickPanel/defaultStrategies.ts +++ b/src/renderer/components/QuickPanel/defaultStrategies.ts @@ -2,6 +2,20 @@ import * as tinyPinyin from 'tiny-pinyin' import type { QuickPanelFilterFn, QuickPanelListItem, QuickPanelSortFn } from './types' +/** + * Concatenates all textual search fields into a single haystack for substring / + * pinyin matching. `filterText` is additive here so the shared QuickPanel + * strategy keeps matching the visible label and description by default. + */ +function buildItemHaystack(item: QuickPanelListItem): string { + const parts: string[] = [] + if (item.filterText) parts.push(item.filterText) + if (typeof item.label === 'string') parts.push(item.label) + if (typeof item.description === 'string') parts.push(item.description) + if (item.searchAliases) parts.push(...item.searchAliases) + return parts.join(' ') +} + /** * Default filter function * Implements standard filtering logic with pinyin support @@ -9,14 +23,7 @@ import type { QuickPanelFilterFn, QuickPanelListItem, QuickPanelSortFn } from '. export const defaultFilterFn: QuickPanelFilterFn = (item, searchText, fuzzyRegex, pinyinCache) => { if (!searchText) return true - let filterText = item.filterText || '' - if (typeof item.label === 'string') { - filterText += item.label - } - if (typeof item.description === 'string') { - filterText += item.description - } - + const filterText = buildItemHaystack(item) const lowerFilterText = filterText.toLowerCase() const lowerSearchText = searchText.toLowerCase() @@ -47,14 +54,7 @@ export const defaultFilterFn: QuickPanelFilterFn = (item, searchText, fuzzyRegex * Higher score = better match */ const calculateMatchScore = (item: QuickPanelListItem, searchText: string): number => { - let filterText = item.filterText || '' - if (typeof item.label === 'string') { - filterText += item.label - } - if (typeof item.description === 'string') { - filterText += item.description - } - + const filterText = buildItemHaystack(item) const lowerFilterText = filterText.toLowerCase() const lowerSearchText = searchText.toLowerCase() diff --git a/src/renderer/components/QuickPanel/types.ts b/src/renderer/components/QuickPanel/types.ts index f796ef13ebd..819e6db65ff 100644 --- a/src/renderer/components/QuickPanel/types.ts +++ b/src/renderer/components/QuickPanel/types.ts @@ -101,10 +101,14 @@ export type QuickPanelListItem = { label: React.ReactNode | string description?: React.ReactNode | string /** - * Since title and description can be ReactNode values, provide separate text - * for search filtering. This can combine the title and description strings. + * Extra searchable text for items whose visible label/description are not + * enough or are not plain strings. The default filter treats this as additive + * with string labels and descriptions; custom filters may choose narrower + * semantics. */ filterText?: string + /** Extra searchable aliases that are not rendered in the panel. */ + searchAliases?: readonly string[] icon: React.ReactNode | string suffix?: React.ReactNode | string isSelected?: boolean diff --git a/src/renderer/components/composer/quickPanel/__tests__/unifiedPanel.test.ts b/src/renderer/components/composer/quickPanel/__tests__/unifiedPanel.test.ts index 2bb7450cced..5546e790f03 100644 --- a/src/renderer/components/composer/quickPanel/__tests__/unifiedPanel.test.ts +++ b/src/renderer/components/composer/quickPanel/__tests__/unifiedPanel.test.ts @@ -129,30 +129,54 @@ describe('createUnifiedQuickPanelOpenOptions', () => { expect(options.sortFn!(reversedItems, '')).toEqual(reversedItems) }) - it('filters by filterText substring and pinyin, without loose fuzzy subsequence', () => { - const options = createUnifiedQuickPanelOpenOptions([], { - quickPanel, - additionalItems: [ - { id: 'skill:pdf', label: 'pdf', description: 'Read and analyze PDFs', filterText: 'pdf', icon: 'skill' } + it('filters by explicit text, search aliases, pinyin, and pinyin initials without loose fuzzy subsequence', () => { + const options = createUnifiedQuickPanelOpenOptions( + [ + { + id: 'web-search', + kind: 'command', + label: '网络搜索', + icon: 'search', + sources: ['root-panel'], + searchAliases: ['Web Search', 'Online Search'] + } ], - resourceItems: [{ id: 'quick-phrases', label: '提示词管理', icon: 'phrase' }] - }) + { + quickPanel, + additionalItems: [ + { + id: 'skill:pdf', + label: 'pdf', + description: 'Read and analyze PDFs', + filterText: 'pdf', + icon: 'skill' + } + ], + resourceItems: [{ id: 'quick-phrases', label: '提示词管理', icon: 'phrase' }] + } + ) const filterFn = options.filterFn! const fuzzyRegex = /s.*l/i const pinyinCache = new WeakMap() const skill = options.list.find((item) => item.label === 'pdf')! const quickPhrases = options.list.find((item) => item.label === '提示词管理')! + const webSearch = options.list.find((item) => item.label === '网络搜索')! - // Skill matches its name... + // Skills keep their explicit root-panel search field and do not match descriptions. expect(filterFn(skill, 'pdf', fuzzyRegex, pinyinCache)).toBe(true) - // ...but not its description (name-only). expect(filterFn(skill, 'analyze', fuzzyRegex, pinyinCache)).toBe(false) - // Chinese row matches by substring and pinyin substring... + // Chinese row matches by substring, pinyin substring, and pinyin initial substring... expect(filterFn(quickPhrases, '提示词', fuzzyRegex, pinyinCache)).toBe(true) expect(filterFn(quickPhrases, 'tishi', fuzzyRegex, pinyinCache)).toBe(true) - // ...but not by a loose fuzzy subsequence of its pinyin (tiShiCiGuanLi). + expect(filterFn(quickPhrases, 'tscgl', fuzzyRegex, pinyinCache)).toBe(true) + + // Launcher rows with filterText still match hidden English aliases and visible Chinese labels by initials. + expect(filterFn(webSearch, 'web', fuzzyRegex, pinyinCache)).toBe(true) + expect(filterFn(webSearch, 'online', fuzzyRegex, pinyinCache)).toBe(true) + expect(filterFn(webSearch, 'wlss', fuzzyRegex, pinyinCache)).toBe(true) + // ...but not by a loose fuzzy subsequence of its pinyin or initials. expect(filterFn(quickPhrases, 'sl', fuzzyRegex, pinyinCache)).toBe(false) }) diff --git a/src/renderer/components/composer/quickPanel/bridge.ts b/src/renderer/components/composer/quickPanel/bridge.ts index 5ec50488c62..9b67c269e87 100644 --- a/src/renderer/components/composer/quickPanel/bridge.ts +++ b/src/renderer/components/composer/quickPanel/bridge.ts @@ -84,6 +84,7 @@ export function createComposerSuggestionQuickPanelItem( icon: item.icon, suffix: item.suffix, filterText: item.filterText, + searchAliases: item.searchAliases, isSelected: item.selected, isMenu: item.isMenu, disabled: item.disabled, diff --git a/src/renderer/components/composer/quickPanel/index.ts b/src/renderer/components/composer/quickPanel/index.ts index 6e4b473ec10..e308ff4c423 100644 --- a/src/renderer/components/composer/quickPanel/index.ts +++ b/src/renderer/components/composer/quickPanel/index.ts @@ -9,6 +9,7 @@ export { hasComposerQuickPanelTriggerBoundary, ROOT_QUICK_PANEL_ALLOWED_PREFIXES } from './bridge' +export { getQuickPanelSearchAliases } from './searchAliases' export { COMPOSER_SUPPRESS_SUGGESTION_META, type ComposerSuggestionActiveChangeOptions, diff --git a/src/renderer/components/composer/quickPanel/searchAliases.ts b/src/renderer/components/composer/quickPanel/searchAliases.ts new file mode 100644 index 00000000000..f73afcd5423 --- /dev/null +++ b/src/renderer/components/composer/quickPanel/searchAliases.ts @@ -0,0 +1,15 @@ +import type { TFunction } from 'i18next' + +export function getQuickPanelSearchAliases(t: TFunction, key: string, extraAliases: readonly string[] = []): string[] { + const aliases = new Set() + const englishText = t(key, { lng: 'en-US', defaultValue: '' }) + + for (const value of [englishText, ...extraAliases]) { + if (typeof value !== 'string') continue + const alias = value.trim() + if (!alias) continue + aliases.add(alias) + } + + return Array.from(aliases) +} diff --git a/src/renderer/components/composer/quickPanel/suggestionExtension.ts b/src/renderer/components/composer/quickPanel/suggestionExtension.ts index 9d8a55ecbd2..387a156d062 100644 --- a/src/renderer/components/composer/quickPanel/suggestionExtension.ts +++ b/src/renderer/components/composer/quickPanel/suggestionExtension.ts @@ -21,6 +21,7 @@ export interface ComposerSuggestionItem { isMenu?: boolean suffix?: ReactNode | string query?: string + searchAliases?: readonly string[] command: (options: { editor: Editor; range: Range; item: ComposerSuggestionItem; query: string }) => void } diff --git a/src/renderer/components/composer/quickPanel/unifiedPanel.ts b/src/renderer/components/composer/quickPanel/unifiedPanel.ts index a0a3144c6d9..3f595061686 100644 --- a/src/renderer/components/composer/quickPanel/unifiedPanel.ts +++ b/src/renderer/components/composer/quickPanel/unifiedPanel.ts @@ -142,20 +142,29 @@ const sortUnifiedQuickPanelItems: QuickPanelSortFn = (items, searchText) => { function getUnifiedQuickPanelMatchText(item: QuickPanelListItem) { // `filterText`, when set, is the authoritative search field for the item - // (e.g. skills set it to their name only). Otherwise fall back to the visible - // label + description so items without an explicit search field stay searchable. - if (item.filterText) return item.filterText + // (e.g. skills set it to their name only). Hidden aliases may still expand search. + if (item.filterText) { + return item.searchAliases ? `${item.filterText} ${item.searchAliases.join(' ')}` : item.filterText + } const parts: string[] = [] if (typeof item.label === 'string') parts.push(item.label) if (typeof item.description === 'string') parts.push(item.description) + if (item.searchAliases) parts.push(...item.searchAliases) return parts.join(' ') } +function getPinyinSearchText(matchText: string) { + const pinyinWords = tinyPinyin.convertToPinyin(matchText, ' ', true).toLowerCase().split(/\s+/).filter(Boolean) + const pinyinText = pinyinWords.join('') + const pinyinInitials = pinyinWords.map((word) => word[0] ?? '').join('') + return `${pinyinText} ${pinyinInitials}` +} + /** - * Root panel filter: substring match, plus pinyin substring for Chinese text. - * Intentionally avoids the default loose fuzzy subsequence matching so unrelated - * rows (e.g. Quick Phrases) don't surface for a query typed for another item. + * Root panel filter: substring match, plus pinyin and pinyin-initial substring + * matching for Chinese text. Intentionally avoids loose fuzzy subsequence matching + * so unrelated rows (e.g. Quick Phrases) don't surface for another item's query. */ const filterUnifiedQuickPanelItems: QuickPanelFilterFn = (item, searchText, _fuzzyRegex, pinyinCache) => { if (!searchText) return true @@ -169,7 +178,7 @@ const filterUnifiedQuickPanelItems: QuickPanelFilterFn = (item, searchText, _fuz if (tinyPinyin.isSupported() && /[\u4e00-\u9fa5]/.test(matchText)) { let pinyinText = pinyinCache.get(item) if (pinyinText === undefined) { - pinyinText = tinyPinyin.convertToPinyin(matchText, '', true).toLowerCase() + pinyinText = getPinyinSearchText(matchText) pinyinCache.set(item, pinyinText) } return pinyinText.includes(query) @@ -251,6 +260,7 @@ function createUnifiedPanelListItem( description: getLauncherDescription(launcher), icon: launcher.icon, suffix: launcher.suffix, + searchAliases: launcher.searchAliases, isSelected: launcher.active, isMenu: launcher.kind === 'panel' || launcher.kind === 'group' || children.length > 0, disabled: launcher.disabled, diff --git a/src/renderer/components/composer/toolLauncher.ts b/src/renderer/components/composer/toolLauncher.ts index fba94beefa6..34d4a18d2cc 100644 --- a/src/renderer/components/composer/toolLauncher.ts +++ b/src/renderer/components/composer/toolLauncher.ts @@ -39,6 +39,7 @@ export interface ComposerToolLauncher { description?: ReactNode | string tooltip?: ReactNode | string disabledReason?: ReactNode | string + searchAliases?: readonly string[] icon: ReactNode | string suffix?: ReactNode | string active?: boolean diff --git a/src/renderer/components/composer/tools/components/AttachmentButton.tsx b/src/renderer/components/composer/tools/components/AttachmentButton.tsx index d5b7089173d..c5645cd00d7 100644 --- a/src/renderer/components/composer/tools/components/AttachmentButton.tsx +++ b/src/renderer/components/composer/tools/components/AttachmentButton.tsx @@ -1,3 +1,4 @@ +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import type { ToolLauncherApi } from '@renderer/components/composer/tools/types' import { filterSupportedFiles } from '@renderer/utils/file' import { type ComposerAttachment, toComposerAttachments } from '@renderer/utils/message/composerAttachment' @@ -72,6 +73,7 @@ const useAttachmentToolController = ({ launcher, couldAddImageFile, extensions, order: 10, label: t('chat.input.upload.attachment'), description: '', + searchAliases: getQuickPanelSearchAliases(t, 'chat.input.upload.attachment', ['upload attachment']), tooltip: isDocumentOnly ? t('chat.input.upload.image_not_supported') : undefined, icon: , suffix: isDocumentOnly ? t('chat.input.upload.document_only') : undefined, diff --git a/src/renderer/components/composer/tools/components/KnowledgeBaseButton.tsx b/src/renderer/components/composer/tools/components/KnowledgeBaseButton.tsx index 39cd6293aec..d546c2461c5 100644 --- a/src/renderer/components/composer/tools/components/KnowledgeBaseButton.tsx +++ b/src/renderer/components/composer/tools/components/KnowledgeBaseButton.tsx @@ -1,4 +1,5 @@ import { ComposerPanelSymbol } from '@renderer/components/composer/quickPanel' +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import type { ToolLauncherApi } from '@renderer/components/composer/tools/types' import { type QuickPanelCallBackOptions, @@ -189,6 +190,7 @@ const useKnowledgeBaseToolController = ({ order: 40, label: t('chat.input.knowledge_base'), description: resolvedDisabledReason ?? '', + searchAliases: getQuickPanelSearchAliases(t, 'chat.input.knowledge_base', ['knowledge base']), disabledReason: resolvedDisabledReason, icon: , active: isEnabled, diff --git a/src/renderer/components/composer/tools/components/QuickPhrasesButton.tsx b/src/renderer/components/composer/tools/components/QuickPhrasesButton.tsx index 0ab05c97656..449d694cef2 100644 --- a/src/renderer/components/composer/tools/components/QuickPhrasesButton.tsx +++ b/src/renderer/components/composer/tools/components/QuickPhrasesButton.tsx @@ -1,6 +1,7 @@ import { useMutation, useQuery } from '@data/hooks/useDataApi' import { loggerService } from '@logger' import { ComposerPanelSymbol } from '@renderer/components/composer/quickPanel' +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import type { ToolLauncherApi } from '@renderer/components/composer/tools/types' import { type QuickPanelCallBackOptions, @@ -210,6 +211,7 @@ const useQuickPhrasesToolController = ({ launcher, setInputValue }: Props) => { order: 70, label: t('settings.prompts.title'), description: '', + searchAliases: getQuickPanelSearchAliases(t, 'settings.prompts.title'), icon: , action: ({ parentPanel, queryAnchor, triggerInfo }) => { openQuickPanel(parentPanel, queryAnchor, triggerInfo) diff --git a/src/renderer/components/composer/tools/components/ThinkingButton.tsx b/src/renderer/components/composer/tools/components/ThinkingButton.tsx index d954c196ad3..859a257bb6d 100644 --- a/src/renderer/components/composer/tools/components/ThinkingButton.tsx +++ b/src/renderer/components/composer/tools/components/ThinkingButton.tsx @@ -1,3 +1,4 @@ +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import type { ToolLauncherApi } from '@renderer/components/composer/tools/types' import { MdiLightbulbAutoOutline, @@ -183,6 +184,10 @@ const useThinkingToolController = ({ order: 60, label: t('assistants.settings.reasoning_effort.label'), description: '', + searchAliases: getQuickPanelSearchAliases(t, 'assistants.settings.reasoning_effort.label', [ + 'think', + 'reasoning effort' + ]), disabledReason, icon: ThinkingIcon({ option: currentReasoningEffort }), active: isReasoningConfigurable && isThinkingEnabled, diff --git a/src/renderer/components/composer/tools/components/WebSearchButton.tsx b/src/renderer/components/composer/tools/components/WebSearchButton.tsx index 8bfb7a71c34..14bcf6428dd 100644 --- a/src/renderer/components/composer/tools/components/WebSearchButton.tsx +++ b/src/renderer/components/composer/tools/components/WebSearchButton.tsx @@ -1,5 +1,6 @@ import { Tooltip } from '@cherrystudio/ui' import ActionIconButton from '@renderer/components/ActionIconButton' +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import type { ToolLauncherApi } from '@renderer/components/composer/tools/types' import { useAssistant } from '@renderer/hooks/useAssistant' import { useProvider } from '@renderer/hooks/useProvider' @@ -145,6 +146,7 @@ const useWebSearchToolController = ({ assistantId, launcher }: Props) => { order: 30, label: t('chat.input.web_search.label'), description: '', + searchAliases: getQuickPanelSearchAliases(t, 'chat.input.web_search.label', ['search']), icon, active: enableWebSearch, disabled: isDisabled, diff --git a/src/renderer/components/composer/tools/components/__tests__/AttachmentButton.test.tsx b/src/renderer/components/composer/tools/components/__tests__/AttachmentButton.test.tsx index 61ed94c24a2..3471d27bf23 100644 --- a/src/renderer/components/composer/tools/components/__tests__/AttachmentButton.test.tsx +++ b/src/renderer/components/composer/tools/components/__tests__/AttachmentButton.test.tsx @@ -10,14 +10,15 @@ vi.mock('@renderer/utils/file', () => ({ filterSupportedFiles: vi.fn(async (files) => files) })) -const t = (key: string) => { - const translations: Record = { +const t = (key: string, options?: { lng?: string; defaultValue?: string }) => { + const englishTranslations: Record = { 'chat.input.upload.attachment': 'Upload attachment', 'chat.input.upload.document_only': 'Documents only', 'chat.input.upload.image_not_supported': 'This model does not support image uploads. Documents only.' } - return translations[key] ?? key + if (options?.lng === 'en-US') return englishTranslations[key] ?? options.defaultValue ?? key + return key } vi.mock('react-i18next', () => ({ @@ -83,9 +84,10 @@ describe('AttachmentToolRuntime', () => { expect(attachmentLauncher).toMatchObject({ id: 'attachment', sources: ['popover'], - label: 'Upload attachment', - suffix: 'Documents only', - tooltip: 'This model does not support image uploads. Documents only.' + label: 'chat.input.upload.attachment', + searchAliases: expect.arrayContaining(['Upload attachment']), + suffix: 'chat.input.upload.document_only', + tooltip: 'chat.input.upload.image_not_supported' }) }) diff --git a/src/renderer/components/composer/tools/definitions/generateImageTool.tsx b/src/renderer/components/composer/tools/definitions/generateImageTool.tsx index fb4926128ef..3ae2af4930a 100644 --- a/src/renderer/components/composer/tools/definitions/generateImageTool.tsx +++ b/src/renderer/components/composer/tools/definitions/generateImageTool.tsx @@ -1,3 +1,4 @@ +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import { defineTool, TopicType } from '@renderer/components/composer/tools/types' import { isGenerateImageModel } from '@renderer/utils/model' import { Image } from 'lucide-react' @@ -22,6 +23,7 @@ const useGenerateImageToolController = (context) => { order: 20, label: t('chat.input.generate_image'), description: '', + searchAliases: getQuickPanelSearchAliases(t, 'chat.input.generate_image', ['generate image']), disabledReason: t('chat.input.generate_image_not_supported'), icon: , active: enabled && isSupported, diff --git a/src/renderer/components/composer/tools/definitions/permissionModeTool.tsx b/src/renderer/components/composer/tools/definitions/permissionModeTool.tsx index 2e35b715080..07943f23f26 100644 --- a/src/renderer/components/composer/tools/definitions/permissionModeTool.tsx +++ b/src/renderer/components/composer/tools/definitions/permissionModeTool.tsx @@ -1,3 +1,4 @@ +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import { defineTool, type ToolRenderContext, TopicType } from '@renderer/components/composer/tools/types' import { useAgent } from '@renderer/hooks/agent/useAgent' import { useUpdateAgent } from '@renderer/hooks/agent/useAgent' @@ -79,6 +80,7 @@ const usePermissionModeToolController = (context: PermissionModeContext) => { order: 80, label: t('agent.settings.permissionMode.title', 'Permission Mode'), description: '', + searchAliases: getQuickPanelSearchAliases(t, 'agent.settings.permissionMode.title'), icon: getPermissionModeIcon(currentMode), suffix: tooltipTitle, submenu: modeSubmenu diff --git a/src/renderer/components/composer/tools/definitions/slashCommandsTool.tsx b/src/renderer/components/composer/tools/definitions/slashCommandsTool.tsx index 12dbb73ce84..1bd4db1e8a8 100644 --- a/src/renderer/components/composer/tools/definitions/slashCommandsTool.tsx +++ b/src/renderer/components/composer/tools/definitions/slashCommandsTool.tsx @@ -1,3 +1,4 @@ +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import type { ComposerToolLauncher } from '@renderer/components/composer/toolLauncher' import { defineTool, TopicType } from '@renderer/components/composer/tools/types' import { type QuickPanelInputAdapter } from '@renderer/components/QuickPanel' @@ -81,6 +82,7 @@ const slashCommandsTool = defineTool({ order: 20 + (index + 1) / 100, label: cmd.command, description: descriptionKey ? t(descriptionKey, cmd.description || '') : cmd.description || '', + searchAliases: descriptionKey ? getQuickPanelSearchAliases(t, descriptionKey) : undefined, icon: , action: ({ inputAdapter }) => { insertSlashCommand(cmd.command, actions.onTextChange, inputAdapter) diff --git a/src/renderer/components/composer/variants/AgentComposer.tsx b/src/renderer/components/composer/variants/AgentComposer.tsx index fae5e2b3eeb..2f87b5bf5a4 100644 --- a/src/renderer/components/composer/variants/AgentComposer.tsx +++ b/src/renderer/components/composer/variants/AgentComposer.tsx @@ -13,6 +13,7 @@ import { useComposerToolLauncherVersion, useComposerToolState } from '@renderer/components/composer/ComposerToolRuntime' +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import { getComposerToolConfig } from '@renderer/components/composer/tools/registry' import type { ToolContext } from '@renderer/components/composer/tools/types' import { ModelSelector } from '@renderer/components/ModelSelector' @@ -844,6 +845,7 @@ const AgentComposerInner = ({ label, icon: , filterText: label, + searchAliases: getQuickPanelSearchAliases(t, 'agent.session.new'), action: () => { handleCreateEmptySession() } @@ -859,6 +861,7 @@ const AgentComposerInner = ({ label, icon: , filterText: label, + searchAliases: getQuickPanelSearchAliases(t, 'agent.session.new'), action: () => { void onNewSessionDraft() } diff --git a/src/renderer/components/composer/variants/ChatComposer.tsx b/src/renderer/components/composer/variants/ChatComposer.tsx index 9b10aefb25e..d46832481e6 100644 --- a/src/renderer/components/composer/variants/ChatComposer.tsx +++ b/src/renderer/components/composer/variants/ChatComposer.tsx @@ -13,6 +13,7 @@ import { useComposerToolLauncherVersion, useComposerToolState } from '@renderer/components/composer/ComposerToolRuntime' +import { getQuickPanelSearchAliases } from '@renderer/components/composer/quickPanel' import { getComposerToolConfig } from '@renderer/components/composer/tools/registry' import EmojiIcon from '@renderer/components/EmojiIcon' import { ModelSelector } from '@renderer/components/ModelSelector' @@ -725,6 +726,7 @@ const ChatComposerInner = ({ icon: , disabled, filterText: label, + searchAliases: getQuickPanelSearchAliases(t, 'chat.conversation.new', ['new chat']), action: () => { handleCreateEmptyTopic() } @@ -740,6 +742,7 @@ const ChatComposerInner = ({ label, icon: , filterText: label, + searchAliases: getQuickPanelSearchAliases(t, 'chat.conversation.new', ['new chat']), action: () => { addNewTopic() }