feat: 添加对话压缩功能和上下文使用情况显示

- 新增 context 模块实现 Prune 和 Compaction 压缩策略
- Prune: 将旧工具调用结果替换为占位符
- Compaction: 使用 AI 生成对话摘要
- CLI 提示符显示上下文使用量 [used/available]
- 添加 /compact 命令手动压缩对话
- 添加 /context 命令查看上下文详情
- Agent 集成自动压缩 (85%阈值) 和强制压缩功能
This commit is contained in:
2025-12-11 10:59:43 +08:00
parent dddec9b6d5
commit c6f8ba95ec
8 changed files with 955 additions and 9 deletions
+61 -1
View File
@@ -12,6 +12,11 @@ import type { Tool, ToolResult, Message, AgentConfig, ProviderType } from '../ty
import { buildZodSchema } from '../types/index.js';
import { ToolRegistry } from '../tools/registry.js';
import { SessionManager } from '../session/index.js';
import {
CompressionManager,
type TokenUsage,
type CompressionConfig,
} from '../context/index.js';
// Provider 工厂函数类型
type ProviderFactory = (apiKey: string) => (model: string) => LanguageModel;
@@ -45,7 +50,10 @@ export class Agent {
// 会话管理器(可选)
private sessionManager: SessionManager | null = null;
constructor(config: AgentConfig) {
// 压缩管理器
private compressionManager: CompressionManager;
constructor(config: AgentConfig, compressionConfig?: Partial<CompressionConfig>) {
this.config = config;
const providerFactory = providers[config.provider];
@@ -53,6 +61,11 @@ export class Agent {
throw new Error(`不支持的 provider: ${config.provider}`);
}
this.getModel = providerFactory(config.apiKey);
// 初始化压缩管理器
this.compressionManager = new CompressionManager(compressionConfig);
// 设置模型用于生成摘要
this.compressionManager.setModel(this.getModel(config.model));
}
/**
@@ -230,6 +243,17 @@ export class Agent {
// 将完整的响应消息添加到历史(包括工具调用和结果)
this.conversationHistory.push(...responseMessages);
// 检查是否需要自动压缩
if (this.compressionManager.shouldCompress(this.conversationHistory)) {
const result = await this.compressionManager.compress(this.conversationHistory);
if (result.freedTokens > 0) {
this.conversationHistory = result.messages;
if (onStream) {
onStream(`\n[自动压缩: 释放了 ${(result.freedTokens / 1000).toFixed(1)}k tokens]\n`);
}
}
}
// 持久化会话
await this.persistSession();
@@ -294,4 +318,40 @@ export class Agent {
};
}
}
/**
* 获取当前上下文使用情况
*/
getContextUsage(): TokenUsage {
return this.compressionManager.calculateUsage(this.conversationHistory);
}
/**
* 获取格式化的上下文使用情况(用于 CLI 显示)
*/
getContextUsageFormatted(): string {
return this.compressionManager.formatUsage(this.conversationHistory);
}
/**
* 获取压缩管理器
*/
getCompressionManager(): CompressionManager {
return this.compressionManager;
}
/**
* 手动压缩对话历史(用于 /compact 命令)
*/
async compactHistory(): Promise<{ freedTokens: number; type: string }> {
const result = await this.compressionManager.forceCompress(this.conversationHistory);
if (result.freedTokens > 0) {
this.conversationHistory = result.messages;
await this.persistSession();
}
return {
freedTokens: result.freedTokens,
type: result.type,
};
}
}