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 (
+
+ )
+}
+
+// 单字段输入工具 (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 (
+
+ )
+}
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
}
}