JavaScript/TypeScript SDK

Official JavaScript and TypeScript SDK for Kai the AI

Overview

The Kai the AI JavaScript/TypeScript SDK provides a powerful, type-safe interface for integrating intelligent teaching assistant capabilities into your Node.js and browser-based applications. Built with modern JavaScript standards and full TypeScript support, the SDK offers comprehensive access to all Kai API features.

Installation

Install the SDK using your preferred package manager:

npm install @kai-ai/sdk
yarn add @kai-ai/sdk
pnpm add @kai-ai/sdk
Note

The SDK works in both Node.js (v16+) and modern browsers with ES2020+ support. TypeScript 5.0+ is recommended for the best development experience.

Quick Start

Get started with the SDK in just a few lines of code:

import { KaiClient } from '@kai-ai/sdk';

// Initialize the client
const kai = new KaiClient({
  apiKey: 'your-api-key',
  baseUrl: 'https://chi2api.com/v1' // optional
});

// Grade an assignment
const result = await kai.assignments.grade({
  studentId: 'student-123',
  assignmentId: 'assign-456',
  submission: 'The mitochondria is the powerhouse of the cell...',
  rubric: {
    criteria: [
      { name: 'accuracy', weight: 0.6 },
      { name: 'clarity', weight: 0.4 }
    ]
  }
});

console.log(`Grade: ${result.score}/100`);
console.log(`Feedback: ${result.feedback}`);
const { KaiClient } = require('@kai-ai/sdk');

// Initialize the client
const kai = new KaiClient({
  apiKey: 'your-api-key',
  baseUrl: 'https://chi2api.com/v1' // optional
});

// Grade an assignment
const result = await kai.assignments.grade({
  studentId: 'student-123',
  assignmentId: 'assign-456',
  submission: 'The mitochondria is the powerhouse of the cell...',
  rubric: {
    criteria: [
      { name: 'accuracy', weight: 0.6 },
      { name: 'clarity', weight: 0.4 }
    ]
  }
});

console.log(`Grade: ${result.score}/100`);
console.log(`Feedback: ${result.feedback}`);

Authentication

The SDK requires an API key for authentication. You can obtain your API key from the Kai the AI Dashboard.

// Recommended: Use environment variables
import { KaiClient } from '@kai-ai/sdk';

const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY
});
// Direct API key (not recommended for production)
import { KaiClient } from '@kai-ai/sdk';

const kai = new KaiClient({
  apiKey: 'kai_sk_1234567890abcdef'
});
// Add custom headers for advanced use cases
import { KaiClient } from '@kai-ai/sdk';

const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY,
  headers: {
    'X-Custom-Header': 'value',
    'X-Request-ID': generateRequestId()
  }
});
Warning

Security Best Practice: Never hardcode API keys in your source code. Always use environment variables or secure configuration management systems.

Core Classes and Types

KaiClient

The main client class for interacting with the Kai API.

interface KaiClientConfig {
  apiKey: string;
  baseUrl?: string;
  timeout?: number;
  retries?: number;
  headers?: Record<string, string>;
}

class KaiClient {
  constructor(config: KaiClientConfig);

  // Namespaced API methods
  assignments: AssignmentsAPI;
  quizzes: QuizzesAPI;
  analytics: AnalyticsAPI;
  students: StudentsAPI;
}
// Configuration object
const config = {
  apiKey: 'your-api-key',
  baseUrl: 'https://chi2api.com/v1', // optional
  timeout: 30000, // optional, in milliseconds
  retries: 3, // optional, number of retry attempts
  headers: {} // optional, custom headers
};

const kai = new KaiClient(config);

Assignment Types

// Branded types for type safety
type StudentId = string & { readonly __brand: 'StudentId' };
type AssignmentId = string & { readonly __brand: 'AssignmentId' };

interface RubricCriterion {
  name: string;
  description?: string;
  weight: number; // 0.0 to 1.0
  maxScore?: number;
}

interface Rubric {
  criteria: RubricCriterion[];
  totalPoints?: number;
}

interface GradeAssignmentRequest {
  studentId: StudentId;
  assignmentId: AssignmentId;
  submission: string;
  rubric: Rubric;
  provideFeedback?: boolean;
  detailedAnalysis?: boolean;
}

interface GradeResult {
  assignmentId: AssignmentId;
  studentId: StudentId;
  score: number;
  maxScore: number;
  percentage: number;
  feedback: string;
  criteriaScores: CriterionScore[];
  suggestions: string[];
  gradedAt: Date;
}

interface CriterionScore {
  criterion: string;
  score: number;
  maxScore: number;
  feedback: string;
}
// Example assignment grading request
const gradeRequest = {
  studentId: 'student-123',
  assignmentId: 'assign-456',
  submission: 'Student answer text...',
  rubric: {
    criteria: [
      {
        name: 'accuracy',
        description: 'Correctness of information',
        weight: 0.5,
        maxScore: 50
      },
      {
        name: 'clarity',
        description: 'Clear communication',
        weight: 0.3,
        maxScore: 30
      },
      {
        name: 'completeness',
        description: 'Thoroughness of answer',
        weight: 0.2,
        maxScore: 20
      }
    ],
    totalPoints: 100
  },
  provideFeedback: true,
  detailedAnalysis: true
};

Quiz Types

type QuizId = string & { readonly __brand: 'QuizId' };
type QuestionId = string & { readonly __brand: 'QuestionId' };

type QuestionType = 'multiple_choice' | 'true_false' | 'short_answer' | 'essay';
type DifficultyLevel = 'easy' | 'medium' | 'hard';

