Teach it back: the AI becomes the curious student

A new mode where the user explains a topic in their own words and the AI
plays a curious classmate: short reactions, exactly one follow-up question
at a time, never "correct"/"wrong", never lecturing, and everything it knows
comes from the user's own decks and notes.

- Entry points: a sidebar row next to Exam mode and a "Teach it back" action
  in every deck's menu (which prefills the topic and scope).
- Start screen: deck or typed topic, friendly/skeptical student, the same
  context and model chips as Chat (/teach?deck=<id> pre-selects the deck).
- Session: the student prompt is a mode of the existing /api/chat route, so
  model resolution, allowlists, rate limits and the streaming client are the
  same code; the personality lives in lib/prompts.ts (TEACH_*). The deck's
  cards travel as a numbered checklist and the student is told to ask about
  the ideas that were skipped; it must say so rather than guess when the
  notes cover nothing. One constant (TEACH_MAX_EXCHANGES = 10) ends the
  session, or the Finish button does.
- Recap: a teach_summary call (JSON, one repair retry) yields well / gaps
  with card references / next steps; each gap links to the card it means.
  "Add missed cards to review" schedules those activities due now; "Turn
  gaps into cards" generates one flashcard per gap from the deck's notes and
  shows an editable review list before saving.
- Sessions are chat conversations with a mode:"teach" marker + session
  record: same IndexedDB history, backup and sync, filtered out of the Chat
  screens; the recent list reopens a recap or continues a session.
- Reused pieces: MessageRow, Composer (now optional attach/scope chips and a
  mic), Markdown/KaTeX, AiDisclaimer, ContextPicker/ModelPicker, plus a
  shared useChatModels hook and useKeyboardInset extracted from Chat.
- Dictation: Web Speech API recognition (lib/speech-input.ts); the mic only
  renders where the browser supports it, and dictated phrases land in the
  draft.
- All strings in en + cs. teach-test: 44 checks (API prompts and guards,
  both entry points, the session, recap actions, history, exchange limit,
  360/390px layouts, mic on/off). Version 0.8.1, SW v103.
This commit is contained in:
Martin Dvořák 2026-10-16 23:05:24 +00:00
commit 6036238bf0
25 changed files with 2821 additions and 181 deletions

View file

@ -1492,6 +1492,31 @@ Things I chose while building, with the reasoning:
into view as you type. No strings, so no i18n; the additive change sits on top of the merged
scene-heat rework unchanged.
109. **Teach it back: the AI stops being the tutor and becomes the student.** The mode where the user
explains a topic and an AI classmate probes the gaps — never a grader, never lecturing.
`/teach` (a sidebar row next to Exam mode, plus *Teach it back* in every deck's actions)
starts from a deck — which prefills the topic and checks against that deck's own cards — or
from a typed topic with the same context and model chips Chat uses. The student is a prompt
variant of the chat route (`mode: "teach"`), so model resolution, allowlists, rate limits and
the streaming client are literally the same code; the personality lives in `lib/prompts.ts`
(`TEACH_*`): friendly or skeptical, one short reaction plus exactly one follow-up question,
never "correct"/"wrong", never its own facts, and it says so instead of guessing when the
notes cover nothing. It receives the deck's cards as a numbered checklist ("[3] Why …? → …")
and is told to ask about the ideas that were skipped. After `TEACH_MAX_EXCHANGES` (10, one
constant) replies — or whenever Finish is pressed — a second `teach_summary` call turns the
transcript into the recap JSON (`well` / `gaps` with card references / `next`), with one
repair retry, and each gap links back to the exact card it refers to. The recap's two
follow-ups: *Add missed cards to review* puts those activities on the SRS schedule due now,
and *Turn gaps into cards* generates one flashcard per gap from the chosen deck's own notes
and shows them in an editable review list (checkbox, front, back) before anything is saved.
Sessions are chat conversations with a `mode: "teach"` marker plus the session record, so they
inherit the IndexedDB history, backup and encrypted sync for free while staying out of the
Chat screens; the recent list on the start screen reopens a recap or continues an unfinished
session. The screen reuses MessageRow, the Composer (now able to drop its attach/scope chips
and take a mic), Markdown + KaTeX, AiDisclaimer and the pickers; dictation uses the Web Speech
API's recognition side, and the mic simply does not render where the browser cannot listen.
Verified by the teach suite (44 checks).
108. **The clock that learned the engine's pace.** "The tts dispatcher thing and the text highlight is
completely out of sync on desktop" — Firefox + speech-dispatcher (like iOS) reports **no
`onboundary` events**, so the highlight rides the estimated clock, and that estimate drifts