feat(context): 优化对话压缩系统
- 添加独立摘要模型配置支持(SUMMARY_PROVIDER/MODEL/API_KEY/BASE_URL) - 添加 CompressionStatus 枚举和 DetailedCompressionResult 详细返回类型 - 实现压缩失败检测(空摘要、token膨胀) - 添加首条 user-assistant 对保护,确保上下文连贯性 - CompressionManager 支持独立摘要模型(优先使用小模型降低成本) - Agent 自动压缩时显示详细状态信息 - 更新相关测试用例
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import type { ModelMessage, LanguageModel } from 'ai';
|
||||
import { CompressionStatus } from '../../../src/context/types.js';
|
||||
|
||||
// Mock prune module
|
||||
const mockPrune = vi.fn();
|
||||
@@ -45,13 +46,13 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
vi.clearAllMocks();
|
||||
manager = new CompressionManager();
|
||||
|
||||
// 默认 mock 返回值
|
||||
// 默认 mock 返回值 - 使用 DetailedCompressionResult
|
||||
mockEstimateMessages.mockReturnValue(1000);
|
||||
mockFormat.mockReturnValue('1K');
|
||||
mockPrune.mockReturnValue({ messages: [], freedTokens: 0 });
|
||||
mockFilterCompacted.mockImplementation((msgs) => msgs);
|
||||
mockCompact.mockResolvedValue({ messages: [], freedTokens: 0 });
|
||||
mockSimpleCompact.mockReturnValue({ messages: [], freedTokens: 0 });
|
||||
mockCompact.mockResolvedValue({ messages: [], freedTokens: 0, type: 'none', status: CompressionStatus.NOOP });
|
||||
mockSimpleCompact.mockReturnValue({ messages: [], freedTokens: 0, type: 'none', status: CompressionStatus.NOOP });
|
||||
mockIsSummaryMessage.mockReturnValue(false);
|
||||
});
|
||||
|
||||
@@ -174,7 +175,7 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
it('有模型时使用 AI 压缩', async () => {
|
||||
const mockModel = {} as LanguageModel;
|
||||
manager.setModel(mockModel);
|
||||
mockCompact.mockResolvedValue({ messages: [], freedTokens: 2000 });
|
||||
mockCompact.mockResolvedValue({ messages: [], freedTokens: 2000, type: 'compaction', status: CompressionStatus.SUCCESS });
|
||||
|
||||
const messages = createMessages(5);
|
||||
const result = await manager.compact(messages);
|
||||
@@ -184,7 +185,7 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
});
|
||||
|
||||
it('无模型时使用简单压缩', async () => {
|
||||
mockSimpleCompact.mockReturnValue({ messages: [], freedTokens: 500 });
|
||||
mockSimpleCompact.mockReturnValue({ messages: [], freedTokens: 500, type: 'compaction', status: CompressionStatus.SUCCESS });
|
||||
|
||||
const messages = createMessages(5);
|
||||
const result = await manager.compact(messages);
|
||||
@@ -196,7 +197,9 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
|
||||
describe('compress - 自动压缩', () => {
|
||||
it('先 prune 后不需要 compact', async () => {
|
||||
mockEstimateMessages.mockReturnValue(10000); // 低于阈值
|
||||
mockEstimateMessages
|
||||
.mockReturnValueOnce(150000) // shouldCompress check - 高于阈值
|
||||
.mockReturnValueOnce(10000); // 第二次 shouldCompress check - prune 后低于阈值
|
||||
mockPrune.mockReturnValue({ messages: [], freedTokens: 500 });
|
||||
|
||||
const messages = createMessages(5);
|
||||
@@ -210,7 +213,7 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
it('prune 后仍需 compact', async () => {
|
||||
mockEstimateMessages.mockReturnValue(150000); // 高于阈值
|
||||
mockPrune.mockReturnValue({ messages: createMessages(3), freedTokens: 500 });
|
||||
mockSimpleCompact.mockReturnValue({ messages: [], freedTokens: 1000 });
|
||||
mockSimpleCompact.mockReturnValue({ messages: [], freedTokens: 1000, type: 'compaction', status: CompressionStatus.SUCCESS });
|
||||
|
||||
const messages = createMessages(5);
|
||||
const result = await manager.compress(messages);
|
||||
@@ -222,7 +225,7 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
it('只 compact 时类型为 compaction', async () => {
|
||||
mockEstimateMessages.mockReturnValue(150000);
|
||||
mockPrune.mockReturnValue({ messages: createMessages(5), freedTokens: 0 });
|
||||
mockSimpleCompact.mockReturnValue({ messages: [], freedTokens: 1000 });
|
||||
mockSimpleCompact.mockReturnValue({ messages: [], freedTokens: 1000, type: 'compaction', status: CompressionStatus.SUCCESS });
|
||||
|
||||
const messages = createMessages(5);
|
||||
const result = await manager.compress(messages);
|
||||
@@ -243,7 +246,7 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
it('足够消息时执行压缩', async () => {
|
||||
mockEstimateMessages.mockReturnValue(10000);
|
||||
mockPrune.mockReturnValue({ messages: createMessages(3), freedTokens: 500 });
|
||||
mockSimpleCompact.mockReturnValue({ messages: createMessages(2), freedTokens: 300 });
|
||||
mockSimpleCompact.mockReturnValue({ messages: createMessages(2), freedTokens: 300, type: 'compaction', status: CompressionStatus.SUCCESS });
|
||||
|
||||
const messages = createMessages(10);
|
||||
const result = await manager.forceCompress(messages);
|
||||
@@ -256,7 +259,7 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
manager.setModel(mockModel);
|
||||
mockEstimateMessages.mockReturnValue(10000);
|
||||
mockPrune.mockReturnValue({ messages: createMessages(5), freedTokens: 500 });
|
||||
mockCompact.mockResolvedValue({ messages: createMessages(2), freedTokens: 1000 });
|
||||
mockCompact.mockResolvedValue({ messages: createMessages(2), freedTokens: 1000, type: 'compaction', status: CompressionStatus.SUCCESS });
|
||||
|
||||
const messages = createMessages(10);
|
||||
await manager.forceCompress(messages);
|
||||
@@ -269,8 +272,9 @@ describe('CompressionManager - 压缩管理器扩展测试', () => {
|
||||
manager.setModel(mockModel);
|
||||
mockEstimateMessages.mockReturnValue(10000);
|
||||
mockPrune.mockReturnValue({ messages: createMessages(5), freedTokens: 500 });
|
||||
mockCompact.mockRejectedValue(new Error('AI error'));
|
||||
mockSimpleCompact.mockReturnValue({ messages: createMessages(2), freedTokens: 800 });
|
||||
// 使用 FAILED 状态而不是 reject
|
||||
mockCompact.mockResolvedValue({ messages: createMessages(5), freedTokens: 0, type: 'none', status: CompressionStatus.FAILED_ERROR });
|
||||
mockSimpleCompact.mockReturnValue({ messages: createMessages(2), freedTokens: 800, type: 'compaction', status: CompressionStatus.SUCCESS });
|
||||
|
||||
const messages = createMessages(10);
|
||||
const result = await manager.forceCompress(messages);
|
||||
|
||||
Reference in New Issue
Block a user