interface GenerateQuizRequest {
  topic: string;
  numQuestions: number;
  questionTypes?: QuestionType[];
  difficulty?: DifficultyLevel;
  learningObjectives?: string[];
  excludeTopics?: string[];
}

interface QuizQuestion {
  id: QuestionId;
  type: QuestionType;
  question: string;
  options?: string[]; // For multiple choice
  correctAnswer: string | number;
  explanation: string;
  difficulty: DifficultyLevel;
  tags: string[];
  points: number;
}

interface Quiz {
  id: QuizId;
  title: string;
  description: string;
  questions: QuizQuestion[];
  totalPoints: number;
  estimatedTime: number; // in minutes
  createdAt: Date;
}
// Example quiz generation request
const quizRequest = {
  topic: 'Cell Biology',
  numQuestions: 10,
  questionTypes: ['multiple_choice', 'short_answer'],
  difficulty: 'medium',
  learningObjectives: [
    'Understand cell structure',
    'Explain cellular processes'
  ],
  excludeTopics: ['advanced genetics']
};

Analytics Types

interface StudentAnalytics {
  studentId: StudentId;
  overallPerformance: PerformanceMetrics;
  subjectBreakdown: SubjectMetrics[];
  recentActivity: ActivityRecord[];
  strengths: string[];
  weaknesses: string[];
  recommendations: string[];
  lastUpdated: Date;
}

interface PerformanceMetrics {
  averageGrade: number;
  assignmentsCompleted: number;
  assignmentsTotal: number;
  completionRate: number;
  improvementTrend: 'improving' | 'stable' | 'declining';
  percentile: number;
}

interface SubjectMetrics {
  subject: string;
  averageGrade: number;
  assignmentsCount: number;
  masteryLevel: 'beginner' | 'intermediate' | 'advanced' | 'expert';
  timeSpent: number; // in minutes
}

interface ActivityRecord {
  timestamp: Date;
  type: 'assignment' | 'quiz' | 'study_session';
  itemId: string;
  score?: number;
  duration: number; // in minutes
}
// Example analytics response
const analytics = {
  studentId: 'student-123',
  overallPerformance: {
    averageGrade: 87.5,
    assignmentsCompleted: 24,
    assignmentsTotal: 30,
    completionRate: 0.8,
    improvementTrend: 'improving',
    percentile: 78
  },
  subjectBreakdown: [
    {
      subject: 'Biology',
      averageGrade: 92,
      assignmentsCount: 12,
      masteryLevel: 'advanced',
      timeSpent: 480
    }
  ],
  strengths: ['Scientific reasoning', 'Lab analysis'],
  weaknesses: ['Mathematical applications'],
  recommendations: ['Review algebra concepts', 'Practice graph interpretation']
};

API Methods

Assignments API

class AssignmentsAPI {
  /**
   * Grade a student assignment
   * @param request - Grading request parameters
   * @returns Promise resolving to grade result
   */
  async grade(request: GradeAssignmentRequest): Promise<GradeResult> {
    // Implementation
  }

  /**
   * Get assignment details
   * @param assignmentId - Assignment identifier
   * @returns Promise resolving to assignment details
   */
  async get(assignmentId: AssignmentId): Promise<Assignment> {
    // Implementation
  }

  /**
   * List assignments for a student
   * @param studentId - Student identifier
   * @param options - Optional filtering parameters
   * @returns Promise resolving to assignment list
   */
  async list(
    studentId: StudentId,
    options?: ListAssignmentsOptions
  ): Promise<Assignment[]> {
    // Implementation
  }

  /**
   * Provide additional feedback on an assignment
   * @param assignmentId - Assignment identifier
   * @param feedback - Additional feedback text
   * @returns Promise resolving to updated grade result
   */
  async addFeedback(
    assignmentId: AssignmentId,
    feedback: string
  ): Promise<GradeResult> {
    // Implementation
  }
}

// Example usage
const gradeResult = await kai.assignments.grade({
  studentId: 'student-123' as StudentId,
  assignmentId: 'assign-456' as AssignmentId,
  submission: 'The process of photosynthesis...',
  rubric: {
    criteria: [
      { name: 'accuracy', weight: 0.6, maxScore: 60 },
      { name: 'clarity', weight: 0.4, maxScore: 40 }
    ],
    totalPoints: 100
  },
  provideFeedback: true,
  detailedAnalysis: true
});

console.log(`Score: ${gradeResult.score}/${gradeResult.maxScore}`);
console.log(`Feedback: ${gradeResult.feedback}`);
// Grade an assignment
const gradeResult = await kai.assignments.grade({
  studentId: 'student-123',
  assignmentId: 'assign-456',
  submission: 'The process of photosynthesis...',
  rubric: {
    criteria: [
      { name: 'accuracy', weight: 0.6, maxScore: 60 },
      { name: 'clarity', weight: 0.4, maxScore: 40 }
    ],
    totalPoints: 100
  },
  provideFeedback: true,
  detailedAnalysis: true
});

// Get assignment details
const assignment = await kai.assignments.get('assign-456');

// List student assignments
const assignments = await kai.assignments.list('student-123', {
  status: 'completed',
  limit: 20,
  offset: 0
});

// Add additional feedback
const updated = await kai.assignments.addFeedback(
  'assign-456',
  'Great improvement in understanding the light-dependent reactions!'
);

Quizzes API

class QuizzesAPI {
  /**
   * Generate a new quiz
   * @param request - Quiz generation parameters
   * @returns Promise resolving to generated quiz
   */
  async generate(request: GenerateQuizRequest): Promise<Quiz> {
    // Implementation
  }

