From b65682da531a7bf4b2ec0d83840649feb61ad9fa Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 16 Aug 2026 07:50:39 +0800 Subject: [PATCH] =?UTF-8?q?refactor(api):=20LLM=20=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E5=95=86=E7=AE=A1=E7=90=86=E8=B0=83=E7=94=A8=E9=80=82=E9=85=8D?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E9=80=9A=E7=94=A8=20manage=20=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - manage.ts 扩展 manageLlmProvider,端点联合类型纳入 llm/manage - useLlmProviderDirectory 的目录/模型查询、授权启动/轮询/断开 全部改走 POST /llm/manage(target+action+params 透传) - 系统设置页 LLM 测试调用改走 manage,provider 字段转为 target - 同步更新 composable 与系统设置页测试断言(GET mock 转 POST) --- src/api/manage.ts | 14 +++++++-- .../__tests__/useLlmProviderDirectory.spec.ts | 12 +++---- src/composables/useLlmProviderDirectory.ts | 31 ++++++++++--------- src/views/setting/AccountSettingSystem.vue | 5 +-- .../__tests__/AccountSettingSystem.spec.ts | 29 +++++++++-------- 5 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/api/manage.ts b/src/api/manage.ts index 2bf177b7..1907fc17 100644 --- a/src/api/manage.ts +++ b/src/api/manage.ts @@ -9,13 +9,13 @@ export interface ManageRequest { } /** - * 调用统一管理端点(通知渠道 / 网盘存储) + * 调用统一管理端点(通知渠道 / 网盘存储 / LLM 提供商) * * 端点层不定义任何目标特定的名称与参数, * 目标标识、管理动作与表单参数原样透传给后端模块 */ function manageTarget>( - endpoint: 'notification/manage' | 'storage/manage', + endpoint: 'notification/manage' | 'storage/manage' | 'llm/manage', request: ManageRequest, config?: AxiosRequestConfig, ): Promise { @@ -41,3 +41,13 @@ export function manageStorage>( ): Promise { return manageTarget('storage/manage', { target: storage, action, params }, config) } + +/** 对指定 LLM 提供商执行管理动作,返回响应中的业务数据。 */ +export function manageLlmProvider>( + provider: string, + action: string, + params: Record = {}, + config?: AxiosRequestConfig, +): Promise { + return manageTarget('llm/manage', { target: provider, action, params }, config) +} diff --git a/src/composables/__tests__/useLlmProviderDirectory.spec.ts b/src/composables/__tests__/useLlmProviderDirectory.spec.ts index 67ce0000..f2e739f9 100644 --- a/src/composables/__tests__/useLlmProviderDirectory.spec.ts +++ b/src/composables/__tests__/useLlmProviderDirectory.spec.ts @@ -4,12 +4,12 @@ import { defineComponent, nextTick, ref } from 'vue' import { beforeEach, describe, expect, it, vi } from 'vitest' const mocks = vi.hoisted(() => ({ - apiGet: vi.fn(), + apiPost: vi.fn(), })) vi.mock('@/api', () => ({ default: createDataApiMock({ - get: (...args: unknown[]) => mocks.apiGet(...args), + post: (...args: unknown[]) => mocks.apiPost(...args), }), })) @@ -33,11 +33,11 @@ function createProvider(id: string, runtime: string) { describe('useLlmProviderDirectory', () => { beforeEach(() => { - mocks.apiGet.mockReset() + mocks.apiPost.mockReset() }) it('只为 OpenAI 兼容 runtime 或声明 Responses 工具能力的模型显示 API 协议字段', async () => { - mocks.apiGet.mockResolvedValue({ + mocks.apiPost.mockResolvedValue({ success: true, data: [ createProvider('openai', 'openai_compatible'), @@ -83,7 +83,7 @@ describe('useLlmProviderDirectory', () => { expect(wrapper.vm.showApiProtocolField).toBe(false) - mocks.apiGet.mockResolvedValueOnce({ + mocks.apiPost.mockResolvedValueOnce({ success: true, data: { models: [ @@ -110,7 +110,7 @@ describe('useLlmProviderDirectory', () => { wrapper.vm.selectProvider('google') await nextTick() - mocks.apiGet.mockResolvedValueOnce({ + mocks.apiPost.mockResolvedValueOnce({ success: true, data: { models: [ diff --git a/src/composables/useLlmProviderDirectory.ts b/src/composables/useLlmProviderDirectory.ts index ecf0f832..bd7136ef 100644 --- a/src/composables/useLlmProviderDirectory.ts +++ b/src/composables/useLlmProviderDirectory.ts @@ -1,5 +1,5 @@ import { computed, onBeforeUnmount, ref, type Ref } from 'vue' -import api from '@/api' +import { manageLlmProvider } from '@/api/manage' export interface LlmProviderAuthMethod { id: string @@ -248,7 +248,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions) async function loadProviders(preserveBaseUrl = true) { loadingProviders.value = true try { - const result = await api.get('llm/providers') + const result = await manageLlmProvider('', 'list_providers') providers.value = Array.isArray(result) ? result : [] if (!selectedProvider.value && providers.value.length > 0) { options.provider.value = providers.value[0].id @@ -266,9 +266,10 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions) loadingModels.value = true try { - const payload = await api.get<{ auth_status?: LlmProviderAuthStatus; models?: LlmModel[] }>('llm/models', { - params: { - provider: normalizeValue(options.provider.value), + const payload = await manageLlmProvider<{ auth_status?: LlmProviderAuthStatus; models?: LlmModel[] }>( + normalizeValue(options.provider.value), + 'list_models', + { api_key: normalizeValue(options.apiKey.value) || undefined, base_url: normalizeValue(options.baseUrl.value) || undefined, base_url_preset: normalizeValue(options.baseUrlPreset?.value) || undefined, @@ -276,7 +277,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions) user_agent: normalizeValue(options.userAgent?.value) || undefined, force_refresh: forceRefresh, }, - }) + ) models.value = Array.isArray(payload.models) ? payload.models : [] updateProviderAuthStatus(normalizeValue(options.provider.value), payload.auth_status) @@ -311,9 +312,10 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions) authPolling.value = true clearPollTimer() try { - const result = await api.post>( - `llm/provider-auth/${authSession.value.session_id}/poll`, - undefined, + const result = await manageLlmProvider>( + normalizeValue(options.provider.value), + 'poll_auth', + { session_id: authSession.value.session_id }, { feedback: 'silent' }, ) @@ -347,10 +349,11 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions) throw new Error('LLM provider is required') } - const result = await api.post('llm/provider-auth/start', { - provider: normalizeValue(options.provider.value), - method: methodId, - }) + const result = await manageLlmProvider( + normalizeValue(options.provider.value), + 'start_auth', + { method: methodId }, + ) authSession.value = result authDialogVisible.value = true @@ -363,7 +366,7 @@ export function useLlmProviderDirectory(options: UseLlmProviderDirectoryOptions) async function disconnectAuth() { if (!selectedProvider.value) return false - await api.delete(`llm/provider-auth/${normalizeValue(options.provider.value)}`) + await manageLlmProvider(normalizeValue(options.provider.value), 'disconnect') await loadProviders() return true diff --git a/src/views/setting/AccountSettingSystem.vue b/src/views/setting/AccountSettingSystem.vue index ea4ee9b0..bd29e93f 100644 --- a/src/views/setting/AccountSettingSystem.vue +++ b/src/views/setting/AccountSettingSystem.vue @@ -2,6 +2,7 @@