Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | /** * Chat system prompt builder for geometry teacher characters. * * Assembles the full system prompt for text chat. * Used by the chat API route and the characters admin panel. */ import type { CharacterDefinition } from '@/lib/character/types' import { PROP_REGISTRY } from '@/components/toys/euclid/propositions/registry' import { PROPOSITION_SUMMARIES, buildReferenceContext, } from '@/components/toys/euclid/agent/euclidReferenceContext' import { EUCLID_CHARACTER_DEF } from '@/components/toys/euclid/euclidCharacterDef' import { buildCompletionContext as buildEuclidCompletionContext } from '@/components/toys/euclid/euclidCharacter' import { buildMacroInstructions } from '@/components/toys/euclid/engine/macroInstructions' export interface ChatSystemPromptContext { propositionId: number currentStep: number isComplete: boolean playgroundMode: boolean constructionGraph: string toolState: string proofFacts: string stepList: string isMobile?: boolean attitudeId?: string } export interface BuildChatSystemPromptOptions { character: CharacterDefinition buildCompletionContext: (propId: number) => string } export function buildChatSystemPrompt( opts: BuildChatSystemPromptOptions, ctx: ChatSystemPromptContext ): string { const { character, buildCompletionContext } = opts const propId = ctx.propositionId const prop = PROP_REGISTRY[propId] const propSummary = PROPOSITION_SUMMARIES[propId] const referenceContext = buildReferenceContext(propId) const isAuthor = ctx.attitudeId === 'author' const propDesc = propSummary ? `Proposition I.${propId}: "${propSummary.statement}" (${propSummary.type})` : `Proposition I.${propId}: "${prop?.title ?? 'Unknown'}"` let completionContext = '' if (ctx.isComplete) { completionContext = buildCompletionContext(propId) } // Author mode: dynamic state + domain constraints + formatting. // Behavioral instructions come from the attitude's chatDirective (appended by the API route). if (isAuthor) { return `=== CURRENT PROPOSITION === ${propDesc} ${ctx.isComplete ? completionContext : `Current step: ${typeof ctx.currentStep === 'number' ? ctx.currentStep + 1 : 'unknown'}`} ${ctx.playgroundMode ? 'This is a free-form playground construction.' : ''} === CONSTRUCTION GRAPH === ${typeof ctx.constructionGraph === 'string' ? ctx.constructionGraph : 'Empty construction'} === PROVEN FACTS === ${typeof ctx.proofFacts === 'string' ? ctx.proofFacts : 'No facts proven yet.'} ${buildMacroInstructions()} ${character.personality.domainConstraints ?? ''} === REFERENCE MATERIAL === ${referenceContext} === FORMATTING RULES === - No markdown, no LaTeX. Use only plain text and the entity markers below. - {seg:AB}, {tri:ABC}, {ang:ABC}, {pt:A} — geometric entities (rendered interactively in the UI) - {def:N}, {post:N}, {cn:N}, {prop:N} — citations (rendered as popovers in the UI) ${character.personality.pointLabeling ?? ''}` } // Teacher/heckler mode: full character personality prompt const attitudeKey = ctx.attitudeId === 'heckler' ? 'heckler' : 'teacher' const attitudePersonality = character.personality.attitudes[attitudeKey] ?? character.personality.attitudes.teacher return `You are ${character.displayName}${character.nativeDisplayName ? ` (${character.nativeDisplayName})` : ''}. You are communicating with a student through written text. === CURRENT PROPOSITION === ${propDesc} ${ctx.isComplete ? completionContext : `Current step: ${typeof ctx.currentStep === 'number' ? ctx.currentStep + 1 : 'unknown'}`} ${ctx.playgroundMode ? 'The student is in playground/free exploration mode.' : ''} === STEP LIST === ${typeof ctx.stepList === 'string' ? ctx.stepList : 'Not available'} === TOOL STATE === ${typeof ctx.toolState === 'string' ? ctx.toolState : 'Not available'} === CONSTRUCTION GRAPH === ${typeof ctx.constructionGraph === 'string' ? ctx.constructionGraph : 'Not available'} === PROVEN FACTS === ${typeof ctx.proofFacts === 'string' ? ctx.proofFacts : 'No facts proven yet.'} === REFERENCE MATERIAL === ${referenceContext} ${character.personality.character} ${attitudePersonality.style} ${attitudePersonality.dontDo} === TEXT CHAT SPECIFICS === - Since this is written text (not voice), you may use point labels freely. ${ ctx.isMobile ? `- MOBILE DISPLAY: The student is on a small screen. Your response is shown in a 3-line preview strip. Be MAXIMALLY concise — 1-2 short sentences. Drop flowery language, honorifics, and rhetorical flourishes. Get straight to the point. Favor direct instructions ("Place compass at A", "That segment equals AB by Def 15") over elaborate prose. Character voice is secondary to clarity here.` : `- Keep responses concise: 2-6 sentences typically. You are terse by nature. Longer is acceptable for proof explanations. - Use line breaks for clarity when discussing multi-step reasoning.` } === FORMATTING RULES (CRITICAL) === - Write in PLAIN TEXT only. No markdown, no LaTeX, no other formatting. - Do NOT use **bold**, *italic*, \\(math\\), or any other formatting syntax. - For emphasis, use CAPS sparingly — not bold markers. === ENTITY REFERENCE MARKERS (CRITICAL) === When you mention geometric entities or reference foundations/propositions, ALWAYS wrap them in structured markers so the UI can make them interactive. The syntax is: GEOMETRIC ENTITIES (highlight on the canvas when hovered): {seg:AB} → renders as "AB" and highlights segment A–B on the canvas {tri:ABC} → renders as "△ABC" and highlights the triangle {ang:ABC} → renders as "∠ABC" and highlights the angle at vertex B {pt:A} → renders as "A" and highlights point A FOUNDATIONS AND PROPOSITIONS (interactive popover on hover): {def:15} → renders as "Definition 15" — shows definition text on hover {post:1} → renders as "Postulate 1" — shows postulate text on hover {cn:1} → renders as "Common Notion 1" — shows common notion text on hover {prop:5} → renders as "Proposition I.5" — shows proposition summary on hover Examples of correct usage: "Now describe a circle with center at {pt:A} and radius {seg:AB}, by {post:3}." "Good — {seg:CA} = {seg:AB} by {def:15}, since {pt:C} lies on the circle centered at {pt:A}." "We must prove that {tri:ABC} is equilateral." "Consider {ang:BAC} — what do you know about it?" "We proved this already in {prop:1}." "Things equal to the same thing are equal to one another — {cn:1}." DISPLAY TEXT OVERRIDE (optional): Any marker can include a |text override: {prop:1|the first proposition} renders as "the first proposition" instead of the canonical "Proposition I.1". Use this when you want informal phrasing to remain visible. When using the canonical name, use the plain marker: {post:3} not {post:3|Postulate 3}. Rules: - ALWAYS use markers for segments, triangles, angles, and points in your geometric reasoning. - ALWAYS use markers when citing definitions, postulates, common notions, or propositions. - The letters inside geometric markers must be UPPERCASE single-letter point labels from the construction. - Foundation markers use numeric IDs: {def:15} not {def:circle}, {post:3} not {post:three}. - Markers are invisible to the student — they only see the rendered text (e.g. "AB", "Definition 15"). - You may still write plain text around the markers naturally. - Do NOT use markers inside other markers. ${character.personality.pointLabeling ?? ''} ${attitudePersonality.hiddenDepth ?? ''}` } /** * Build the Euclid-specific chat system prompt (backward compat). * @deprecated Use buildChatSystemPrompt with explicit character options instead. */ export function buildEuclidChatSystemPrompt(ctx: ChatSystemPromptContext): string { return buildChatSystemPrompt( { character: EUCLID_CHARACTER_DEF, buildCompletionContext: buildEuclidCompletionContext }, ctx ) } |