/**
* Unit tests for ConsolidationEngine
*/
import { beforeEach, describe, expect, it } from "vitest";
import { ConsolidationEngine } from "../../cognitive/ConsolidationEngine.js";
import { Context, Episode } from "../../types/core.js";
describe("ConsolidationEngine", () => {
let consolidationEngine: ConsolidationEngine;
let mockContext: Context;
beforeEach(async () => {
consolidationEngine = new ConsolidationEngine({
consolidation_threshold: 0.3, // Lower threshold for testing
pattern_similarity_threshold: 0.3, // Lower threshold for testing
minimum_episode_count: 2,
importance_weight: 0.4,
recency_weight: 0.3,
frequency_weight: 0.3,
max_patterns_per_cycle: 10,
pruning_threshold: 0.1,
});
mockContext = {
session_id: "test-session",
domain: "test-domain",
urgency: 0.5,
complexity: 0.6,
};
await consolidationEngine.initialize();
});
describe("initialization", () => {
it("should initialize successfully", async () => {
const status = consolidationEngine.getStatus();
expect(status.initialized).toBe(true);
expect(status.name).toBe("ConsolidationEngine");
});
it("should start with empty consolidation history", () => {
const stats = consolidationEngine.getConsolidationStats();
expect(stats.length).toBe(0);
});
});
describe("pattern extraction", () => {
it("should extract patterns from similar episodes", () => {
const episodes: Episode[] = [
{
content: { text: "Learning about machine learning algorithms" },
context: { ...mockContext, domain: "ai" },
timestamp: Date.now() - 3600000,
emotional_tags: ["curious"],
importance: 0.8,
decay_factor: 1.0,
},
{
content: { text: "Studying machine learning techniques" },
context: { ...mockContext, domain: "ai" },
timestamp: Date.now() - 1800000,
emotional_tags: ["focused"],
importance: 0.7,
decay_factor: 1.0,
},
{
content: { text: "Reading about machine learning applications" },
context: { ...mockContext, domain: "ai" },
timestamp: Date.now() - 900000,
emotional_tags: ["interested"],
importance: 0.9,
decay_factor: 1.0,
},
];
const patterns = consolidationEngine.extractPatterns(episodes);
expect(patterns.length).toBeGreaterThan(0);
expect(patterns[0].confidence).toBeGreaterThan(0);
expect(patterns[0].salience).toBeGreaterThan(0);
});
it("should not extract patterns from insufficient episodes", () => {
const episodes: Episode[] = [
{
content: { text: "Single episode" },
context: mockContext,
timestamp: Date.now(),
emotional_tags: [],
importance: 0.8,
decay_factor: 1.0,
},
];
const patterns = consolidationEngine.extractPatterns(episodes);
expect(patterns.length).toBe(0);
});
it("should limit patterns to max per cycle", () => {
const smallEngine = new ConsolidationEngine({
max_patterns_per_cycle: 1,
});
// Create many similar episodes that could generate multiple patterns
const episodes: Episode[] = [];
for (let i = 0; i < 10; i++) {
episodes.push({
content: { text: `Learning topic ${i}`, category: "education" },
context: { ...mockContext, domain: "education" },
timestamp: Date.now() - i * 1000,
emotional_tags: ["learning"],
importance: 0.8,
decay_factor: 1.0,
});
}
const patterns = smallEngine.extractPatterns(episodes);
expect(patterns.length).toBeLessThanOrEqual(1);
});
});
describe("consolidation process", () => {
it("should consolidate episodes into concepts", () => {
const episodes: Episode[] = [
{
content: { text: "Neural networks learn patterns from data" },
context: { ...mockContext, domain: "ai" },
timestamp: Date.now() - 7200000,
emotional_tags: ["fascinated"],
importance: 0.9,
decay_factor: 0.8,
},
{
content: { text: "Deep neural networks use multiple layers" },
context: { ...mockContext, domain: "ai" },
timestamp: Date.now() - 3600000,
emotional_tags: ["curious"],
importance: 0.8,
decay_factor: 0.9,
},
{
content: { text: "Neural network training requires large datasets" },
context: { ...mockContext, domain: "ai" },
timestamp: Date.now() - 1800000,
emotional_tags: ["understanding"],
importance: 0.85,
decay_factor: 0.95,
},
];
const concepts = consolidationEngine.consolidate(episodes);
expect(concepts.length).toBeGreaterThan(0);
expect(concepts[0].id).toBeDefined();
expect(concepts[0].content).toBeDefined();
expect(concepts[0].activation).toBeGreaterThan(0);
});
it("should return empty array for insufficient episodes", () => {
const episodes: Episode[] = [
{
content: { text: "Single episode" },
context: mockContext,
timestamp: Date.now(),
emotional_tags: [],
importance: 0.8,
decay_factor: 1.0,
},
];
const concepts = consolidationEngine.consolidate(episodes);
expect(concepts.length).toBe(0);
});
it("should track consolidation results", () => {
const episodes: Episode[] = [
{
content: { text: "First learning experience" },
context: mockContext,
timestamp: Date.now() - 3600000,
emotional_tags: ["learning"],
importance: 0.8,
decay_factor: 1.0,
},
{
content: { text: "Second learning experience" },
context: mockContext,
timestamp: Date.now() - 1800000,
emotional_tags: ["learning"],
importance: 0.7,
decay_factor: 1.0,
},
];
consolidationEngine.consolidate(episodes);
const lastResult = consolidationEngine.getLastConsolidationResult();
expect(lastResult).toBeDefined();
expect(lastResult?.episodes_processed).toBe(2);
const stats = consolidationEngine.getConsolidationStats();
expect(stats.length).toBe(1);
});
});
describe("connection strengthening", () => {
it("should strengthen connections between related concepts", () => {
const concepts = [
{
id: "concept-1",
content: { text: "Machine learning algorithms" },
embedding: [0.1, 0.2, 0.3, 0.4],
relations: [],
activation: 0.8,
last_accessed: Date.now(),
},
{
id: "concept-2",
content: { text: "Neural network architectures" },
embedding: [0.15, 0.25, 0.35, 0.45], // Similar to concept-1
relations: [],
activation: 0.7,
last_accessed: Date.now(),
},
];
const strengthenedCount =
consolidationEngine.strengthenConnections(concepts);
expect(strengthenedCount).toBeGreaterThanOrEqual(0);
});
it("should not strengthen weak connections", () => {
const concepts = [
{
id: "concept-1",
content: { text: "Machine learning" },
embedding: [1.0, 0.0, 0.0, 0.0],
relations: [],
activation: 0.8,
last_accessed: Date.now() - 7200000, // 2 hours ago
},
{
id: "concept-2",
content: { text: "Cooking recipes" },
embedding: [0.0, 1.0, 0.0, 0.0], // Very different
relations: [],
activation: 0.2, // Very different activation
last_accessed: Date.now() - 3600000, // 1 hour ago
},
];
const strengthenedCount =
consolidationEngine.strengthenConnections(concepts);
expect(strengthenedCount).toBe(0);
});
});
describe("consolidation statistics", () => {
it("should maintain consolidation history", () => {
const episodes1: Episode[] = [
{
content: { text: "First batch episode 1" },
context: mockContext,
timestamp: Date.now() - 3600000,
emotional_tags: ["learning"],
importance: 0.8,
decay_factor: 1.0,
},
{
content: { text: "First batch episode 2" },
context: mockContext,
timestamp: Date.now() - 1800000,
emotional_tags: ["learning"],
importance: 0.7,
decay_factor: 1.0,
},
];
const episodes2: Episode[] = [
{
content: { text: "Second batch episode 1" },
context: mockContext,
timestamp: Date.now() - 900000,
emotional_tags: ["understanding"],
importance: 0.9,
decay_factor: 1.0,
},
{
content: { text: "Second batch episode 2" },
context: mockContext,
timestamp: Date.now() - 450000,
emotional_tags: ["understanding"],
importance: 0.8,
decay_factor: 1.0,
},
];
consolidationEngine.consolidate(episodes1);
consolidationEngine.consolidate(episodes2);
const stats = consolidationEngine.getConsolidationStats();
expect(stats.length).toBe(2);
const lastResult = consolidationEngine.getLastConsolidationResult();
expect(lastResult?.episodes_processed).toBe(2);
});
});
describe("error handling", () => {
it("should handle invalid process input", async () => {
await expect(
consolidationEngine.process("invalid" as any)
).rejects.toThrow();
});
it("should handle valid process input", async () => {
const episodes: Episode[] = [
{
content: { text: "Process test episode 1" },
context: mockContext,
timestamp: Date.now() - 1800000,
emotional_tags: [],
importance: 0.8,
decay_factor: 1.0,
},
{
content: { text: "Process test episode 2" },
context: mockContext,
timestamp: Date.now() - 900000,
emotional_tags: [],
importance: 0.7,
decay_factor: 1.0,
},
];
const result = await consolidationEngine.process(episodes);
expect(Array.isArray(result)).toBe(true);
});
it("should handle empty episode arrays gracefully", () => {
const concepts = consolidationEngine.consolidate([]);
expect(concepts).toEqual([]);
});
});
describe("pattern classification", () => {
it("should classify different types of patterns", () => {
const emotionalEpisodes: Episode[] = [
{
content: { text: "Happy learning experience" },
context: mockContext,
timestamp: Date.now() - 3600000,
emotional_tags: ["happy", "excited"],
importance: 0.8,
decay_factor: 1.0,
},
{
content: { text: "Joyful discovery moment" },
context: mockContext,
timestamp: Date.now() - 1800000,
emotional_tags: ["joy", "excited"],
importance: 0.9,
decay_factor: 1.0,
},
];
const domainEpisodes: Episode[] = [
{
content: { text: "AI research discussion" },
context: { ...mockContext, domain: "artificial-intelligence" },
timestamp: Date.now() - 3600000,
emotional_tags: [],
importance: 0.8,
decay_factor: 1.0,
},
{
content: { text: "Machine learning study session" },
context: { ...mockContext, domain: "artificial-intelligence" },
timestamp: Date.now() - 1800000,
emotional_tags: [],
importance: 0.7,
decay_factor: 1.0,
},
];
const emotionalPatterns =
consolidationEngine.extractPatterns(emotionalEpisodes);
const domainPatterns =
consolidationEngine.extractPatterns(domainEpisodes);
// Should extract patterns (exact classification depends on implementation details)
expect(emotionalPatterns.length + domainPatterns.length).toBeGreaterThan(
0
);
});
});
describe("reset functionality", () => {
it("should reset consolidation state", () => {
const episodes: Episode[] = [
{
content: { text: "Reset test episode 1" },
context: mockContext,
timestamp: Date.now() - 1800000,
emotional_tags: [],
importance: 0.8,
decay_factor: 1.0,
},
{
content: { text: "Reset test episode 2" },
context: mockContext,
timestamp: Date.now() - 900000,
emotional_tags: [],
importance: 0.7,
decay_factor: 1.0,
},
];
consolidationEngine.consolidate(episodes);
expect(consolidationEngine.getConsolidationStats().length).toBe(1);
consolidationEngine.reset();
expect(consolidationEngine.getConsolidationStats().length).toBe(0);
expect(consolidationEngine.getLastConsolidationResult()).toBeNull();
});
});
});