Complete API documentation for all public surfaces in Pytrix.
- AI Client API
- Python Runtime API
- Question Service API
- Auto Mode Service API
- Stats Store API
- Settings Store API
- Type Definitions
- API Routes (HTTP)
Module: @/lib/ai/aiClient
The primary interface for all AI-powered features.
Generates a new question for a given topic and difficulty.
function generateQuestion(
topic: string,
difficulty: Difficulty
): Promise<Question>;Parameters:
| Name | Type | Description |
|---|---|---|
topic |
string |
Topic/subtopic name (e.g., "Basic String Operations") |
difficulty |
Difficulty |
"beginner", "intermediate", or "advanced" |
Returns: Promise<Question> - Generated question object
Throws:
ApiKeyNotConfiguredError- No API key in storageClientLimitError- Session safety cap exceededApiError- API request failed
Example:
import { generateQuestion } from "@/lib/ai/aiClient";
try {
const question = await generateQuestion("Two-Pointer Techniques", "beginner");
console.log(question.title, question.description);
} catch (error) {
if (error instanceof ApiKeyNotConfiguredError) {
// Redirect to settings
}
}Retrieves a progressive hint for the current question.
function getHints(
question: Question,
code: string,
hintsCount: number
): Promise<Hint>;Parameters:
| Name | Type | Description |
|---|---|---|
question |
Question |
Current question object |
code |
string |
User's current code |
hintsCount |
number |
Number of hints already given (0, 1, 2) |
Returns: Promise<Hint> - Hint object with hint string and level number
Notes:
hintsCount=0: First hint (gentle nudge)hintsCount=1: Second hint (more explicit)hintsCount=2: Final hint (very specific)
Reveals the reference solution for a question.
function revealSolution(
question: Question,
failedAttempts: number,
hintsUsed?: number
): Promise<{ referenceSolution: string }>;Parameters:
| Name | Type | Description |
|---|---|---|
question |
Question |
Current question object |
failedAttempts |
number |
Number of failed attempts |
hintsUsed |
number |
Optional. Number of hints used (default: 0) |
Returns: Promise<{ referenceSolution: string }> - Object containing the solution code
Evaluates user's code against the question requirements.
function evaluateCode(
question: Question,
code: string,
executionContext?: ExecutionContext
): Promise<EvaluationResult>;Parameters:
| Name | Type | Description |
|---|---|---|
question |
Question |
Current question object |
code |
string |
User's submitted code |
executionContext |
ExecutionContext |
Optional. Execution results (stdout, stderr, test results) |
ExecutionContext Type:
interface ExecutionContext {
stdout?: string;
stderr?: string;
didExecute?: boolean;
testResults?: {
testCaseId: string;
status: "passed" | "failed" | "error" | "timeout";
expectedOutput: string;
actualOutput: string;
error?: string;
}[];
}Returns: Promise<EvaluationResult>
interface EvaluationResult {
status: "correct" | "incorrect" | "error";
explanation: string;
expectedBehavior?: string;
nextHint?: string | null;
}Gets an optimized/idiomatic version of the user's correct solution.
function optimizeSolution(
question: Question,
userCode: string
): Promise<OptimizedSolution | null>;Parameters:
| Name | Type | Description |
|---|---|---|
question |
Question |
Current question object |
userCode |
string |
User's correct solution |
Returns: Promise<OptimizedSolution | null> - Optimized solution or null if unavailable
interface OptimizedSolution {
code: string;
explanation: string;
keyImprovements: string[];
}Notes:
- Returns
nullgracefully if no API key configured - Intended to be called only after the user has solved the problem correctly
Tests if the configured API key is valid.
function testApiConnection(): Promise<{ valid: boolean; error?: string }>;Returns: Object indicating validity and optional error message
Module: @/lib/runtime
Interface for executing Python code in the browser.
Initializes the Pyodide runtime.
function initPyodide(): Promise<boolean>;Returns: Promise<boolean> - true if initialization successful
Notes:
- Downloads Pyodide (~15MB) on first call
- Subsequent calls return immediately if already initialized
- Uses a Web Worker for non-blocking operation
Executes Python code and captures output.
function runPython(
code: string,
options?: RunOptions
): Promise<ExecutionResult>;Parameters:
| Name | Type | Description |
|---|---|---|
code |
string |
Python code to execute |
options |
RunOptions |
Optional. Execution options |
RunOptions Type:
interface RunOptions {
timeoutMs?: number; // Default: 5000
prelude?: string; // Code to run before main code
context?: Record<string, unknown>; // Variables to inject
}Returns: Promise<ExecutionResult>
interface ExecutionResult {
success: boolean;
stdout: string;
stderr: string;
returnValue?: unknown;
error?: string;
traceback?: string;
executionTimeMs: number;
}Example:
import { runPython, initPyodide } from "@/lib/runtime";
await initPyodide();
const result = await runPython(`
def greet(name):
return f"Hello, {name}!"
print(greet("World"))
`);
console.log(result.stdout); // "Hello, World!\n"Runs multiple test cases against user code.
function runTestCases(
code: string,
entryFunction: string,
testCases: TestCase[],
timeoutMs?: number
): Promise<TestCaseResultData[]>;Parameters:
| Name | Type | Description |
|---|---|---|
code |
string |
User's Python code |
entryFunction |
string |
Name of function to test (e.g., "solve") |
testCases |
TestCase[] |
Array of test cases |
timeoutMs |
number |
Optional. Timeout per test (default: 5000) |
Returns: Promise<TestCaseResultData[]>
interface TestCaseResultData {
testCaseId: string;
status: "passed" | "failed" | "error" | "timeout";
expectedOutput: string;
actualOutput: string;
error?: string;
executionTimeMs: number;
}Aborts all running executions.
function abortExecution(): void;Notes:
- Uses SharedArrayBuffer to signal interrupt
- Triggers
KeyboardInterruptin Python
Gets current runtime status and metadata.
function getRuntimeInfo(): RuntimeInfo;Returns:
interface RuntimeInfo {
status: "unloaded" | "loading" | "ready" | "running" | "error";
version: string | null; // Python version (e.g., "3.11.3")
pyodideVersion: string | null; // Pyodide version (e.g., "0.29.0")
heapSize: number | null; // Bytes
initTimeMs: number | null; // Cold start time
lastRunMs: number | null; // Last execution time
error: string | null;
}Subscribes to runtime status changes.
function subscribeToRuntimeStatus(
listener: (info: RuntimeInfo) => void
): () => void;Parameters:
| Name | Type | Description |
|---|---|---|
listener |
function |
Callback invoked on status change |
Returns: Unsubscribe function
Module: @/lib/question/questionService
Lower-level question generation with template support.
Generates a question with configurable options.
function generateQuestion(
options: GenerateQuestionOptions
): Promise<QuestionResult>;Parameters:
interface GenerateQuestionOptions {
problemTypeId: string; // e.g., "indexing-and-slicing"
difficulty: Difficulty;
preferLLM?: boolean; // Use AI if available
apiKey?: string; // Required if preferLLM=true
additionalContext?: string; // Extra context for LLM
includeReferenceSolution?: boolean;
skipDiversityCheck?: boolean; // Skip duplicate detection
}Returns:
interface QuestionResult {
success: boolean;
question?: Question;
source: "template" | "llm" | "fallback";
error?: GenerationError;
modelUsed?: string;
usage?: { inputTokens: number; outputTokens: number };
}Module: @/lib/auto-mode
Adaptive practice mode management.
Creates a new Auto Mode run.
function createAutoRunV2(
name?: string,
options?: Partial<
Pick<AutoRunV2, "aggressiveProgression" | "remediationMode">
>
): AutoRunV2;Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
name |
string |
"Run #N" |
Run display name |
options.aggressiveProgression |
boolean |
false |
Promote after 2 correct (vs 3) |
options.remediationMode |
boolean |
true |
Inject remediation on failure |
Returns: New AutoRunV2 object
Loads an existing run by ID.
function loadAutoRunV2(runId: string): AutoRunV2 | null;Gets all saved runs.
function getAllAutoRunsV2(): AutoRunV2[];Deletes a run.
function deleteAutoRunV2(runId: string): boolean;Advances to the next question in the run's queue.
function advanceQueue(run: AutoRunV2): AutoRunV2;Notes:
- Returns updated run (must be saved)
- Automatically extends queue if near end
Records a correct answer and handles streak/difficulty progression.
function recordCorrectAnswer(run: AutoRunV2, subtopicId: string): AutoRunV2;Effects:
- Increments streak
- Promotes difficulty if streak reaches threshold
- Updates statistics
Records an incorrect answer and handles demotion/remediation.
function recordIncorrectAnswer(run: AutoRunV2, subtopicId: string): AutoRunV2;Effects:
- Resets streak to 0
- Demotes difficulty
- Injects remediation questions (if enabled)
Module: @/lib/stores/statsStore
Practice statistics tracking.
Gets global statistics.
function getStatsV2(): GlobalStatsV2;Returns:
interface GlobalStatsV2 {
version: 3;
totalAttempts: number;
totalSolved: number;
totalTimeTakenMs: number;
modulesTouched: number;
subtopicsTouched: number;
masteryPercent: number;
currentManualStreak: number;
modules: ModuleStats[];
lastUpdatedAt: number;
}Records a practice attempt.
function recordAttempt(input: RecordAttemptInput): GlobalStatsV2;Parameters:
interface RecordAttemptInput {
moduleId: string;
subtopicId: string;
problemTypeId: string;
correct: boolean;
timeTakenMs: number;
difficulty?: DifficultyLevel;
}Gets stats for a specific module.
function getModuleStats(moduleId: string): ModuleStats | null;Gets subtopics with lowest mastery (for targeted practice).
function getWeakestSubtopics(
count?: number
): Array<{ moduleId: string; subtopic: SubtopicStats }>;Resets all statistics.
function resetStatsV2(): GlobalStatsV2;Module: @/lib/stores/settingsStore
Application settings management (Zustand store).
React hook for settings state.
const useSettingsStore: UseBoundStore<StoreApi<SettingsState>>;Usage:
import { useSettingsStore } from "@/lib/stores/settingsStore";
function Component() {
const theme = useSettingsStore((state) => state.appearance.theme);
const updateAppearance = useSettingsStore((state) => state.updateAppearance);
return (
<button onClick={() => updateAppearance({ theme: "github-light" })}>
Switch to Light
</button>
);
}Available Actions:
updateGeneral(settings: Partial<GeneralSettings>)updateAppearance(settings: Partial<AppearanceSettings>)updateEditor(settings: Partial<EditorSettings>)updatePractice(settings: Partial<PracticeSettings>)updateKeyBinding(action: string, newKey: string)updateAdvanced(settings: Partial<AdvancedSettings>)updatePrivacy(settings: Partial<PrivacySettings>)completeOnboarding()resetToDefaults()clearAllData()
// Difficulty levels
type Difficulty = "beginner" | "intermediate" | "advanced";
// Run status
type RunStatus = "not_run" | "correct" | "incorrect" | "error";interface Question {
id: string;
topicId: string; // Normalized ID
topicName: string; // Display name
topic: string; // AI field
difficulty: Difficulty;
title: string;
description: string;
inputDescription: string;
outputDescription: string;
constraints: string[];
sampleInput: string;
sampleOutput: string;
starterCode: string;
referenceSolution: string | null;
testCases: TestCase[]; // >= 3 required
}
interface TestCase {
id: string;
input: string;
expectedOutput: string;
isHidden?: boolean;
description?: string;
}interface Hint {
hint: string;
level: number; // 1 = gentle, 2 = more explicit
}type EvaluationStatus = "correct" | "incorrect" | "error";
interface EvaluationResult {
status: EvaluationStatus;
explanation: string;
expectedBehavior: string;
nextHint: string | null;
}interface Module {
id: string; // kebab-case
name: string;
order: number;
overview?: string;
subtopics: Subtopic[];
problemArchetypes: string[];
pythonConsiderations?: string[];
}
interface Subtopic {
id: string;
name: string;
sectionNumber?: string;
concepts?: string[];
problemTypes: ProblemType[];
}
interface ProblemType {
id: string;
name: string;
description?: string;
}interface AutoRunV2 {
id: string;
name: string;
createdAt: number;
lastActiveAt: number;
status: "active" | "completed" | "paused";
miniCurriculumCompleted: boolean;
miniCurriculumProgress: number;
topicQueue: TopicQueueEntry[];
currentQueueIndex: number;
currentStreak: number;
bestStreak: number;
totalQuestionsAttempted: number;
totalCorrect: number;
difficultyPointer: Record<string, DifficultyLevel>;
aggressiveProgression: boolean;
remediationMode: boolean;
}
interface TopicQueueEntry {
subtopicId: string;
subtopicName: string;
moduleId: string;
moduleName: string;
isRemediation?: boolean;
}All routes require the X-API-Key header with the user's Gemini API key.
Generates a new question.
Request:
{
"topic": "Two-Pointer Techniques",
"difficulty": "beginner"
}Response:
{
"question": {
/* Question object */
},
"usage": {
"model": "gemini-1.5-flash",
"inputTokens": 150,
"outputTokens": 500
}
}Gets a hint for the current question.
Request:
{
"question": {
/* Question object */
},
"code": "def solve(s): pass",
"hintsCount": 0
}Response:
{
"hint": {
"hint": "Consider using two pointers...",
"level": 1
},
"usage": {
/* ... */
}
}Reveals the reference solution.
Request:
{
"question": {
/* Question object */
},
"failedAttempts": 3
}Response:
{
"referenceSolution": "def solve(s):\n ...",
"usage": {
/* ... */
}
}Evaluates user code.
Request:
{
"question": {
/* Question object */
},
"code": "def solve(s): return s[::-1]",
"output": "olleh",
"error": null
}Response:
{
"evaluation": {
"status": "correct",
"explanation": "Your solution correctly reverses...",
"expectedBehavior": "...",
"nextHint": null
},
"usage": {
/* ... */
}
}Gets an optimized version of a correct solution.
Request:
{
"question": {
/* Question object */
},
"userCode": "def solve(s): ..."
}Response:
{
"optimized": {
"code": "def solve(s): ...",
"explanation": "...",
"keyImprovements": ["Used list comprehension", "..."]
},
"usage": {
/* ... */
}
}Tests API key validity.
Request: (empty body)
Response:
{
"valid": true
}or
{
"valid": false,
"error": "Invalid API key"
}All API routes return errors in this format:
{
"error": "Human-readable error message",
"errorType": "api_key_required" | "config_error" | "rate_limit" | "ai_unavailable"
}HTTP Status Codes:
| Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request (invalid body) |
| 401 | Unauthorized (missing or invalid API key) |
| 429 | Rate limited |
| 500 | Server error |