feat: tool call visualization in TaskAssistant
Some checks failed
Deploy Admin Frontend / build-and-deploy (push) Failing after 7s

This commit is contained in:
WangDL 2026-05-22 17:20:05 +08:00
parent 059dfd55c9
commit 3b8493075d
2 changed files with 21 additions and 4 deletions

View File

@ -1,7 +1,7 @@
import { useState, useRef, useEffect, useCallback } from 'react' import { useState, useRef, useEffect, useCallback } from 'react'
import { Input, Button, theme, Typography, App } from 'antd' import { Input, Button, theme, Typography, App } from 'antd'
import { import {
SendOutlined, RobotOutlined, PlusOutlined, SendOutlined, RobotOutlined, PlusOutlined, ToolOutlined,
DeleteOutlined, StopOutlined, MessageOutlined, DeleteOutlined, StopOutlined, MessageOutlined,
} from '@ant-design/icons' } from '@ant-design/icons'
import { streamChat, type StreamEvent } from '@/services/ai-chat' import { streamChat, type StreamEvent } from '@/services/ai-chat'
@ -19,6 +19,7 @@ interface Message {
content: string content: string
timestamp: number timestamp: number
streaming?: boolean streaming?: boolean
toolCalls?: { tool: string; preview?: string; done: boolean; duration?: number; error?: boolean }[]
} }
function ChatPage() { function ChatPage() {
@ -123,6 +124,14 @@ function ChatPage() {
completedConvId = event.conversationId completedConvId = event.conversationId
if (event.conversationId && event.conversationId !== activeId) { setActiveId(event.conversationId); loadConversations() } if (event.conversationId && event.conversationId !== activeId) { setActiveId(event.conversationId); loadConversations() }
break break
case 'tool.started':
currentTools.push({ tool: event.tool, preview: event.preview, done: false })
update({ toolCalls: [...currentTools] })
break
case 'tool.completed':
const idx = currentTools.findIndex((t: any) => t.tool === event.tool && !t.done)
if (idx >= 0) { currentTools[idx] = { ...currentTools[idx], done: true, duration: event.duration, error: event.error }; update({ toolCalls: [...currentTools] }) }
break
case 'message.delta': case 'message.delta':
currentContent += event.delta || '' currentContent += event.delta || ''
update({ content: currentContent, streaming: true }) update({ content: currentContent, streaming: true })
@ -198,6 +207,15 @@ function ChatPage() {
: <Text type="secondary" style={{ fontSize: 13 }}>...</Text>) : <Text type="secondary" style={{ fontSize: 13 }}>...</Text>)
: msg.content} : msg.content}
</div> </div>
{msg.toolCalls && msg.toolCalls.length > 0 && (
<div style={{ marginTop: 4, display: 'flex', flexWrap: 'wrap', gap: 4 }}>
{msg.toolCalls.map((t, i) => (
<span key={i} style={{ fontSize: 11, color: token.colorTextSecondary, background: token.colorFillSecondary, padding: '2px 8px', borderRadius: 4 }}>
<ToolOutlined style={{ marginRight: 4, fontSize: 10 }} />{t.preview || t.tool}{t.done ? (t.error ? ' ❌' : ' ✓') : ' ···'}
</span>
))}
</div>
)}
</div> </div>
))} ))}
<div ref={messagesEndRef} /> <div ref={messagesEndRef} />

View File

@ -5,9 +5,8 @@ interface ChatMessage { role: 'user' | 'assistant' | 'system'; content: string }
export type StreamEvent = export type StreamEvent =
| { event: 'meta'; conversationId: string } | { event: 'meta'; conversationId: string }
| { event: 'message.delta'; delta: string; runId?: string } | { event: 'message.delta'; delta: string; runId?: string }
| { event: 'reasoning.available'; text: string; runId?: string } | { event: 'tool.started'; tool: string; preview?: string; runId?: string }
| { event: 'tool.start'; toolName?: string; input?: any; runId?: string } | { event: 'tool.completed'; tool: string; duration?: number; error?: boolean; runId?: string }
| { event: 'tool.result'; output?: string; runId?: string }
| { event: 'run.completed'; output?: string; usage?: any; runId?: string } | { event: 'run.completed'; output?: string; usage?: any; runId?: string }
| { event: 'done'; conversationId?: string } | { event: 'done'; conversationId?: string }
| { event: 'stopped' } | { event: 'stopped' }