@intellectif/lk-core 1.1.0 → 1.3.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.
- package/CHANGELOG.md +30 -0
- package/README.md +4 -3
- package/dist/ai-B222dtHH.d.cts +2154 -0
- package/dist/ai-B222dtHH.d.cts.map +1 -0
- package/dist/ai-B222dtHH.d.ts +2154 -0
- package/dist/ai-B222dtHH.d.ts.map +1 -0
- package/dist/ai-check.cjs +758 -464
- package/dist/ai-check.cjs.map +1 -1
- package/dist/ai-check.d.cts +82 -68
- package/dist/ai-check.d.cts.map +1 -0
- package/dist/ai-check.d.ts +82 -68
- package/dist/ai-check.d.ts.map +1 -0
- package/dist/ai-check.js +756 -465
- package/dist/ai-check.js.map +1 -1
- package/dist/ai-writing-CCBjTOM3.js +2496 -0
- package/dist/ai-writing-CCBjTOM3.js.map +1 -0
- package/dist/ai-writing-DCVkv4Zj.cjs +2735 -0
- package/dist/ai-writing-DCVkv4Zj.cjs.map +1 -0
- package/dist/{index-DlcqkM_L.d.ts → index-BWPRPIXL.d.ts} +263 -258
- package/dist/index-BWPRPIXL.d.ts.map +1 -0
- package/dist/index-CXyOV8sm.d.cts +153 -0
- package/dist/index-CXyOV8sm.d.cts.map +1 -0
- package/dist/index-CegM8o15.d.ts +153 -0
- package/dist/index-CegM8o15.d.ts.map +1 -0
- package/dist/index-Dyu66R4-.d.cts +1071 -0
- package/dist/index-Dyu66R4-.d.cts.map +1 -0
- package/dist/{index-DlCW0XaQ.d.cts → index-O4_ExlAD.d.cts} +263 -258
- package/dist/index-O4_ExlAD.d.cts.map +1 -0
- package/dist/index-UGxRSopE.d.ts +1071 -0
- package/dist/index-UGxRSopE.d.ts.map +1 -0
- package/dist/index.cjs +1210 -1671
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1090 -853
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +1090 -853
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1063 -1672
- package/dist/index.js.map +1 -1
- package/dist/item-group-DXiR8nOr.js +445 -0
- package/dist/item-group-DXiR8nOr.js.map +1 -0
- package/dist/item-group-DroFXgLb.cjs +505 -0
- package/dist/item-group-DroFXgLb.cjs.map +1 -0
- package/dist/registry-DVi0LR_i.cjs +5915 -0
- package/dist/registry-DVi0LR_i.cjs.map +1 -0
- package/dist/registry-Dsx9mNsS.js +5449 -0
- package/dist/registry-Dsx9mNsS.js.map +1 -0
- package/dist/schemas-Bdw0nGPo.js +152 -0
- package/dist/schemas-Bdw0nGPo.js.map +1 -0
- package/dist/schemas-DVbAOrtd.cjs +224 -0
- package/dist/schemas-DVbAOrtd.cjs.map +1 -0
- package/dist/schemas.cjs +16 -32
- package/dist/schemas.d.cts +2 -2
- package/dist/schemas.d.ts +2 -2
- package/dist/schemas.js +3 -32
- package/dist/scoring-B2_HEhMT.cjs +1748 -0
- package/dist/scoring-B2_HEhMT.cjs.map +1 -0
- package/dist/scoring-BZqUkuDF.js +1604 -0
- package/dist/scoring-BZqUkuDF.js.map +1 -0
- package/dist/scoring.cjs +37 -75
- package/dist/scoring.d.cts +3 -1103
- package/dist/scoring.d.ts +3 -1103
- package/dist/scoring.js +3 -75
- package/dist/xapi-CMTph7wG.js +332 -0
- package/dist/xapi-CMTph7wG.js.map +1 -0
- package/dist/xapi-DNzkSJ0S.cjs +362 -0
- package/dist/xapi-DNzkSJ0S.cjs.map +1 -0
- package/dist/xapi.cjs +7 -16
- package/dist/xapi.d.cts +2 -150
- package/dist/xapi.d.ts +2 -150
- package/dist/xapi.js +2 -16
- package/package.json +4 -4
- package/dist/activity-MBOYLBjR.d.cts +0 -1840
- package/dist/activity-MBOYLBjR.d.ts +0 -1840
- package/dist/chunk-2JT2WUQ2.cjs +0 -458
- package/dist/chunk-2JT2WUQ2.cjs.map +0 -1
- package/dist/chunk-DSDXL3JO.cjs +0 -4597
- package/dist/chunk-DSDXL3JO.cjs.map +0 -1
- package/dist/chunk-FBKTION6.js +0 -4597
- package/dist/chunk-FBKTION6.js.map +0 -1
- package/dist/chunk-IARLJ5MW.js +0 -1256
- package/dist/chunk-IARLJ5MW.js.map +0 -1
- package/dist/chunk-LDFQUZII.cjs +0 -950
- package/dist/chunk-LDFQUZII.cjs.map +0 -1
- package/dist/chunk-NQHETFDA.js +0 -950
- package/dist/chunk-NQHETFDA.js.map +0 -1
- package/dist/chunk-SJVRUPJT.js +0 -272
- package/dist/chunk-SJVRUPJT.js.map +0 -1
- package/dist/chunk-TJJFKKH2.cjs +0 -272
- package/dist/chunk-TJJFKKH2.cjs.map +0 -1
- package/dist/chunk-VSH7ECQL.cjs +0 -1256
- package/dist/chunk-VSH7ECQL.cjs.map +0 -1
- package/dist/chunk-XS6U2ARZ.js +0 -458
- package/dist/chunk-XS6U2ARZ.js.map +0 -1
- package/dist/schemas.cjs.map +0 -1
- package/dist/schemas.js.map +0 -1
- package/dist/scoring.cjs.map +0 -1
- package/dist/scoring.js.map +0 -1
- package/dist/xapi.cjs.map +0 -1
- package/dist/xapi.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export { a as MediaTimeline, R as RedactedActivity, b as RedactedBlankConfig, c as RedactedDictationData, d as RedactedDictationSlowMedia, e as RedactedFillInTheBlanksData, f as RedactedGapSelectBank, g as RedactedGapSelectChoice, h as RedactedGapSelectData, i as RedactedGapSelectGap, j as RedactedMultipleChoiceData, k as RedactedMultipleChoiceOption, l as RedactedMultipleChoiceOptionMedia, m as RedactedReadAloudData, n as RedactedStimulus, o as RedactedWrittenResponseData, q as SequenceSlotGroup, r as Stimulus, s as StimulusKind, T as TimelineChapter, t as TimelineCue, u as dictationJsonSchema, v as fillInTheBlanksJsonSchema, w as gapSelectJsonSchema, x as itemGroupJsonSchema, y as jsonSchemaFor, z as multipleChoiceJsonSchema, A as readAloudJsonSchema, B as stimulusJsonSchema, C as validateActivity, D as validateItemGroup, E as validateMedia, F as validateOptionMedia, G as writtenResponseJsonSchema } from './index-DlCW0XaQ.cjs';
|
|
7
|
-
export { AnsweredStatementParams, CompletedStatementParams, SubmittedStatementParams, XAPIObjectParams, XAPIStatementParams, XAPIVerb, XAPIVerbKey, XAPI_VERB_DISPLAY, validateXAPIStatement, xAPIBuilder, xapiDefinitionFor } from './xapi.cjs';
|
|
8
|
-
|
|
1
|
+
import { $ as DraftComplete, $t as WrittenResponseLearnerResponse, A as AiGapSelectFacts, At as ItemOutcome, B as AiRefusal, Bt as ReadAloudData, C as AiDraftsCall, Ct as GapSelectBank, D as AiFeature, Dt as GapSelectLearnerResponse, E as AiExplanationRequest, Et as GapSelectGap, F as AiMultipleChoiceFacts, Ft as MultipleChoiceData, G as AiVerdict, Gt as RecordingBounds, H as AiSoundFact, Ht as ReadAloudDimensionWeight, I as AiOptionFact, It as MultipleChoiceLearnerResponse, J as AiWritingCorrection, Jt as ScoringOutcome, K as AiVideoDraft, Kt as RecordingRef, L as AiProvenance, Lt as MultipleChoiceOption, M as AiGrade, Mt as LearnerResponseMap, N as AiHintRequest, Nt as MediaPlaybackPolicy, O as AiFillInTheBlanksFacts, Ot as InteractionEvent, P as AiItemFacts, Pt as MediaTrack, Q as AiWritingFeedbackResult, Qt as WrittenResponseData, R as AiReadingFacts, Rt as MultipleChoiceOptionMedia, S as AiDrafts, Sn as matchText, St as FillInTheBlanksLearnerResponse, T as AiDraftsRun, Tt as GapSelectData, U as AiSupportedActivityType, Ut as ReadAloudLearnerResponse, V as AiRubricCriterionFact, Vt as ReadAloudDimension, W as AiTextResult, Wt as ReadAloudSlowMedia, X as AiWritingFeedback, Xt as ValidationError, Y as AiWritingFacts, Yt as ScoringResult, Z as AiWritingFeedbackRequest, Zt as ValidationResult, _ as AiDraftCaption, _n as GradingState, _t as DictationEquivalence, a as AiCoachingRequest, an as XAPIContextActivities, at as ItemFinding, b as AiDraftSource, bn as TextMatchResult, bt as DictationTolerance, c as AiCriterionJudgement, cn as XAPIResult, ct as ActivityDataMap, d as AiCritiqueFinding, dn as XAPIVerbObject, dt as ActivityResult, en as WrittenResponseRubric, et as DraftContext, f as AiCritiqueFindingResult, fn as CriterionScore, ft as ActivityType, g as AiDictationFacts, gn as GraderUsage, gt as DictationData, h as AiCritiqueResult, hn as GraderKind, ht as DeferredScoringPartial, i as AiCoaching, in as XAPIContext, it as DraftValidationResult, j as AiGeneratedDraft, jt as LearnerResponse, k as AiGapFact, kt as InteractionKind, l as AiCritique, ln as XAPIScore, lt as ActivityFeedback, m as AiCritiqueRequest, mn as Grader, mt as DeferredReason, n as AiActivityInput, nn as XAPIActor, nt as DraftNotComplete, o as AiCoachingResult, on as XAPIError, ot as ItemFindingSeverity, p as AiCritiqueKind, pn as GradeRecord, pt as BlankConfig, q as AiWordFact, qt as ScoringDetail, r as AiBlankFact, rn as XAPIConfig, rt as DraftSeverity, s as AiCoachingWord, sn as XAPIObject, st as ActivityData, t as ActivityAiPermissions, tn as WrittenResponseRubricCriterion, tt as DraftIssue, u as AiCritiqueField, un as XAPIStatement, ut as ActivityMedia, v as AiDraftProblem, vn as InlineCorrection, vt as DictationLearnerResponse, w as AiDraftsRequest, wt as GapSelectChoice, x as AiDraftType, xn as levenshteinDistance, xt as FillInTheBlanksData, y as AiDraftSettings, yn as TextMatchPolicy, yt as DictationSlowMedia, z as AiReadingWordFact, zt as NativeControlHint } from "./ai-B222dtHH.cjs";
|
|
2
|
+
import { $ as SpeechAssessment, A as diffDictationChars, B as ItemTry, C as validateItemScoringPolicy, D as DICTATION_MAX_TEXT_LENGTH, E as DICTATION_MAX_EQUIVALENCE_LENGTH, F as dictationReferenceWords, G as CompositionPolicy, H as ResolvedItemScoringPolicy, I as ItemScoringCount, J as SectionScore, K as PassFailureReason, L as ItemScoringPolicy, M as DictationReference, N as DictationWordAlignment, O as DICTATION_MAX_TRANSCRIPT_LENGTH, P as alignDictation, Q as ReadAloudWordState, R as ItemScoringPolicyIssue, S as scoreTries, T as DICTATION_MAX_EQUIVALENCES, U as AssessmentScore, V as ItemTryScore, W as AssessmentSectionInput, X as GradeReadAloudOptions, Y as composeAssessmentScore, Z as ReadAloudWordAlignment, _ as DEFAULT_PASS_THRESHOLD, a as evaluateTries, at as SpeechUnscorable, b as ITEM_SCORING_MAX_RETRIES, c as inspectWav, ct as SpeechWordError, d as READ_ALOUD_MAX_SECONDS, dt as Band, et as SpeechMeasurement, f as READ_ALOUD_MAX_TAKES, ft as RoundingMode, g as alignReadAloud, gt as roundGrade, h as validateSpeechAssessment, ht as gte, i as evaluate, it as SpeechSyllable, j as DictationAlignment, k as DictationCharOp, l as READ_ALOUD_MAX_DIMENSION_WEIGHT, lt as WavInspection, m as gradeReadAloud, mt as classifyBand, n as ItemTriesOutcome, nt as SpeechPhonemeCandidate, o as score, ot as SpeechUnscorableCode, p as SPEECH_ASSESSMENT_MAX_WORDS, pt as RoundingPolicy, q as ScoredItem, r as ScoringOptions, rt as SpeechPlausibilityPolicy, s as outcomeFromUnscorable, st as SpeechWord, t as EvaluateOptions, tt as SpeechPhoneme, u as READ_ALOUD_MAX_REFERENCE_LENGTH, ut as WavInspectionPolicy, v as computePassThreshold, w as DICTATION_MAX_ACCEPTED_TRANSCRIPTS, x as resolveItemScoringPolicy, y as DEFAULT_ITEM_SCORING_POLICY, z as ItemTriesScore } from "./index-Dyu66R4-.cjs";
|
|
3
|
+
import { A as MediaProgress, C as RedactedMultipleChoiceData, D as RedactedStimulus, E as RedactedReadAloudData, F as Stimulus, I as StimulusKind, L as TimelineChapter, M as SequenceEntry, N as SequenceSlot, O as RedactedWrittenResponseData, P as SequenceSlotGroup, R as TimelineCue, S as RedactedGapSelectGap, T as RedactedMultipleChoiceOptionMedia, _ as RedactedDictationSlowMedia, a as fillInTheBlanksJsonSchema, b as RedactedGapSelectChoice, c as jsonSchemaFor, d as stimulusJsonSchema, f as writtenResponseJsonSchema, g as RedactedDictationData, h as RedactedBlankConfig, i as dictationJsonSchema, j as MediaTimeline, k as ItemGroup, l as multipleChoiceJsonSchema, m as RedactedActivity, n as validateMedia, o as gapSelectJsonSchema, p as validateItemGroup, r as validateOptionMedia, s as itemGroupJsonSchema, t as validateActivity, u as readAloudJsonSchema, v as RedactedFillInTheBlanksData, w as RedactedMultipleChoiceOption, x as RedactedGapSelectData, y as RedactedGapSelectBank } from "./index-O4_ExlAD.cjs";
|
|
4
|
+
import { a as XAPIObjectParams, c as xapiDefinitionFor, d as XAPI_VERB_DISPLAY, i as SubmittedStatementParams, l as XAPIVerb, n as AnsweredStatementParams, o as XAPIStatementParams, r as CompletedStatementParams, s as xAPIBuilder, t as validateXAPIStatement, u as XAPIVerbKey } from "./index-CXyOV8sm.cjs";
|
|
5
|
+
//#region src/ai.d.ts
|
|
9
6
|
/**
|
|
10
7
|
* The activity types the SDK builds facts for, and which of them take hints.
|
|
11
8
|
* A dictation takes none: its answer is the whole sentence, and it has
|
|
12
9
|
* word-by-word hints of its own.
|
|
13
10
|
*/
|
|
14
|
-
declare const AI_EXPLANATION_TYPES: readonly AiSupportedActivityType[];
|
|
15
|
-
declare const AI_HINT_TYPES: readonly AiSupportedActivityType[];
|
|
11
|
+
export declare const AI_EXPLANATION_TYPES: readonly AiSupportedActivityType[];
|
|
12
|
+
export declare const AI_HINT_TYPES: readonly AiSupportedActivityType[];
|
|
16
13
|
/** The longest AI text shown, in code points. Longer is refused, not cut. */
|
|
17
|
-
declare const AI_TEXT_MAX_LENGTH = 2000;
|
|
14
|
+
export declare const AI_TEXT_MAX_LENGTH = 2000;
|
|
18
15
|
/**
|
|
19
16
|
* Whether the SDK supports `feature` for this activity type: explanations and
|
|
20
17
|
* hints for the types it builds facts for, and writing feedback for a written
|
|
21
18
|
* response, and coaching for a read-aloud. A consumer's own type has none.
|
|
22
19
|
*/
|
|
23
|
-
declare function aiSupports(activityType: string, feature: AiFeature): boolean;
|
|
20
|
+
export declare function aiSupports(activityType: string, feature: AiFeature): boolean;
|
|
24
21
|
/**
|
|
25
22
|
* Whether the item's author allows `feature`. Only an explicit `false`
|
|
26
23
|
* switches it off: an author can refuse a feature, never force one on.
|
|
@@ -29,12 +26,12 @@ declare function aiSupports(activityType: string, feature: AiFeature): boolean;
|
|
|
29
26
|
* model's words about the learner's own answer, and an author who switched one
|
|
30
27
|
* off has switched off the others.
|
|
31
28
|
*/
|
|
32
|
-
declare function aiAllowedByContent(data: AiActivityInput, feature: AiFeature): boolean;
|
|
29
|
+
export declare function aiAllowedByContent(data: AiActivityInput, feature: AiFeature): boolean;
|
|
33
30
|
/** A grade as an explanation must speak to it: all marks, some, or none. */
|
|
34
|
-
declare function aiGradeOf(result: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
export declare function aiGradeOf(result: {
|
|
32
|
+
score: number;
|
|
33
|
+
maxScore: number;
|
|
34
|
+
passed: boolean;
|
|
38
35
|
}): AiGrade;
|
|
39
36
|
/**
|
|
40
37
|
* The facts a model is given about one item and one answer. `details` are the
|
|
@@ -45,7 +42,7 @@ declare function aiGradeOf(result: {
|
|
|
45
42
|
*
|
|
46
43
|
* `null` for a type the SDK builds no facts for.
|
|
47
44
|
*/
|
|
48
|
-
declare function buildAiFacts(data: AiActivityInput, response: LearnerResponse | null, details: readonly ScoringDetail[] | null): AiItemFacts | null;
|
|
45
|
+
export declare function buildAiFacts(data: AiActivityInput, response: LearnerResponse | null, details: readonly ScoringDetail[] | null): AiItemFacts | null;
|
|
49
46
|
/**
|
|
50
47
|
* The request for an explanation of `response`, or `null` when there is none
|
|
51
48
|
* to give: an unsupported type, an author who switched explanations off,
|
|
@@ -58,11 +55,11 @@ declare function buildAiFacts(data: AiActivityInput, response: LearnerResponse |
|
|
|
58
55
|
* explaining 85 "out of 1" would tell the model a wrong answer was correct, and
|
|
59
56
|
* grading locally instead would speak to a grade the screen does not show.
|
|
60
57
|
*/
|
|
61
|
-
declare function aiExplanationRequest(input: {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
export declare function aiExplanationRequest(input: {
|
|
59
|
+
data: AiActivityInput;
|
|
60
|
+
response: LearnerResponse | null;
|
|
61
|
+
outcome?: ItemOutcome;
|
|
62
|
+
learnerLocale?: string;
|
|
66
63
|
}): AiExplanationRequest | null;
|
|
67
64
|
/**
|
|
68
65
|
* The request for the next hint on an unsubmitted answer, or `null` when
|
|
@@ -73,23 +70,23 @@ declare function aiExplanationRequest(input: {
|
|
|
73
70
|
* model can hint where it helps. The learner never sees them; a hint that
|
|
74
71
|
* contains an answer is refused by {@link checkAiHint}.
|
|
75
72
|
*/
|
|
76
|
-
declare function aiHintRequest(input: {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
73
|
+
export declare function aiHintRequest(input: {
|
|
74
|
+
data: AiActivityInput;
|
|
75
|
+
response: LearnerResponse | null;
|
|
76
|
+
previousHints: readonly string[];
|
|
77
|
+
learnerLocale?: string;
|
|
81
78
|
}): AiHintRequest | null;
|
|
82
79
|
/**
|
|
83
80
|
* Reads what a port returned. Anything but an object with a string `text` is
|
|
84
81
|
* `malformed`; text that is empty once cleaned, or longer than
|
|
85
82
|
* {@link AI_TEXT_MAX_LENGTH}, is refused rather than shown or cut.
|
|
86
83
|
*/
|
|
87
|
-
declare function readAiTextResult(raw: unknown): {
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
export declare function readAiTextResult(raw: unknown): {
|
|
85
|
+
ok: true;
|
|
86
|
+
result: AiTextResult;
|
|
90
87
|
} | {
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
ok: false;
|
|
89
|
+
refusal: AiRefusal;
|
|
93
90
|
};
|
|
94
91
|
/**
|
|
95
92
|
* Checks an explanation a port returned for `request`. On top of
|
|
@@ -97,24 +94,24 @@ declare function readAiTextResult(raw: unknown): {
|
|
|
97
94
|
* the SDK's grade is refused (`contradicts-grade`) — it explains an answer
|
|
98
95
|
* the learner did not get.
|
|
99
96
|
*/
|
|
100
|
-
declare function checkAiExplanation(raw: unknown, request: AiExplanationRequest): {
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
export declare function checkAiExplanation(raw: unknown, request: AiExplanationRequest): {
|
|
98
|
+
ok: true;
|
|
99
|
+
result: AiTextResult;
|
|
103
100
|
} | {
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
ok: false;
|
|
102
|
+
refusal: AiRefusal;
|
|
106
103
|
};
|
|
107
104
|
/**
|
|
108
105
|
* Checks a hint a port returned for `request`. On top of
|
|
109
106
|
* {@link readAiTextResult}: a hint that contains an answer is refused
|
|
110
107
|
* (`reveals-answer`) — see {@link hintRevealsAnswer}.
|
|
111
108
|
*/
|
|
112
|
-
declare function checkAiHint(raw: unknown, request: AiHintRequest): {
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
export declare function checkAiHint(raw: unknown, request: AiHintRequest): {
|
|
110
|
+
ok: true;
|
|
111
|
+
result: AiTextResult;
|
|
115
112
|
} | {
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
ok: false;
|
|
114
|
+
refusal: AiRefusal;
|
|
118
115
|
};
|
|
119
116
|
/**
|
|
120
117
|
* Whether a hint gives away an answer, judged against the facts it was asked
|
|
@@ -126,15 +123,18 @@ declare function checkAiHint(raw: unknown, request: AiHintRequest): {
|
|
|
126
123
|
* An answer of one short word ("is", "the") counts only where the hint
|
|
127
124
|
* writes it beside a neighbour it has in the passage — "name is", "is
|
|
128
125
|
* Rossi" — so a hint may still use the word on its own.
|
|
126
|
+
* - **Facts of any other kind:** revealing. A hint the check cannot read is
|
|
127
|
+
* withheld, not shown unchecked.
|
|
129
128
|
*
|
|
130
129
|
* Case, accents and punctuation are ignored on both sides.
|
|
131
130
|
*/
|
|
132
|
-
declare function hintRevealsAnswer(facts: AiItemFacts, hint: string): boolean;
|
|
133
|
-
|
|
131
|
+
export declare function hintRevealsAnswer(facts: AiItemFacts, hint: string): boolean;
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/ai-coaching.d.ts
|
|
134
134
|
/** The most words one coaching may work on. More is refused, not cut. */
|
|
135
|
-
declare const AI_COACHING_MAX_WORDS = 20;
|
|
135
|
+
export declare const AI_COACHING_MAX_WORDS = 20;
|
|
136
136
|
/** The longest tip for one word, in code points. */
|
|
137
|
-
declare const AI_COACHING_MAX_TIP_LENGTH = 500;
|
|
137
|
+
export declare const AI_COACHING_MAX_TIP_LENGTH = 500;
|
|
138
138
|
/**
|
|
139
139
|
* The request for coaching on a graded reading, or `null` when there is none
|
|
140
140
|
* to give: not a read-aloud, an author who switched explanations off (coaching
|
|
@@ -151,11 +151,11 @@ declare const AI_COACHING_MAX_TIP_LENGTH = 500;
|
|
|
151
151
|
* the engine's dimension scores. The marks are the engine's; the model
|
|
152
152
|
* explains them.
|
|
153
153
|
*/
|
|
154
|
-
declare function aiCoachingRequest(input: {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
154
|
+
export declare function aiCoachingRequest(input: {
|
|
155
|
+
data: AiActivityInput;
|
|
156
|
+
assessment?: SpeechAssessment | null;
|
|
157
|
+
grade?: GradeRecord | null;
|
|
158
|
+
learnerLocale?: string;
|
|
159
159
|
}): AiCoachingRequest | null;
|
|
160
160
|
/**
|
|
161
161
|
* Checks coaching a port returned for `request`, and turns it into what a
|
|
@@ -180,18 +180,207 @@ declare function aiCoachingRequest(input: {
|
|
|
180
180
|
* (the SDK's reading of the text, never the model's), and each sound spelt as
|
|
181
181
|
* the engine spelt it.
|
|
182
182
|
*/
|
|
183
|
-
declare function checkAiCoaching(raw: unknown, request: AiCoachingRequest): {
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
export declare function checkAiCoaching(raw: unknown, request: AiCoachingRequest): {
|
|
184
|
+
ok: true;
|
|
185
|
+
coaching: AiCoaching;
|
|
186
186
|
} | {
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
ok: false;
|
|
188
|
+
refusal: AiRefusal;
|
|
189
189
|
};
|
|
190
|
-
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/ai-critique.d.ts
|
|
192
|
+
/** The most findings one critique may carry. More is refused, not cut. */
|
|
193
|
+
export declare const AI_CRITIQUE_MAX_FINDINGS = 20;
|
|
194
|
+
/** The longest message or quote in a finding, in code points. */
|
|
195
|
+
export declare const AI_CRITIQUE_MAX_FIELD_LENGTH = 500;
|
|
196
|
+
/**
|
|
197
|
+
* What a model is given to review an item, or `null` when there is nothing to
|
|
198
|
+
* review: a draft that is not an object, or one with no words in it yet.
|
|
199
|
+
*
|
|
200
|
+
* The facts are the item as the author wrote it — the answer key included; this
|
|
201
|
+
* is for an author, never a learner — every text field a finding may point at,
|
|
202
|
+
* and what the SDK's own critic already found there, so a model spends its
|
|
203
|
+
* words on what a rule cannot see: a stem that reads two ways, a distractor
|
|
204
|
+
* that is defensibly right, a key that is wrong, language above the level.
|
|
205
|
+
*
|
|
206
|
+
* Works for every registered type, the SDK's own and yours: the fields are read
|
|
207
|
+
* from the draft itself.
|
|
208
|
+
*
|
|
209
|
+
* @throws UnknownActivityTypeError when `type` has no registered descriptor.
|
|
210
|
+
*/
|
|
211
|
+
export declare function aiCritiqueRequest(input: {
|
|
212
|
+
type: ActivityType;
|
|
213
|
+
draft: unknown;
|
|
214
|
+
level?: string;
|
|
215
|
+
authorLocale?: string;
|
|
216
|
+
}): AiCritiqueRequest | null;
|
|
217
|
+
/**
|
|
218
|
+
* Checks a critique a port returned for `request`, and turns it into findings
|
|
219
|
+
* an editor lists beside the SDK's own. As every AI answer, it is shown whole
|
|
220
|
+
* or not at all.
|
|
221
|
+
*
|
|
222
|
+
* - **Every finding points at a field the item has.** Its `path` is one of
|
|
223
|
+
* `facts.fields`, exactly; a path to a field the item does not have refuses
|
|
224
|
+
* the whole reply as `contradicts-item`.
|
|
225
|
+
* - **A quote is words that field contains**, typographic quotes and runs of
|
|
226
|
+
* spacing aside, case kept; one it does not refuses the reply the same way.
|
|
227
|
+
* - **Every finding is `advice`.** It is a model's opinion about the item, and
|
|
228
|
+
* nothing in the SDK acts on it; its code is `ai_` and the kind
|
|
229
|
+
* (`ai_second_answer`).
|
|
230
|
+
* - **Limits:** {@link AI_CRITIQUE_MAX_FINDINGS} findings; a message or quote of
|
|
231
|
+
* {@link AI_CRITIQUE_MAX_FIELD_LENGTH} code points; over them `too-long`. A
|
|
232
|
+
* kind the SDK does not name, or any other shape, is `malformed`.
|
|
233
|
+
*/
|
|
234
|
+
export declare function checkAiCritique(raw: unknown, request: AiCritiqueRequest): {
|
|
235
|
+
ok: true;
|
|
236
|
+
critique: AiCritique;
|
|
237
|
+
} | {
|
|
238
|
+
ok: false;
|
|
239
|
+
refusal: AiRefusal;
|
|
240
|
+
};
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/ai-drafts.d.ts
|
|
243
|
+
/** The most drafts one request may ask for, and the most a reply may hold when it names no count. */
|
|
244
|
+
export declare const AI_DRAFTS_MAX_COUNT = 50;
|
|
245
|
+
/** The most repair passes `generateDrafts` makes. */
|
|
246
|
+
export declare const AI_DRAFTS_MAX_REPAIRS = 3;
|
|
247
|
+
/**
|
|
248
|
+
* What a model is given to draft items from a source, or `null` when there is
|
|
249
|
+
* no source to draft from: an empty text, or no caption with words in it.
|
|
250
|
+
*
|
|
251
|
+
* `types` are the ones the author chose, in the author's order: the model
|
|
252
|
+
* leans on the first, and where several drafts share a moment of a video — or
|
|
253
|
+
* the end of one — they are shown in this order. `count` is how many to write
|
|
254
|
+
* at most; left out, the model writes as many as the source is worth, up to
|
|
255
|
+
* {@link AI_DRAFTS_MAX_COUNT}.
|
|
256
|
+
*
|
|
257
|
+
* The facts are the source — a caption list numbered, with its times in
|
|
258
|
+
* seconds — the types, the count, and the language, level and instructions
|
|
259
|
+
* the author gave. `shape` is the JSON Schema of the reply: each draft names
|
|
260
|
+
* its type and writes that type's own fields, with no ids, no HTML, no media
|
|
261
|
+
* and no settings. Those are not a model's to write. `settings` are yours, put
|
|
262
|
+
* on every draft of a type: a read-aloud's `recording` and `scoring`, say, which
|
|
263
|
+
* the SDK has no default for.
|
|
264
|
+
*
|
|
265
|
+
* @throws RangeError when `types` is empty, repeats a type or names one a model
|
|
266
|
+
* does not draft, or `count` is not a whole number from 1 to
|
|
267
|
+
* {@link AI_DRAFTS_MAX_COUNT}.
|
|
268
|
+
*/
|
|
269
|
+
export declare function aiDraftsRequest(input: {
|
|
270
|
+
types: readonly AiDraftType[];
|
|
271
|
+
source: AiDraftSource;
|
|
272
|
+
count?: number;
|
|
273
|
+
locale?: string;
|
|
274
|
+
level?: string;
|
|
275
|
+
instructions?: string;
|
|
276
|
+
settings?: AiDraftSettings;
|
|
277
|
+
}): AiDraftsRequest | null;
|
|
278
|
+
/**
|
|
279
|
+
* Reads a model's reply to {@link aiDraftsRequest} into drafts an editor can
|
|
280
|
+
* show for approval: each with ids from `newId`, your settings for its type,
|
|
281
|
+
* what `validateDraft` says of it, what the item critic finds in it, and — from
|
|
282
|
+
* captions — where it goes, and for a dictation the stretch of the video that
|
|
283
|
+
* says its words. They come back in the author's order of types.
|
|
284
|
+
*
|
|
285
|
+
* Drafts are independent: one that is unfinished or wrong is returned as such,
|
|
286
|
+
* for an author or {@link aiDraftsRepairRequest} to fix, beside the ones that
|
|
287
|
+
* are complete. `complete` means valid, never approved: a model wrote it, and a
|
|
288
|
+
* person decides whether learners see it. The whole reply is refused only when
|
|
289
|
+
* it is not `{ drafts: [...] }` of objects of the chosen types (`malformed`), or
|
|
290
|
+
* holds more drafts than asked for (`too-long`) — on a repair, not exactly one
|
|
291
|
+
* per draft to fix (`malformed`).
|
|
292
|
+
*
|
|
293
|
+
* Only the fields a type's shape names are read: a model cannot set an id,
|
|
294
|
+
* HTML, media, a switch or a scoring setting through this. A question is scored
|
|
295
|
+
* `all-or-nothing` unless your settings say otherwise, a written response's
|
|
296
|
+
* criteria are weighted equally, and a dictation carries no recording — attach
|
|
297
|
+
* one, or cut it from the video at `clip`.
|
|
298
|
+
*
|
|
299
|
+
* @throws Error when `newId` returns an empty or repeated id.
|
|
300
|
+
*/
|
|
301
|
+
export declare function checkAiDrafts(raw: unknown, request: AiDraftsRequest, options: {
|
|
302
|
+
newId: () => string;
|
|
303
|
+
}): {
|
|
304
|
+
ok: true;
|
|
305
|
+
drafts: AiDrafts;
|
|
306
|
+
} | {
|
|
307
|
+
ok: false;
|
|
308
|
+
refusal: AiRefusal;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* A second request, for the drafts with something wrong the model can fix —
|
|
312
|
+
* unfinished, wrong, or a flaw the critic warns about, at a field the model
|
|
313
|
+
* writes — each as the model wrote it, with those problems at the paths the
|
|
314
|
+
* model wrote. `null` when there is none.
|
|
315
|
+
*
|
|
316
|
+
* The reply holds one draft for each, in order; {@link checkAiDrafts} reads it
|
|
317
|
+
* and gives each the `index` of the draft it replaces.
|
|
318
|
+
*/
|
|
319
|
+
export declare function aiDraftsRepairRequest(request: AiDraftsRequest, drafts: AiDrafts | readonly AiGeneratedDraft[]): AiDraftsRequest | null;
|
|
320
|
+
/**
|
|
321
|
+
* Drafts items from a source, with a bounded repair loop: asks the port with
|
|
322
|
+
* `request`, reads the reply with {@link checkAiDrafts}, then — up to `repairs`
|
|
323
|
+
* times — sends back the drafts with something wrong the model can fix
|
|
324
|
+
* ({@link aiDraftsRepairRequest}), and keeps a repaired draft only when it is
|
|
325
|
+
* no worse than the one it replaces. A repaired draft keeps its id.
|
|
326
|
+
*
|
|
327
|
+
* Never throws for a model's failure: a port that throws or a reply the SDK
|
|
328
|
+
* refuses ends the loop, and is recorded in `calls` beside the provenance and
|
|
329
|
+
* usage of every call — which the SDK never adds up. A first call that fails
|
|
330
|
+
* leaves no drafts.
|
|
331
|
+
*
|
|
332
|
+
* ```ts
|
|
333
|
+
* const run = await generateDrafts({
|
|
334
|
+
* request: aiDraftsRequest({ types: ['multiple-choice', 'dictation'], source: { kind: 'transcript', text } }),
|
|
335
|
+
* port: (request) => callMyModel(DRAFTS_PROMPT, request),
|
|
336
|
+
* newId: () => crypto.randomUUID(),
|
|
337
|
+
* });
|
|
338
|
+
* // run.drafts: store each as proposed, for a person to approve.
|
|
339
|
+
* ```
|
|
340
|
+
*
|
|
341
|
+
* @throws RangeError when `repairs` is not a whole number from 0 to
|
|
342
|
+
* {@link AI_DRAFTS_MAX_REPAIRS} (default 1), and Error when `newId` returns an
|
|
343
|
+
* empty or repeated id.
|
|
344
|
+
*/
|
|
345
|
+
export declare function generateDrafts(input: {
|
|
346
|
+
request: AiDraftsRequest;
|
|
347
|
+
port: (request: AiDraftsRequest) => Promise<unknown> | unknown;
|
|
348
|
+
newId: () => string;
|
|
349
|
+
repairs?: number;
|
|
350
|
+
}): Promise<AiDraftsRun>;
|
|
351
|
+
/**
|
|
352
|
+
* An interactive video made of drafts: an item group whose stimulus is
|
|
353
|
+
* `video`, whose items are the drafts, and whose timeline opens a quiz at each
|
|
354
|
+
* moment a draft was placed — drafts placed at one moment share its quiz, in
|
|
355
|
+
* the author's order of types — and one more at `durationSeconds` for every
|
|
356
|
+
* draft placed nowhere: all of them when the source had no times.
|
|
357
|
+
*
|
|
358
|
+
* The SDK never reads the video, so it cannot know where the end is: without
|
|
359
|
+
* `durationSeconds` that last quiz has no time yet, which
|
|
360
|
+
* `validateItemGroupDraft` reports for the author to set. The source is kept on
|
|
361
|
+
* the stimulus as its author-only `transcript`.
|
|
362
|
+
*
|
|
363
|
+
* Like every draft it is checked (`validateItemGroupDraft`) and critiqued
|
|
364
|
+
* (`critiqueItemGroupDraft`), never approved. A dictation still needs its own
|
|
365
|
+
* recording; a type a video does not take — a written response — is reported,
|
|
366
|
+
* not dropped.
|
|
367
|
+
*
|
|
368
|
+
* @throws Error when `newId` returns an empty or repeated id.
|
|
369
|
+
*/
|
|
370
|
+
export declare function interactiveVideoFromDrafts(input: {
|
|
371
|
+
request: AiDraftsRequest;
|
|
372
|
+
drafts: AiDrafts | AiDraftsRun | readonly AiGeneratedDraft[];
|
|
373
|
+
video: ActivityMedia;
|
|
374
|
+
durationSeconds?: number;
|
|
375
|
+
title?: string;
|
|
376
|
+
newId: () => string;
|
|
377
|
+
}): AiVideoDraft;
|
|
378
|
+
//#endregion
|
|
379
|
+
//#region src/ai-writing.d.ts
|
|
191
380
|
/** The most corrections one piece of writing feedback may carry. More is refused, not cut. */
|
|
192
|
-
declare const AI_WRITING_MAX_CORRECTIONS = 20;
|
|
381
|
+
export declare const AI_WRITING_MAX_CORRECTIONS = 20;
|
|
193
382
|
/** The longest quote, correction, explanation or criterion comment, in code points. */
|
|
194
|
-
declare const AI_WRITING_MAX_FIELD_LENGTH = 500;
|
|
383
|
+
export declare const AI_WRITING_MAX_FIELD_LENGTH = 500;
|
|
195
384
|
/**
|
|
196
385
|
* The request for feedback on a draft, or `null` when there is none to give:
|
|
197
386
|
* not a written response, an author who switched explanations off (writing
|
|
@@ -203,11 +392,11 @@ declare const AI_WRITING_MAX_FIELD_LENGTH = 500;
|
|
|
203
392
|
* will be graded on. `previousFeedback` is the text of the feedback already
|
|
204
393
|
* shown on earlier drafts, so a model can speak to what changed.
|
|
205
394
|
*/
|
|
206
|
-
declare function aiWritingFeedbackRequest(input: {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
395
|
+
export declare function aiWritingFeedbackRequest(input: {
|
|
396
|
+
data: AiActivityInput;
|
|
397
|
+
response: LearnerResponse | null;
|
|
398
|
+
previousFeedback?: readonly string[];
|
|
399
|
+
learnerLocale?: string;
|
|
211
400
|
}): AiWritingFeedbackRequest | null;
|
|
212
401
|
/**
|
|
213
402
|
* Checks writing feedback a port returned for `request`, and turns it into what
|
|
@@ -233,14 +422,15 @@ declare function aiWritingFeedbackRequest(input: {
|
|
|
233
422
|
* `gradeFromRubric` computes a grade, when every criterion of the rubric was
|
|
234
423
|
* judged; `null` otherwise. An indication, never a grade.
|
|
235
424
|
*/
|
|
236
|
-
declare function checkAiWritingFeedback(raw: unknown, request: AiWritingFeedbackRequest): {
|
|
237
|
-
|
|
238
|
-
|
|
425
|
+
export declare function checkAiWritingFeedback(raw: unknown, request: AiWritingFeedbackRequest): {
|
|
426
|
+
ok: true;
|
|
427
|
+
feedback: AiWritingFeedback;
|
|
239
428
|
} | {
|
|
240
|
-
|
|
241
|
-
|
|
429
|
+
ok: false;
|
|
430
|
+
refusal: AiRefusal;
|
|
242
431
|
};
|
|
243
|
-
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/types/delivery.d.ts
|
|
244
434
|
/**
|
|
245
435
|
* How a paper is delivered: what a learner is shown around the questions, as
|
|
246
436
|
* the school running it decides — separately from the content, so that one
|
|
@@ -253,45 +443,45 @@ declare function checkAiWritingFeedback(raw: unknown, request: AiWritingFeedback
|
|
|
253
443
|
* because the client in an exam has no answer key to grade with.
|
|
254
444
|
*/
|
|
255
445
|
interface DeliveryPolicy {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
446
|
+
/**
|
|
447
|
+
* Whether a graded answer shows as graded: right and wrong marks, the score,
|
|
448
|
+
* and the author's feedback. `false` leaves the learner with "Answer
|
|
449
|
+
* submitted." — a homework quiz marked on the client and shown to the
|
|
450
|
+
* learner at the end, or a review that shows what was answered and not how
|
|
451
|
+
* it was marked. Never on in `exam`.
|
|
452
|
+
*/
|
|
453
|
+
feedback?: boolean | null;
|
|
454
|
+
/**
|
|
455
|
+
* Whether the right answer is shown beside a wrong one, wherever an activity
|
|
456
|
+
* would show it: the correct option of a multiple-choice question, the
|
|
457
|
+
* correct answers `showCorrectAnswers` puts in the blanks, a dictation's
|
|
458
|
+
* transcript. `false` still marks what the learner answered right or wrong.
|
|
459
|
+
* Use it on a paper that will be sat again, or before a retry.
|
|
460
|
+
*/
|
|
461
|
+
solutions?: boolean | null;
|
|
462
|
+
/**
|
|
463
|
+
* Whether the learner can ask for hints: the author's hints on a
|
|
464
|
+
* fill-in-the-blanks blank, a dictation's word hints, and AI hints. `false`
|
|
465
|
+
* switches every kind off.
|
|
466
|
+
*
|
|
467
|
+
* **The author's fill-in-the-blanks hints are on in `exam` unless this says
|
|
468
|
+
* otherwise** — they are public content, and were designed to be. Set
|
|
469
|
+
* `hints: false` on a paper of record whose hints are not part of the test.
|
|
470
|
+
*/
|
|
471
|
+
hints?: boolean | null;
|
|
472
|
+
/**
|
|
473
|
+
* The deployment's switches for AI help, beside the author's switch on the
|
|
474
|
+
* item and the ports the host supplies: a feature appears only where all
|
|
475
|
+
* three allow it. `false` switches a feature off; nothing here can switch one
|
|
476
|
+
* on, and nothing switches AI help on in an `exam`.
|
|
477
|
+
*
|
|
478
|
+
* `ai: false` switches both off and `ai: true` leaves both as the other
|
|
479
|
+
* settings allow — the same as leaving `ai` out.
|
|
480
|
+
*/
|
|
481
|
+
ai?: boolean | {
|
|
281
482
|
hints?: boolean | null;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
* item and the ports the host supplies: a feature appears only where all
|
|
285
|
-
* three allow it. `false` switches a feature off; nothing here can switch one
|
|
286
|
-
* on, and nothing switches AI help on in an `exam`.
|
|
287
|
-
*
|
|
288
|
-
* `ai: false` switches both off and `ai: true` leaves both as the other
|
|
289
|
-
* settings allow — the same as leaving `ai` out.
|
|
290
|
-
*/
|
|
291
|
-
ai?: boolean | {
|
|
292
|
-
hints?: boolean | null;
|
|
293
|
-
explanations?: boolean | null;
|
|
294
|
-
} | null;
|
|
483
|
+
explanations?: boolean | null;
|
|
484
|
+
} | null;
|
|
295
485
|
}
|
|
296
486
|
/**
|
|
297
487
|
* A policy with every setting spelled out: what {@link resolveDeliveryPolicy}
|
|
@@ -300,231 +490,220 @@ interface DeliveryPolicy {
|
|
|
300
490
|
* change.
|
|
301
491
|
*/
|
|
302
492
|
interface ResolvedDeliveryPolicy {
|
|
303
|
-
|
|
304
|
-
|
|
493
|
+
feedback: boolean;
|
|
494
|
+
solutions: boolean;
|
|
495
|
+
hints: boolean;
|
|
496
|
+
ai: {
|
|
305
497
|
hints: boolean;
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
explanations: boolean;
|
|
309
|
-
};
|
|
498
|
+
explanations: boolean;
|
|
499
|
+
};
|
|
310
500
|
}
|
|
311
501
|
/** One thing {@link validateDeliveryPolicy} found wrong with a policy. */
|
|
312
502
|
interface DeliveryPolicyIssue {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
503
|
+
/** Where, as a dotted path: `hints`, `ai.explanations`, or `''` for the policy itself. */
|
|
504
|
+
path: string;
|
|
505
|
+
message: string;
|
|
316
506
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
* The frozen record of what one attempt was served.
|
|
320
|
-
*
|
|
321
|
-
* A sequence definition is live content: it gets edited, re-ordered, corrected.
|
|
322
|
-
* An attempt is a historical fact. Everything that decides a grade — which
|
|
323
|
-
* questions, in what order, each worth how much, against which version of the
|
|
324
|
-
* content — has to be pinned at the moment the attempt starts, or a re-grade
|
|
325
|
-
* six months later silently answers a different question than the learner was
|
|
326
|
-
* asked.
|
|
327
|
-
*
|
|
328
|
-
* This is the thing you persist next to the responses.
|
|
329
|
-
*/
|
|
330
|
-
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/types/attempt-plan.d.ts
|
|
331
509
|
/** One planned position: an item, its identity, its worth, and its fingerprint. */
|
|
332
510
|
interface AttemptPlanSlot {
|
|
511
|
+
/**
|
|
512
|
+
* Slot identity, from `flattenSequence`. Stable under shuffling; stable
|
|
513
|
+
* under editing too when the entries declare `slotKey`. This is the key to
|
|
514
|
+
* store responses and scores against.
|
|
515
|
+
*/
|
|
516
|
+
slotId: string;
|
|
517
|
+
/** 0-based PRESENTED position in this attempt. */
|
|
518
|
+
index: number;
|
|
519
|
+
/** The activity that filled the slot. */
|
|
520
|
+
activityId: string;
|
|
521
|
+
/** The activity's `type` discriminator. */
|
|
522
|
+
activityType: string;
|
|
523
|
+
/**
|
|
524
|
+
* What this slot is worth, frozen. Points belong to the PAPER, not the item:
|
|
525
|
+
* the same question can be worth 1 in a quiz and 3 in a final, so they are
|
|
526
|
+
* resolved when the attempt is planned and never read from content again.
|
|
527
|
+
*/
|
|
528
|
+
points: number;
|
|
529
|
+
/**
|
|
530
|
+
* Fingerprint of the activity's content as served. Compare it later with
|
|
531
|
+
* {@link verifyAttemptPlan} to find out whether the item has been edited
|
|
532
|
+
* since — the difference between "re-grading this attempt" and "grading a
|
|
533
|
+
* different exam".
|
|
534
|
+
*/
|
|
535
|
+
contentHash: string;
|
|
536
|
+
/** Present when the slot came from an item group. */
|
|
537
|
+
group?: {
|
|
538
|
+
id: string;
|
|
539
|
+
title?: string;
|
|
540
|
+
/** Fingerprint of the stimulus as served — a corrected passage changes the question. */
|
|
541
|
+
stimulusHash: string;
|
|
333
542
|
/**
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
|
|
338
|
-
slotId: string;
|
|
339
|
-
/** 0-based PRESENTED position in this attempt. */
|
|
340
|
-
index: number;
|
|
341
|
-
/** The activity that filled the slot. */
|
|
342
|
-
activityId: string;
|
|
343
|
-
/** The activity's `type` discriminator. */
|
|
344
|
-
activityType: string;
|
|
345
|
-
/**
|
|
346
|
-
* What this slot is worth, frozen. Points belong to the PAPER, not the item:
|
|
347
|
-
* the same question can be worth 1 in a quiz and 3 in a final, so they are
|
|
348
|
-
* resolved when the attempt is planned and never read from content again.
|
|
349
|
-
*/
|
|
350
|
-
points: number;
|
|
351
|
-
/**
|
|
352
|
-
* Fingerprint of the activity's content as served. Compare it later with
|
|
353
|
-
* {@link verifyAttemptPlan} to find out whether the item has been edited
|
|
354
|
-
* since — the difference between "re-grading this attempt" and "grading a
|
|
355
|
-
* different exam".
|
|
543
|
+
* The quiz this slot's question sat in, when the group is an interactive
|
|
544
|
+
* video. Frozen because WHEN a question is asked is part of what is asked:
|
|
545
|
+
* moved from before the passage it is about to after it, the same item is
|
|
546
|
+
* a different question.
|
|
356
547
|
*/
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
title?: string;
|
|
362
|
-
/** Fingerprint of the stimulus as served — a corrected passage changes the question. */
|
|
363
|
-
stimulusHash: string;
|
|
364
|
-
/**
|
|
365
|
-
* The quiz this slot's question sat in, when the group is an interactive
|
|
366
|
-
* video. Frozen because WHEN a question is asked is part of what is asked:
|
|
367
|
-
* moved from before the passage it is about to after it, the same item is
|
|
368
|
-
* a different question.
|
|
369
|
-
*/
|
|
370
|
-
cue?: {
|
|
371
|
-
id: string;
|
|
372
|
-
at: number;
|
|
373
|
-
required?: boolean;
|
|
374
|
-
};
|
|
548
|
+
cue?: {
|
|
549
|
+
id: string;
|
|
550
|
+
at: number;
|
|
551
|
+
required?: boolean;
|
|
375
552
|
};
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
553
|
+
};
|
|
554
|
+
/**
|
|
555
|
+
* Play budgets in force for this slot when the attempt was planned.
|
|
556
|
+
*
|
|
557
|
+
* Frozen for the same reason `points` is: a budget decides the grade, so an
|
|
558
|
+
* author who edits `maxPlays: 2 → 4` mid-window must not be able to change
|
|
559
|
+
* what a past learner was held to. A group's stimulus budget repeats on every
|
|
560
|
+
* slot of the group, exactly as `group.stimulusHash` already does.
|
|
561
|
+
*
|
|
562
|
+
* Absent when the slot budgets nothing, which keeps the plan — and therefore
|
|
563
|
+
* `planHash` — byte-identical for every paper written before 0.8.0.
|
|
564
|
+
*/
|
|
565
|
+
mediaBudgets?: MediaBudgetRef[];
|
|
388
566
|
}
|
|
389
567
|
/** A budgeted recording a slot presents, frozen as served. */
|
|
390
568
|
interface MediaBudgetRef {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
569
|
+
/** `slot:<slotId>` or `stimulus:<entryKey>`. */
|
|
570
|
+
key: string;
|
|
571
|
+
/** The `maxPlays` in force when the attempt was planned. */
|
|
572
|
+
maxPlays: number;
|
|
395
573
|
}
|
|
396
574
|
/** Everything needed to reproduce and re-grade one attempt. */
|
|
397
575
|
interface AttemptPlan {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
576
|
+
/** Version of this envelope, so a stored plan stays readable as it evolves. */
|
|
577
|
+
planVersion: '1.0';
|
|
578
|
+
/**
|
|
579
|
+
* The seed every shuffle in this attempt used, when anything shuffled.
|
|
580
|
+
* Absent means nothing was shuffled and the order is the authored one.
|
|
581
|
+
*/
|
|
582
|
+
seed?: string;
|
|
583
|
+
/**
|
|
584
|
+
* Whether the top-level entries were shuffled. Recorded because
|
|
585
|
+
* {@link verifyAttemptPlan} needs to rebuild the SAME presented order: a
|
|
586
|
+
* re-plan that omitted this returned authored order, every slot compared as
|
|
587
|
+
* re-ordered, and unchanged content reported as drift.
|
|
588
|
+
*/
|
|
589
|
+
shuffleEntries?: boolean;
|
|
590
|
+
/**
|
|
591
|
+
* Fingerprint of the whole plan's content — every slot's identity, order,
|
|
592
|
+
* points and content hash. One value to store against an attempt and compare
|
|
593
|
+
* later; the per-slot hashes then say WHICH item moved.
|
|
594
|
+
*/
|
|
595
|
+
planHash: string;
|
|
596
|
+
/**
|
|
597
|
+
* The delivery policy the attempt was sat under, every setting spelled out:
|
|
598
|
+
* whether feedback, solutions and hints showed, and which AI help was on.
|
|
599
|
+
* Absent when `planAttempt` was given none. Part of `planHash` when present.
|
|
600
|
+
*/
|
|
601
|
+
delivery?: ResolvedDeliveryPolicy;
|
|
602
|
+
/**
|
|
603
|
+
* The scoring policy the attempt was sat under, every setting spelled out:
|
|
604
|
+
* the tries each question gave, which counted, and what tries and hints
|
|
605
|
+
* cost. Absent when `planAttempt` was given none. Part of `planHash` when
|
|
606
|
+
* present.
|
|
607
|
+
*/
|
|
608
|
+
scoring?: ResolvedItemScoringPolicy;
|
|
609
|
+
slots: AttemptPlanSlot[];
|
|
610
|
+
/** Sum of every slot's `points`, frozen. The denominator of the paper. */
|
|
611
|
+
totalPoints: number;
|
|
434
612
|
}
|
|
435
613
|
/** What {@link verifyAttemptPlan} found when a plan met current content. */
|
|
436
614
|
interface AttemptPlanDrift {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
615
|
+
/** True when the plan and the content still agree in every respect. */
|
|
616
|
+
matches: boolean;
|
|
617
|
+
/** Slots in the plan that no longer exist in the content at all. */
|
|
618
|
+
missingSlotIds: string[];
|
|
619
|
+
/** Slots present now that the plan never held — content added since. */
|
|
620
|
+
addedSlotIds: string[];
|
|
621
|
+
/** Slots whose activity content has been edited since the attempt. */
|
|
622
|
+
changedSlotIds: string[];
|
|
623
|
+
/** Slots whose item group's stimulus has been edited since the attempt. */
|
|
624
|
+
changedStimulusSlotIds: string[];
|
|
625
|
+
/**
|
|
626
|
+
* Slots of an interactive video whose question now sits in a different quiz,
|
|
627
|
+
* at a different moment, or under a different `required` — or that gained or
|
|
628
|
+
* lost a quiz altogether. Always empty for content without a timeline.
|
|
629
|
+
*/
|
|
630
|
+
changedCueSlotIds: string[];
|
|
631
|
+
/**
|
|
632
|
+
* Slots now worth a different number of points. A reweight is a paper
|
|
633
|
+
* change — it moves the grade without touching a single question — so it
|
|
634
|
+
* cannot be left out of a remark or an appeal.
|
|
635
|
+
*/
|
|
636
|
+
changedPointsSlotIds: string[];
|
|
637
|
+
/** Slots presented at a different position now than they were then. */
|
|
638
|
+
reorderedSlotIds: string[];
|
|
639
|
+
/**
|
|
640
|
+
* The delivery policy differs: one plan records a policy the other does not,
|
|
641
|
+
* or a setting differs. Not a change to any question, but a change to the
|
|
642
|
+
* conditions it was asked under — hints on in one, off in the other — so it
|
|
643
|
+
* breaks `matches` like any other difference.
|
|
644
|
+
*
|
|
645
|
+
* Present only when it is `true`, so a report between two plans without a
|
|
646
|
+
* policy has exactly the shape it had before policies existed.
|
|
647
|
+
*/
|
|
648
|
+
deliveryChanged?: true;
|
|
649
|
+
/**
|
|
650
|
+
* The scoring policy differs: one plan records a policy the other does not,
|
|
651
|
+
* or a setting differs. The same answers are worth something else under
|
|
652
|
+
* another policy, so it breaks `matches`. Present only when it is `true`.
|
|
653
|
+
*/
|
|
654
|
+
scoringChanged?: true;
|
|
477
655
|
}
|
|
478
|
-
|
|
656
|
+
//#endregion
|
|
657
|
+
//#region src/attempt-plan.d.ts
|
|
479
658
|
/** Options for {@link planAttempt}. */
|
|
480
|
-
interface PlanAttemptOptions<TItem> {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
659
|
+
export interface PlanAttemptOptions<TItem> {
|
|
660
|
+
/** Shuffle the top-level entries. A group moves as one block. */
|
|
661
|
+
shuffleEntries?: boolean;
|
|
662
|
+
/**
|
|
663
|
+
* Seed for every shuffle in this attempt. Required whenever anything
|
|
664
|
+
* shuffles — the attempt has to be reproducible, which is the entire point
|
|
665
|
+
* of writing a plan down. Use the attempt id.
|
|
666
|
+
*/
|
|
667
|
+
seed?: string;
|
|
668
|
+
/**
|
|
669
|
+
* What each slot is worth. Defaults to 1 for every slot.
|
|
670
|
+
*
|
|
671
|
+
* Points are resolved HERE, not read from content, because they belong to
|
|
672
|
+
* the paper rather than the item: the same question is worth 1 in a practice
|
|
673
|
+
* quiz and 3 in a final. Whatever this returns is frozen into the plan and
|
|
674
|
+
* is what `composeAssessmentScore` will weight by.
|
|
675
|
+
*
|
|
676
|
+
* @throws Error when it returns a value that is not a finite, non-negative
|
|
677
|
+
* number — a slot worth `NaN` points would poison the whole total.
|
|
678
|
+
*/
|
|
679
|
+
points?: (slot: SequenceSlot<TItem>) => number;
|
|
680
|
+
/**
|
|
681
|
+
* The delivery policy this attempt is sat under — whether hints were
|
|
682
|
+
* offered, whether AI help was, whether feedback and solutions showed.
|
|
683
|
+
* Frozen into the plan with every setting spelled out, so the record of the
|
|
684
|
+
* conditions a grade was earned under does not depend on today's defaults.
|
|
685
|
+
*
|
|
686
|
+
* Recorded only when given: a plan made without one is byte-identical to a
|
|
687
|
+
* plan made before policies existed, `planHash` included.
|
|
688
|
+
*
|
|
689
|
+
* @throws Error when the policy does not pass `validateDeliveryPolicy` —
|
|
690
|
+
* a misspelled restriction is no restriction, and a plan is the
|
|
691
|
+
* record an appeal reads.
|
|
692
|
+
*/
|
|
693
|
+
delivery?: DeliveryPolicy | null;
|
|
694
|
+
/**
|
|
695
|
+
* The scoring policy this attempt is sat under — how many tries each
|
|
696
|
+
* question gives, which one counts, and what tries and hints cost. Frozen
|
|
697
|
+
* into the plan with every setting spelled out, like `delivery`, and for a
|
|
698
|
+
* stronger reason: every setting in it moves a grade, so a re-grade must
|
|
699
|
+
* apply the rules the learner sat under, not today's.
|
|
700
|
+
*
|
|
701
|
+
* Recorded only when given: a plan made without one is byte-identical to a
|
|
702
|
+
* plan made before scoring policies existed, `planHash` included.
|
|
703
|
+
*
|
|
704
|
+
* @throws Error when the policy does not pass `validateItemScoringPolicy`.
|
|
705
|
+
*/
|
|
706
|
+
scoring?: ItemScoringPolicy | null;
|
|
528
707
|
}
|
|
529
708
|
/**
|
|
530
709
|
* Freezes what an attempt is being served: the presented order, each slot's
|
|
@@ -542,9 +721,9 @@ interface PlanAttemptOptions<TItem> {
|
|
|
542
721
|
* empty, when two entries collide on a `slotKey`, or when `points`
|
|
543
722
|
* returns a value that is not finite and non-negative.
|
|
544
723
|
*/
|
|
545
|
-
declare function planAttempt<TItem extends {
|
|
546
|
-
|
|
547
|
-
|
|
724
|
+
export declare function planAttempt<TItem extends {
|
|
725
|
+
id: string;
|
|
726
|
+
type: string;
|
|
548
727
|
}>(entries: readonly SequenceEntry<TItem>[], options?: PlanAttemptOptions<TItem>): AttemptPlan;
|
|
549
728
|
/**
|
|
550
729
|
* Compares a stored plan with the content as it stands now, and reports every
|
|
@@ -570,23 +749,23 @@ declare function planAttempt<TItem extends {
|
|
|
570
749
|
* A drift is not automatically a problem — a fixed typo changes a hash without
|
|
571
750
|
* changing what was asked. It is a fact somebody has to be able to see.
|
|
572
751
|
*/
|
|
573
|
-
declare function verifyAttemptPlan(plan: AttemptPlan, current: AttemptPlan): AttemptPlanDrift;
|
|
752
|
+
export declare function verifyAttemptPlan(plan: AttemptPlan, current: AttemptPlan): AttemptPlanDrift;
|
|
574
753
|
/** How {@link scoredItemsFromPlan} fills a slot that has no recorded outcome. */
|
|
575
|
-
type MissingOutcomePolicy =
|
|
754
|
+
export type MissingOutcomePolicy =
|
|
576
755
|
/**
|
|
577
756
|
* Default. `{ status: 'deferred', reason: 'no_response_recorded' }` — a
|
|
578
757
|
* non-terminal state, so the composed result stays `provisional` and cannot
|
|
579
758
|
* be recorded as a final pass or fail.
|
|
580
759
|
*/
|
|
581
|
-
'deferred'
|
|
760
|
+
'deferred' |
|
|
582
761
|
/**
|
|
583
762
|
* `{ status: 'scored', score: 0 }` — the learner left it blank on a paper
|
|
584
763
|
* that IS complete. Choose this only when you know the attempt was
|
|
585
764
|
* submitted; it is a real zero and makes the result final.
|
|
586
765
|
*/
|
|
587
|
-
|
|
766
|
+
'zero' |
|
|
588
767
|
/** Build the outcome yourself, per slot. */
|
|
589
|
-
|
|
768
|
+
((slot: AttemptPlanSlot) => ItemOutcome);
|
|
590
769
|
/**
|
|
591
770
|
* Turns a plan plus whatever outcomes exist into the `ScoredItem[]`
|
|
592
771
|
* `composeAssessmentScore` consumes.
|
|
@@ -607,12 +786,13 @@ type MissingOutcomePolicy =
|
|
|
607
786
|
* Pass outcomes keyed by `slotId`. Keys the plan does not know are ignored:
|
|
608
787
|
* a plan is the authority on what the attempt contained.
|
|
609
788
|
*/
|
|
610
|
-
declare function scoredItemsFromPlan(plan: AttemptPlan, outcomes: Readonly<Record<string, ItemOutcome>>, options?: {
|
|
611
|
-
|
|
789
|
+
export declare function scoredItemsFromPlan(plan: AttemptPlan, outcomes: Readonly<Record<string, ItemOutcome>>, options?: {
|
|
790
|
+
missing?: MissingOutcomePolicy;
|
|
612
791
|
}): ScoredItem[];
|
|
613
792
|
/** Convenience alias: the entry type a plan is built from. */
|
|
614
|
-
type PlannableEntry = SequenceEntry<ActivityData>;
|
|
615
|
-
|
|
793
|
+
export type PlannableEntry = SequenceEntry<ActivityData>;
|
|
794
|
+
//#endregion
|
|
795
|
+
//#region src/types/attempt-state.d.ts
|
|
616
796
|
/**
|
|
617
797
|
* A resumable snapshot of an attempt in progress.
|
|
618
798
|
*
|
|
@@ -626,46 +806,47 @@ type PlannableEntry = SequenceEntry<ActivityData>;
|
|
|
626
806
|
* slot ids alone would happily line up against the wrong questions.
|
|
627
807
|
*/
|
|
628
808
|
interface AttemptState {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
809
|
+
/** Version of this envelope, so a stored snapshot stays readable as it evolves. */
|
|
810
|
+
stateVersion: '1.0';
|
|
811
|
+
/**
|
|
812
|
+
* `planHash` of the {@link AttemptPlan} this state belongs to. `restoreAttemptState`
|
|
813
|
+
* refuses a plan that does not match, rather than restoring a learner's
|
|
814
|
+
* answers onto a paper they never sat.
|
|
815
|
+
*/
|
|
816
|
+
planHash: string;
|
|
817
|
+
/** The learner's answers so far, keyed by `slotId`. */
|
|
818
|
+
responses: Record<string, LearnerResponse>;
|
|
819
|
+
/**
|
|
820
|
+
* Slots the learner has already submitted. Kept apart from `responses`
|
|
821
|
+
* because they answer different questions: what did they write, and may they
|
|
822
|
+
* still change it.
|
|
823
|
+
*/
|
|
824
|
+
submittedSlotIds: string[];
|
|
825
|
+
/** Presented position the learner was on, so a resume reopens there. */
|
|
826
|
+
index: number;
|
|
827
|
+
/** ISO 8601 timestamp of the snapshot, when the caller supplies one. */
|
|
828
|
+
savedAt?: string;
|
|
649
829
|
}
|
|
650
830
|
/** One slot whose response differs between two snapshots. */
|
|
651
831
|
interface ResponseDiffEntry {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
832
|
+
slotId: string;
|
|
833
|
+
/** `added` — answered since; `removed` — cleared; `changed` — a different answer. */
|
|
834
|
+
change: 'added' | 'removed' | 'changed';
|
|
835
|
+
before?: LearnerResponse;
|
|
836
|
+
after?: LearnerResponse;
|
|
657
837
|
}
|
|
658
|
-
|
|
838
|
+
//#endregion
|
|
839
|
+
//#region src/attempt-state.d.ts
|
|
659
840
|
/** What {@link serializeAttemptState} is given about an attempt in progress. */
|
|
660
|
-
interface AttemptProgress {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
841
|
+
export interface AttemptProgress {
|
|
842
|
+
/** Answers so far, keyed by `slotId`. */
|
|
843
|
+
responses: Readonly<Record<string, LearnerResponse>>;
|
|
844
|
+
/** Slots already submitted. Defaults to none. */
|
|
845
|
+
submittedSlotIds?: readonly string[];
|
|
846
|
+
/** Presented position the learner is on. Defaults to 0. */
|
|
847
|
+
index?: number;
|
|
848
|
+
/** ISO 8601 timestamp to stamp the snapshot with. The SDK does not read a clock. */
|
|
849
|
+
savedAt?: string;
|
|
669
850
|
}
|
|
670
851
|
/**
|
|
671
852
|
* Captures an in-progress attempt as a storable snapshot, bound to its plan.
|
|
@@ -681,7 +862,7 @@ interface AttemptProgress {
|
|
|
681
862
|
* @throws Error when a response or submitted slot is not in the plan, or when
|
|
682
863
|
* `index` is not a position the plan actually has.
|
|
683
864
|
*/
|
|
684
|
-
declare function serializeAttemptState(plan: AttemptPlan, progress: AttemptProgress): AttemptState;
|
|
865
|
+
export declare function serializeAttemptState(plan: AttemptPlan, progress: AttemptProgress): AttemptState;
|
|
685
866
|
/**
|
|
686
867
|
* Reopens a stored snapshot against a plan, refusing anything that does not
|
|
687
868
|
* belong to it.
|
|
@@ -695,7 +876,7 @@ declare function serializeAttemptState(plan: AttemptPlan, progress: AttemptProgr
|
|
|
695
876
|
* @throws Error when the snapshot belongs to a different plan, or references
|
|
696
877
|
* slots the plan does not contain.
|
|
697
878
|
*/
|
|
698
|
-
declare function restoreAttemptState(plan: AttemptPlan, state: AttemptState): AttemptState;
|
|
879
|
+
export declare function restoreAttemptState(plan: AttemptPlan, state: AttemptState): AttemptState;
|
|
699
880
|
/**
|
|
700
881
|
* Reports how two snapshots' responses differ, slot by slot.
|
|
701
882
|
*
|
|
@@ -707,63 +888,9 @@ declare function restoreAttemptState(plan: AttemptPlan, state: AttemptState): At
|
|
|
707
888
|
* Entries come back sorted by `slotId`, so the output is stable regardless of
|
|
708
889
|
* the order the two objects happened to be written in.
|
|
709
890
|
*/
|
|
710
|
-
declare function diffResponses(before: Pick<AttemptState, 'responses'>, after: Pick<AttemptState, 'responses'>): ResponseDiffEntry[];
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
* Why a draft is not an activity yet.
|
|
714
|
-
*
|
|
715
|
-
* - `incomplete` — something the author has not written yet: an empty title, an
|
|
716
|
-
* option with no text, no option marked correct. The fix is to add it.
|
|
717
|
-
* - `invalid` — something is wrong in a way that writing more cannot fix: two
|
|
718
|
-
* correct options on a single-selection question, a maximum word count below
|
|
719
|
-
* the minimum, a media address with a scheme the SDK refuses, a `null` in an
|
|
720
|
-
* optional field that accepts none. The fix is to change it.
|
|
721
|
-
*/
|
|
722
|
-
type DraftSeverity = 'incomplete' | 'invalid';
|
|
723
|
-
/**
|
|
724
|
-
* One problem with a draft. A {@link ValidationError} with a severity, so code
|
|
725
|
-
* that already lists `validateActivity` errors can list these unchanged.
|
|
726
|
-
*/
|
|
727
|
-
interface DraftIssue extends ValidationError {
|
|
728
|
-
severity: DraftSeverity;
|
|
729
|
-
}
|
|
730
|
-
/** A draft that is a valid activity and has nothing left to write. */
|
|
731
|
-
interface DraftComplete<T> {
|
|
732
|
-
status: 'complete';
|
|
733
|
-
/** The validated activity, exactly as `validateActivity` returns it. */
|
|
734
|
-
data: T;
|
|
735
|
-
/** Always empty. Present so that every result can be read the same way. */
|
|
736
|
-
issues: DraftIssue[];
|
|
737
|
-
}
|
|
738
|
-
/**
|
|
739
|
-
* A draft that is not an activity yet: `invalid` when any issue is invalid,
|
|
740
|
-
* otherwise `incomplete`. It carries no `data`, because nothing here may be
|
|
741
|
-
* stored or rendered as an activity.
|
|
742
|
-
*/
|
|
743
|
-
interface DraftNotComplete {
|
|
744
|
-
status: 'incomplete' | 'invalid';
|
|
745
|
-
issues: DraftIssue[];
|
|
746
|
-
}
|
|
747
|
-
/**
|
|
748
|
-
* The result of `validateDraft`.
|
|
749
|
-
*
|
|
750
|
-
* There is deliberately no `success` boolean. A boolean has to call an
|
|
751
|
-
* incomplete draft either a success, which lets a half-written answer key
|
|
752
|
-
* through anything that checks it, or a failure, which is the conflation this
|
|
753
|
-
* result exists to remove. Branch on `status`.
|
|
754
|
-
*/
|
|
755
|
-
type DraftValidationResult<T> = DraftComplete<T> | DraftNotComplete;
|
|
756
|
-
/** What `createDraft` hands an activity type's `authoring.createDraft`. */
|
|
757
|
-
interface DraftContext {
|
|
758
|
-
/**
|
|
759
|
-
* Returns a new id on every call. The SDK invents none: an id made here would
|
|
760
|
-
* need `crypto`, which plain-http origins do not have, or would be positional —
|
|
761
|
-
* and option ids reach the learner, so ids like `"a"` and `"b"` would tell them
|
|
762
|
-
* which option was written first.
|
|
763
|
-
*/
|
|
764
|
-
newId: () => string;
|
|
765
|
-
}
|
|
766
|
-
|
|
891
|
+
export declare function diffResponses(before: Pick<AttemptState, 'responses'>, after: Pick<AttemptState, 'responses'>): ResponseDiffEntry[];
|
|
892
|
+
//#endregion
|
|
893
|
+
//#region src/authoring/item-group.d.ts
|
|
767
894
|
/**
|
|
768
895
|
* A new, empty reading or listening testlet for an editor to start from.
|
|
769
896
|
*
|
|
@@ -775,7 +902,7 @@ interface DraftContext {
|
|
|
775
902
|
*
|
|
776
903
|
* @throws Error when `newId` returns an empty or repeated id.
|
|
777
904
|
*/
|
|
778
|
-
declare function createItemGroupDraft(context: DraftContext): ItemGroup;
|
|
905
|
+
export declare function createItemGroupDraft(context: DraftContext): ItemGroup;
|
|
779
906
|
/**
|
|
780
907
|
* A new, empty interactive video for an editor to start from: an item group
|
|
781
908
|
* whose stimulus is a video with no file yet, no questions, and a timeline with
|
|
@@ -788,7 +915,7 @@ declare function createItemGroupDraft(context: DraftContext): ItemGroup;
|
|
|
788
915
|
*
|
|
789
916
|
* @throws Error when `newId` returns an empty or repeated id.
|
|
790
917
|
*/
|
|
791
|
-
declare function createInteractiveVideoDraft(context: DraftContext): ItemGroup;
|
|
918
|
+
export declare function createInteractiveVideoDraft(context: DraftContext): ItemGroup;
|
|
792
919
|
/**
|
|
793
920
|
* Tells an unfinished testlet from a broken one — {@link validateDraft} for the
|
|
794
921
|
* container that holds several questions around one passage or recording.
|
|
@@ -814,8 +941,27 @@ declare function createInteractiveVideoDraft(context: DraftContext): ItemGroup;
|
|
|
814
941
|
* turned into an issue: a fault in a type's own code is not a problem with the
|
|
815
942
|
* draft, and reporting it as an unknown type would hide it.
|
|
816
943
|
*/
|
|
817
|
-
|
|
818
|
-
|
|
944
|
+
/**
|
|
945
|
+
* The item critic over a testlet: each item's findings, under `items.N.…`, and
|
|
946
|
+
* what only the set shows — every single-answer question keeping its right
|
|
947
|
+
* option in one place. The stimulus is not searched for answers: a reading
|
|
948
|
+
* group's answers are meant to be in its passage.
|
|
949
|
+
*
|
|
950
|
+
* An item of a type that is not registered, or without a `type`, is skipped:
|
|
951
|
+
* {@link validateItemGroupDraft} already reports it.
|
|
952
|
+
*/
|
|
953
|
+
export declare function critiqueItemGroupDraft(draft: unknown): ItemFinding[];
|
|
954
|
+
/**
|
|
955
|
+
* The item critic over a question set, as `<ActivitySequence>` takes one: each
|
|
956
|
+
* entry's findings under its index — an item group's under `N.items.M.…` — and,
|
|
957
|
+
* over the entries that are items, what only the set shows (see
|
|
958
|
+
* {@link critiqueItemGroupDraft}). An entry of a type that is not registered is
|
|
959
|
+
* skipped.
|
|
960
|
+
*/
|
|
961
|
+
export declare function critiqueDrafts(entries: readonly unknown[]): ItemFinding[];
|
|
962
|
+
export declare function validateItemGroupDraft(draft: unknown): DraftValidationResult<ItemGroup>;
|
|
963
|
+
//#endregion
|
|
964
|
+
//#region src/authoring/index.d.ts
|
|
819
965
|
/**
|
|
820
966
|
* Tells a draft that is not finished from a draft that is wrong.
|
|
821
967
|
*
|
|
@@ -853,7 +999,7 @@ declare function validateItemGroupDraft(draft: unknown): DraftValidationResult<I
|
|
|
853
999
|
* @throws UnknownActivityTypeError when `type` has no registered descriptor —
|
|
854
1000
|
* including `'item-group'`, which is a container, not an activity type.
|
|
855
1001
|
*/
|
|
856
|
-
declare function validateDraft<T extends ActivityType>(type: T, draft: unknown): DraftValidationResult<ActivityDataMap[T]>;
|
|
1002
|
+
export declare function validateDraft<T extends ActivityType>(type: T, draft: unknown): DraftValidationResult<ActivityDataMap[T]>;
|
|
857
1003
|
/**
|
|
858
1004
|
* A new, empty draft of an activity type, for an editor to start from.
|
|
859
1005
|
*
|
|
@@ -871,8 +1017,52 @@ declare function validateDraft<T extends ActivityType>(type: T, draft: unknown):
|
|
|
871
1017
|
* @throws Error when the type declares no `authoring.createDraft`, or when
|
|
872
1018
|
* `newId` returns an empty or repeated id.
|
|
873
1019
|
*/
|
|
874
|
-
declare function createDraft<T extends ActivityType>(type: T, context: DraftContext): ActivityDataMap[T];
|
|
875
|
-
|
|
1020
|
+
export declare function createDraft<T extends ActivityType>(type: T, context: DraftContext): ActivityDataMap[T];
|
|
1021
|
+
/**
|
|
1022
|
+
* What an experienced item writer would point out on review: flaws a learner
|
|
1023
|
+
* can exploit or trip over (`warning`) and item-writing guidelines the item
|
|
1024
|
+
* departs from (`advice`) — the right option much longer than the rest, an
|
|
1025
|
+
* answer printed in the passage, a hint that gives the answer away, two
|
|
1026
|
+
* options that read the same, "all of the above" under shuffle.
|
|
1027
|
+
*
|
|
1028
|
+
* A finding is never a reason to refuse an item. It does not change what
|
|
1029
|
+
* {@link validateDraft} says: a valid item with findings is still valid. The
|
|
1030
|
+
* shape is a `DraftIssue`'s, so an editor shows both in one list.
|
|
1031
|
+
*
|
|
1032
|
+
* It reads a draft, finished or not, and skips any rule whose fields are not
|
|
1033
|
+
* written yet. The codes are documented in `docs/authoring.md`, each with its
|
|
1034
|
+
* severity; the rule behind a code is advice and may be refined in a minor.
|
|
1035
|
+
*
|
|
1036
|
+
* ```ts
|
|
1037
|
+
* const list = [...validateDraft(type, draft).issues, ...critiqueDraft(type, draft)];
|
|
1038
|
+
* ```
|
|
1039
|
+
*
|
|
1040
|
+
* @throws UnknownActivityTypeError when `type` has no registered descriptor —
|
|
1041
|
+
* including `'item-group'`: use {@link critiqueItemGroupDraft}.
|
|
1042
|
+
*/
|
|
1043
|
+
export declare function critiqueDraft(type: ActivityType, draft: unknown): ItemFinding[];
|
|
1044
|
+
//#endregion
|
|
1045
|
+
//#region src/built-in-types.d.ts
|
|
1046
|
+
/**
|
|
1047
|
+
* The activity types the SDK ships, in one closed list.
|
|
1048
|
+
*
|
|
1049
|
+
* {@link ActivityType} is `keyof ActivityDataMap`, which a host widens by
|
|
1050
|
+
* module augmentation to name its own types, so it cannot say which types are
|
|
1051
|
+
* the SDK's. This list can: every table the SDK keeps per built-in type is
|
|
1052
|
+
* typed against it (`satisfies Record<BuiltInActivityType, …>`) or walks it, so
|
|
1053
|
+
* a type added here is a compile error, or a failing test, everywhere it has
|
|
1054
|
+
* not been handled yet.
|
|
1055
|
+
*
|
|
1056
|
+
* The SDK's own registry holds exactly these, in this order, before a host
|
|
1057
|
+
* registers anything.
|
|
1058
|
+
*/
|
|
1059
|
+
export declare const BUILT_IN_ACTIVITY_TYPES: readonly ["multiple-choice", "fill-in-the-blanks", "written-response", "gap-select", "dictation", "read-aloud"];
|
|
1060
|
+
/** One of {@link BUILT_IN_ACTIVITY_TYPES}: an activity type the SDK ships, not one a host registered. */
|
|
1061
|
+
type BuiltInActivityType = (typeof BUILT_IN_ACTIVITY_TYPES)[number];
|
|
1062
|
+
/** Whether `type` names an activity type the SDK ships. */
|
|
1063
|
+
export declare function isBuiltInActivityType(type: unknown): type is BuiltInActivityType;
|
|
1064
|
+
//#endregion
|
|
1065
|
+
//#region src/content-hash.d.ts
|
|
876
1066
|
/**
|
|
877
1067
|
* Content fingerprinting — "is this the same content the learner was served?"
|
|
878
1068
|
*
|
|
@@ -893,7 +1083,7 @@ declare function createDraft<T extends ActivityType>(type: T, context: DraftCont
|
|
|
893
1083
|
* that disagreed would raise a false alarm every time a payload made a
|
|
894
1084
|
* round-trip through a different serializer.
|
|
895
1085
|
*/
|
|
896
|
-
declare function canonicalJson(value: unknown, seen?: Set<object>): string;
|
|
1086
|
+
export declare function canonicalJson(value: unknown, seen?: Set<object>): string;
|
|
897
1087
|
/**
|
|
898
1088
|
* FNV-1a over the UTF-8 bytes of `input`, as 16 lowercase hex digits.
|
|
899
1089
|
*
|
|
@@ -904,28 +1094,30 @@ declare function canonicalJson(value: unknown, seen?: Set<object>): string;
|
|
|
904
1094
|
* property, sign the plan with a key the content author does not hold; this
|
|
905
1095
|
* exists to catch honest edits, which is what actually happens.
|
|
906
1096
|
*/
|
|
907
|
-
declare function fingerprint(input: string): string;
|
|
1097
|
+
export declare function fingerprint(input: string): string;
|
|
908
1098
|
/**
|
|
909
1099
|
* Fingerprints any JSON-serialisable value through {@link canonicalJson}, so
|
|
910
1100
|
* the result depends on the content and not on how it was written.
|
|
911
1101
|
*/
|
|
912
|
-
declare function contentHash(value: unknown): string;
|
|
913
|
-
|
|
1102
|
+
export declare function contentHash(value: unknown): string;
|
|
1103
|
+
//#endregion
|
|
1104
|
+
//#region src/count-words.d.ts
|
|
914
1105
|
/**
|
|
915
|
-
* Canonical word counter for written-response bounds
|
|
1106
|
+
* Canonical word counter for written-response bounds: tokens are
|
|
916
1107
|
* maximal runs of non-whitespace (split on `\s+`), so hyphenated forms
|
|
917
1108
|
* (`well-known`) count as one word. The empty / whitespace-only string counts
|
|
918
1109
|
* 0. Consumers must use this helper rather than re-implementing the split so
|
|
919
1110
|
* client previews, SDK scoring, and stored `wordCount` values always agree.
|
|
920
1111
|
*/
|
|
921
|
-
declare function countWords(text: string): number;
|
|
922
|
-
|
|
1112
|
+
export declare function countWords(text: string): number;
|
|
1113
|
+
//#endregion
|
|
1114
|
+
//#region src/delivery.d.ts
|
|
923
1115
|
/**
|
|
924
1116
|
* The policy that restricts nothing: every setting `true`. It is what an absent
|
|
925
1117
|
* policy resolves to, and it is exactly the behaviour the SDK had before
|
|
926
1118
|
* delivery policies existed.
|
|
927
1119
|
*/
|
|
928
|
-
declare const OPEN_DELIVERY_POLICY: ResolvedDeliveryPolicy;
|
|
1120
|
+
export declare const OPEN_DELIVERY_POLICY: ResolvedDeliveryPolicy;
|
|
929
1121
|
/**
|
|
930
1122
|
* A policy with every setting spelled out — see {@link DeliveryPolicy}.
|
|
931
1123
|
*
|
|
@@ -934,13 +1126,13 @@ declare const OPEN_DELIVERY_POLICY: ResolvedDeliveryPolicy;
|
|
|
934
1126
|
* policy that is not an object at all restricts everything. Check a policy
|
|
935
1127
|
* before you store it with {@link validateDeliveryPolicy}; `planAttempt` does.
|
|
936
1128
|
*/
|
|
937
|
-
declare function resolveDeliveryPolicy(policy: unknown): ResolvedDeliveryPolicy;
|
|
1129
|
+
export declare function resolveDeliveryPolicy(policy: unknown): ResolvedDeliveryPolicy;
|
|
938
1130
|
/**
|
|
939
1131
|
* The strictest of several policies: a setting is on only where every one of
|
|
940
1132
|
* them leaves it on. How a course's policy and an assessment's combine, and
|
|
941
1133
|
* how a pager's policy wins over whatever a question it draws was handed.
|
|
942
1134
|
*/
|
|
943
|
-
declare function combineDeliveryPolicies(...policies: unknown[]): ResolvedDeliveryPolicy;
|
|
1135
|
+
export declare function combineDeliveryPolicies(...policies: unknown[]): ResolvedDeliveryPolicy;
|
|
944
1136
|
/**
|
|
945
1137
|
* Checks a policy before it is stored: each setting `true`, `false`, `null`
|
|
946
1138
|
* or absent, and nothing else — no misspelled setting, no string standing in
|
|
@@ -951,24 +1143,25 @@ declare function combineDeliveryPolicies(...policies: unknown[]): ResolvedDelive
|
|
|
951
1143
|
* policy is a record of the conditions a paper was sat under: it is worth
|
|
952
1144
|
* refusing before it is written down, rather than read charitably after.
|
|
953
1145
|
*/
|
|
954
|
-
declare function validateDeliveryPolicy(policy: unknown): {
|
|
955
|
-
|
|
956
|
-
|
|
1146
|
+
export declare function validateDeliveryPolicy(policy: unknown): {
|
|
1147
|
+
success: true;
|
|
1148
|
+
data: DeliveryPolicy;
|
|
957
1149
|
} | {
|
|
958
|
-
|
|
959
|
-
|
|
1150
|
+
success: false;
|
|
1151
|
+
issues: DeliveryPolicyIssue[];
|
|
960
1152
|
};
|
|
961
|
-
|
|
1153
|
+
//#endregion
|
|
1154
|
+
//#region src/errors.d.ts
|
|
962
1155
|
/** Thrown when activity data fails schema validation at a component boundary. */
|
|
963
|
-
declare class ActivitySchemaError extends Error {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1156
|
+
export declare class ActivitySchemaError extends Error {
|
|
1157
|
+
readonly activityType: string;
|
|
1158
|
+
readonly errors: ValidationError[];
|
|
1159
|
+
constructor(activityType: string, errors: ValidationError[]);
|
|
967
1160
|
}
|
|
968
1161
|
/** Thrown when an unrecognised activity type is passed to the scoring engine. */
|
|
969
|
-
declare class UnknownActivityTypeError extends Error {
|
|
970
|
-
|
|
971
|
-
|
|
1162
|
+
export declare class UnknownActivityTypeError extends Error {
|
|
1163
|
+
readonly activityType: string;
|
|
1164
|
+
constructor(activityType: string);
|
|
972
1165
|
}
|
|
973
1166
|
/**
|
|
974
1167
|
* Thrown when a grading entry point is asked to grade a `redact()` projection
|
|
@@ -980,9 +1173,9 @@ declare class UnknownActivityTypeError extends Error {
|
|
|
980
1173
|
* type comes back `unscorable`, and a deferred one `deferred`, as it does for
|
|
981
1174
|
* any item of that type.
|
|
982
1175
|
*/
|
|
983
|
-
declare class RedactedScoringError extends Error {
|
|
984
|
-
|
|
985
|
-
|
|
1176
|
+
export declare class RedactedScoringError extends Error {
|
|
1177
|
+
readonly activityType: string;
|
|
1178
|
+
constructor(activityType: string);
|
|
986
1179
|
}
|
|
987
1180
|
/**
|
|
988
1181
|
* Thrown when `score()` is called for an activity type whose grading is
|
|
@@ -991,33 +1184,34 @@ declare class RedactedScoringError extends Error {
|
|
|
991
1184
|
* a learner a failing grade for work that simply has not been graded yet.
|
|
992
1185
|
* Call `evaluate()` instead, which returns `{ status: 'deferred', ... }`.
|
|
993
1186
|
*/
|
|
994
|
-
declare class DeferredScoringError extends Error {
|
|
995
|
-
|
|
996
|
-
|
|
1187
|
+
export declare class DeferredScoringError extends Error {
|
|
1188
|
+
readonly activityType: string;
|
|
1189
|
+
constructor(activityType: string);
|
|
997
1190
|
}
|
|
998
|
-
|
|
1191
|
+
//#endregion
|
|
1192
|
+
//#region src/grading.d.ts
|
|
999
1193
|
/** Options for {@link gradeFromRubric}. */
|
|
1000
|
-
interface GradeFromRubricOptions {
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1194
|
+
export interface GradeFromRubricOptions {
|
|
1195
|
+
/**
|
|
1196
|
+
* Scaled score [0,1] required to pass. Defaults to the activity's
|
|
1197
|
+
* `passThreshold`, or {@link DEFAULT_PASS_THRESHOLD} when absent.
|
|
1198
|
+
*/
|
|
1199
|
+
passThreshold?: number;
|
|
1200
|
+
/** Narrative feedback for the learner, carried onto the record verbatim. */
|
|
1201
|
+
feedback?: string | null;
|
|
1202
|
+
/**
|
|
1203
|
+
* Compare the pass line the way the score is displayed — both sides rounded,
|
|
1204
|
+
* via `gte` — whichever threshold applies: `passThreshold` above, the
|
|
1205
|
+
* activity's own, or the 0.7 default. The returned `score` stays unrounded.
|
|
1206
|
+
* Opt-in, as on `score()` and `evaluate()`: switching it on moves pass/fail
|
|
1207
|
+
* for totals in the rounding band.
|
|
1208
|
+
*
|
|
1209
|
+
* Checked before any criterion is read: `null` reads as no policy, and a
|
|
1210
|
+
* policy that cannot be applied — an unknown `mode`, or a `dp` that is not a
|
|
1211
|
+
* whole number from 0 to 15 — throws a `RangeError`, even for a rubric that
|
|
1212
|
+
* turns out to be unscorable.
|
|
1213
|
+
*/
|
|
1214
|
+
rounding?: RoundingPolicy;
|
|
1021
1215
|
}
|
|
1022
1216
|
/**
|
|
1023
1217
|
* Computes the weighted total from per-criterion scores — the arithmetic that
|
|
@@ -1051,9 +1245,9 @@ interface GradeFromRubricOptions {
|
|
|
1051
1245
|
* The returned `GradeRecord.score` is always scaled [0,1] against
|
|
1052
1246
|
* `maxScore: 1`, like every other score in the SDK.
|
|
1053
1247
|
*/
|
|
1054
|
-
declare function gradeFromRubric(criteria: readonly CriterionScore[], activityData?: ActivityData, options?: GradeFromRubricOptions): GradeRecord | {
|
|
1055
|
-
|
|
1056
|
-
|
|
1248
|
+
export declare function gradeFromRubric(criteria: readonly CriterionScore[], activityData?: ActivityData, options?: GradeFromRubricOptions): GradeRecord | {
|
|
1249
|
+
unscorable: true;
|
|
1250
|
+
reason: string;
|
|
1057
1251
|
};
|
|
1058
1252
|
/**
|
|
1059
1253
|
* Lifts a {@link GradeRecord} into the `graded` arm of {@link ItemOutcome}, so
|
|
@@ -1074,36 +1268,37 @@ declare function gradeFromRubric(criteria: readonly CriterionScore[], activityDa
|
|
|
1074
1268
|
* is what it is: the slot is still owed a real grade, so a composed attempt
|
|
1075
1269
|
* stays `provisional` and names the slot in `rejectedSlotIds`.
|
|
1076
1270
|
*/
|
|
1077
|
-
declare function outcomeFromGrade(grade: GradeRecord): ItemOutcome;
|
|
1271
|
+
export declare function outcomeFromGrade(grade: GradeRecord): ItemOutcome;
|
|
1078
1272
|
/**
|
|
1079
1273
|
* True when an outcome carries a real grade — either the SDK scored it
|
|
1080
1274
|
* synchronously or a grader returned one. Use this instead of testing
|
|
1081
1275
|
* `status === 'scored'`, which silently misses asynchronously graded work.
|
|
1082
1276
|
*/
|
|
1083
|
-
declare function hasGrade(outcome: ItemOutcome): outcome is Extract<ItemOutcome, {
|
|
1084
|
-
|
|
1277
|
+
export declare function hasGrade(outcome: ItemOutcome): outcome is Extract<ItemOutcome, {
|
|
1278
|
+
status: 'scored' | 'graded';
|
|
1085
1279
|
}>;
|
|
1086
|
-
|
|
1280
|
+
//#endregion
|
|
1281
|
+
//#region src/item-group.d.ts
|
|
1087
1282
|
/** Narrows a sequence entry to an item group. */
|
|
1088
|
-
declare function isItemGroup<TItem extends {
|
|
1089
|
-
|
|
1283
|
+
export declare function isItemGroup<TItem extends {
|
|
1284
|
+
type: string;
|
|
1090
1285
|
}>(entry: SequenceEntry<TItem>): entry is ItemGroup<TItem>;
|
|
1091
1286
|
/** Options for {@link flattenSequence}. */
|
|
1092
|
-
interface FlattenSequenceOptions {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1287
|
+
export interface FlattenSequenceOptions {
|
|
1288
|
+
/**
|
|
1289
|
+
* Shuffle the top-level entries. A group moves as ONE block — its items are
|
|
1290
|
+
* never interleaved with other entries — which is the reason a group exists
|
|
1291
|
+
* as a container rather than as a flag on each item.
|
|
1292
|
+
*/
|
|
1293
|
+
shuffleEntries?: boolean;
|
|
1294
|
+
/**
|
|
1295
|
+
* Seed for every shuffle in this call: the entries, and each group whose
|
|
1296
|
+
* `shuffle` is `within-group`. REQUIRED whenever anything shuffles. The SDK
|
|
1297
|
+
* never invents one, because the server that stores an attempt and the
|
|
1298
|
+
* client that renders it must derive the SAME order, and only a shared seed
|
|
1299
|
+
* makes that true. The attempt id is the natural choice.
|
|
1300
|
+
*/
|
|
1301
|
+
seed?: string;
|
|
1107
1302
|
}
|
|
1108
1303
|
/**
|
|
1109
1304
|
* Turns a sequence definition — loose activities and item groups, in authored
|
|
@@ -1119,30 +1314,31 @@ interface FlattenSequenceOptions {
|
|
|
1119
1314
|
*
|
|
1120
1315
|
* @throws Error when a shuffle is requested without a `seed`.
|
|
1121
1316
|
*/
|
|
1122
|
-
declare function flattenSequence<TItem extends {
|
|
1123
|
-
|
|
1124
|
-
|
|
1317
|
+
export declare function flattenSequence<TItem extends {
|
|
1318
|
+
id: string;
|
|
1319
|
+
type: string;
|
|
1125
1320
|
}>(entries: readonly SequenceEntry<TItem>[], options?: FlattenSequenceOptions): SequenceSlot<TItem>[];
|
|
1126
|
-
|
|
1321
|
+
//#endregion
|
|
1322
|
+
//#region src/types/media-budget.d.ts
|
|
1127
1323
|
/**
|
|
1128
1324
|
* What one budgeted recording has cost the learner so far.
|
|
1129
1325
|
*/
|
|
1130
1326
|
interface MediaPlayLedgerEntry {
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1327
|
+
/**
|
|
1328
|
+
* Plays consumed. A non-negative integer. It MAY exceed the budget: an
|
|
1329
|
+
* invigilator override and a race the server resolved both legitimately
|
|
1330
|
+
* produce that, and clamping here would hide it.
|
|
1331
|
+
*/
|
|
1332
|
+
plays: number;
|
|
1333
|
+
/**
|
|
1334
|
+
* Where playback stood at the last report, in seconds.
|
|
1335
|
+
*
|
|
1336
|
+
* Restored on mount so a refresh RESUMES the play the learner already paid
|
|
1337
|
+
* for instead of charging them again for it. It can only ever let them
|
|
1338
|
+
* continue from where they were, never restart, because `seek` resolves to
|
|
1339
|
+
* `'none'` under a budget.
|
|
1340
|
+
*/
|
|
1341
|
+
at?: number;
|
|
1146
1342
|
}
|
|
1147
1343
|
/**
|
|
1148
1344
|
* The spent-play ledger for one attempt.
|
|
@@ -1162,13 +1358,13 @@ interface MediaPlayLedgerEntry {
|
|
|
1162
1358
|
* Bound to its paper by `planHash` for the same reason `AttemptState` is.
|
|
1163
1359
|
*/
|
|
1164
1360
|
interface MediaPlayLedger {
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1361
|
+
ledgerVersion: '1.0';
|
|
1362
|
+
/** The `planHash` of the paper these counts were spent on. */
|
|
1363
|
+
planHash: string;
|
|
1364
|
+
/** Keyed by `slotMediaKey()` / `stimulusMediaKey()`. An absent key means nothing spent. */
|
|
1365
|
+
entries: Record<string, MediaPlayLedgerEntry>;
|
|
1366
|
+
/** ISO 8601, when the caller supplies one. The SDK reads no clock. */
|
|
1367
|
+
savedAt?: string;
|
|
1172
1368
|
}
|
|
1173
1369
|
/**
|
|
1174
1370
|
* What the SDK asks the consumer to record, before a sample of audio is
|
|
@@ -1178,28 +1374,29 @@ interface MediaPlayLedger {
|
|
|
1178
1374
|
* seeded at 0 both claim 1, and only an atomic write can tell them apart.
|
|
1179
1375
|
*/
|
|
1180
1376
|
interface MediaPlayClaim {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1377
|
+
/** `slot:…` / `stimulus:…`. */
|
|
1378
|
+
key: string;
|
|
1379
|
+
/** The count the client believes was already spent — the value to compare against. */
|
|
1380
|
+
previousPlaysUsed: number;
|
|
1381
|
+
/** The count the client is claiming: `previousPlaysUsed + 1`. */
|
|
1382
|
+
playsUsed: number;
|
|
1383
|
+
maxPlays: number;
|
|
1384
|
+
playsRemaining: number;
|
|
1385
|
+
/** Where the learner stood when the claim was made. Forensics; never identity. */
|
|
1386
|
+
slotId: string;
|
|
1387
|
+
index: number;
|
|
1388
|
+
activityId?: string;
|
|
1193
1389
|
}
|
|
1194
1390
|
/** The consumer's authoritative answer to a {@link MediaPlayClaim}. */
|
|
1195
1391
|
interface MediaPlayGrant {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1392
|
+
/**
|
|
1393
|
+
* The count AFTER the server's atomic write. A value greater than
|
|
1394
|
+
* `maxPlays` refuses the play — which is how a second tab is caught.
|
|
1395
|
+
*/
|
|
1396
|
+
playsUsed: number;
|
|
1201
1397
|
}
|
|
1202
|
-
|
|
1398
|
+
//#endregion
|
|
1399
|
+
//#region src/media-budget.d.ts
|
|
1203
1400
|
/**
|
|
1204
1401
|
* The authored-entry prefix of a slot id: `"3"` for both `"3"` and `"3.1"`.
|
|
1205
1402
|
*
|
|
@@ -1207,9 +1404,9 @@ interface MediaPlayGrant {
|
|
|
1207
1404
|
* `keyOf` rejects a `.` in both an entry key and an item key — so the first
|
|
1208
1405
|
* `.` is always the group/item separator.
|
|
1209
1406
|
*/
|
|
1210
|
-
declare function entryKeyOf(slotId: string): string;
|
|
1407
|
+
export declare function entryKeyOf(slotId: string): string;
|
|
1211
1408
|
/** Budget key for an activity's OWN `data.media`. One budget per slot. */
|
|
1212
|
-
declare function slotMediaKey(slotId: string): string;
|
|
1409
|
+
export declare function slotMediaKey(slotId: string): string;
|
|
1213
1410
|
/**
|
|
1214
1411
|
* Budget key for an item group's `stimulus.media`.
|
|
1215
1412
|
*
|
|
@@ -1219,15 +1416,15 @@ declare function slotMediaKey(slotId: string): string;
|
|
|
1219
1416
|
* `stimulus.id` would collide across papers, which is the thing slot keys and
|
|
1220
1417
|
* `planHash` exist to prevent.
|
|
1221
1418
|
*/
|
|
1222
|
-
declare function stimulusMediaKey(slotId: string): string;
|
|
1419
|
+
export declare function stimulusMediaKey(slotId: string): string;
|
|
1223
1420
|
/** A playback policy with every default resolved. One derivation, used everywhere. */
|
|
1224
|
-
interface ResolvedPlaybackPolicy {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1421
|
+
export interface ResolvedPlaybackPolicy {
|
|
1422
|
+
controls: 'native' | 'minimal';
|
|
1423
|
+
/** `null` when the recording is unbudgeted. */
|
|
1424
|
+
maxPlays: number | null;
|
|
1425
|
+
seek: 'allow' | 'none';
|
|
1426
|
+
rate: 'allow' | 'fixed';
|
|
1427
|
+
nativeControlHints: readonly NativeControlHint[];
|
|
1231
1428
|
}
|
|
1232
1429
|
/**
|
|
1233
1430
|
* Resolves the defaults once, so the schema refinements, the plan and the
|
|
@@ -1236,7 +1433,7 @@ interface ResolvedPlaybackPolicy {
|
|
|
1236
1433
|
* Absent `playback` resolves to exactly the SDK's pre-0.8.0 behaviour:
|
|
1237
1434
|
* `controls: 'native'`, no budget, free seeking, free speed, no hints.
|
|
1238
1435
|
*/
|
|
1239
|
-
declare function resolvePlaybackPolicy(media: ActivityMedia): ResolvedPlaybackPolicy;
|
|
1436
|
+
export declare function resolvePlaybackPolicy(media: ActivityMedia): ResolvedPlaybackPolicy;
|
|
1240
1437
|
/**
|
|
1241
1438
|
* Every budgeted recording a plan contains: budget key → the `maxPlays` that
|
|
1242
1439
|
* was frozen when the attempt was planned.
|
|
@@ -1244,7 +1441,7 @@ declare function resolvePlaybackPolicy(media: ActivityMedia): ResolvedPlaybackPo
|
|
|
1244
1441
|
* Use it to build the storage rows an attempt needs, and to check a stored
|
|
1245
1442
|
* ledger against the paper it claims to belong to.
|
|
1246
1443
|
*/
|
|
1247
|
-
declare function planMediaBudgets(plan: AttemptPlan): Record<string, number>;
|
|
1444
|
+
export declare function planMediaBudgets(plan: AttemptPlan): Record<string, number>;
|
|
1248
1445
|
/**
|
|
1249
1446
|
* Validates a set of spent-play counts against the plan that budgeted them,
|
|
1250
1447
|
* and stamps the envelope.
|
|
@@ -1256,8 +1453,8 @@ declare function planMediaBudgets(plan: AttemptPlan): Record<string, number>;
|
|
|
1256
1453
|
* @throws Error when a key is not budgeted by the plan, or a count is not a
|
|
1257
1454
|
* non-negative integer, or a position is not a finite number.
|
|
1258
1455
|
*/
|
|
1259
|
-
declare function serializeMediaPlayLedger(plan: AttemptPlan, entries: Readonly<Record<string, MediaPlayLedgerEntry>>, options?: {
|
|
1260
|
-
|
|
1456
|
+
export declare function serializeMediaPlayLedger(plan: AttemptPlan, entries: Readonly<Record<string, MediaPlayLedgerEntry>>, options?: {
|
|
1457
|
+
savedAt?: string;
|
|
1261
1458
|
}): MediaPlayLedger;
|
|
1262
1459
|
/**
|
|
1263
1460
|
* Reopens a stored ledger against the paper it was spent on.
|
|
@@ -1271,8 +1468,9 @@ declare function serializeMediaPlayLedger(plan: AttemptPlan, entries: Readonly<R
|
|
|
1271
1468
|
* @throws Error on an unrecognised `ledgerVersion`, a `planHash` mismatch, or
|
|
1272
1469
|
* anything `serializeMediaPlayLedger` refuses.
|
|
1273
1470
|
*/
|
|
1274
|
-
declare function restoreMediaPlayLedger(plan: AttemptPlan, stored: MediaPlayLedger): MediaPlayLedger;
|
|
1275
|
-
|
|
1471
|
+
export declare function restoreMediaPlayLedger(plan: AttemptPlan, stored: MediaPlayLedger): MediaPlayLedger;
|
|
1472
|
+
//#endregion
|
|
1473
|
+
//#region src/standard-schema.d.ts
|
|
1276
1474
|
/**
|
|
1277
1475
|
* Standard Schema v1 (https://standardschema.dev): the interface zod, valibot,
|
|
1278
1476
|
* ArkType and other validators implement, so a library can accept a schema from
|
|
@@ -1285,68 +1483,85 @@ declare function restoreMediaPlayLedger(plan: AttemptPlan, stored: MediaPlayLedg
|
|
|
1285
1483
|
*/
|
|
1286
1484
|
/** A schema that validates unknown input and produces `Output`. */
|
|
1287
1485
|
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
1288
|
-
|
|
1289
|
-
|
|
1486
|
+
/** The Standard Schema properties. */
|
|
1487
|
+
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
|
|
1290
1488
|
}
|
|
1291
1489
|
declare namespace StandardSchemaV1 {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1490
|
+
/** The Standard Schema properties interface. */
|
|
1491
|
+
interface Props<Input = unknown, Output = Input> {
|
|
1492
|
+
/** The version number of the standard. */
|
|
1493
|
+
readonly version: 1;
|
|
1494
|
+
/** The vendor name of the schema library. */
|
|
1495
|
+
readonly vendor: string;
|
|
1496
|
+
/**
|
|
1497
|
+
* Validates unknown input values. lk-core validates synchronously, so a
|
|
1498
|
+
* schema whose validation returns a Promise is refused when it is read.
|
|
1499
|
+
*/
|
|
1500
|
+
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
|
|
1501
|
+
/** Inferred types associated with the schema. */
|
|
1502
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
1503
|
+
}
|
|
1504
|
+
/** The result interface of the validate function. */
|
|
1505
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
1506
|
+
/** The result interface if validation succeeds. */
|
|
1507
|
+
interface SuccessResult<Output> {
|
|
1508
|
+
/** The typed output value. */
|
|
1509
|
+
readonly value: Output;
|
|
1510
|
+
/** The absence of issues indicates success. */
|
|
1511
|
+
readonly issues?: undefined;
|
|
1512
|
+
}
|
|
1513
|
+
/** Options for the validate function. */
|
|
1514
|
+
interface Options {
|
|
1515
|
+
/** Implicit support for additional vendor-specific parameters, if needed. */
|
|
1516
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
1517
|
+
}
|
|
1518
|
+
/** The result interface if validation fails. */
|
|
1519
|
+
interface FailureResult {
|
|
1520
|
+
/** The issues of failed validation. */
|
|
1521
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
1522
|
+
}
|
|
1523
|
+
/** The issue interface of the failure output. */
|
|
1524
|
+
interface Issue {
|
|
1525
|
+
/** The error message of the issue. */
|
|
1526
|
+
readonly message: string;
|
|
1527
|
+
/** The path of the issue, if any. */
|
|
1528
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
1529
|
+
}
|
|
1530
|
+
/** The path segment interface of the issue. */
|
|
1531
|
+
interface PathSegment {
|
|
1532
|
+
/** The key representing a path segment. */
|
|
1533
|
+
readonly key: PropertyKey;
|
|
1534
|
+
}
|
|
1535
|
+
/** The Standard Schema types interface. */
|
|
1536
|
+
interface Types<Input = unknown, Output = Input> {
|
|
1537
|
+
/** The input type of the schema. */
|
|
1538
|
+
readonly input: Input;
|
|
1539
|
+
/** The output type of the schema. */
|
|
1540
|
+
readonly output: Output;
|
|
1541
|
+
}
|
|
1542
|
+
/** Infers the input type of a Standard Schema. */
|
|
1543
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
|
|
1544
|
+
/** Infers the output type of a Standard Schema. */
|
|
1545
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
|
|
1348
1546
|
}
|
|
1349
|
-
|
|
1547
|
+
//#endregion
|
|
1548
|
+
//#region src/registry/define.d.ts
|
|
1549
|
+
/**
|
|
1550
|
+
* Identity helper that gives full type inference when authoring a descriptor:
|
|
1551
|
+
*
|
|
1552
|
+
* ```ts
|
|
1553
|
+
* const myType = defineActivityType<MyTypeData, MyTypeLearnerResponse>({ ... });
|
|
1554
|
+
* registerActivityType(myType);
|
|
1555
|
+
* ```
|
|
1556
|
+
*
|
|
1557
|
+
* In a module of its own so the SDK's built-in descriptors can use it without
|
|
1558
|
+
* importing the registry they are read into.
|
|
1559
|
+
*/
|
|
1560
|
+
export declare function defineActivityType<TData extends {
|
|
1561
|
+
type: string;
|
|
1562
|
+
}, TResponse>(descriptor: ActivityTypeDescriptor<TData, TResponse>): ActivityTypeDescriptor<TData, TResponse>;
|
|
1563
|
+
//#endregion
|
|
1564
|
+
//#region src/registry/registry.d.ts
|
|
1350
1565
|
/** ScoringResult without `passed` — the public `score()` / `evaluate()` fill that in. */
|
|
1351
1566
|
type PartialScoringResult = Omit<ScoringResult, 'passed'>;
|
|
1352
1567
|
/**
|
|
@@ -1369,18 +1584,18 @@ type Sensitivity = 'public' | 'answer-key' | 'author-only';
|
|
|
1369
1584
|
* without classifying it hides it, never leaks it.
|
|
1370
1585
|
*/
|
|
1371
1586
|
interface FieldPolicy {
|
|
1372
|
-
|
|
1587
|
+
readonly [field: string]: Sensitivity | FieldPolicy;
|
|
1373
1588
|
}
|
|
1374
1589
|
/** xAPI interaction types defined by xAPI 1.0.3 (cmi.interaction vocabulary). */
|
|
1375
1590
|
type XAPIInteractionType = 'choice' | 'fill-in' | 'long-fill-in' | 'matching' | 'sequencing' | 'performance' | 'true-false' | 'other';
|
|
1376
1591
|
/** Interop facts a generic statement builder cannot infer from data alone. */
|
|
1377
1592
|
interface ActivityTypeInterop<TData> {
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1593
|
+
/** IRI for the xAPI Activity `definition.type`. */
|
|
1594
|
+
readonly xapiActivityTypeIri?: string;
|
|
1595
|
+
/** xAPI `definition.interactionType` for this activity type. */
|
|
1596
|
+
readonly xapiInteractionType?: XAPIInteractionType;
|
|
1597
|
+
/** Builds the xAPI `correctResponsesPattern` strings for an item. */
|
|
1598
|
+
readonly correctResponsesPattern?: (data: TData) => string[];
|
|
1384
1599
|
}
|
|
1385
1600
|
/**
|
|
1386
1601
|
* How responses to an activity type are graded:
|
|
@@ -1390,12 +1605,12 @@ interface ActivityTypeInterop<TData> {
|
|
|
1390
1605
|
* (e.g. word counts), surfaced in `ItemOutcome.partial`.
|
|
1391
1606
|
*/
|
|
1392
1607
|
type ActivityTypeScoring<TData, TResponse> = {
|
|
1393
|
-
|
|
1394
|
-
|
|
1608
|
+
readonly kind: 'sync';
|
|
1609
|
+
readonly score: (data: TData, response: TResponse) => PartialScoringResult;
|
|
1395
1610
|
} | {
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1611
|
+
readonly kind: 'deferred';
|
|
1612
|
+
readonly reason: 'requires_async_grading';
|
|
1613
|
+
readonly partial?: (data: TData, response: TResponse | undefined) => DeferredScoringPartial;
|
|
1399
1614
|
};
|
|
1400
1615
|
/**
|
|
1401
1616
|
* Authoring support for an activity type: the empty draft an editor starts
|
|
@@ -1405,34 +1620,47 @@ type ActivityTypeScoring<TData, TResponse> = {
|
|
|
1405
1620
|
* `createDraft()` throws for the type.
|
|
1406
1621
|
*/
|
|
1407
1622
|
interface ActivityTypeAuthoring<TData> {
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1623
|
+
/**
|
|
1624
|
+
* A new draft: every required field present, nothing authored yet. It must
|
|
1625
|
+
* come back from `validateDraft` as `incomplete` — never `invalid`, and never
|
|
1626
|
+
* `complete` — so a freshly added question is not reported as an error, and
|
|
1627
|
+
* cannot pass validation before anyone has written it.
|
|
1628
|
+
*/
|
|
1629
|
+
readonly createDraft?: (context: DraftContext) => TData;
|
|
1630
|
+
/**
|
|
1631
|
+
* Reports what is missing (`incomplete`) and what is wrong (`invalid`) in a
|
|
1632
|
+
* draft. Receives any plain object and must not throw on one.
|
|
1633
|
+
*
|
|
1634
|
+
* Report each problem at the path the schema reports it. `validateDraft` adds
|
|
1635
|
+
* every schema failure as `invalid` unless an issue returned here sits at that
|
|
1636
|
+
* path or inside it — so an issue at the wrong path leaves the schema's
|
|
1637
|
+
* message standing beside yours, and makes an unfinished draft read as wrong.
|
|
1638
|
+
* An issue inside a path accounts for every failure at that path, a list's
|
|
1639
|
+
* length included, so report a rule about a whole list at the list's own path.
|
|
1640
|
+
* A failure at the root of the draft is accounted for only by an issue at the
|
|
1641
|
+
* root. A `null` the schema refuses, where nothing here reports it, comes back
|
|
1642
|
+
* as `null_not_allowed`. A zod 4 schema tells a refused `null` from a rule of
|
|
1643
|
+
* yours that merely points at one, which keeps its own code; a schema from
|
|
1644
|
+
* another library cannot, so report such a rule here, at its path.
|
|
1645
|
+
*
|
|
1646
|
+
* A code documented in `docs/authoring.md` is reported with its documented
|
|
1647
|
+
* severity. For a code of your own, a severity other than `'incomplete'` is
|
|
1648
|
+
* reported as `invalid`.
|
|
1649
|
+
*/
|
|
1650
|
+
readonly checkDraft?: (draft: Readonly<Record<string, unknown>>) => DraftIssue[];
|
|
1651
|
+
/**
|
|
1652
|
+
* The item critic for the type: what `critiqueDraft` reports about a draft
|
|
1653
|
+
* that may be perfectly valid — a flaw a learner can exploit (`warning`), or
|
|
1654
|
+
* an item-writing guideline it departs from (`advice`). Receives any plain
|
|
1655
|
+
* object, finished or not, and must not throw on one: skip a rule whose
|
|
1656
|
+
* fields are not there yet. Never a reason to refuse the item; that is
|
|
1657
|
+
* `checkDraft`'s.
|
|
1658
|
+
*
|
|
1659
|
+
* A code documented in `docs/authoring.md` is reported with its documented
|
|
1660
|
+
* severity. For a code of your own, a severity other than `'advice'` is
|
|
1661
|
+
* reported as `warning`.
|
|
1662
|
+
*/
|
|
1663
|
+
readonly critique?: (draft: Readonly<Record<string, unknown>>) => ItemFinding[];
|
|
1436
1664
|
}
|
|
1437
1665
|
/**
|
|
1438
1666
|
* A value-level description of an activity type: its contract (schema), its
|
|
@@ -1455,77 +1683,66 @@ interface ActivityTypeAuthoring<TData> {
|
|
|
1455
1683
|
* ```
|
|
1456
1684
|
*/
|
|
1457
1685
|
interface ActivityTypeDescriptor<TData extends {
|
|
1458
|
-
|
|
1686
|
+
type: string;
|
|
1459
1687
|
}, TResponse> {
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1688
|
+
/** The `type` discriminator string (kebab-case by convention). */
|
|
1689
|
+
readonly type: TData['type'];
|
|
1690
|
+
/**
|
|
1691
|
+
* The activity's data contract, as a Standard Schema whose output is the
|
|
1692
|
+
* data. Its validation must be synchronous: every entry point that reads it
|
|
1693
|
+
* is.
|
|
1694
|
+
*/
|
|
1695
|
+
readonly schema: StandardSchemaV1<unknown, TData>;
|
|
1696
|
+
/**
|
|
1697
|
+
* The contract as JSON Schema, for `jsonSchemaFor`. Leave it out when
|
|
1698
|
+
* `schema` can produce one itself through the Standard JSON Schema converter
|
|
1699
|
+
* (`'~standard'.jsonSchema`), as a zod 4.6 schema can; give it to override
|
|
1700
|
+
* that, or for a library that cannot.
|
|
1701
|
+
*/
|
|
1702
|
+
readonly jsonSchema?: Readonly<Record<string, unknown>>;
|
|
1703
|
+
/** How responses are graded. */
|
|
1704
|
+
readonly scoring: ActivityTypeScoring<TData, TResponse>;
|
|
1705
|
+
/** Whether a response counts as an answer (vs. blank/untouched). */
|
|
1706
|
+
readonly isAnswered?: (response: TResponse | undefined) => boolean;
|
|
1707
|
+
/** Per-field sensitivity map driving `redact()`. Fail-closed. */
|
|
1708
|
+
readonly fieldPolicy?: FieldPolicy;
|
|
1709
|
+
/**
|
|
1710
|
+
* Schema the output of `redact(data)` (with default `reveal: 'none'`) must
|
|
1711
|
+
* satisfy, as a Standard Schema. Strict by design: it proves the ABSENCE of
|
|
1712
|
+
* answer-key fields, so `assertRedacted` can guarantee a payload is safe to
|
|
1713
|
+
* send to a learner.
|
|
1714
|
+
*/
|
|
1715
|
+
readonly redactedSchema?: StandardSchemaV1;
|
|
1716
|
+
/** Interop facts for xAPI (and later QTI) statement building. */
|
|
1717
|
+
readonly interop?: ActivityTypeInterop<TData>;
|
|
1718
|
+
/** The interaction-event kinds components for this type emit. */
|
|
1719
|
+
readonly interactions?: readonly string[];
|
|
1720
|
+
/** Draft support for authoring tools. See {@link ActivityTypeAuthoring}. */
|
|
1721
|
+
readonly authoring?: ActivityTypeAuthoring<TData>;
|
|
1494
1722
|
}
|
|
1495
1723
|
/**
|
|
1496
1724
|
* Internal type-erased descriptor shape stored in the registry. Dispatch call
|
|
1497
1725
|
* sites cast payloads back; the public generic API preserves inference.
|
|
1498
1726
|
*/
|
|
1499
1727
|
interface RegisteredActivityTypeDescriptor {
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1728
|
+
readonly type: string;
|
|
1729
|
+
readonly schema: StandardSchemaV1;
|
|
1730
|
+
readonly jsonSchema?: Readonly<Record<string, unknown>>;
|
|
1731
|
+
readonly scoring: {
|
|
1732
|
+
readonly kind: 'sync';
|
|
1733
|
+
readonly score: (data: unknown, response: unknown) => PartialScoringResult;
|
|
1734
|
+
} | {
|
|
1735
|
+
readonly kind: 'deferred';
|
|
1736
|
+
readonly reason: 'requires_async_grading';
|
|
1737
|
+
readonly partial?: (data: unknown, response: unknown) => DeferredScoringPartial;
|
|
1738
|
+
};
|
|
1739
|
+
readonly isAnswered?: (response: unknown) => boolean;
|
|
1740
|
+
readonly fieldPolicy?: FieldPolicy;
|
|
1741
|
+
readonly redactedSchema?: StandardSchemaV1;
|
|
1742
|
+
readonly interop?: ActivityTypeInterop<unknown>;
|
|
1743
|
+
readonly interactions?: readonly string[];
|
|
1744
|
+
readonly authoring?: ActivityTypeAuthoring<unknown>;
|
|
1517
1745
|
}
|
|
1518
|
-
/**
|
|
1519
|
-
* Identity helper that gives full type inference when authoring a descriptor:
|
|
1520
|
-
*
|
|
1521
|
-
* ```ts
|
|
1522
|
-
* const myType = defineActivityType<MyTypeData, MyTypeLearnerResponse>({ ... });
|
|
1523
|
-
* registerActivityType(myType);
|
|
1524
|
-
* ```
|
|
1525
|
-
*/
|
|
1526
|
-
declare function defineActivityType<TData extends {
|
|
1527
|
-
type: string;
|
|
1528
|
-
}, TResponse>(descriptor: ActivityTypeDescriptor<TData, TResponse>): ActivityTypeDescriptor<TData, TResponse>;
|
|
1529
1746
|
/**
|
|
1530
1747
|
* Registers an activity type on the default registry, making it live for
|
|
1531
1748
|
* `validateActivity`, `score`, `evaluate`, `redact`, and `jsonSchemaFor`.
|
|
@@ -1534,14 +1751,15 @@ declare function defineActivityType<TData extends {
|
|
|
1534
1751
|
* type's contract or scoring is exactly the class of accident a summative
|
|
1535
1752
|
* SDK must not allow.
|
|
1536
1753
|
*/
|
|
1537
|
-
declare function registerActivityType<TData extends {
|
|
1538
|
-
|
|
1754
|
+
export declare function registerActivityType<TData extends {
|
|
1755
|
+
type: string;
|
|
1539
1756
|
}, TResponse>(descriptor: ActivityTypeDescriptor<TData, TResponse>): void;
|
|
1540
1757
|
/** Returns the registered descriptor for `type`, or `undefined`. */
|
|
1541
|
-
declare function getActivityTypeDescriptor(type: string): RegisteredActivityTypeDescriptor | undefined;
|
|
1758
|
+
export declare function getActivityTypeDescriptor(type: string): RegisteredActivityTypeDescriptor | undefined;
|
|
1542
1759
|
/** The type strings currently registered (built-ins plus consumer-registered). */
|
|
1543
|
-
declare function registeredActivityTypes(): string[];
|
|
1544
|
-
|
|
1760
|
+
export declare function registeredActivityTypes(): string[];
|
|
1761
|
+
//#endregion
|
|
1762
|
+
//#region src/redact.d.ts
|
|
1545
1763
|
/**
|
|
1546
1764
|
* A learner-safe projection of activity data produced by {@link redact}:
|
|
1547
1765
|
* the activity's public fields plus the `redacted: true` marker. Renderable
|
|
@@ -1549,49 +1767,49 @@ declare function registeredActivityTypes(): string[];
|
|
|
1549
1767
|
* but stripped of the answer key, scoring rules, authored feedback, and
|
|
1550
1768
|
* author-only assets.
|
|
1551
1769
|
*/
|
|
1552
|
-
interface RedactedActivityData {
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1770
|
+
export interface RedactedActivityData {
|
|
1771
|
+
redacted: true;
|
|
1772
|
+
schemaVersion: string;
|
|
1773
|
+
type: string;
|
|
1774
|
+
id: string;
|
|
1775
|
+
title: string;
|
|
1776
|
+
[key: string]: unknown;
|
|
1559
1777
|
}
|
|
1560
1778
|
/** Options for {@link redact}. */
|
|
1561
|
-
interface RedactOptions {
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1779
|
+
export interface RedactOptions {
|
|
1780
|
+
/**
|
|
1781
|
+
* Which sensitivity tiers to keep beyond `public`:
|
|
1782
|
+
* - `'none'` (default) — public fields only; the output satisfies the
|
|
1783
|
+
* type's strict redacted schema and `assertRedacted`.
|
|
1784
|
+
* - `'after-submit'` — public + answer-key fields (for post-submission
|
|
1785
|
+
* review renders). `author-only` fields and unclassified fields are
|
|
1786
|
+
* STILL removed; the output will NOT pass `assertRedacted`.
|
|
1787
|
+
*/
|
|
1788
|
+
reveal?: 'none' | 'after-submit';
|
|
1789
|
+
/**
|
|
1790
|
+
* Per-call sensitivity overrides, merged over the type's registered
|
|
1791
|
+
* `fieldPolicy` (top-level keys replace; nested objects merge one level).
|
|
1792
|
+
*
|
|
1793
|
+
* Sensitivity is partly a PEDAGOGICAL decision, not purely a security one —
|
|
1794
|
+
* whether a rubric or a hint is learner-visible differs legitimately between
|
|
1795
|
+
* deployments — and the SDK must not freeze that choice. Use this to tighten
|
|
1796
|
+
* a field the SDK ships as `public`:
|
|
1797
|
+
*
|
|
1798
|
+
* ```ts
|
|
1799
|
+
* redact(essay, { policy: { rubric: 'author-only' } });
|
|
1800
|
+
* ```
|
|
1801
|
+
*
|
|
1802
|
+
* Overrides can only be applied to fields; they cannot re-open a field the
|
|
1803
|
+
* caller has not classified, because unclassified still means removed.
|
|
1804
|
+
* What can be tightened is a field the type's `redactedSchema` leaves
|
|
1805
|
+
* OPTIONAL, as it leaves the rubric above: the schema check rejects a
|
|
1806
|
+
* payload that reveals more than the learner-safe shape, and equally one
|
|
1807
|
+
* that is missing part of it. Tightening a field the redacted shape requires
|
|
1808
|
+
* — a read-aloud item's `scoring`, `recording`, `referenceText` or `locale`,
|
|
1809
|
+
* without which the learner has no item to read — throws
|
|
1810
|
+
* {@link ActivitySchemaError} instead of hiding it.
|
|
1811
|
+
*/
|
|
1812
|
+
policy?: FieldPolicy;
|
|
1595
1813
|
}
|
|
1596
1814
|
/**
|
|
1597
1815
|
* Produces the learner-safe projection of activity data (R7), driven by the
|
|
@@ -1608,8 +1826,8 @@ interface RedactOptions {
|
|
|
1608
1826
|
* @throws Error when the registered descriptor declares no `fieldPolicy`
|
|
1609
1827
|
* (redaction cannot guess sensitivities).
|
|
1610
1828
|
*/
|
|
1611
|
-
declare function redact<T extends {
|
|
1612
|
-
|
|
1829
|
+
export declare function redact<T extends {
|
|
1830
|
+
type: string;
|
|
1613
1831
|
}>(data: T, options?: RedactOptions): RedactedActivityData;
|
|
1614
1832
|
/**
|
|
1615
1833
|
* Asserts that `data` is a learner-safe redacted projection: it carries the
|
|
@@ -1618,10 +1836,10 @@ declare function redact<T extends {
|
|
|
1618
1836
|
* Use this at the server boundary before sending activity data to a client
|
|
1619
1837
|
* that must not hold the key.
|
|
1620
1838
|
*/
|
|
1621
|
-
declare function assertRedacted(data: unknown): asserts data is RedactedActivityData;
|
|
1839
|
+
export declare function assertRedacted(data: unknown): asserts data is RedactedActivityData;
|
|
1622
1840
|
/** A learner-safe item group: the container with its marker, holding `redact()` projections. */
|
|
1623
|
-
type RedactedItemGroup = ItemGroup<RedactedActivityData> & {
|
|
1624
|
-
|
|
1841
|
+
export type RedactedItemGroup = ItemGroup<RedactedActivityData> & {
|
|
1842
|
+
redacted: true;
|
|
1625
1843
|
};
|
|
1626
1844
|
/**
|
|
1627
1845
|
* Produces the learner-safe projection of an item group: the container and
|
|
@@ -1633,8 +1851,8 @@ type RedactedItemGroup = ItemGroup<RedactedActivityData> & {
|
|
|
1633
1851
|
* With the default `reveal: 'none'` the container is verified against the
|
|
1634
1852
|
* strict redacted schema; each item was already verified by `redact`.
|
|
1635
1853
|
*/
|
|
1636
|
-
declare function redactItemGroup<TItem extends {
|
|
1637
|
-
|
|
1854
|
+
export declare function redactItemGroup<TItem extends {
|
|
1855
|
+
type: string;
|
|
1638
1856
|
}>(group: ItemGroup<TItem>, options?: RedactOptions): RedactedItemGroup;
|
|
1639
1857
|
/**
|
|
1640
1858
|
* Asserts that `data` is a learner-safe item group: it carries the marker,
|
|
@@ -1644,12 +1862,13 @@ declare function redactItemGroup<TItem extends {
|
|
|
1644
1862
|
* failures are reported at `items.<index>.…`. Use it at the server boundary
|
|
1645
1863
|
* before sending a group to a client that must not hold the key.
|
|
1646
1864
|
*/
|
|
1647
|
-
declare function assertRedactedItemGroup(data: unknown): asserts data is RedactedItemGroup;
|
|
1648
|
-
|
|
1865
|
+
export declare function assertRedactedItemGroup(data: unknown): asserts data is RedactedItemGroup;
|
|
1866
|
+
//#endregion
|
|
1867
|
+
//#region src/registry/builtins.d.ts
|
|
1649
1868
|
/** Built-in Multiple Choice descriptor. */
|
|
1650
|
-
declare const multipleChoiceType: ActivityTypeDescriptor<MultipleChoiceData, MultipleChoiceLearnerResponse>;
|
|
1869
|
+
export declare const multipleChoiceType: ActivityTypeDescriptor<MultipleChoiceData, MultipleChoiceLearnerResponse>;
|
|
1651
1870
|
/** Built-in Fill-in-the-Blanks descriptor. */
|
|
1652
|
-
declare const fillInTheBlanksType: ActivityTypeDescriptor<FillInTheBlanksData, FillInTheBlanksLearnerResponse>;
|
|
1871
|
+
export declare const fillInTheBlanksType: ActivityTypeDescriptor<FillInTheBlanksData, FillInTheBlanksLearnerResponse>;
|
|
1653
1872
|
/**
|
|
1654
1873
|
* Built-in Written Response descriptor. Grading is DEFERRED: submissions are
|
|
1655
1874
|
* graded asynchronously (AI or human) by the consumer; the synchronous
|
|
@@ -1657,23 +1876,24 @@ declare const fillInTheBlanksType: ActivityTypeDescriptor<FillInTheBlanksData, F
|
|
|
1657
1876
|
* submitted text with the canonical `countWords()` — the client-supplied
|
|
1658
1877
|
* count is informational, never trusted.
|
|
1659
1878
|
*/
|
|
1660
|
-
declare const writtenResponseType: ActivityTypeDescriptor<WrittenResponseData, WrittenResponseLearnerResponse>;
|
|
1879
|
+
export declare const writtenResponseType: ActivityTypeDescriptor<WrittenResponseData, WrittenResponseLearnerResponse>;
|
|
1661
1880
|
/** Built-in Gap Select descriptor. */
|
|
1662
|
-
declare const gapSelectType: ActivityTypeDescriptor<GapSelectData, GapSelectLearnerResponse>;
|
|
1881
|
+
export declare const gapSelectType: ActivityTypeDescriptor<GapSelectData, GapSelectLearnerResponse>;
|
|
1663
1882
|
/**
|
|
1664
1883
|
* Built-in Dictation descriptor. Graded synchronously: the score is the
|
|
1665
1884
|
* character-level similarity of the typed text to the transcript, a pure
|
|
1666
1885
|
* computation identical in a browser and on a server.
|
|
1667
1886
|
*/
|
|
1668
|
-
declare const dictationType: ActivityTypeDescriptor<DictationData, DictationLearnerResponse>;
|
|
1887
|
+
export declare const dictationType: ActivityTypeDescriptor<DictationData, DictationLearnerResponse>;
|
|
1669
1888
|
/**
|
|
1670
1889
|
* Built-in Read Aloud descriptor. Grading is DEFERRED: the SDK calls no
|
|
1671
1890
|
* assessor, so the synchronous outcome reports only whether a recording was
|
|
1672
1891
|
* stored, and `gradeReadAloud` produces the grade once the application holds a
|
|
1673
1892
|
* speech assessment.
|
|
1674
1893
|
*/
|
|
1675
|
-
declare const readAloudType: ActivityTypeDescriptor<ReadAloudData, ReadAloudLearnerResponse>;
|
|
1676
|
-
|
|
1894
|
+
export declare const readAloudType: ActivityTypeDescriptor<ReadAloudData, ReadAloudLearnerResponse>;
|
|
1895
|
+
//#endregion
|
|
1896
|
+
//#region src/shuffle.d.ts
|
|
1677
1897
|
/**
|
|
1678
1898
|
* Seeded, deterministic shuffling — the ONE algorithm every presentation-order
|
|
1679
1899
|
* decision in the SDK goes through: option order in a multiple-choice item,
|
|
@@ -1688,7 +1908,7 @@ declare const readAloudType: ActivityTypeDescriptor<ReadAloudData, ReadAloudLear
|
|
|
1688
1908
|
* permutation test exists so an accidental one fails loudly.
|
|
1689
1909
|
*/
|
|
1690
1910
|
/** FNV-1a hash of a string → unsigned 32-bit integer. */
|
|
1691
|
-
declare function hashSeed(input: string): number;
|
|
1911
|
+
export declare function hashSeed(input: string): number;
|
|
1692
1912
|
/**
|
|
1693
1913
|
* Which draw the Fisher–Yates step uses.
|
|
1694
1914
|
*
|
|
@@ -1720,11 +1940,16 @@ declare function hashSeed(input: string): number;
|
|
|
1720
1940
|
* is a package major — scheduled, not smuggled in. Choose v2 for new content
|
|
1721
1941
|
* where no attempt has been recorded yet.
|
|
1722
1942
|
*/
|
|
1723
|
-
type ShuffleVersion = 1 | 2;
|
|
1943
|
+
export type ShuffleVersion = 1 | 2;
|
|
1724
1944
|
/** Options for {@link seededShuffle}. */
|
|
1725
|
-
interface SeededShuffleOptions {
|
|
1726
|
-
|
|
1727
|
-
|
|
1945
|
+
export interface SeededShuffleOptions {
|
|
1946
|
+
/**
|
|
1947
|
+
* Draw algorithm — see {@link ShuffleVersion}. Left out, it is `1`; leaving
|
|
1948
|
+
* it out is deprecated since lk-core 1.3, since a 2.0 may make `2` the
|
|
1949
|
+
* default. Name it: `1` to reproduce an order already recorded, `2` for new
|
|
1950
|
+
* content.
|
|
1951
|
+
*/
|
|
1952
|
+
version?: ShuffleVersion;
|
|
1728
1953
|
}
|
|
1729
1954
|
/**
|
|
1730
1955
|
* Returns a new array holding a permutation of `items` determined entirely by
|
|
@@ -1735,8 +1960,17 @@ interface SeededShuffleOptions {
|
|
|
1735
1960
|
* (`${attemptId}:${itemId}`), so two shuffles in one attempt do not share an
|
|
1736
1961
|
* order.
|
|
1737
1962
|
*/
|
|
1738
|
-
declare function seededShuffle<T>(items: readonly T[], seed: string, options
|
|
1739
|
-
|
|
1963
|
+
export declare function seededShuffle<T>(items: readonly T[], seed: string, options: SeededShuffleOptions & {
|
|
1964
|
+
version: ShuffleVersion;
|
|
1965
|
+
}): T[];
|
|
1966
|
+
/**
|
|
1967
|
+
* @deprecated Since lk-core 1.3, name the version: `{ version: 1 }` draws
|
|
1968
|
+
* exactly what this does, `{ version: 2 }` reaches every order. A 2.0 may make
|
|
1969
|
+
* `2` the default, which would re-order what this call returns.
|
|
1970
|
+
*/
|
|
1971
|
+
export declare function seededShuffle<T>(items: readonly T[], seed: string, options?: SeededShuffleOptions): T[];
|
|
1972
|
+
//#endregion
|
|
1973
|
+
//#region src/timeline.d.ts
|
|
1740
1974
|
/**
|
|
1741
1975
|
* Reads a stored {@link MediaProgress}. Never throws: anything that is not one
|
|
1742
1976
|
* — a string, a stale shape, an object whose getters throw — answers `null`,
|
|
@@ -1748,7 +1982,7 @@ declare function seededShuffle<T>(items: readonly T[], seed: string, options?: S
|
|
|
1748
1982
|
* re-cut must not put the playhead somewhere it cannot be. Give `duration`
|
|
1749
1983
|
* once the video's metadata is known, and both positions are held inside it.
|
|
1750
1984
|
*/
|
|
1751
|
-
declare function readMediaProgress(value: unknown, duration?: number): MediaProgress | null;
|
|
1985
|
+
export declare function readMediaProgress(value: unknown, duration?: number): MediaProgress | null;
|
|
1752
1986
|
/**
|
|
1753
1987
|
* One interactive video's composed result: the scored items whose slot belongs
|
|
1754
1988
|
* to the entry, composed as one section of weight 1. A slot belongs when
|
|
@@ -1763,8 +1997,9 @@ declare function readMediaProgress(value: unknown, duration?: number): MediaProg
|
|
|
1763
1997
|
* otherwise compose nothing into a `final` result, and a refusal must
|
|
1764
1998
|
* never read as a grade.
|
|
1765
1999
|
*/
|
|
1766
|
-
declare function composeTimelineScore(entryKey: string, items: readonly ScoredItem[], policy: CompositionPolicy): AssessmentScore;
|
|
1767
|
-
|
|
2000
|
+
export declare function composeTimelineScore(entryKey: string, items: readonly ScoredItem[], policy: CompositionPolicy): AssessmentScore;
|
|
2001
|
+
//#endregion
|
|
2002
|
+
//#region src/timeline-limits.d.ts
|
|
1768
2003
|
/**
|
|
1769
2004
|
* The bounds of an interactive video — an item group with a `timeline`.
|
|
1770
2005
|
*
|
|
@@ -1778,78 +2013,80 @@ declare function composeTimelineScore(entryKey: string, items: readonly ScoredIt
|
|
|
1778
2013
|
* a read-aloud's microphone included, because every quiz pauses the video
|
|
1779
2014
|
* first.
|
|
1780
2015
|
*/
|
|
1781
|
-
declare const INTERACTIVE_VIDEO_ITEM_TYPES: readonly ["multiple-choice", "fill-in-the-blanks", "gap-select", "dictation", "read-aloud"];
|
|
2016
|
+
export declare const INTERACTIVE_VIDEO_ITEM_TYPES: readonly ["multiple-choice", "fill-in-the-blanks", "gap-select", "dictation", "read-aloud"];
|
|
1782
2017
|
/** One of {@link INTERACTIVE_VIDEO_ITEM_TYPES}. */
|
|
1783
|
-
type InteractiveVideoItemType = (typeof INTERACTIVE_VIDEO_ITEM_TYPES)[number];
|
|
2018
|
+
export type InteractiveVideoItemType = (typeof INTERACTIVE_VIDEO_ITEM_TYPES)[number];
|
|
1784
2019
|
/** Whether `type` is one of the item types an interactive video may present. */
|
|
1785
|
-
declare function isInteractiveVideoItemType(type: unknown): type is InteractiveVideoItemType;
|
|
2020
|
+
export declare function isInteractiveVideoItemType(type: unknown): type is InteractiveVideoItemType;
|
|
1786
2021
|
/** The most quizzes one video may hold. */
|
|
1787
|
-
declare const TIMELINE_MAX_QUIZZES = 100;
|
|
2022
|
+
export declare const TIMELINE_MAX_QUIZZES = 100;
|
|
1788
2023
|
/**
|
|
1789
2024
|
* The most questions one interactive video may hold, across all its quizzes.
|
|
1790
2025
|
* The player keeps every one of them mounted, so an answer survives the
|
|
1791
2026
|
* learner rewinding past its quiz.
|
|
1792
2027
|
*/
|
|
1793
|
-
declare const TIMELINE_MAX_ITEMS = 200;
|
|
2028
|
+
export declare const TIMELINE_MAX_ITEMS = 200;
|
|
1794
2029
|
/** The most chapters one video may hold. */
|
|
1795
|
-
declare const TIMELINE_MAX_CHAPTERS = 100;
|
|
2030
|
+
export declare const TIMELINE_MAX_CHAPTERS = 100;
|
|
1796
2031
|
/** The longest quiz or chapter title, in UTF-16 units. A title sits on one line of the player. */
|
|
1797
|
-
declare const TIMELINE_MAX_TITLE_LENGTH = 120;
|
|
1798
|
-
|
|
2032
|
+
export declare const TIMELINE_MAX_TITLE_LENGTH = 120;
|
|
2033
|
+
//#endregion
|
|
2034
|
+
//#region src/types/theme.d.ts
|
|
1799
2035
|
/**
|
|
1800
2036
|
* All CSS custom property tokens consumed by learning-kit components.
|
|
1801
2037
|
* Every key maps to a `--lk-*` CSS variable name; every value is a CSS value string.
|
|
1802
2038
|
* Pass a `Partial<ThemeTokens>` to `ThemeProvider` to override individual tokens.
|
|
1803
2039
|
*/
|
|
1804
2040
|
interface ThemeTokens {
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
2041
|
+
'--lk-color-primary': string;
|
|
2042
|
+
'--lk-color-primary-hover': string;
|
|
2043
|
+
'--lk-color-surface': string;
|
|
2044
|
+
'--lk-color-surface-raised': string;
|
|
2045
|
+
'--lk-color-border': string;
|
|
2046
|
+
'--lk-color-text': string;
|
|
2047
|
+
'--lk-color-text-muted': string;
|
|
2048
|
+
'--lk-color-success': string;
|
|
2049
|
+
'--lk-color-error': string;
|
|
2050
|
+
'--lk-color-warning': string;
|
|
2051
|
+
'--lk-color-focus-ring': string;
|
|
2052
|
+
/**
|
|
2053
|
+
* The accent a video player draws on its own dark chrome: the played part
|
|
2054
|
+
* of the progress bar, quiz markers, the centre play button. Optional, so a
|
|
2055
|
+
* theme written before it existed still type-checks; the default is white,
|
|
2056
|
+
* which reads on any video. Set it to a brand colour to match a product.
|
|
2057
|
+
*/
|
|
2058
|
+
'--lk-color-media-accent'?: string;
|
|
2059
|
+
/**
|
|
2060
|
+
* The interactive video's drawn captions. Optional like the accent above, so
|
|
2061
|
+
* a theme written before them still type-checks. The primary line's colour;
|
|
2062
|
+
* the second language's colour, which must clear 4.5:1 on the caption box;
|
|
2063
|
+
* the second line's size as a share of the first (a number, e.g. `0.85`);
|
|
2064
|
+
* and the space between the two lines. The second line differs from the
|
|
2065
|
+
* first by position and size as well as colour: colour alone would fail
|
|
2066
|
+
* WCAG 1.4.1.
|
|
2067
|
+
*/
|
|
2068
|
+
'--lk-iv-caption-color'?: string;
|
|
2069
|
+
'--lk-iv-caption-secondary-color'?: string;
|
|
2070
|
+
'--lk-iv-caption-secondary-scale'?: string;
|
|
2071
|
+
'--lk-iv-caption-gap'?: string;
|
|
2072
|
+
'--lk-spacing-xs': string;
|
|
2073
|
+
'--lk-spacing-sm': string;
|
|
2074
|
+
'--lk-spacing-md': string;
|
|
2075
|
+
'--lk-spacing-lg': string;
|
|
2076
|
+
'--lk-spacing-xl': string;
|
|
2077
|
+
'--lk-font-family-base': string;
|
|
2078
|
+
'--lk-font-size-sm': string;
|
|
2079
|
+
'--lk-font-size-base': string;
|
|
2080
|
+
'--lk-font-size-lg': string;
|
|
2081
|
+
'--lk-font-weight-normal': string;
|
|
2082
|
+
'--lk-font-weight-bold': string;
|
|
2083
|
+
'--lk-line-height-base': string;
|
|
2084
|
+
'--lk-radius-sm': string;
|
|
2085
|
+
'--lk-radius-base': string;
|
|
2086
|
+
'--lk-radius-lg': string;
|
|
2087
|
+
'--lk-transition-fast': string;
|
|
2088
|
+
'--lk-transition-base': string;
|
|
1853
2089
|
}
|
|
1854
|
-
|
|
1855
|
-
export {
|
|
2090
|
+
//#endregion
|
|
2091
|
+
export { type ActivityAiPermissions, type ActivityData, type ActivityDataMap, type ActivityFeedback, type ActivityMedia, type ActivityResult, type ActivityType, type ActivityTypeAuthoring, type ActivityTypeDescriptor, type ActivityTypeInterop, type ActivityTypeScoring, type AiActivityInput, type AiBlankFact, type AiCoaching, type AiCoachingRequest, type AiCoachingResult, type AiCoachingWord, type AiCriterionJudgement, type AiCritique, type AiCritiqueField, type AiCritiqueFinding, type AiCritiqueFindingResult, type AiCritiqueKind, type AiCritiqueRequest, type AiCritiqueResult, type AiDictationFacts, type AiDraftCaption, type AiDraftProblem, type AiDraftSettings, type AiDraftSource, type AiDraftType, type AiDrafts, type AiDraftsCall, type AiDraftsRequest, type AiDraftsRun, type AiExplanationRequest, type AiFeature, type AiFillInTheBlanksFacts, type AiGapFact, type AiGapSelectFacts, type AiGeneratedDraft, type AiGrade, type AiHintRequest, type AiItemFacts, type AiMultipleChoiceFacts, type AiOptionFact, type AiProvenance, type AiReadingFacts, type AiReadingWordFact, type AiRefusal, type AiRubricCriterionFact, type AiSoundFact, type AiSupportedActivityType, type AiTextResult, type AiVerdict, type AiVideoDraft, type AiWordFact, type AiWritingCorrection, type AiWritingFacts, type AiWritingFeedback, type AiWritingFeedbackRequest, type AiWritingFeedbackResult, type AnsweredStatementParams, type AssessmentScore, type AssessmentSectionInput, type AttemptPlan, type AttemptPlanDrift, type AttemptPlanSlot, type AttemptState, type Band, type BlankConfig, type BuiltInActivityType, type CompletedStatementParams, type CompositionPolicy, type CriterionScore, DEFAULT_ITEM_SCORING_POLICY, DEFAULT_PASS_THRESHOLD, DICTATION_MAX_ACCEPTED_TRANSCRIPTS, DICTATION_MAX_EQUIVALENCES, DICTATION_MAX_EQUIVALENCE_LENGTH, DICTATION_MAX_TEXT_LENGTH, DICTATION_MAX_TRANSCRIPT_LENGTH, type DeferredReason, type DeferredScoringPartial, type DeliveryPolicy, type DeliveryPolicyIssue, type DictationAlignment, type DictationCharOp, type DictationData, type DictationEquivalence, type DictationLearnerResponse, type DictationReference, type DictationSlowMedia, type DictationTolerance, type DictationWordAlignment, type DraftComplete, type DraftContext, type DraftIssue, type DraftNotComplete, type DraftSeverity, type DraftValidationResult, EvaluateOptions, type FieldPolicy, type FillInTheBlanksData, type FillInTheBlanksLearnerResponse, type GapSelectBank, type GapSelectChoice, type GapSelectData, type GapSelectGap, type GapSelectLearnerResponse, type GradeReadAloudOptions, type GradeRecord, type Grader, type GraderKind, type GraderUsage, type GradingState, ITEM_SCORING_MAX_RETRIES, type InlineCorrection, type InteractionEvent, type InteractionKind, type ItemFinding, type ItemFindingSeverity, type ItemGroup, type ItemOutcome, type ItemScoringCount, type ItemScoringPolicy, type ItemScoringPolicyIssue, ItemTriesOutcome, type ItemTriesScore, type ItemTry, type ItemTryScore, type LearnerResponse, type LearnerResponseMap, type MediaBudgetRef, type MediaPlayClaim, type MediaPlayGrant, type MediaPlayLedger, type MediaPlayLedgerEntry, type MediaPlaybackPolicy, type MediaProgress, type MediaTimeline, type MediaTrack, type MultipleChoiceData, type MultipleChoiceLearnerResponse, type MultipleChoiceOption, type MultipleChoiceOptionMedia, type NativeControlHint, type PartialScoringResult, type PassFailureReason, READ_ALOUD_MAX_DIMENSION_WEIGHT, READ_ALOUD_MAX_REFERENCE_LENGTH, READ_ALOUD_MAX_SECONDS, READ_ALOUD_MAX_TAKES, type ReadAloudData, type ReadAloudDimension, type ReadAloudDimensionWeight, type ReadAloudLearnerResponse, type ReadAloudSlowMedia, type ReadAloudWordAlignment, type ReadAloudWordState, type RecordingBounds, type RecordingRef, type RedactedActivity, type RedactedBlankConfig, type RedactedDictationData, type RedactedDictationSlowMedia, type RedactedFillInTheBlanksData, type RedactedGapSelectBank, type RedactedGapSelectChoice, type RedactedGapSelectData, type RedactedGapSelectGap, type RedactedMultipleChoiceData, type RedactedMultipleChoiceOption, type RedactedMultipleChoiceOptionMedia, type RedactedReadAloudData, type RedactedStimulus, type RedactedWrittenResponseData, type RegisteredActivityTypeDescriptor, type ResolvedDeliveryPolicy, type ResolvedItemScoringPolicy, type ResponseDiffEntry, type RoundingMode, type RoundingPolicy, SPEECH_ASSESSMENT_MAX_WORDS, type ScoredItem, type ScoringDetail, ScoringOptions, type ScoringOutcome, type ScoringResult, type SectionScore, type Sensitivity, type SequenceEntry, type SequenceSlot, type SequenceSlotGroup, type SpeechAssessment, type SpeechMeasurement, type SpeechPhoneme, type SpeechPhonemeCandidate, type SpeechPlausibilityPolicy, type SpeechSyllable, type SpeechUnscorable, type SpeechUnscorableCode, type SpeechWord, type SpeechWordError, type StandardSchemaV1, type Stimulus, type StimulusKind, type SubmittedStatementParams, type TextMatchPolicy, type TextMatchResult, type ThemeTokens, type TimelineChapter, type TimelineCue, type ValidationError, type ValidationResult, type WavInspection, type WavInspectionPolicy, type WrittenResponseData, type WrittenResponseLearnerResponse, type WrittenResponseRubric, type WrittenResponseRubricCriterion, type XAPIActor, type XAPIConfig, type XAPIContext, type XAPIContextActivities, type XAPIError, type XAPIInteractionType, type XAPIObject, type XAPIObjectParams, type XAPIResult, type XAPIScore, type XAPIStatement, type XAPIStatementParams, XAPIVerb, type XAPIVerbKey, type XAPIVerbObject, XAPI_VERB_DISPLAY, alignDictation, alignReadAloud, classifyBand, composeAssessmentScore, computePassThreshold, dictationJsonSchema, dictationReferenceWords, diffDictationChars, evaluate, evaluateTries, fillInTheBlanksJsonSchema, gapSelectJsonSchema, gradeReadAloud, gte, inspectWav, itemGroupJsonSchema, jsonSchemaFor, levenshteinDistance, matchText, multipleChoiceJsonSchema, outcomeFromUnscorable, readAloudJsonSchema, resolveItemScoringPolicy, roundGrade, score, scoreTries, stimulusJsonSchema, validateActivity, validateItemGroup, validateItemScoringPolicy, validateMedia, validateOptionMedia, validateSpeechAssessment, validateXAPIStatement, writtenResponseJsonSchema, xAPIBuilder, xapiDefinitionFor };
|
|
2092
|
+
//# sourceMappingURL=index.d.cts.map
|