From d91df12dbc0f005fe96ad3c3a5e956e144d469e3 Mon Sep 17 00:00:00 2001 From: Vaayne Date: Fri, 19 Sep 2025 16:36:11 +0800 Subject: [PATCH] feat(models): refactor models service to use new API models schema and types --- src/main/apiServer/services/models.ts | 33 ++++++++++----------------- src/main/apiServer/utils/index.ts | 17 ++++---------- src/renderer/src/types/apiModels.ts | 33 +++++++++++++++++++++++++++ src/renderer/src/types/index.ts | 1 + 4 files changed, 50 insertions(+), 34 deletions(-) create mode 100644 src/renderer/src/types/apiModels.ts diff --git a/src/main/apiServer/services/models.ts b/src/main/apiServer/services/models.ts index f52e222853..98445081c6 100644 --- a/src/main/apiServer/services/models.ts +++ b/src/main/apiServer/services/models.ts @@ -1,29 +1,20 @@ -import { z } from 'zod' - +import { + ApiModelsRequest, + ApiModelsRequestSchema, + ApiModelsResponse, + OpenAICompatibleModel +} from '../../../renderer/src/types/apiModels' import { loggerService } from '../../services/LoggerService' -import { getAvailableProviders, listAllAvailableModels, OpenAICompatibleModel, transformModelToOpenAI } from '../utils' +import { getAvailableProviders, listAllAvailableModels, transformModelToOpenAI } from '../utils' const logger = loggerService.withContext('ModelsService') -// Zod schema for models filtering -export const ModelsFilterSchema = z.object({ - provider: z.enum(['openai', 'anthropic']).optional(), - offset: z.coerce.number().min(0).default(0).optional(), - limit: z.coerce.number().min(1).optional() -}) - -export type ModelsFilter = z.infer - -export interface ModelsResponse { - object: 'list' - data: OpenAICompatibleModel[] - total?: number - offset?: number - limit?: number -} +// Re-export for backward compatibility +export const ModelsFilterSchema = ApiModelsRequestSchema +export type ModelsFilter = ApiModelsRequest export class ModelsService { - async getModels(filter?: ModelsFilter): Promise { + async getModels(filter?: ModelsFilter): Promise { try { logger.info('Getting available models from providers', { filter }) @@ -83,7 +74,7 @@ export class ModelsService { logger.debug(`Filtered out ${models.length - total} models after deduplication and filtering`) } - const response: ModelsResponse = { + const response: ApiModelsResponse = { object: 'list', data: modelData } diff --git a/src/main/apiServer/utils/index.ts b/src/main/apiServer/utils/index.ts index d535e404dc..d3137d3a1f 100644 --- a/src/main/apiServer/utils/index.ts +++ b/src/main/apiServer/utils/index.ts @@ -1,20 +1,9 @@ import { loggerService } from '@main/services/LoggerService' import { reduxService } from '@main/services/ReduxService' -import { Model, Provider } from '@types' +import { Model, OpenAICompatibleModel, Provider } from '@types' const logger = loggerService.withContext('ApiServerUtils') -// OpenAI compatible model format -export interface OpenAICompatibleModel { - id: string - object: 'model' - created: number - name: string - owned_by: string - provider?: string - provider_model_id?: string -} - export async function getAvailableProviders(): Promise { try { // Wait for store to be ready before accessing providers @@ -25,7 +14,9 @@ export async function getAvailableProviders(): Promise { } // Support OpenAI and Anthropic type providers for API server - const supportedProviders = providers.filter((p: Provider) => p.enabled && (p.type === 'openai' || p.type === 'anthropic')) + const supportedProviders = providers.filter( + (p: Provider) => p.enabled && (p.type === 'openai' || p.type === 'anthropic') + ) logger.info(`Filtered to ${supportedProviders.length} supported providers from ${providers.length} total providers`) diff --git a/src/renderer/src/types/apiModels.ts b/src/renderer/src/types/apiModels.ts new file mode 100644 index 0000000000..f023085bd8 --- /dev/null +++ b/src/renderer/src/types/apiModels.ts @@ -0,0 +1,33 @@ +import { z } from 'zod' + +// Request schema for /v1/models +export const ApiModelsRequestSchema = z.object({ + provider: z.enum(['openai', 'anthropic']).optional(), + offset: z.coerce.number().min(0).default(0).optional(), + limit: z.coerce.number().min(1).optional() +}) + +// OpenAI compatible model schema +export const OpenAICompatibleModelSchema = z.object({ + id: z.string(), + object: z.literal('model'), + created: z.number(), + name: z.string(), + owned_by: z.string(), + provider: z.string().optional(), + provider_model_id: z.string().optional() +}) + +// Response schema for /v1/models +export const ApiModelsResponseSchema = z.object({ + object: z.literal('list'), + data: z.array(OpenAICompatibleModelSchema), + total: z.number().optional(), + offset: z.number().optional(), + limit: z.number().optional() +}) + +// Inferred TypeScript types +export type ApiModelsRequest = z.infer +export type OpenAICompatibleModel = z.infer +export type ApiModelsResponse = z.infer diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index 50f507fb04..b54e701074 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -16,6 +16,7 @@ import type { Message } from './newMessage' import type { BaseTool, MCPTool } from './tool' export * from './agent' +export * from './apiModels' export * from './knowledge' export * from './mcp' export * from './notification'