diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/BashTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/BashTool.tsx new file mode 100644 index 0000000000..6e7826b298 --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/BashTool.tsx @@ -0,0 +1,30 @@ +import { AccordionItem, Code } from '@heroui/react' +import { Terminal } from 'lucide-react' + +import { ToolTitle } from './GenericTools' +import type { BashToolInput as BashToolInputType, BashToolOutput as BashToolOutputType } from './types' + +export function BashTool({ input, output }: { input: BashToolInputType; output?: BashToolOutputType }) { + // 如果有输出,计算输出行数 + const outputLines = output ? output.split('\n').length : 0 + + return ( + } + label="Bash" + params={ + + {input.command} + + } + stats={output ? `${outputLines} ${outputLines === 1 ? 'line' : 'lines'}` : undefined} + /> + }> +
{output}
+
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GenericTools.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GenericTools.tsx new file mode 100644 index 0000000000..e4f033dc14 --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GenericTools.tsx @@ -0,0 +1,95 @@ +// 通用工具组件 - 减少重复代码 + +import { ReactNode } from 'react' + +// 生成 AccordionItem 的标题 +export function ToolTitle({ + icon, + label, + params, + stats, + className = 'text-sm' +}: { + icon?: ReactNode + label: string + params?: string | ReactNode + stats?: string | ReactNode + className?: string +}) { + return ( +
+ {icon} + {label && {label}} + {params && {params}} + {stats && {stats}} +
+ ) +} + +// 纯字符串输入工具 (Task, Bash, Search) +export function StringInputTool({ + input, + label, + className = '' +}: { + input: string + label: string + className?: string +}) { + return ( +
+
{label}:
+
{input}
+
+ ) +} + +// 单字段输入工具 (pattern, query, file_path 等) +export function SimpleFieldInputTool({ + input, + label, + fieldName, + className = '' +}: { + input: Record + label: string + fieldName: string + className?: string +}) { + return ( +
+
{label}:
+
+
{input[fieldName]}
+ {/* 显示其他字段(如 Grep 的 output_mode) */} + {Object.entries(input) + .filter(([key]) => key !== fieldName) + .map(([key, value]) => ( + + {key}: {String(value)} + + ))} +
+
+ ) +} + +// 字符串输出工具 (Read, Bash, Search, Glob, WebSearch, Grep 等) +export function StringOutputTool({ + output, + label, + className = '', + textColor = '' +}: { + output: string + label: string + className?: string + textColor?: string +}) { + return ( +
+
{label}:
+
{output}
+
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GlobTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GlobTool.tsx new file mode 100644 index 0000000000..c057b3f8d1 --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GlobTool.tsx @@ -0,0 +1,26 @@ +import { AccordionItem } from '@heroui/react' +import { FolderSearch } from 'lucide-react' + +import { ToolTitle } from './GenericTools' +import type { GlobToolInput as GlobToolInputType, GlobToolOutput as GlobToolOutputType } from './types' + +export function GlobTool({ input, output }: { input: GlobToolInputType; output?: GlobToolOutputType }) { + // 如果有输出,计算文件数量 + const fileCount = output ? output.split('\n').filter((line) => line.trim()).length : 0 + + return ( + } + label="Glob" + params={input.pattern} + stats={output ? `${fileCount} found` : undefined} + /> + }> +
{output}
+
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GrepTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GrepTool.tsx new file mode 100644 index 0000000000..92e1530c74 --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/GrepTool.tsx @@ -0,0 +1,31 @@ +import { AccordionItem } from '@heroui/react' +import { FileSearch } from 'lucide-react' + +import { ToolTitle } from './GenericTools' +import type { GrepToolInput, GrepToolOutput } from './types' + +export function GrepTool({ input, output }: { input: GrepToolInput; output?: GrepToolOutput }) { + // 如果有输出,计算结果行数 + const resultLines = output ? output.split('\n').filter((line) => line.trim()).length : 0 + + return ( + } + label="Grep" + params={ + <> + {input.pattern} + {input.output_mode && ({input.output_mode})} + + } + stats={output ? `${resultLines} ${resultLines === 1 ? 'line' : 'lines'}` : undefined} + /> + }> +
{output}
+
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/ReadTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/ReadTool.tsx new file mode 100644 index 0000000000..beba2f2164 --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/ReadTool.tsx @@ -0,0 +1,43 @@ +import { AccordionItem } from '@heroui/react' +import { FileText } from 'lucide-react' + +import { SimpleFieldInputTool, StringOutputTool, ToolTitle } from './GenericTools' +import type { ReadToolInput as ReadToolInputType, ReadToolOutput as ReadToolOutputType } from './types' + +export function ReadTool({ input, output }: { input: ReadToolInputType; output?: ReadToolOutputType }) { + // 如果有输出,计算统计信息 + const stats = output + ? { + lineCount: output.split('\n').length, + fileSize: new Blob([output]).size, + formatSize: (bytes: number) => { + if (bytes < 1024) return `${bytes} B` + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` + return `${(bytes / (1024 * 1024)).toFixed(1)} MB` + } + } + : null + + return ( + } + label="Read File" + params={input.file_path.split('/').pop()} + stats={output && stats ? `${stats.lineCount} lines, ${stats.formatSize(stats.fileSize)}` : undefined} + /> + }> +
+ + {output && ( +
+ +
+ )} +
+
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/SearchTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/SearchTool.tsx new file mode 100644 index 0000000000..ea569159f1 --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/SearchTool.tsx @@ -0,0 +1,33 @@ +import { AccordionItem } from '@heroui/react' +import { Search } from 'lucide-react' + +import { StringInputTool, StringOutputTool, ToolTitle } from './GenericTools' +import type { SearchToolInput as SearchToolInputType, SearchToolOutput as SearchToolOutputType } from './types' + +export function SearchTool({ input, output }: { input: SearchToolInputType; output?: SearchToolOutputType }) { + // 如果有输出,计算结果数量 + const resultCount = output ? output.split('\n').filter((line) => line.trim()).length : 0 + + return ( + } + label="Search" + params={`"${input}"`} + stats={output ? `${resultCount} ${resultCount === 1 ? 'result' : 'results'}` : undefined} + /> + }> +
+ + {output && ( +
+ +
+ )} +
+
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/TaskTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/TaskTool.tsx new file mode 100644 index 0000000000..0b8d4495ed --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/TaskTool.tsx @@ -0,0 +1,21 @@ +import { AccordionItem } from '@heroui/react' +import { Bot } from 'lucide-react' + +import { ToolTitle } from './GenericTools' +import type { TaskToolInput as TaskToolInputType, TaskToolOutput as TaskToolOutputType } from './types' + +export function TaskTool({ input, output }: { input: TaskToolInputType; output?: TaskToolOutputType }) { + return ( + } label="Task" params={input.description} />}> + {output?.map((item) => ( +
+
Type: {item.type}
+
{item.text}
+
+ ))} +
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/TodoWriteTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/TodoWriteTool.tsx new file mode 100644 index 0000000000..988b86fefc --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/TodoWriteTool.tsx @@ -0,0 +1,36 @@ +import { AccordionItem } from '@heroui/react' +import { ListTodo } from 'lucide-react' + +import { ToolTitle } from './GenericTools' +import type { + TodoWriteToolInput as TodoWriteToolInputType, + TodoWriteToolOutput as TodoWriteToolOutputType +} from './types' + +export function TodoWriteTool({ input, output }: { input: TodoWriteToolInputType; output?: TodoWriteToolOutputType }) { + return ( + } + label="Todo Update" + stats={`${input.todos.length} ${input.todos.length === 1 ? 'item' : 'items'}`} + /> + }> +
+ {input.todos.map((todo, index) => ( +
+
+ {todo.status} + {todo.activeForm && {todo.activeForm}} +
+
{todo.content}
+
+ ))} +
+ {output} +
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/WebSearchTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/WebSearchTool.tsx new file mode 100644 index 0000000000..0aaafcd394 --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/WebSearchTool.tsx @@ -0,0 +1,29 @@ +import { AccordionItem } from '@heroui/react' +import { Globe } from 'lucide-react' + +import { SimpleFieldInputTool, ToolTitle } from './GenericTools' +import type { WebSearchToolInput, WebSearchToolOutput } from './types' + +export function WebSearchTool({ input, output }: { input: WebSearchToolInput; output?: WebSearchToolOutput }) { + // 如果有输出,计算结果数量 + const resultCount = output ? output.split('\n').filter((line) => line.trim()).length : 0 + + return ( + } + label="Web Search" + params={input.query} + stats={output ? `${resultCount} ${resultCount === 1 ? 'result' : 'results'}` : undefined} + /> + }> +
+ + {output} +
+
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/WriteTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/WriteTool.tsx new file mode 100644 index 0000000000..8b5e116efc --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/WriteTool.tsx @@ -0,0 +1,16 @@ +import { AccordionItem } from '@heroui/react' +import { FileText } from 'lucide-react' + +import { ToolTitle } from './GenericTools' +import type { WriteToolInput, WriteToolOutput } from './types' + +export function WriteTool({ input, output }: { input: WriteToolInput; output?: WriteToolOutput }) { + return ( + } label="Write" params={input.file_path} />}> +
{input.content}
+
+ ) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/index.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/index.tsx new file mode 100644 index 0000000000..9eae101020 --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/index.tsx @@ -0,0 +1,83 @@ +import { Accordion } from '@heroui/react' +import { loggerService } from '@logger' +import { NormalToolResponse } from '@renderer/types' + +// 导出所有类型 +export * from './types' + +// 导入所有渲染器 +import { BashTool } from './BashTool' +import { GlobTool } from './GlobTool' +import { GrepTool } from './GrepTool' +import { ReadTool } from './ReadTool' +import { SearchTool } from './SearchTool' +import { TaskTool } from './TaskTool' +import { TodoWriteTool } from './TodoWriteTool' +import { AgentToolsType, ToolInput, ToolOutput } from './types' +import { WebSearchTool } from './WebSearchTool' +import { WriteTool } from './WriteTool' + +const logger = loggerService.withContext('MessageAgentTools') + +// 创建工具渲染器映射,这样就实现了完全的类型安全 +export const toolRenderers = { + [AgentToolsType.Read]: ReadTool, + [AgentToolsType.Task]: TaskTool, + [AgentToolsType.Bash]: BashTool, + [AgentToolsType.Search]: SearchTool, + [AgentToolsType.Glob]: GlobTool, + [AgentToolsType.TodoWrite]: TodoWriteTool, + [AgentToolsType.WebSearch]: WebSearchTool, + [AgentToolsType.Grep]: GrepTool, + [AgentToolsType.Write]: WriteTool +} as const + +// 类型守卫函数 +export function isValidAgentToolsType(toolName: unknown): toolName is AgentToolsType { + return typeof toolName === 'string' && Object.values(AgentToolsType).includes(toolName as AgentToolsType) +} + +// 统一的渲染函数 +function renderToolContent(toolName: AgentToolsType, input: ToolInput, output?: ToolOutput) { + const Renderer = toolRenderers[toolName] + if (!Renderer) { + logger.error('Unknown tool type', { toolName }) + return
Unknown tool type: {toolName}
+ } + + return ( + div:first-child]:!flex-none [&>div:first-child]:flex [&>div:first-child]:flex-col [&>div:first-child]:text-start' + }}> + {/* */} + {Renderer({ input: input as any, output: output as any })} + + ) +} + +// 统一的组件渲染入口 +export function MessageAgentTools({ toolResponse }: { toolResponse: NormalToolResponse }) { + const { arguments: args, response, tool } = toolResponse + logger.info('Rendering agent tool response', { + tool: tool, + arguments: args, + response + }) + + // 使用类型守卫确保类型安全 + if (!isValidAgentToolsType(tool?.name)) { + logger.warn('Invalid tool name received', { toolName: tool?.name }) + return ( +
+
Invalid tool name: {tool?.name}
+
+ ) + } + + const toolName = tool.name + + return renderToolContent(toolName, args as ToolInput, response as ToolOutput) +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/types.ts b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/types.ts new file mode 100644 index 0000000000..019e8a737b --- /dev/null +++ b/src/renderer/src/pages/home/Messages/Tools/MessageAgentTools/types.ts @@ -0,0 +1,111 @@ +export enum AgentToolsType { + Read = 'Read', + Task = 'Task', + Bash = 'Bash', + Search = 'Search', + Glob = 'Glob', + TodoWrite = 'TodoWrite', + WebSearch = 'WebSearch', + Grep = 'Grep', + Write = 'Write' +} + +// Read 工具的类型定义 +export interface ReadToolInput { + file_path: string +} + +export type ReadToolOutput = string + +// Task 工具的类型定义 +export type TaskToolInput = { + description: string + prompt: string + subagent_type: string +} + +export type TaskToolOutput = { + type: 'text' + text: string +}[] + +// Bash 工具的类型定义 +export type BashToolInput = { + command: string + description: string +} + +export type BashToolOutput = string + +// Search 工具的类型定义 +export type SearchToolInput = string + +export type SearchToolOutput = string + +// Glob 工具的类型定义 +export interface GlobToolInput { + pattern: string +} + +export type GlobToolOutput = string + +// TodoWrite 工具的类型定义 +export interface TodoItem { + content: string + status: string + activeForm?: string +} + +export type TodoWriteToolInput = { + todos: TodoItem[] +} + +export type TodoWriteToolOutput = string + +// WebSearch 工具的类型定义 +export interface WebSearchToolInput { + query: string +} + +export type WebSearchToolOutput = string + +// Grep 工具的类型定义 +export interface GrepToolInput { + pattern: string + output_mode: string +} + +export type GrepToolOutput = string + +export type WriteToolInput = { + content: string + file_path: string +} + +export type WriteToolOutput = string + +// 联合类型 +export type ToolInput = + | ReadToolInput + | TaskToolInput + | BashToolInput + | SearchToolInput + | GlobToolInput + | TodoWriteToolInput + | WebSearchToolInput + | GrepToolInput + | WriteToolInput +export type ToolOutput = + | ReadToolOutput + | TaskToolOutput + | BashToolOutput + | SearchToolOutput + | GlobToolOutput + | TodoWriteToolOutput + | WebSearchToolOutput + | GrepToolOutput + | WriteToolOutput +// 工具渲染器接口 +export interface ToolRenderer { + render: (props: { input: ToolInput; output?: ToolOutput }) => React.ReactElement +} diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageKnowledgeSearch.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageKnowledgeSearch.tsx index 72a3f6e36c..19c3a135d7 100644 --- a/src/renderer/src/pages/home/Messages/Tools/MessageKnowledgeSearch.tsx +++ b/src/renderer/src/pages/home/Messages/Tools/MessageKnowledgeSearch.tsx @@ -1,13 +1,13 @@ import { KnowledgeSearchToolInput, KnowledgeSearchToolOutput } from '@renderer/aiCore/tools/KnowledgeSearchTool' import Spinner from '@renderer/components/Spinner' import i18n from '@renderer/i18n' -import { MCPToolResponse } from '@renderer/types' +import { NormalToolResponse } from '@renderer/types' import { Typography } from 'antd' import { FileSearch } from 'lucide-react' import styled from 'styled-components' const { Text } = Typography -export function MessageKnowledgeSearchToolTitle({ toolResponse }: { toolResponse: MCPToolResponse }) { +export function MessageKnowledgeSearchToolTitle({ toolResponse }: { toolResponse: NormalToolResponse }) { const toolInput = toolResponse.arguments as KnowledgeSearchToolInput const toolOutput = toolResponse.response as KnowledgeSearchToolOutput @@ -28,7 +28,7 @@ export function MessageKnowledgeSearchToolTitle({ toolResponse }: { toolResponse ) } -export function MessageKnowledgeSearchToolBody({ toolResponse }: { toolResponse: MCPToolResponse }) { +export function MessageKnowledgeSearchToolBody({ toolResponse }: { toolResponse: NormalToolResponse }) { const toolOutput = toolResponse.response as KnowledgeSearchToolOutput return toolResponse.status === 'done' ? ( diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageMcpTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageMcpTool.tsx index be5b21104a..b70c117984 100644 --- a/src/renderer/src/pages/home/Messages/Tools/MessageMcpTool.tsx +++ b/src/renderer/src/pages/home/Messages/Tools/MessageMcpTool.tsx @@ -4,6 +4,7 @@ import { useCodeStyle } from '@renderer/context/CodeStyleProvider' import { useMCPServers } from '@renderer/hooks/useMCPServers' import { useSettings } from '@renderer/hooks/useSettings' import { useTimer } from '@renderer/hooks/useTimer' +import { MCPToolResponse } from '@renderer/types' import type { ToolMessageBlock } from '@renderer/types/newMessage' import { isToolAutoApproved } from '@renderer/utils/mcp-tools' import { cancelToolAction, confirmToolAction } from '@renderer/utils/userConfirmation' @@ -59,7 +60,7 @@ const MessageMcpTool: FC = ({ block }) => { const toolResponse = block.metadata?.rawMcpToolResponse - const { id, tool, status, response } = toolResponse! + const { id, tool, status, response } = toolResponse as MCPToolResponse const isPending = status === 'pending' const isDone = status === 'done' const isError = status === 'error' diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageMemorySearch.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageMemorySearch.tsx index cb86d8a259..2d49144633 100644 --- a/src/renderer/src/pages/home/Messages/Tools/MessageMemorySearch.tsx +++ b/src/renderer/src/pages/home/Messages/Tools/MessageMemorySearch.tsx @@ -1,6 +1,6 @@ import { MemorySearchToolInput, MemorySearchToolOutput } from '@renderer/aiCore/tools/MemorySearchTool' import Spinner from '@renderer/components/Spinner' -import { MCPToolResponse } from '@renderer/types' +import { NormalToolResponse } from '@renderer/types' import { Typography } from 'antd' import { ChevronRight } from 'lucide-react' import { useTranslation } from 'react-i18next' @@ -8,7 +8,7 @@ import styled from 'styled-components' const { Text } = Typography -export const MessageMemorySearchToolTitle = ({ toolResponse }: { toolResponse: MCPToolResponse }) => { +export const MessageMemorySearchToolTitle = ({ toolResponse }: { toolResponse: NormalToolResponse }) => { const { t } = useTranslation() const toolInput = toolResponse.arguments as MemorySearchToolInput const toolOutput = toolResponse.response as MemorySearchToolOutput diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageTool.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageTool.tsx index 38ae73e95e..07b97976c3 100644 --- a/src/renderer/src/pages/home/Messages/Tools/MessageTool.tsx +++ b/src/renderer/src/pages/home/Messages/Tools/MessageTool.tsx @@ -1,7 +1,7 @@ -import { MCPToolResponse } from '@renderer/types' +import { NormalToolResponse } from '@renderer/types' import type { ToolMessageBlock } from '@renderer/types/newMessage' -import { Collapse } from 'antd' +import { MessageAgentTools } from './MessageAgentTools' import { MessageKnowledgeSearchToolTitle } from './MessageKnowledgeSearch' import { MessageMemorySearchToolTitle } from './MessageMemorySearch' import { MessageWebSearchToolTitle } from './MessageWebSearch' @@ -11,7 +11,7 @@ interface Props { } const prefix = 'builtin_' -const ChooseTool = (toolResponse: MCPToolResponse): { label: React.ReactNode; body: React.ReactNode } | null => { +const ChooseTool = (toolResponse: NormalToolResponse): React.ReactNode | null => { let toolName = toolResponse.tool.name if (toolName.startsWith(prefix)) { toolName = toolName.slice(prefix.length) @@ -20,20 +20,21 @@ const ChooseTool = (toolResponse: MCPToolResponse): { label: React.ReactNode; bo switch (toolName) { case 'web_search': case 'web_search_preview': - return { - label: , - body: null - } + return case 'knowledge_search': - return { - label: , - body: null - } + return case 'memory_search': - return { - label: , - body: null - } + return + case 'Read': + case 'Task': + case 'Bash': + case 'Search': + case 'Glob': + case 'TodoWrite': + case 'WebSearch': + case 'Grep': + case 'Write': + return default: return null } @@ -45,32 +46,13 @@ export default function MessageTool({ block }: Props) { if (!toolResponse) return null - const toolRenderer = ChooseTool(toolResponse) + const toolRenderer = ChooseTool(toolResponse as NormalToolResponse) if (!toolRenderer) return null - return toolRenderer.body ? ( - - ) : ( - toolRenderer.label - ) + return toolRenderer } + // const PrepareToolWrapper = styled.span` // display: flex; // align-items: center; diff --git a/src/renderer/src/pages/home/Messages/Tools/MessageWebSearch.tsx b/src/renderer/src/pages/home/Messages/Tools/MessageWebSearch.tsx index cd04de3a24..5fe71bbae8 100644 --- a/src/renderer/src/pages/home/Messages/Tools/MessageWebSearch.tsx +++ b/src/renderer/src/pages/home/Messages/Tools/MessageWebSearch.tsx @@ -1,6 +1,6 @@ import { WebSearchToolInput, WebSearchToolOutput } from '@renderer/aiCore/tools/WebSearchTool' import Spinner from '@renderer/components/Spinner' -import { MCPToolResponse } from '@renderer/types' +import { NormalToolResponse } from '@renderer/types' import { Typography } from 'antd' import { Search } from 'lucide-react' import { useTranslation } from 'react-i18next' @@ -8,7 +8,7 @@ import styled from 'styled-components' const { Text } = Typography -export const MessageWebSearchToolTitle = ({ toolResponse }: { toolResponse: MCPToolResponse }) => { +export const MessageWebSearchToolTitle = ({ toolResponse }: { toolResponse: NormalToolResponse }) => { const { t } = useTranslation() const toolInput = toolResponse.arguments as WebSearchToolInput const toolOutput = toolResponse.response as WebSearchToolOutput diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index 733672d043..be91d56bb2 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -730,7 +730,7 @@ export type MCPToolResponseStatus = 'pending' | 'cancelled' | 'invoking' | 'done interface BaseToolResponse { id: string // unique id tool: BaseTool | MCPTool - arguments: Record | undefined + arguments: Record | Record[] | string | undefined status: MCPToolResponseStatus response?: any } diff --git a/src/renderer/src/types/newMessage.ts b/src/renderer/src/types/newMessage.ts index 1dd9d86d92..cd3b70b855 100644 --- a/src/renderer/src/types/newMessage.ts +++ b/src/renderer/src/types/newMessage.ts @@ -11,6 +11,7 @@ import type { MemoryItem, Metrics, Model, + NormalToolResponse, Topic, Usage, WebSearchResponse, @@ -114,7 +115,7 @@ export interface ToolMessageBlock extends BaseMessageBlock { arguments?: Record content?: string | object metadata?: BaseMessageBlock['metadata'] & { - rawMcpToolResponse?: MCPToolResponse + rawMcpToolResponse?: MCPToolResponse | NormalToolResponse } }