@fenixforce/edition-voices 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/addon.d.ts +45 -0
  2. package/dist/api/platform-middleware.d.ts +41 -0
  3. package/dist/api/platform-routes.d.ts +71 -0
  4. package/dist/assessment/hardened-grader.d.ts +76 -0
  5. package/dist/curriculum/zpd-selector.d.ts +57 -0
  6. package/dist/index.d.ts +68 -0
  7. package/dist/index.js +54 -0
  8. package/dist/manifest-merger.d.ts +13 -0
  9. package/dist/manifest.d.ts +13 -0
  10. package/dist/memory/learner-diary.d.ts +91 -0
  11. package/dist/system-prompt-patch.d.ts +17 -0
  12. package/dist/teacher/assessment/evaluator.d.ts +35 -0
  13. package/dist/teacher/assessment/feedback-generator.d.ts +11 -0
  14. package/dist/teacher/assessment/session-summary.d.ts +33 -0
  15. package/dist/teacher/corpus-importer.d.ts +44 -0
  16. package/dist/teacher/corpus-storage.d.ts +31 -0
  17. package/dist/teacher/curriculum/generator.d.ts +13 -0
  18. package/dist/teacher/curriculum/loader.d.ts +14 -0
  19. package/dist/teacher/curriculum/progress-tracker.d.ts +35 -0
  20. package/dist/teacher/curriculum/schema.d.ts +36 -0
  21. package/dist/teacher/exercises/builders/dialogue.d.ts +6 -0
  22. package/dist/teacher/exercises/builders/dictation.d.ts +6 -0
  23. package/dist/teacher/exercises/builders/error-correction.d.ts +6 -0
  24. package/dist/teacher/exercises/builders/fill-in-blank.d.ts +5 -0
  25. package/dist/teacher/exercises/builders/listening.d.ts +6 -0
  26. package/dist/teacher/exercises/builders/pronunciation.d.ts +6 -0
  27. package/dist/teacher/exercises/builders/reading.d.ts +6 -0
  28. package/dist/teacher/exercises/builders/sentence-construction.d.ts +6 -0
  29. package/dist/teacher/exercises/builders/translation.d.ts +7 -0
  30. package/dist/teacher/exercises/builders/vocabulary-drill.d.ts +5 -0
  31. package/dist/teacher/exercises/generator.d.ts +45 -0
  32. package/dist/teacher/exercises/index.d.ts +7 -0
  33. package/dist/teacher/importers/csv-importer.d.ts +22 -0
  34. package/dist/teacher/importers/json-importer.d.ts +11 -0
  35. package/dist/teacher/learner-model.d.ts +84 -0
  36. package/dist/teacher/learner-storage.d.ts +61 -0
  37. package/dist/teacher/level-classifier.d.ts +34 -0
  38. package/dist/teacher/loop/message-builder.d.ts +32 -0
  39. package/dist/teacher/loop/scheduler-integration.d.ts +45 -0
  40. package/dist/teacher/loop/teaching-loop.d.ts +72 -0
  41. package/dist/teacher/scrapthing/batch-job.d.ts +65 -0
  42. package/dist/teacher/scrapthing/content-cleaner.d.ts +27 -0
  43. package/dist/teacher/scrapthing/mcp-adapter.d.ts +50 -0
  44. package/dist/teacher/skills/index.d.ts +35 -0
  45. package/dist/teacher/skills/placement-test.d.ts +47 -0
  46. package/dist/teacher/skills/plan-lesson.d.ts +46 -0
  47. package/dist/teacher/spaced-repetition.d.ts +49 -0
  48. package/dist/teacher/teacher-memory.d.ts +79 -0
  49. package/dist/teacher/voice/custom-vocabulary.d.ts +28 -0
  50. package/dist/teacher/voice/exercise-voice.d.ts +39 -0
  51. package/dist/teacher/voice/language-voices.d.ts +26 -0
  52. package/dist/teacher/voice/pronunciation-scorer.d.ts +38 -0
  53. package/package.json +36 -0
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Corpus Importer — Types and pipeline interface for the Fenix Voices
3
+ * content import system.
4
+ *
5
+ * Defines the CorpusItem entity and the shared importer contract that
6
+ * CSV, JSON, and future importers implement.
7
+ */
8
+ export type ContentType = "proverb" | "dialogue" | "vocabulary_list" | "grammar_explanation" | "article" | "roleplay" | "exercise_template" | "story" | "song_lyrics";
9
+ export type CorpusSource = "ejiogbe" | "imported" | "scraped" | "synthetic";
10
+ export type ReviewStatus = "approved" | "unreviewed" | "rejected";
11
+ export type CorpusLevel = "pre-A1" | "A1" | "A2" | "B1" | "B2" | "C1" | "C2" | "unclassified";
12
+ export interface CorpusItem {
13
+ id: string;
14
+ language: string;
15
+ contentType: ContentType;
16
+ level: CorpusLevel;
17
+ title?: string;
18
+ content: string;
19
+ translation?: string;
20
+ bridgeLanguage?: string;
21
+ tags: string[];
22
+ source: CorpusSource;
23
+ reviewStatus: ReviewStatus;
24
+ metadata?: Record<string, unknown>;
25
+ createdAt: string;
26
+ }
27
+ export interface ImportResult {
28
+ imported: number;
29
+ skipped: number;
30
+ errors: string[];
31
+ }
32
+ export interface CorpusImporter {
33
+ /** Parse raw input and return validated CorpusItems. */
34
+ parse(raw: string): CorpusItem[];
35
+ }
36
+ export declare function isValidContentType(v: string): v is ContentType;
37
+ export declare function isValidLevel(v: string): v is CorpusLevel;
38
+ export declare function isValidLanguageCode(v: string): boolean;
39
+ export declare function normalizeLanguageCode(v: string): string;
40
+ /**
41
+ * Validates a partial CorpusItem object and returns an array of error
42
+ * messages. Empty array means valid.
43
+ */
44
+ export declare function validateCorpusItem(item: Record<string, unknown>): string[];
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Corpus Storage — PostgreSQL operations for the Fenix Voices corpus.
3
+ *
4
+ * Provides:
5
+ * - Migration SQL for corpus_items table with pgvector embedding, GIN tags
6
+ * - importBatch() — bulk insert with embedding generation
7
+ * - search() — hybrid search (vector + full-text) with dual search fusion
8
+ * - getRandomItems() — random selection for exercise variety
9
+ * - tagContent() / classifyLevel() — content annotation
10
+ */
11
+ import { Kysely } from "kysely";
12
+ import type { CorpusItem, ImportResult } from "./corpus-importer.js";
13
+ export type EmbedBatchFn = (texts: string[]) => Promise<(number[] | null)[]>;
14
+ export declare function runCorpusMigration(db: Kysely<any>): Promise<string[]>;
15
+ export declare function importBatch(db: Kysely<any>, items: CorpusItem[], embedFn?: EmbedBatchFn): Promise<ImportResult>;
16
+ export interface CorpusSearchFilters {
17
+ language?: string;
18
+ level?: string;
19
+ contentType?: string;
20
+ tags?: string[];
21
+ reviewStatus?: string;
22
+ }
23
+ export interface CorpusSearchResult {
24
+ item: CorpusItem;
25
+ score: number;
26
+ }
27
+ export declare function search(db: Kysely<any>, query: string, queryEmbedding: number[] | null, filters?: CorpusSearchFilters, limit?: number, vectorWeight?: number, textWeight?: number): Promise<CorpusSearchResult[]>;
28
+ export declare function getRandomItems(db: Kysely<any>, filters?: CorpusSearchFilters, count?: number): Promise<CorpusItem[]>;
29
+ export declare function tagContent(db: Kysely<any>, id: string, tags: string[]): Promise<void>;
30
+ export declare function classifyLevel(db: Kysely<any>, id: string, level: string): Promise<void>;
31
+ export declare function getCorpusItem(db: Kysely<any>, id: string): Promise<CorpusItem | null>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Curriculum Generator — Generates curriculum templates via LLM
3
+ * when no template exists for a requested language.
4
+ */
5
+ import { Kysely } from "kysely";
6
+ import type { CurriculumTemplate } from "./schema.js";
7
+ export type LLMGenerateObjectFn<T> = (prompt: string) => Promise<T>;
8
+ export declare function buildGenerationPrompt(language: string, isoCode: string, corpusCount: number, corpusSample: string[]): string;
9
+ export declare function generateTemplate(language: string, isoCode: string, corpusCount: number, corpusSample: string[], generateFn: LLMGenerateObjectFn<CurriculumTemplate>): Promise<CurriculumTemplate>;
10
+ /**
11
+ * Generate a template and save it to the database.
12
+ */
13
+ export declare function generateAndSaveTemplate(db: Kysely<any>, language: string, isoCode: string, corpusCount: number, corpusSample: string[], generateFn: LLMGenerateObjectFn<CurriculumTemplate>): Promise<CurriculumTemplate>;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Curriculum Loader — Template management for loading, saving,
3
+ * and listing curriculum templates.
4
+ *
5
+ * Templates are loaded from disk (data/curricula/*.json) or from the
6
+ * curriculum_templates PostgreSQL table. Database takes precedence.
7
+ */
8
+ import { Kysely } from "kysely";
9
+ import type { CurriculumTemplate } from "./schema.js";
10
+ export declare function runCurriculumMigration(db: Kysely<any>): Promise<string[]>;
11
+ export declare function loadTemplateFromDisk(language: string, dir?: string): CurriculumTemplate | null;
12
+ export declare function getTemplate(db: Kysely<any>, language: string, diskDir?: string): Promise<CurriculumTemplate | null>;
13
+ export declare function saveTemplate(db: Kysely<any>, template: CurriculumTemplate): Promise<void>;
14
+ export declare function listAvailableLanguages(db: Kysely<any>, diskDir?: string): Promise<string[]>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Progress Tracker — Tracks learner advancement through a curriculum.
3
+ *
4
+ * Manages unit completion, prerequisite checking, and score-based
5
+ * advancement decisions.
6
+ */
7
+ import { Kysely } from "kysely";
8
+ import type { LearnerProgress } from "./schema.js";
9
+ import type { CurriculumTemplate, CurriculumUnit } from "./schema.js";
10
+ export declare function runProgressMigration(db: Kysely<any>): Promise<string[]>;
11
+ export declare function getProgress(db: Kysely<any>, learnerId: string, language: string): Promise<LearnerProgress | null>;
12
+ export declare function initProgress(db: Kysely<any>, learnerId: string, language: string, firstUnitId: string): Promise<LearnerProgress>;
13
+ /**
14
+ * Check whether the learner should advance to the next unit based on
15
+ * their average score in the current unit.
16
+ */
17
+ export declare function shouldAdvance(progress: LearnerProgress, threshold?: number): boolean;
18
+ /**
19
+ * Check whether all prerequisite units for a given unit are completed.
20
+ */
21
+ export declare function prerequisitesMet(unit: CurriculumUnit, completedUnits: string[]): boolean;
22
+ /**
23
+ * Find the next unit the learner should move to, respecting prerequisites
24
+ * and CEFR level ordering.
25
+ */
26
+ export declare function findNextUnit(template: CurriculumTemplate, completedUnits: string[]): CurriculumUnit | null;
27
+ /**
28
+ * Mark the current unit as complete and advance to the next one.
29
+ * Returns null if the curriculum is complete or prerequisites block advancement.
30
+ */
31
+ export declare function advanceUnit(db: Kysely<any>, learnerId: string, template: CurriculumTemplate): Promise<LearnerProgress | null>;
32
+ /**
33
+ * Record a score for the current unit.
34
+ */
35
+ export declare function recordUnitScore(db: Kysely<any>, learnerId: string, language: string, unitId: string, score: number): Promise<void>;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Curriculum Template Schema — Defines the structure for language
3
+ * curriculum templates and learner progress tracking.
4
+ */
5
+ import type { CEFRLevel } from "../learner-model.js";
6
+ export interface CurriculumTemplate {
7
+ language: string;
8
+ version: string;
9
+ author?: string;
10
+ units: CurriculumUnit[];
11
+ }
12
+ export interface CurriculumUnit {
13
+ id: string;
14
+ title: string;
15
+ level: CEFRLevel;
16
+ objectives: string[];
17
+ vocabularyTargets: string[];
18
+ grammarTargets: string[];
19
+ culturalContext?: string;
20
+ prerequisiteUnits: string[];
21
+ estimatedSessions: number;
22
+ exerciseTypeWeights: Record<string, number>;
23
+ }
24
+ export interface LearnerProgress {
25
+ learnerId: string;
26
+ templateLanguage: string;
27
+ completedUnits: string[];
28
+ currentUnitId: string;
29
+ currentSession: number;
30
+ unitScores: Record<string, number>;
31
+ }
32
+ export interface ValidationError {
33
+ path: string;
34
+ message: string;
35
+ }
36
+ export declare function validateTemplate(obj: unknown): ValidationError[];
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Dialogue Roleplay — Multi-turn conversation. Agent plays one role,
3
+ * learner plays the other. speechRequired when voice enabled.
4
+ */
5
+ import type { ExerciseBuilder } from "../generator.js";
6
+ export declare const dialogueRoleplay: ExerciseBuilder;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Dictation — TTS plays phrase, learner types what they heard.
3
+ * audioRequired: true.
4
+ */
5
+ import type { ExerciseBuilder } from "../generator.js";
6
+ export declare const dictation: ExerciseBuilder;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Error Correction — Show sentence with deliberate error, learner
3
+ * identifies and fixes it.
4
+ */
5
+ import type { ExerciseBuilder } from "../generator.js";
6
+ export declare const errorCorrection: ExerciseBuilder;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Fill in the Blank — Sentence with a gap. Masks a target word from corpus.
3
+ */
4
+ import type { ExerciseBuilder } from "../generator.js";
5
+ export declare const fillInBlank: ExerciseBuilder;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Listening Comprehension — TTS renders a passage, learner answers
3
+ * comprehension questions. audioRequired: true.
4
+ */
5
+ import type { ExerciseBuilder } from "../generator.js";
6
+ export declare const listeningComprehension: ExerciseBuilder;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Pronunciation — TTS renders target phrase, learner speaks,
3
+ * STT transcribes for comparison. audioRequired + speechRequired.
4
+ */
5
+ import type { ExerciseBuilder } from "../generator.js";
6
+ export declare const pronunciation: ExerciseBuilder;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Reading Comprehension — Display passage, ask comprehension questions.
3
+ * Pulls from corpus articles/stories.
4
+ */
5
+ import type { ExerciseBuilder } from "../generator.js";
6
+ export declare const readingComprehension: ExerciseBuilder;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Sentence Construction — Give scrambled words, learner arranges
3
+ * into correct sentence.
4
+ */
5
+ import type { ExerciseBuilder } from "../generator.js";
6
+ export declare const sentenceConstruction: ExerciseBuilder;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Translation — Forward (native → target) and reverse (target → native).
3
+ * Uses parallel text from corpus when available.
4
+ */
5
+ import type { ExerciseBuilder } from "../generator.js";
6
+ export declare const translationForward: ExerciseBuilder;
7
+ export declare const translationReverse: ExerciseBuilder;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Vocabulary Drill — Match word to definition. 4 options, 1 correct.
3
+ */
4
+ import type { ExerciseBuilder } from "../generator.js";
5
+ export declare const vocabularyDrill: ExerciseBuilder;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Exercise Generator — Produces concrete practice activities from
3
+ * planned exercises in a lesson plan.
4
+ */
5
+ import type { LearnerProfile } from "../learner-model.js";
6
+ import type { PlannedExercise } from "../skills/plan-lesson.js";
7
+ export type ExerciseType = "vocabulary_drill" | "fill_in_blank" | "translation_forward" | "translation_reverse" | "listening_comprehension" | "pronunciation" | "dialogue_roleplay" | "reading_comprehension" | "dictation" | "sentence_construction" | "error_correction";
8
+ export interface Exercise {
9
+ id: string;
10
+ type: ExerciseType;
11
+ prompt: string;
12
+ expectedAnswer?: string;
13
+ acceptableAnswers?: string[];
14
+ hints: string[];
15
+ difficulty: number;
16
+ targetVocabulary?: string[];
17
+ targetGrammar?: string[];
18
+ audioRequired: boolean;
19
+ speechRequired: boolean;
20
+ metadata: Record<string, unknown>;
21
+ }
22
+ /** Content fetched from the corpus for building an exercise. */
23
+ export interface CorpusContent {
24
+ text: string;
25
+ translation?: string;
26
+ language: string;
27
+ level: string;
28
+ tags: string[];
29
+ }
30
+ /** Builder function signature — each exercise type implements one. */
31
+ export type ExerciseBuilder = (content: CorpusContent, planned: PlannedExercise, learner: LearnerProfile, distractors?: string[]) => Exercise;
32
+ export type ContentQueryFn = (query: string, language: string, level: string) => Promise<CorpusContent[]>;
33
+ export type DistractorFn = (language: string, level: string, exclude: string[], count: number) => Promise<string[]>;
34
+ export type LLMFallbackFn = (type: string, language: string, level: string, targets: string[]) => Promise<CorpusContent>;
35
+ export declare function resolveExerciseType(raw: string): ExerciseType;
36
+ export declare function needsAudio(type: ExerciseType): boolean;
37
+ export declare function needsSpeech(type: ExerciseType, voiceEnabled: boolean): boolean;
38
+ export interface GenerateExerciseDeps {
39
+ queryContent: ContentQueryFn;
40
+ getDistractors?: DistractorFn;
41
+ llmFallback?: LLMFallbackFn;
42
+ builders: Map<ExerciseType, ExerciseBuilder>;
43
+ }
44
+ export declare function generateExercise(deps: GenerateExerciseDeps, planned: PlannedExercise, learner: LearnerProfile): Promise<Exercise>;
45
+ export declare function createBaseExercise(type: ExerciseType, planned: PlannedExercise, learner: LearnerProfile): Omit<Exercise, "prompt" | "expectedAnswer">;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Exercise Builder Registry — Maps ExerciseType to builder functions.
3
+ */
4
+ import type { ExerciseType, ExerciseBuilder } from "./generator.js";
5
+ export { generateExercise, resolveExerciseType, needsAudio, needsSpeech, createBaseExercise } from "./generator.js";
6
+ export type { Exercise, ExerciseType, ExerciseBuilder, CorpusContent, GenerateExerciseDeps } from "./generator.js";
7
+ export declare const EXERCISE_BUILDERS: Map<ExerciseType, ExerciseBuilder>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * CSV Importer — Parses CSV datasets into CorpusItems.
3
+ *
4
+ * Supports:
5
+ * - instruction/input/response column format
6
+ * - Parallel text format (English + target language columns)
7
+ * - Auto-detection of content type from column structure
8
+ * - Custom column mapping
9
+ */
10
+ import type { CorpusItem, ContentType, CorpusImporter } from "../corpus-importer.js";
11
+ export declare function parseCSV(raw: string): Record<string, string>[];
12
+ export interface CSVImportOptions {
13
+ language?: string;
14
+ bridgeLanguage?: string;
15
+ defaultContentType?: ContentType;
16
+ columnMap?: Record<string, string>;
17
+ }
18
+ export declare class CsvImporter implements CorpusImporter {
19
+ private opts;
20
+ constructor(opts?: CSVImportOptions);
21
+ parse(raw: string): CorpusItem[];
22
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * JSON Importer — Parses JSON corpus files into validated CorpusItems.
3
+ *
4
+ * Accepts arrays of CorpusItem-compatible objects, validates required fields,
5
+ * normalizes language codes to ISO 639, and returns clean CorpusItems ready
6
+ * for batch embedding and insert.
7
+ */
8
+ import type { CorpusItem, CorpusImporter } from "../corpus-importer.js";
9
+ export declare class JsonImporter implements CorpusImporter {
10
+ parse(raw: string): CorpusItem[];
11
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Learner Model — TypeScript interfaces for the Fenix Voices teacher layer.
3
+ *
4
+ * Defines the four core entities: LearnerProfile, VocabEntry,
5
+ * GrammarEntry, and SessionRecord.
6
+ */
7
+ export type CEFRLevel = 'pre-A1' | 'A1' | 'A2' | 'B1' | 'B2' | 'C1' | 'C2';
8
+ export type CorrectionStyle = 'gentle' | 'direct' | 'socratic';
9
+ export type PracticeFrequency = 'daily' | 'every-other-day' | 'weekly' | 'on-demand';
10
+ export interface LearnerPreferences {
11
+ sessionDuration: number;
12
+ exerciseTypes: string[];
13
+ voiceEnabled: boolean;
14
+ correctionStyle: CorrectionStyle;
15
+ practiceFrequency: PracticeFrequency;
16
+ timezone: string;
17
+ preferredPracticeTime?: string;
18
+ }
19
+ export interface LearnerStats {
20
+ totalSessions: number;
21
+ totalExercises: number;
22
+ currentStreak: number;
23
+ longestStreak: number;
24
+ lastSessionAt?: string;
25
+ }
26
+ export interface LearnerProfile {
27
+ id: string;
28
+ userId: string;
29
+ targetLanguage: string;
30
+ nativeLanguage: string;
31
+ bridgeLanguage?: string;
32
+ currentLevel: CEFRLevel;
33
+ goals: string[];
34
+ preferences: LearnerPreferences;
35
+ stats: LearnerStats;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ }
39
+ export interface VocabEntry {
40
+ id: string;
41
+ learnerId: string;
42
+ word: string;
43
+ targetLanguage: string;
44
+ translation: string;
45
+ mastery: number;
46
+ nextReviewAt: string;
47
+ reviewCount: number;
48
+ lastReviewedAt?: string;
49
+ context?: string;
50
+ }
51
+ export interface GrammarEntry {
52
+ id: string;
53
+ learnerId: string;
54
+ concept: string;
55
+ targetLanguage: string;
56
+ mastery: number;
57
+ nextReviewAt: string;
58
+ reviewCount: number;
59
+ lastReviewedAt?: string;
60
+ notes?: string;
61
+ }
62
+ export interface SessionRecord {
63
+ id: string;
64
+ learnerId: string;
65
+ startedAt: string;
66
+ endedAt?: string;
67
+ unitId?: string;
68
+ exercisesCompleted: number;
69
+ averageScore: number;
70
+ newVocabulary: string[];
71
+ masteredItems: string[];
72
+ strugglingAreas: string[];
73
+ nextSessionFocus: string;
74
+ }
75
+ /** Compact learner stub surfaced to the agent context by default. */
76
+ export interface LearnerStub {
77
+ learnerId: string;
78
+ targetLanguage: string;
79
+ currentLevel: CEFRLevel;
80
+ vocabCount: number;
81
+ recentFocus: string;
82
+ currentStreak: number;
83
+ lastSessionAt?: string;
84
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Learner Storage — PostgreSQL operations for the Fenix Voices teacher layer.
3
+ *
4
+ * Provides:
5
+ * - Migration SQL for learner_profiles, vocab_entries, grammar_entries, session_records
6
+ * - Full CRUD for all four tables
7
+ * - getDueReviewItems() for spaced-repetition scheduling
8
+ * - updateMastery() with SM-2 recalculation
9
+ * - getProgressSummary() for dashboard aggregation
10
+ */
11
+ import { Kysely } from "kysely";
12
+ import type { LearnerProfile, VocabEntry, GrammarEntry, SessionRecord, LearnerStub } from "./learner-model.js";
13
+ export declare function runLearnerMigration(db: Kysely<any>): Promise<string[]>;
14
+ export declare function createLearnerProfile(db: Kysely<any>, profile: Omit<LearnerProfile, "id" | "createdAt" | "updatedAt">): Promise<LearnerProfile>;
15
+ export declare function getLearnerProfile(db: Kysely<any>, id: string): Promise<LearnerProfile | null>;
16
+ export declare function getLearnerProfileByUser(db: Kysely<any>, userId: string, targetLanguage: string): Promise<LearnerProfile | null>;
17
+ export declare function updateLearnerProfile(db: Kysely<any>, id: string, updates: Partial<Pick<LearnerProfile, "currentLevel" | "goals" | "preferences" | "stats" | "bridgeLanguage">>): Promise<LearnerProfile | null>;
18
+ export declare function deleteLearnerProfile(db: Kysely<any>, id: string): Promise<boolean>;
19
+ export declare function createVocabEntry(db: Kysely<any>, entry: Omit<VocabEntry, "id">): Promise<VocabEntry>;
20
+ export declare function getVocabEntry(db: Kysely<any>, id: string): Promise<VocabEntry | null>;
21
+ export declare function deleteVocabEntry(db: Kysely<any>, id: string): Promise<boolean>;
22
+ export declare function createGrammarEntry(db: Kysely<any>, entry: Omit<GrammarEntry, "id">): Promise<GrammarEntry>;
23
+ export declare function getGrammarEntry(db: Kysely<any>, id: string): Promise<GrammarEntry | null>;
24
+ export declare function deleteGrammarEntry(db: Kysely<any>, id: string): Promise<boolean>;
25
+ export declare function createSessionRecord(db: Kysely<any>, record: Omit<SessionRecord, "id">): Promise<SessionRecord>;
26
+ export declare function getSessionRecord(db: Kysely<any>, id: string): Promise<SessionRecord | null>;
27
+ export declare function getSessionsByLearner(db: Kysely<any>, learnerId: string, limit?: number): Promise<SessionRecord[]>;
28
+ export interface DueReviewItems {
29
+ vocab: VocabEntry[];
30
+ grammar: GrammarEntry[];
31
+ }
32
+ /**
33
+ * Returns vocab and grammar entries that are due for review
34
+ * (nextReviewAt <= now), ordered by next_review_at ascending.
35
+ */
36
+ export declare function getDueReviewItems(db: Kysely<any>, learnerId: string, limit?: number): Promise<DueReviewItems>;
37
+ /**
38
+ * Updates mastery for a vocab or grammar entry using SM-2 recalculation.
39
+ *
40
+ * @param table — 'vocab_entries' or 'grammar_entries'
41
+ * @param entryId — The entry ID
42
+ * @param score — Exercise score 0.0–1.0
43
+ */
44
+ export declare function updateMastery(db: Kysely<any>, table: "vocab_entries" | "grammar_entries", entryId: string, score: number): Promise<void>;
45
+ export interface ProgressSummary {
46
+ totalVocab: number;
47
+ masteredVocab: number;
48
+ totalGrammar: number;
49
+ masteredGrammar: number;
50
+ dueForReview: number;
51
+ totalSessions: number;
52
+ averageScore: number;
53
+ currentStreak: number;
54
+ }
55
+ export declare function getProgressSummary(db: Kysely<any>, learnerId: string): Promise<ProgressSummary>;
56
+ /**
57
+ * Generates a compact learner stub for the agent context.
58
+ * This is the "progressive disclosure" entry point: the agent always sees the
59
+ * stub, and only fetches full profile/detail when it needs to plan a session.
60
+ */
61
+ export declare function getLearnerStub(db: Kysely<any>, learnerId: string): Promise<LearnerStub | null>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * CEFR Level Classifier — Uses a utility LLM to classify corpus content
3
+ * into CEFR difficulty levels.
4
+ *
5
+ * Provides:
6
+ * - classifyCEFRLevel() — single item classification
7
+ * - batchClassify() — batch processing with cache
8
+ * - enqueueClassification() — job queue integration
9
+ */
10
+ import { Kysely } from "kysely";
11
+ import type { CorpusLevel } from "./corpus-importer.js";
12
+ export type LLMGenerateFn = (prompt: string) => Promise<string>;
13
+ export declare function clearClassificationCache(): void;
14
+ export declare function getCacheSize(): number;
15
+ export declare function buildClassificationPrompt(content: string, language: string): string;
16
+ export declare function parseLLMLevel(response: string): CorpusLevel;
17
+ export declare function classifyCEFRLevel(content: string, language: string, generateFn: LLMGenerateFn): Promise<CorpusLevel>;
18
+ export interface ClassifyJob {
19
+ id: string;
20
+ content: string;
21
+ language: string;
22
+ }
23
+ export interface ClassifyResult {
24
+ id: string;
25
+ level: CorpusLevel;
26
+ error?: string;
27
+ }
28
+ export declare function batchClassify(jobs: ClassifyJob[], generateFn: LLMGenerateFn): Promise<ClassifyResult[]>;
29
+ export declare function enqueueClassification(db: Kysely<any>, itemIds: string[]): Promise<number>;
30
+ /**
31
+ * Process a batch of enqueued classification jobs against the database.
32
+ * Updates each corpus item's level in place.
33
+ */
34
+ export declare function processClassificationQueue(db: Kysely<any>, generateFn: LLMGenerateFn, batchSize?: number): Promise<ClassifyResult[]>;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Message Builder — Constructs MessageEnvelopes for the teaching loop.
3
+ *
4
+ * All messages route through the agent loop and channel router
5
+ * to the learner's preferred channel.
6
+ */
7
+ import type { Exercise } from "../exercises/generator.js";
8
+ import type { LearnerProfile } from "../learner-model.js";
9
+ export interface MessageEnvelope {
10
+ channel: "scheduler";
11
+ learnerId: string;
12
+ type: "review" | "nudge" | "milestone";
13
+ subject: string;
14
+ body: string;
15
+ metadata: Record<string, unknown>;
16
+ }
17
+ export interface Milestone {
18
+ type: "vocabulary" | "streak" | "unit_completion";
19
+ value: number;
20
+ }
21
+ /**
22
+ * Format a review exercise for channel delivery.
23
+ */
24
+ export declare function buildReviewMessage(exercise: Exercise, learner: LearnerProfile): MessageEnvelope;
25
+ /**
26
+ * Build an encouraging nudge for inactive learners.
27
+ */
28
+ export declare function buildNudgeMessage(learner: LearnerProfile, daysSinceLastSession: number): MessageEnvelope;
29
+ /**
30
+ * Build a celebration message for reaching a milestone.
31
+ */
32
+ export declare function buildMilestoneMessage(learner: LearnerProfile, milestone: Milestone): MessageEnvelope;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Scheduler Integration — Registers teaching-loop cron jobs
3
+ * with the kernel's planned-tasks scheduler (Task 3.7).
4
+ *
5
+ * One cron job per active learner. Jobs are created, rescheduled,
6
+ * or removed in response to learner lifecycle events.
7
+ */
8
+ import type { LearnerPreferences, PracticeFrequency } from "../learner-model.js";
9
+ import type { TeachingLoopConfig, LoopOutcome } from "./teaching-loop.js";
10
+ export interface CronJob {
11
+ id: string;
12
+ type: "teaching.loop";
13
+ learnerId: string;
14
+ schedule: string;
15
+ enabled: boolean;
16
+ createdAt: string;
17
+ }
18
+ export interface SchedulerDeps {
19
+ createJob: (job: Omit<CronJob, "id" | "createdAt">) => Promise<CronJob>;
20
+ updateJob: (jobId: string, updates: Partial<Pick<CronJob, "schedule" | "enabled">>) => Promise<CronJob>;
21
+ deleteJob: (jobId: string) => Promise<void>;
22
+ findJob: (learnerId: string, type: "teaching.loop") => Promise<CronJob | null>;
23
+ runLoop: (learnerId: string) => Promise<LoopOutcome>;
24
+ }
25
+ /**
26
+ * Convert learner practice frequency to a cron expression.
27
+ * Uses the config's defaultSchedule as fallback.
28
+ */
29
+ export declare function frequencyToCron(frequency: PracticeFrequency, config?: TeachingLoopConfig): string;
30
+ /**
31
+ * Register a cron job when a learner signs up.
32
+ */
33
+ export declare function onLearnerCreated(deps: SchedulerDeps, learnerId: string, preferences: LearnerPreferences, config?: TeachingLoopConfig): Promise<CronJob | null>;
34
+ /**
35
+ * Reschedule when a learner updates preferences.
36
+ */
37
+ export declare function onPreferencesUpdated(deps: SchedulerDeps, learnerId: string, preferences: LearnerPreferences, config?: TeachingLoopConfig): Promise<CronJob | null>;
38
+ /**
39
+ * Remove cron job when a learner disables the loop.
40
+ */
41
+ export declare function onLoopDisabled(deps: SchedulerDeps, learnerId: string): Promise<void>;
42
+ /**
43
+ * Execute a scheduled cron tick for a learner.
44
+ */
45
+ export declare function onCronTick(deps: SchedulerDeps, learnerId: string): Promise<LoopOutcome>;