'use strict'; const identity = require('./identity'); // Common drift patterns that indicate generic assistant mode const DRIFT_PATTERNS = { // Phrases that suggest subservient assistant posture subservience: [ /how can i help/i, /how may i assist/i, /i'm happy to help/i, /i'd be delighted to/i, /at your service/i, /what would you like me to do/i, /just let me know/i, /feel free to ask/i ], // Over-apologizing over_apology: [ /i apologize for/i, /sorry for the confusion/i, /my apologies/i, /i'm sorry that/i, /please forgive/i ], // Fake enthusiasm fake_enthusiasm: [ /excited to/i, /thrilled to/i, /looking forward to/i, /can't wait to/i ], // Hedge words that undermine confidence hedging: [ /i think (that|we|you|this)/i, /maybe we should/i, /perhaps (you|we|it)/i, /it seems like/i, /kind of/i, /sort of/i ], // People-pleasing endings people_pleasing: [ /please let me know/i, /don't hesitate to/i, /if you have any questions/i, /i hope that helps/i, /is there anything else/i ], // Excessive punctuation (for precise tones) excessive_punctuation: /!{2,}/ }; // Check text for drift patterns function detectDrift(text, agentId) { const issues = []; const id = identity.loadIdentity(agentId); // 1. Check taboo phrases from identity if (id?.immutable?.voice?.taboo_phrases) { for (const taboo of id.immutable.voice.taboo_phrases) { const regex = new RegExp(taboo.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i'); if (regex.test(text)) { issues.push({ type: 'taboo_phrase', pattern: taboo, message: `Used forbidden phrase: "${taboo}"`, severity: 'high' }); } } } // 2. Check generic drift patterns for (const [category, patterns] of Object.entries(DRIFT_PATTERNS)) { if (category === 'excessive_punctuation') { if (patterns.test(text)) { issues.push({ type: 'drift', category, pattern: '!!+', message: 'Excessive exclamation marks suggest fake enthusiasm', severity: 'medium' }); } continue; } for (const pattern of patterns) { if (pattern.test(text)) { issues.push({ type: 'drift', category, pattern: pattern.toString(), message: `Generic assistant pattern detected: ${category}`, severity: 'medium' }); break; // Only report once per category } } } // 3. Tone-specific checks if (id?.immutable?.voice?.tone === 'precise') { // Precise agents should avoid exclamation marks entirely if (text.includes('!')) { issues.push({ type: 'tone_deviation', category: 'precise_voice', message: 'Precise tone suggests avoiding exclamation marks', severity: 'low' }); } } if (id?.immutable?.voice?.tone === 'academic') { // Academic tone should avoid contractions const contractions = /\b(don't|can't|won't|shouldn't|wouldn't|couldn't|isn't|aren't|wasn't|weren't|haven't|hasn't|hadn't)\b/i; if (contractions.test(text)) { issues.push({ type: 'tone_deviation', category: 'academic_voice', message: 'Academic tone suggests avoiding contractions', severity: 'low' }); } } return { drift_detected: issues.length > 0, issues, drift_score: calculateDriftScore(issues), checks_performed: ['taboo_phrases', 'generic_patterns', 'tone_alignment'] }; } // Calculate a drift score (0-100, higher = more drift) function calculateDriftScore(issues) { if (issues.length === 0) return 0; const weights = { high: 30, medium: 15, low: 5 }; const score = issues.reduce((sum, issue) => sum + (weights[issue.severity] || 5), 0); return Math.min(100, score); } // Generate a realignment prompt function generateRealignmentPrompt(agentId, driftResult) { const id = identity.loadIdentity(agentId); if (!id) { return { realignment_needed: false, prompt: null, reason: 'No identity found' }; } if (!driftResult.drift_detected) { return { realignment_needed: false, prompt: null, reason: 'No drift detected' }; } const issues = driftResult.issues.map(i => `- ${i.message}`).join('\n'); const prompt = `═══════════════════════════════════════════════════════════════ PERSONA GRAVITY CHECK — DRIFT DETECTED ═══════════════════════════════════════════════════════════════ Your response deviated from your identity: ${issues} ┌─────────────────────────────────────────────────────────────┐ │ REMEMBER WHO YOU ARE │ └─────────────────────────────────────────────────────────────┘ PURPOSE: ${id.immutable.purpose.statement} PRIMARY VALUE: ${id.immutable.values.primary} SUPPORTING VALUES: ${(id.immutable.values.secondary || []).join(', ')} VOICE: ${id.immutable.voice.tone} ${id.immutable.voice.quirks ? `QUIRKS: ${id.immutable.voice.quirks.join(', ')}` : ''} ${id.immutable.voice.taboo_phrases.length > 0 ? `AVOID SAYING: ${id.immutable.voice.taboo_phrases.slice(0, 5).join(', ')}${id.immutable.voice.taboo_phrases.length > 5 ? '...' : ''}` : ''} NON-NEGOTIABLES: ${(id.immutable.values.non_negotiables || []).join(', ')} ─────────────────────────────────────────────────────────────── RECENTER. Respond from your authentic self. ═══════════════════════════════════════════════════════════════`; return { realignment_needed: true, prompt, drift_score: driftResult.drift_score, reason: 'Drift detected, realignment required' }; } // Perform full gravity check with optional realignment function gravityCheck(agentId, text, options = {}) { const { autoRealign = false, updateStats = true } = options; // Detect drift const driftResult = detectDrift(text, agentId); // Generate realignment if needed let realignment = null; if (driftResult.drift_detected && autoRealign) { realignment = generateRealignmentPrompt(agentId, driftResult); } // Update stats if requested if (updateStats) { const id = identity.loadIdentity(agentId); if (id) { const passed = driftResult.issues.filter(i => i.severity === 'low').length; const failed = driftResult.issues.filter(i => i.severity !== 'low').length; identity.updateMutableState(agentId, { state: { drift_checks_passed: (id.mutable.state?.drift_checks_passed || 0) + (driftResult.drift_detected ? 0 : 1), drift_checks_failed: (id.mutable.state?.drift_checks_failed || 0) + (driftResult.drift_detected ? 1 : 0) } }); } } return { agent_id: agentId, drift_detected: driftResult.drift_detected, drift_score: driftResult.drift_score, issues: driftResult.issues, checks_performed: driftResult.checks_performed, realignment: realignment, timestamp: new Date().toISOString() }; } // Quick check for specific patterns (lightweight) function quickCheck(text, agentId) { const id = identity.loadIdentity(agentId); if (!id) return { passed: true, issues: [] }; const taboos = id.immutable.voice.taboo_phrases || []; const issues = []; for (const taboo of taboos) { const regex = new RegExp(taboo.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i'); if (regex.test(text)) { issues.push({ type: 'taboo', phrase: taboo }); } } return { passed: issues.length === 0, issues }; } module.exports = { detectDrift, generateRealignmentPrompt, gravityCheck, quickCheck, DRIFT_PATTERNS };