Files
pwa/scripts/verify-coach-prompt.ts
T
ar.badieiandCursor c6243caa35 Add read-only Noya admin panel with assignments and UX polish.
Ship admin auth, user overview, assessments, chats, assignment filters/export, security hardening, and a separate desktop admin shell with clearer assessment answers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 08:00:24 +03:30

192 lines
9.9 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.
/**
* 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'),
chatgptLayout: prompt.includes('Write like ChatGPT'),
shortParagraphs: prompt.includes('1–2 short sentences per paragraph'),
occasionalEmoji: prompt.includes('EMOJI / STICKER-LIKE EXPRESSIONS'),
emojiHardLimit: prompt.includes('0–1 emoji per message'),
numberedListFormatting: prompt.includes('numbered list') || prompt.includes('numbered ۱'),
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') || prompt.includes('Write like ChatGPT'),
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('بسته آموزشی مثبت‌نگر ایرانی ـ اسلامی'),
startCueInformalTone: COACH_SESSION_START_CUE.includes('informal colloquial Persian'),
startCueGrounding: COACH_SESSION_START_CUE.includes('Do not invent missing details'),
startCueNoAssessment: COACH_SESSION_START_CUE.includes('or assessments'),
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('بسته آموزشی مثبت‌نگر ایرانی ـ اسلامی'),
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');