Files
IC-Coder-Plugin/src/utils/chatHistoryManager.ts
XiaoFeng a1e88d473b fix: 修复自动压缩机制的多个问题
- P0: 新增工具执行结果追踪(trackToolResult),防止后端重启丢失
- P1: 版本冲突检查改为从尾部扫描,与加载逻辑一致
- P1: projectPath为空时添加用户警告通知
- 追踪工具错误信息,保留失败记录
2026-01-12 14:29:15 +08:00

924 lines
27 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as vscode from 'vscode';
import * as path from 'path';
import {
ChatMessage,
TaskMeta,
TaskSession,
ConversationMeta,
MessageType,
UserMessage,
AiMessage,
SystemMessage,
ToolExecutionResultMessage,
CompactionSummaryMessage
} from '../types/chatHistory';
import { CompactedMemory, CompactedMessage } from '../types/memory';
/**
* 会话历史管理器
* 按照设计文档实现:~/.iccoder/projects/{项目路径编码}/{taskId}/
*/
export class ChatHistoryManager {
private static instance: ChatHistoryManager;
private baseDir: string; // ~/.iccoder
private currentTaskId: string | null = null;
private currentProjectPath: string | null = null;
// 存储每个面板的任务信息taskId 和 projectPath
private panelTaskMap: Map<string, { taskId: string; projectPath: string }> = new Map();
// 追踪压缩后产生的新消息
private newMessagesSinceCompaction: CompactedMessage[] = [];
private constructor() {
// 设置存储路径: ~/.iccoder
const userHome = process.env.USERPROFILE || process.env.HOME || '';
this.baseDir = path.join(userHome, '.iccoder');
this.ensureBaseDir();
}
/**
* 项目路径编码
* 规则:
* - 替换 \ 和 / 为 --
* - 替换 : 为空
* 例如C:\Users\admin\Documents\Project -> C--Users--admin--Documents--Project
*/
private encodeProjectPath(projectPath: string): string {
return projectPath
.replace(/\\/g, '--') // 替换反斜杠为 --
.replace(/\//g, '--') // 替换正斜杠为 --
.replace(/:/g, ''); // 移除冒号
}
/**
* 生成任务ID
* 格式task_{date}_{sequence}
*/
private generateTaskId(): string {
const date = new Date().toISOString().split('T')[0].replace(/-/g, '');
const sequence = Math.random().toString(36).substr(2, 6);
return `task_${date}_${sequence}`;
}
/**
* 获取任务目录路径
*/
private getTaskDir(projectPath: string, taskId: string): string {
const encodedPath = this.encodeProjectPath(projectPath);
return path.join(this.baseDir, 'projects', encodedPath, taskId);
}
/**
* 确保基础目录存在
*/
private async ensureBaseDir(): Promise<void> {
try {
const uri = vscode.Uri.file(this.baseDir);
try {
await vscode.workspace.fs.stat(uri);
} catch {
// 目录不存在,创建它
await vscode.workspace.fs.createDirectory(uri);
console.log(`创建存储目录: ${this.baseDir}`);
}
} catch (error) {
console.error("创建存储目录失败:", error);
vscode.window.showErrorMessage("创建会话历史存储目录失败");
}
}
/**
* 确保任务目录存在
*/
private async ensureTaskDir(taskDir: string): Promise<void> {
try {
const uri = vscode.Uri.file(taskDir);
try {
await vscode.workspace.fs.stat(uri);
} catch {
// 目录不存在,创建它
await vscode.workspace.fs.createDirectory(uri);
console.log(`创建任务目录: ${taskDir}`);
}
} catch (error) {
console.error("创建任务目录失败:", error);
throw error;
}
}
/**
* 获取单例实例
*/
public static getInstance(): ChatHistoryManager {
if (!ChatHistoryManager.instance) {
ChatHistoryManager.instance = new ChatHistoryManager();
}
return ChatHistoryManager.instance;
}
/**
* 为面板设置任务ID
*/
public setPanelTask(panelId: string, taskId: string, projectPath: string): void {
this.panelTaskMap.set(panelId, { taskId, projectPath });
this.currentTaskId = taskId;
this.currentProjectPath = projectPath;
}
/**
* 获取面板的任务ID
*/
public getPanelTask(panelId: string): string | null {
const taskInfo = this.panelTaskMap.get(panelId);
return taskInfo ? taskInfo.taskId : null;
}
/**
* 切换到指定面板的任务上下文
*/
public switchToPanelTask(panelId: string): boolean {
const taskInfo = this.panelTaskMap.get(panelId);
if (taskInfo) {
this.currentTaskId = taskInfo.taskId;
this.currentProjectPath = taskInfo.projectPath;
return true;
}
return false;
}
/**
* 移除面板的任务映射
*/
public removePanelTask(panelId: string): void {
this.panelTaskMap.delete(panelId);
}
/**
* 创建新任务
*/
public async createTask(projectPath: string, taskName: string): Promise<TaskMeta> {
const taskId = this.generateTaskId();
const now = new Date().toISOString();
const meta: TaskMeta = {
taskId,
taskName,
projectPath,
createdAt: now,
updatedAt: now,
stats: {
credits: 0,
totalTokens: 0,
inputTokens: 0,
outputTokens: 0
}
};
this.currentTaskId = taskId;
this.currentProjectPath = projectPath;
// 创建任务目录
const taskDir = this.getTaskDir(projectPath, taskId);
await this.ensureTaskDir(taskDir);
// 保存 meta.json
await this.saveTaskMeta(meta);
// 初始化空的 conversation.json
await this.saveConversation([]);
return meta;
}
/**
* 保存任务元数据
*/
private async saveTaskMeta(meta: TaskMeta): Promise<void> {
if (!this.currentTaskId || !this.currentProjectPath) {
throw new Error("没有当前任务");
}
const taskDir = this.getTaskDir(this.currentProjectPath, this.currentTaskId);
const metaPath = path.join(taskDir, 'meta.json');
try {
const uri = vscode.Uri.file(metaPath);
const content = Buffer.from(JSON.stringify(meta, null, 2), 'utf-8');
await vscode.workspace.fs.writeFile(uri, content);
} catch (error) {
console.error("保存任务元数据失败:", error);
throw error;
}
}
/**
* 加载任务元数据
*/
private async loadTaskMeta(): Promise<TaskMeta | null> {
if (!this.currentTaskId || !this.currentProjectPath) {
return null;
}
const taskDir = this.getTaskDir(this.currentProjectPath, this.currentTaskId);
const metaPath = path.join(taskDir, 'meta.json');
try {
const uri = vscode.Uri.file(metaPath);
const content = await vscode.workspace.fs.readFile(uri);
const data = Buffer.from(content).toString('utf-8');
return JSON.parse(data);
} catch (error) {
// 文件不存在或读取失败
return null;
}
}
/**
* 保存对话历史conversation.json
*/
private async saveConversation(messages: ChatMessage[]): Promise<void> {
if (!this.currentTaskId || !this.currentProjectPath) {
throw new Error("没有当前任务");
}
const taskDir = this.getTaskDir(this.currentProjectPath, this.currentTaskId);
const conversationPath = path.join(taskDir, 'conversation.json');
try {
const uri = vscode.Uri.file(conversationPath);
const content = Buffer.from(JSON.stringify(messages, null, 2), 'utf-8');
await vscode.workspace.fs.writeFile(uri, content);
} catch (error) {
console.error("保存对话历史失败:", error);
throw error;
}
}
/**
* 加载对话历史
*/
private async loadConversation(): Promise<ChatMessage[]> {
if (!this.currentTaskId || !this.currentProjectPath) {
return [];
}
const taskDir = this.getTaskDir(this.currentProjectPath, this.currentTaskId);
const conversationPath = path.join(taskDir, 'conversation.json');
try {
const uri = vscode.Uri.file(conversationPath);
const content = await vscode.workspace.fs.readFile(uri);
const data = Buffer.from(content).toString('utf-8');
return JSON.parse(data);
} catch (error) {
// 文件不存在或读取失败
return [];
}
}
/**
* 追加对话元数据conversation_meta.jsonl
*/
private async appendConversationMeta(meta: ConversationMeta): Promise<void> {
if (!this.currentTaskId || !this.currentProjectPath) {
throw new Error("没有当前任务");
}
const taskDir = this.getTaskDir(this.currentProjectPath, this.currentTaskId);
const metaPath = path.join(taskDir, 'conversation_meta.jsonl');
try {
const uri = vscode.Uri.file(metaPath);
const line = JSON.stringify(meta) + '\n';
// 读取现有内容
let existingContent = '';
try {
const content = await vscode.workspace.fs.readFile(uri);
existingContent = Buffer.from(content).toString('utf-8');
} catch {
// 文件不存在,忽略错误
}
// 追加新内容
const newContent = existingContent + line;
await vscode.workspace.fs.writeFile(uri, Buffer.from(newContent, 'utf-8'));
} catch (error) {
console.error("追加对话元数据失败:", error);
throw error;
}
}
/**
* 确保有当前任务,如果没有则抛出错误
*/
private async ensureCurrentTask(): Promise<void> {
if (!this.currentTaskId || !this.currentProjectPath) {
throw new Error("没有当前任务上下文,请确保已正确初始化面板任务");
}
}
/**
* 添加用户消息
*/
public async addUserMessage(text: string): Promise<void> {
await this.ensureCurrentTask();
const messages = await this.loadConversation();
const userMessage: UserMessage = {
type: MessageType.USER,
contents: [{ type: "TEXT", text }]
};
messages.push(userMessage);
await this.saveConversation(messages);
// 更新任务元数据
await this.updateTaskTimestamp();
}
/**
* 添加AI消息
*/
public async addAiMessage(text: string, toolRequests?: any[], segments?: any[]): Promise<void> {
await this.ensureCurrentTask();
const messages = await this.loadConversation();
const aiMessage: AiMessage = {
type: MessageType.AI,
text,
toolExecutionRequests: toolRequests,
segments // 保存完整的 segments 信息
};
messages.push(aiMessage);
await this.saveConversation(messages);
// 更新任务元数据
await this.updateTaskTimestamp();
}
/**
* 添加系统消息
*/
public async addSystemMessage(text: string): Promise<void> {
await this.ensureCurrentTask();
const messages = await this.loadConversation();
const systemMessage: SystemMessage = {
type: MessageType.SYSTEM,
text
};
messages.push(systemMessage);
await this.saveConversation(messages);
}
/**
* 添加工具执行结果消息
*/
public async addToolExecutionResult(id: string, toolName: string, result: string): Promise<void> {
await this.ensureCurrentTask();
const messages = await this.loadConversation();
const toolResultMessage: ToolExecutionResultMessage = {
type: MessageType.TOOL_EXECUTION_RESULT,
id,
toolName,
text: result
};
messages.push(toolResultMessage);
await this.saveConversation(messages);
}
/**
* 记录对话轮次元数据
*/
public async recordTurnMeta(
turnId: number,
usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number },
model?: string,
duration?: number
): Promise<void> {
const meta: ConversationMeta = {
turnId,
timestamp: new Date().toISOString(),
usage,
model,
duration
};
await this.appendConversationMeta(meta);
// 更新任务统计
if (usage) {
await this.updateTaskStats(usage);
}
}
/**
* 更新任务时间戳
*/
private async updateTaskTimestamp(): Promise<void> {
const meta = await this.loadTaskMeta();
if (meta) {
meta.updatedAt = new Date().toISOString();
await this.saveTaskMeta(meta);
}
}
/**
* 更新任务统计
*/
private async updateTaskStats(usage: { inputTokens?: number; outputTokens?: number; totalTokens?: number }): Promise<void> {
const meta = await this.loadTaskMeta();
if (meta) {
meta.stats.inputTokens += usage.inputTokens || 0;
meta.stats.outputTokens += usage.outputTokens || 0;
meta.stats.totalTokens += usage.totalTokens || 0;
meta.updatedAt = new Date().toISOString();
await this.saveTaskMeta(meta);
}
}
/**
* 获取当前任务会话
*/
public async getCurrentTaskSession(): Promise<TaskSession | null> {
const meta = await this.loadTaskMeta();
if (!meta) {
return null;
}
const messages = await this.loadConversation();
const conversationMeta = await this.loadConversationMeta();
return {
meta,
messages,
conversationMeta
};
}
/**
* 加载对话元数据
*/
private async loadConversationMeta(): Promise<ConversationMeta[]> {
if (!this.currentTaskId || !this.currentProjectPath) {
return [];
}
const taskDir = this.getTaskDir(this.currentProjectPath, this.currentTaskId);
const metaPath = path.join(taskDir, 'conversation_meta.jsonl');
try {
const uri = vscode.Uri.file(metaPath);
const content = await vscode.workspace.fs.readFile(uri);
const data = Buffer.from(content).toString('utf-8');
return data
.split('\n')
.filter(line => line.trim())
.map(line => JSON.parse(line));
} catch (error) {
// 文件不存在或读取失败
return [];
}
}
/**
* 列出项目的所有任务
*/
public async listProjectTasks(projectPath: string): Promise<TaskMeta[]> {
const encodedPath = this.encodeProjectPath(projectPath);
const projectDir = path.join(this.baseDir, 'projects', encodedPath);
try {
const uri = vscode.Uri.file(projectDir);
const entries = await vscode.workspace.fs.readDirectory(uri);
const tasks: TaskMeta[] = [];
for (const [taskId, type] of entries) {
if (type === vscode.FileType.Directory) {
const metaPath = path.join(projectDir, taskId, 'meta.json');
try {
const metaUri = vscode.Uri.file(metaPath);
const content = await vscode.workspace.fs.readFile(metaUri);
const data = Buffer.from(content).toString('utf-8');
tasks.push(JSON.parse(data));
} catch (error) {
console.error(`加载任务 ${taskId} 失败:`, error);
// 跳过无效的任务目录
// 尝试清理空目录
try {
const taskDirUri = vscode.Uri.file(path.join(projectDir, taskId));
const taskDirEntries = await vscode.workspace.fs.readDirectory(taskDirUri);
if (taskDirEntries.length === 0) {
// 目录为空,删除它
await vscode.workspace.fs.delete(taskDirUri, { recursive: false });
console.log(`已清理空任务目录: ${taskId}`);
}
} catch (cleanupError) {
// 清理失败,忽略错误
console.warn(`清理任务目录 ${taskId} 失败:`, cleanupError);
}
}
}
}
return tasks.sort((a, b) =>
new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
);
} catch (error) {
// 目录不存在
return [];
}
}
/**
* 切换到指定任务
*/
public async switchTask(projectPath: string, taskId: string): Promise<boolean> {
const taskDir = this.getTaskDir(projectPath, taskId);
const metaPath = path.join(taskDir, 'meta.json');
try {
const uri = vscode.Uri.file(metaPath);
await vscode.workspace.fs.stat(uri);
this.currentProjectPath = projectPath;
this.currentTaskId = taskId;
return true;
} catch {
return false;
}
}
/**
* 获取当前任务ID
*/
public getCurrentTaskId(): string | null {
return this.currentTaskId;
}
/**
* 获取基础目录
*/
public getBaseDir(): string {
return this.baseDir;
}
/**
* 加载指定任务的会话内容
* @param projectPath 项目路径
* @param taskId 任务ID
* @returns 任务会话内容如果任务不存在则返回null
*/
public async loadTaskSession(projectPath: string, taskId: string): Promise<TaskSession | null> {
const taskDir = this.getTaskDir(projectPath, taskId);
const metaPath = path.join(taskDir, 'meta.json');
try {
// 检查任务是否存在
const metaUri = vscode.Uri.file(metaPath);
const metaContent = await vscode.workspace.fs.readFile(metaUri);
const meta: TaskMeta = JSON.parse(Buffer.from(metaContent).toString('utf-8'));
// 读取会话内容
const conversationPath = path.join(taskDir, 'conversation.json');
let messages: ChatMessage[] = [];
try {
const conversationUri = vscode.Uri.file(conversationPath);
const conversationContent = await vscode.workspace.fs.readFile(conversationUri);
messages = JSON.parse(Buffer.from(conversationContent).toString('utf-8'));
} catch {
// 会话文件不存在,使用空数组
}
// 读取会话元数据
const conversationMetaPath = path.join(taskDir, 'conversation_meta.jsonl');
let conversationMeta: ConversationMeta[] = [];
try {
const metaUri = vscode.Uri.file(conversationMetaPath);
const content = await vscode.workspace.fs.readFile(metaUri);
const data = Buffer.from(content).toString('utf-8');
conversationMeta = data
.split('\n')
.filter(line => line.trim())
.map(line => JSON.parse(line));
} catch {
// 元数据文件不存在,使用空数组
}
return {
meta,
messages,
conversationMeta
};
} catch (error) {
console.error(`加载任务 ${taskId} 的会话失败:`, error);
return null;
}
}
/**
* 获取会话历史列表(支持分页)
* 返回格式:{ id: taskId, title: 第一句用户消息, timestamp: 创建时间 }
* @param projectPath 项目路径
* @param offset 偏移量从第几条开始默认0
* @param limit 每页数量默认10条
* @returns { items: 历史列表, total: 总数, hasMore: 是否还有更多 }
*/
public async getConversationHistoryList(
projectPath: string,
offset: number = 0,
limit: number = 10
): Promise<{
items: Array<{ id: string; title: string; timestamp: string }>;
total: number;
hasMore: boolean;
}> {
const tasks = await this.listProjectTasks(projectPath);
const total = tasks.length;
const historyList: Array<{ id: string; title: string; timestamp: string }> = [];
// 计算分页范围
const start = offset;
const end = Math.min(offset + limit, total);
const limitedTasks = tasks.slice(start, end);
for (const task of limitedTasks) {
// 读取该任务的 conversation.json 获取第一句用户消息
const taskDir = this.getTaskDir(task.projectPath, task.taskId);
const conversationPath = path.join(taskDir, 'conversation.json');
try {
const uri = vscode.Uri.file(conversationPath);
const content = await vscode.workspace.fs.readFile(uri);
const data = Buffer.from(content).toString('utf-8');
const messages: ChatMessage[] = JSON.parse(data);
// 找到第一条用户消息
const firstUserMessage = messages.find(msg => msg.type === MessageType.USER) as UserMessage | undefined;
let title = '未命名会话';
if (firstUserMessage && firstUserMessage.contents && firstUserMessage.contents.length > 0) {
const textContent = firstUserMessage.contents.find(c => c.type === 'TEXT');
if (textContent && 'text' in textContent) {
// 截取前50个字符作为标题
title = textContent.text.length > 50
? textContent.text.substring(0, 50) + '...'
: textContent.text;
}
}
historyList.push({
id: task.taskId,
title,
timestamp: task.createdAt
});
} catch (error) {
console.error(`读取任务 ${task.taskId} 的会话历史失败:`, error);
// 如果读取失败,使用任务名称作为标题
historyList.push({
id: task.taskId,
title: task.taskName || '未命名会话',
timestamp: task.createdAt
});
}
}
// 返回分页结果
return {
items: historyList,
total,
hasMore: end < total
};
}
// ========== 压缩数据相关方法 ==========
/**
* 保存压缩数据(存入 conversation.json 作为压缩摘要消息)
*/
public async saveCompactedData(compacted: CompactedMemory): Promise<void> {
// 尝试从多个来源获取 projectPath
let projectPath = this.currentProjectPath;
if (!projectPath) {
for (const [, taskInfo] of this.panelTaskMap) {
if (taskInfo.taskId === compacted.taskId) {
projectPath = taskInfo.projectPath;
break;
}
}
}
if (!projectPath) {
console.error('[ChatHistoryManager] 无法保存压缩数据projectPath 为空');
// 通知用户压缩数据保存失败
vscode.window.showWarningMessage(
'对话历史压缩数据保存失败:无法确定项目路径。后端重启后可能无法恢复完整对话历史。'
);
return;
}
// 读取现有对话历史
const taskDir = this.getTaskDir(projectPath, compacted.taskId);
const conversationPath = path.join(taskDir, 'conversation.json');
let messages: ChatMessage[] = [];
try {
const uri = vscode.Uri.file(conversationPath);
const content = await vscode.workspace.fs.readFile(uri);
messages = JSON.parse(Buffer.from(content).toString('utf-8'));
} catch {
// 文件不存在,使用空数组
}
// 版本检查:防止旧版本覆盖新版本(从尾部扫描,与加载逻辑一致)
let existingSummary: CompactionSummaryMessage | null = null;
for (let i = messages.length - 1; i >= 0; i--) {
if (messages[i].type === MessageType.COMPACTION_SUMMARY) {
existingSummary = messages[i] as CompactionSummaryMessage;
break;
}
}
if (existingSummary && existingSummary.version >= compacted.version) {
console.log(`[ChatHistoryManager] 跳过旧版本压缩数据: 现有版本=${existingSummary.version}, 新版本=${compacted.version}`);
return;
}
// 创建压缩摘要消息
const summaryMessage: CompactionSummaryMessage = {
type: MessageType.COMPACTION_SUMMARY,
summary: compacted.summary,
version: compacted.version,
compactedAt: compacted.compactedAt,
originalMessageCount: compacted.originalMessageCount,
compactedMessageCount: compacted.compactedMessageCount
};
// 添加到对话历史
messages.push(summaryMessage);
// 保存
const uri = vscode.Uri.file(conversationPath);
const content = Buffer.from(JSON.stringify(messages, null, 2), 'utf-8');
await vscode.workspace.fs.writeFile(uri, content);
// 重置新消息追踪
this.newMessagesSinceCompaction = [];
console.log(`[ChatHistoryManager] 压缩摘要已保存到 conversation.json: taskId=${compacted.taskId}`);
}
/**
* 加载压缩数据(从 conversation.json 构建)
*/
public async loadCompactedData(taskId: string): Promise<CompactedMemory | null> {
// 尝试从多个来源获取 projectPath
let projectPath = this.currentProjectPath;
if (!projectPath) {
for (const [, taskInfo] of this.panelTaskMap) {
if (taskInfo.taskId === taskId) {
projectPath = taskInfo.projectPath;
break;
}
}
}
if (!projectPath) {
console.log('[ChatHistoryManager] loadCompactedData: projectPath 为空');
return null;
}
// 读取 conversation.json
const taskDir = this.getTaskDir(projectPath, taskId);
const conversationPath = path.join(taskDir, 'conversation.json');
try {
const uri = vscode.Uri.file(conversationPath);
const content = await vscode.workspace.fs.readFile(uri);
const messages: ChatMessage[] = JSON.parse(Buffer.from(content).toString('utf-8'));
if (messages.length === 0) {
console.log('[ChatHistoryManager] conversation.json 为空');
return null;
}
// 从 conversation.json 构建 CompactedMemory
return this.buildCompactedMemoryFromConversation(taskId, messages);
} catch {
console.log('[ChatHistoryManager] conversation.json 不存在:', conversationPath);
return null;
}
}
/**
* 从 conversation.json 构建 CompactedMemory
*/
private buildCompactedMemoryFromConversation(taskId: string, messages: ChatMessage[]): CompactedMemory {
// 查找最后一个压缩摘要消息
let lastSummary: CompactionSummaryMessage | null = null;
let summaryIndex = -1;
for (let i = messages.length - 1; i >= 0; i--) {
if (messages[i].type === MessageType.COMPACTION_SUMMARY) {
lastSummary = messages[i] as CompactionSummaryMessage;
summaryIndex = i;
break;
}
}
// 获取摘要后的消息(或全部消息)
const recentMessages = summaryIndex >= 0
? messages.slice(summaryIndex + 1)
: messages;
// 转换为 CompactedMessage 格式
const compactedMessages: CompactedMessage[] = recentMessages.map(msg => ({
type: this.mapMessageType(msg.type),
content: this.extractMessageContent(msg)
}));
return {
taskId,
version: lastSummary?.version || Date.now(),
compactedAt: lastSummary?.compactedAt || new Date().toISOString(),
summary: lastSummary?.summary || '',
recentMessages: compactedMessages,
originalMessageCount: messages.length,
compactedMessageCount: compactedMessages.length
};
}
/**
* 映射消息类型
*/
private mapMessageType(type: MessageType): 'USER' | 'AI' | 'SYSTEM' | 'TOOL_RESULT' {
switch (type) {
case MessageType.USER: return 'USER';
case MessageType.AI: return 'AI';
case MessageType.SYSTEM: return 'SYSTEM';
case MessageType.TOOL_EXECUTION_RESULT: return 'TOOL_RESULT';
default: return 'USER';
}
}
/**
* 提取消息内容
*/
private extractMessageContent(msg: ChatMessage): string {
switch (msg.type) {
case MessageType.USER:
return (msg as UserMessage).contents?.[0]?.text || '';
case MessageType.AI:
return (msg as AiMessage).text || '';
case MessageType.SYSTEM:
return (msg as SystemMessage).text || '';
case MessageType.TOOL_EXECUTION_RESULT:
return (msg as ToolExecutionResultMessage).text || '';
default:
return '';
}
}
/**
* 获取压缩后产生的新消息
*/
public getNewMessagesSinceCompaction(): CompactedMessage[] {
return this.newMessagesSinceCompaction;
}
/**
* 追踪新消息(用户消息)
*/
public trackUserMessage(text: string): void {
this.newMessagesSinceCompaction.push({
type: 'USER',
content: text
});
}
/**
* 追踪新消息AI消息
*/
public trackAiMessage(text: string): void {
this.newMessagesSinceCompaction.push({
type: 'AI',
content: text
});
}
/**
* 追踪新消息(工具执行结果)
*/
public trackToolResult(toolName: string, result: string): void {
this.newMessagesSinceCompaction.push({
type: 'TOOL_RESULT',
content: `[${toolName}] ${result}`
});
}
}