/** Stable boundary between Makelore, downloaded course packages and Works Square. */ export const LEARNING_API_PATH = '/api/works/learning'; export const LEARNING_GENERATION_CONTRACT_VERSION = 2; export const LEARNING_MATERIAL_MAX_FILES = 5; export const LEARNING_MATERIAL_MAX_FILE_BYTES = 50 * 1024 * 1024; export const LEARNING_MATERIAL_MAX_TOTAL_BYTES = 150 * 1024 * 1024; export type LearningGenerationOptions = { requirement: string; enableWebSearch: boolean; enableImageGeneration: boolean; enableVideoGeneration: boolean; enableTTS: boolean; interactiveMode: boolean; taskEngineMode: boolean; }; export type LearningGenerationMaterialRef = { id: string; name: string; mimeType: string; size: number; lastModified: number; order: number; }; /** IPC-only upload shape. File bytes are never persisted in Renderer state. */ export type LearningGenerationMaterialUpload = LearningGenerationMaterialRef & { bytes: Uint8Array; }; export type LearningGenerationUploadRequest = { options: LearningGenerationOptions; materials: LearningGenerationMaterialUpload[]; }; export type LearningRuntimeCapability = | 'quiz-grade' | 'pbl/v2/task/update' | 'pbl/v2/open-task' | 'pbl/v2/simulator' | 'pbl/v2/instructor' | 'pbl/v2/evaluate'; export type LearningRuntimeBridgeRequest = { requestId: string; courseId: string; contentHash: string; capability: LearningRuntimeCapability; method: 'POST'; context: { moduleId: string | null; moduleContentHash: string; anchor: { sceneId: string; sceneOrder?: number; }; }; body: unknown; }; export type LearningRuntimeBridgeEvent = | { requestId: string; type: 'start'; status: number; contentType: string } | { requestId: string; type: 'chunk'; chunk: Uint8Array } | { requestId: string; type: 'end' } | { requestId: string; type: 'error'; code: string; message: string }; export type LearningSceneKind = 'slide' | 'interactive' | 'quiz' | 'pbl'; export type LearningCourseStatus = 'generating' | 'ready' | 'published' | 'failed' | 'archived'; export type LearningSingleCourseCapabilities = { modular?: false; sceneKinds: LearningSceneKind[]; hasAudio: boolean; hasWhiteboard: boolean; hasAgent: boolean; }; export type LearningLargeCourseCapabilities = { modular: true; orderedModules: true; productionStagePerModule: true; }; export type LearningCourseCapabilities = LearningSingleCourseCapabilities | LearningLargeCourseCapabilities; export type LearningCourseModule = { moduleId: string; title: string; summary: string | null; sceneCount: number; contentHash: string; }; export type LearningCourse = { id: string; origin: 'user_single' | 'ops_large'; status: LearningCourseStatus; title: string; summary: string | null; language: string | null; contentHash: string; archiveSha256: string; archiveBytes: number; formatVersion: number; minPlayerVersion: string; sceneCount: number; /** Ordered learning units inside one product-level course. */ modules?: LearningCourseModule[]; capabilities: LearningCourseCapabilities; createdAt: string; publishedAt: string | null; }; export type LearningProgress = { courseId: string; /** Aggregate course hash used by Works ownership and entitlement checks. */ contentHash: string; moduleId?: string | null; moduleContentHash?: string | null; sceneOrder: number; actionIndex: number | null; positionMs: number | null; completed: boolean; updatedAt: string; }; export type LearningProgressWrite = Pick< LearningProgress, 'contentHash' | 'moduleId' | 'sceneOrder' | 'actionIndex' | 'positionMs' | 'completed' >; export type InstalledLearningCourse = { schemaVersion: 1; course: LearningCourse; archivePath: string; installedAt: string; }; export type LearningClassroomPayload = { courseId: string; /** Aggregate package identity used to address immutable local assets. */ courseContentHash: string; /** Aggregate hash kept as a compatibility alias for existing Stage bridges. */ contentHash: string; moduleId: string | null; /** Selected frozen module hash; equals courseContentHash for legacy single-classroom packages. */ moduleContentHash: string; modules: LearningCourseModule[]; classroom: { stage: Record; scenes: unknown[] }; }; export type LearningGeneration = { contractVersion?: number; jobId: string; status: string; mode?: 'single' | 'large'; step: string | null; progress: number | null; message: string | null; scenesGenerated: number | null; totalScenes: number | null; courseId: string | null; error: string | null; done: boolean; };