mirror of
https://github.com/langgenius/dify.git
synced 2026-08-01 09:50:50 +08:00
feat: prioritize configured tools in the agent prompt picker (#39850)
This commit is contained in:
parent
f9966c2ee4
commit
37bf80dcf6
@ -93,6 +93,33 @@ const mockBuiltInTools = vi.hoisted(() => [
|
||||
},
|
||||
])
|
||||
|
||||
const wikipediaProvider = {
|
||||
id: 'wikipedia',
|
||||
name: 'Wikipedia',
|
||||
author: 'Dify',
|
||||
description: { en_US: 'Wikipedia tools' },
|
||||
icon: 'wikipedia.svg',
|
||||
icon_dark: 'wikipedia-dark.svg',
|
||||
label: { en_US: 'Wikipedia' },
|
||||
type: 'builtin',
|
||||
team_credentials: {},
|
||||
is_team_authorization: true,
|
||||
allow_delete: false,
|
||||
labels: [],
|
||||
meta: {},
|
||||
tools: [
|
||||
{
|
||||
name: 'wikipedia_search',
|
||||
author: 'Dify',
|
||||
label: { en_US: 'Wikipedia Search' },
|
||||
description: { en_US: 'Search Wikipedia.' },
|
||||
parameters: [],
|
||||
labels: [],
|
||||
output_schema: {},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
vi.mock('@/app/components/base/prompt-editor', () => ({
|
||||
__esModule: true,
|
||||
default: (props: PromptEditorProps) => {
|
||||
@ -929,6 +956,60 @@ describe('AgentPromptEditor', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('should show configured providers and actions before other available tools', () => {
|
||||
mockBuiltInTools.unshift(wikipediaProvider)
|
||||
const configuredDuckDuckGoTranslateTool: AgentTool = {
|
||||
...duckDuckGoProviderTool,
|
||||
actions: [
|
||||
{
|
||||
id: 'duckduckgo-translate',
|
||||
name: 'DuckDuckGo Translate',
|
||||
toolName: 'ddg_translate',
|
||||
description: 'Translate search results.',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const view = render(
|
||||
<AgentPromptSlashMenu
|
||||
view="tools"
|
||||
categories={[{ key: 'tools', label: 'Tools', icon: 'i-ri-box-3-line' }]}
|
||||
skills={[]}
|
||||
files={[]}
|
||||
configuredTools={[configuredDuckDuckGoTranslateTool]}
|
||||
onAddProviderTools={vi.fn()}
|
||||
knowledgeRetrievals={[]}
|
||||
onBack={vi.fn()}
|
||||
onOpenCategory={vi.fn()}
|
||||
onInsertToken={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
try {
|
||||
const providerButtons = screen
|
||||
.getAllByRole('button')
|
||||
.filter(
|
||||
(button) =>
|
||||
button.textContent?.includes('DuckDuckGo') ||
|
||||
button.textContent?.includes('Wikipedia'),
|
||||
)
|
||||
|
||||
expect(providerButtons).toHaveLength(2)
|
||||
expect(providerButtons[0]).toHaveTextContent('DuckDuckGo')
|
||||
expect(providerButtons[1]).toHaveTextContent('Wikipedia')
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'DuckDuckGo' }))
|
||||
const actionButtons = screen.getAllByRole('button', {
|
||||
name: /DuckDuckGo (Search|Translate)/,
|
||||
})
|
||||
expect(actionButtons[0]).toHaveTextContent('DuckDuckGo Translate')
|
||||
expect(actionButtons[1]).toHaveTextContent('DuckDuckGo Search')
|
||||
} finally {
|
||||
view.unmount()
|
||||
mockBuiltInTools.shift()
|
||||
}
|
||||
})
|
||||
|
||||
it('should close the slash menu when the trailing slash is deleted', async () => {
|
||||
const { setPromptValue } = renderAgentPromptEditor('Review /')
|
||||
|
||||
|
||||
@ -329,20 +329,23 @@ function AgentPromptToolRows({
|
||||
const configuredCliTools = ENABLE_AGENT_CLI_TOOLS
|
||||
? configuredTools.filter((tool) => tool.kind === 'cli')
|
||||
: []
|
||||
const availableProviders = useMemo(() => {
|
||||
if (activeTab === 'all') return [...builtInTools, ...workflowTools, ...customTools, ...mcpTools]
|
||||
if (activeTab === ToolType.BuiltIn) return builtInTools
|
||||
if (activeTab === ToolType.Workflow) return workflowTools
|
||||
if (activeTab === ToolType.Custom) return customTools
|
||||
if (activeTab === ToolType.MCP) return mcpTools
|
||||
|
||||
return []
|
||||
}, [activeTab, builtInTools, customTools, mcpTools, workflowTools])
|
||||
|
||||
const selectedTools = useMemo(
|
||||
() => configuredTools.flatMap(toSelectedToolValue),
|
||||
[configuredTools],
|
||||
)
|
||||
const availableProviders = useMemo(() => {
|
||||
let providers: ToolWithProvider[] = []
|
||||
if (activeTab === 'all')
|
||||
providers = [...builtInTools, ...workflowTools, ...customTools, ...mcpTools]
|
||||
if (activeTab === ToolType.BuiltIn) providers = builtInTools
|
||||
if (activeTab === ToolType.Workflow) providers = workflowTools
|
||||
if (activeTab === ToolType.Custom) providers = customTools
|
||||
if (activeTab === ToolType.MCP) providers = mcpTools
|
||||
|
||||
return prioritizeItems(providers, (provider) =>
|
||||
provider.tools.some((tool) => isToolSelected(selectedTools, provider, tool)),
|
||||
)
|
||||
}, [activeTab, builtInTools, customTools, mcpTools, selectedTools, workflowTools])
|
||||
const tabs = [
|
||||
{ key: 'all' as const, label: t(($) => $['agentDetail.configure.tools.toolTabs.all']) },
|
||||
{
|
||||
@ -435,7 +438,9 @@ function AgentPromptToolRows({
|
||||
onToggle={() => toggleProvider(provider.id)}
|
||||
/>
|
||||
{expandedProviderIds.has(provider.id) &&
|
||||
provider.tools.map((tool) => (
|
||||
prioritizeItems(provider.tools, (tool) =>
|
||||
isToolSelected(selectedTools, provider, tool),
|
||||
).map((tool) => (
|
||||
<AgentPromptProviderToolActionRow
|
||||
key={tool.name}
|
||||
tool={tool}
|
||||
@ -452,6 +457,18 @@ function AgentPromptToolRows({
|
||||
|
||||
type ToolPromptTab = ToolType | 'cli'
|
||||
|
||||
function prioritizeItems<T>(items: T[], isPriority: (item: T) => boolean) {
|
||||
const priorityItems: T[] = []
|
||||
const remainingItems: T[] = []
|
||||
|
||||
items.forEach((item) => {
|
||||
if (isPriority(item)) priorityItems.push(item)
|
||||
else remainingItems.push(item)
|
||||
})
|
||||
|
||||
return [...priorityItems, ...remainingItems]
|
||||
}
|
||||
|
||||
function getLocalizedText(text: Record<string, string> | undefined | null, language: string) {
|
||||
if (!text) return ''
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user