diff --git a/packages/aiCore/src/core/plugins/built-in/index.ts b/packages/aiCore/src/core/plugins/built-in/index.ts index a6abc2125..20c4b7859 100644 --- a/packages/aiCore/src/core/plugins/built-in/index.ts +++ b/packages/aiCore/src/core/plugins/built-in/index.ts @@ -7,3 +7,4 @@ export const BUILT_IN_PLUGIN_PREFIX = 'built-in:' export { createLoggingPlugin } from './logging' export type { MCPPromptConfig, ToolUseResult } from './mcpPromptPlugin' export { createMCPPromptPlugin } from './mcpPromptPlugin' +export { type WebSearchConfig, webSearchPlugin } from './webSearchPlugin' diff --git a/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/helper.ts b/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/helper.ts new file mode 100644 index 000000000..7b4cee56f --- /dev/null +++ b/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/helper.ts @@ -0,0 +1,136 @@ +/** + * 网络搜索助手函数 + * 提取各个 ApiClient 中的网络搜索逻辑,提供统一的适配器 + */ +import type { OpenAIProvider } from '@ai-sdk/openai' + +// 派生自 OpenAI SDK 的标准工具入参类型 +type WebSearchPreviewParams = Parameters[0] + +// 使用交叉类型合并,并为 extra 添加注释 +export type WebSearchConfig = WebSearchPreviewParams & { + /** + * 扩展字段,用于提供给开发者自定义参数的能力 + * 这些参数将被合并到对应 provider 的 providerOptions 中 + */ + extra?: Record +} + +/** + * 适配 OpenAI 网络搜索 + * 基于 Vercel AI SDK 的 web_search_preview 工具 + */ +export function adaptOpenAIWebSearch(params: any, webSearchConfig: WebSearchConfig | boolean): any { + const config = typeof webSearchConfig === 'boolean' ? {} : webSearchConfig + const { extra, ...stdParams } = config + + const webSearchTool = { + type: 'web_search_preview', + ...stdParams + } + + // 假设 params.tools 是一个数组或 undefined + const existingTools = Array.isArray(params.tools) ? params.tools : [] + + // 将 extra 参数添加到 providerOptions 中 + const providerOptions = { + ...params.providerOptions, + openai: { + ...params.providerOptions?.openai, + ...(extra || {}) + } + } + + return { + ...params, + tools: [...existingTools, webSearchTool], + providerOptions + } +} + +/** + * 适配 Gemini 网络搜索 + * 将 googleSearch 工具放入 providerOptions.google.tools + */ +export function adaptGeminiWebSearch(params: any, webSearchConfig: WebSearchConfig | boolean): any { + const config = typeof webSearchConfig === 'boolean' ? {} : webSearchConfig + const googleSearchTool = { googleSearch: {} } + + const existingTools = Array.isArray(params.providerOptions?.google?.tools) ? params.providerOptions.google.tools : [] + + return { + ...params, + providerOptions: { + ...params.providerOptions, + google: { + ...params.providerOptions?.google, + tools: [...existingTools, googleSearchTool], + ...(config.extra || {}) + } + } + } +} + +/** + * 适配 Anthropic 网络搜索 + * 将 web_search_20250305 工具放入 providerOptions.anthropic.tools + */ +export function adaptAnthropicWebSearch(params: any, webSearchConfig: WebSearchConfig | boolean): any { + const config = typeof webSearchConfig === 'boolean' ? {} : webSearchConfig + const webSearchTool = { + type: 'web_search_20250305', + name: 'web_search', + max_uses: 5 // 默认值,可以通过 extra 覆盖 + } + + const existingTools = Array.isArray(params.providerOptions?.anthropic?.tools) + ? params.providerOptions.anthropic.tools + : [] + + return { + ...params, + providerOptions: { + ...params.providerOptions, + anthropic: { + ...params.providerOptions?.anthropic, + tools: [...existingTools, webSearchTool], + ...(config.extra || {}) + } + } + } +} + +/** + * 通用网络搜索适配器 + * 根据 providerId 选择对应的适配函数 + */ +export function adaptWebSearchForProvider( + params: any, + providerId: string, + webSearchConfig: WebSearchConfig | boolean +): any { + switch (providerId) { + case 'openai': + return adaptOpenAIWebSearch(params, webSearchConfig) + + case 'google': + case 'google-vertex': + return adaptGeminiWebSearch(params, webSearchConfig) + + case 'anthropic': + return adaptAnthropicWebSearch(params, webSearchConfig) + + default: + // 不支持的 provider,保持原样 + return params + } +} + +/** + * 检查 provider 是否支持网络搜索 + */ +export function isWebSearchSupported(providerId: string): boolean { + const supportedProviders = ['openai', 'google', 'google-vertex', 'anthropic'] + + return supportedProviders.includes(providerId) +} diff --git a/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts b/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts new file mode 100644 index 000000000..4833f45f2 --- /dev/null +++ b/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts @@ -0,0 +1,58 @@ +/** + * Web Search Plugin + * 提供统一的网络搜索能力,支持多个 AI Provider + */ + +import { definePlugin } from '../../' +import type { AiRequestContext } from '../../types' +import { adaptWebSearchForProvider, isWebSearchSupported, type WebSearchConfig } from './helper' + +/** + * 网络搜索插件 + * + * 此插件会检查 params.providerOptions.[providerId].webSearch 来激活。 + * options.ts 文件负责将高层级的设置(如 assistant.enableWebSearch) + * 转换为 providerOptions 中的 webSearch: { enabled: true } 配置。 + */ +export const webSearchPlugin = definePlugin({ + name: 'webSearch', + + transformParams: async (params: any, context: AiRequestContext) => { + const { providerId } = context + + // 从 providerOptions 中提取 webSearch 配置 + const webSearchConfig = params.providerOptions?.[providerId]?.webSearch + + // 检查是否启用了网络搜索 (enabled: false 可用于显式禁用) + if (!webSearchConfig || (typeof webSearchConfig === 'object' && webSearchConfig.enabled === false)) { + return params + } + + // 检查当前 provider 是否支持网络搜索 + if (!isWebSearchSupported(providerId)) { + // 对于不支持的 provider,只记录警告,不修改参数 + console.warn( + `[webSearchPlugin] Provider '${providerId}' does not support web search. Ignoring webSearch parameter.` + ) + return params + } + + // 使用适配器函数处理网络搜索 + const adaptedParams = adaptWebSearchForProvider(params, providerId, webSearchConfig as WebSearchConfig | boolean) + + // 清理原始的 webSearch 配置 + if (adaptedParams.providerOptions?.[providerId]) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { webSearch, ...rest } = adaptedParams.providerOptions[providerId] + adaptedParams.providerOptions[providerId] = rest + } + + return adaptedParams + } +}) + +// 导出类型定义供开发者使用 +export type { WebSearchConfig } from './helper' + +// 默认导出 +export default webSearchPlugin diff --git a/src/renderer/src/aiCore/index_new.ts b/src/renderer/src/aiCore/index_new.ts index 1474d1e73..17ff9076f 100644 --- a/src/renderer/src/aiCore/index_new.ts +++ b/src/renderer/src/aiCore/index_new.ts @@ -126,6 +126,7 @@ export default class ModernAiProvider { const plugins: AiPlugin[] = [] // 1. 总是添加通用插件 // plugins.push(textPlugin) + // plugins.push(webSearchPlugin) // 2. 推理模型时添加推理插件 if (middlewareConfig.enableReasoning) { @@ -138,7 +139,6 @@ export default class ModernAiProvider { createMCPPromptPlugin({ enabled: true, createSystemMessage: (systemPrompt, params, context) => { - console.log('createSystemMessage_context', context.isRecursiveCall) if (context.modelId.includes('o1-mini') || context.modelId.includes('o1-preview')) { if (context.isRecursiveCall) { return null