refactor: 将 Ask 模式的工具确认从弹窗改为内嵌聊天卡片
## 主要修改
### dialogService.ts
- 移除 `vscode.window.showWarningMessage` 弹窗
- 将工具确认改为添加 question 类型的 segment
- 使用 `userInteractionManager.handleAskUser` 等待用户回答
- 生成唯一的 askId: `tool_confirm_{confirmId}`
### userInteraction.ts
- 导入 `submitToolConfirm` 方法
- 在 `submitUserAnswer` 中识别工具确认类型的 askId
- 根据用户选择("确认执行" / "取消")调用对应的 API
## 用户体验改进
- 工具确认问题自然融入对话流程
- 用户可以看到历史确认记录
- 非阻塞式交互,体验更流畅
This commit is contained in:
@ -301,30 +301,64 @@ export class DialogSession {
|
|||||||
onToolConfirm: async (data: ToolConfirmEvent) => {
|
onToolConfirm: async (data: ToolConfirmEvent) => {
|
||||||
console.log('[DialogSession] onToolConfirm:', data.toolName, data.confirmId);
|
console.log('[DialogSession] onToolConfirm:', data.toolName, data.confirmId);
|
||||||
|
|
||||||
// 调用回调通知 UI 显示确认对话框
|
// 结束当前文本段落
|
||||||
|
this.finalizeTextSegment();
|
||||||
|
|
||||||
|
// 生成工具描述
|
||||||
|
const toolDescription = this.getToolDescription(data.toolName, data.toolInput);
|
||||||
|
|
||||||
|
// 构建问题文本
|
||||||
|
const toolNameMap: Record<string, string> = {
|
||||||
|
'file_write': '写入文件',
|
||||||
|
'file_delete': '删除文件',
|
||||||
|
'syntax_check': '语法检查',
|
||||||
|
'simulation': '运行仿真'
|
||||||
|
};
|
||||||
|
const toolDisplayName = toolNameMap[data.toolName] || data.toolName;
|
||||||
|
const question = `确认执行操作:${toolDisplayName}\n\n${toolDescription}`;
|
||||||
|
|
||||||
|
// 生成唯一的 askId
|
||||||
|
const askId = `tool_confirm_${data.confirmId}`;
|
||||||
|
|
||||||
|
// 添加问题段落到聊天界面
|
||||||
|
this.segments.push({
|
||||||
|
type: 'question',
|
||||||
|
askId: askId,
|
||||||
|
question: question,
|
||||||
|
options: ['确认执行', '取消']
|
||||||
|
});
|
||||||
|
|
||||||
|
// 实时发送段落更新
|
||||||
|
callbacks.onSegmentUpdate?.(this.segments);
|
||||||
|
|
||||||
|
// 调用回调通知 UI
|
||||||
callbacks.onToolConfirm?.(data.confirmId, data.toolName, data.toolInput);
|
callbacks.onToolConfirm?.(data.confirmId, data.toolName, data.toolInput);
|
||||||
|
|
||||||
// 使用 VSCode 快速选择框显示确认对话框
|
// 使用 userInteractionManager 等待用户回答
|
||||||
const toolDescription = this.getToolDescription(data.toolName, data.toolInput);
|
try {
|
||||||
const result = await vscode.window.showWarningMessage(
|
await userInteractionManager.handleAskUser(
|
||||||
`确认执行操作: ${data.toolName}`,
|
{
|
||||||
{ modal: true, detail: toolDescription },
|
askId: askId,
|
||||||
'确认执行',
|
question: question,
|
||||||
'取消'
|
options: ['确认执行', '取消']
|
||||||
|
} as AskUserEvent,
|
||||||
|
this.taskId
|
||||||
);
|
);
|
||||||
|
|
||||||
const approved = result === '确认执行';
|
// 注意:用户回答后,需要在 receiveAnswer 中处理 tool_confirm 类型的 askId
|
||||||
console.log('[DialogSession] 用户确认结果:', approved);
|
// 这里不直接调用 submitToolConfirm,而是在 userInteractionManager 中统一处理
|
||||||
|
} catch (error) {
|
||||||
// 发送确认响应到后端
|
console.error('[DialogSession] 处理工具确认失败:', error);
|
||||||
|
// 如果出错,默认取消执行
|
||||||
try {
|
try {
|
||||||
await submitToolConfirm({
|
await submitToolConfirm({
|
||||||
confirmId: data.confirmId,
|
confirmId: data.confirmId,
|
||||||
taskId: this.taskId,
|
taskId: this.taskId,
|
||||||
approved
|
approved: false
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (submitError) {
|
||||||
console.error('[DialogSession] 发送确认响应失败:', error);
|
console.error('[DialogSession] 发送取消响应失败:', submitError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* 处理 ask_user 事件,通过 WebView 显示问题并收集用户回答
|
* 处理 ask_user 事件,通过 WebView 显示问题并收集用户回答
|
||||||
*/
|
*/
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { submitAnswer } from './apiClient';
|
import { submitAnswer, submitToolConfirm } from './apiClient';
|
||||||
import type { AskUserEvent, AnswerRequest } from '../types/api';
|
import type { AskUserEvent, AnswerRequest } from '../types/api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,6 +107,30 @@ export class UserInteractionManager {
|
|||||||
taskId: string,
|
taskId: string,
|
||||||
answer: string
|
answer: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
// 检查是否是工具确认类型的问题
|
||||||
|
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 = {
|
const request: AnswerRequest = {
|
||||||
askId,
|
askId,
|
||||||
taskId,
|
taskId,
|
||||||
@ -124,6 +148,7 @@ export class UserInteractionManager {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消所有待处理的问题
|
* 取消所有待处理的问题
|
||||||
|
|||||||
Reference in New Issue
Block a user