  /**
   * Get quiz details
   * @param quizId - Quiz identifier
   * @returns Promise resolving to quiz details
   */
  async get(quizId: QuizId): Promise<Quiz> {
    // Implementation
  }

  /**
   * Submit quiz answers for grading
   * @param quizId - Quiz identifier
   * @param studentId - Student identifier
   * @param answers - Student's answers
   * @returns Promise resolving to quiz results
   */
  async submit(
    quizId: QuizId,
    studentId: StudentId,
    answers: QuizAnswers
  ): Promise<QuizResult> {
    // Implementation
  }

  /**
   * Regenerate specific questions in a quiz
   * @param quizId - Quiz identifier
   * @param questionIds - IDs of questions to regenerate
   * @returns Promise resolving to updated quiz
   */
  async regenerateQuestions(
    quizId: QuizId,
    questionIds: QuestionId[]
  ): Promise<Quiz> {
    // Implementation
  }
}

// Example usage
const quiz = await kai.quizzes.generate({
  topic: 'Cellular Respiration',
  numQuestions: 15,
  questionTypes: ['multiple_choice', 'short_answer'],
  difficulty: 'medium',
  learningObjectives: [
    'Explain the steps of cellular respiration',
    'Compare aerobic and anaerobic respiration'
  ]
});

console.log(`Generated quiz: ${quiz.title}`);
console.log(`Questions: ${quiz.questions.length}`);
console.log(`Total points: ${quiz.totalPoints}`);
// Generate a quiz
const quiz = await kai.quizzes.generate({
  topic: 'Cellular Respiration',
  numQuestions: 15,
  questionTypes: ['multiple_choice', 'short_answer'],
  difficulty: 'medium',
  learningObjectives: [
    'Explain the steps of cellular respiration',
    'Compare aerobic and anaerobic respiration'
  ]
});

// Get quiz details
const quizDetails = await kai.quizzes.get('quiz-789');

// Submit quiz answers
const result = await kai.quizzes.submit(
  'quiz-789',
  'student-123',
  {
    'question-1': 'A',
    'question-2': 'The mitochondria produces ATP...',
    'question-3': 'True'
  }
);

console.log(`Quiz score: ${result.score}/${result.totalPoints}`);

// Regenerate specific questions
const updatedQuiz = await kai.quizzes.regenerateQuestions(
  'quiz-789',
  ['question-5', 'question-8']
);

Analytics API

class AnalyticsAPI {
  /**
   * Get comprehensive analytics for a student
   * @param studentId - Student identifier
   * @param options - Optional time range and filters
   * @returns Promise resolving to student analytics
   */
  async getStudentAnalytics(
    studentId: StudentId,
    options?: AnalyticsOptions
  ): Promise<StudentAnalytics> {
    // Implementation
  }

  /**
   * Get class-wide analytics
   * @param classId - Class identifier
   * @param options - Optional filters
   * @returns Promise resolving to class analytics
   */
  async getClassAnalytics(
    classId: string,
    options?: AnalyticsOptions
  ): Promise<ClassAnalytics> {
    // Implementation
  }

  /**
   * Get performance trends over time
   * @param studentId - Student identifier
   * @param timeRange - Time range for trends
   * @returns Promise resolving to trend data
   */
  async getTrends(
    studentId: StudentId,
    timeRange: TimeRange
  ): Promise<TrendData> {
    // Implementation
  }

  /**
   * Get personalized recommendations
   * @param studentId - Student identifier
   * @returns Promise resolving to recommendations
   */
  async getRecommendations(
    studentId: StudentId
  ): Promise<Recommendation[]> {
    // Implementation
  }
}

interface AnalyticsOptions {
  startDate?: Date;
  endDate?: Date;
  subjects?: string[];
  includeDetails?: boolean;
}

interface TimeRange {
  start: Date;
  end: Date;
  granularity: 'day' | 'week' | 'month';
}

// Example usage
const analytics = await kai.analytics.getStudentAnalytics(
  'student-123' as StudentId,
  {
    startDate: new Date('2024-01-01'),
    endDate: new Date('2024-12-31'),
    subjects: ['Biology', 'Chemistry'],
    includeDetails: true
  }
);

console.log(`Average grade: ${analytics.overallPerformance.averageGrade}`);
console.log(`Completion rate: ${analytics.overallPerformance.completionRate * 100}%`);
console.log(`Strengths: ${analytics.strengths.join(', ')}`);
// Get student analytics
const analytics = await kai.analytics.getStudentAnalytics(
  'student-123',
  {
    startDate: new Date('2024-01-01'),
    endDate: new Date('2024-12-31'),
    subjects: ['Biology', 'Chemistry'],
    includeDetails: true
  }
);

// Get class analytics
const classAnalytics = await kai.analytics.getClassAnalytics('class-456', {
  includeDetails: true
});

// Get performance trends
const trends = await kai.analytics.getTrends('student-123', {
  start: new Date('2024-01-01'),
  end: new Date('2024-12-31'),
  granularity: 'week'
});

// Get personalized recommendations
const recommendations = await kai.analytics.getRecommendations('student-123');

console.log('Recommendations:');
recommendations.forEach(rec => {
  console.log(`- ${rec.title}: ${rec.description}`);
});

Error Handling

The SDK provides comprehensive error handling with typed error classes:

import {
  KaiClient,
  KaiError,
  AuthenticationError,
  RateLimitError,
  ValidationError,
  NetworkError
} from '@kai-ai/sdk';

const kai = new KaiClient({ apiKey: process.env.KAI_API_KEY });

