diff --git a/frontend/src/components/content/InteractivePracticeBlock.tsx b/frontend/src/components/content/InteractivePracticeBlock.tsx index ffaefc2..9a3be54 100644 --- a/frontend/src/components/content/InteractivePracticeBlock.tsx +++ b/frontend/src/components/content/InteractivePracticeBlock.tsx @@ -1,5 +1,5 @@ import { useRef, useState } from 'react' -import { CheckCircle2, Circle, ArrowRight } from 'lucide-react' +import { CheckCircle2, Circle, XCircle, ArrowRight } from 'lucide-react' import { Button } from '@/components/ui/button' import { Textarea } from '@/components/ui/textarea' @@ -26,6 +26,7 @@ export function InteractivePracticeBlock({ const interaction = block.interaction const startedAt = useRef(null) const [selectedOptionId, setSelectedOptionId] = useState(null) + const [submitted, setSubmitted] = useState(false) const [responseText, setResponseText] = useState('') if (interaction?.type !== 'multiple_choice') { @@ -47,11 +48,14 @@ export function InteractivePracticeBlock({

{interaction.prompt}

{interaction.options.map((option) => { const selected = option.option_id === selectedOptionId + const isCorrectOption = option.option_id === interaction.correct_option_id + const showCorrect = submitted && isCorrectOption + const showIncorrect = submitted && selected && !isCorrectOption return ( @@ -107,6 +121,7 @@ export function InteractivePracticeBlock({ if (!selectedOptionId) { return } + setSubmitted(true) onSubmit({ blockId: block.block_id ?? block.title, selectedOptionId, diff --git a/src/dibble/services/llm_prompting.py b/src/dibble/services/llm_prompting.py index cdc8cdb..f1e4aae 100644 --- a/src/dibble/services/llm_prompting.py +++ b/src/dibble/services/llm_prompting.py @@ -277,13 +277,17 @@ def _block_schema_contract(content_type: RequestedContentType) -> str: '{"kind":"summary","title":"...","body":"..."},' '{"kind":"practice_problem","title":"...","body":"...",' '"interaction":{"type":"multiple_choice","prompt":"...","options":[' - '{"option_id":"A","label":"Option A","body":"..."},' - '{"option_id":"B","label":"Option B","body":"..."}],' + '{"option_id":"A","label":"Option A","body":"why a student might pick this"},' + '{"option_id":"B","label":"Option B","body":"why a student might pick this"}],' '"correct_option_id":"B",' '"reveal":{"trigger":"after_selection","prompt":"...","support":"...","placeholder":"..."}}}' ']}. Always include at least one summary block and one practice_problem block. ' "For the practice_problem block, put the learner's actual choice set in interaction.options, " - "keep body to a short cue, and use plain text only." + "keep body to a short cue, and use plain text only. " + "CRITICAL: option body must NEVER reveal whether the option is correct or incorrect. " + "Do not use words like 'Correct', 'Right', 'Wrong', or 'Incorrect' in option body. " + "Option body should describe the reasoning or common misconception behind the choice, " + "not whether it is the right answer. Correctness feedback is shown separately after submission." ) return ( '{"blocks":[{"kind":"summary","title":"...","body":"..."},{"kind":"instruction","title":"...","body":"..."}]}. ' @@ -296,11 +300,12 @@ def _stream_schema_contract(content_type: RequestedContentType) -> str: return ( '{"block_index":0,"block":{"kind":"practice_problem","title":"...","body":"...",' '"interaction":{"type":"multiple_choice","prompt":"...","options":[' - '{"option_id":"A","label":"Option A","body":"..."},' - '{"option_id":"B","label":"Option B","body":"..."}],' + '{"option_id":"A","label":"Option A","body":"why a student might pick this"},' + '{"option_id":"B","label":"Option B","body":"why a student might pick this"}],' '"correct_option_id":"B",' '"reveal":{"trigger":"after_selection","prompt":"...","support":"...","placeholder":"..."}}},"done":true}. ' - "Emit one complete block object per line for interactive practice blocks." + "Emit one complete block object per line for interactive practice blocks. " + "Option body must NEVER reveal whether the option is correct or incorrect." ) return ( '{"block_index":0,"kind":"summary","title":"...","body_delta":"...","done":true}. '