feat:实现任务历史加载功能 - 完整还原对话样式
主要改进: 1. 实现selectConversation功能,支持点击任务历史列表加载会话 2. 优化会话存储格式,保存完整的segments信息(包括工具调用) 3. 添加旧格式到新格式的自动转换,兼容历史数据 4. 改进错误处理,自动清理无效的空任务目录 5. 优化路径编码逻辑,确保跨平台一致性 6. 前端支持clearChat、addUserMessage、addAiMessage命令 技术细节: - 扩展AiMessage数据结构,添加segments字段 - 修改messageHandler保存逻辑,将完整segments保存到一条消息 - 实现loadTaskSession方法,加载指定任务的完整会话 - 添加自动清理机制,删除无效的空任务目录
This commit is contained in:
@ -11,6 +11,8 @@ import {
|
||||
abortCurrentDialog,
|
||||
} from "../utils/messageHandler";
|
||||
import { VCDViewerPanel } from "./VCDViewerPanel";
|
||||
import { ChatHistoryManager } from "../utils/chatHistoryManager";
|
||||
import { MessageType } from "../types/chatHistory";
|
||||
|
||||
/**
|
||||
* 创建并显示 IC 助手面板
|
||||
@ -96,14 +98,14 @@ export function showICHelperPanel(
|
||||
showICHelperPanel(context, panel.viewColumn);
|
||||
break;
|
||||
case "loadConversationHistory":
|
||||
// 加载会话历史(暂未实现)
|
||||
panel.webview.postMessage({
|
||||
command: "conversationHistory",
|
||||
history: [],
|
||||
});
|
||||
// 加载会话历史(支持分页)
|
||||
loadConversationHistory(panel, message.offset || 0, message.limit || 10);
|
||||
break;
|
||||
case "selectConversation":
|
||||
// 选择会话(暂未实现)
|
||||
// 选择会话
|
||||
if (message.conversationId) {
|
||||
selectConversation(panel, message.conversationId, context.extensionPath);
|
||||
}
|
||||
break;
|
||||
// 新增:处理用户回答
|
||||
case "submitAnswer":
|
||||
@ -302,3 +304,222 @@ function parseVCDSignals(content: string, maxSignals: number = 3) {
|
||||
|
||||
return signals;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载会话历史(支持分页)
|
||||
*/
|
||||
async function loadConversationHistory(
|
||||
panel: vscode.WebviewPanel,
|
||||
offset: number = 0,
|
||||
limit: number = 10
|
||||
) {
|
||||
try {
|
||||
const historyManager = ChatHistoryManager.getInstance();
|
||||
const workspacePath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
|
||||
if (!workspacePath) {
|
||||
// 没有打开的工作区,返回空历史
|
||||
panel.webview.postMessage({
|
||||
command: "conversationHistory",
|
||||
items: [],
|
||||
total: 0,
|
||||
hasMore: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取会话历史列表(支持分页)
|
||||
const result = await historyManager.getConversationHistoryList(
|
||||
workspacePath,
|
||||
offset,
|
||||
limit
|
||||
);
|
||||
|
||||
// 发送会话历史到前端
|
||||
panel.webview.postMessage({
|
||||
command: "conversationHistory",
|
||||
items: result.items,
|
||||
total: result.total,
|
||||
hasMore: result.hasMore,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("加载会话历史失败:", error);
|
||||
// 发生错误时返回空历史
|
||||
panel.webview.postMessage({
|
||||
command: "conversationHistory",
|
||||
items: [],
|
||||
total: 0,
|
||||
hasMore: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择并加载指定的会话
|
||||
*/
|
||||
async function selectConversation(
|
||||
panel: vscode.WebviewPanel,
|
||||
taskId: string,
|
||||
extensionPath: string
|
||||
) {
|
||||
try {
|
||||
const historyManager = ChatHistoryManager.getInstance();
|
||||
const workspacePath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
|
||||
if (!workspacePath) {
|
||||
vscode.window.showErrorMessage("没有打开的工作区");
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载任务会话
|
||||
const taskSession = await historyManager.loadTaskSession(workspacePath, taskId);
|
||||
|
||||
if (!taskSession) {
|
||||
vscode.window.showErrorMessage(`加载任务 ${taskId} 失败: 任务不存在或数据损坏`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 切换到该任务
|
||||
const switched = await historyManager.switchTask(workspacePath, taskId);
|
||||
if (!switched) {
|
||||
vscode.window.showErrorMessage(`切换到任务 ${taskId} 失败`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 清空当前聊天界面
|
||||
panel.webview.postMessage({
|
||||
command: "clearChat"
|
||||
});
|
||||
|
||||
// 将会话历史消息转换为 segments 格式并发送到前端显示
|
||||
const segments: any[] = [];
|
||||
let i = 0;
|
||||
|
||||
while (i < taskSession.messages.length) {
|
||||
const message = taskSession.messages[i];
|
||||
|
||||
if (message.type === MessageType.USER) {
|
||||
// 用户消息 - 如果有累积的 segments,先发送
|
||||
if (segments.length > 0) {
|
||||
panel.webview.postMessage({
|
||||
command: "receiveSegments",
|
||||
segments: [...segments]
|
||||
});
|
||||
segments.length = 0;
|
||||
}
|
||||
|
||||
// 发送用户消息
|
||||
const textContent = message.contents?.find(c => c.type === 'TEXT');
|
||||
if (textContent && 'text' in textContent) {
|
||||
panel.webview.postMessage({
|
||||
command: "addUserMessage",
|
||||
text: textContent.text
|
||||
});
|
||||
}
|
||||
i++;
|
||||
} else if (message.type === MessageType.AI) {
|
||||
// AI消息 - 如果有 segments,直接使用
|
||||
if (message.segments && message.segments.length > 0) {
|
||||
panel.webview.postMessage({
|
||||
command: "receiveSegments",
|
||||
segments: message.segments
|
||||
});
|
||||
i++;
|
||||
} else {
|
||||
// 旧格式:需要转换为 segments
|
||||
// 收集连续的 AI 消息、工具调用和工具结果
|
||||
if (message.text) {
|
||||
segments.push({
|
||||
type: 'text',
|
||||
content: message.text
|
||||
});
|
||||
}
|
||||
|
||||
// 检查是否有工具调用
|
||||
if (message.toolExecutionRequests && message.toolExecutionRequests.length > 0) {
|
||||
for (const toolReq of message.toolExecutionRequests) {
|
||||
// 查找对应的工具执行结果
|
||||
let toolResult = '';
|
||||
if (i + 1 < taskSession.messages.length) {
|
||||
const nextMsg = taskSession.messages[i + 1];
|
||||
if (nextMsg.type === MessageType.TOOL_EXECUTION_RESULT &&
|
||||
nextMsg.id === toolReq.id) {
|
||||
toolResult = nextMsg.text;
|
||||
i++; // 跳过工具结果消息
|
||||
}
|
||||
}
|
||||
|
||||
segments.push({
|
||||
type: 'tool',
|
||||
toolName: toolReq.name,
|
||||
askId: toolReq.id,
|
||||
toolResult: toolResult
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
// 继续收集后续的 AI 消息,直到遇到用户消息或有 segments 的 AI 消息
|
||||
while (i < taskSession.messages.length) {
|
||||
const nextMsg = taskSession.messages[i];
|
||||
if (nextMsg.type === MessageType.USER) {
|
||||
break;
|
||||
}
|
||||
if (nextMsg.type === MessageType.AI) {
|
||||
if (nextMsg.segments && nextMsg.segments.length > 0) {
|
||||
break;
|
||||
}
|
||||
if (nextMsg.text) {
|
||||
segments.push({
|
||||
type: 'text',
|
||||
content: nextMsg.text
|
||||
});
|
||||
}
|
||||
if (nextMsg.toolExecutionRequests && nextMsg.toolExecutionRequests.length > 0) {
|
||||
for (const toolReq of nextMsg.toolExecutionRequests) {
|
||||
let toolResult = '';
|
||||
if (i + 1 < taskSession.messages.length) {
|
||||
const resultMsg = taskSession.messages[i + 1];
|
||||
if (resultMsg.type === MessageType.TOOL_EXECUTION_RESULT &&
|
||||
resultMsg.id === toolReq.id) {
|
||||
toolResult = resultMsg.text;
|
||||
i++; // 跳过工具结果消息
|
||||
}
|
||||
}
|
||||
segments.push({
|
||||
type: 'tool',
|
||||
toolName: toolReq.name,
|
||||
askId: toolReq.id,
|
||||
toolResult: toolResult
|
||||
});
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} else if (nextMsg.type === MessageType.TOOL_EXECUTION_RESULT) {
|
||||
// 独立的工具结果(没有被上面处理的)
|
||||
i++;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// 发送剩余的 segments
|
||||
if (segments.length > 0) {
|
||||
panel.webview.postMessage({
|
||||
command: "receiveSegments",
|
||||
segments: segments
|
||||
});
|
||||
}
|
||||
|
||||
vscode.window.showInformationMessage(`已加载会话: ${taskSession.meta.taskName}`);
|
||||
} catch (error) {
|
||||
console.error("选择会话失败:", error);
|
||||
vscode.window.showErrorMessage(`加载会话失败: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user