UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

335 lines (279 loc) 10.7 kB
/** * @fileoverview Unit tests for ConfidenceScorer * @story WIS-2 - Workflow Registry Enhancement */ 'use strict'; const { ConfidenceScorer, createConfidenceScorer, SCORING_WEIGHTS, } = require('../engine/confidence-scorer'); describe('ConfidenceScorer', () => { let scorer; beforeEach(() => { scorer = createConfidenceScorer(); }); describe('constructor', () => { it('should create scorer with default weights', () => { const weights = scorer.getWeights(); expect(weights.COMMAND_MATCH).toBe(0.4); expect(weights.AGENT_MATCH).toBe(0.25); expect(weights.HISTORY_DEPTH).toBe(0.2); expect(weights.PROJECT_STATE).toBe(0.15); }); it('should accept custom weights', () => { const customScorer = createConfidenceScorer({ weights: { COMMAND_MATCH: 0.5, AGENT_MATCH: 0.2, HISTORY_DEPTH: 0.15, PROJECT_STATE: 0.15, }, }); const weights = customScorer.getWeights(); expect(weights.COMMAND_MATCH).toBe(0.5); }); it('should throw error if weights do not sum to 1.0', () => { expect(() => { createConfidenceScorer({ weights: { COMMAND_MATCH: 0.5, AGENT_MATCH: 0.5, HISTORY_DEPTH: 0.2, PROJECT_STATE: 0.15, }, }); }).toThrow('Scoring weights must sum to 1.0'); }); }); describe('score()', () => { it('should return 0 for null suggestion', () => { const result = scorer.score(null, { lastCommand: 'test' }); expect(result).toBe(0); }); it('should return 0 for null context', () => { const result = scorer.score({ trigger: 'test' }, null); expect(result).toBe(0); }); it('should return high score for exact command match', () => { const suggestion = { trigger: 'create-epic', agentSequence: ['po', 'sm'], keyCommands: ['create-epic', 'create-story'], }; const context = { lastCommand: 'create-epic', lastCommands: ['create-epic'], agentId: '@po', projectState: {}, }; const result = scorer.score(suggestion, context); // Score is composed of: command(40%) + agent(25%) + history(20%) + state(15%) expect(result).toBeGreaterThanOrEqual(0.7); }); it('should return medium score for partial command match', () => { const suggestion = { trigger: 'create-epic', agentSequence: ['po', 'sm'], keyCommands: ['create-epic', 'create-story'], }; const context = { lastCommand: 'create-story', lastCommands: ['create-story'], agentId: '@sm', projectState: {}, }; const result = scorer.score(suggestion, context); expect(result).toBeGreaterThan(0.4); expect(result).toBeLessThan(0.8); }); it('should return low score for no command match', () => { const suggestion = { trigger: 'create-epic', agentSequence: ['po', 'sm'], keyCommands: ['create-epic', 'create-story'], }; const context = { lastCommand: 'push', lastCommands: ['push'], agentId: '@devops', projectState: {}, }; const result = scorer.score(suggestion, context); expect(result).toBeLessThanOrEqual(0.3); }); it('should return normalized score between 0 and 1', () => { const suggestion = { trigger: 'any', agentSequence: [], keyCommands: [] }; const context = { lastCommand: 'any', lastCommands: [], agentId: '' }; const result = scorer.score(suggestion, context); expect(result).toBeGreaterThanOrEqual(0); expect(result).toBeLessThanOrEqual(1); }); }); describe('matchCommand()', () => { it('should return 1.0 for exact match', () => { const result = scorer.matchCommand('create-epic', 'create-epic'); expect(result).toBe(1.0); }); it('should return 1.0 when normalized trigger equals command', () => { // "create-epic completed" normalizes to "create-epic" const result = scorer.matchCommand('create-epic completed', 'create-epic'); expect(result).toBe(1.0); }); it('should return partial score for keyword match', () => { const result = scorer.matchCommand('create-epic', 'create-story'); // Both share "create" word, so partial match expect(result).toBeGreaterThan(0); expect(result).toBeLessThan(1); }); it('should return 0 for no match', () => { const result = scorer.matchCommand('create-epic', 'push'); expect(result).toBe(0); }); it('should handle null trigger', () => { const result = scorer.matchCommand(null, 'test'); expect(result).toBe(0); }); it('should handle null command', () => { const result = scorer.matchCommand('test', null); expect(result).toBe(0); }); }); describe('matchAgent()', () => { it('should return high score for first agent in sequence', () => { const result = scorer.matchAgent(['po', 'sm', 'dev'], '@po'); expect(result).toBeGreaterThan(0.6); }); it('should return higher score for later agents', () => { const result1 = scorer.matchAgent(['po', 'sm', 'dev'], '@po'); const result2 = scorer.matchAgent(['po', 'sm', 'dev'], '@dev'); expect(result2).toBeGreaterThan(result1); }); it('should return 0 for agent not in sequence', () => { const result = scorer.matchAgent(['po', 'sm'], '@devops'); expect(result).toBe(0); }); it('should handle agent with @ prefix', () => { const result = scorer.matchAgent(['po'], '@po'); expect(result).toBeGreaterThan(0); }); it('should handle null agent sequence', () => { const result = scorer.matchAgent(null, '@po'); expect(result).toBe(0); }); }); describe('matchHistory()', () => { it('should return high score when history matches key commands', () => { const keyCommands = ['create-epic', 'create-story']; const history = ['create-epic', 'create-story', 'validate']; const result = scorer.matchHistory(keyCommands, history); expect(result).toBeGreaterThan(0.8); }); it('should give recency bonus for recent commands', () => { const keyCommands = ['create-epic']; const historyRecent = ['create-epic', 'other', 'another']; const historyOld = ['other', 'another', 'create-epic']; const resultRecent = scorer.matchHistory(keyCommands, historyRecent); const resultOld = scorer.matchHistory(keyCommands, historyOld); // Recent should get higher score due to recency bonus expect(resultRecent).toBeGreaterThanOrEqual(resultOld); }); it('should return 0 for no matching commands', () => { const keyCommands = ['create-epic']; const history = ['push', 'commit']; const result = scorer.matchHistory(keyCommands, history); expect(result).toBe(0); }); it('should handle empty history', () => { const result = scorer.matchHistory(['test'], []); expect(result).toBe(0); }); it('should handle empty key commands', () => { const result = scorer.matchHistory([], ['test']); expect(result).toBe(0); }); }); describe('matchProjectState()', () => { it('should return neutral score for empty state', () => { const result = scorer.matchProjectState({}, {}); expect(result).toBe(0.5); }); it('should boost score for git-related suggestions when uncommitted changes', () => { const suggestion = { trigger: 'git commit' }; const state = { hasUncommittedChanges: true }; const result = scorer.matchProjectState(suggestion, state); expect(result).toBeGreaterThan(0.5); }); it('should boost score for test suggestions when tests failing', () => { const suggestion = { trigger: 'run tests' }; const state = { failingTests: true }; const result = scorer.matchProjectState(suggestion, state); expect(result).toBeGreaterThan(0.5); }); it('should return 0.5 for null project state', () => { const result = scorer.matchProjectState({}, null); expect(result).toBe(0.5); }); }); describe('normalizeCommand()', () => { it('should convert to lowercase', () => { const result = scorer.normalizeCommand('CREATE-EPIC'); expect(result).toBe('create-epic'); }); it('should remove "completed" suffix', () => { const result = scorer.normalizeCommand('create-epic completed'); expect(result).toBe('create-epic'); }); it('should remove "successfully" suffix', () => { const result = scorer.normalizeCommand('create-epic successfully'); expect(result).toBe('create-epic'); }); it('should remove * prefix', () => { const result = scorer.normalizeCommand('*create-epic'); expect(result).toBe('create-epic'); }); it('should handle null', () => { const result = scorer.normalizeCommand(null); expect(result).toBe(''); }); }); describe('rankSuggestions()', () => { it('should return empty array for empty suggestions', () => { const result = scorer.rankSuggestions([], {}); expect(result).toEqual([]); }); it('should rank suggestions by score descending', () => { const suggestions = [ { trigger: 'push', agentSequence: ['devops'] }, { trigger: 'create-epic', agentSequence: ['po'] }, ]; const context = { lastCommand: 'create-epic', lastCommands: ['create-epic'], agentId: '@po', }; const result = scorer.rankSuggestions(suggestions, context); expect(result[0].trigger).toBe('create-epic'); expect(result[0].score).toBeGreaterThan(result[1].score); }); it('should add score property to each suggestion', () => { const suggestions = [{ trigger: 'test' }]; const context = { lastCommand: 'test' }; const result = scorer.rankSuggestions(suggestions, context); expect(result[0]).toHaveProperty('score'); expect(typeof result[0].score).toBe('number'); }); }); describe('SCORING_WEIGHTS constant', () => { it('should have correct default weights', () => { expect(SCORING_WEIGHTS.COMMAND_MATCH).toBe(0.4); expect(SCORING_WEIGHTS.AGENT_MATCH).toBe(0.25); expect(SCORING_WEIGHTS.HISTORY_DEPTH).toBe(0.2); expect(SCORING_WEIGHTS.PROJECT_STATE).toBe(0.15); }); it('should sum to 1.0', () => { const sum = Object.values(SCORING_WEIGHTS).reduce((a, b) => a + b, 0); expect(sum).toBe(1.0); }); }); });