fex:尝试修复流式显示工具调用不穿插显示的问题
This commit is contained in:
@ -9,6 +9,20 @@ import { userInteractionManager } from './userInteraction';
|
||||
import { getConfig } from '../config/settings';
|
||||
import type { DialogRequest, ToolCallRequest, AskUserEvent } from '../types/api';
|
||||
|
||||
/**
|
||||
* 消息段落类型
|
||||
*/
|
||||
export interface MessageSegment {
|
||||
type: 'text' | 'tool' | 'question';
|
||||
content?: string;
|
||||
toolName?: string;
|
||||
toolStatus?: 'running' | 'success' | 'error';
|
||||
toolResult?: string;
|
||||
askId?: string;
|
||||
question?: string;
|
||||
options?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话回调接口
|
||||
*/
|
||||
@ -23,8 +37,8 @@ export interface DialogCallbacks {
|
||||
onToolError?: (toolName: string, error: string) => void;
|
||||
/** 显示问题(ask_user) */
|
||||
onQuestion?: (askId: string, question: string, options: string[]) => void;
|
||||
/** 对话完成 */
|
||||
onComplete?: () => void;
|
||||
/** 对话完成,返回所有段落 */
|
||||
onComplete?: (segments: MessageSegment[]) => void;
|
||||
/** 错误 */
|
||||
onError?: (message: string) => void;
|
||||
/** 通知消息 */
|
||||
@ -40,12 +54,62 @@ export class DialogSession {
|
||||
private toolContext: ToolExecutorContext;
|
||||
private accumulatedText = '';
|
||||
private isActive = false;
|
||||
private segments: MessageSegment[] = [];
|
||||
private currentTextSegment: MessageSegment | null = null;
|
||||
|
||||
constructor(extensionPath: string) {
|
||||
this.taskId = generateTaskId();
|
||||
this.toolContext = createToolExecutorContext(extensionPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文本到当前文本段落
|
||||
*/
|
||||
private appendText(text: string): void {
|
||||
if (!this.currentTextSegment) {
|
||||
this.currentTextSegment = { type: 'text', content: '' };
|
||||
this.segments.push(this.currentTextSegment);
|
||||
}
|
||||
this.currentTextSegment.content = (this.currentTextSegment.content || '') + text;
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束当前文本段落
|
||||
*/
|
||||
private finalizeTextSegment(): void {
|
||||
this.currentTextSegment = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加工具段落
|
||||
*/
|
||||
private addToolSegment(toolName: string, status: 'running' | 'success' | 'error', result?: string): MessageSegment {
|
||||
this.finalizeTextSegment();
|
||||
const segment: MessageSegment = {
|
||||
type: 'tool',
|
||||
toolName,
|
||||
toolStatus: status,
|
||||
toolResult: result
|
||||
};
|
||||
this.segments.push(segment);
|
||||
return segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新工具段落状态
|
||||
*/
|
||||
private updateToolSegment(toolName: string, status: 'success' | 'error', result?: string): void {
|
||||
// 找到最后一个匹配的工具段落
|
||||
for (let i = this.segments.length - 1; i >= 0; i--) {
|
||||
const seg = this.segments[i];
|
||||
if (seg.type === 'tool' && seg.toolName === toolName && seg.toolStatus === 'running') {
|
||||
seg.toolStatus = status;
|
||||
seg.toolResult = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务ID
|
||||
*/
|
||||
@ -74,6 +138,8 @@ export class DialogSession {
|
||||
|
||||
this.isActive = true;
|
||||
this.accumulatedText = '';
|
||||
this.segments = [];
|
||||
this.currentTextSegment = null;
|
||||
|
||||
const config = getConfig();
|
||||
const request: DialogRequest = {
|
||||
@ -86,34 +152,64 @@ export class DialogSession {
|
||||
const sseCallbacks: SSECallbacks = {
|
||||
onTextDelta: (data) => {
|
||||
this.accumulatedText += data.text;
|
||||
this.appendText(data.text);
|
||||
console.log('[DialogSession] onTextDelta, 累积文本长度:', this.accumulatedText.length);
|
||||
callbacks.onText?.(this.accumulatedText, true);
|
||||
},
|
||||
|
||||
onToolCall: async (data: ToolCallRequest) => {
|
||||
callbacks.onToolStart?.(data.params.name);
|
||||
const toolName = data.params.name;
|
||||
console.log('[DialogSession] onToolCall:', toolName);
|
||||
// 检查是否已经有相同的工具段落(可能由 onToolStart 添加)
|
||||
const lastToolSegment = this.segments.filter(s => s.type === 'tool').pop();
|
||||
if (lastToolSegment && lastToolSegment.toolName === toolName && lastToolSegment.toolStatus === 'running') {
|
||||
console.log('[DialogSession] onToolCall: 跳过重复的工具段落:', toolName);
|
||||
} else {
|
||||
this.addToolSegment(toolName, 'running');
|
||||
}
|
||||
// 注意:不在这里调用 callbacks.onToolStart,避免与 onToolStart 事件重复
|
||||
try {
|
||||
await executeToolCall(data, this.toolContext);
|
||||
callbacks.onToolComplete?.(data.params.name, '执行完成');
|
||||
this.updateToolSegment(toolName, 'success', '执行完成');
|
||||
// 也不调用 callbacks.onToolComplete,避免重复
|
||||
} catch (error) {
|
||||
const errorMsg = error instanceof Error ? error.message : '未知错误';
|
||||
callbacks.onToolError?.(data.params.name, errorMsg);
|
||||
this.updateToolSegment(toolName, 'error', errorMsg);
|
||||
callbacks.onToolError?.(toolName, errorMsg);
|
||||
}
|
||||
},
|
||||
|
||||
onToolStart: (data) => {
|
||||
console.log('[DialogSession] onToolStart:', data.tool_name);
|
||||
// 检查是否已经有相同的工具段落(可能由 onToolCall 添加)
|
||||
const lastToolSegment = this.segments.filter(s => s.type === 'tool').pop();
|
||||
if (lastToolSegment && lastToolSegment.toolName === data.tool_name && lastToolSegment.toolStatus === 'running') {
|
||||
console.log('[DialogSession] 跳过重复的工具段落:', data.tool_name);
|
||||
} else {
|
||||
this.addToolSegment(data.tool_name, 'running');
|
||||
}
|
||||
console.log('[DialogSession] segments 数量:', this.segments.length);
|
||||
callbacks.onToolStart?.(data.tool_name);
|
||||
},
|
||||
|
||||
onToolComplete: (data) => {
|
||||
this.updateToolSegment(data.tool_name, 'success', data.result);
|
||||
callbacks.onToolComplete?.(data.tool_name, data.result);
|
||||
},
|
||||
|
||||
onToolError: (data) => {
|
||||
this.updateToolSegment(data.tool_name, 'error', data.error);
|
||||
callbacks.onToolError?.(data.tool_name, data.error);
|
||||
},
|
||||
|
||||
onAskUser: async (data: AskUserEvent) => {
|
||||
this.finalizeTextSegment();
|
||||
this.segments.push({
|
||||
type: 'question',
|
||||
askId: data.askId,
|
||||
question: data.question,
|
||||
options: data.options
|
||||
});
|
||||
callbacks.onQuestion?.(data.askId, data.question, data.options);
|
||||
try {
|
||||
await userInteractionManager.handleAskUser(data, this.taskId);
|
||||
@ -124,11 +220,9 @@ export class DialogSession {
|
||||
|
||||
onComplete: (data) => {
|
||||
this.isActive = false;
|
||||
// 发送最终文本(非流式)
|
||||
if (this.accumulatedText) {
|
||||
callbacks.onText?.(this.accumulatedText, false);
|
||||
}
|
||||
callbacks.onComplete?.();
|
||||
this.finalizeTextSegment();
|
||||
// 发送所有段落
|
||||
callbacks.onComplete?.(this.segments);
|
||||
},
|
||||
|
||||
onError: (data) => {
|
||||
|
||||
Reference in New Issue
Block a user