23f7624596
ADR-166 MCP Bridge Security Lock / Static-source security lock (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / Compose default binds loopback + Mongo has auth (push) Failing after 2s
CodeQL Advanced / Analyze (rust) (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / plugin-agent-federation bindHost default (push) Failing after 1s
ADR-166 MCP Bridge Security Lock / Runtime behavior — 401 + terminal gate + fail-closed (push) Failing after 4s
business-pods-smoke / smoke (push) Failing after 1s
all-plugins-smoke / smoke-all (push) Failing after 2s
CI/CD Pipeline / Security & Code Quality (push) Failing after 1s
CI/CD Pipeline / Test Suite (ubuntu-latest) (push) Failing after 1s
CI/CD Pipeline / Build & Package (macos-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (ubuntu-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (windows-latest) (push) Has been skipped
CI/CD Pipeline / Documentation & Examples (push) Failing after 1s
Clone Tracker (14-day rolling) / Snapshot clones for ruflo ecosystem (push) Failing after 1s
CodeQL Advanced / Analyze (actions) (push) Failing after 1s
CodeQL Advanced / Analyze (javascript-typescript) (push) Failing after 1s
federation-peer-rust / stable-noop (push) Failing after 1s
metaharness-ci / score (push) Failing after 1s
metaharness-ci / router-compat (push) Failing after 0s
metaharness-ci / similarity-tests (push) Failing after 0s
no-agentbbs-smoke / smoke-without-agentbbs (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (windows-latest) (push) Has been skipped
codex-integration-audit / Codex integration audit (push) Failing after 1s
helpers-manifest-guard / guard (push) Failing after 1s
🔗 Cross-Agent Integration Tests / 🤝 Agent Coordination Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🧠 Memory Sharing Integration (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🛡️ Fault Tolerance Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / ⚡ Performance Integration Tests (push) Has been skipped
metaharness-ci / mcp-scan (push) Failing after 1s
metaharness-ci / eject-dryrun (push) Failing after 1s
metaharness-ci / metaharness-real-data (push) Failing after 0s
no-cli-optdep-bloat-2561 / guard (push) Failing after 1s
no-metaharness-smoke / smoke-without-metaharness (push) Failing after 1s
no-phantom-agentic-flow-subpath / guard (push) Failing after 1s
🔄 Automated Rollback Manager / 🚨 Failure Detection (push) Failing after 1s
V3 CI/CD Pipeline / Plugin hooks smoke / ubuntu-latest / Node 22 (push) Failing after 1s
V3 CI/CD Pipeline / ruflo-graph-intelligence build + test smoke (#2044, ADR-123) (push) Failing after 1s
CVE Audit Gate / Audit root (critical-blocking) (push) Failing after 2s
cost-tracker-smoke / smoke (push) Failing after 3s
oia-audit-weekly / audit (push) Failing after 2s
ruflo-agent-smoke / ruflo-agent structural smoke (push) Failing after 1s
📊 Status Badges Update / 📊 Update Status Badges (push) Failing after 1s
V3 CI/CD Pipeline / Static regression guards (#2267 YAML + (push) Failing after 1s
V3 CI/CD Pipeline / Test V3 Packages (push) Failing after 0s
V3 CI/CD Pipeline / agent_execute provider routing smoke (#2042) (push) Failing after 0s
CVE Audit Gate / Audit v3 (critical-blocking) (push) Failing after 1s
federation-peer-rust / stable-native (push) Failing after 2s
🔗 Cross-Agent Integration Tests / 🚀 Integration Test Setup (push) Failing after 2s
neural-trader-smoke / runtime-smoke (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (macos-latest) (push) Has been skipped
V3 CI/CD Pipeline / Build V3 (ubuntu-latest) (push) Has been skipped
V3 CI/CD Pipeline / Type Check V3 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 24 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 22 (push) Failing after 2s
V3 CI/CD Pipeline / browser rvf create flag smoke (#2015) (push) Failing after 0s
V3 CI/CD Pipeline / Dependency review (#2046) (push) Has been skipped
V3 CI/CD Pipeline / Supply-chain audit (#2046) (push) Failing after 0s
V3 CI/CD Pipeline / witness marker drift smoke (#2021) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader portfolio CG smoke (#2068, ADR-126 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader backtest signing smoke (#2068, ADR-126 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / kg-extract type-import classification smoke (#2049) (push) Failing after 0s
V3 CI/CD Pipeline / witness verify precondition smoke (#1880) (push) Failing after 2s
V3 CI/CD Pipeline / neural-trader pipeline risk-gate smoke (#2068, ADR-126 Phase 5) (push) Failing after 0s
V3 CI/CD Pipeline / neural-trader feature attribution smoke (#2068, ADR-126 Phase 6) (push) Failing after 0s
V3 CI/CD Pipeline / plugin-registry signature verification smoke (#1922, CWE-347) (push) Failing after 4s
V3 CI/CD Pipeline / memory stats legacy-DB smoke (#2120) (push) Failing after 4s
V3 CI/CD Pipeline / github deprecated actions smoke (#2089, ADR-127 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / graph query + pathfinder smoke (ADR-130 P2+P5) (push) Has been skipped
V3 CI/CD Pipeline / graph trajectory hooks smoke (ADR-130 P3) (push) Has been skipped
V3 CI/CD Pipeline / graph plugin adapter smoke (ADR-130 P4) (push) Has been skipped
V3 CI/CD Pipeline / graph benchmark (ADR-130 P6) (push) Has been skipped
V3 CI/CD Pipeline / statusline generator delegation smoke (#2195) (push) Failing after 1s
V3 CI/CD Pipeline / wizard init regression guard (#2206 (push) Failing after 1s
V3 CI/CD Pipeline / memory no-stray-db smoke (ADR-125 P7) (push) Failing after 1s
V3 CI/CD Pipeline / github-safe injection smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github actions pin smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github attribution opt-in smoke (#2089, ADR-127 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / pre-bash hook safety smoke (#2017) (push) Failing after 1s
V3 CI/CD Pipeline / Memory import smoke / ubuntu-latest (push) Failing after 0s
V3 CI/CD Pipeline / MCP protocol smoke / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / ruvllm WASM auto-init smoke (#2086) (push) Failing after 4s
V3 CI/CD Pipeline / MCP paired-tool round-trip smoke (#1889) (push) Failing after 1s
V3 CI/CD Pipeline / Plugin package install-safety (#1902/#1903/#1904) (push) Failing after 1s
V3 CI/CD Pipeline / Tool description discoverability (ADR-112) (push) Failing after 3s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (22) (push) Failing after 1s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (24) (push) Failing after 1s
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Vector-index dimension audit (#1947) (push) Failing after 0s
V3 CI/CD Pipeline / Hook-command install safety (#1921) (push) Failing after 1s
V3 CI/CD Pipeline / ToolOutputGuardrail smoke (ADR-131, (push) Failing after 1s
V3 CI/CD Pipeline / init-bundle invariants smoke (#2095, ADR-128 Phase 5) (push) Failing after 1s
V3 CI/CD Pipeline / wasm provider bridge smoke (ADR-129 P1) (push) Failing after 2s
V3 CI/CD Pipeline / wasm gallery CRUD smoke (ADR-129 P3) (push) Failing after 1s
V3 CI/CD Pipeline / wasm plugin bridge smoke (ADR-129 P4) (push) Failing after 0s
V3 CI/CD Pipeline / wasm compose smoke (ADR-129 P2) (push) Failing after 4s
V3 CI/CD Pipeline / graph schema smoke (ADR-130 P1) (push) Failing after 0s
Validate Marketplace / validate (push) Failing after 1s
🔍 Verification Pipeline / 🚀 Setup Verification (push) Failing after 1s
🔍 Verification Pipeline / 🛡️ Security Verification (push) Has been skipped
🔍 Verification Pipeline / 📝 Code Quality (push) Has been skipped
🔍 Verification Pipeline / 🧪 Test Verification (${{ matrix.os }}, Node ${{ matrix.node }}) (push) Has been skipped
🔍 Verification Pipeline / 🏗️ Build Verification (push) Has been skipped
🔍 Verification Pipeline / 📚 Documentation Verification (push) Has been skipped
CVE Audit Gate / High-severity report (warn only) (push) Has been cancelled
🔄 Automated Rollback Manager / 🔄 Execute Rollback (push) Has been cancelled
🔄 Automated Rollback Manager / ✅ Post-Rollback Verification (push) Has been cancelled
🔄 Automated Rollback Manager / 📊 Rollback Monitoring (push) Has been cancelled
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / windows-latest (push) Has been cancelled
🔄 Automated Rollback Manager / ⏳ Manual Rollback Approval (push) Has been cancelled
V3 CI/CD Pipeline / MCP protocol smoke / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Memory import smoke / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / ubuntu-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Publish to npm (alpha) (push) Has been cancelled
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / macos-latest / Node 22 (push) Has been cancelled
V3 CI/CD Pipeline / Plugin hooks smoke / macos-latest / Node 22 (push) Has been cancelled
CI/CD Pipeline / Deploy & Release (push) Has been cancelled
CI/CD Pipeline / CI Status (push) Has been cancelled
🔗 Cross-Agent Integration Tests / 📊 Integration Test Report (push) Has been cancelled
🔄 Automated Rollback Manager / 🔍 Pre-Rollback Validation (push) Has been cancelled
🔍 Verification Pipeline / ⚡ Performance Verification (push) Has been cancelled
🔍 Verification Pipeline / 📊 Verification Report (push) Has been cancelled
550 lines
17 KiB
TypeScript
550 lines
17 KiB
TypeScript
/**
|
|
* Pattern Learning and ReasoningBank Tests
|
|
*
|
|
* Tests for pattern extraction, memory distillation, and trajectory tracking:
|
|
* - Pattern extraction from trajectories
|
|
* - Memory distillation (4-step pipeline)
|
|
* - Trajectory tracking and judgment
|
|
* - Pattern evolution and consolidation
|
|
*
|
|
* Performance target: <10ms for learning operations
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import {
|
|
ReasoningBank,
|
|
createReasoningBank,
|
|
type RetrievalResult,
|
|
type ConsolidationResult,
|
|
} from '../src/reasoning-bank.js';
|
|
import type {
|
|
Trajectory,
|
|
TrajectoryVerdict,
|
|
DistilledMemory,
|
|
Pattern,
|
|
} from '../src/types.js';
|
|
|
|
// Helper function to create test trajectories
|
|
function createTestTrajectory(
|
|
quality: number = 0.75,
|
|
domain: 'code' | 'creative' | 'reasoning' | 'chat' | 'math' | 'general' = 'code',
|
|
steps: number = 5
|
|
): Trajectory {
|
|
return {
|
|
trajectoryId: `test-traj-${Date.now()}-${Math.random()}`,
|
|
context: `Test task for ${domain}`,
|
|
domain,
|
|
steps: Array.from({ length: steps }, (_, i) => ({
|
|
stepId: `step-${i}`,
|
|
timestamp: Date.now() + i * 100,
|
|
action: `action-${i}`,
|
|
stateBefore: new Float32Array(768).fill(i * 0.1),
|
|
stateAfter: new Float32Array(768).fill((i + 1) * 0.1),
|
|
reward: 0.5 + (i / steps) * (quality - 0.5) * 2,
|
|
})),
|
|
qualityScore: quality,
|
|
isComplete: true,
|
|
startTime: Date.now() - 1000,
|
|
endTime: Date.now(),
|
|
};
|
|
}
|
|
|
|
describe('ReasoningBank - Pattern Extraction', () => {
|
|
let bank: ReasoningBank;
|
|
|
|
beforeEach(() => {
|
|
bank = createReasoningBank({
|
|
maxTrajectories: 1000,
|
|
distillationThreshold: 0.6,
|
|
retrievalK: 3,
|
|
mmrLambda: 0.7,
|
|
});
|
|
});
|
|
|
|
it('should initialize correctly', () => {
|
|
expect(bank).toBeDefined();
|
|
const stats = bank.getStats();
|
|
expect(stats.trajectoryCount).toBe(0);
|
|
expect(stats.memoryCount).toBe(0);
|
|
expect(stats.patternCount).toBe(0);
|
|
});
|
|
|
|
it('should store trajectories', () => {
|
|
const trajectory = createTestTrajectory(0.8);
|
|
bank.storeTrajectory(trajectory);
|
|
|
|
const stats = bank.getStats();
|
|
expect(stats.trajectoryCount).toBe(1);
|
|
|
|
const retrieved = bank.getTrajectory(trajectory.trajectoryId);
|
|
expect(retrieved).toBeDefined();
|
|
expect(retrieved?.trajectoryId).toBe(trajectory.trajectoryId);
|
|
});
|
|
|
|
it('should retrieve all trajectories', () => {
|
|
for (let i = 0; i < 5; i++) {
|
|
bank.storeTrajectory(createTestTrajectory(0.7 + i * 0.05));
|
|
}
|
|
|
|
const trajectories = bank.getTrajectories();
|
|
expect(trajectories).toHaveLength(5);
|
|
});
|
|
|
|
it('should judge successful trajectories correctly', async () => {
|
|
const trajectory = createTestTrajectory(0.85, 'code', 10);
|
|
const verdict = await bank.judge(trajectory);
|
|
|
|
expect(verdict).toBeDefined();
|
|
expect(verdict.success).toBe(true);
|
|
expect(verdict.confidence).toBeGreaterThan(0);
|
|
expect(verdict.strengths).toBeDefined();
|
|
expect(verdict.weaknesses).toBeDefined();
|
|
expect(verdict.improvements).toBeDefined();
|
|
});
|
|
|
|
it('should judge failed trajectories correctly', async () => {
|
|
const trajectory = createTestTrajectory(0.3, 'code', 10);
|
|
const verdict = await bank.judge(trajectory);
|
|
|
|
expect(verdict.success).toBe(false);
|
|
expect(verdict.weaknesses.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should identify strengths in high-quality trajectories', async () => {
|
|
const trajectory = createTestTrajectory(0.95, 'code', 8);
|
|
const verdict = await bank.judge(trajectory);
|
|
|
|
expect(verdict.strengths.length).toBeGreaterThan(0);
|
|
expect(verdict.strengths.some(s => s.includes('quality'))).toBe(true);
|
|
});
|
|
|
|
it('should identify weaknesses in low-quality trajectories', async () => {
|
|
const trajectory = createTestTrajectory(0.2, 'code', 15);
|
|
const verdict = await bank.judge(trajectory);
|
|
|
|
expect(verdict.weaknesses.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should generate improvement suggestions', async () => {
|
|
const trajectory = createTestTrajectory(0.4, 'code', 12);
|
|
const verdict = await bank.judge(trajectory);
|
|
|
|
expect(verdict.improvements).toBeDefined();
|
|
if (verdict.weaknesses.length > 0) {
|
|
expect(verdict.improvements.length).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
|
|
it('should throw on judging incomplete trajectory', async () => {
|
|
const incompleteTrajectory: Trajectory = {
|
|
...createTestTrajectory(0.8),
|
|
isComplete: false,
|
|
};
|
|
|
|
await expect(bank.judge(incompleteTrajectory)).rejects.toThrow('incomplete');
|
|
});
|
|
});
|
|
|
|
describe('ReasoningBank - Memory Distillation', () => {
|
|
let bank: ReasoningBank;
|
|
|
|
beforeEach(() => {
|
|
bank = createReasoningBank({
|
|
distillationThreshold: 0.6,
|
|
});
|
|
});
|
|
|
|
it('should distill successful trajectories', async () => {
|
|
const trajectory = createTestTrajectory(0.8);
|
|
const memory = await bank.distill(trajectory);
|
|
|
|
expect(memory).toBeDefined();
|
|
expect(memory?.memoryId).toBeDefined();
|
|
expect(memory?.strategy).toBeDefined();
|
|
expect(memory?.keyLearnings).toBeDefined();
|
|
expect(memory?.embedding).toBeInstanceOf(Float32Array);
|
|
expect(memory?.quality).toBeCloseTo(0.8);
|
|
});
|
|
|
|
it('should not distill low-quality trajectories', async () => {
|
|
const trajectory = createTestTrajectory(0.3);
|
|
const memory = await bank.distill(trajectory);
|
|
|
|
expect(memory).toBeNull();
|
|
});
|
|
|
|
it('should automatically judge before distillation', async () => {
|
|
const trajectory = createTestTrajectory(0.85);
|
|
expect(trajectory.verdict).toBeUndefined();
|
|
|
|
const memory = await bank.distill(trajectory);
|
|
|
|
expect(trajectory.verdict).toBeDefined();
|
|
expect(memory).not.toBeNull();
|
|
});
|
|
|
|
it('should extract meaningful strategy', async () => {
|
|
const trajectory = createTestTrajectory(0.9, 'code', 8);
|
|
const memory = await bank.distill(trajectory);
|
|
|
|
expect(memory).not.toBeNull();
|
|
expect(memory!.strategy).toBeTruthy();
|
|
expect(typeof memory!.strategy).toBe('string');
|
|
});
|
|
|
|
it('should extract key learnings', async () => {
|
|
const trajectory = createTestTrajectory(0.85, 'reasoning', 10);
|
|
const memory = await bank.distill(trajectory);
|
|
|
|
expect(memory).not.toBeNull();
|
|
expect(memory!.keyLearnings).toBeDefined();
|
|
expect(Array.isArray(memory!.keyLearnings)).toBe(true);
|
|
expect(memory!.keyLearnings.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should compute aggregate embedding', async () => {
|
|
const trajectory = createTestTrajectory(0.8, 'code', 10);
|
|
const memory = await bank.distill(trajectory);
|
|
|
|
expect(memory).not.toBeNull();
|
|
expect(memory!.embedding).toBeInstanceOf(Float32Array);
|
|
expect(memory!.embedding.length).toBe(768);
|
|
});
|
|
|
|
it('should track distillation performance', async () => {
|
|
const trajectory = createTestTrajectory(0.8);
|
|
await bank.distill(trajectory);
|
|
|
|
const stats = bank.getStats();
|
|
expect(stats.avgDistillationTimeMs).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should link distilled memory to trajectory', async () => {
|
|
const trajectory = createTestTrajectory(0.9);
|
|
const memory = await bank.distill(trajectory);
|
|
|
|
expect(trajectory.distilledMemory).toBeDefined();
|
|
expect(trajectory.distilledMemory?.memoryId).toBe(memory?.memoryId);
|
|
});
|
|
});
|
|
|
|
describe('ReasoningBank - Retrieval (MMR)', () => {
|
|
let bank: ReasoningBank;
|
|
|
|
beforeEach(async () => {
|
|
bank = createReasoningBank({
|
|
retrievalK: 3,
|
|
mmrLambda: 0.7,
|
|
});
|
|
|
|
// Add some diverse memories
|
|
for (let i = 0; i < 10; i++) {
|
|
const trajectory = createTestTrajectory(0.7 + i * 0.02, 'code', 8);
|
|
await bank.distill(trajectory);
|
|
}
|
|
});
|
|
|
|
it('should retrieve top-k similar memories', async () => {
|
|
const queryEmbedding = new Float32Array(768).fill(0.5);
|
|
const results = await bank.retrieve(queryEmbedding, 3);
|
|
|
|
expect(results).toBeDefined();
|
|
expect(results.length).toBeLessThanOrEqual(3);
|
|
});
|
|
|
|
it('should apply MMR for diversity', async () => {
|
|
const queryEmbedding = new Float32Array(768).fill(0.5);
|
|
const results = await bank.retrieve(queryEmbedding, 5);
|
|
|
|
// Check that results have diversity scores
|
|
for (const result of results) {
|
|
expect(result.relevanceScore).toBeGreaterThanOrEqual(0);
|
|
expect(result.diversityScore).toBeGreaterThanOrEqual(0);
|
|
expect(result.combinedScore).toBeDefined();
|
|
}
|
|
});
|
|
|
|
it('should return retrieval results with proper structure', async () => {
|
|
const queryEmbedding = new Float32Array(768).fill(0.3);
|
|
const results = await bank.retrieve(queryEmbedding);
|
|
|
|
for (const result of results) {
|
|
expect(result.memory).toBeDefined();
|
|
expect(result.memory.memoryId).toBeTruthy();
|
|
expect(result.relevanceScore).toBeGreaterThanOrEqual(0);
|
|
expect(result.relevanceScore).toBeLessThanOrEqual(1);
|
|
}
|
|
});
|
|
|
|
it('should track retrieval performance', async () => {
|
|
const queryEmbedding = new Float32Array(768).fill(0.5);
|
|
await bank.retrieve(queryEmbedding);
|
|
|
|
const stats = bank.getStats();
|
|
expect(stats.avgRetrievalTimeMs).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should handle retrieval with no memories', async () => {
|
|
const emptyBank = createReasoningBank();
|
|
const queryEmbedding = new Float32Array(768).fill(0.5);
|
|
const results = await emptyBank.retrieve(queryEmbedding);
|
|
|
|
expect(results).toHaveLength(0);
|
|
});
|
|
|
|
it('should respect retrieval k parameter', async () => {
|
|
const queryEmbedding = new Float32Array(768).fill(0.5);
|
|
const results = await bank.retrieve(queryEmbedding, 2);
|
|
|
|
expect(results.length).toBeLessThanOrEqual(2);
|
|
});
|
|
});
|
|
|
|
describe('ReasoningBank - Consolidation', () => {
|
|
let bank: ReasoningBank;
|
|
|
|
beforeEach(async () => {
|
|
bank = createReasoningBank({
|
|
dedupThreshold: 0.95,
|
|
enableContradictionDetection: true,
|
|
maxPatternAgeDays: 30,
|
|
});
|
|
});
|
|
|
|
it('should deduplicate similar memories', async () => {
|
|
// Add very similar trajectories
|
|
for (let i = 0; i < 5; i++) {
|
|
const trajectory = createTestTrajectory(0.8, 'code', 5);
|
|
await bank.distill(trajectory);
|
|
}
|
|
|
|
const beforeStats = bank.getStats();
|
|
const result = await bank.consolidate();
|
|
|
|
expect(result.removedDuplicates).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should detect contradictions', async () => {
|
|
// Add similar contexts with different outcomes
|
|
const highQualityTraj = createTestTrajectory(0.95, 'code', 5);
|
|
const lowQualityTraj = createTestTrajectory(0.2, 'code', 5);
|
|
|
|
await bank.distill(highQualityTraj);
|
|
await bank.distill(lowQualityTraj);
|
|
|
|
const result = await bank.consolidate();
|
|
|
|
expect(result.contradictionsDetected).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should merge similar patterns', async () => {
|
|
// Create some patterns first
|
|
for (let i = 0; i < 5; i++) {
|
|
const trajectory = createTestTrajectory(0.75, 'code', 5);
|
|
const memory = await bank.distill(trajectory);
|
|
if (memory) {
|
|
bank.memoryToPattern(memory);
|
|
}
|
|
}
|
|
|
|
const result = await bank.consolidate();
|
|
expect(result.mergedPatterns).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should prune old patterns', async () => {
|
|
const result = await bank.consolidate();
|
|
expect(result.prunedPatterns).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should return consolidation result', async () => {
|
|
const result = await bank.consolidate();
|
|
|
|
expect(result).toBeDefined();
|
|
expect(result.removedDuplicates).toBeGreaterThanOrEqual(0);
|
|
expect(result.contradictionsDetected).toBeGreaterThanOrEqual(0);
|
|
expect(result.prunedPatterns).toBeGreaterThanOrEqual(0);
|
|
expect(result.mergedPatterns).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should emit consolidation event', async () => {
|
|
let eventEmitted = false;
|
|
bank.addEventListener((event) => {
|
|
if (event.type === 'memory_consolidated') {
|
|
eventEmitted = true;
|
|
}
|
|
});
|
|
|
|
await bank.consolidate();
|
|
expect(eventEmitted).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Pattern Management', () => {
|
|
let bank: ReasoningBank;
|
|
|
|
beforeEach(() => {
|
|
bank = createReasoningBank();
|
|
});
|
|
|
|
it('should convert memory to pattern', async () => {
|
|
const trajectory = createTestTrajectory(0.85, 'code', 8);
|
|
const memory = await bank.distill(trajectory);
|
|
|
|
expect(memory).not.toBeNull();
|
|
const pattern = bank.memoryToPattern(memory!);
|
|
|
|
expect(pattern).toBeDefined();
|
|
expect(pattern.patternId).toBeTruthy();
|
|
expect(pattern.name).toBeTruthy();
|
|
expect(pattern.domain).toBe('code');
|
|
expect(pattern.strategy).toBe(memory!.strategy);
|
|
expect(pattern.successRate).toBe(memory!.quality);
|
|
});
|
|
|
|
it('should evolve pattern based on new experience', async () => {
|
|
const trajectory1 = createTestTrajectory(0.8, 'code', 5);
|
|
const memory = await bank.distill(trajectory1);
|
|
const pattern = bank.memoryToPattern(memory!);
|
|
|
|
const trajectory2 = createTestTrajectory(0.9, 'code', 5);
|
|
bank.evolvePattern(pattern.patternId, trajectory2);
|
|
|
|
const patterns = bank.getPatterns();
|
|
const evolvedPattern = patterns.find(p => p.patternId === pattern.patternId);
|
|
|
|
expect(evolvedPattern).toBeDefined();
|
|
expect(evolvedPattern!.usageCount).toBe(1);
|
|
expect(evolvedPattern!.qualityHistory.length).toBeGreaterThan(1);
|
|
expect(evolvedPattern!.evolutionHistory.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should track pattern usage', async () => {
|
|
const trajectory = createTestTrajectory(0.85, 'code', 5);
|
|
const memory = await bank.distill(trajectory);
|
|
const pattern = bank.memoryToPattern(memory!);
|
|
|
|
// Evolve multiple times
|
|
for (let i = 0; i < 3; i++) {
|
|
const newTraj = createTestTrajectory(0.7 + i * 0.05, 'code', 5);
|
|
bank.evolvePattern(pattern.patternId, newTraj);
|
|
}
|
|
|
|
const patterns = bank.getPatterns();
|
|
const usedPattern = patterns.find(p => p.patternId === pattern.patternId);
|
|
|
|
expect(usedPattern!.usageCount).toBe(3);
|
|
});
|
|
|
|
it('should update success rate on evolution', async () => {
|
|
const trajectory1 = createTestTrajectory(0.7, 'code', 5);
|
|
const memory = await bank.distill(trajectory1);
|
|
const pattern = bank.memoryToPattern(memory!);
|
|
|
|
const initialSuccessRate = pattern.successRate;
|
|
|
|
const trajectory2 = createTestTrajectory(0.9, 'code', 5);
|
|
bank.evolvePattern(pattern.patternId, trajectory2);
|
|
|
|
const patterns = bank.getPatterns();
|
|
const evolvedPattern = patterns.find(p => p.patternId === pattern.patternId);
|
|
|
|
expect(evolvedPattern!.successRate).not.toBe(initialSuccessRate);
|
|
});
|
|
|
|
it('should maintain quality history (max 100)', async () => {
|
|
const trajectory = createTestTrajectory(0.8, 'code', 5);
|
|
const memory = await bank.distill(trajectory);
|
|
const pattern = bank.memoryToPattern(memory!);
|
|
|
|
// Evolve many times
|
|
for (let i = 0; i < 150; i++) {
|
|
const newTraj = createTestTrajectory(0.6 + (i % 40) * 0.01, 'code', 3);
|
|
bank.evolvePattern(pattern.patternId, newTraj);
|
|
}
|
|
|
|
const patterns = bank.getPatterns();
|
|
const evolvedPattern = patterns.find(p => p.patternId === pattern.patternId);
|
|
|
|
expect(evolvedPattern!.qualityHistory.length).toBeLessThanOrEqual(100);
|
|
});
|
|
|
|
it('should emit pattern evolution event', async () => {
|
|
let eventEmitted = false;
|
|
bank.addEventListener((event) => {
|
|
if (event.type === 'pattern_evolved') {
|
|
eventEmitted = true;
|
|
}
|
|
});
|
|
|
|
const trajectory1 = createTestTrajectory(0.8, 'code', 5);
|
|
const memory = await bank.distill(trajectory1);
|
|
const pattern = bank.memoryToPattern(memory!);
|
|
|
|
const trajectory2 = createTestTrajectory(0.85, 'code', 5);
|
|
bank.evolvePattern(pattern.patternId, trajectory2);
|
|
|
|
expect(eventEmitted).toBe(true);
|
|
});
|
|
|
|
it('should get all patterns', async () => {
|
|
for (let i = 0; i < 5; i++) {
|
|
const trajectory = createTestTrajectory(0.75 + i * 0.02, 'code', 5);
|
|
const memory = await bank.distill(trajectory);
|
|
if (memory) {
|
|
bank.memoryToPattern(memory);
|
|
}
|
|
}
|
|
|
|
const patterns = bank.getPatterns();
|
|
expect(patterns.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Event System', () => {
|
|
let bank: ReasoningBank;
|
|
|
|
beforeEach(() => {
|
|
bank = createReasoningBank();
|
|
});
|
|
|
|
it('should add and remove event listeners', () => {
|
|
const listener = () => {};
|
|
|
|
expect(() => bank.addEventListener(listener)).not.toThrow();
|
|
expect(() => bank.removeEventListener(listener)).not.toThrow();
|
|
});
|
|
|
|
it('should emit consolidation events', async () => {
|
|
let eventReceived = false;
|
|
|
|
bank.addEventListener((event) => {
|
|
if (event.type === 'memory_consolidated') {
|
|
eventReceived = true;
|
|
}
|
|
});
|
|
|
|
await bank.consolidate();
|
|
expect(eventReceived).toBe(true);
|
|
});
|
|
|
|
it('should emit pattern evolution events', async () => {
|
|
let evolutionEvent: any = null;
|
|
|
|
bank.addEventListener((event) => {
|
|
if (event.type === 'pattern_evolved') {
|
|
evolutionEvent = event;
|
|
}
|
|
});
|
|
|
|
const trajectory1 = createTestTrajectory(0.8, 'code', 5);
|
|
const memory = await bank.distill(trajectory1);
|
|
const pattern = bank.memoryToPattern(memory!);
|
|
|
|
const trajectory2 = createTestTrajectory(0.9, 'code', 5);
|
|
bank.evolvePattern(pattern.patternId, trajectory2);
|
|
|
|
expect(evolutionEvent).not.toBeNull();
|
|
expect(evolutionEvent.patternId).toBe(pattern.patternId);
|
|
});
|
|
});
|