Skip to content

Latest commit

 

History

History
1013 lines (743 loc) · 18 KB

File metadata and controls

1013 lines (743 loc) · 18 KB

Pytrix API Reference

Complete API documentation for all public surfaces in Pytrix.


Table of Contents

  1. AI Client API
  2. Python Runtime API
  3. Question Service API
  4. Auto Mode Service API
  5. Stats Store API
  6. Settings Store API
  7. Type Definitions
  8. API Routes (HTTP)

AI Client API

Module: @/lib/ai/aiClient

The primary interface for all AI-powered features.

generateQuestion

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 storage
  • ClientLimitError - Session safety cap exceeded
  • ApiError - 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
  }
}

getHints

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)

revealSolution

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


evaluateCode

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;
}

optimizeSolution

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 null gracefully if no API key configured
  • Intended to be called only after the user has solved the problem correctly

testApiConnection

Tests if the configured API key is valid.

function testApiConnection(): Promise<{ valid: boolean; error?: string }>;

Returns: Object indicating validity and optional error message


Python Runtime API

Module: @/lib/runtime

Interface for executing Python code in the browser.

initPyodide

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

runPython

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"

runTestCases

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;
}

abortExecution

Aborts all running executions.

function abortExecution(): void;

Notes:

  • Uses SharedArrayBuffer to signal interrupt
  • Triggers KeyboardInterrupt in Python

getRuntimeInfo

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;
}

subscribeToRuntimeStatus

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


Question Service API

Module: @/lib/question/questionService

Lower-level question generation with template support.

generateQuestion

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 };
}

Auto Mode Service API

Module: @/lib/auto-mode

Adaptive practice mode management.

createAutoRunV2

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


loadAutoRunV2

Loads an existing run by ID.

function loadAutoRunV2(runId: string): AutoRunV2 | null;

getAllAutoRunsV2

Gets all saved runs.

function getAllAutoRunsV2(): AutoRunV2[];

deleteAutoRunV2

Deletes a run.

function deleteAutoRunV2(runId: string): boolean;

advanceQueue

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

recordCorrectAnswer

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

recordIncorrectAnswer

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)

Stats Store API

Module: @/lib/stores/statsStore

Practice statistics tracking.

getStatsV2

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;
}

recordAttempt

Records a practice attempt.

function recordAttempt(input: RecordAttemptInput): GlobalStatsV2;

Parameters:

interface RecordAttemptInput {
  moduleId: string;
  subtopicId: string;
  problemTypeId: string;
  correct: boolean;
  timeTakenMs: number;
  difficulty?: DifficultyLevel;
}

getModuleStats

Gets stats for a specific module.

function getModuleStats(moduleId: string): ModuleStats | null;

getWeakestSubtopics

Gets subtopics with lowest mastery (for targeted practice).

function getWeakestSubtopics(
  count?: number
): Array<{ moduleId: string; subtopic: SubtopicStats }>;

resetStatsV2

Resets all statistics.

function resetStatsV2(): GlobalStatsV2;

Settings Store API

Module: @/lib/stores/settingsStore

Application settings management (Zustand store).

useSettingsStore

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()

Type Definitions

Core Types

// Difficulty levels
type Difficulty = "beginner" | "intermediate" | "advanced";

// Run status
type RunStatus = "not_run" | "correct" | "incorrect" | "error";

Question Types

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;
}

Hint Types

interface Hint {
  hint: string;
  level: number; // 1 = gentle, 2 = more explicit
}

Evaluation Types

type EvaluationStatus = "correct" | "incorrect" | "error";

interface EvaluationResult {
  status: EvaluationStatus;
  explanation: string;
  expectedBehavior: string;
  nextHint: string | null;
}

Topic Types

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;
}

Auto Mode Types

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;
}

API Routes (HTTP)

All routes require the X-API-Key header with the user's Gemini API key.

POST /api/ai/generate-question

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
  }
}

POST /api/ai/get-hints

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": {
    /* ... */
  }
}

POST /api/ai/reveal-solution

Reveals the reference solution.

Request:

{
  "question": {
    /* Question object */
  },
  "failedAttempts": 3
}

Response:

{
  "referenceSolution": "def solve(s):\n    ...",
  "usage": {
    /* ... */
  }
}

POST /api/ai/evaluate-code

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": {
    /* ... */
  }
}

POST /api/ai/optimize-solution

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": {
    /* ... */
  }
}

POST /api/ai/test-connection

Tests API key validity.

Request: (empty body)

Response:

{
  "valid": true
}

or

{
  "valid": false,
  "error": "Invalid API key"
}

Error Responses

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