From 0187f1780e7815b446512bfecc2f27da7b4babfd Mon Sep 17 00:00:00 2001 From: Phantom <59059173+EurFelux@users.noreply.github.com> Date: Sun, 7 Sep 2025 16:39:22 +0800 Subject: [PATCH] Refactor/migrate zod v4 (#10002) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * build: 更新 zod 依赖至 v4.1.5 * refactor: 将zod导入从'zod/v4'更新为'zod' 统一使用zod主包而非v4子路径,简化依赖管理 * refactor: 统一使用命名导入方式导入zod库 * refactor(mcpServers): 更新RequestPayloadSchema的url和headers类型定义 * refactor(mcp): 将默认值从pipe移动到string以简化schema 默认值'stdio'从pipe操作中移动到string操作,使schema定义更清晰 * refactor(Markdown): 简化 CitationSchema 中 url 的验证方式 * refactor: 将类型断言改为使用 satisfies 操作符 * build: 更新 aiCore 的 zod 依赖至 v4.1.5 * refactor: 更新zod导入方式并简化基础provider类型定义 将zod从'zod/v4'更新为'zod'导入 将baseProviderSchema替换为更简洁的接口类型定义 * fix(providers): 优化provider配置的schema定义并添加注释 调整creator函数的类型定义,增加输入输出类型约束 --- package.json | 2 +- packages/aiCore/package.json | 2 +- packages/aiCore/src/core/options/xai.ts | 2 +- packages/aiCore/src/core/providers/schemas.ts | 25 +++++++++++-------- .../langchain/embeddings/JinaEmbeddings.ts | 2 +- src/main/mcpServers/dify-knowledge.ts | 2 +- src/main/mcpServers/fetch.ts | 4 +-- src/main/mcpServers/filesystem.ts | 2 +- .../services/knowledge/LangChainFramework.ts | 2 +- .../src/aiCore/tools/MemorySearchTool.ts | 2 +- .../pages/home/Markdown/CitationTooltip.tsx | 2 +- src/renderer/src/types/index.ts | 2 +- src/renderer/src/types/mcp.ts | 7 +++--- src/renderer/src/types/tool.ts | 2 +- src/renderer/src/utils/error.ts | 2 +- yarn.lock | 14 +++++------ 16 files changed, 38 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 7d92b048fc..f5c4e71032 100644 --- a/package.json +++ b/package.json @@ -327,7 +327,7 @@ "yjs": "^13.6.27", "youtubei.js": "^15.0.1", "zipread": "^1.3.3", - "zod": "^3.25.74" + "zod": "^4.1.5" }, "resolutions": { "@codemirror/language": "6.11.3", diff --git a/packages/aiCore/package.json b/packages/aiCore/package.json index 2e02700563..020c95d7cb 100644 --- a/packages/aiCore/package.json +++ b/packages/aiCore/package.json @@ -45,7 +45,7 @@ "@ai-sdk/provider": "^2.0.0", "@ai-sdk/provider-utils": "^3.0.4", "@ai-sdk/xai": "^2.0.9", - "zod": "^3.25.0" + "zod": "^4.1.5" }, "devDependencies": { "tsdown": "^0.12.9", diff --git a/packages/aiCore/src/core/options/xai.ts b/packages/aiCore/src/core/options/xai.ts index 8d82f587e8..7fe5672778 100644 --- a/packages/aiCore/src/core/options/xai.ts +++ b/packages/aiCore/src/core/options/xai.ts @@ -1,7 +1,7 @@ // copy from @ai-sdk/xai/xai-chat-options.ts // 如果@ai-sdk/xai暴露出了xaiProviderOptions就删除这个文件 -import * as z from 'zod/v4' +import { z } from 'zod' const webSourceSchema = z.object({ type: z.literal('web'), diff --git a/packages/aiCore/src/core/providers/schemas.ts b/packages/aiCore/src/core/providers/schemas.ts index 0c1c847d98..e4b8d8aa64 100644 --- a/packages/aiCore/src/core/providers/schemas.ts +++ b/packages/aiCore/src/core/providers/schemas.ts @@ -10,8 +10,8 @@ import { createGoogleGenerativeAI } from '@ai-sdk/google' import { createOpenAI, type OpenAIProviderSettings } from '@ai-sdk/openai' import { createOpenAICompatible } from '@ai-sdk/openai-compatible' import { createXai } from '@ai-sdk/xai' -import { customProvider, type Provider } from 'ai' -import * as z from 'zod' +import { customProvider, Provider } from 'ai' +import { z } from 'zod' /** * 基础 Provider IDs @@ -38,14 +38,12 @@ export const baseProviderIdSchema = z.enum(baseProviderIds) */ export type BaseProviderId = z.infer -export const baseProviderSchema = z.object({ - id: baseProviderIdSchema, - name: z.string(), - creator: z.function().args(z.any()).returns(z.any()) as z.ZodType<(options: any) => Provider>, - supportsImageGeneration: z.boolean() -}) - -export type BaseProvider = z.infer +type BaseProvider = { + id: BaseProviderId + name: string + creator: (options: any) => Provider + supportsImageGeneration: boolean +} /** * 基础 Providers 定义 @@ -148,7 +146,12 @@ export const providerConfigSchema = z .object({ id: customProviderIdSchema, // 只允许自定义ID name: z.string().min(1), - creator: z.function().optional(), + creator: z + .function({ + input: z.any(), + output: z.any() + }) + .optional(), import: z.function().optional(), creatorFunctionName: z.string().optional(), supportsImageGeneration: z.boolean().default(false), diff --git a/src/main/knowledge/langchain/embeddings/JinaEmbeddings.ts b/src/main/knowledge/langchain/embeddings/JinaEmbeddings.ts index 0a6c5f1f84..f0380ff360 100644 --- a/src/main/knowledge/langchain/embeddings/JinaEmbeddings.ts +++ b/src/main/knowledge/langchain/embeddings/JinaEmbeddings.ts @@ -1,7 +1,7 @@ import { Embeddings, type EmbeddingsParams } from '@langchain/core/embeddings' import { chunkArray } from '@langchain/core/utils/chunk_array' import { getEnvironmentVariable } from '@langchain/core/utils/env' -import z from 'zod/v4' +import { z } from 'zod' const jinaModelSchema = z.union([ z.literal('jina-clip-v2'), diff --git a/src/main/mcpServers/dify-knowledge.ts b/src/main/mcpServers/dify-knowledge.ts index 83a352fd4f..04f010ce16 100644 --- a/src/main/mcpServers/dify-knowledge.ts +++ b/src/main/mcpServers/dify-knowledge.ts @@ -3,7 +3,7 @@ import { loggerService } from '@logger' import { Server } from '@modelcontextprotocol/sdk/server/index.js' import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js' import { net } from 'electron' -import * as z from 'zod/v4' +import { z } from 'zod' const logger = loggerService.withContext('DifyKnowledgeServer') diff --git a/src/main/mcpServers/fetch.ts b/src/main/mcpServers/fetch.ts index e55b114776..f170cc54c0 100644 --- a/src/main/mcpServers/fetch.ts +++ b/src/main/mcpServers/fetch.ts @@ -8,8 +8,8 @@ import TurndownService from 'turndown' import { z } from 'zod' export const RequestPayloadSchema = z.object({ - url: z.string().url(), - headers: z.record(z.string()).optional() + url: z.url(), + headers: z.record(z.string(), z.string()).optional() }) export type RequestPayload = z.infer diff --git a/src/main/mcpServers/filesystem.ts b/src/main/mcpServers/filesystem.ts index 3b3c5ed799..9ec5ced0b0 100644 --- a/src/main/mcpServers/filesystem.ts +++ b/src/main/mcpServers/filesystem.ts @@ -8,7 +8,7 @@ import fs from 'fs/promises' import { minimatch } from 'minimatch' import os from 'os' import path from 'path' -import * as z from 'zod/v4' +import { z } from 'zod' const logger = loggerService.withContext('MCP:FileSystemServer') diff --git a/src/main/services/knowledge/LangChainFramework.ts b/src/main/services/knowledge/LangChainFramework.ts index b82242e102..c281c7ad94 100644 --- a/src/main/services/knowledge/LangChainFramework.ts +++ b/src/main/services/knowledge/LangChainFramework.ts @@ -30,7 +30,7 @@ import { KnowledgeBaseParams, KnowledgeSearchResult } from '@types' -import { uuidv4 } from 'zod/v4' +import { uuidv4 } from 'zod' import { windowService } from '../WindowService' import { diff --git a/src/renderer/src/aiCore/tools/MemorySearchTool.ts b/src/renderer/src/aiCore/tools/MemorySearchTool.ts index 6430692d4c..d8e402db5d 100644 --- a/src/renderer/src/aiCore/tools/MemorySearchTool.ts +++ b/src/renderer/src/aiCore/tools/MemorySearchTool.ts @@ -82,7 +82,7 @@ export const memorySearchToolWithExtraction = (assistant: Assistant) => { role: z.enum(['user', 'assistant', 'system']).describe('Message role') }) .optional() - }) as z.ZodSchema, + }) satisfies z.ZodSchema, execute: async ({ userMessage }) => { // console.log('🧠 [memorySearchToolWithExtraction] Processing:', { userMessage, lastAnswer }) diff --git a/src/renderer/src/pages/home/Markdown/CitationTooltip.tsx b/src/renderer/src/pages/home/Markdown/CitationTooltip.tsx index 2e496dd7ee..1c66be71c0 100644 --- a/src/renderer/src/pages/home/Markdown/CitationTooltip.tsx +++ b/src/renderer/src/pages/home/Markdown/CitationTooltip.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components' import { z } from 'zod' export const CitationSchema = z.object({ - url: z.string().url(), + url: z.url(), title: z.string().optional(), content: z.string().optional() }) diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index 8fa0099c3f..428631e39d 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -2,7 +2,7 @@ import type { WebSearchResultBlock } from '@anthropic-ai/sdk/resources' import type { GenerateImagesConfig, GroundingMetadata, PersonGeneration } from '@google/genai' import type OpenAI from 'openai' import type { CSSProperties } from 'react' -import * as z from 'zod/v4' +import { z } from 'zod' export * from './file' export * from './note' diff --git a/src/renderer/src/types/mcp.ts b/src/renderer/src/types/mcp.ts index cfc7271714..23f04e882e 100644 --- a/src/renderer/src/types/mcp.ts +++ b/src/renderer/src/types/mcp.ts @@ -1,4 +1,4 @@ -import z from 'zod' +import { z } from 'zod' import { isBuiltinMCPServerName } from '.' @@ -17,6 +17,7 @@ export type MCPConfigSample = z.infer */ export const McpServerTypeSchema = z .string() + .default('stdio') .transform((type) => { if (type.includes('http')) { return 'streamableHttp' @@ -24,9 +25,7 @@ export const McpServerTypeSchema = z return type } }) - .pipe( - z.union([z.literal('stdio'), z.literal('sse'), z.literal('streamableHttp'), z.literal('inMemory')]).default('stdio') // 大多数情况下默认使用 stdio - ) + .pipe(z.union([z.literal('stdio'), z.literal('sse'), z.literal('streamableHttp'), z.literal('inMemory')])) // 大多数情况下默认使用 stdio /** * 定义单个 MCP 服务器的配置。 diff --git a/src/renderer/src/types/tool.ts b/src/renderer/src/types/tool.ts index b552c67685..d0567a8a61 100644 --- a/src/renderer/src/types/tool.ts +++ b/src/renderer/src/types/tool.ts @@ -1,4 +1,4 @@ -import * as z from 'zod/v4' +import { z } from 'zod' export type ToolType = 'builtin' | 'provider' | 'mcp' diff --git a/src/renderer/src/utils/error.ts b/src/renderer/src/utils/error.ts index a1640fd99d..1a2f13a855 100644 --- a/src/renderer/src/utils/error.ts +++ b/src/renderer/src/utils/error.ts @@ -8,7 +8,7 @@ import { } from '@renderer/types/error' import { InvalidToolInputError, NoSuchToolError } from 'ai' import { t } from 'i18next' -import z from 'zod' +import { z } from 'zod' import { safeSerialize } from './serialize' diff --git a/yarn.lock b/yarn.lock index f86b71a54e..de965b531a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2258,7 +2258,7 @@ __metadata: tsdown: "npm:^0.12.9" typescript: "npm:^5.0.0" vitest: "npm:^3.2.4" - zod: "npm:^3.25.0" + zod: "npm:^4.1.5" peerDependencies: ai: ^5.0.26 languageName: unknown @@ -10131,7 +10131,7 @@ __metadata: yjs: "npm:^13.6.27" youtubei.js: "npm:^15.0.1" zipread: "npm:^1.3.3" - zod: "npm:^3.25.74" + zod: "npm:^4.1.5" languageName: unknown linkType: soft @@ -25631,17 +25631,17 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.25.0, zod@npm:^3.25.32": +"zod@npm:^3.25.32": version: 3.25.76 resolution: "zod@npm:3.25.76" checksum: 10c0/5718ec35e3c40b600316c5b4c5e4976f7fee68151bc8f8d90ec18a469be9571f072e1bbaace10f1e85cf8892ea12d90821b200e980ab46916a6166a4260a983c languageName: node linkType: hard -"zod@npm:^3.25.74": - version: 3.25.74 - resolution: "zod@npm:3.25.74" - checksum: 10c0/59e38b046ac333b5bd1ba325a83b6798721227cbfb1e69dfc7159bd7824b904241ab923026edb714fafefec3624265ae374a70aee9a5a45b365bd31781ffa105 +"zod@npm:^4.1.5": + version: 4.1.5 + resolution: "zod@npm:4.1.5" + checksum: 10c0/7826fb931bc71d4d0fff2fbb72f1a1cf30a6672cf9dbe6933a216bbb60242ef1c3bdfbcd3c5b27e806235a35efaad7a4a9897ff4d3621452f9ea278bce6fd42a languageName: node linkType: hard