chore: remove cli tool

This commit is contained in:
Joel 2026-06-24 17:56:41 +08:00
parent 6e1bfdf4ac
commit 614c23da32
7 changed files with 86 additions and 66 deletions

View File

@ -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', () => {

View File

@ -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}

View File

@ -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'
? (
<AgentPromptToolFooter
onAddCliTool={() => {
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({
<span aria-hidden className="i-ri-store-2-line size-4 shrink-0 text-text-secondary" />
<span className="system-sm-regular text-text-secondary">{t('findMoreInMarketplace', { ns: 'plugin' })}</span>
</a>
<button
type="button"
className="flex h-7 w-full items-center gap-1.5 rounded-md px-2 text-left hover:bg-state-base-hover focus-visible:bg-state-base-hover focus-visible:outline-hidden"
onClick={onAddCliTool}
>
<span aria-hidden className="i-ri-add-line size-4 shrink-0 text-text-secondary" />
<span className="system-sm-regular text-text-secondary">{t('agentDetail.configure.tools.cliDialog.title', { ns: 'agentV2' })}</span>
</button>
{onAddCliTool && (
<button
type="button"
className="flex h-7 w-full items-center gap-1.5 rounded-md px-2 text-left hover:bg-state-base-hover focus-visible:bg-state-base-hover focus-visible:outline-hidden"
onClick={onAddCliTool}
>
<span aria-hidden className="i-ri-add-line size-4 shrink-0 text-text-secondary" />
<span className="system-sm-regular text-text-secondary">{t('agentDetail.configure.tools.cliDialog.title', { ns: 'agentV2' })}</span>
</button>
)}
</div>
)
}

View File

@ -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()
})
})

View File

@ -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}
/>
<AddToolMenuItem
iconClassName="i-ri-terminal-box-line"
label={t('agentDetail.configure.tools.addMenu.cliTool.label')}
badge={t('agentDetail.configure.tools.addMenu.cliTool.badge')}
description={t('agentDetail.configure.tools.addMenu.cliTool.description')}
onClick={openCliToolDialog}
/>
{ENABLE_AGENT_CLI_TOOLS && (
<AddToolMenuItem
iconClassName="i-ri-terminal-box-line"
label={t('agentDetail.configure.tools.addMenu.cliTool.label')}
badge={t('agentDetail.configure.tools.addMenu.cliTool.badge')}
description={t('agentDetail.configure.tools.addMenu.cliTool.description')}
onClick={openCliToolDialog}
/>
)}
</>
)
: (
@ -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<AgentOrchestrateAddActionOptions['onAdded']>(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}
/>
<CliToolDialog
key={`${editingCliTool?.id ?? 'add'}:${isCliToolDialogOpen ? 'open' : 'closed'}`}
mode={editingCliTool ? 'edit' : 'add'}
tool={editingCliTool}
onDeleteCliTool={deleteCliTool}
onSaveCliTool={handleCliDialogSaveWithPromptInsert}
open={isCliToolDialogOpen}
onOpenChange={handleCliDialogOpenChangeWithPromptInsert}
/>
{ENABLE_AGENT_CLI_TOOLS && (
<CliToolDialog
key={`${editingCliTool?.id ?? 'add'}:${isCliToolDialogOpen ? 'open' : 'closed'}`}
mode={editingCliTool ? 'edit' : 'add'}
tool={editingCliTool}
onDeleteCliTool={deleteCliTool}
onSaveCliTool={handleCliDialogSaveWithPromptInsert}
open={isCliToolDialogOpen}
onOpenChange={handleCliDialogOpenChangeWithPromptInsert}
/>
)}
</>
)
}

View File

@ -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 || '',

View File

@ -0,0 +1 @@
export const ENABLE_AGENT_CLI_TOOLS = false