Personalization
Make generation learner-aware with learnerContext, past work analysis, and topic-aware grading.
Edu SDK stays stateless: no learner database. Your app owns persistence. The SDK owns contracts and helpers that turn performance signals into better generation.
Personalization is additive. Pass optional learnerContext on any create* helper (including learning sets and study sessions). Generation remains grounded in content.
The loop
- Signals — explicit focus areas, past exams/homework, and/or quiz history
analyzePastWork— LLM diagnostic of past work →PastWorkAnalysisgradeQuiz/completeQuizAttempt— optionalbyTopicwhen questions havetopicsbuildLearnerContext— merge signals intoLearnerContext- Pass
learnerContextintocreate*/createLearningSet/createStudySession - Generated materials carry
topics(where applicable) so the next grade feeds the loop again
LearnerContext
type LearnerContext = {
focusAreas?: string[];
strongAreas?: string[];
pastPerformance?: Array<{
topic: string;
correct: number;
total: number;
lastAttemptAt?: string;
}>;
examInsights?: Array<{
sourceLabel?: string;
weakTopics: string[];
missedConcepts?: string[];
notes?: string;
}>;
priorities?: string[];
};All fields are optional. Pass only what you have.
Topic tags
Generated quizzes, flashcards, practice problems, and study-guide key concepts get 1–4 short topics tags.
On public TypeScript types, topics is optional so hand-authored materials can omit them. Generation requires topics; grading/byTopic only runs when topics are present.
QuizQuestion always requires an id (SDK-stamped on generate). Notes can take learnerContext but do not get topic tags on the body.
analyzePastWork
import { analyzePastWork } from "edu-sdk";
const analysis = await analyzePastWork({
model: "google/gemini-3.6-flash",
content: pastExamText, // or FileContent, or an array of sources
sourceLabel: "Fall midterm",
});
// analysis is Artifact<PastWorkAnalysis>
analysis.content.weakTopics;
analysis.content.suggestedFocusAreas;PastWorkAnalysis includes required weakTopics, plus optional strongTopics, missedConcepts, suggestedFocusAreas, notes, and sourceLabel (from options when provided).
gradeQuiz and byTopic
When questions include topics, gradeQuiz() (and assessment completion) may return byTopic:
{
topic: string;
correct: number;
total: number;
percentage: number;
}If no questions have topics, byTopic is omitted.
buildLearnerContext
Pure merge helper — no model call.
import {
analyzePastWork,
buildLearnerContext,
createStudySession,
gradeQuiz,
} from "edu-sdk";
const analysis = await analyzePastWork({
model,
content: pastExam,
sourceLabel: "Fall midterm",
});
const grade = gradeQuiz({ questions: quiz.content, answers });
const learnerContext = buildLearnerContext({
focusAreas: ["Series circuits"],
examAnalysis: analysis.content,
quizResults: [{ result: grade, attemptedAt: new Date().toISOString() }],
});
const session = await createStudySession({
model,
content: chapterText,
durationMinutes: 45,
learnerContext,
});examAnalysis accepts the fields from PastWorkAnalysis (or an array of analyses). Quiz results contribute only via result.byTopic.
Study sessions
With learnerContext, createStudySession():
- Seeds goals from
focusAreaswhen you do not passgoals - Biases the plan toward weaker/focus topics
- Forwards context into material generation
What React does today
<Quiz /> and <StudySession /> accept the same data shapes (QuizQuestion with optional topics, GradeQuizResult with optional byTopic). They do not render topics or byTopic yet — use onComplete / your own UI if you need to display them.
Related
- Concepts — shared options including
learnerContext createStudySession()— session-level biasgradeQuiz()—byTopicscoring- Study session flow — running a session in React