@intellectif/lk-core 0.16.0 → 0.17.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 (43) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/{activity-DcxtpX7Z.d.cts → activity-BmjBjXVJ.d.cts} +213 -2
  3. package/dist/{activity-DcxtpX7Z.d.ts → activity-BmjBjXVJ.d.ts} +213 -2
  4. package/dist/{chunk-FJJ2GVBA.cjs → chunk-2CV6NU32.cjs} +19 -19
  5. package/dist/{chunk-FJJ2GVBA.cjs.map → chunk-2CV6NU32.cjs.map} +1 -1
  6. package/dist/{chunk-IRUD73IQ.js → chunk-D3GP5MET.js} +683 -638
  7. package/dist/chunk-D3GP5MET.js.map +1 -0
  8. package/dist/{chunk-F7UOLKWV.cjs → chunk-D4TOPSHV.cjs} +518 -473
  9. package/dist/chunk-D4TOPSHV.cjs.map +1 -0
  10. package/dist/{chunk-VFTVZJO5.cjs → chunk-EOFWSGLU.cjs} +4 -4
  11. package/dist/{chunk-VFTVZJO5.cjs.map → chunk-EOFWSGLU.cjs.map} +1 -1
  12. package/dist/{chunk-S63IOKFP.js → chunk-WXS5EB65.js} +2 -2
  13. package/dist/{chunk-OXF7VT7S.js → chunk-X5DAXBJI.js} +2 -2
  14. package/dist/{chunk-6P6XK2LI.cjs → chunk-XNMKDFPW.cjs} +31 -31
  15. package/dist/{chunk-6P6XK2LI.cjs.map → chunk-XNMKDFPW.cjs.map} +1 -1
  16. package/dist/{chunk-GOZGBVJP.js → chunk-Z7QQZ53L.js} +2 -2
  17. package/dist/{chunk-GOZGBVJP.js.map → chunk-Z7QQZ53L.js.map} +1 -1
  18. package/dist/{index-BWpwZRQw.d.cts → index-CvfeD_cU.d.cts} +144 -86
  19. package/dist/{index-DRJqwO2y.d.ts → index-G_KusUcK.d.ts} +144 -86
  20. package/dist/index.cjs +542 -127
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +122 -5
  23. package/dist/index.d.ts +122 -5
  24. package/dist/index.js +422 -7
  25. package/dist/index.js.map +1 -1
  26. package/dist/schemas.cjs +5 -3
  27. package/dist/schemas.cjs.map +1 -1
  28. package/dist/schemas.d.cts +2 -2
  29. package/dist/schemas.d.ts +2 -2
  30. package/dist/schemas.js +4 -2
  31. package/dist/scoring.cjs +3 -3
  32. package/dist/scoring.d.cts +2 -2
  33. package/dist/scoring.d.ts +2 -2
  34. package/dist/scoring.js +2 -2
  35. package/dist/xapi.cjs +3 -3
  36. package/dist/xapi.d.cts +1 -1
  37. package/dist/xapi.d.ts +1 -1
  38. package/dist/xapi.js +2 -2
  39. package/package.json +1 -1
  40. package/dist/chunk-F7UOLKWV.cjs.map +0 -1
  41. package/dist/chunk-IRUD73IQ.js.map +0 -1
  42. /package/dist/{chunk-S63IOKFP.js.map → chunk-WXS5EB65.js.map} +0 -0
  43. /package/dist/{chunk-OXF7VT7S.js.map → chunk-X5DAXBJI.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # @intellectif/lk-core
2
2
 
3
+ ## 0.17.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 15a3435: The contract for AI help a learner reads — an explanation of a graded answer, and hints before one —
8
+ between an activity and a model the host runs. The SDK never calls a model and holds no key or prompt;
9
+ it builds what the model is given and checks what comes back.
10
+
11
+ - **Facts:** `buildAiFacts(data, response, details)` describes an item as the learner saw it, their
12
+ answer, and the SDK's own verdict part by part. It covers multiple choice (every option), fill in the
13
+ blanks and gap select (each blank or gap in passage order, the passage written with `[1]`, `[2]`…),
14
+ and dictation (the word-by-word alignment). On a redacted item the key is absent, except where a
15
+ server's outcome supplies it.
16
+ - **Requests:**
17
+ - `aiExplanationRequest({ data, response, outcome?, learnerLocale? })` carries the facts and the
18
+ `grade`, with its `category` (`correct`, `partly-correct` or `incorrect`). A scored `outcome` wins
19
+ over grading locally, so an explanation speaks to the grade of record.
20
+ - `aiHintRequest({ data, response, previousHints, learnerLocale? })` carries the key and the answer
21
+ so far, marked part by part. It gives none for a dictation, which has hints of its own, or for a
22
+ redacted item.
23
+ - **Checks:**
24
+ - `readAiTextResult` refuses anything but plain text of up to 2,000 characters (`malformed`,
25
+ `empty`, `too-long`), with control characters removed.
26
+ - `checkAiExplanation` also refuses an explanation stating a verdict other than the SDK's
27
+ (`contradicts-grade`).
28
+ - `checkAiHint` also refuses a hint that contains an answer (`reveals-answer`).
29
+ - **The guard:** `hintRevealsAnswer(facts, text)` finds an answer written out, ignoring case,
30
+ accents and punctuation. An answer of one short word counts only where the hint writes it beside a
31
+ neighbour it has in the passage, so a hint can still say "the verb is…".
32
+ - **Permissions:** `aiSupports(type, feature)`, `aiAllowedByContent(data, feature)`, `aiGradeOf`, and
33
+ the types `AiItemFacts`, `AiExplanationRequest`, `AiHintRequest`, `AiTextResult`, `AiProvenance`,
34
+ `ActivityAiPermissions` and more. Two new interaction kinds: `ai-hint-shown` and
35
+ `ai-explanation-shown`.
36
+
37
+ **The author's switch, and one tightened rule.** Every built-in type now defines an optional
38
+ `ai: { hints?: boolean, explanations?: boolean }`: `false` switches that help off for the item,
39
+ wherever it is delivered, and an author can only switch help off. `redact()` keeps both flags, as
40
+ public, and drops any other key inside `ai`; the strict redacted schemas accept them.
41
+
42
+ A field named `ai` was until now an unknown key the loose schemas kept, whatever it held. A sidecar
43
+ such as `ai: 'generated'`, or a flag that is not a boolean, now fails `validateActivity`: check stored
44
+ content before upgrading.
45
+
46
+ See `docs/ai.md`.
47
+
3
48
  ## 0.16.0
4
49
 
5
50
  ### Minor Changes
@@ -63,6 +63,197 @@ declare function levenshteinDistance(a: string, b: string, max: number): number;
63
63
  */
64
64
  declare function matchText(input: string, accepted: string | readonly string[], policy?: TextMatchPolicy): TextMatchResult;
65
65
 
66
+ /**
67
+ * The contract between an activity and a model the HOST runs, for help a
68
+ * learner reads: an explanation of a graded answer, and hints before one.
69
+ *
70
+ * The SDK never calls a model and holds no key, prompt or provider. It builds
71
+ * the facts a model is given — from the item, the learner's answer and the
72
+ * SDK's own scorer — and checks what comes back. The model explains a verdict
73
+ * the SDK reached; it never reaches one.
74
+ */
75
+ /**
76
+ * What an author allows AI to do for one item. Absent, or a feature left out,
77
+ * leaves the choice to the deployment. `false` switches a feature off for this
78
+ * item wherever it is delivered; an author can only switch a feature off,
79
+ * never force one on.
80
+ *
81
+ * Switch hints off where any hint would give the answer away — a
82
+ * one-word vocabulary item, say.
83
+ */
84
+ interface ActivityAiPermissions {
85
+ /** An explanation of the learner's graded answer. */
86
+ explanations?: boolean;
87
+ /** Hints before the learner submits. */
88
+ hints?: boolean;
89
+ }
90
+ /**
91
+ * An activity as a renderer holds it: full data or a `redact()` projection.
92
+ * Structural rather than the data union, so a renderer's own view of an item —
93
+ * whose answer-key fields may be absent — is accepted as it is. The AI
94
+ * functions read every field defensively.
95
+ */
96
+ interface AiActivityInput {
97
+ readonly type: string;
98
+ readonly id: string;
99
+ readonly title: string;
100
+ readonly locale?: unknown;
101
+ readonly redacted?: unknown;
102
+ readonly ai?: unknown;
103
+ }
104
+ /** The two kinds of help a learner can be given. */
105
+ type AiFeature = 'explanation' | 'hint';
106
+ /** The activity types the SDK builds facts for. */
107
+ type AiSupportedActivityType = 'multiple-choice' | 'fill-in-the-blanks' | 'gap-select' | 'dictation';
108
+ /**
109
+ * A whole answer's grade, from the SDK's scorer. `category` is the verdict an
110
+ * explanation must agree with: all marks, some, or none.
111
+ */
112
+ interface AiGrade {
113
+ score: number;
114
+ maxScore: number;
115
+ passed: boolean;
116
+ category: AiVerdict;
117
+ }
118
+ /** The three verdicts an explanation can speak to. */
119
+ type AiVerdict = 'correct' | 'partly-correct' | 'incorrect';
120
+ interface AiFactsBase {
121
+ activityId: string;
122
+ title: string;
123
+ /** The language the item is written in, when the author gave one. */
124
+ locale?: string;
125
+ }
126
+ /** One option of a multiple-choice question, and what the learner did with it. */
127
+ interface AiOptionFact {
128
+ id: string;
129
+ text: string;
130
+ chosen: boolean;
131
+ /** Whether this option is part of the answer; `null` when the key is not available. */
132
+ correct: boolean | null;
133
+ /** The author's feedback on this option. */
134
+ feedback?: string;
135
+ }
136
+ interface AiMultipleChoiceFacts extends AiFactsBase {
137
+ activityType: 'multiple-choice';
138
+ question: string;
139
+ mode: 'single' | 'multi';
140
+ options: AiOptionFact[];
141
+ }
142
+ /** One blank, in the order it appears in the passage. */
143
+ interface AiBlankFact {
144
+ id: string;
145
+ /** 1-based, in passage order. */
146
+ position: number;
147
+ /** What the learner typed, or `''`. */
148
+ typed: string;
149
+ /** The answers that count; `null` when the key is not available. */
150
+ accepted: string[] | null;
151
+ /** The SDK's verdict on this blank; `null` before it is graded or without a key. */
152
+ correct: boolean | null;
153
+ /** The author's hint for this blank. */
154
+ hint?: string;
155
+ /** The author's feedback for this blank. */
156
+ feedback?: string;
157
+ }
158
+ interface AiFillInTheBlanksFacts extends AiFactsBase {
159
+ activityType: 'fill-in-the-blanks';
160
+ /** The passage, each blank written as `[1]`, `[2]`… in passage order. */
161
+ passage: string;
162
+ blanks: AiBlankFact[];
163
+ }
164
+ /** One gap, in the order it appears in the passage. */
165
+ interface AiGapFact {
166
+ id: string;
167
+ /** 1-based, in passage order. */
168
+ position: number;
169
+ /** The words offered at this gap. */
170
+ choices: string[];
171
+ /** The word the learner chose, or `null`. */
172
+ chosen: string | null;
173
+ /** The right word; `null` when the key is not available. */
174
+ answer: string | null;
175
+ /** The SDK's verdict on this gap; `null` before it is graded or without a key. */
176
+ correct: boolean | null;
177
+ /** The author's feedback for this gap. */
178
+ feedback?: string;
179
+ }
180
+ interface AiGapSelectFacts extends AiFactsBase {
181
+ activityType: 'gap-select';
182
+ /** The passage, each gap written as `[1]`, `[2]`… in passage order. */
183
+ passage: string;
184
+ gaps: AiGapFact[];
185
+ }
186
+ /** One word of a dictation, as the SDK's alignment paired it. */
187
+ interface AiWordFact {
188
+ /** The word the recording says; `''` for an extra word the learner added. */
189
+ expected: string;
190
+ /** The word the learner typed; `''` for a word they left out. */
191
+ typed: string;
192
+ status: 'correct' | 'incorrect' | 'missing' | 'extra';
193
+ }
194
+ interface AiDictationFacts extends AiFactsBase {
195
+ activityType: 'dictation';
196
+ /** What the recording says; `null` when the key is not available. */
197
+ transcript: string | null;
198
+ /** What the learner typed. */
199
+ typed: string;
200
+ /** The alignment word by word; `null` when the key is not available. */
201
+ words: AiWordFact[] | null;
202
+ }
203
+ /**
204
+ * What a model is told about one item and one answer: the question as the
205
+ * learner saw it, what they answered, and — part by part — the SDK's verdict.
206
+ */
207
+ type AiItemFacts = AiMultipleChoiceFacts | AiFillInTheBlanksFacts | AiGapSelectFacts | AiDictationFacts;
208
+ /**
209
+ * Asks for an explanation of a graded answer. Sent after the SDK has graded
210
+ * it, so `grade` is always present, and an explanation that contradicts
211
+ * `grade.category` is refused.
212
+ */
213
+ interface AiExplanationRequest {
214
+ feature: 'explanation';
215
+ facts: AiItemFacts;
216
+ grade: AiGrade;
217
+ /** The language to answer in: the learner's interface language, when known. */
218
+ learnerLocale?: string;
219
+ }
220
+ /**
221
+ * Asks for the next hint before the learner submits. `facts` carries the key
222
+ * so a model can hint toward the answer; the SDK refuses any hint that
223
+ * contains it.
224
+ */
225
+ interface AiHintRequest {
226
+ feature: 'hint';
227
+ facts: AiItemFacts;
228
+ /** 1-based: the hint being asked for. */
229
+ hintNumber: number;
230
+ /** The hints already shown for this item, oldest first. */
231
+ previousHints: string[];
232
+ learnerLocale?: string;
233
+ }
234
+ /** What produced an AI text, for the record a host keeps. */
235
+ interface AiProvenance {
236
+ /** The model's identifier, e.g. a name and version. */
237
+ model?: string;
238
+ /** A hash or id of the prompt revision. */
239
+ promptHash?: string;
240
+ /** ISO 8601. */
241
+ generatedAt?: string;
242
+ }
243
+ /**
244
+ * What a host's port returns. Plain text: the SDK renders it as text, never
245
+ * as HTML. An explanation may state the verdict it assumed; one that
246
+ * disagrees with the SDK's is refused.
247
+ */
248
+ interface AiTextResult {
249
+ text: string;
250
+ /** For an explanation: the verdict the model explained. */
251
+ verdict?: AiVerdict;
252
+ provenance?: AiProvenance;
253
+ }
254
+ /** Why a result was not shown. */
255
+ type AiRefusal = 'malformed' | 'empty' | 'too-long' | 'contradicts-grade' | 'reveals-answer';
256
+
66
257
  /**
67
258
  * The return trip for deferred grading.
68
259
  *
@@ -590,6 +781,8 @@ interface MultipleChoiceData {
590
781
  learningObjectives?: string[];
591
782
  /** Subjective difficulty on a 1–5 scale. */
592
783
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
784
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
785
+ ai?: ActivityAiPermissions;
593
786
  }
