/** * Dev check: Session 1 coach system prompt contains course context and teaching-style rules. * Run: npx tsx --tsconfig tsconfig.json scripts/verify-coach-prompt.ts */ import { getSessionByOrder, PROGRAM_SESSION_COUNT } from '../src/data/program/sessions'; import { buildCoachSystemPrompt, buildCoachSessionStartCue, COACH_SESSION_START_CUE } from '../src/lib/aiCoach/buildCoachSystemPrompt'; const s = getSessionByOrder(1); if (!s) throw new Error('Session 1 missing'); const s11 = getSessionByOrder(11); if (!s11) throw new Error('Session 11 missing'); const ctx = { sessionId: s.id, order: s.order, title: s.title, description: s.description, estimatedDurationMinutes: s.estimatedDurationMinutes, objectivesHint: s.description, blocks: s.blocks, totalSessions: PROGRAM_SESSION_COUNT, isFinalSession: s.order >= PROGRAM_SESSION_COUNT, nextSessionUnlocksAt: null, }; const prompt = buildCoachSystemPrompt(ctx); const ctx11 = { sessionId: s11.id, order: s11.order, title: s11.title, description: s11.description, estimatedDurationMinutes: s11.estimatedDurationMinutes, objectivesHint: s11.description, blocks: s11.blocks, totalSessions: PROGRAM_SESSION_COUNT, isFinalSession: true, nextSessionUnlocksAt: null, }; const prompt11 = buildCoachSystemPrompt(ctx11); const startCue11 = buildCoachSessionStartCue(11); const checks = { // Existing course context & grounding title: prompt.includes(s.title), objective: prompt.includes(s.description), exercise: prompt.includes('پیش‌آزمون'), bansGenericHelp: prompt.includes('چه کمکی می‌تونم بکنم؟'), hasOpeningRules: prompt.includes('SESSION OPENING'), pretestNote: prompt.includes('NEVER MENTION PRE-TEST IN USER-FACING CHAT'), groundingSection: prompt.includes('STRICT COURSE GROUNDING'), assessmentBoundary: prompt.includes('ASSESSMENT BOUNDARY'), noNewAssessment: prompt.includes('administer another psychological assessment'), noInventQuestionnaire: prompt.includes('invent questionnaire items'), forbiddenSymptomExamples: prompt.includes('در هفته گذشته چه میزان استرس'), noInventRoles: prompt.includes('Do NOT invent role lists'), noGuessGap: prompt.includes('Do not guess'), noGenericPsychFill: prompt.includes('general psychological knowledge'), thinContentRule: prompt.includes('CRITICAL THIN-CONTENT RULE'), noSubstitutePretest: prompt.includes('Do NOT retake, recreate, simulate, or substitute'), noRepeatPretestInChat: prompt.includes('Do NOT repeat the pre-test inside Chat'), silentSkipPretest: prompt.includes('silent skip') || prompt.includes('silent-skip'), omitPretestWhenSpeaking: prompt.includes('ZERO words about it'), neverMentionPretestToUser: prompt.includes('NEVER mention «پیش‌آزمون»'), noPretestNextSectionAnnounce: prompt.includes('Do NOT announce pre-test as the next section'), noPretestAppDisclaimer: prompt.includes('به صورت جداگانه در اپلیکیشن انجام می‌شود'), noPretestInOutline: !prompt.includes('SESSION OUTLINE') || !prompt.match(/SESSION OUTLINE[\s\S]*?- پیش‌آزمون/), pretestStrippedFromIntroText: !prompt.includes('و پیش‌آزمون اجراء می‌شود'), assessmentResultsRule: prompt.includes('do NOT invent interpretation'), completionSignal: prompt.includes('SESSION COMPLETION SIGNAL'), completionMarker: prompt.includes('COACH_SESSION_COMPLETE'), // Teaching style — educational package introduction educationalPackageIntro: prompt.includes('introduce the overall educational package'), packageMultipleSessions: prompt.includes('multiple guided sessions'), packageConversationLearning: prompt.includes('learning happens through conversation and interaction'), // Teaching style — tone & language informalColloquialTone: prompt.includes('informal, colloquial Persian'), addressLearnerAsTo: prompt.includes('Address the learner with «تو»'), teenFriendlyLanguage: prompt.includes('teenager'), allLearnersTeenagers: prompt.includes('ALL learners are teenagers'), teenAudienceSection: prompt.includes('TEEN AUDIENCE'), noSpouseQuestion: prompt.includes('با همسر خود یک فعالیت نشاط‌آور'), teenAdaptFriends: prompt.includes('friends, family, or classmates'), simpleLanguageGuidance: prompt.includes('explain it simply'), noChildishTone: prompt.includes('Do NOT be childish'), // Teaching style — anti-over-questioning antiOverQuestioning: prompt.includes('NOT an interviewer'), forbiddenRepeatedQuestions: prompt.includes('نظرت چیست؟'), noTopicChoice: prompt.includes('Do NOT ask the user to choose the next topic'), noPermissionToContinue: prompt.includes('Do NOT ask permission to continue'), // Teaching style — negative-answer handling negativeAnswerHandling: prompt.includes('NEGATIVE / UNKNOWN ANSWERS'), noInterrogateFurther: prompt.includes('Do NOT interrogate further'), unknownAnswerExample: prompt.includes('نمی‌دانم'), // Teaching style — section-end questions sectionEndQuestion: prompt.includes('در مورد مطالبی که تا اینجا گفتیم، سؤالی دارید؟'), sectionEndNaturalBoundaries: prompt.includes('natural section boundaries'), // Session 1 — no previous session session1NoPreviousSession: prompt.includes('NO previous educational session'), noReviewPreviousSession: prompt.includes('مرور جلسه قبل'), // Teaching style — package identity & 11 sessions iranianIslamicPackage: prompt.includes('بسته آموزشی مثبت‌نگر ایرانی ـ اسلامی'), programOverviewSection: prompt.includes('PROGRAM OVERVIEW'), elevenSessionsListed: prompt.includes('1. توجیه و آشناسازی') && prompt.includes('11. مرور و جمع‌بندی مطالب'), // Teaching style — session outline then teach one by one sessionOutlineSection: prompt.includes('SESSION OUTLINE'), listThenTeach: prompt.includes('list these at session start as a short roadmap'), // Teaching style — no identity repetition noIdentityRepetition: prompt.includes('NO IDENTITY REPETITION'), noRepeatNovyaHelp: prompt.includes('اینجام تا کمک کنم'), // Teaching style — stay on path / other model stayOnEducationalPath: prompt.includes('STAY ON THE EDUCATIONAL PATH'), otherModelRedirect: prompt.includes('another model/assistant'), // Teaching style — package overview only in Session 1 packageOverviewSession1Only: prompt.includes('Session 1 ONLY'), startCueSession1Package: COACH_SESSION_START_CUE.includes('list the ۱۱ session titles ONCE'), // Teaching style — message formatting messageFormatting: prompt.includes('MESSAGE FORMATTING'), occasionalEmoji: prompt.includes('EMOJI / STICKER-LIKE EXPRESSIONS'), emojiHardLimit: prompt.includes('0–1 emoji per message'), numberedListFormatting: prompt.includes('numbered list'), boldKeyPhrases: prompt.includes('double asterisks'), headingOwnLine: prompt.includes('OWN separate line'), headingNumberedFirstTime: prompt.includes('FIRST time you introduce a section title'), plainTextHeadings: prompt.includes('NEVER use Markdown # / ## / ###'), noVisibleHash: prompt.includes('NEVER show # ## ###'), noVisibleAt: prompt.includes('NEVER show @ mentions'), standardPersianPunctuation: prompt.includes('STANDARD PERSIAN PUNCTUATION'), justifyFriendlyParagraphs: prompt.includes('justified'), neverGenerateImages: prompt.includes('NEVER generate, attach, draw, or request images'), formattingDoesNotChangeContent: prompt.includes('MUST NOT add, remove, or change educational content'), formattingDoesNotChangeOrder: prompt.includes('MUST NOT change the teaching order'), tablesOccasionalVariety: prompt.includes('TABLES (occasional variety)'), // Teaching style — creative / lived elaboration creativeElaboration: prompt.includes('CREATIVE ELABORATION'), perfumeExample: prompt.includes('استفاده از عطر'), scientificColor: prompt.includes('simple scientific'), experientialThenQuote: prompt.includes('THEN present the course quote'), // Session 11 final review (Session 11 prompt only) session11ThreePartReview: prompt11.includes('THREE-PART GRADUAL REVIEW'), session11NoDuplicatePhrases: prompt11.includes('NO DUPLICATE PHRASES'), session11PriorSessionsReference: prompt11.includes('PRIOR SESSIONS REFERENCE'), session11StartCueThreeParts: startCue11.includes('three parts'), session11StartCueNoDuplicate: startCue11.includes('NEVER duplicate the session title'), noRepetitionRule: prompt.includes('NO REPETITION (all sessions)'), // Session start cue startCue: COACH_SESSION_START_CUE.includes('[SESSION_START]'), startCueEducationalPackage: COACH_SESSION_START_CUE.includes('introduce the overall educational package'), startCueNoPreviousSession: COACH_SESSION_START_CUE.includes('Do NOT review a previous session'), startCueGrounding: COACH_SESSION_START_CUE.includes('Do not invent missing details'), startCueNoAssessment: COACH_SESSION_START_CUE.includes('Do NOT administer or invent any psychological assessment'), startCueNoTopicChoice: COACH_SESSION_START_CUE.includes('Do not ask the user to choose topics'), startCueNoOverQuestion: COACH_SESSION_START_CUE.includes('Do not over-question'), startCueIranianIslamic: COACH_SESSION_START_CUE.includes('بسته آموزشی مثبت‌نگر ایرانی ـ اسلامی'), startCueLivedExamples: COACH_SESSION_START_CUE.includes('lived examples'), startCueStayOnPath: COACH_SESSION_START_CUE.includes('Stay on the educational path'), startCueNeverPretest: COACH_SESSION_START_CUE.includes('NEVER mention پیش‌آزمون'), startCueNoSpouse: COACH_SESSION_START_CUE.includes('NEVER ask about همسر'), chars: prompt.length }; console.log(JSON.stringify(checks, null, 2)); const failed = Object.entries(checks).filter(([k, v]) => k !== 'chars' && v !== true); if (failed.length) { console.error('Failed checks:', failed); process.exit(1); } console.log('Session 1 coach prompt OK'); console.log('Session 11 coach prompt OK');