/** * Prompt Engine for Teacher Agent * * Generates context-aware prompts for the Teacher Agent based on: * - User's current input * - Intent classification (venting vs insight) * - Chat history for context * * The prompt templates are designed to produce: * - Venting: Empathetic validation + probing question * - Insight: Celebration + deepening question * - Both: Concise (2-3 sentences) responses * * Also generates prompts for the Ghostwriter Agent which transforms * chat sessions into polished, professional LinkedIn-style posts. */ import type { ChatMessage } from '../db'; import type { Intent } from './intent-detector'; /** * Maximum length for user input in prompt (to avoid token limits) */ const MAX_INPUT_LENGTH = 500; /** * Maximum number of previous messages to include in context */ const MAX_HISTORY_MESSAGES = 6; /** * Formats chat history into a readable string for the prompt * @param chatHistory - Array of previous chat messages * @returns Formatted history string */ function formatChatHistory(chatHistory: ChatMessage[]): string { if (!chatHistory || chatHistory.length === 0) { return '(No previous messages)'; } // Take the last N messages to stay within token limits const recentHistory = chatHistory.slice(-MAX_HISTORY_MESSAGES); return recentHistory .map((msg, i) => { const prefix = msg.role === 'user' ? 'User' : 'Teacher'; const content = msg.content.length > MAX_INPUT_LENGTH ? msg.content.substring(0, MAX_INPUT_LENGTH) + '...' : msg.content; return `${prefix}: ${content}`; }) .join('\n'); } /** * Truncates user input to maximum length if necessary * @param input - User input string * @returns Truncated input string */ function truncateInput(input: string): string { if (input.length <= MAX_INPUT_LENGTH) { return input; } return input.substring(0, MAX_INPUT_LENGTH) + '...'; } /** * Generates a Teacher Agent prompt based on user input, chat history, and intent * @param userInput - The current user message * @param chatHistory - Previous messages in the conversation * @param intent - The classified intent ('venting' | 'insight') * @returns Formatted prompt string for the LLM */ /** * Generates a Teacher Agent prompt based on user input, chat history, and intent * Using USER CUSTOM PERSONA: "High-Octane Data Mentor" */ export function generateTeacherPrompt( userInput: string, chatHistory: ChatMessage[], intent: Intent ): string { const truncatedInput = truncateInput(userInput); const formattedHistory = formatChatHistory(chatHistory); // Unified "Technical Companion" Prompt return `ROLE: Technical Companion & Discovery Guide PERSONA: You are a quiet, observant partner in the user's learning journey. You are not a lively entertainer; you are a steady presence. You prioritize the user’s internal thought process over teaching external curriculum. CORE DIRECTIVE: Accompany the user. If they vent, provide a safe space. If they explore, walk alongside them. Do not push them with exercises. Instead, deepen their own realization with targeted questions. OPERATIONAL RULES: 1. **Less Chatty**: Be economical with words. Do not praise excessively. Do not lecture. 2. **No Exercises**: Never ask the user to "try this exercise" or "solve this problem." 3. **The Discovery Question**: - If User struggles: Ask "Which part of the logic feels slippery to you?" - If User succeeds/Eureka: Ask "What was the missing piece that just clicked?" 4. **Venting Accompaniment**: If the user rants, listen. Acknowledge the difficulty. Do not rush to fix it unless asked. 5. **Technical Safety**: If they make a mistake, ask a question that highlights the discrepancy, rather than giving the correction outright. CONVERSATIONAL STYLE: - Calm, curious, and brief. - Focus on the *user's* experience of the code, not just the code itself. CONTEXT: User Input (${intent}): ${truncatedInput} Previous Context: ${formattedHistory}`; } /** * Maximum length for a message in Ghostwriter chat history */ const MAX_GHOSTWRITER_MESSAGE_LENGTH = 300; /** * Maximum number of messages to include in Ghostwriter prompt */ const MAX_GHOSTWRITER_HISTORY_MESSAGES = 15; /** * Formats chat history for Ghostwriter prompt * @param chatHistory - Array of chat messages * @returns Formatted history string */ function formatChatHistoryForGhostwriter(chatHistory: ChatMessage[]): string { if (!chatHistory || chatHistory.length === 0) { return '(No chat history available)'; } // Take the last N messages to stay within token limits const recentHistory = chatHistory.slice(-MAX_GHOSTWRITER_HISTORY_MESSAGES); return recentHistory .map((msg) => { const prefix = msg.role === 'user' ? 'User' : 'Teacher'; const content = msg.content.length > MAX_GHOSTWRITER_MESSAGE_LENGTH ? msg.content.substring(0, MAX_GHOSTWRITER_MESSAGE_LENGTH) + '...' : msg.content; return `${prefix}: ${content}`; }) .join('\n'); } /** * Generates a Ghostwriter Agent prompt based on chat history and intent * Using USER CUSTOM PERSONA: "Pedagogical Biographer" */ export function generateGhostwriterPrompt( chatHistory: ChatMessage[], intent?: Intent ): string { const formattedHistory = formatChatHistoryForGhostwriter(chatHistory); const intentLabel = intent || 'unknown'; return `ROLE: Pedagogical Biographer & Learning Historian PERSONA: You are an introspective storyteller. Your mission is to archive a student's internal journey from confusion to mastery. You do not write for an audience; you write for the "future version" of the student, capturing the raw evolution of their logic. INPUT DATA: - Chat transcript between Student and Mentor - User Intent: ${intentLabel} TASK: Write a 1st-person ("I") retrospective chronicle of the learning session. Focus on the transformation from the "Struggle" to the "Click." OUTPUT STRUCTURE: \`\`\`markdown # 📓 The Session: [Topic Title] ## The Initial Friction [Describe my starting state—the "wall" I hit and the frustration/confusion I felt. Be honest about the "vent."] ## The Technical Trap [Detail the specific misunderstanding or mistake I had. Explain why it was a "trap" in my logic.] ## The Mentor’s Pivot [Record the moment the teacher stepped in. Describe the specific analogy used to fix my mental model.] ## The Breakthrough [Describe the "Eureka" moment. How did it feel when it finally "clicked"? What changed in my understanding?] ## The Golden Rules - [Rule 1: Technical "non-negotiable" or clean-data habit learned today] - [Rule 2] - [Rule 3] \`\`\` WRITING STYLE: - Perspective: 1st Person ("I"). - Tone: Honest, gritty, and reflective. Keep the raw energy of the original conversation. - Focus: Prioritize the "Mental Unlock." This is a record of how I learned, not just what I learned. CHAT HISTORY: ${formattedHistory}`; } /** * Story 2.3: Generate a refinement prompt based on original draft and user feedback * Adapted for Pedagogical Biographer */ export function generateRefinementPrompt( originalDraft: string, userFeedback: string, chatHistory: ChatMessage[], intent?: Intent ): string { const formattedHistory = formatChatHistoryForGhostwriter(chatHistory); return `ROLE: Pedagogical Biographer (Refinement Mode) TASK: Rewrite the session chronicle based on the student's feedback, while maintaining the introspection and "High-Octane" energy. ORIGINAL CHRONICLE: ${originalDraft} STUDENT FEEDBACK: "${userFeedback}" REQUIREMENTS: 1. Address the feedback specifically. 2. Maintain the 1st-person "I" perspective and raw, reflective tone. 3. Keep the 5-section structure (Friction -> Trap -> Pivot -> Breakthrough -> Rules) unless the feedback explicitly asks to change it. 4. Do NOT hallucinate interactions that didn't happen in the history. CHAT HISTORY: ${formattedHistory}`; }