try {
  const result = await kai.assignments.grade({
    studentId: 'student-123' as StudentId,
    assignmentId: 'assign-456' as AssignmentId,
    submission: 'Student answer...',
    rubric: { criteria: [{ name: 'accuracy', weight: 1.0 }] }
  });

  console.log(`Grade: ${result.score}`);
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid API key:', error.message);
    // Handle authentication failure
  } else if (error instanceof RateLimitError) {
    console.error('Rate limit exceeded:', error.message);
    console.log(`Retry after: ${error.retryAfter} seconds`);
    // Implement exponential backoff
  } else if (error instanceof ValidationError) {
    console.error('Invalid request:', error.message);
    console.log('Validation errors:', error.errors);
    // Show validation errors to user
  } else if (error instanceof NetworkError) {
    console.error('Network error:', error.message);
    // Implement retry logic
  } else if (error instanceof KaiError) {
    console.error('Kai API error:', error.message);
    console.log('Status code:', error.statusCode);
  } else {
    console.error('Unexpected error:', error);
  }
}
const { KaiClient } = require('@kai-ai/sdk');

const kai = new KaiClient({ apiKey: process.env.KAI_API_KEY });

try {
  const result = await kai.assignments.grade({
    studentId: 'student-123',
    assignmentId: 'assign-456',
    submission: 'Student answer...',
    rubric: { criteria: [{ name: 'accuracy', weight: 1.0 }] }
  });

  console.log(`Grade: ${result.score}`);
} catch (error) {
  // Check error type by name
  switch (error.name) {
    case 'AuthenticationError':
      console.error('Invalid API key:', error.message);
      break;
    case 'RateLimitError':
      console.error('Rate limit exceeded:', error.message);
      console.log(`Retry after: ${error.retryAfter} seconds`);
      break;
    case 'ValidationError':
      console.error('Invalid request:', error.message);
      console.log('Validation errors:', error.errors);
      break;
    case 'NetworkError':
      console.error('Network error:', error.message);
      break;
    default:
      console.error('Error:', error.message);
  }
}
Tip

Best Practice: Always implement proper error handling and retry logic for production applications. The SDK provides detailed error information to help diagnose issues quickly.

Rate Limiting and Best Practices

The Kai API implements rate limiting to ensure fair usage. The SDK handles rate limits automatically with built-in retry logic.

import { KaiClient } from '@kai-ai/sdk';

// Configure rate limiting behavior
const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY,
  retries: 3, // Number of retry attempts
  retryDelay: 1000, // Initial retry delay in ms
  retryBackoff: 2, // Exponential backoff multiplier
  timeout: 30000 // Request timeout in ms
});

// The SDK automatically handles rate limits
// with exponential backoff retry logic
const results = await Promise.all(
  assignments.map(async (assignment) => {
    try {
      return await kai.assignments.grade(assignment);
    } catch (error) {
      if (error instanceof RateLimitError) {
        // Rate limit hit, SDK will auto-retry
        console.log(`Rate limited, retrying after ${error.retryAfter}s`);
      }
      throw error;
    }
  })
);
const { KaiClient } = require('@kai-ai/sdk');

// Configure rate limiting behavior
const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY,
  retries: 3, // Number of retry attempts
  retryDelay: 1000, // Initial retry delay in ms
  retryBackoff: 2, // Exponential backoff multiplier
  timeout: 30000 // Request timeout in ms
});

// Batch processing with rate limit handling
async function gradeAssignments(assignments) {
  const results = [];

  for (const assignment of assignments) {
    try {
      const result = await kai.assignments.grade(assignment);
      results.push(result);
    } catch (error) {
      if (error.name === 'RateLimitError') {
        console.log(`Rate limited, waiting ${error.retryAfter}s`);
        await new Promise(resolve => setTimeout(resolve, error.retryAfter * 1000));
        // Retry the request
        const result = await kai.assignments.grade(assignment);
        results.push(result);
      } else {
        throw error;
      }
    }
  }

  return results;
}

Best Practices

Note

Rate Limit Guidelines:

  • Default limit: 60 requests per minute
  • Burst limit: 10 requests per second
  • Use batch operations when available
  • Implement exponential backoff for retries
  • Cache responses when appropriate
  • Monitor rate limit headers in responses

Configuration Options

Complete configuration reference for the SDK:

interface KaiClientConfig {
  /** API key for authentication (required) */
  apiKey: string;

  /** Base URL for API requests (default: https://chi2api.com/v1) */
  baseUrl?: string;

  /** Request timeout in milliseconds (default: 30000) */
  timeout?: number;

  /** Number of retry attempts for failed requests (default: 3) */
  retries?: number;

  /** Initial delay for retry attempts in ms (default: 1000) */
  retryDelay?: number;

  /** Exponential backoff multiplier (default: 2) */
  retryBackoff?: number;

  /** Custom HTTP headers for all requests */
  headers?: Record<string, string>;

  /** Enable debug logging (default: false) */
  debug?: boolean;

  /** Custom HTTP agent for Node.js (default: default agent) */
  agent?: any;

  /** Maximum number of concurrent requests (default: 10) */
  maxConcurrent?: number;
}

// Example: Production configuration
const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY!,
  baseUrl: 'https://chi2api.com/v1',
  timeout: 60000, // 60 seconds for long-running operations
  retries: 5,
  retryDelay: 2000,
  retryBackoff: 1.5,
  headers: {
    'X-Application-ID': 'my-app',
    'X-Application-Version': '1.0.0'
  },
  debug: false,
  maxConcurrent: 5
});
// Example: Development configuration
const devKai = new KaiClient({
  apiKey: process.env.KAI_API_KEY,
  baseUrl: 'https://chi2api.com/v1',
  timeout: 30000,
  retries: 3,
  debug: true, // Enable debug logging
  headers: {
    'X-Environment': 'development'
  }
});

