From 614c23da328b1c8d6ca98c5c4dc78facf53c9943 Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 24 Jun 2026 17:56:41 +0800 Subject: [PATCH] chore: remove cli tool --- .../__tests__/agent-prompt-editor.spec.tsx | 8 +-- .../orchestrate/prompt-editor/index.tsx | 6 +- .../orchestrate/prompt-editor/slash.tsx | 45 ++++++++------ .../tools/__tests__/index.spec.tsx | 31 ++++------ .../components/orchestrate/tools/index.tsx | 58 ++++++++++++------- .../components/preview/chat-runtime.tsx | 3 +- .../agent-detail/configure/feature-flags.ts | 1 + 7 files changed, 86 insertions(+), 66 deletions(-) create mode 100644 web/features/agent-v2/agent-detail/configure/feature-flags.ts diff --git a/web/features/agent-v2/agent-detail/configure/components/__tests__/agent-prompt-editor.spec.tsx b/web/features/agent-v2/agent-detail/configure/components/__tests__/agent-prompt-editor.spec.tsx index bc10dec2ac7..7de47e23451 100644 --- a/web/features/agent-v2/agent-detail/configure/components/__tests__/agent-prompt-editor.spec.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/__tests__/agent-prompt-editor.spec.tsx @@ -249,7 +249,7 @@ describe('AgentPromptEditor', () => { , ) - expect(container.querySelector('.i-ri-terminal-box-line')).toBeInTheDocument() + expect(container.querySelector('.i-ri-terminal-box-line')).not.toBeInTheDocument() }) }) @@ -295,7 +295,7 @@ describe('AgentPromptEditor', () => { expect(screen.queryByRole('button', { name: /agentDetail\.configure\.prompt\.mention\.label/i })).not.toBeInTheDocument() }) - it('should insert references after prompt add actions create skills, files, CLI tools, or knowledge retrievals', () => { + it('should insert references after prompt add actions create skills, files, or knowledge retrievals', () => { const onSelect = vi.fn() const categories = [ { key: 'skills' as const, label: 'Skills', icon: 'i-ri-box-3-line' }, @@ -373,8 +373,8 @@ describe('AgentPromptEditor', () => { onSelect={onSelect} />, ) - fireEvent.click(screen.getByRole('button', { name: /agentDetail\.configure\.tools\.cliDialog\.title/i })) - expect(onSelect).toHaveBeenCalledWith('[§cli_tool:cli-1:Lark CLI§]') + expect(screen.queryByRole('button', { name: /agentDetail\.configure\.tools\.cliDialog\.title/i })).not.toBeInTheDocument() + expect(screen.queryByRole('button', { name: /agentDetail\.configure\.tools\.toolTabs\.cli/i })).not.toBeInTheDocument() }) it('should append available provider tool references and add missing tools to the configuration', () => { diff --git a/web/features/agent-v2/agent-detail/configure/components/orchestrate/prompt-editor/index.tsx b/web/features/agent-v2/agent-detail/configure/components/orchestrate/prompt-editor/index.tsx index 8ca5b8f5efb..2c4e87d3e45 100644 --- a/web/features/agent-v2/agent-detail/configure/components/orchestrate/prompt-editor/index.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/orchestrate/prompt-editor/index.tsx @@ -19,6 +19,7 @@ import { BlockEnum } from '@/app/components/workflow/types' import { agentComposerKnowledgeRetrievalsAtom } from '@/features/agent-v2/agent-composer/store-modules/knowledge' import { agentComposerPromptAtom } from '@/features/agent-v2/agent-composer/store-modules/prompt' import { agentComposerToolsAtom } from '@/features/agent-v2/agent-composer/store-modules/tools' +import { ENABLE_AGENT_CLI_TOOLS } from '@/features/agent-v2/agent-detail/configure/feature-flags' import useTheme from '@/hooks/use-theme' import { Theme } from '@/types/app' import { useAgentOrchestrateAddActions } from '../add-actions-context' @@ -261,6 +262,9 @@ export function AgentPromptEditor() { } const renderRosterReferenceIcon = useCallback((token: RosterReferenceToken) => { + if (!ENABLE_AGENT_CLI_TOOLS && token.kind === 'cli_tool') + return null + if (token.kind !== 'tool' && token.kind !== 'tool-all' && token.kind !== 'cli_tool') return null @@ -407,7 +411,7 @@ export function AgentPromptEditor() { files={files} tools={tools} onToolsChange={setTools} - onAddCliTool={addActions.cli} + onAddCliTool={ENABLE_AGENT_CLI_TOOLS ? addActions.cli : undefined} onAddFile={addActions.files} onAddKnowledge={addActions.knowledge} onAddSkill={addActions.skills} diff --git a/web/features/agent-v2/agent-detail/configure/components/orchestrate/prompt-editor/slash.tsx b/web/features/agent-v2/agent-detail/configure/components/orchestrate/prompt-editor/slash.tsx index 9aee10696ef..fe611d1bcda 100644 --- a/web/features/agent-v2/agent-detail/configure/components/orchestrate/prompt-editor/slash.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/orchestrate/prompt-editor/slash.tsx @@ -16,6 +16,7 @@ import { PluginCategoryEnum } from '@/app/components/plugins/types' import { CollectionType } from '@/app/components/tools/types' import { ToolTypeEnum as ToolTabEnum } from '@/app/components/workflow/block-selector/types' import { useGetLanguage } from '@/context/i18n' +import { ENABLE_AGENT_CLI_TOOLS } from '@/features/agent-v2/agent-detail/configure/feature-flags' import { useAllBuiltInTools, useAllCustomTools, @@ -170,14 +171,16 @@ export function AgentPromptSlashMenu({ {view === 'tools' ? ( { - onAddCliTool?.({ - onAdded: (item) => { - if (isCliToolItem(item)) - onSelect(createReferenceToken('cli_tool', item.id, item.name)) - }, - }) - }} + onAddCliTool={ENABLE_AGENT_CLI_TOOLS + ? () => { + onAddCliTool?.({ + onAdded: (item) => { + if (isCliToolItem(item)) + onSelect(createReferenceToken('cli_tool', item.id, item.name)) + }, + }) + } + : undefined} /> ) : ( @@ -281,7 +284,9 @@ function AgentPromptToolRows({ const { data: customTools = [] } = useAllCustomTools() const { data: workflowTools = [] } = useAllWorkflowTools() const { data: mcpTools = [] } = useAllMCPTools() - const configuredCliTools = configuredTools.filter(tool => tool.kind === 'cli') + const configuredCliTools = ENABLE_AGENT_CLI_TOOLS + ? configuredTools.filter(tool => tool.kind === 'cli') + : [] const availableProviders = useMemo(() => { if (activeTab === 'all') return [...builtInTools, ...workflowTools, ...customTools, ...mcpTools] @@ -304,7 +309,9 @@ function AgentPromptToolRows({ { key: ToolTabEnum.Workflow, label: t('agentDetail.configure.tools.toolTabs.workflow') }, { key: ToolTabEnum.Custom, label: t('agentDetail.configure.tools.toolTabs.custom') }, { key: ToolTabEnum.MCP, label: t('agentDetail.configure.tools.toolTabs.mcp') }, - { key: 'cli' as const, label: t('agentDetail.configure.tools.toolTabs.cli') }, + ...(ENABLE_AGENT_CLI_TOOLS + ? [{ key: 'cli' as const, label: t('agentDetail.configure.tools.toolTabs.cli') }] + : []), ] const selectTools = (tools: AgentProviderToolDefaultValue[]) => { @@ -565,14 +572,16 @@ function AgentPromptToolFooter({ {t('findMoreInMarketplace', { ns: 'plugin' })} - + {onAddCliTool && ( + + )} ) } diff --git a/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/__tests__/index.spec.tsx b/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/__tests__/index.spec.tsx index 801033033cc..4b59db51a42 100644 --- a/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/__tests__/index.spec.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/__tests__/index.spec.tsx @@ -291,7 +291,7 @@ describe('AgentTools', () => { expect(screen.queryByText('DuckDuckGo')).not.toBeInTheDocument() expect(screen.queryByText('DuckDuckGo Search')).not.toBeInTheDocument() - expect(screen.getByText('Lark CLI')).toBeInTheDocument() + expect(screen.queryByText('Lark CLI')).not.toBeInTheDocument() }) it('should keep the add trigger mounted while the tool picker is open', async () => { @@ -301,6 +301,9 @@ describe('AgentTools', () => { await user.click(screen.getByRole('button', { name: 'agentV2.agentDetail.configure.tools.add', })) + expect(screen.queryByRole('button', { + name: /agentV2\.agentDetail\.configure\.tools\.addMenu\.cliTool\.label/, + })).not.toBeInTheDocument() await user.click(screen.getByRole('button', { name: /agentV2\.agentDetail\.configure\.tools\.addMenu\.tool\.label/, })) @@ -340,30 +343,16 @@ describe('AgentTools', () => { })).not.toBeInTheDocument() }) - it('should keep CLI tool row actions out of layout until hover or focus', () => { + it('should hide CLI tool rows while CLI tools are disabled', () => { renderAgentTools() - const editButton = screen.getByRole('button', { + expect(screen.queryByText('Lark CLI')).not.toBeInTheDocument() + expect(screen.queryByRole('button', { name: 'agentV2.agentDetail.configure.tools.editAction:{"name":"Lark CLI"}', - }) - const removeButton = screen.getByRole('button', { + })).not.toBeInTheDocument() + expect(screen.queryByRole('button', { name: 'agentV2.agentDetail.configure.tools.removeAction:{"name":"Lark CLI"}', - }) - const actionGroup = editButton.parentElement - - expect(actionGroup).toHaveClass('hidden') - expect(actionGroup).toHaveClass( - 'group-focus-within:flex', - 'group-hover:flex', - ) - expect(removeButton).toHaveClass( - 'hover:bg-state-destructive-hover', - 'hover:text-text-destructive', - ) - expect(screen.getByText('agentV2.agentDetail.configure.tools.cliTool')).toHaveClass( - 'group-focus-within:hidden', - 'group-hover:hidden', - ) + })).not.toBeInTheDocument() }) }) diff --git a/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/index.tsx b/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/index.tsx index 7c8a12e8ca4..b9080a0cdc6 100644 --- a/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/index.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/index.tsx @@ -12,6 +12,7 @@ import { useTranslation } from 'react-i18next' import { ToolPickerContent } from '@/app/components/workflow/block-selector/tool-picker' import { useGetLanguage } from '@/context/i18n' import { useSetProviderToolCredential } from '@/features/agent-v2/agent-composer/store-modules/tools' +import { ENABLE_AGENT_CLI_TOOLS } from '@/features/agent-v2/agent-detail/configure/feature-flags' import { useAllBuiltInTools, useAllCustomTools, @@ -300,13 +301,15 @@ function AddToolMenu({ description={t('agentDetail.configure.tools.addMenu.tool.description')} onClick={openToolPicker} /> - + {ENABLE_AGENT_CLI_TOOLS && ( + + )} ) : ( @@ -349,14 +352,22 @@ export function AgentTools() { handleCliDialogOpenChange, closeProviderSettingsDialog, } = useAgentToolsOperations() - const displayTools = useDisplayTools(tools, providerById) + const visibleTools = useMemo( + () => ENABLE_AGENT_CLI_TOOLS ? tools : tools.filter(tool => tool.kind !== 'cli'), + [tools], + ) + const displayTools = useDisplayTools(visibleTools, providerById) + const displayToolById = useMemo( + () => new Map(displayTools.map(tool => [tool.id, tool])), + [displayTools], + ) useEffect(() => { if (readOnly) return let shouldSyncCredentials = false - const nextTools = tools.map((tool, index) => { - const displayTool = displayTools[index] + const nextTools = tools.map((tool) => { + const displayTool = displayToolById.get(tool.id) if (tool.kind !== 'provider' || displayTool?.kind !== 'provider') return tool @@ -382,7 +393,7 @@ export function AgentTools() { if (shouldSyncCredentials) setTools(nextTools) - }, [displayTools, readOnly, setTools, tools]) + }, [displayToolById, readOnly, setTools, tools]) const promptAddCallbackRef = useRef(undefined) const openCliToolDialogFromPrompt = useCallback((options?: AgentOrchestrateAddActionOptions) => { promptAddCallbackRef.current = options?.onAdded @@ -400,7 +411,10 @@ export function AgentTools() { promptAddCallbackRef.current = undefined handleCliDialogOpenChange(open) }, [handleCliDialogOpenChange]) - useRegisterAgentOrchestrateAddAction('cli', openCliToolDialogFromPrompt) + useRegisterAgentOrchestrateAddAction( + 'cli', + ENABLE_AGENT_CLI_TOOLS ? openCliToolDialogFromPrompt : () => {}, + ) const toolsTip = t('agentDetail.configure.tools.tip') const toolsListId = 'agent-configure-tools-list' const settingTargetCollection = settingTarget @@ -455,15 +469,17 @@ export function AgentTools() { collection={settingTargetCollection} onClose={closeProviderSettingsDialog} /> - + {ENABLE_AGENT_CLI_TOOLS && ( + + )} ) } diff --git a/web/features/agent-v2/agent-detail/configure/components/preview/chat-runtime.tsx b/web/features/agent-v2/agent-detail/configure/components/preview/chat-runtime.tsx index 0908fb0b7d0..b3f01240766 100644 --- a/web/features/agent-v2/agent-detail/configure/components/preview/chat-runtime.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/preview/chat-runtime.tsx @@ -36,6 +36,7 @@ import { DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/ import { useAppContext } from '@/context/app-context' import { agentComposerModelAtom } from '@/features/agent-v2/agent-composer/store-modules/model' import { agentComposerPromptAtom } from '@/features/agent-v2/agent-composer/store-modules/prompt' +import { ENABLE_AGENT_CLI_TOOLS } from '@/features/agent-v2/agent-detail/configure/feature-flags' import { PromptMode } from '@/models/debug' import dynamic from '@/next/dynamic' import { consoleClient } from '@/service/client' @@ -326,7 +327,7 @@ const buildChatConfig = ({ const modelSettings = getModelSettings(agentSoulConfig) const appFeatures = agentSoulConfig?.app_features ?? {} const difyTools = agentSoulConfig?.tools?.dify_tools ?? [] - const cliTools = agentSoulConfig?.tools?.cli_tools ?? [] + const cliTools = ENABLE_AGENT_CLI_TOOLS ? (agentSoulConfig?.tools?.cli_tools ?? []) : [] return { pre_prompt: prompt || agentSoulConfig?.prompt?.system_prompt || '', diff --git a/web/features/agent-v2/agent-detail/configure/feature-flags.ts b/web/features/agent-v2/agent-detail/configure/feature-flags.ts new file mode 100644 index 00000000000..0769fc6f597 --- /dev/null +++ b/web/features/agent-v2/agent-detail/configure/feature-flags.ts @@ -0,0 +1 @@ +export const ENABLE_AGENT_CLI_TOOLS = false