Edu SDKEdu SDK

Study session flow

Turn createStudySession output into a timed UI with React.

createStudySession() returns a timed agenda plus nested learning materials. Use <StudySession /> for the default runner, or build your own from blocks and materials.

What you get

import { createStudySession } from "edu-sdk";

const session = await createStudySession({
  model: "google/gemini-3.6-flash",
  content,
  durationMinutes: 45,
  difficulty: "medium",
});

const { topic, goals, tips, blocks, materials } = session.content;
  • blocks — ordered agenda items (read, flashcards, quiz, break, …) with durations and instructions.
  • materials — a LearningSetContent object: nested full artifacts keyed by type (quiz, flashcards, …). May be {} if nothing was allocated.

Under the hood the SDK plans the session, then generates materials with createLearningSet.

Default: <StudySession />

import { StudySession } from "@edu-sdk/react";
import "@edu-sdk/react/styles.css";

<StudySession session={session.content} />

The component owns block progress, a per-block countdown, Skip / Next / Finish, and mounts the matching material components. Customize nested materials with renderQuiz / quizProps (and the same pattern for flashcards, practice problems, study guide, and renderNotes) — see <StudySession />. You do not need a fully custom runner just to style a nested quiz or attach onComplete.

Custom runner

If you need different session UX (custom timers, forced revisit rules, etc.), walk blocks yourself and compose materials:

for (const block of blocks) {
  console.log(block.title, block.durationMinutes, block.instructions);

  if (block.materialKey === "quiz" && materials.quiz) {
    // materials.quiz is Artifact<QuizQuestion[]>
    renderQuiz(materials.quiz.content);
  }

  if (block.materialKey === "flashcards" && materials.flashcards) {
    renderFlashcards(materials.flashcards.content);
  }

  // break / read / review often have no materialKey
}

materialKey is only set when that material was allocated. Blocks like break or read usually have none.

import { Quiz, Flashcards, StudyGuide, PracticeProblems } from "@edu-sdk/react";
import "@edu-sdk/react/styles.css";

function SessionBlock({ block, materials }) {
  switch (block.materialKey) {
    case "quiz":
      return materials.quiz ? (
        <Quiz questions={materials.quiz.content} />
      ) : null;
    case "flashcards":
      return materials.flashcards ? (
        <Flashcards flashcards={materials.flashcards.content} />
      ) : null;
    case "practiceProblems":
      return materials.practiceProblems ? (
        <PracticeProblems problems={materials.practiceProblems.content} />
      ) : null;
    case "studyGuide":
      return materials.studyGuide ? (
        <StudyGuide studyGuide={materials.studyGuide} />
      ) : null;
    case "notes":
      return materials.notes ? (
        <article>{/* render Markdown: materials.notes.content */}</article>
      ) : null;
    default:
      return <p>{block.instructions}</p>;
  }
}

Remember: list UIs take .content; StudyGuide takes the full nested artifact.

What your app still owns

  • Persistence of session state (even with <StudySession />, use the callbacks)
  • A Markdown renderer for notes if you want more than plain text (renderNotes or your own UI)
  • Nested material styling/callbacks via *Props, or full replacement via render* on <StudySession />
  • Any UX beyond the default runner (custom timers, forced revisit rules, etc.) when you build your own

See also Concepts and createStudySession.

On this page