import type { Dispatch, SetStateAction } from 'react' import type { AiAgentMessage } from './aiAgentConversation' import type { AppLocale } from './i18n' export interface ToolInvocation { tool: string input?: string } export function updateMessage( setMessages: Dispatch>, messageId: string, updater: (message: AiAgentMessage) => AiAgentMessage, ): void { setMessages((current) => current.map((message) => (message.id === messageId ? updater(message) : message))) } export function markReasoningDone( setMessages: Dispatch>, messageId: string, ): void { updateMessage(setMessages, messageId, (message) => ( message.reasoningDone ? message : { ...message, reasoningDone: true } )) } type ToolActionStatus = 'pending' | 'done' | 'error' function parsedToolInput(input?: string): Record { if (!input) return {} try { const parsed: unknown = JSON.parse(input) return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) ? parsed as Record : {} } catch { return {} } } function toolDetail(input?: string): string | undefined { const parsed = parsedToolInput(input) for (const key of ['purpose', 'query', 'url', 'path', 'file_path']) { const value = parsed[key] if (typeof value === 'string' && value.trim()) return value.trim() } return undefined } function chineseToolVerb(toolName: string, status: ToolActionStatus): string { const verbs: Record = { magic_brush: ['正在执行', '已完成', '执行失败'], search_web: ['正在联网搜索', '已联网搜索', '联网搜索失败'], read_web_page: ['正在浏览网页', '已浏览网页', '网页浏览失败'], read_guanghu_url: ['正在读取光湖页面', '已读取光湖页面', '光湖页面读取失败'], search_notes: ['正在搜索知识库', '已搜索知识库', '知识库搜索失败'], get_vault_context: ['正在了解知识库', '已读取知识库概况', '知识库概况读取失败'], get_note: ['正在读取页面', '已读取页面', '页面读取失败'], open_note: ['正在打开页面', '已打开页面', '页面打开失败'], create_note: ['正在新建页面', '已新建页面', '页面新建失败'], edit_note: ['正在写入页面', '已写入页面', '页面写入失败'], delete_note: ['正在删除页面', '已删除页面', '页面删除失败'], get_fifth_domain_wake_route: ['正在读取第五域路径', '已读取第五域路径', '第五域路径读取失败'], get_current_time: ['正在校准当前时间', '已校准当前时间', '当前时间校准失败'], Bash: ['正在运行命令', '已运行命令', '命令运行失败'], Write: ['正在写入文件', '已写入文件', '文件写入失败'], Edit: ['正在编辑文件', '已编辑文件', '文件编辑失败'], Read: ['正在读取文件', '已读取文件', '文件读取失败'], Glob: ['正在查找文件', '已查找文件', '文件查找失败'], Grep: ['正在搜索内容', '已搜索内容', '内容搜索失败'], } const index = status === 'pending' ? 0 : status === 'done' ? 1 : 2 return verbs[toolName]?.[index] ?? (status === 'pending' ? `正在调用 ${toolName}` : status === 'done' ? `已调用 ${toolName}` : `${toolName} 调用失败`) } export function formatToolLabel( toolName: string, input?: string, locale: AppLocale = 'en', status: ToolActionStatus = 'pending', ): string { if (locale.startsWith('zh')) { const detail = toolDetail(input) const verb = chineseToolVerb(toolName, status) return detail ? `${verb}:${detail}` : verb } if (toolName === 'Bash') { return 'Ran shell command' } if (toolName === 'Write') return 'Wrote file' if (toolName === 'Edit') return 'Edited file' return toolName } export function updateToolAction( message: AiAgentMessage, toolName: string, toolId: string, input?: string, locale: AppLocale = 'en', ): AiAgentMessage { const existing = message.actions.find((action) => action.toolId === toolId) if (existing) { return { ...message, actions: message.actions.map((action) => ( action.toolId === toolId ? { ...action, input: input ?? action.input, label: formatToolLabel(toolName, input ?? action.input, locale), } : action )), } } return { ...message, actions: [ ...message.actions, { tool: toolName, toolId, label: formatToolLabel(toolName, input, locale), status: 'pending' as const, input, }, ], } }