diff --git a/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/helper.ts b/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/helper.ts index 2b03777271..d5f9b682c2 100644 --- a/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/helper.ts +++ b/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/helper.ts @@ -1,5 +1,5 @@ -import type { anthropic } from '@ai-sdk/anthropic' -import type { openai } from '@ai-sdk/openai' +import { anthropic } from '@ai-sdk/anthropic' +import { openai } from '@ai-sdk/openai' import { ProviderOptionsMap } from '../../../options/types' @@ -8,7 +8,6 @@ import { ProviderOptionsMap } from '../../../options/types' */ type OpenAISearchConfig = Parameters[0] type AnthropicSearchConfig = Parameters[0] - /** * XAI 特有的搜索参数 * @internal @@ -77,3 +76,14 @@ export const getXaiProviderOptions = (providerOptions: any, config?: XaiProvider } return providerOptions } + +export type AnthropicSearchInput = { + query: string +} +export type AnthropicSearchOutput = { + url: string + title: string + pageAge: string | null + encryptedContent: string + type: string +}[] diff --git a/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts b/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts index 6d91f6a011..5daeff8699 100644 --- a/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts +++ b/packages/aiCore/src/core/plugins/built-in/webSearchPlugin/index.ts @@ -78,7 +78,7 @@ export const webSearchPlugin = (config: WebSearchPluginConfig = DEFAULT_WEB_SEAR }) // 导出类型定义供开发者使用 -export type { WebSearchPluginConfig } from './helper' +export type { AnthropicSearchInput, AnthropicSearchOutput, WebSearchPluginConfig } from './helper' // 默认导出 export default webSearchPlugin diff --git a/src/renderer/src/aiCore/AiSdkToChunkAdapter.ts b/src/renderer/src/aiCore/AiSdkToChunkAdapter.ts index 494f69effe..d800b17e73 100644 --- a/src/renderer/src/aiCore/AiSdkToChunkAdapter.ts +++ b/src/renderer/src/aiCore/AiSdkToChunkAdapter.ts @@ -81,6 +81,12 @@ export class AiSdkToChunkAdapter { console.log('AI SDK chunk type:', chunk.type, chunk) switch (chunk.type) { // === 文本相关事件 === + // case 'text-start': + // this.onChunk({ + // type: ChunkType.blo, + // text: chunk.text || '' + // }) + // break case 'text': final.text += chunk.text || '' this.onChunk({ @@ -93,6 +99,7 @@ export class AiSdkToChunkAdapter { type: ChunkType.TEXT_COMPLETE, text: final.text || '' }) + final.text = '' break case 'reasoning': this.onChunk({ @@ -206,9 +213,7 @@ export class AiSdkToChunkAdapter { case 'error': this.onChunk({ type: ChunkType.ERROR, - error: { - message: chunk.error || 'Unknown error' - } + error: chunk.error as Record }) break diff --git a/src/renderer/src/aiCore/chunk/handleTooCallChunk.ts b/src/renderer/src/aiCore/chunk/handleTooCallChunk.ts index 3aa1a7ac13..70134c5e43 100644 --- a/src/renderer/src/aiCore/chunk/handleTooCallChunk.ts +++ b/src/renderer/src/aiCore/chunk/handleTooCallChunk.ts @@ -1,6 +1,6 @@ /** * 工具调用 Chunk 处理模块 - * + * TODO: Tool包含了providerTool和普通的Tool还有MCPTool,后面需要重构 * 提供工具调用相关的处理API,每个交互使用一个新的实例 */ @@ -8,7 +8,18 @@ import { ToolCallUnion, ToolResultUnion, ToolSet } from '@cherrystudio/ai-core/i import Logger from '@renderer/config/logger' import { MCPTool, MCPToolResponse } from '@renderer/types' import { Chunk, ChunkType } from '@renderer/types/chunk' +// import type { +// AnthropicSearchOutput, +// WebSearchPluginConfig +// } from '@cherrystudio/ai-core/core/plugins/built-in/webSearchPlugin' +// 为 Provider 执行的工具创建一个通用类型 +// 这避免了污染 MCPTool 的定义,同时提供了 UI 显示所需的基本信息 +type GenericProviderTool = { + name: string + description: string + type: 'provider' +} /** * 工具调用处理器类 */ @@ -20,7 +31,8 @@ export class ToolCallChunkHandler { toolCallId: string toolName: string args: any - mcpTool: MCPTool + // mcpTool 现在可以是 MCPTool 或我们为 Provider 工具创建的通用类型 + mcpTool: MCPTool | GenericProviderTool } >() constructor( @@ -43,30 +55,47 @@ export class ToolCallChunkHandler { type: 'tool-call' } & ToolCallUnion ): void { - const toolCallId = chunk.toolCallId - const toolName = chunk.toolName - const args = chunk.input || {} + const { toolCallId, toolName, input: args, providerExecuted } = chunk if (!toolCallId || !toolName) { Logger.warn(`🔧 [ToolCallChunkHandler] Invalid tool call chunk: missing toolCallId or toolName`) return } - // 从 chunk 信息构造 MCPTool - // const mcpTool = this.createMcpToolFromChunk(chunk) + let tool: MCPTool | GenericProviderTool + + // 根据 providerExecuted 标志区分处理逻辑 + if (providerExecuted) { + // 如果是 Provider 执行的工具(如 web_search) + Logger.info(`[ToolCallChunkHandler] Handling provider-executed tool: ${toolName}`) + tool = { + name: toolName, + description: toolName, + type: 'provider' + } + } else { + // 如果是客户端执行的 MCP 工具,沿用现有逻辑 + Logger.info(`[ToolCallChunkHandler] Handling client-side MCP tool: ${toolName}`) + const mcpTool = this.mcpTools.find((t) => t.name === toolName) + if (!mcpTool) { + Logger.warn(`[ToolCallChunkHandler] MCP tool not found: ${toolName}`) + return + } + tool = mcpTool + } // 记录活跃的工具调用 this.activeToolCalls.set(toolCallId, { toolCallId, toolName, args, - mcpTool: this.mcpTools.find((tool) => tool.name === toolName)! + mcpTool: tool }) // 创建 MCPToolResponse 格式 const toolResponse: MCPToolResponse = { id: toolCallId, - tool: this.activeToolCalls.get(toolCallId)!.mcpTool, + tool: tool, arguments: args, status: 'invoking', toolCallId: toolCallId @@ -121,7 +150,6 @@ export class ToolCallChunkHandler { }, toolCallId: toolCallId } - // 从活跃调用中移除(交互结束后整个实例会被丢弃) this.activeToolCalls.delete(toolCallId) diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index f851d85766..38a038c8ac 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -5,6 +5,12 @@ import type { CSSProperties } from 'react' import type { Message } from './newMessage' +export type GenericProviderTool = { + name: string + description: string + type: 'provider' +} + export type Assistant = { id: string name: string @@ -655,7 +661,7 @@ export interface MCPConfig { interface BaseToolResponse { id: string // unique id - tool: MCPTool + tool: MCPTool | GenericProviderTool arguments: Record | undefined status: string // 'invoking' | 'done' response?: any