114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
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<HandleImageAttachmentClick>(
|
||
(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<string, unknown> | 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<string, unknown> | 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,
|
||
}
|
||
}
|