import { useCallback } from 'react' import type { Attachment, HandleImageAttachmentClick, TaskArtifact } from '../types' import type { ApiEvent } from './useNovaEvents' import { extractToolOutputArtifact } from '../task-panel/Preview/previewUtils' /** * 附件处理逻辑 Hook */ export function useAttachmentHandlers(onSelectAttachment: (artifact: TaskArtifact) => void) { // 处理附件点击 const handleAttachmentClick = useCallback( (attachment: Attachment) => { const artifact: TaskArtifact = { path: attachment.path || attachment.file_url || attachment.file_id || '', file_name: attachment.file_name, file_type: attachment.file_type, url: attachment.file_url, } onSelectAttachment(artifact) }, [onSelectAttachment] ) // 处理图片附件点击 const handleImageAttachmentClick = useCallback( (image, from = 'assistant') => { const getFileExtension = (str?: string): string => { if (!str) return 'jpg' const parts = str.split('.') const ext = parts.length > 1 ? parts[parts.length - 1].toLowerCase().replace(/\?.*$/, '') : '' return ext || 'jpg' } const fileType = getFileExtension(image.file_name) || getFileExtension(image.path) || getFileExtension(image.url) || 'jpg' const artifact: TaskArtifact = { path: image.path || image.url || '', file_name: image.file_name || '图片', file_type: fileType, url: image.url, from, } onSelectAttachment(artifact) }, [onSelectAttachment] ) // 处理工具调用点击 const handleToolCallClick = useCallback( (event: ApiEvent) => { const content = event.content as Record | undefined const actionType = (content?.action_type as string | undefined) || undefined const toolName = content?.tool_name as string | undefined const actionName = content?.action_name as string | undefined const metaToolName = (content?.metadata as Record | undefined)?.tool_name as string | undefined const toLower = (v?: string) => v?.toLowerCase() const isSkillLoader = toLower(actionType) === 'skill_loader' || toLower(actionName) === 'skill_loader' || toLower(toolName) === 'skill_loader' || toLower(metaToolName) === 'skill_loader' const base: TaskArtifact = { path: event.event_id, file_name: toolName || '工具调用', file_type: 'tool_call', event_type: 'tool_call', action_type: isSkillLoader ? 'skill_loader' : actionType || actionName || toolName, tool_name: toolName, event_arguments: content?.arguments, tool_input: content?.tool_input, tool_output: content?.tool_output, } // Skill Loader:点击时按 Markdown 文档渲染 if (isSkillLoader) { const output = content?.tool_output const mdContent = typeof output === 'string' ? output : output != null ? JSON.stringify(output, null, 2) : '' onSelectAttachment({ ...base, file_type: 'md', content: mdContent, }) return } const outputArtifact = extractToolOutputArtifact(base) if (outputArtifact) { onSelectAttachment(outputArtifact) return } onSelectAttachment(base) }, [onSelectAttachment] ) return { handleAttachmentClick, handleImageAttachmentClick, handleToolCallClick, } }