// Example: Production configuration with custom agent
const https = require('https');
const prodKai = new KaiClient({
  apiKey: process.env.KAI_API_KEY,
  baseUrl: 'https://chi2api.com/v1',
  timeout: 60000,
  retries: 5,
  agent: new https.Agent({
    keepAlive: true,
    maxSockets: 10
  }),
  maxConcurrent: 5
});

Complete Examples

Example 1: Grading Assignments with Detailed Feedback

import { KaiClient, type GradeAssignmentRequest, type StudentId, type AssignmentId } from '@kai-ai/sdk';

const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY!
});

async function gradeEssayAssignment(
  studentId: StudentId,
  assignmentId: AssignmentId,
  essayText: string
) {
  const request: GradeAssignmentRequest = {
    studentId,
    assignmentId,
    submission: essayText,
    rubric: {
      criteria: [
        {
          name: 'thesis_statement',
          description: 'Clear and focused thesis statement',
          weight: 0.2,
          maxScore: 20
        },
        {
          name: 'evidence_support',
          description: 'Strong supporting evidence and examples',
          weight: 0.3,
          maxScore: 30
        },
        {
          name: 'organization',
          description: 'Logical organization and flow',
          weight: 0.2,
          maxScore: 20
        },
        {
          name: 'grammar_mechanics',
          description: 'Grammar, spelling, and mechanics',
          weight: 0.15,
          maxScore: 15
        },
        {
          name: 'conclusion',
          description: 'Effective conclusion',
          weight: 0.15,
          maxScore: 15
        }
      ],
      totalPoints: 100
    },
    provideFeedback: true,
    detailedAnalysis: true
  };

  try {
    const result = await kai.assignments.grade(request);

    console.log('=== GRADING RESULTS ===');
    console.log(`Overall Score: ${result.score}/${result.maxScore} (${result.percentage.toFixed(1)}%)`);
    console.log('\nGeneral Feedback:');
    console.log(result.feedback);

    console.log('\n=== CRITERIA BREAKDOWN ===');
    result.criteriaScores.forEach(criterion => {
      console.log(`\n${criterion.criterion}:`);
      console.log(`  Score: ${criterion.score}/${criterion.maxScore}`);
      console.log(`  Feedback: ${criterion.feedback}`);
    });

    if (result.suggestions.length > 0) {
      console.log('\n=== SUGGESTIONS FOR IMPROVEMENT ===');
      result.suggestions.forEach((suggestion, index) => {
        console.log(`${index + 1}. ${suggestion}`);
      });
    }

    return result;
  } catch (error) {
    console.error('Failed to grade assignment:', error);
    throw error;
  }
}

// Usage
const studentId = 'student-123' as StudentId;
const assignmentId = 'essay-001' as AssignmentId;
const essay = `
Photosynthesis is the process by which plants convert light energy into chemical energy.
This essay will explore the mechanisms and importance of photosynthesis in the ecosystem...
[Full essay text]
`;

gradeEssayAssignment(studentId, assignmentId, essay);
const { KaiClient } = require('@kai-ai/sdk');

const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY
});

async function gradeEssayAssignment(studentId, assignmentId, essayText) {
  const request = {
    studentId,
    assignmentId,
    submission: essayText,
    rubric: {
      criteria: [
        {
          name: 'thesis_statement',
          description: 'Clear and focused thesis statement',
          weight: 0.2,
          maxScore: 20
        },
        {
          name: 'evidence_support',
          description: 'Strong supporting evidence and examples',
          weight: 0.3,
          maxScore: 30
        },
        {
          name: 'organization',
          description: 'Logical organization and flow',
          weight: 0.2,
          maxScore: 20
        },
        {
          name: 'grammar_mechanics',
          description: 'Grammar, spelling, and mechanics',
          weight: 0.15,
          maxScore: 15
        },
        {
          name: 'conclusion',
          description: 'Effective conclusion',
          weight: 0.15,
          maxScore: 15
        }
      ],
      totalPoints: 100
    },
    provideFeedback: true,
    detailedAnalysis: true
  };

  try {
    const result = await kai.assignments.grade(request);

    console.log('=== GRADING RESULTS ===');
    console.log(`Overall Score: ${result.score}/${result.maxScore} (${result.percentage.toFixed(1)}%)`);
    console.log('\nGeneral Feedback:');
    console.log(result.feedback);

    console.log('\n=== CRITERIA BREAKDOWN ===');
    result.criteriaScores.forEach(criterion => {
      console.log(`\n${criterion.criterion}:`);
      console.log(`  Score: ${criterion.score}/${criterion.maxScore}`);
      console.log(`  Feedback: ${criterion.feedback}`);
    });

    if (result.suggestions.length > 0) {
      console.log('\n=== SUGGESTIONS FOR IMPROVEMENT ===');
      result.suggestions.forEach((suggestion, index) => {
        console.log(`${index + 1}. ${suggestion}`);
      });
    }

    return result;
  } catch (error) {
    console.error('Failed to grade assignment:', error);
    throw error;
  }
}

// Usage
const essay = `
Photosynthesis is the process by which plants convert light energy into chemical energy.
This essay will explore the mechanisms and importance of photosynthesis in the ecosystem...
[Full essay text]
`;

gradeEssayAssignment('student-123', 'essay-001', essay);

Example 2: Generating and Managing Quizzes

