import { describe, expect, test } from 'vitest'; import { messageUserClarifyingQuestionTool, processClarificationResponseTool, shouldAskClarification, } from '../../../src/tools/communication-tools/message-user-clarifying-question-tool'; describe('Message User Clarifying Question Tool Unit Tests', () => { test('should have correct configuration', () => { expect(messageUserClarifyingQuestionTool.id).toBe('message-user-clarifying-question'); expect(messageUserClarifyingQuestionTool.description).toBe( 'Ask the user a clarifying question when requirements are unclear' ); expect(messageUserClarifyingQuestionTool.inputSchema).toBeDefined(); expect(messageUserClarifyingQuestionTool.outputSchema).toBeDefined(); expect(messageUserClarifyingQuestionTool.execute).toBeDefined(); }); test('should validate input schema', () => { const validInput = { question: 'Which time period would you like to analyze?', context: 'Multiple time periods are available in the data', question_type: 'open_ended' as const, priority: 'medium' as const, }; const result = messageUserClarifyingQuestionTool.inputSchema.safeParse(validInput); expect(result.success).toBe(true); }); test('should validate output schema structure', () => { const validOutput = { success: true, message_sent: true, formatted_question: 'Which time period would you like to analyze?', requires_response: true, conversation_paused: true, }; const result = messageUserClarifyingQuestionTool.outputSchema.safeParse(validOutput); expect(result.success).toBe(true); }); test('should format open-ended question correctly', async () => { const result = await messageUserClarifyingQuestionTool.execute({ context: { question: 'Which time period would you like to analyze?', context: 'Multiple time periods are available in the data', question_type: 'open_ended', }, }); expect(result.success).toBe(true); expect(result.formatted_question).toContain('Which time period'); expect(result.formatted_question).toContain('Context:'); expect(result.conversation_paused).toBe(true); expect(result.requires_response).toBe(true); }); test('should format multiple choice question with options', async () => { const result = await messageUserClarifyingQuestionTool.execute({ context: { question: 'Which metric would you like to focus on?', question_type: 'multiple_choice', options: [ { value: 'revenue', label: 'Revenue', description: 'Total sales revenue' }, { value: 'profit', label: 'Profit', description: 'Net profit after costs' }, { value: 'volume', label: 'Volume', description: 'Number of units sold' }, ], }, }); expect(result.success).toBe(true); expect(result.formatted_question).toContain('1. **Revenue**'); expect(result.formatted_question).toContain('Total sales revenue'); expect(result.formatted_question).toContain('2. **Profit**'); expect(result.formatted_question).toContain('3. **Volume**'); }); test('should format yes/no question correctly', async () => { const result = await messageUserClarifyingQuestionTool.execute({ context: { question: 'Should I include historical data?', question_type: 'yes_no', }, }); expect(result.success).toBe(true); expect(result.formatted_question).toContain('Should I include historical data?'); expect(result.formatted_question).toContain('**Yes** or **No**'); }); test('should format confirmation question correctly', async () => { const result = await messageUserClarifyingQuestionTool.execute({ context: { question: 'Please confirm before proceeding with data deletion', question_type: 'confirmation', }, }); expect(result.success).toBe(true); expect(result.formatted_question).toContain('data deletion'); expect(result.formatted_question).toContain('**Confirm**'); }); test('should handle high priority questions', async () => { const result = await messageUserClarifyingQuestionTool.execute({ context: { question: 'Please confirm before proceeding with data deletion', question_type: 'confirmation', priority: 'high', }, }); expect(result.success).toBe(true); expect(result.formatted_question).toContain('🔴 **Important Clarification Needed**'); }); test('should include related context', async () => { const result = await messageUserClarifyingQuestionTool.execute({ context: { question: 'Which format should I use?', question_type: 'open_ended', related_to: 'data export functionality', }, }); expect(result.success).toBe(true); expect(result.formatted_question).toContain('related to: data export functionality'); }); test('should handle medium and low priority questions', async () => { const mediumResult = await messageUserClarifyingQuestionTool.execute({ context: { question: 'Which chart type?', priority: 'medium', }, }); const lowResult = await messageUserClarifyingQuestionTool.execute({ context: { question: 'Which color scheme?', priority: 'low', }, }); expect(mediumResult.formatted_question).not.toContain('🔴'); expect(lowResult.formatted_question).not.toContain('🔴'); }); }); describe('Process Clarification Response Tool Tests', () => { test('should have correct configuration', () => { expect(processClarificationResponseTool.id).toBe('process-clarification-response'); expect(processClarificationResponseTool.description).toBe( 'Process user response to a clarifying question' ); }); test('should validate input schema', () => { const validInput = { response: 'Yes, include historical data', question_id: 'clarify_123', }; const result = processClarificationResponseTool.inputSchema.safeParse(validInput); expect(result.success).toBe(true); }); test('should process valid yes/no response', async () => { // First ask a yes/no question await messageUserClarifyingQuestionTool.execute({ context: { question: 'Should I include historical data?', question_type: 'yes_no', }, }); // Then process the response const result = await processClarificationResponseTool.execute({ context: { response: 'Yes' }, }); expect(result.success).toBe(true); expect(result.response_processed).toBe(true); expect(result.workflow_resumed).toBe(true); expect(result.validation_result?.valid).toBe(true); }); test('should reject invalid yes/no response', async () => { // First ask a yes/no question await messageUserClarifyingQuestionTool.execute({ context: { question: 'Should I proceed?', question_type: 'yes_no', }, }); // Then process invalid response const result = await processClarificationResponseTool.execute({ context: { response: 'Maybe' }, }); expect(result.success).toBe(false); expect(result.response_processed).toBe(false); expect(result.workflow_resumed).toBe(false); expect(result.validation_result?.valid).toBe(false); expect(result.validation_result?.error_message).toContain('Yes or No'); }); test('should process valid confirmation response', async () => { // First ask a confirmation question await messageUserClarifyingQuestionTool.execute({ context: { question: 'Please confirm the data deletion', question_type: 'confirmation', }, }); // Then process confirmation const result = await processClarificationResponseTool.execute({ context: { response: 'Confirm' }, }); expect(result.success).toBe(true); expect(result.validation_result?.valid).toBe(true); }); test('should reject invalid confirmation response', async () => { // First ask a confirmation question await messageUserClarifyingQuestionTool.execute({ context: { question: 'Please confirm the action', question_type: 'confirmation', }, }); // Then process short/invalid response const result = await processClarificationResponseTool.execute({ context: { response: 'ok' }, }); expect(result.success).toBe(false); expect(result.validation_result?.error_message).toContain('Confirm'); }); test('should process open-ended responses', async () => { // First ask an open-ended question await messageUserClarifyingQuestionTool.execute({ context: { question: 'What time period would you like?', question_type: 'open_ended', }, }); // Then process any response (open-ended doesn't validate) const result = await processClarificationResponseTool.execute({ context: { response: 'Last 3 months' }, }); expect(result.success).toBe(true); expect(result.validation_result?.valid).toBe(true); }); test('should handle no pending clarification request', async () => { // Try to process response without asking question first const result = await processClarificationResponseTool.execute({ context: { response: 'Some response' }, }); // The tool may handle this gracefully rather than throwing expect(result.success).toBe(true); expect(result.response_processed).toBe(true); }); }); describe('Should Ask Clarification Helper Tests', () => { test('should ask clarification for high ambiguity', () => { const result = shouldAskClarification({ ambiguity_score: 0.8, missing_requirements: [], confidence_level: 0.7, }); expect(result).toBe(true); }); test('should ask clarification for missing requirements', () => { const result = shouldAskClarification({ ambiguity_score: 0.3, missing_requirements: ['time_period', 'metrics'], confidence_level: 0.7, }); expect(result).toBe(true); }); test('should ask clarification for low confidence', () => { const result = shouldAskClarification({ ambiguity_score: 0.3, missing_requirements: [], confidence_level: 0.4, }); expect(result).toBe(true); }); test('should not ask clarification when all conditions are good', () => { const result = shouldAskClarification({ ambiguity_score: 0.2, missing_requirements: [], confidence_level: 0.8, }); expect(result).toBe(false); }); test('should ask clarification when multiple conditions are borderline', () => { const result = shouldAskClarification({ ambiguity_score: 0.6, missing_requirements: ['time_period'], confidence_level: 0.6, }); expect(result).toBe(true); }); });