From 0f7e4fd5a81641dda9479793cccf1f40c779e2fd Mon Sep 17 00:00:00 2001 From: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Date: Fri, 16 Oct 2026 01:05:54 +0800 Subject: [PATCH] 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 --- oxlint-suppressions.json | 10 +- .../__tests__/setting-built-in-tool.spec.tsx | 10 +- .../config/agent/agent-tools/index.tsx | 1 - .../agent-tools/setting-built-in-tool.tsx | 12 +- .../plugin-detail-panel/action-list.tsx | 1 - web/app/components/tools/mcp/modal.tsx | 2 +- .../tools/provider/__tests__/detail.spec.tsx | 27 ---- .../provider/__tests__/tool-item.spec.tsx | 4 +- web/app/components/tools/provider/detail.tsx | 5 - .../components/tools/provider/tool-item.tsx | 4 +- web/app/components/tools/types.ts | 1 + .../__tests__/tool-picker.spec.tsx | 2 +- .../tools/provider-tool/dialog.tsx | 1 - web/service/__tests__/use-tools.spec.tsx | 14 +-- web/service/_tools_util.spec.ts | 52 -------- web/service/_tools_util.ts | 5 - web/service/tools.ts | 113 +++++++++-------- web/service/use-tools.ts | 115 +++++++++--------- 18 files changed, 137 insertions(+), 242 deletions(-) delete mode 100644 web/service/_tools_util.spec.ts delete mode 100644 web/service/_tools_util.ts diff --git a/oxlint-suppressions.json b/oxlint-suppressions.json index 7fc1aab6b71..954cd4fef50 100644 --- a/oxlint-suppressions.json +++ b/oxlint-suppressions.json @@ -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 } } -} +} \ No newline at end of file diff --git a/web/app/components/app/configuration/config/agent/agent-tools/__tests__/setting-built-in-tool.spec.tsx b/web/app/components/app/configuration/config/agent/agent-tools/__tests__/setting-built-in-tool.spec.tsx index 86b86cfb398..f94aebe5215 100644 --- a/web/app/components/app/configuration/config/agent/agent-tools/__tests__/setting-built-in-tool.spec.tsx +++ b/web/app/components/app/configuration/config/agent/agent-tools/__tests__/setting-built-in-tool.spec.tsx @@ -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 { }) 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(() => { diff --git a/web/app/components/app/configuration/config/agent/agent-tools/index.tsx b/web/app/components/app/configuration/config/agent/agent-tools/index.tsx index 95703f7be31..7ad92410dd0 100644 --- a/web/app/components/app/configuration/config/agent/agent-tools/index.tsx +++ b/web/app/components/app/configuration/config/agent/agent-tools/index.tsx @@ -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} diff --git a/web/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx b/web/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx index 8334ca4dbe0..0b0dd5d56ea 100644 --- a/web/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx +++ b/web/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx @@ -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 readonly?: boolean @@ -56,7 +50,6 @@ const SettingBuiltInTool: FC = ({ showBackButton = false, collection, isBuiltIn = true, - isModel = true, toolName, setting = {}, readonly, @@ -90,8 +83,7 @@ const SettingBuiltInTool: FC = ({ try { const list = await new Promise((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)) diff --git a/web/app/components/plugins/plugin-detail-panel/action-list.tsx b/web/app/components/plugins/plugin-detail-panel/action-list.tsx index 10dd51dc2a5..892520f0e20 100644 --- a/web/app/components/plugins/plugin-detail-panel/action-list.tsx +++ b/web/app/components/plugins/plugin-detail-panel/action-list.tsx @@ -40,7 +40,6 @@ const ActionList = ({ detail }: Props) => { collection={provider} tool={tool} isBuiltIn={true} - isModel={false} /> ))} diff --git a/web/app/components/tools/mcp/modal.tsx b/web/app/components/tools/mcp/modal.tsx index d07104413b6..0cf2156549e 100644 --- a/web/app/components/tools/mcp/modal.tsx +++ b/web/app/components/tools/mcp/modal.tsx @@ -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 is_dynamic_registration?: boolean diff --git a/web/app/components/tools/provider/__tests__/detail.spec.tsx b/web/app/components/tools/provider/__tests__/detail.spec.tsx index bfac8c6c1fd..8853010d663 100644 --- a/web/app/components/tools/provider/__tests__/detail.spec.tsx +++ b/web/app/components/tools/provider/__tests__/detail.spec.tsx @@ -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( { }) }) - it('calls fetchModelToolList for model type', async () => { - render( - , - ) - await waitFor(() => { - expect(mockFetchModelToolList).toHaveBeenCalledWith('test-collection') - }) - }) - it('calls fetchCustomToolList for custom type', async () => { render( { it('opens and closes tool details from the keyboard', async () => { const user = userEvent.setup() - render() + render() 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() + render() const toolButton = screen.getByRole('button', { name: 'Tool label' }) expect(toolButton).toBeDisabled() diff --git a/web/app/components/tools/provider/detail.tsx b/web/app/components/tools/provider/detail.tsx index b52f3e08304..13c20b51b3f 100644 --- a/web/app/components/tools/provider/detail.tsx +++ b/web/app/components/tools/provider/detail.tsx @@ -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 && diff --git a/web/app/components/tools/provider/tool-item.tsx b/web/app/components/tools/provider/tool-item.tsx index eb1bd73307b..f89a7b43292 100644 --- a/web/app/components/tools/provider/tool-item.tsx +++ b/web/app/components/tools/provider/tool-item.tsx @@ -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} /> )} diff --git a/web/app/components/tools/types.ts b/web/app/components/tools/types.ts index 22884c21803..560dc80a5f0 100644 --- a/web/app/components/tools/types.ts +++ b/web/app/components/tools/types.ts @@ -247,6 +247,7 @@ export type WorkflowToolProviderOutputSchema = { export type WorkflowToolProviderRequest = { name: string + label: string icon: Emoji description: string parameters: WorkflowToolProviderParameter[] diff --git a/web/app/components/workflow/block-selector/__tests__/tool-picker.spec.tsx b/web/app/components/workflow/block-selector/__tests__/tool-picker.spec.tsx index 7425c259a4b..abf3e22d17f 100644 --- a/web/app/components/workflow/block-selector/__tests__/tool-picker.spec.tsx +++ b/web/app/components/workflow/block-selector/__tests__/tool-picker.spec.tsx @@ -387,7 +387,7 @@ describe('ToolPicker', () => { plugins: [], isLoading: false, } as ReturnType) - mockCreateCustomCollection.mockResolvedValue(undefined) + mockCreateCustomCollection.mockResolvedValue({ result: 'success' }) mockInstallPackageFromMarketPlace.mockResolvedValue({ all_installed: true, task_id: 'task-1', diff --git a/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/provider-tool/dialog.tsx b/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/provider-tool/dialog.tsx index 5849b7ca620..17b5d8d66a3 100644 --- a/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/provider-tool/dialog.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/provider-tool/dialog.tsx @@ -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} diff --git a/web/service/__tests__/use-tools.spec.tsx b/web/service/__tests__/use-tools.spec.tsx index 35213ac72f0..e5a463b68bc 100644 --- a/web/service/__tests__/use-tools.spec.tsx +++ b/web/service/__tests__/use-tools.spec.tsx @@ -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' } }) }) }) diff --git a/web/service/_tools_util.spec.ts b/web/service/_tools_util.spec.ts deleted file mode 100644 index e3bec3efcf6..00000000000 --- a/web/service/_tools_util.spec.ts +++ /dev/null @@ -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') - }) - }) -}) diff --git a/web/service/_tools_util.ts b/web/service/_tools_util.ts deleted file mode 100644 index 89dede8163f..00000000000 --- a/web/service/_tools_util.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const buildProviderQuery = (collectionName: string): string => { - const query = new URLSearchParams() - query.set('provider', collectionName) - return query.toString() -} diff --git a/web/service/tools.ts b/web/service/tools.ts index 08b6f54e5c1..69eea1e0202 100644 --- a/web/service/tools.ts +++ b/web/service/tools.ts @@ -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('/workspaces/current/tool-providers') + return narrowResponse(consoleClient.workspaces.current.toolProviders.get({})) } export const fetchBuiltInToolList = (collectionName: string) => { - return get(`/workspaces/current/tool-provider/builtin/${collectionName}/tools`) + return narrowResponse( + toolProvider.builtin.byProvider.tools.get({ params: { provider: collectionName } }), + ) } export const fetchCustomToolList = (collectionName: string) => { - const query = buildProviderQuery(collectionName) - return get(`/workspaces/current/tool-provider/api/tools?${query}`) -} - -export const fetchModelToolList = (collectionName: string) => { - const query = buildProviderQuery(collectionName) - return get(`/workspaces/current/tool-provider/model/tools?${query}`) + return narrowResponse(toolProvider.api.tools.get({ query: { provider: collectionName } })) } export const fetchWorkflowToolList = (appID: string) => { - return get(`/workspaces/current/tool-provider/workflow/tools?workflow_tool_id=${appID}`) + return narrowResponse( + 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( `/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, @@ -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(`/workspaces/current/tool-provider/api/get?${query}`) + return narrowResponse( + 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 }) => { - 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( - `/workspaces/current/tool-provider/workflow/get?workflow_tool_id=${toolID}`, + return narrowResponse( + 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 } }) } diff --git a/web/service/use-tools.ts b/web/service/use-tools.ts index 002cbc9b264..15c024f7d26 100644 --- a/web/service/use-tools.ts +++ b/web/service/use-tools.ts @@ -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({ queryKey: type ? [...useAllToolProvidersKey, type] : useAllToolProvidersKey, queryFn: () => - type - ? get('/workspaces/current/tool-providers', { params: { type } }) - : get('/workspaces/current/tool-providers'), + narrowResponse( + 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({ queryKey: useAllBuiltInToolsKey, - queryFn: () => get('/workspaces/current/tools/builtin'), + queryFn: () => + narrowResponse(consoleClient.workspaces.current.tools.builtin.get()), enabled, }) } @@ -51,7 +53,8 @@ const useAllCustomToolsKey = [NAME_SPACE, 'customTools'] export const useAllCustomTools = (enabled = true) => { return useQuery({ queryKey: useAllCustomToolsKey, - queryFn: () => get('/workspaces/current/tools/api'), + queryFn: () => + narrowResponse(consoleClient.workspaces.current.tools.api.get()), enabled, }) } @@ -64,7 +67,8 @@ const useAllWorkflowToolsKey = [NAME_SPACE, 'workflowTools'] export const useAllWorkflowTools = (enabled = true) => { return useQuery({ queryKey: useAllWorkflowToolsKey, - queryFn: () => get('/workspaces/current/tools/workflow'), + queryFn: () => + narrowResponse(consoleClient.workspaces.current.tools.workflow.get()), enabled, }) } @@ -77,7 +81,8 @@ const useAllMCPToolsKey = [NAME_SPACE, 'MCPTools'] export const useAllMCPTools = (enabled = true) => { return useQuery({ queryKey: useAllMCPToolsKey, - queryFn: () => get('/workspaces/current/tools/mcp'), + queryFn: () => + narrowResponse(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 identity_mode?: 'off' | 'idp_token' }) => { - return post('workspaces/current/tool-provider/mcp', { - body: { - ...payload, - }, - }) + return narrowResponse( + 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 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({ queryKey: [NAME_SPACE, 'MCPServerDetail', appID], - queryFn: () => get(`/apps/${appID}/server`), + queryFn: () => + narrowResponse( + 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 + parameters: Record }) => { 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 + status?: AppMcpServerStatus + parameters: Record }) => { 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(`/workspaces/current/tool-provider/builtin/${providerName}/tools`), + queryFn: () => + narrowResponse( + consoleClient.workspaces.current.toolProvider.builtin.byProvider.tools.get({ + params: { provider: providerName }, + }), + ), }) } @@ -279,11 +279,9 @@ export const useRAGRecommendedPlugins = (type: 'tool' | 'datasource' | 'all' = ' return useQuery({ queryKey: [...useRAGRecommendedPluginListKey, type], queryFn: () => - get('/rag/pipelines/recommended-plugins', { - params: { - type, - }, - }), + narrowResponse( + 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({ queryKey: workflowToolDetailByAppIDKey(appId), queryFn: () => - get( - `/workspaces/current/tool-provider/workflow/get?workflow_app_id=${appId}`, + narrowResponse( + consoleClient.workspaces.current.toolProvider.workflow.get.get({ + query: { workflow_app_id: appId }, + }), ), enabled: enabled && !!appId, })