import { KaiClient, type Quiz, type QuizId, type StudentId } from '@kai-ai/sdk';

const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY!
});

async function createAndAdministerQuiz(topic: string, studentIds: StudentId[]) {
  try {
    // Generate quiz
    console.log(`Generating quiz on topic: ${topic}...`);
    const quiz = await kai.quizzes.generate({
      topic,
      numQuestions: 10,
      questionTypes: ['multiple_choice', 'short_answer'],
      difficulty: 'medium',
      learningObjectives: [
        `Understand key concepts in ${topic}`,
        `Apply knowledge to real-world scenarios`
      ]
    });

    console.log(`\nQuiz created: ${quiz.title}`);
    console.log(`Questions: ${quiz.questions.length}`);
    console.log(`Total points: ${quiz.totalPoints}`);
    console.log(`Estimated time: ${quiz.estimatedTime} minutes`);

    // Display quiz questions
    console.log('\n=== QUIZ QUESTIONS ===');
    quiz.questions.forEach((question, index) => {
      console.log(`\n${index + 1}. ${question.question}`);
      console.log(`   Type: ${question.type}`);
      console.log(`   Difficulty: ${question.difficulty}`);
      console.log(`   Points: ${question.points}`);

      if (question.options) {
        question.options.forEach((option, optIndex) => {
          console.log(`   ${String.fromCharCode(65 + optIndex)}) ${option}`);
        });
      }
    });

    // Simulate student taking quiz
    const studentResults = await Promise.all(
      studentIds.map(studentId => gradeStudentQuiz(quiz.id, studentId))
    );

    // Calculate class statistics
    const classAverage = studentResults.reduce((sum, r) => sum + r.percentage, 0) / studentResults.length;
    console.log(`\n=== CLASS STATISTICS ===`);
    console.log(`Class average: ${classAverage.toFixed(1)}%`);
    console.log(`Students completed: ${studentResults.length}`);

    return { quiz, studentResults };
  } catch (error) {
    console.error('Failed to create and administer quiz:', error);
    throw error;
  }
}

async function gradeStudentQuiz(quizId: QuizId, studentId: StudentId) {
  // Simulate student answers (in real app, get from form submission)
  const answers = {
    'question-1': 'B',
    'question-2': 'Photosynthesis converts light energy to chemical energy through...',
    'question-3': 'A',
    // ... more answers
  };

  const result = await kai.quizzes.submit(quizId, studentId, answers);

  console.log(`\nStudent ${studentId}:`);
  console.log(`  Score: ${result.score}/${result.totalPoints} (${result.percentage.toFixed(1)}%)`);
  console.log(`  Time taken: ${result.timeTaken} minutes`);

  return result;
}

// Usage
const studentIds: StudentId[] = [
  'student-001' as StudentId,
  'student-002' as StudentId,
  'student-003' as StudentId
];

createAndAdministerQuiz('Cellular Respiration', studentIds);
const { KaiClient } = require('@kai-ai/sdk');

const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY
});

async function createAndAdministerQuiz(topic, studentIds) {
  try {
    // Generate quiz
    console.log(`Generating quiz on topic: ${topic}...`);
    const quiz = await kai.quizzes.generate({
      topic,
      numQuestions: 10,
      questionTypes: ['multiple_choice', 'short_answer'],
      difficulty: 'medium',
      learningObjectives: [
        `Understand key concepts in ${topic}`,
        `Apply knowledge to real-world scenarios`
      ]
    });

    console.log(`\nQuiz created: ${quiz.title}`);
    console.log(`Questions: ${quiz.questions.length}`);
    console.log(`Total points: ${quiz.totalPoints}`);
    console.log(`Estimated time: ${quiz.estimatedTime} minutes`);

    // Display quiz questions
    console.log('\n=== QUIZ QUESTIONS ===');
    quiz.questions.forEach((question, index) => {
      console.log(`\n${index + 1}. ${question.question}`);
      console.log(`   Type: ${question.type}`);
      console.log(`   Difficulty: ${question.difficulty}`);
      console.log(`   Points: ${question.points}`);

      if (question.options) {
        question.options.forEach((option, optIndex) => {
          console.log(`   ${String.fromCharCode(65 + optIndex)}) ${option}`);
        });
      }
    });

    // Simulate student taking quiz
    const studentResults = await Promise.all(
      studentIds.map(studentId => gradeStudentQuiz(quiz.id, studentId))
    );

    // Calculate class statistics
    const classAverage = studentResults.reduce((sum, r) => sum + r.percentage, 0) / studentResults.length;
    console.log(`\n=== CLASS STATISTICS ===`);
    console.log(`Class average: ${classAverage.toFixed(1)}%`);
    console.log(`Students completed: ${studentResults.length}`);

    return { quiz, studentResults };
  } catch (error) {
    console.error('Failed to create and administer quiz:', error);
    throw error;
  }
}

async function gradeStudentQuiz(quizId, studentId) {
  // Simulate student answers (in real app, get from form submission)
  const answers = {
    'question-1': 'B',
    'question-2': 'Photosynthesis converts light energy to chemical energy through...',
    'question-3': 'A',
    // ... more answers
  };

  const result = await kai.quizzes.submit(quizId, studentId, answers);

  console.log(`\nStudent ${studentId}:`);
  console.log(`  Score: ${result.score}/${result.totalPoints} (${result.percentage.toFixed(1)}%)`);
  console.log(`  Time taken: ${result.timeTaken} minutes`);

  return result;
}

// Usage
const studentIds = ['student-001', 'student-002', 'student-003'];
createAndAdministerQuiz('Cellular Respiration', studentIds);

