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:
Stephen Zhou
2026-10-16 01:05:54 +08:00
co-authored by Claude Opus 5.5
parent 42a3ab4790
commit 0f7e4fd5a8
18 changed files with 137 additions and 242 deletions
+1 -9
View File
@@ -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
}
}
}
}
@@ -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}
@@ -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>
+1 -1
View File
@@ -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}
/>
)}
</>
+1
View File
@@ -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',
@@ -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}
+3 -11
View File
@@ -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' } })
})
})
-52
View File
@@ -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')
})
})
})
-5
View File
@@ -1,5 +0,0 @@
export const buildProviderQuery = (collectionName: string): string => {
const query = new URLSearchParams()
query.set('provider', collectionName)
return query.toString()
}
+63 -50
View File
@@ -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
View File
@@ -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,
})