594
787
  /** Configuration for a single fill-in-the-blank slot. */
595
788
  interface BlankConfig {
@@ -724,6 +917,8 @@ interface GapSelectData {
724
917
  learningObjectives?: string[];
725
918
  /** Subjective difficulty on a 1–5 scale. */
726
919
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
920
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
921
+ ai?: ActivityAiPermissions;
727
922
  }
728
923
  interface FillInTheBlanksData {
729
924
  schemaVersion: '1.0';
@@ -756,6 +951,8 @@ interface FillInTheBlanksData {
756
951
  learningObjectives?: string[];
757
952
  /** Subjective difficulty on a 1–5 scale. */
758
953
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
954
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
955
+ ai?: ActivityAiPermissions;
759
956
  }
760
957
  /** A single criterion within a written-response grading rubric. */
761
958
  interface WrittenResponseRubricCriterion {
@@ -818,6 +1015,8 @@ interface WrittenResponseData {
818
1015
  learningObjectives?: string[];
819
1016
  /** Subjective difficulty on a 1–5 scale. */
820
1017
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
1018
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
1019
+ ai?: ActivityAiPermissions;
821
1020
  }
822
1021
  /**
823
1022
  * A second, slower recording of a dictation — a separate file (a text-to-speech
@@ -920,6 +1119,8 @@ interface DictationData {
920
1119
  learningObjectives?: string[];
921
1120
  /** Subjective difficulty on a 1–5 scale. */
922
1121
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
1122
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
1123
+ ai?: ActivityAiPermissions;
923
1124
  }
924
1125
  /** A dimension of speech a pronunciation assessor scores, on a 0–100 scale. */
925
1126
  type ReadAloudDimension = 'accuracy' | 'fluency' | 'completeness' | 'prosody';
@@ -1010,6 +1211,8 @@ interface ReadAloudData {
1010
1211
  learningObjectives?: string[];
1011
1212
  /** Subjective difficulty on a 1–5 scale. */
1012
1213
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
1214
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
1215
+ ai?: ActivityAiPermissions;
1013
1216
  }
1014
1217
  /**
1015
1218
  * Maps each ActivityType string to its learner-response shape. Open for
@@ -1320,7 +1523,15 @@ type InteractionKind = 'option-selected' | 'option-deselected' | 'blank-filled'
1320
1523
  * primary line's language, or `null` with captions off; `payload.secondary` is
1321
1524
  * the second line's, or `null` with none showing. Fires when either changes.
1322
1525
  */
1323
- | 'video-captions-changed' | 'video-fullscreen-changed' | 'video-pip-changed' | (string & {});
1526
+ | 'video-captions-changed' | 'video-fullscreen-changed' | 'video-pip-changed'
1527
+ /**
1528
+ * An AI hint was shown to the learner (`hintNumber`, and the port's
1529
+ * `provenance` when it sent one). Only a hint the SDK accepted: a refused one
1530
+ * is never shown and never reported here.
1531
+ */
1532
+ | 'ai-hint-shown'
1533
+ /** An AI explanation of the graded answer was shown (`provenance` when sent). */
1534
+ | 'ai-explanation-shown' | (string & {});
1324
1535
  /** Fired by activity components on every discrete learner interaction. */
1325
1536
  interface InteractionEvent {
1326
1537
  /** The kind of interaction that occurred. */
@@ -1333,4 +1544,4 @@ interface InteractionEvent {
1333
1544
  payload: Record<string, unknown>;
1334
1545
  }
1335
1546
 
1336
- export { type ValidationResult as $, type ActivityData as A, type BlankConfig as B, type CriterionScore as C, type DeferredReason as D, type MultipleChoiceData as E, type FillInTheBlanksData as F, type GapSelectBank as G, type MultipleChoiceLearnerResponse as H, type InlineCorrection as I, type MultipleChoiceOption as J, type MultipleChoiceOptionMedia as K, type LearnerResponse as L, type MediaPlaybackPolicy as M, type NativeControlHint as N, type ReadAloudDimension as O, type ReadAloudDimensionWeight as P, type ReadAloudLearnerResponse as Q, type ReadAloudData as R, type ReadAloudSlowMedia as S, type RecordingBounds as T, type RecordingRef as U, type ScoringDetail as V, type ScoringOutcome as W, type ScoringResult as X, type TextMatchPolicy as Y, type TextMatchResult as Z, type ValidationError as _, type ActivityDataMap as a, type WrittenResponseData as a0, type WrittenResponseLearnerResponse as a1, type WrittenResponseRubric as a2, type WrittenResponseRubricCriterion as a3, type XAPIActor as a4, type XAPIConfig as a5, type XAPIContext as a6, type XAPIContextActivities as a7, type XAPIError as a8, type XAPIObject as a9, type XAPIResult as aa, type XAPIScore as ab, type XAPIStatement as ac, type XAPIVerbObject as ad, levenshteinDistance as ae, matchText as af, type ActivityFeedback as b, type ActivityMedia as c, type ActivityResult as d, type ActivityType as e, type DeferredScoringPartial as f, type DictationData as g, type DictationEquivalence as h, type DictationLearnerResponse as i, type DictationSlowMedia as j, type DictationTolerance as k, type FillInTheBlanksLearnerResponse as l, type GapSelectChoice as m, type GapSelectData as n, type GapSelectGap as o, type GapSelectLearnerResponse as p, type GradeRecord as q, type Grader as r, type GraderKind as s, type GraderUsage as t, type GradingState as u, type InteractionEvent as v, type InteractionKind as w, type ItemOutcome as x, type LearnerResponseMap as y, type MediaTrack as z };
1547
+ export { type MediaPlaybackPolicy as $, type ActivityAiPermissions as A, type BlankConfig as B, type CriterionScore as C, type DeferredReason as D, type DictationData as E, type DictationEquivalence as F, type DictationLearnerResponse as G, type DictationSlowMedia as H, type DictationTolerance as I, type FillInTheBlanksData as J, type FillInTheBlanksLearnerResponse as K, type GapSelectBank as L, type GapSelectChoice as M, type GapSelectData as N, type GapSelectGap as O, type GapSelectLearnerResponse as P, type GradeRecord as Q, type Grader as R, type GraderKind as S, type GraderUsage as T, type GradingState as U, type InlineCorrection as V, type InteractionEvent as W, type InteractionKind as X, type ItemOutcome as Y, type LearnerResponse as Z, type LearnerResponseMap as _, type ActivityData as a, type MediaTrack as a0, type MultipleChoiceData as a1, type MultipleChoiceLearnerResponse as a2, type MultipleChoiceOption as a3, type MultipleChoiceOptionMedia as a4, type NativeControlHint as a5, type ReadAloudData as a6, type ReadAloudDimension as a7, type ReadAloudDimensionWeight as a8, type ReadAloudLearnerResponse as a9, type ReadAloudSlowMedia as aa, type RecordingBounds as ab, type RecordingRef as ac, type ScoringDetail as ad, type ScoringOutcome as ae, type ScoringResult as af, type TextMatchPolicy as ag, type TextMatchResult as ah, type ValidationError as ai, type ValidationResult as aj, type WrittenResponseData as ak, type WrittenResponseLearnerResponse as al, type WrittenResponseRubric as am, type WrittenResponseRubricCriterion as an, type XAPIActor as ao, type XAPIConfig as ap, type XAPIContext as aq, type XAPIContextActivities as ar, type XAPIError as as, type XAPIObject as at, type XAPIResult as au, type XAPIScore as av, type XAPIStatement as aw, type XAPIVerbObject as ax, levenshteinDistance as ay, matchText as az, type ActivityDataMap as b, type ActivityFeedback as c, type ActivityMedia as d, type ActivityResult as e, type ActivityType as f, type AiActivityInput as g, type AiBlankFact as h, type AiDictationFacts as i, type AiExplanationRequest as j, type AiFeature as k, type AiFillInTheBlanksFacts as l, type AiGapFact as m, type AiGapSelectFacts as n, type AiGrade as o, type AiHintRequest as p, type AiItemFacts as q, type AiMultipleChoiceFacts as r, type AiOptionFact as s, type AiProvenance as t, type AiRefusal as u, type AiSupportedActivityType as v, type AiTextResult as w, type AiVerdict as x, type AiWordFact as y, type DeferredScoringPartial as z };
@@ -63,6 +63,197 @@ declare function levenshteinDistance(a: string, b: string, max: number): number;
63
63
  */
64
64
  declare function matchText(input: string, accepted: string | readonly string[], policy?: TextMatchPolicy): TextMatchResult;
65
65
 
66
+ /**
67
+ * The contract between an activity and a model the HOST runs, for help a
68
+ * learner reads: an explanation of a graded answer, and hints before one.
69
+ *
70
+ * The SDK never calls a model and holds no key, prompt or provider. It builds
71
+ * the facts a model is given — from the item, the learner's answer and the
72
+ * SDK's own scorer — and checks what comes back. The model explains a verdict
73
+ * the SDK reached; it never reaches one.
74
+ */
75
+ /**
76
+ * What an author allows AI to do for one item. Absent, or a feature left out,
77
+ * leaves the choice to the deployment. `false` switches a feature off for this
78
+ * item wherever it is delivered; an author can only switch a feature off,
79
+ * never force one on.
80
+ *
81
+ * Switch hints off where any hint would give the answer away — a
82
+ * one-word vocabulary item, say.
83
+ */
84
+ interface ActivityAiPermissions {
85
+ /** An explanation of the learner's graded answer. */
86
+ explanations?: boolean;
87
+ /** Hints before the learner submits. */
88
+ hints?: boolean;
89
+ }
90
+ /**
91
+ * An activity as a renderer holds it: full data or a `redact()` projection.
92
+ * Structural rather than the data union, so a renderer's own view of an item —
93
+ * whose answer-key fields may be absent — is accepted as it is. The AI
94
+ * functions read every field defensively.
95
+ */
96
+ interface AiActivityInput {
97
+ readonly type: string;
98
+ readonly id: string;
99
+ readonly title: string;
100
+ readonly locale?: unknown;
101
+ readonly redacted?: unknown;
102
+ readonly ai?: unknown;
103
+ }
104
+ /** The two kinds of help a learner can be given. */
105
+ type AiFeature = 'explanation' | 'hint';
106
+ /** The activity types the SDK builds facts for. */
107
+ type AiSupportedActivityType = 'multiple-choice' | 'fill-in-the-blanks' | 'gap-select' | 'dictation';
108
+ /**
109
+ * A whole answer's grade, from the SDK's scorer. `category` is the verdict an
110
+ * explanation must agree with: all marks, some, or none.
111
+ */
112
+ interface AiGrade {
113
+ score: number;
114
+ maxScore: number;
115
+ passed: boolean;
116
+ category: AiVerdict;
117
+ }
118
+ /** The three verdicts an explanation can speak to. */
119
+ type AiVerdict = 'correct' | 'partly-correct' | 'incorrect';
120
+ interface AiFactsBase {
121
+ activityId: string;
122
+ title: string;
123
+ /** The language the item is written in, when the author gave one. */
124
+ locale?: string;
125
+ }
126
+ /** One option of a multiple-choice question, and what the learner did with it. */
127
+ interface AiOptionFact {
128
+ id: string;
129
+ text: string;
130
+ chosen: boolean;
131
+ /** Whether this option is part of the answer; `null` when the key is not available. */
132
+ correct: boolean | null;
133
+ /** The author's feedback on this option. */
134
+ feedback?: string;
135
+ }
136
+ interface AiMultipleChoiceFacts extends AiFactsBase {
137
+ activityType: 'multiple-choice';
138
+ question: string;
139
+ mode: 'single' | 'multi';
140
+ options: AiOptionFact[];
141
+ }
142
+ /** One blank, in the order it appears in the passage. */
143
+ interface AiBlankFact {
144
+ id: string;
145
+ /** 1-based, in passage order. */
146
+ position: number;
147
+ /** What the learner typed, or `''`. */
148
+ typed: string;
149
+ /** The answers that count; `null` when the key is not available. */
150
+ accepted: string[] | null;
151
+ /** The SDK's verdict on this blank; `null` before it is graded or without a key. */
152
+ correct: boolean | null;
153
+ /** The author's hint for this blank. */
154
+ hint?: string;
155
+ /** The author's feedback for this blank. */
156
+ feedback?: string;
157
+ }
158
+ interface AiFillInTheBlanksFacts extends AiFactsBase {
159
+ activityType: 'fill-in-the-blanks';
160
+ /** The passage, each blank written as `[1]`, `[2]`… in passage order. */
161
+ passage: string;
162
+ blanks: AiBlankFact[];
163
+ }
164
+ /** One gap, in the order it appears in the passage. */
165
+ interface AiGapFact {
166
+ id: string;
167
+ /** 1-based, in passage order. */
168
+ position: number;
169
+ /** The words offered at this gap. */
170
+ choices: string[];
171
+ /** The word the learner chose, or `null`. */
172
+ chosen: string | null;
173
+ /** The right word; `null` when the key is not available. */
174
+ answer: string | null;
175
+ /** The SDK's verdict on this gap; `null` before it is graded or without a key. */
176
+ correct: boolean | null;
177
+ /** The author's feedback for this gap. */
178
+ feedback?: string;
179
+ }
180
+ interface AiGapSelectFacts extends AiFactsBase {
181
+ activityType: 'gap-select';
182
+ /** The passage, each gap written as `[1]`, `[2]`… in passage order. */
183
+ passage: string;
184
+ gaps: AiGapFact[];
185
+ }
186
+ /** One word of a dictation, as the SDK's alignment paired it. */
187
+ interface AiWordFact {
188
+ /** The word the recording says; `''` for an extra word the learner added. */
189
+ expected: string;
190
+ /** The word the learner typed; `''` for a word they left out. */
191
+ typed: string;
192
+ status: 'correct' | 'incorrect' | 'missing' | 'extra';
193
+ }
194
+ interface AiDictationFacts extends AiFactsBase {
195
+ activityType: 'dictation';
196
+ /** What the recording says; `null` when the key is not available. */
197
+ transcript: string | null;
198
+ /** What the learner typed. */
199
+ typed: string;
200
+ /** The alignment word by word; `null` when the key is not available. */
201
+ words: AiWordFact[] | null;
202
+ }
203
+ /**
204
+ * What a model is told about one item and one answer: the question as the
205
+ * learner saw it, what they answered, and — part by part — the SDK's verdict.
206
+ */
207
+ type AiItemFacts = AiMultipleChoiceFacts | AiFillInTheBlanksFacts | AiGapSelectFacts | AiDictationFacts;
208
+ /**
209
+ * Asks for an explanation of a graded answer. Sent after the SDK has graded
210
+ * it, so `grade` is always present, and an explanation that contradicts
211
+ * `grade.category` is refused.
212
+ */
213
+ interface AiExplanationRequest {
214
+ feature: 'explanation';
215
+ facts: AiItemFacts;
216
+ grade: AiGrade;
217
+ /** The language to answer in: the learner's interface language, when known. */
218
+ learnerLocale?: string;
219
+ }
220
+ /**
221
+ * Asks for the next hint before the learner submits. `facts` carries the key
222
+ * so a model can hint toward the answer; the SDK refuses any hint that
223
+ * contains it.
224
+ */
225
+ interface AiHintRequest {
226
+ feature: 'hint';
227
+ facts: AiItemFacts;
228
+ /** 1-based: the hint being asked for. */
229
+ hintNumber: number;
230
+ /** The hints already shown for this item, oldest first. */
231
+ previousHints: string[];
232
+ learnerLocale?: string;
233
+ }
234
+ /** What produced an AI text, for the record a host keeps. */
235
+ interface AiProvenance {
236
+ /** The model's identifier, e.g. a name and version. */
237
+ model?: string;
238
+ /** A hash or id of the prompt revision. */
239
+ promptHash?: string;
240
+ /** ISO 8601. */
241
+ generatedAt?: string;
242
+ }
243
+ /**
244
+ * What a host's port returns. Plain text: the SDK renders it as text, never
245
+ * as HTML. An explanation may state the verdict it assumed; one that
246
+ * disagrees with the SDK's is refused.
247
+ */
248
+ interface AiTextResult {
249
+ text: string;
250
+ /** For an explanation: the verdict the model explained. */
251
+ verdict?: AiVerdict;
252
+ provenance?: AiProvenance;
253
+ }
254
+ /** Why a result was not shown. */
255
+ type AiRefusal = 'malformed' | 'empty' | 'too-long' | 'contradicts-grade' | 'reveals-answer';
256
+
66
257
  /**
67
258
  * The return trip for deferred grading.
68
259
  *
@@ -590,6 +781,8 @@ interface MultipleChoiceData {
590
781
  learningObjectives?: string[];
591
782
  /** Subjective difficulty on a 1–5 scale. */
592
783
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
784
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
785
+ ai?: ActivityAiPermissions;
593
786
  }
594
787
  /** Configuration for a single fill-in-the-blank slot. */
595
788
  interface BlankConfig {
@@ -724,6 +917,8 @@ interface GapSelectData {
724
917
  learningObjectives?: string[];
725
918
  /** Subjective difficulty on a 1–5 scale. */
726
919
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
920
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
921
+ ai?: ActivityAiPermissions;
727
922
  }
728
923
  interface FillInTheBlanksData {
729
924
  schemaVersion: '1.0';
@@ -756,6 +951,8 @@ interface FillInTheBlanksData {
756
951
  learningObjectives?: string[];
757
952
  /** Subjective difficulty on a 1–5 scale. */
758
953
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
954
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
955
+ ai?: ActivityAiPermissions;
759
956
  }
760
957
  /** A single criterion within a written-response grading rubric. */
761
958
  interface WrittenResponseRubricCriterion {
@@ -818,6 +1015,8 @@ interface WrittenResponseData {
818
1015
  learningObjectives?: string[];
819
1016
  /** Subjective difficulty on a 1–5 scale. */
820
1017
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
1018
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
1019
+ ai?: ActivityAiPermissions;
821
1020
  }
822
1021
  /**
823
1022
  * A second, slower recording of a dictation — a separate file (a text-to-speech
@@ -920,6 +1119,8 @@ interface DictationData {
920
1119
  learningObjectives?: string[];
921
1120
  /** Subjective difficulty on a 1–5 scale. */
922
1121
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
1122
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
1123
+ ai?: ActivityAiPermissions;
923
1124
  }
924
1125
  /** A dimension of speech a pronunciation assessor scores, on a 0–100 scale. */
925
1126
  type ReadAloudDimension = 'accuracy' | 'fluency' | 'completeness' | 'prosody';
@@ -1010,6 +1211,8 @@ interface ReadAloudData {
1010
1211
  learningObjectives?: string[];
1011
1212
  /** Subjective difficulty on a 1–5 scale. */
1012
1213
  difficultyLevel?: 1 | 2 | 3 | 4 | 5;
1214
+ /** What an author allows AI to do for this item: see {@link ActivityAiPermissions}. */
1215
+ ai?: ActivityAiPermissions;
1013
1216
  }
1014
1217
  /**
1015
1218
  * Maps each ActivityType string to its learner-response shape. Open for
@@ -1320,7 +1523,15 @@ type InteractionKind = 'option-selected' | 'option-deselected' | 'blank-filled'
1320
1523
  * primary line's language, or `null` with captions off; `payload.secondary` is
1321
1524
  * the second line's, or `null` with none showing. Fires when either changes.
1322
1525
  */
1323
- | 'video-captions-changed' | 'video-fullscreen-changed' | 'video-pip-changed' | (string & {});
1526
+ | 'video-captions-changed' | 'video-fullscreen-changed' | 'video-pip-changed'
1527
+ /**
1528
+ * An AI hint was shown to the learner (`hintNumber`, and the port's
1529
+ * `provenance` when it sent one). Only a hint the SDK accepted: a refused one
1530
+ * is never shown and never reported here.
1531
+ */
1532
+ | 'ai-hint-shown'
1533
+ /** An AI explanation of the graded answer was shown (`provenance` when sent). */
1534
+ | 'ai-explanation-shown' | (string & {});
1324
1535
  /** Fired by activity components on every discrete learner interaction. */
1325
1536
  interface InteractionEvent {
1326
1537
  /** The kind of interaction that occurred. */
@@ -1333,4 +1544,4 @@ interface InteractionEvent {
1333
1544
  payload: Record<string, unknown>;
1334
1545
  }
1335
1546
 
1336
- export { type ValidationResult as $, type ActivityData as A, type BlankConfig as B, type CriterionScore as C, type DeferredReason as D, type MultipleChoiceData as E, type FillInTheBlanksData as F, type GapSelectBank as G, type MultipleChoiceLearnerResponse as H, type InlineCorrection as I, type MultipleChoiceOption as J, type MultipleChoiceOptionMedia as K, type LearnerResponse as L, type MediaPlaybackPolicy as M, type NativeControlHint as N, type ReadAloudDimension as O, type ReadAloudDimensionWeight as P, type ReadAloudLearnerResponse as Q, type ReadAloudData as R, type ReadAloudSlowMedia as S, type RecordingBounds as T, type RecordingRef as U, type ScoringDetail as V, type ScoringOutcome as W, type ScoringResult as X, type TextMatchPolicy as Y, type TextMatchResult as Z, type ValidationError as _, type ActivityDataMap as a, type WrittenResponseData as a0, type WrittenResponseLearnerResponse as a1, type WrittenResponseRubric as a2, type WrittenResponseRubricCriterion as a3, type XAPIActor as a4, type XAPIConfig as a5, type XAPIContext as a6, type XAPIContextActivities as a7, type XAPIError as a8, type XAPIObject as a9, type XAPIResult as aa, type XAPIScore as ab, type XAPIStatement as ac, type XAPIVerbObject as ad, levenshteinDistance as ae, matchText as af, type ActivityFeedback as b, type ActivityMedia as c, type ActivityResult as d, type ActivityType as e, type DeferredScoringPartial as f, type DictationData as g, type DictationEquivalence as h, type DictationLearnerResponse as i, type DictationSlowMedia as j, type DictationTolerance as k, type FillInTheBlanksLearnerResponse as l, type GapSelectChoice as m, type GapSelectData as n, type GapSelectGap as o, type GapSelectLearnerResponse as p, type GradeRecord as q, type Grader as r, type GraderKind as s, type GraderUsage as t, type GradingState as u, type InteractionEvent as v, type InteractionKind as w, type ItemOutcome as x, type LearnerResponseMap as y, type MediaTrack as z };
1547
+ export { type MediaPlaybackPolicy as $, type ActivityAiPermissions as A, type BlankConfig as B, type CriterionScore as C, type DeferredReason as D, type DictationData as E, type DictationEquivalence as F, type DictationLearnerResponse as G, type DictationSlowMedia as H, type DictationTolerance as I, type FillInTheBlanksData as J, type FillInTheBlanksLearnerResponse as K, type GapSelectBank as L, type GapSelectChoice as M, type GapSelectData as N, type GapSelectGap as O, type GapSelectLearnerResponse as P, type GradeRecord as Q, type Grader as R, type GraderKind as S, type GraderUsage as T, type GradingState as U, type InlineCorrection as V, type InteractionEvent as W, type InteractionKind as X, type ItemOutcome as Y, type LearnerResponse as Z, type LearnerResponseMap as _, type ActivityData as a, type MediaTrack as a0, type MultipleChoiceData as a1, type MultipleChoiceLearnerResponse as a2, type MultipleChoiceOption as a3, type MultipleChoiceOptionMedia as a4, type NativeControlHint as a5, type ReadAloudData as a6, type ReadAloudDimension as a7, type ReadAloudDimensionWeight as a8, type ReadAloudLearnerResponse as a9, type ReadAloudSlowMedia as aa, type RecordingBounds as ab, type RecordingRef as ac, type ScoringDetail as ad, type ScoringOutcome as ae, type ScoringResult as af, type TextMatchPolicy as ag, type TextMatchResult as ah, type ValidationError as ai, type ValidationResult as aj, type WrittenResponseData as ak, type WrittenResponseLearnerResponse as al, type WrittenResponseRubric as am, type WrittenResponseRubricCriterion as an, type XAPIActor as ao, type XAPIConfig as ap, type XAPIContext as aq, type XAPIContextActivities as ar, type XAPIError as as, type XAPIObject as at, type XAPIResult as au, type XAPIScore as av, type XAPIStatement as aw, type XAPIVerbObject as ax, levenshteinDistance as ay, matchText as az, type ActivityDataMap as b, type ActivityFeedback as c, type ActivityMedia as d, type ActivityResult as e, type ActivityType as f, type AiActivityInput as g, type AiBlankFact as h, type AiDictationFacts as i, type AiExplanationRequest as j, type AiFeature as k, type AiFillInTheBlanksFacts as l, type AiGapFact as m, type AiGapSelectFacts as n, type AiGrade as o, type AiHintRequest as p, type AiItemFacts as q, type AiMultipleChoiceFacts as r, type AiOptionFact as s, type AiProvenance as t, type AiRefusal as u, type AiSupportedActivityType as v, type AiTextResult as w, type AiVerdict as x, type AiWordFact as y, type DeferredScoringPartial as z };