mirror of
https://github.com/langgenius/dify.git
synced 2026-10-16 07:20:34 +08:00
refactor(web): migrate tool services and hooks to the console contract
- service/tools.ts and service/use-tools.ts call consoleClient; tool UI DTOs are narrowed at the boundary - remove fetchModelToolList and the isModel prop: the backend has no model tool provider type and /tool-provider/model/tools does not exist - keep the legacy built-in credential flow handwritten: it no longer matches the backend (schema moved, credentials became a list, update/delete need credential_id) - MCP provider payloads require server_identifier and send icon_background without null; MCP server payloads require parameters; workflow tool requests carry label - drop the unused _tools_util helper Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
42a3ab4790
commit
0f7e4fd5a8
@@ -4129,11 +4129,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/service/tools.ts": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/service/use-common.ts": {
|
||||
"@tanstack/query/prefer-query-options": {
|
||||
"count": 1
|
||||
@@ -4200,9 +4195,6 @@
|
||||
"web/service/use-tools.ts": {
|
||||
"@tanstack/query/prefer-query-options": {
|
||||
"count": 15
|
||||
},
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/service/use-triggers.ts": {
|
||||
@@ -4299,4 +4291,4 @@
|
||||
"count": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-7
@@ -5,12 +5,10 @@ import * as React from 'react'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import SettingBuiltInTool from '../setting-built-in-tool'
|
||||
|
||||
const fetchModelToolList = vi.fn()
|
||||
const fetchBuiltInToolList = vi.fn()
|
||||
const fetchCustomToolList = vi.fn()
|
||||
const fetchWorkflowToolList = vi.fn()
|
||||
vi.mock('@/service/tools', () => ({
|
||||
fetchModelToolList: (collectionName: string) => fetchModelToolList(collectionName),
|
||||
fetchBuiltInToolList: (collectionName: string) => fetchBuiltInToolList(collectionName),
|
||||
fetchCustomToolList: (collectionName: string) => fetchCustomToolList(collectionName),
|
||||
fetchWorkflowToolList: (appId: string) => fetchWorkflowToolList(appId),
|
||||
@@ -133,7 +131,6 @@ const renderComponent = (props?: Partial<React.ComponentProps<typeof SettingBuil
|
||||
<SettingBuiltInTool
|
||||
collection={baseCollection as any}
|
||||
toolName="search"
|
||||
isModel
|
||||
setting={{ settingParam: 'value' }}
|
||||
onHide={onHide}
|
||||
onSave={onSave}
|
||||
@@ -157,7 +154,7 @@ describe('SettingBuiltInTool', () => {
|
||||
})
|
||||
|
||||
it('should fetch tool list when collection has no tools', async () => {
|
||||
fetchModelToolList.mockResolvedValueOnce([createTool()])
|
||||
fetchBuiltInToolList.mockResolvedValueOnce([createTool()])
|
||||
renderComponent({
|
||||
collection: {
|
||||
...baseCollection,
|
||||
@@ -166,8 +163,8 @@ describe('SettingBuiltInTool', () => {
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchModelToolList).toHaveBeenCalledTimes(1)
|
||||
expect(fetchModelToolList).toHaveBeenCalledWith('vendor/provider-1')
|
||||
expect(fetchBuiltInToolList).toHaveBeenCalledTimes(1)
|
||||
expect(fetchBuiltInToolList).toHaveBeenCalledWith('vendor/provider-1')
|
||||
})
|
||||
expect(await screen.findByText('Search Tool')).toBeInTheDocument()
|
||||
})
|
||||
@@ -287,7 +284,6 @@ describe('SettingBuiltInTool', () => {
|
||||
id: 'workflow-1',
|
||||
} as any,
|
||||
isBuiltIn: false,
|
||||
isModel: false,
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
|
||||
@@ -402,7 +402,6 @@ const AgentTools: FC = () => {
|
||||
toolName={currentTool?.tool_name as string}
|
||||
setting={currentTool?.tool_parameters}
|
||||
collection={currentTool?.collection as ToolWithProvider}
|
||||
isModel={currentTool?.collection?.type === CollectionType.model}
|
||||
onSave={handleToolSettingChange}
|
||||
onHide={() => setIsShowSettingTool(false)}
|
||||
credentialId={currentTool?.credential_id}
|
||||
|
||||
+2
-10
@@ -30,18 +30,12 @@ import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import { toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
||||
import { getPluginLanguage } from '@/i18n/metadata'
|
||||
import {
|
||||
fetchBuiltInToolList,
|
||||
fetchCustomToolList,
|
||||
fetchModelToolList,
|
||||
fetchWorkflowToolList,
|
||||
} from '@/service/tools'
|
||||
import { fetchBuiltInToolList, fetchCustomToolList, fetchWorkflowToolList } from '@/service/tools'
|
||||
|
||||
type Props = Readonly<{
|
||||
showBackButton?: boolean
|
||||
collection: Collection | ToolWithProvider
|
||||
isBuiltIn?: boolean
|
||||
isModel?: boolean
|
||||
toolName: string
|
||||
setting?: Record<string, any>
|
||||
readonly?: boolean
|
||||
@@ -56,7 +50,6 @@ const SettingBuiltInTool: FC<Props> = ({
|
||||
showBackButton = false,
|
||||
collection,
|
||||
isBuiltIn = true,
|
||||
isModel = true,
|
||||
toolName,
|
||||
setting = {},
|
||||
readonly,
|
||||
@@ -90,8 +83,7 @@ const SettingBuiltInTool: FC<Props> = ({
|
||||
try {
|
||||
const list = await new Promise<Tool[]>((resolve) => {
|
||||
;(async function () {
|
||||
if (isModel) resolve(await fetchModelToolList(collection.name))
|
||||
else if (isBuiltIn) resolve(await fetchBuiltInToolList(collection.name))
|
||||
if (isBuiltIn) resolve(await fetchBuiltInToolList(collection.name))
|
||||
else if (collection.type === CollectionType.workflow)
|
||||
resolve(await fetchWorkflowToolList(collection.id))
|
||||
else resolve(await fetchCustomToolList(collection.name))
|
||||
|
||||
@@ -40,7 +40,6 @@ const ActionList = ({ detail }: Props) => {
|
||||
collection={provider}
|
||||
tool={tool}
|
||||
isBuiltIn={true}
|
||||
isModel={false}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -39,7 +39,7 @@ type MCPModalConfirmPayload = {
|
||||
server_url: string
|
||||
icon_type: AppIconType
|
||||
icon: string
|
||||
icon_background?: string | null
|
||||
icon_background?: string
|
||||
server_identifier: string
|
||||
headers?: Record<string, string>
|
||||
is_dynamic_registration?: boolean
|
||||
|
||||
@@ -81,7 +81,6 @@ vi.mock('@/context/modal-context', () => ({
|
||||
|
||||
const mockFetchBuiltInToolList = vi.fn().mockResolvedValue([])
|
||||
const mockFetchCustomToolList = vi.fn().mockResolvedValue([])
|
||||
const mockFetchModelToolList = vi.fn().mockResolvedValue([])
|
||||
const mockFetchCustomCollection = vi.fn().mockResolvedValue({
|
||||
credentials: { auth_type: 'none' },
|
||||
})
|
||||
@@ -100,7 +99,6 @@ const mockSaveWorkflowToolProvider = vi.fn().mockResolvedValue({})
|
||||
vi.mock('@/service/tools', () => ({
|
||||
fetchBuiltInToolList: (...args: unknown[]) => mockFetchBuiltInToolList(...args),
|
||||
fetchCustomToolList: (...args: unknown[]) => mockFetchCustomToolList(...args),
|
||||
fetchModelToolList: (...args: unknown[]) => mockFetchModelToolList(...args),
|
||||
fetchCustomCollection: (...args: unknown[]) => mockFetchCustomCollection(...args),
|
||||
fetchWorkflowToolDetail: (...args: unknown[]) => mockFetchWorkflowToolDetail(...args),
|
||||
updateBuiltInToolCredential: (...args: unknown[]) => mockUpdateBuiltInToolCredential(...args),
|
||||
@@ -278,7 +276,6 @@ describe('ProviderDetail', () => {
|
||||
},
|
||||
])
|
||||
mockFetchCustomToolList.mockResolvedValue([])
|
||||
mockFetchModelToolList.mockResolvedValue([])
|
||||
mockConsoleState.workspacePermissionKeys = [
|
||||
'tool.manage',
|
||||
'credential.use',
|
||||
@@ -584,17 +581,6 @@ describe('ProviderDetail', () => {
|
||||
|
||||
describe('Model Collection', () => {
|
||||
it('opens model modal when clicking auth button for model type', async () => {
|
||||
mockFetchModelToolList.mockResolvedValue([
|
||||
{
|
||||
name: 'model-tool-1',
|
||||
label: { en_US: 'MT1' },
|
||||
description: { en_US: '' },
|
||||
parameters: [],
|
||||
labels: [],
|
||||
author: '',
|
||||
output_schema: {},
|
||||
},
|
||||
])
|
||||
render(
|
||||
<ProviderDetail
|
||||
collection={createMockCollection({
|
||||
@@ -647,19 +633,6 @@ describe('ProviderDetail', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('calls fetchModelToolList for model type', async () => {
|
||||
render(
|
||||
<ProviderDetail
|
||||
collection={createMockCollection({ type: CollectionType.model })}
|
||||
onHide={mockOnHide}
|
||||
onRefreshData={mockOnRefreshData}
|
||||
/>,
|
||||
)
|
||||
await waitFor(() => {
|
||||
expect(mockFetchModelToolList).toHaveBeenCalledWith('test-collection')
|
||||
})
|
||||
})
|
||||
|
||||
it('calls fetchCustomToolList for custom type', async () => {
|
||||
render(
|
||||
<ProviderDetail
|
||||
|
||||
@@ -44,7 +44,7 @@ const tool = {
|
||||
describe('ToolItem', () => {
|
||||
it('opens and closes tool details from the keyboard', async () => {
|
||||
const user = userEvent.setup()
|
||||
render(<ToolItem collection={collection} tool={tool} isBuiltIn isModel={false} />)
|
||||
render(<ToolItem collection={collection} tool={tool} isBuiltIn />)
|
||||
|
||||
const toolButton = screen.getByRole('button', { name: 'Tool label' })
|
||||
toolButton.focus()
|
||||
@@ -62,7 +62,7 @@ describe('ToolItem', () => {
|
||||
|
||||
it('does not open tool details when disabled', async () => {
|
||||
const user = userEvent.setup()
|
||||
render(<ToolItem collection={collection} tool={tool} isBuiltIn isModel={false} disabled />)
|
||||
render(<ToolItem collection={collection} tool={tool} isBuiltIn disabled />)
|
||||
|
||||
const toolButton = screen.getByRole('button', { name: 'Tool label' })
|
||||
expect(toolButton).toBeDisabled()
|
||||
|
||||
@@ -54,7 +54,6 @@ import {
|
||||
fetchBuiltInToolList,
|
||||
fetchCustomCollection,
|
||||
fetchCustomToolList,
|
||||
fetchModelToolList,
|
||||
fetchWorkflowToolDetail,
|
||||
removeBuiltInToolCredential,
|
||||
removeCustomCollection,
|
||||
@@ -234,9 +233,6 @@ const ProviderDetail = ({ collection, onHide, onRefreshData }: Props) => {
|
||||
if (collection.type === CollectionType.builtIn) {
|
||||
const list = await fetchBuiltInToolList(collection.name)
|
||||
setToolList(list)
|
||||
} else if (collection.type === CollectionType.model) {
|
||||
const list = await fetchModelToolList(collection.name)
|
||||
setToolList(list)
|
||||
} else if (collection.type === CollectionType.workflow) {
|
||||
setToolList([])
|
||||
} else {
|
||||
@@ -470,7 +466,6 @@ const ProviderDetail = ({ collection, onHide, onRefreshData }: Props) => {
|
||||
collection={collection}
|
||||
tool={tool}
|
||||
isBuiltIn={isBuiltIn}
|
||||
isModel={isModel}
|
||||
/>
|
||||
))}
|
||||
{collection.type === CollectionType.workflow &&
|
||||
|
||||
@@ -12,10 +12,9 @@ type Props = Readonly<{
|
||||
collection: Collection
|
||||
tool: Tool
|
||||
isBuiltIn: boolean
|
||||
isModel: boolean
|
||||
}>
|
||||
|
||||
const ToolItem = ({ disabled, collection, tool, isBuiltIn, isModel }: Props) => {
|
||||
const ToolItem = ({ disabled, collection, tool, isBuiltIn }: Props) => {
|
||||
const locale = useLocale()
|
||||
const language = getPluginLanguage(locale)
|
||||
const [showDetail, setShowDetail] = useState(false)
|
||||
@@ -53,7 +52,6 @@ const ToolItem = ({ disabled, collection, tool, isBuiltIn, isModel }: Props) =>
|
||||
setShowDetail(false)
|
||||
}}
|
||||
isBuiltIn={isBuiltIn}
|
||||
isModel={isModel}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -247,6 +247,7 @@ export type WorkflowToolProviderOutputSchema = {
|
||||
|
||||
export type WorkflowToolProviderRequest = {
|
||||
name: string
|
||||
label: string
|
||||
icon: Emoji
|
||||
description: string
|
||||
parameters: WorkflowToolProviderParameter[]
|
||||
|
||||
@@ -387,7 +387,7 @@ describe('ToolPicker', () => {
|
||||
plugins: [],
|
||||
isLoading: false,
|
||||
} as ReturnType<typeof useFeaturedToolsRecommendations>)
|
||||
mockCreateCustomCollection.mockResolvedValue(undefined)
|
||||
mockCreateCustomCollection.mockResolvedValue({ result: 'success' })
|
||||
mockInstallPackageFromMarketPlace.mockResolvedValue({
|
||||
all_installed: true,
|
||||
task_id: 'task-1',
|
||||
|
||||
-1
@@ -94,7 +94,6 @@ export function ProviderToolSettingsDialog({
|
||||
toolName={currentTarget.action.toolName}
|
||||
setting={toolSettings[currentTarget.action.id]}
|
||||
collection={toolCollection}
|
||||
isModel={false}
|
||||
credentialId={currentTarget.tool.credentialId}
|
||||
onSave={handleSave}
|
||||
onHide={onClose}
|
||||
|
||||
@@ -10,15 +10,9 @@ const { mockGet, mockPost } = vi.hoisted(() => ({
|
||||
mockPost: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/base', () => ({
|
||||
del: vi.fn(),
|
||||
get: mockGet,
|
||||
post: mockPost,
|
||||
put: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/console', () => ({
|
||||
consoleClient: {
|
||||
workspaces: { current: { toolProviders: { get: mockGet } } },
|
||||
apps: {
|
||||
byAppId: {
|
||||
server: {
|
||||
@@ -85,9 +79,7 @@ describe('useAllToolProviders', () => {
|
||||
)
|
||||
|
||||
await waitFor(() => expect(mockGet).toHaveBeenCalledTimes(2))
|
||||
expect(mockGet).toHaveBeenCalledWith('/workspaces/current/tool-providers')
|
||||
expect(mockGet).toHaveBeenCalledWith('/workspaces/current/tool-providers', {
|
||||
params: { type: 'mcp' },
|
||||
})
|
||||
expect(mockGet).toHaveBeenCalledWith({ query: {} })
|
||||
expect(mockGet).toHaveBeenCalledWith({ query: { type: 'mcp' } })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import { buildProviderQuery } from './_tools_util'
|
||||
|
||||
describe('makeProviderQuery', () => {
|
||||
it('collectionName without special chars', () => {
|
||||
expect(buildProviderQuery('ABC')).toBe('provider=ABC')
|
||||
})
|
||||
it('should escape &', () => {
|
||||
expect(buildProviderQuery('ABC&DEF')).toBe('provider=ABC%26DEF')
|
||||
})
|
||||
it('should escape /', () => {
|
||||
expect(buildProviderQuery('ABC/DEF')).toBe('provider=ABC%2FDEF')
|
||||
})
|
||||
it('should escape ?', () => {
|
||||
expect(buildProviderQuery('ABC?DEF')).toBe('provider=ABC%3FDEF')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Tools Utilities', () => {
|
||||
describe('buildProviderQuery', () => {
|
||||
it('should build query string with provider parameter', () => {
|
||||
const result = buildProviderQuery('openai')
|
||||
expect(result).toBe('provider=openai')
|
||||
})
|
||||
|
||||
it('should handle provider names with special characters', () => {
|
||||
const result = buildProviderQuery('provider-name')
|
||||
expect(result).toBe('provider=provider-name')
|
||||
})
|
||||
|
||||
it('should handle empty string', () => {
|
||||
const result = buildProviderQuery('')
|
||||
expect(result).toBe('provider=')
|
||||
})
|
||||
|
||||
it('should URL encode special characters', () => {
|
||||
const result = buildProviderQuery('provider name')
|
||||
expect(result).toBe('provider=provider+name')
|
||||
})
|
||||
|
||||
it('should handle Unicode characters', () => {
|
||||
const result = buildProviderQuery('提供者')
|
||||
expect(result).toContain('provider=')
|
||||
expect(decodeURIComponent(result)).toBe('provider=提供者')
|
||||
})
|
||||
|
||||
it('should handle provider names with slashes', () => {
|
||||
const result = buildProviderQuery('langgenius/openai/gpt-4')
|
||||
expect(result).toContain('provider=')
|
||||
expect(decodeURIComponent(result)).toBe('provider=langgenius/openai/gpt-4')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,5 +0,0 @@
|
||||
export const buildProviderQuery = (collectionName: string): string => {
|
||||
const query = new URLSearchParams()
|
||||
query.set('provider', collectionName)
|
||||
return query.toString()
|
||||
}
|
||||
+63
-50
@@ -5,34 +5,57 @@ import type {
|
||||
CustomParamSchema,
|
||||
Tool,
|
||||
ToolCredential,
|
||||
WorkflowToolProviderParameter,
|
||||
WorkflowToolProviderRequest,
|
||||
WorkflowToolProviderResponse,
|
||||
} from '@/app/components/tools/types'
|
||||
import { buildProviderQuery } from './_tools_util'
|
||||
// oxlint-disable-next-line no-restricted-imports -- legacy built-in credential flow, see below
|
||||
import { get, post } from './base'
|
||||
import { consoleClient } from './console'
|
||||
import { narrowResponse } from './console/narrow-response'
|
||||
|
||||
const toolProvider = consoleClient.workspaces.current.toolProvider
|
||||
|
||||
type ApiToolSchemaType = 'openai_actions' | 'openai_plugin' | 'openapi' | 'swagger'
|
||||
|
||||
type WorkflowToolParameterForm = 'form' | 'llm' | 'schema'
|
||||
|
||||
// The workflow tool editor keeps parameter forms as select values; the backend validates them.
|
||||
const toWorkflowToolParameters = (parameters: WorkflowToolProviderParameter[]) =>
|
||||
parameters.map((parameter) => ({
|
||||
...parameter,
|
||||
form: parameter.form as WorkflowToolParameterForm,
|
||||
}))
|
||||
|
||||
// The custom tool editor keeps `schema_type` as a free string until a schema is parsed;
|
||||
// the backend validates the value.
|
||||
const toSchemaType = (schemaType: string) => schemaType as ApiToolSchemaType
|
||||
|
||||
export const fetchCollectionList = () => {
|
||||
return get<Collection[]>('/workspaces/current/tool-providers')
|
||||
return narrowResponse<Collection[]>(consoleClient.workspaces.current.toolProviders.get({}))
|
||||
}
|
||||
|
||||
export const fetchBuiltInToolList = (collectionName: string) => {
|
||||
return get<Tool[]>(`/workspaces/current/tool-provider/builtin/${collectionName}/tools`)
|
||||
return narrowResponse<Tool[]>(
|
||||
toolProvider.builtin.byProvider.tools.get({ params: { provider: collectionName } }),
|
||||
)
|
||||
}
|
||||
|
||||
export const fetchCustomToolList = (collectionName: string) => {
|
||||
const query = buildProviderQuery(collectionName)
|
||||
return get<Tool[]>(`/workspaces/current/tool-provider/api/tools?${query}`)
|
||||
}
|
||||
|
||||
export const fetchModelToolList = (collectionName: string) => {
|
||||
const query = buildProviderQuery(collectionName)
|
||||
return get<Tool[]>(`/workspaces/current/tool-provider/model/tools?${query}`)
|
||||
return narrowResponse<Tool[]>(toolProvider.api.tools.get({ query: { provider: collectionName } }))
|
||||
}
|
||||
|
||||
export const fetchWorkflowToolList = (appID: string) => {
|
||||
return get<Tool[]>(`/workspaces/current/tool-provider/workflow/tools?workflow_tool_id=${appID}`)
|
||||
return narrowResponse<Tool[]>(
|
||||
toolProvider.workflow.tools.get({ query: { workflow_tool_id: appID } }),
|
||||
)
|
||||
}
|
||||
|
||||
// Not migrated to the console contract: this legacy built-in credential flow predates
|
||||
// multi-credential tool auth. The backend now serves the schema at
|
||||
// `credential/schema/{credential_type}`, returns a credential list from `credentials`, and
|
||||
// requires `credential_id` for update/delete. Only providers without a plugin reach it, and
|
||||
// none of the remaining hard-coded built-in providers require credentials.
|
||||
export const fetchBuiltInToolCredentialSchema = (collectionName: string) => {
|
||||
return get<ToolCredential[]>(
|
||||
`/workspaces/current/tool-provider/builtin/${collectionName}/credentials_schema`,
|
||||
@@ -44,6 +67,7 @@ export const fetchBuiltInToolCredential = (collectionName: string) => {
|
||||
`/workspaces/current/tool-provider/builtin/${collectionName}/credentials`,
|
||||
)
|
||||
}
|
||||
|
||||
export const updateBuiltInToolCredential = (
|
||||
collectionName: string,
|
||||
credential: Record<string, unknown>,
|
||||
@@ -62,51 +86,40 @@ export const removeBuiltInToolCredential = (collectionName: string) => {
|
||||
}
|
||||
|
||||
export const parseParamsSchema = (schema: string) => {
|
||||
return post<{ parameters_schema: CustomParamSchema[]; schema_type: string }>(
|
||||
'/workspaces/current/tool-provider/api/schema',
|
||||
{
|
||||
body: {
|
||||
schema,
|
||||
},
|
||||
},
|
||||
return narrowResponse<{ parameters_schema: CustomParamSchema[]; schema_type: string }>(
|
||||
toolProvider.api.schema.post({ body: { schema } }),
|
||||
)
|
||||
}
|
||||
|
||||
export const fetchCustomCollection = (collectionName: string) => {
|
||||
const query = buildProviderQuery(collectionName)
|
||||
return get<CustomCollectionBackend>(`/workspaces/current/tool-provider/api/get?${query}`)
|
||||
return narrowResponse<CustomCollectionBackend>(
|
||||
toolProvider.api.get.get({ query: { provider: collectionName } }),
|
||||
)
|
||||
}
|
||||
|
||||
export const createCustomCollection = (collection: CustomCollectionBackend) => {
|
||||
return post('/workspaces/current/tool-provider/api/add', {
|
||||
body: {
|
||||
...collection,
|
||||
},
|
||||
return toolProvider.api.add.post({
|
||||
body: { ...collection, schema_type: toSchemaType(collection.schema_type) },
|
||||
})
|
||||
}
|
||||
|
||||
export const updateCustomCollection = (collection: CustomCollectionBackend) => {
|
||||
return post('/workspaces/current/tool-provider/api/update', {
|
||||
return toolProvider.api.update.post({
|
||||
body: {
|
||||
...collection,
|
||||
// A collection that was not renamed keeps its current name as the original one.
|
||||
original_provider: collection.original_provider ?? collection.provider,
|
||||
schema_type: toSchemaType(collection.schema_type),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const removeCustomCollection = (collectionName: string) => {
|
||||
return post('/workspaces/current/tool-provider/api/delete', {
|
||||
body: {
|
||||
provider: collectionName,
|
||||
},
|
||||
})
|
||||
return toolProvider.api.delete.post({ body: { provider: collectionName } })
|
||||
}
|
||||
|
||||
export const importSchemaFromURL = (url: string) => {
|
||||
return get<{ schema: string }>('/workspaces/current/tool-provider/api/remote', {
|
||||
params: {
|
||||
url,
|
||||
},
|
||||
})
|
||||
return toolProvider.api.remote.get({ query: { url } })
|
||||
}
|
||||
|
||||
export const testAPIAvailable = (payload: {
|
||||
@@ -117,18 +130,16 @@ export const testAPIAvailable = (payload: {
|
||||
schema: string
|
||||
parameters: Record<string, string>
|
||||
}) => {
|
||||
return post('/workspaces/current/tool-provider/api/test/pre', {
|
||||
body: {
|
||||
...payload,
|
||||
},
|
||||
return toolProvider.api.test.pre.post({
|
||||
body: { ...payload, schema_type: toSchemaType(payload.schema_type) },
|
||||
})
|
||||
}
|
||||
|
||||
export const createWorkflowToolProvider = (
|
||||
payload: WorkflowToolProviderRequest & { workflow_app_id: string },
|
||||
) => {
|
||||
return post('/workspaces/current/tool-provider/workflow/create', {
|
||||
body: { ...payload },
|
||||
return toolProvider.workflow.create.post({
|
||||
body: { ...payload, parameters: toWorkflowToolParameters(payload.parameters) },
|
||||
})
|
||||
}
|
||||
|
||||
@@ -139,21 +150,23 @@ export const saveWorkflowToolProvider = (
|
||||
workflow_tool_id: string
|
||||
}>,
|
||||
) => {
|
||||
return post('/workspaces/current/tool-provider/workflow/update', {
|
||||
body: { ...payload },
|
||||
const { workflow_tool_id } = payload
|
||||
if (!workflow_tool_id) throw new Error('workflow_tool_id is required to update a workflow tool')
|
||||
return toolProvider.workflow.update.post({
|
||||
body: {
|
||||
...payload,
|
||||
workflow_tool_id,
|
||||
parameters: toWorkflowToolParameters(payload.parameters),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchWorkflowToolDetail = (toolID: string) => {
|
||||
return get<WorkflowToolProviderResponse>(
|
||||
`/workspaces/current/tool-provider/workflow/get?workflow_tool_id=${toolID}`,
|
||||
return narrowResponse<WorkflowToolProviderResponse>(
|
||||
toolProvider.workflow.get.get({ query: { workflow_tool_id: toolID } }),
|
||||
)
|
||||
}
|
||||
|
||||
export const deleteWorkflowTool = (toolID: string) => {
|
||||
return post('/workspaces/current/tool-provider/workflow/delete', {
|
||||
body: {
|
||||
workflow_tool_id: toolID,
|
||||
},
|
||||
})
|
||||
return toolProvider.workflow.delete.post({ body: { workflow_tool_id: toolID } })
|
||||
}
|
||||
|
||||
+59
-56
@@ -1,3 +1,4 @@
|
||||
import type { AppMcpServerStatus } from '@dify/contracts/api/console/apps/types.gen'
|
||||
import type { QueryKey, UseQueryOptions } from '@tanstack/react-query'
|
||||
import type {
|
||||
Collection,
|
||||
@@ -11,7 +12,7 @@ import type { AppIconType } from '@/types/app'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import { consoleClient } from '@/service/console'
|
||||
import { del, get, post, put } from './base'
|
||||
import { narrowResponse } from './console/narrow-response'
|
||||
import { useInvalid } from './use-base'
|
||||
|
||||
const NAME_SPACE = 'tools'
|
||||
@@ -23,9 +24,9 @@ export const useAllToolProviders = (enabled = true, type?: ToolProviderListType)
|
||||
return useQuery<Collection[]>({
|
||||
queryKey: type ? [...useAllToolProvidersKey, type] : useAllToolProvidersKey,
|
||||
queryFn: () =>
|
||||
type
|
||||
? get<Collection[]>('/workspaces/current/tool-providers', { params: { type } })
|
||||
: get<Collection[]>('/workspaces/current/tool-providers'),
|
||||
narrowResponse<Collection[]>(
|
||||
consoleClient.workspaces.current.toolProviders.get({ query: type ? { type } : {} }),
|
||||
),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
@@ -38,7 +39,8 @@ const useAllBuiltInToolsKey = [NAME_SPACE, 'builtIn']
|
||||
export const useAllBuiltInTools = (enabled = true) => {
|
||||
return useQuery<ToolWithProvider[]>({
|
||||
queryKey: useAllBuiltInToolsKey,
|
||||
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/builtin'),
|
||||
queryFn: () =>
|
||||
narrowResponse<ToolWithProvider[]>(consoleClient.workspaces.current.tools.builtin.get()),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
@@ -51,7 +53,8 @@ const useAllCustomToolsKey = [NAME_SPACE, 'customTools']
|
||||
export const useAllCustomTools = (enabled = true) => {
|
||||
return useQuery<ToolWithProvider[]>({
|
||||
queryKey: useAllCustomToolsKey,
|
||||
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/api'),
|
||||
queryFn: () =>
|
||||
narrowResponse<ToolWithProvider[]>(consoleClient.workspaces.current.tools.api.get()),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
@@ -64,7 +67,8 @@ const useAllWorkflowToolsKey = [NAME_SPACE, 'workflowTools']
|
||||
export const useAllWorkflowTools = (enabled = true) => {
|
||||
return useQuery<ToolWithProvider[]>({
|
||||
queryKey: useAllWorkflowToolsKey,
|
||||
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/workflow'),
|
||||
queryFn: () =>
|
||||
narrowResponse<ToolWithProvider[]>(consoleClient.workspaces.current.tools.workflow.get()),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
@@ -77,7 +81,8 @@ const useAllMCPToolsKey = [NAME_SPACE, 'MCPTools']
|
||||
export const useAllMCPTools = (enabled = true) => {
|
||||
return useQuery<ToolWithProvider[]>({
|
||||
queryKey: useAllMCPToolsKey,
|
||||
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/mcp'),
|
||||
queryFn: () =>
|
||||
narrowResponse<ToolWithProvider[]>(consoleClient.workspaces.current.tools.mcp.get()),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
@@ -103,19 +108,18 @@ export const useCreateMCP = () => {
|
||||
mutationFn: (payload: {
|
||||
name: string
|
||||
server_url: string
|
||||
server_identifier: string
|
||||
icon_type: AppIconType
|
||||
icon: string
|
||||
icon_background?: string | null
|
||||
icon_background?: string
|
||||
timeout?: number
|
||||
sse_read_timeout?: number
|
||||
headers?: Record<string, string>
|
||||
identity_mode?: 'off' | 'idp_token'
|
||||
}) => {
|
||||
return post<ToolWithProvider>('workspaces/current/tool-provider/mcp', {
|
||||
body: {
|
||||
...payload,
|
||||
},
|
||||
})
|
||||
return narrowResponse<ToolWithProvider>(
|
||||
consoleClient.workspaces.current.toolProvider.mcp.post({ body: { ...payload } }),
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -126,20 +130,17 @@ export const useUpdateMCP = ({ onSuccess }: { onSuccess?: () => void }) => {
|
||||
mutationFn: (payload: {
|
||||
name: string
|
||||
server_url: string
|
||||
server_identifier: string
|
||||
icon_type: AppIconType
|
||||
icon: string
|
||||
icon_background?: string | null
|
||||
icon_background?: string
|
||||
provider_id: string
|
||||
timeout?: number
|
||||
sse_read_timeout?: number
|
||||
headers?: Record<string, string>
|
||||
identity_mode?: 'off' | 'idp_token'
|
||||
}) => {
|
||||
return put('workspaces/current/tool-provider/mcp', {
|
||||
body: {
|
||||
...payload,
|
||||
},
|
||||
})
|
||||
return consoleClient.workspaces.current.toolProvider.mcp.put({ body: { ...payload } })
|
||||
},
|
||||
onSuccess,
|
||||
})
|
||||
@@ -149,11 +150,7 @@ export const useDeleteMCP = ({ onSuccess }: { onSuccess?: () => void }) => {
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'delete-mcp'],
|
||||
mutationFn: (id: string) => {
|
||||
return del('/workspaces/current/tool-provider/mcp', {
|
||||
body: {
|
||||
provider_id: id,
|
||||
},
|
||||
})
|
||||
return consoleClient.workspaces.current.toolProvider.mcp.delete({ body: { provider_id: id } })
|
||||
},
|
||||
onSuccess,
|
||||
})
|
||||
@@ -163,12 +160,7 @@ export const useAuthorizeMCP = () => {
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'authorize-mcp'],
|
||||
mutationFn: (payload: { provider_id: string }) => {
|
||||
return post<{ result?: string; authorization_url?: string }>(
|
||||
'/workspaces/current/tool-provider/mcp/auth',
|
||||
{
|
||||
body: payload,
|
||||
},
|
||||
)
|
||||
return consoleClient.workspaces.current.toolProvider.mcp.auth.post({ body: payload })
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -178,7 +170,11 @@ export const useMCPTools = (providerID: string) => {
|
||||
enabled: !!providerID,
|
||||
queryKey: [NAME_SPACE, 'get-MCP-provider-tool', providerID],
|
||||
queryFn: () =>
|
||||
get<{ tools: Tool[] }>(`/workspaces/current/tool-provider/mcp/tools/${providerID}`),
|
||||
narrowResponse<{ tools: Tool[] }>(
|
||||
consoleClient.workspaces.current.toolProvider.mcp.tools.byProviderId.get({
|
||||
params: { provider_id: providerID },
|
||||
}),
|
||||
),
|
||||
})
|
||||
}
|
||||
export const useInvalidateMCPTools = () => {
|
||||
@@ -193,14 +189,21 @@ export const useInvalidateMCPTools = () => {
|
||||
export const useUpdateMCPTools = () => {
|
||||
return useMutation({
|
||||
mutationFn: (providerID: string) =>
|
||||
get<{ tools: Tool[] }>(`/workspaces/current/tool-provider/mcp/update/${providerID}`),
|
||||
narrowResponse<{ tools: Tool[] }>(
|
||||
consoleClient.workspaces.current.toolProvider.mcp.update.byProviderId.get({
|
||||
params: { provider_id: providerID },
|
||||
}),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
export const useMCPServerDetail = (appID: string, enabled = true) => {
|
||||
return useQuery<MCPServerDetail>({
|
||||
queryKey: [NAME_SPACE, 'MCPServerDetail', appID],
|
||||
queryFn: () => get<MCPServerDetail>(`/apps/${appID}/server`),
|
||||
queryFn: () =>
|
||||
narrowResponse<MCPServerDetail>(
|
||||
consoleClient.apps.byAppId.server.get({ params: { app_id: appID } }),
|
||||
),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
@@ -220,14 +223,10 @@ export const useCreateMCPServer = () => {
|
||||
mutationFn: (payload: {
|
||||
appID: string
|
||||
description?: string
|
||||
parameters?: Record<string, string>
|
||||
parameters: Record<string, string>
|
||||
}) => {
|
||||
const { appID, ...rest } = payload
|
||||
return post(`apps/${appID}/server`, {
|
||||
body: {
|
||||
...rest,
|
||||
},
|
||||
})
|
||||
return consoleClient.apps.byAppId.server.post({ params: { app_id: appID }, body: rest })
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -239,15 +238,11 @@ export const useUpdateMCPServer = () => {
|
||||
appID: string
|
||||
id: string
|
||||
description?: string
|
||||
status?: string
|
||||
parameters?: Record<string, string>
|
||||
status?: AppMcpServerStatus
|
||||
parameters: Record<string, string>
|
||||
}) => {
|
||||
const { appID, ...rest } = payload
|
||||
return put(`apps/${appID}/server`, {
|
||||
body: {
|
||||
...rest,
|
||||
},
|
||||
})
|
||||
return consoleClient.apps.byAppId.server.put({ params: { app_id: appID }, body: rest })
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -269,7 +264,12 @@ export const useBuiltinTools = (providerName: string) => {
|
||||
return useQuery({
|
||||
enabled: !!providerName,
|
||||
queryKey: [NAME_SPACE, 'builtin-provider-tools', providerName],
|
||||
queryFn: () => get<Tool[]>(`/workspaces/current/tool-provider/builtin/${providerName}/tools`),
|
||||
queryFn: () =>
|
||||
narrowResponse<Tool[]>(
|
||||
consoleClient.workspaces.current.toolProvider.builtin.byProvider.tools.get({
|
||||
params: { provider: providerName },
|
||||
}),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -279,11 +279,9 @@ export const useRAGRecommendedPlugins = (type: 'tool' | 'datasource' | 'all' = '
|
||||
return useQuery<RAGRecommendedPlugins>({
|
||||
queryKey: [...useRAGRecommendedPluginListKey, type],
|
||||
queryFn: () =>
|
||||
get<RAGRecommendedPlugins>('/rag/pipelines/recommended-plugins', {
|
||||
params: {
|
||||
type,
|
||||
},
|
||||
}),
|
||||
narrowResponse<RAGRecommendedPlugins>(
|
||||
consoleClient.rag.pipelines.recommendedPlugins.get({ query: { type } }),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -315,7 +313,10 @@ export const useAppTriggers = (
|
||||
) => {
|
||||
return useQuery<{ data: AppTrigger[] }>({
|
||||
queryKey: [NAME_SPACE, 'app-triggers', appId],
|
||||
queryFn: () => get<{ data: AppTrigger[] }>(`/apps/${appId}/triggers`),
|
||||
queryFn: () =>
|
||||
narrowResponse<{ data: AppTrigger[] }>(
|
||||
consoleClient.apps.byAppId.triggers.get({ params: { app_id: appId! } }),
|
||||
),
|
||||
enabled: !!appId,
|
||||
...options, // Merge additional options while maintaining backward compatibility
|
||||
})
|
||||
@@ -340,8 +341,10 @@ export const useWorkflowToolDetailByAppID = (appId: string, enabled = true) => {
|
||||
return useQuery<WorkflowToolProviderResponse>({
|
||||
queryKey: workflowToolDetailByAppIDKey(appId),
|
||||
queryFn: () =>
|
||||
get<WorkflowToolProviderResponse>(
|
||||
`/workspaces/current/tool-provider/workflow/get?workflow_app_id=${appId}`,
|
||||
narrowResponse<WorkflowToolProviderResponse>(
|
||||
consoleClient.workspaces.current.toolProvider.workflow.get.get({
|
||||
query: { workflow_app_id: appId },
|
||||
}),
|
||||
),
|
||||
enabled: enabled && !!appId,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user