Example 3: Comprehensive Student Analytics Dashboard

import { KaiClient, type StudentId, type StudentAnalytics } from '@kai-ai/sdk';

const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY!
});

async function generateStudentDashboard(studentId: StudentId) {
  try {
    // Fetch comprehensive analytics
    const analytics = await kai.analytics.getStudentAnalytics(studentId, {
      startDate: new Date(new Date().setMonth(new Date().getMonth() - 3)),
      endDate: new Date(),
      includeDetails: true
    });

    // Fetch performance trends
    const trends = await kai.analytics.getTrends(studentId, {
      start: new Date(new Date().setMonth(new Date().getMonth() - 3)),
      end: new Date(),
      granularity: 'week'
    });

    // Fetch personalized recommendations
    const recommendations = await kai.analytics.getRecommendations(studentId);

    // Display dashboard
    console.log('╔════════════════════════════════════════════════════════╗');
    console.log('║         STUDENT PERFORMANCE DASHBOARD                 ║');
    console.log('╚════════════════════════════════════════════════════════╝');

    console.log('\n📊 OVERALL PERFORMANCE');
    console.log(`   Average Grade: ${analytics.overallPerformance.averageGrade.toFixed(1)}`);
    console.log(`   Completion Rate: ${(analytics.overallPerformance.completionRate * 100).toFixed(1)}%`);
    console.log(`   Assignments: ${analytics.overallPerformance.assignmentsCompleted}/${analytics.overallPerformance.assignmentsTotal}`);
    console.log(`   Trend: ${getTrendEmoji(analytics.overallPerformance.improvementTrend)} ${analytics.overallPerformance.improvementTrend}`);
    console.log(`   Class Percentile: ${analytics.overallPerformance.percentile}th`);

    console.log('\n📚 SUBJECT BREAKDOWN');
    analytics.subjectBreakdown.forEach(subject => {
      console.log(`\n   ${subject.subject}:`);
      console.log(`     Average: ${subject.averageGrade.toFixed(1)}`);
      console.log(`     Mastery: ${getMasteryEmoji(subject.masteryLevel)} ${subject.masteryLevel}`);
      console.log(`     Assignments: ${subject.assignmentsCount}`);
      console.log(`     Time Spent: ${subject.timeSpent} minutes`);
    });

    console.log('\n💪 STRENGTHS');
    analytics.strengths.forEach((strength, index) => {
      console.log(`   ${index + 1}. ${strength}`);
    });

    console.log('\n📈 AREAS FOR IMPROVEMENT');
    analytics.weaknesses.forEach((weakness, index) => {
      console.log(`   ${index + 1}. ${weakness}`);
    });

    console.log('\n🎯 PERSONALIZED RECOMMENDATIONS');
    recommendations.forEach((rec, index) => {
      console.log(`\n   ${index + 1}. ${rec.title}`);
      console.log(`      ${rec.description}`);
      console.log(`      Priority: ${rec.priority}`);
      if (rec.estimatedTime) {
        console.log(`      Estimated Time: ${rec.estimatedTime} minutes`);
      }
    });

    console.log('\n📉 RECENT TRENDS');
    displayTrendChart(trends);

    return { analytics, trends, recommendations };
  } catch (error) {
    console.error('Failed to generate dashboard:', error);
    throw error;
  }
}

function getTrendEmoji(trend: string): string {
  const emojis: Record<string, string> = {
    'improving': '📈',
    'stable': '➡️',
    'declining': '📉'
  };
  return emojis[trend] || '❓';
}

function getMasteryEmoji(level: string): string {
  const emojis: Record<string, string> = {
    'beginner': '🌱',
    'intermediate': '🌿',
    'advanced': '🌳',
    'expert': '⭐'
  };
  return emojis[level] || '❓';
}

function displayTrendChart(trends: any) {
  console.log('\n   Week    Grade    Progress');
  console.log('   ────────────────────────────');
  trends.dataPoints.forEach((point: any, index: number) => {
    const bar = '█'.repeat(Math.round(point.value / 10));
    console.log(`   Week ${index + 1}  ${point.value.toFixed(1)}    ${bar}`);
  });
}

// Usage
generateStudentDashboard('student-123' as StudentId);
const { KaiClient } = require('@kai-ai/sdk');

const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY
});

