UNPKG

@iservu-inc/adf-cli

Version:

CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support

298 lines (263 loc) 9.96 kB
const fs = require('fs-extra'); const path = require('path'); const { PatternDetector, detectPatterns, getPatternSummary } = require('../lib/learning/pattern-detector'); describe('Pattern Detector', () => { const tempDir = path.join(__dirname, 'temp-pattern-test'); beforeEach(async () => { await fs.ensureDir(tempDir); }); afterEach(async () => { await fs.remove(tempDir); }); describe('PatternDetector', () => { test('should detect consistent skip patterns', () => { const skipHistory = { sessions: [ { sessionId: 's1', skips: [ { questionId: 'q1', text: 'Deploy where?', category: 'deployment', reason: 'manual' } ] }, { sessionId: 's2', skips: [ { questionId: 'q1', text: 'Deploy where?', category: 'deployment', reason: 'manual' } ] }, { sessionId: 's3', skips: [ { questionId: 'q1', text: 'Deploy where?', category: 'deployment', reason: 'manual' } ] } ] }; const detector = new PatternDetector(skipHistory, {}, { minSessionsForPattern: 3 }); const patterns = detector.detectConsistentSkips(); expect(patterns.length).toBeGreaterThan(0); expect(patterns[0].questionId).toBe('q1'); expect(patterns[0].confidence).toBe(100); // 3/3 sessions expect(patterns[0].type).toBe('consistent_skip'); }); test('should not detect patterns with insufficient sessions', () => { const skipHistory = { sessions: [ { sessionId: 's1', skips: [ { questionId: 'q1', text: 'Q1', reason: 'manual' } ] }, { sessionId: 's2', skips: [ { questionId: 'q1', text: 'Q1', reason: 'manual' } ] } ] }; const detector = new PatternDetector(skipHistory, {}, { minSessionsForPattern: 3 }); const patterns = detector.detectConsistentSkips(); expect(patterns.length).toBe(0); // Not enough sessions }); test('should detect category skip patterns', () => { const skipHistory = { sessions: [ { sessionId: 's1', skips: [ { questionId: 'q1', category: 'deployment', reason: 'manual' }, { questionId: 'q2', category: 'deployment', reason: 'manual' }, { questionId: 'q3', category: 'deployment', reason: 'manual' }, { questionId: 'q4', category: 'deployment', reason: 'manual' }, { questionId: 'q5', category: 'deployment', reason: 'manual' } ] } ] }; const detector = new PatternDetector(skipHistory, {}); const patterns = detector.detectCategoryPatterns(); expect(patterns.length).toBeGreaterThan(0); expect(patterns[0].category).toBe('deployment'); expect(patterns[0].type).toBe('category_skip'); expect(patterns[0].confidence).toBe(100); // 5/5 questions skipped }); test('should detect framework-specific skip patterns', () => { const skipHistory = { sessions: [ { sessionId: 's1', frameworks: ['Next.js'], skips: [ { questionId: 'q_routing', text: 'Routing setup?', category: 'frontend', reason: 'manual' } ] }, { sessionId: 's2', frameworks: ['Next.js'], skips: [ { questionId: 'q_routing', text: 'Routing setup?', category: 'frontend', reason: 'manual' } ] }, { sessionId: 's3', frameworks: ['Next.js'], skips: [ { questionId: 'q_routing', text: 'Routing setup?', category: 'frontend', reason: 'manual' } ] } ] }; const detector = new PatternDetector(skipHistory, {}, { minSessionsForPattern: 3 }); const patterns = detector.detectFrameworkPatterns(); expect(patterns.length).toBeGreaterThan(0); expect(patterns[0].framework).toBe('Next.js'); expect(patterns[0].questionId).toBe('q_routing'); expect(patterns[0].confidence).toBe(100); // 3/3 Next.js sessions }); test('should detect user preference patterns', () => { const skipHistory = { sessions: [] }; const answerHistory = { sessions: [ { sessionId: 's1', answers: [ { questionId: 'q1', category: 'testing', wordCount: 15 }, { questionId: 'q2', category: 'testing', wordCount: 18 }, { questionId: 'q3', category: 'testing', wordCount: 20 } ] } ] }; const detector = new PatternDetector(skipHistory, answerHistory); const patterns = detector.detectUserPreferences(); expect(patterns.length).toBeGreaterThan(0); expect(patterns[0].category).toBe('testing'); expect(patterns[0].preference).toBe('brief_answers'); expect(patterns[0].avgWordCount).toBeLessThan(30); }); test('should detect detailed answer preferences', () => { const skipHistory = { sessions: [] }; const answerHistory = { sessions: [ { sessionId: 's1', answers: [ { questionId: 'q1', category: 'architecture', wordCount: 120 }, { questionId: 'q2', category: 'architecture', wordCount: 150 }, { questionId: 'q3', category: 'architecture', wordCount: 110 } ] } ] }; const detector = new PatternDetector(skipHistory, answerHistory); const patterns = detector.detectUserPreferences(); expect(patterns.length).toBeGreaterThan(0); expect(patterns[0].category).toBe('architecture'); expect(patterns[0].preference).toBe('detailed_answers'); expect(patterns[0].avgWordCount).toBeGreaterThan(100); }); test('should aggregate all pattern types', () => { const skipHistory = { sessions: [ { sessionId: 's1', skips: [ { questionId: 'q1', category: 'deployment', reason: 'manual' } ] }, { sessionId: 's2', skips: [ { questionId: 'q1', category: 'deployment', reason: 'manual' } ] }, { sessionId: 's3', skips: [ { questionId: 'q1', category: 'deployment', reason: 'manual' } ] } ] }; const detector = new PatternDetector(skipHistory, {}, { minSessionsForPattern: 3 }); const allPatterns = detector.detectAllPatterns(); expect(allPatterns).toHaveProperty('consistentSkips'); expect(allPatterns).toHaveProperty('categoryPatterns'); expect(allPatterns).toHaveProperty('frameworkPatterns'); expect(allPatterns).toHaveProperty('userPreferences'); expect(allPatterns.consistentSkips.length).toBeGreaterThan(0); }); }); describe('detectPatterns', () => { test('should detect patterns from project files', async () => { const skipHistory = { version: '1.0', sessions: [ { sessionId: 's1', skips: [ { questionId: 'q1', category: 'deployment', reason: 'manual' } ] }, { sessionId: 's2', skips: [ { questionId: 'q1', category: 'deployment', reason: 'manual' } ] }, { sessionId: 's3', skips: [ { questionId: 'q1', category: 'deployment', reason: 'manual' } ] } ] }; await fs.ensureDir(path.join(tempDir, '.adf', 'learning')); await fs.writeJSON(path.join(tempDir, '.adf', 'learning', 'skip-history.json'), skipHistory); await fs.writeJSON(path.join(tempDir, '.adf', 'learning', 'answer-history.json'), { version: '1.0', sessions: [] }); await fs.writeJSON(path.join(tempDir, '.adf', 'learning', 'config.json'), { minSessionsForPattern: 3 }); const patterns = await detectPatterns(tempDir); expect(patterns).toHaveProperty('consistentSkips'); expect(patterns.consistentSkips.length).toBeGreaterThan(0); }); }); describe('getPatternSummary', () => { test('should summarize patterns by confidence level', () => { const patterns = { consistentSkips: [ { confidence: 90 }, { confidence: 70 }, { confidence: 50 } ], categoryPatterns: [ { confidence: 85 } ], frameworkPatterns: [], userPreferences: [] }; const summary = getPatternSummary(patterns); expect(summary.total).toBe(4); expect(summary.highConfidence).toBe(2); // 90, 85 expect(summary.mediumConfidence).toBe(1); // 70 expect(summary.lowConfidence).toBe(1); // 50 expect(summary.byType.consistentSkips).toBe(3); expect(summary.byType.categoryPatterns).toBe(1); }); test('should handle empty patterns', () => { const patterns = { consistentSkips: [], categoryPatterns: [], frameworkPatterns: [], userPreferences: [] }; const summary = getPatternSummary(patterns); expect(summary.total).toBe(0); expect(summary.highConfidence).toBe(0); expect(summary.mediumConfidence).toBe(0); expect(summary.lowConfidence).toBe(0); }); }); });