- Rewrite context-compactor.test.ts to use intelligenceClient - Rewrite heartbeat-reflection.test.ts to use intelligenceClient - Rewrite swarm-skills.test.ts to use intelligenceClient - Update CLAUDE.md architecture section for unified intelligence layer All tests now mock Tauri backend calls for unit testing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
126 lines
3.9 KiB
TypeScript
126 lines
3.9 KiB
TypeScript
/**
|
|
* Tests for Context Compactor (Phase 2)
|
|
*
|
|
* Covers: token estimation, threshold checking, memory flush, compaction
|
|
*
|
|
* Now uses intelligenceClient which delegates to Rust backend.
|
|
* These tests mock the backend calls for unit testing.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import {
|
|
intelligenceClient,
|
|
type CompactableMessage,
|
|
} from '../../desktop/src/lib/intelligence-client';
|
|
|
|
// === Mock localStorage ===
|
|
|
|
const localStorageMock = (() => {
|
|
let store: Record<string, string> = {};
|
|
return {
|
|
getItem: (key: string) => store[key] ?? null,
|
|
setItem: (key: string, value: string) => { store[key] = value; },
|
|
removeItem: (key: string) => { delete store[key]; },
|
|
clear: () => { store = {}; },
|
|
};
|
|
})();
|
|
|
|
vi.stubGlobal('localStorage', localStorageMock);
|
|
|
|
// === Mock Tauri invoke ===
|
|
vi.mock('@tauri-apps/api/core', () => ({
|
|
invoke: vi.fn(async (cmd: string, _args?: unknown) => {
|
|
// Mock responses for compactor commands
|
|
if (cmd === 'compactor_check_threshold') {
|
|
return {
|
|
should_compact: false,
|
|
current_tokens: 100,
|
|
threshold: 15000,
|
|
urgency: 'none',
|
|
};
|
|
}
|
|
if (cmd === 'compactor_compact') {
|
|
return {
|
|
compacted_messages: _args?.messages?.slice(-4) || [],
|
|
summary: '压缩摘要:讨论了技术方案',
|
|
original_count: _args?.messages?.length || 0,
|
|
retained_count: 4,
|
|
flushed_memories: 0,
|
|
tokens_before_compaction: 1000,
|
|
tokens_after_compaction: 200,
|
|
};
|
|
}
|
|
return null;
|
|
}),
|
|
}));
|
|
|
|
// === Helpers ===
|
|
|
|
function makeMessages(count: number, contentLength: number = 100): CompactableMessage[] {
|
|
const msgs: CompactableMessage[] = [];
|
|
for (let i = 0; i < count; i++) {
|
|
msgs.push({
|
|
role: i % 2 === 0 ? 'user' : 'assistant',
|
|
content: '测试消息内容'.repeat(Math.ceil(contentLength / 6)).slice(0, contentLength),
|
|
id: `msg_${i}`,
|
|
timestamp: new Date(Date.now() - (count - i) * 60000).toISOString(),
|
|
});
|
|
}
|
|
return msgs;
|
|
}
|
|
|
|
// =============================================
|
|
// ContextCompactor Tests (via intelligenceClient)
|
|
// =============================================
|
|
|
|
describe('ContextCompactor (via intelligenceClient)', () => {
|
|
beforeEach(() => {
|
|
localStorageMock.clear();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('checkThreshold', () => {
|
|
it('returns check result with expected structure', async () => {
|
|
const msgs = makeMessages(4);
|
|
const check = await intelligenceClient.compactor.checkThreshold(msgs);
|
|
|
|
expect(check).toHaveProperty('should_compact');
|
|
expect(check).toHaveProperty('current_tokens');
|
|
expect(check).toHaveProperty('threshold');
|
|
expect(check).toHaveProperty('urgency');
|
|
});
|
|
|
|
it('returns none urgency for small conversations', async () => {
|
|
const msgs = makeMessages(4);
|
|
const check = await intelligenceClient.compactor.checkThreshold(msgs);
|
|
expect(check.urgency).toBe('none');
|
|
});
|
|
});
|
|
|
|
describe('compact', () => {
|
|
it('returns compaction result with expected structure', async () => {
|
|
const msgs = makeMessages(20);
|
|
|
|
const result = await intelligenceClient.compactor.compact(msgs, 'agent-1');
|
|
|
|
expect(result).toHaveProperty('compacted_messages');
|
|
expect(result).toHaveProperty('summary');
|
|
expect(result).toHaveProperty('original_count');
|
|
expect(result).toHaveProperty('retained_count');
|
|
});
|
|
|
|
it('generates a summary', async () => {
|
|
const msgs = makeMessages(20);
|
|
const result = await intelligenceClient.compactor.compact(msgs, 'agent-1');
|
|
|
|
expect(result.summary).toBeDefined();
|
|
expect(result.summary.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('handles empty message list', async () => {
|
|
const result = await intelligenceClient.compactor.compact([], 'agent-1');
|
|
expect(result).toHaveProperty('retained_count');
|
|
});
|
|
});
|
|
});
|