Files
brachnha-insight/src/lib/llm/prompt-engine.ts
Max 3fbbb1a93b Initial commit: Brachnha Insight project setup
- Next.js 14+ with App Router and TypeScript
- Tailwind CSS and ShadCN UI styling
- Zustand state management
- Dexie.js for IndexedDB (local-first data)
- Auth.js v5 for authentication
- BMAD framework integration

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-26 12:28:43 +07:00

228 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 users 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 Mentors 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}`;
}