feat(ui): 优化流式输出工具调用渲染
- 添加 tool_start/tool_end WebSocket 事件支持 - 流式消息复用 ChatMessage 组件渲染工具调用卡片 - 修复 AI SDK v5 格式兼容问题(input/output 字段) - 修复会话恢复时 tool-result 格式错误 - 放宽 ToolState schema 中 input 字段类型为 unknown
This commit is contained in:
@@ -67,11 +67,33 @@ interface SessionManagerConstructor {
|
||||
new (): SessionManagerInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具开始信息
|
||||
*/
|
||||
interface ToolStartInfo {
|
||||
id: string;
|
||||
toolName: string;
|
||||
args: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具结束信息
|
||||
*/
|
||||
interface ToolEndInfo {
|
||||
id: string;
|
||||
status: 'completed' | 'error';
|
||||
result?: unknown;
|
||||
error?: string;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat 选项接口
|
||||
*/
|
||||
interface ChatOptions {
|
||||
onStream?: (chunk: string) => void;
|
||||
onToolStart?: (info: ToolStartInfo) => void;
|
||||
onToolEnd?: (info: ToolEndInfo) => void;
|
||||
abortSignal?: AbortSignal;
|
||||
}
|
||||
|
||||
@@ -397,7 +419,7 @@ export async function processMessage(sessionId: string, content: string): Promis
|
||||
payload: { content: chunk },
|
||||
});
|
||||
|
||||
// 检测工具调用
|
||||
// 检测工具调用(向后兼容 - SSE 日志)
|
||||
if (chunk.includes('[调用工具:')) {
|
||||
const match = chunk.match(/\[调用工具: (.+?)\]/);
|
||||
if (match) {
|
||||
@@ -405,6 +427,38 @@ export async function processMessage(sessionId: string, content: string): Promis
|
||||
}
|
||||
}
|
||||
},
|
||||
onToolStart: (info) => {
|
||||
// 检查是否已取消
|
||||
if (abortController.signal.aborted) return;
|
||||
|
||||
// 推送工具开始事件
|
||||
broadcastToSession(sessionId, {
|
||||
type: 'tool_start',
|
||||
sessionId,
|
||||
payload: {
|
||||
id: info.id,
|
||||
toolName: info.toolName,
|
||||
arguments: info.args,
|
||||
},
|
||||
});
|
||||
},
|
||||
onToolEnd: (info) => {
|
||||
// 检查是否已取消
|
||||
if (abortController.signal.aborted) return;
|
||||
|
||||
// 推送工具结束事件
|
||||
broadcastToSession(sessionId, {
|
||||
type: 'tool_end',
|
||||
sessionId,
|
||||
payload: {
|
||||
id: info.id,
|
||||
status: info.status,
|
||||
result: info.result,
|
||||
error: info.error,
|
||||
duration: info.duration,
|
||||
},
|
||||
});
|
||||
},
|
||||
abortSignal: abortController.signal,
|
||||
});
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ export interface ServerMessage {
|
||||
| 'chunk'
|
||||
| 'tool_call'
|
||||
| 'tool_result'
|
||||
| 'tool_start' // 工具开始执行
|
||||
| 'tool_end' // 工具执行完成
|
||||
| 'done'
|
||||
| 'cancelled'
|
||||
| 'error'
|
||||
@@ -119,6 +121,22 @@ export interface ServerMessage {
|
||||
payload?: unknown;
|
||||
}
|
||||
|
||||
// 工具开始事件 Payload
|
||||
export interface ToolStartPayload {
|
||||
id: string;
|
||||
toolName: string;
|
||||
arguments: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// 工具结束事件 Payload
|
||||
export interface ToolEndPayload {
|
||||
id: string;
|
||||
status: 'completed' | 'error';
|
||||
result?: unknown;
|
||||
error?: string;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
// ============ Permission 相关 ============
|
||||
|
||||
export type PermissionType = 'bash' | 'file' | 'git' | 'web';
|
||||
|
||||
Reference in New Issue
Block a user