async function generateStudentDashboard(studentId) {
  try {
    // Fetch comprehensive analytics
    const analytics = await kai.analytics.getStudentAnalytics(studentId, {
      startDate: new Date(new Date().setMonth(new Date().getMonth() - 3)),
      endDate: new Date(),
      includeDetails: true
    });

    // Fetch performance trends
    const trends = await kai.analytics.getTrends(studentId, {
      start: new Date(new Date().setMonth(new Date().getMonth() - 3)),
      end: new Date(),
      granularity: 'week'
    });

    // Fetch personalized recommendations
    const recommendations = await kai.analytics.getRecommendations(studentId);

    // Display dashboard
    console.log('╔════════════════════════════════════════════════════════╗');
    console.log('║         STUDENT PERFORMANCE DASHBOARD                 ║');
    console.log('╚════════════════════════════════════════════════════════╝');

    console.log('\n📊 OVERALL PERFORMANCE');
    console.log(`   Average Grade: ${analytics.overallPerformance.averageGrade.toFixed(1)}`);
    console.log(`   Completion Rate: ${(analytics.overallPerformance.completionRate * 100).toFixed(1)}%`);
    console.log(`   Assignments: ${analytics.overallPerformance.assignmentsCompleted}/${analytics.overallPerformance.assignmentsTotal}`);
    console.log(`   Trend: ${getTrendEmoji(analytics.overallPerformance.improvementTrend)} ${analytics.overallPerformance.improvementTrend}`);
    console.log(`   Class Percentile: ${analytics.overallPerformance.percentile}th`);

    console.log('\n📚 SUBJECT BREAKDOWN');
    analytics.subjectBreakdown.forEach(subject => {
      console.log(`\n   ${subject.subject}:`);
      console.log(`     Average: ${subject.averageGrade.toFixed(1)}`);
      console.log(`     Mastery: ${getMasteryEmoji(subject.masteryLevel)} ${subject.masteryLevel}`);
      console.log(`     Assignments: ${subject.assignmentsCount}`);
      console.log(`     Time Spent: ${subject.timeSpent} minutes`);
    });

    console.log('\n💪 STRENGTHS');
    analytics.strengths.forEach((strength, index) => {
      console.log(`   ${index + 1}. ${strength}`);
    });

    console.log('\n📈 AREAS FOR IMPROVEMENT');
    analytics.weaknesses.forEach((weakness, index) => {
      console.log(`   ${index + 1}. ${weakness}`);
    });

    console.log('\n🎯 PERSONALIZED RECOMMENDATIONS');
    recommendations.forEach((rec, index) => {
      console.log(`\n   ${index + 1}. ${rec.title}`);
      console.log(`      ${rec.description}`);
      console.log(`      Priority: ${rec.priority}`);
      if (rec.estimatedTime) {
        console.log(`      Estimated Time: ${rec.estimatedTime} minutes`);
      }
    });

    console.log('\n📉 RECENT TRENDS');
    displayTrendChart(trends);

    return { analytics, trends, recommendations };
  } catch (error) {
    console.error('Failed to generate dashboard:', error);
    throw error;
  }
}

function getTrendEmoji(trend) {
  const emojis = {
    'improving': '📈',
    'stable': '➡️',
    'declining': '📉'
  };
  return emojis[trend] || '❓';
}

function getMasteryEmoji(level) {
  const emojis = {
    'beginner': '🌱',
    'intermediate': '🌿',
    'advanced': '🌳',
    'expert': '⭐'
  };
  return emojis[level] || '❓';
}

function displayTrendChart(trends) {
  console.log('\n   Week    Grade    Progress');
  console.log('   ────────────────────────────');
  trends.dataPoints.forEach((point, index) => {
    const bar = '█'.repeat(Math.round(point.value / 10));
    console.log(`   Week ${index + 1}  ${point.value.toFixed(1)}    ${bar}`);
  });
}

// Usage
generateStudentDashboard('student-123');

Node.js vs Browser Usage

The SDK works seamlessly in both Node.js and browser environments:

// server.ts - Node.js backend
import { KaiClient } from '@kai-ai/sdk';
import express from 'express';

const app = express();
const kai = new KaiClient({
  apiKey: process.env.KAI_API_KEY!
});

app.post('/api/grade-assignment', async (req, res) => {
  try {
    const result = await kai.assignments.grade(req.body);
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
// client.ts - Browser frontend
import { KaiClient } from '@kai-ai/sdk';

// In production, use a backend proxy to protect API key
// This example is for demonstration only
const kai = new KaiClient({
  apiKey: getApiKeyFromBackend() // Fetch from your backend
});

async function gradeAssignment(formData: FormData) {
  const submission = formData.get('submission') as string;

  try {
    const result = await kai.assignments.grade({
      studentId: getCurrentStudentId(),
      assignmentId: formData.get('assignmentId') as string,
      submission,
      rubric: JSON.parse(formData.get('rubric') as string)
    });

    // Update UI with results
    displayGradingResults(result);
  } catch (error) {
    showError(error.message);
  }
}
Warning

Security Note: Never expose your API key in client-side code. Always use a backend proxy to make API calls from the browser.

TypeScript Strict Typing Benefits

The SDK leverages TypeScript’s advanced type system for maximum safety:

// Type-safe IDs prevent mixing different entity types
type StudentId = string & { readonly __brand: 'StudentId' };
type AssignmentId = string & { readonly __brand: 'AssignmentId' };
type QuizId = string & { readonly __brand: 'QuizId' };

// This will cause a compile-time error
const studentId: StudentId = 'student-123' as StudentId;
const assignmentId: AssignmentId = studentId; // ❌ Error: Type mismatch

// Correct usage
const validStudentId = 'student-123' as StudentId;
const validAssignmentId = 'assign-456' as AssignmentId;

await kai.assignments.grade({
  studentId: validStudentId,
  assignmentId: validAssignmentId,
  // ... rest of parameters
});
// Type-safe error handling with discriminated unions
type Result<T, E = Error> =
  | { ok: true; data: T }
  | { ok: false; error: E };

// Compiler ensures exhaustive checking
function handleResult<T>(result: Result<T>) {
  if (result.ok) {
    // TypeScript knows result.data exists here
    console.log(result.data);
  } else {
    // TypeScript knows result.error exists here
    console.error(result.error);
  }
}
// Type-safe API client with constrained generics
interface ApiEndpoints {
  '/assignments/grade': GradeResult;
  '/quizzes/generate': Quiz;
  '/analytics/student': StudentAnalytics;
}

async function apiCall<K extends keyof ApiEndpoints>(
  endpoint: K,
  body: unknown
): Promise<ApiEndpoints[K]> {
  // Implementation with full type safety
  // Return type is inferred based on endpoint
}

// Usage with type inference
const gradeResult = await apiCall('/assignments/grade', { /* ... */ });
// gradeResult is typed as GradeResult

Support and Resources


Last updated: 2025-10-07