/** * 用户交互处理器 * 处理 ask_user 事件,通过 WebView 显示问题并收集用户回答 */ import * as vscode from 'vscode'; import { submitAnswer, submitToolConfirm } from './apiClient'; import type { AskUserEvent, AnswerRequest } from '../types/api'; /** * 待处理的用户问题 */ interface PendingQuestion { askId: string; taskId: string; question: string; options: string[]; resolve: (answer: string) => void; reject: (error: Error) => void; } /** * 用户交互管理器 */ export class UserInteractionManager { private pendingQuestions = new Map(); private webviewPanel: vscode.WebviewPanel | null = null; /** * 设置 WebView 面板(用于发送消息) */ setWebviewPanel(panel: vscode.WebviewPanel): void { this.webviewPanel = panel; } /** * 获取 WebView 面板 */ getWebviewPanel(): vscode.WebviewPanel | null { return this.webviewPanel; } /** * 处理 ask_user 事件 * @param event ask_user 事件数据 * @param taskId 当前任务ID */ async handleAskUser(event: AskUserEvent, taskId: string): Promise { const { askId, question, options } = event; console.log(`[UserInteraction] 收到问题: askId=${askId}, question=${question}`); // 注意:问题显示已经通过 dialogService 的 onSegmentUpdate 统一处理 // 这里不再单独发送 showQuestion 命令,避免重复显示 // 创建 Promise 等待用户回答 return new Promise((resolve, reject) => { this.pendingQuestions.set(askId, { askId, taskId, question, options, resolve: (answer: string) => { this.submitUserAnswer(askId, taskId, answer) .then(() => resolve()) .catch(reject); }, reject }); // 设置超时(2小时) setTimeout(() => { if (this.pendingQuestions.has(askId)) { this.pendingQuestions.delete(askId); reject(new Error('用户回答超时')); } }, 7200000); }); } /** * 处理用户提交的回答(从 WebView 调用) * @param askId 问题ID * @param selected 选中的选项 * @param customInput 自定义输入 */ async receiveAnswer( askId: string, selected?: string[], customInput?: string ): Promise { const pending = this.pendingQuestions.get(askId); if (!pending) { console.warn(`[UserInteraction] 问题不存在或已超时: askId=${askId}`); return; } // 构建答案 const answer = customInput || selected?.join(', ') || ''; console.log(`[UserInteraction] 收到用户回答: askId=${askId}, answer=${answer}`); // 移除待处理问题 this.pendingQuestions.delete(askId); // 触发 resolve pending.resolve(answer); } /** * 提交用户回答到后端 */ private async submitUserAnswer( askId: string, taskId: string, answer: string ): Promise { // 检查是否是工具确认类型的问题 if (askId.startsWith('tool_confirm_')) { // 提取 confirmId const confirmId = parseInt(askId.replace('tool_confirm_', '')); const approved = answer === '确认执行'; console.log(`[UserInteraction] 提交工具确认: confirmId=${confirmId}, approved=${approved}`); try { const response = await submitToolConfirm({ confirmId, taskId, approved }); if (!response.success) { throw new Error(response.error || '提交工具确认失败'); } console.log(`[UserInteraction] 工具确认已提交: confirmId=${confirmId}`); } catch (error) { console.error(`[UserInteraction] 提交工具确认失败: confirmId=${confirmId}`, error); throw error; } } else { // 普通问题回答 const request: AnswerRequest = { askId, taskId, customInput: answer }; try { const response = await submitAnswer(request); if (!response.success) { throw new Error(response.error || '提交回答失败'); } console.log(`[UserInteraction] 回答已提交: askId=${askId}`); } catch (error) { console.error(`[UserInteraction] 提交回答失败: askId=${askId}`, error); throw error; } } } /** * 取消所有待处理的问题 */ cancelAll(): void { for (const [askId, pending] of this.pendingQuestions) { pending.reject(new Error('用户交互已取消')); } this.pendingQuestions.clear(); } /** * 检查是否有待处理的问题 */ hasPendingQuestions(): boolean { return this.pendingQuestions.size > 0; } } // 全局实例 export const userInteractionManager = new UserInteractionManager();