import { describe, it, expect } from 'vitest'; import { generateTeacherPrompt, generateGhostwriterPrompt } from './prompt-engine'; import type { ChatMessage } from '../db'; describe('Prompt Engine - Teacher Agent', () => { describe('generateTeacherPrompt - Venting Intent', () => { it('should generate empathetic venting prompt with user input', () => { const userInput = "I'm so frustrated with this bug"; const chatHistory: ChatMessage[] = []; const intent = 'venting'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result).toContain(userInput); expect(result.toLowerCase()).toContain('empath'); expect(result.toLowerCase()).toContain('validate'); }); it('should include probing question instruction for venting', () => { const userInput = "This keeps breaking"; const chatHistory: ChatMessage[] = []; const intent = 'venting'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result.toLowerCase()).toContain('probing'); expect(result.toLowerCase()).toContain('question'); }); it('should be supportive and encouraging for venting', () => { const userInput = "I don't understand why this isn't working"; const chatHistory: ChatMessage[] = []; const intent = 'venting'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result.toLowerCase()).toContain('supportive'); expect(result.toLowerCase()).toContain('encourag'); }); it('should specify concise response (2-3 sentences) for venting', () => { const userInput = "Stuck on this problem"; const chatHistory: ChatMessage[] = []; const intent = 'venting'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result).toContain('2-3 sentences'); }); it('should include chat history when available for venting', () => { const userInput = "Still having issues"; const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Having trouble with React hooks', timestamp: Date.now() }, { role: 'assistant', content: 'What specific hook are you struggling with?', timestamp: Date.now() }, ]; const intent = 'venting'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result).toContain('Previous context'); expect(result).toContain('React hooks'); }); }); describe('generateTeacherPrompt - Insight Intent', () => { it('should generate curious insight prompt with user input', () => { const userInput = "I finally understand closures"; const chatHistory: ChatMessage[] = []; const intent = 'insight'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result).toContain(userInput); expect(result.toLowerCase()).toContain('curious'); expect(result.toLowerCase()).toContain('celebrate'); }); it('should include deepening question instruction for insight', () => { const userInput = "The key was using useMemo"; const chatHistory: ChatMessage[] = []; const intent = 'insight'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result.toLowerCase()).toContain('deepen'); expect(result.toLowerCase()).toContain('expand'); }); it('should be encouraging for insight', () => { const userInput = "It just clicked"; const chatHistory: ChatMessage[] = []; const intent = 'insight'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result.toLowerCase()).toContain('encourag'); }); it('should specify concise response (2-3 sentences) for insight', () => { const userInput = "Solved the problem"; const chatHistory: ChatMessage[] = []; const intent = 'insight'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result).toContain('2-3 sentences'); }); it('should include chat history when available for insight', () => { const userInput = "Got it working now"; const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Trying to fix the async issue', timestamp: Date.now() }, { role: 'assistant', content: 'Have you tried using await?', timestamp: Date.now() }, ]; const intent = 'insight'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result).toContain('Previous context'); expect(result).toContain('async'); }); }); describe('generateTeacherPrompt - Edge Cases', () => { it('should handle empty chat history gracefully', () => { const userInput = "Help me debug"; const chatHistory: ChatMessage[] = []; const intent = 'venting'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result).toContain('Previous context:'); expect(result).toContain('(No previous messages)'); }); it('should handle very long user input', () => { const userInput = "I".repeat(1000) + " frustrated"; const chatHistory: ChatMessage[] = []; const intent = 'venting'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result.length).toBeGreaterThan(0); expect(result).toContain('...'); }); it('should handle multiple messages in chat history', () => { const userInput = "Still confused"; const chatHistory: ChatMessage[] = [ { role: 'user', content: 'First question', timestamp: Date.now() }, { role: 'assistant', content: 'First answer', timestamp: Date.now() }, { role: 'user', content: 'Second question', timestamp: Date.now() }, { role: 'assistant', content: 'Second answer', timestamp: Date.now() }, ]; const intent = 'venting'; const result = generateTeacherPrompt(userInput, chatHistory, intent); expect(result).toContain('First question'); expect(result).toContain('Second question'); }); }); describe('generateTeacherPrompt - Format and Structure', () => { it('should return non-empty string', () => { const result = generateTeacherPrompt("Test", [], 'venting'); expect(result).toBeTruthy(); expect(result.length).toBeGreaterThan(0); }); it('should include system role definition', () => { const result = generateTeacherPrompt("Test", [], 'venting'); expect(result).toContain('You are'); }); it('should be clearly formatted for LLM consumption', () => { const result = generateTeacherPrompt("Test input", [], 'insight'); expect(result).toMatch(/user input|your role|response/i); }); }); }); describe('Prompt Engine - Ghostwriter Agent', () => { describe('generateGhostwriterPrompt - Basic Functionality', () => { it('should generate Ghostwriter prompt with chat history', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'I struggled with dependency injection today', timestamp: Date.now() }, { role: 'assistant', content: 'What aspect was challenging?', timestamp: Date.now() }, { role: 'user', content: 'Understanding how to inject dependencies without tight coupling', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'venting'); expect(result).toBeTruthy(); expect(result.length).toBeGreaterThan(0); }); it('should include Ghostwriter Agent role definition', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'I learned something cool about React', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'insight'); expect(result).toContain('Ghostwriter'); expect(result.toLowerCase()).toContain('agent'); }); it('should include intent context in prompt', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Frustrated with debugging', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'venting'); expect(result).toContain('venting'); }); it('should handle insight intent context', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Finally understand closures', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'insight'); expect(result).toContain('insight'); }); it('should handle unknown intent gracefully', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Some message', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, undefined); expect(result).toContain('unknown'); }); }); describe('generateGhostwriterPrompt - Output Format', () => { it('should specify Markdown output format', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Learned about React hooks', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'insight'); expect(result.toLowerCase()).toContain('markdown'); expect(result.toLowerCase()).toContain('title'); expect(result.toLowerCase()).toContain('body'); expect(result.toLowerCase()).toContain('tags'); }); it('should include code block format specification', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Struggled with async/await', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'venting'); expect(result).toContain('```'); }); it('should specify professional LinkedIn-style tone', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Had a breakthrough', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'insight'); expect(result.toLowerCase()).toContain('professional'); expect(result.toLowerCase()).toContain('linkedin'); }); }); describe('generateGhostwriterPrompt - Content Requirements', () => { it('should include constraint to avoid hallucinations', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Fixed a bug', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'insight'); expect(result.toLowerCase()).toContain('hallucinat'); }); it('should specify grounded in user input requirement', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Learned TypeScript', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'insight'); expect(result.toLowerCase()).toContain('grounded'); expect(result.toLowerCase()).toContain('user input'); }); it('should include transformation focus instruction', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'This was hard but I learned a lot', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'venting'); expect(result.toLowerCase()).toContain('transformation'); }); it('should specify word count constraint', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Understanding React now', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'insight'); expect(result).toMatch(/\d{2,3}\s*words/); }); }); describe('generateGhostwriterPrompt - Edge Cases', () => { it('should handle empty chat history gracefully', () => { const chatHistory: ChatMessage[] = []; const result = generateGhostwriterPrompt(chatHistory, 'venting'); expect(result).toBeTruthy(); expect(result.length).toBeGreaterThan(0); }); it('should handle very long chat history', () => { const longHistory: ChatMessage[] = Array.from({ length: 50 }, (_, i) => ({ role: i % 2 === 0 ? 'user' : 'assistant', content: `Message ${i} with some content to make it longer`, timestamp: Date.now() + i * 1000, })); const result = generateGhostwriterPrompt(longHistory, 'venting'); expect(result).toBeTruthy(); // Should truncate to avoid token limits expect(result.length).toBeLessThan(10000); }); it('should handle short chat history', () => { const shortHistory: ChatMessage[] = [ { role: 'user', content: 'Hi', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(shortHistory, 'venting'); expect(result).toBeTruthy(); }); it('should handle chat history with only user messages', () => { const userOnlyHistory: ChatMessage[] = [ { role: 'user', content: 'First thought', timestamp: Date.now() }, { role: 'user', content: 'Second thought', timestamp: Date.now() + 1000 }, { role: 'user', content: 'Third thought', timestamp: Date.now() + 2000 }, ]; const result = generateGhostwriterPrompt(userOnlyHistory, 'venting'); expect(result).toBeTruthy(); }); }); describe('generateGhostwriterPrompt - Intent-Specific Behavior', () => { it('should emphasize reframing struggle for venting intent', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'This error is driving me crazy', timestamp: Date.now() }, { role: 'assistant', content: 'What error are you seeing?', timestamp: Date.now() }, { role: 'user', content: 'Cannot read property of undefined', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'venting'); expect(result.toLowerCase()).toContain('struggle'); expect(result.toLowerCase()).toContain('lesson'); }); it('should emphasize articulating breakthrough for insight intent', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'I finally got it!', timestamp: Date.now() }, { role: 'assistant', content: 'What did you discover?', timestamp: Date.now() }, { role: 'user', content: 'The key was understanding the render cycle', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'insight'); expect(result.toLowerCase()).toContain('breakthrough'); expect(result.toLowerCase()).toContain('articulat'); }); }); describe('generateGhostwriterPrompt - Structure and Formatting', () => { it('should have clear section headers', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Test content', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'venting'); expect(result).toMatch(/context|requirements|output format/i); }); it('should be properly formatted for LLM consumption', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'Test message', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'venting'); // Should have numbered lists or clear structure expect(result).toMatch(/\d+\./); }); it('should include chat history formatted properly', () => { const chatHistory: ChatMessage[] = [ { role: 'user', content: 'User message here', timestamp: Date.now() }, { role: 'assistant', content: 'Teacher response here', timestamp: Date.now() }, ]; const result = generateGhostwriterPrompt(chatHistory, 'venting'); expect(result).toContain('Chat History'); expect(result).toContain('User message here'); expect(result).toContain('Teacher response here'); }); }); });