@intellectif/lk-core 0.21.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +6 -5
  3. package/dist/{activity-xhGV-Aeh.d.cts → activity-DgpBJeBc.d.cts} +137 -22
  4. package/dist/{activity-xhGV-Aeh.d.ts → activity-DgpBJeBc.d.ts} +137 -22
  5. package/dist/ai-check.cjs +104 -16
  6. package/dist/ai-check.cjs.map +1 -1
  7. package/dist/ai-check.d.cts +9 -5
  8. package/dist/ai-check.d.ts +9 -5
  9. package/dist/ai-check.js +103 -15
  10. package/dist/ai-check.js.map +1 -1
  11. package/dist/{chunk-2CV6NU32.cjs → chunk-2JT2WUQ2.cjs} +77 -39
  12. package/dist/chunk-2JT2WUQ2.cjs.map +1 -0
  13. package/dist/{chunk-D4TOPSHV.cjs → chunk-DSDXL3JO.cjs} +1216 -1105
  14. package/dist/chunk-DSDXL3JO.cjs.map +1 -0
  15. package/dist/{chunk-D3GP5MET.js → chunk-FBKTION6.js} +1093 -982
  16. package/dist/chunk-FBKTION6.js.map +1 -0
  17. package/dist/{chunk-Q7MV3IXJ.js → chunk-IARLJ5MW.js} +15 -16
  18. package/dist/chunk-IARLJ5MW.js.map +1 -0
  19. package/dist/{chunk-IHOEP4EB.js → chunk-RCZCP5OE.js} +311 -25
  20. package/dist/chunk-RCZCP5OE.js.map +1 -0
  21. package/dist/{chunk-X5DAXBJI.js → chunk-SJVRUPJT.js} +2 -2
  22. package/dist/{chunk-EOFWSGLU.cjs → chunk-TJJFKKH2.cjs} +4 -4
  23. package/dist/{chunk-EOFWSGLU.cjs.map → chunk-TJJFKKH2.cjs.map} +1 -1
  24. package/dist/{chunk-WQVZPIN7.cjs → chunk-VSH7ECQL.cjs} +44 -45
  25. package/dist/chunk-VSH7ECQL.cjs.map +1 -0
  26. package/dist/{chunk-NRTP7WCW.cjs → chunk-W5KB3DNT.cjs} +315 -29
  27. package/dist/chunk-W5KB3DNT.cjs.map +1 -0
  28. package/dist/{chunk-Z7QQZ53L.js → chunk-XS6U2ARZ.js} +70 -32
  29. package/dist/chunk-XS6U2ARZ.js.map +1 -0
  30. package/dist/index-BVNeSCWC.d.ts +548 -0
  31. package/dist/index-BlOLlwOi.d.cts +548 -0
  32. package/dist/index.cjs +129 -198
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +175 -18
  35. package/dist/index.d.ts +175 -18
  36. package/dist/index.js +34 -103
  37. package/dist/index.js.map +1 -1
  38. package/dist/schemas.cjs +3 -94
  39. package/dist/schemas.cjs.map +1 -1
  40. package/dist/schemas.d.cts +2 -3
  41. package/dist/schemas.d.ts +2 -3
  42. package/dist/schemas.js +6 -97
  43. package/dist/scoring.cjs +3 -3
  44. package/dist/scoring.d.cts +2 -2
  45. package/dist/scoring.d.ts +2 -2
  46. package/dist/scoring.js +2 -2
  47. package/dist/xapi.cjs +3 -3
  48. package/dist/xapi.d.cts +1 -1
  49. package/dist/xapi.d.ts +1 -1
  50. package/dist/xapi.js +2 -2
  51. package/package.json +4 -4
  52. package/vectors/README.md +32 -2
  53. package/vectors/scoring.json +1 -498
  54. package/vectors/validation.json +6742 -0
  55. package/vectors/validation.mjs +195 -0
  56. package/dist/chunk-2CV6NU32.cjs.map +0 -1
  57. package/dist/chunk-D3GP5MET.js.map +0 -1
  58. package/dist/chunk-D4TOPSHV.cjs.map +0 -1
  59. package/dist/chunk-IHOEP4EB.js.map +0 -1
  60. package/dist/chunk-NRTP7WCW.cjs.map +0 -1
  61. package/dist/chunk-Q7MV3IXJ.js.map +0 -1
  62. package/dist/chunk-WQVZPIN7.cjs.map +0 -1
  63. package/dist/chunk-Z7QQZ53L.js.map +0 -1
  64. package/dist/index-BuD8Hc8o.d.cts +0 -2303
  65. package/dist/index-DnJ_PI4d.d.ts +0 -2303
  66. /package/dist/{chunk-X5DAXBJI.js.map → chunk-SJVRUPJT.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @intellectif/lk-core
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#82](https://github.com/intellectif/learning-kit/pull/82) [`bcae525`](https://github.com/intellectif/learning-kit/commit/bcae52599d7d0481ccd8ceecdfc59f2bd6d4d281) Thanks [@diego28e](https://github.com/diego28e)! - **1.0**: what every 1.x keeps stable, written down, and from now on a lk-core minor releases no lk-react. No grade changes.
8
+
9
+ **Action required:** only if you read `ScoringDetail.correct`, import a zod schema from lk-core, or register an activity type of your own. Install lk-core 1.0.0 and lk-react 23.0.0 together. Each change and its replacement is in the upgrading guide: https://github.com/intellectif/learning-kit/blob/main/docs/upgrading.md
10
+
11
+ - **Stability:** grades, the public API, content and runtimes — what a 1.x release may and may not change — are set out in https://github.com/intellectif/learning-kit/blob/main/docs/stability.md. lk-react 23 peers on `@intellectif/lk-core@^1.0.0`, and a lk-core minor or patch releases no lk-react.
12
+ - **`ScoringDetail.correct` is removed, and `outcome` is required.** Deprecated since 0.3; on a multiple-choice option it meant "the learner acted rightly on it". Read `outcome`. The grade-stability corpus changed only there: 142 vectors lose `correct`, and no score, pass or feedback moves. A detail stored before 0.3 still carries only `correct`; the SDK's components still read it.
13
+ - **Zod is private to lk-core.** No zod schema is exported and no published type names zod, so your app can use any zod, or none. `validateMedia` and `validateOptionMedia` replace `MediaSchema.safeParse` and `MultipleChoiceOptionMediaSchema.safeParse`; `validateActivity`, `validateDraft` and `validateItemGroup` replace the rest. The `*JsonSchema` constants are typed `Record<string, unknown>`, and the `Redacted*` types are written out, unchanged in shape.
14
+ - **A type you register takes Standard Schemas** (https://standardschema.dev): `schema` and `redactedSchema` are `StandardSchemaV1`. A zod 4 schema is one as written; valibot and ArkType work too. Validation must be synchronous. `registerActivityType` throws on a value that is not a Standard Schema, and `jsonSchemaFor` on your type needs the descriptor's new `jsonSchema` unless the schema produces JSON Schema itself, as zod 4.6 does.
15
+ - **Built on zod 4.6.5, pinned exactly**, instead of the zod 4 preview in zod 3.25. A new zod reaches you only in a lk-core release. If your app uses another version of zod, your bundle carries two copies. Every built-in validation accepts and refuses what it did, checked against 0.21.0 on 28,000 inputs; from 1.0, `vectors/validation.json` in the tarball freezes that for over three thousand inputs, and each release replays it. Two error lists are one error shorter: a speech assessment with a string where a list of phonemes or syllables belongs, and an xAPI statement whose actor's `mbox` is not a `mailto:` address.
16
+ - **Fixed (lk-react):** a host's grade whose details carry no `correct` — every detail lk-core 1.0 writes — had all its details dropped, a read-aloud's word marks among them. It is now read.
17
+
18
+ ## 0.22.0
19
+
20
+ ### Minor Changes
21
+
22
+ - [#80](https://github.com/intellectif/learning-kit/pull/80) [`782b01b`](https://github.com/intellectif/learning-kit/commit/782b01ba697a90583b472ab1a7a2be102fd888c4) Thanks [@diego28e](https://github.com/diego28e)! - **Feedback on writing**: "Get feedback on my draft" on a written response in practice. The learner revises and asks again, and every correction must quote what they wrote.
23
+
24
+ **Action required:** none unless your code switches exhaustively over `AiFeature` or `AiRefusal` (new members `'writing-feedback'` and `'misquotes-answer'`), reads `AiCheckCase.request` without narrowing on `feature`, or implements a complete `LkStrings` (eight new keys). Nothing changes until you pass a `writingFeedback` port. Otherwise this is a major only because the peer range moves to `@intellectif/lk-core@^0.22.0`.
25
+
26
+ - **lk-core:** `aiWritingFeedbackRequest` builds what a model is given: the task, the draft verbatim, its word count as the grader counts it, the rubric, and the feedback on earlier drafts. `checkAiWritingFeedback` checks the reply before a learner sees it. It finds each correction's quote in the draft itself (typographic quotes and runs of whitespace folded, case kept) and anchors it there. A correction of words the draft does not contain refuses the whole reply as `misquotes-answer`. Criteria must be the rubric's; the author's weights are attached, and a model's weight is ignored. The indicative score is `gradeFromRubric`'s total, computed only when every criterion was judged. It is never a grade. Limits: 20 corrections, 500 characters a field.
27
+ - **lk-react:** a `writingFeedback` port and `maxWritingFeedback` (3 by default, at most 10) on `LearnerAi`. `<WrittenResponse>` shows the feedback with its corrections, rubric comments, the indicative score marked "Not a grade." and the AI notice, and says so once the draft has changed. It is never in `exam` or `review`, and it follows the author's and the paper's `ai.explanations`, `feedback` and `solutions`. `useAiWritingFeedback` gives a written response you draw yourself the same rules.
28
+ - **Records:** `ai-writing-feedback-shown` (the draft number, how many corrections, the indicative score, provenance and usage; never the text), and `ai-help-refused` with `feature: 'writing-feedback'`.
29
+ - **ai-check:** a `writingFeedback` port runs four writing cases: a draft with mistakes, one without, a revision, and feedback asked for in Spanish.
30
+ - Eight new strings: `aiWritingFeedback`, `aiWritingFeedbackLoading`, `aiWritingFeedbackHeading`, `aiWritingFeedbackUnavailable`, `aiNoMoreWritingFeedback`, `aiWritingFeedbackOutdated`, `aiCorrections`, `aiIndicativeScore`.
31
+
32
+ Guide: https://github.com/intellectif/learning-kit/blob/main/docs/ai.md#feedback-on-writing
33
+
3
34
  ## 0.21.0
4
35
 
5
36
  ### Minor Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @intellectif/lk-core
2
2
 
3
- Framework-free TypeScript core of [learning-kit](https://github.com/intellectif/learning-kit): Zod-based **activity schemas**, a pure **scoring engine**, **rubric and deferred grading**, **weighted assessment composition**, reproducible **exam attempt plans**, fail-closed **redaction**, and an **xAPI 1.0.3 statement builder + validator**. Zero React, zero DOM — usable in Node, browsers, edge, workers, or as the data layer behind `@intellectif/lk-react`.
3
+ Framework-free TypeScript core of [learning-kit](https://github.com/intellectif/learning-kit): **activity schemas and validation**, a pure **scoring engine**, **rubric and deferred grading**, **weighted assessment composition**, reproducible **exam attempt plans**, fail-closed **redaction**, and an **xAPI 1.0.3 statement builder + validator**. Zero React, zero DOM — usable in Node, browsers, edge, workers, or as the data layer behind `@intellectif/lk-react`.
4
4
 
5
5
  It is built for **summative** assessment as much as practice: nothing here grades on the client, "not marked yet" is a first-class outcome that is never conflated with a zero, and every behavioural change that could move a historical grade is opt-in. A frozen corpus of grading vectors ships in the package, fails CI if any of them moves, and can be replayed against the build you install.
6
6
 
@@ -28,6 +28,7 @@ npm install @intellectif/lk-core
28
28
  - **Item groups** — `Stimulus` + `ItemGroup` (one passage or recording serving several questions), `flattenSequence()` for seeded, shuffle-atomic presentation order with stable slot identity. Slot ids are positional by default (`"3"`, `"1.0"`); author a `slotKey` on an entry and its id survives an insert, so a stored response cannot slide onto a different question.
29
29
  - **Delivery policies** — `DeliveryPolicy` says what a school lets a learner see around a question: feedback, solutions, hints and AI help. `resolveDeliveryPolicy` spells one out (an unreadable setting restricts, never allows), `validateDeliveryPolicy` checks one before it is stored, and `combineDeliveryPolicies` keeps a setting on only where every policy leaves it on.
30
30
  - **Scoring policies** — `ItemScoringPolicy` says how a paper's questions are scored when a learner can try again or ask for hints: `retries`, which try `counts`, and what a try and a hint cost. `scoreTries` does the arithmetic, `evaluate(…, { scoring })` and `evaluateTries` reach a question's outcome from its answers, and `validateItemScoringPolicy` / `resolveItemScoringPolicy` refuse a policy that cannot be applied rather than guess — every setting moves a grade. No policy changes nothing, and the arithmetic is pinned by the grade vectors.
31
+ - **AI help contracts** — the SDK calls no model; it builds what yours is given and checks what comes back. `aiExplanationRequest`, `aiHintRequest` and `aiWritingFeedbackRequest` build the requests a component makes, so a server can rebuild them from its own copy of an item; `checkAiExplanation`, `checkAiHint` and `checkAiWritingFeedback` refuse an explanation that contradicts the grade, a hint that contains the answer, and writing feedback that corrects words the learner never wrote, and `checkAiWritingFeedback` computes the rubric's indicative score itself.
31
32
  - **Attempt plans** — `planAttempt(entries, { seed, shuffleEntries, points, delivery })` freezes the exact paper a learner sat, and the delivery policy it was sat under: slot order, per-slot points, a content hash of each item, and a `planHash` over the lot. `verifyAttemptPlan(plan, current)` reports the drift when that content is later edited (`changedSlotIds`, `changedStimulusSlotIds`, `changedPointsSlotIds`, `missingSlotIds`, …) — the thing you need during a remark or an appeal. `scoredItemsFromPlan(plan, outcomes)` turns collected outcomes into the `ScoredItem[]` composition wants, and defaults a slot with **no** outcome to `deferred` rather than silently shrinking the denominator.
32
33
  - **Attempt state** — `serializeAttemptState(plan, progress)` / `restoreAttemptState(plan, snapshot)` round-trip an interrupted attempt (responses, submitted slots, position) and are **bound to the plan**: restoring answers onto a paper the learner never sat throws instead of succeeding quietly. `diffResponses(before, after)` reports what moved between two snapshots, including an answer the learner *cleared*.
33
34
  - **Media playback policy** — `media.playback` on an audio recording: `maxPlays`, `seek`, `rate`, and advisory `nativeControlHints`. `resolvePlaybackPolicy()` derives the defaults once so the schema, the plan and the renderer cannot drift. Budgets are frozen into the plan by `planAttempt`, so editing `maxPlays` mid-window cannot change what a past learner was held to, and `planAttempt` refuses a paper where one recording is budgeted under two keys.
@@ -40,7 +41,7 @@ npm install @intellectif/lk-core
40
41
  - **xAPI builder** — `xAPIBuilder.buildAnsweredStatement(...)` / `buildSubmittedStatement(...)` / `buildCompletedStatement(...)` (plus `buildStatement(...)` for any verb) emit well-formed xAPI 1.0.3 statements with a v4 statement id and an ISO-8601 timestamp. Ids use `crypto.randomUUID()` where available and fall back to `crypto.getRandomValues()`, so statements stay well-formed on the non-secure origins `randomUUID` is gated behind.
41
42
  - **xAPI verbs for async grading** — `XAPIVerb.SUBMITTED` is emitted for work whose grade does not exist yet (`answered` would assert a score nobody computed), and `XAPIVerb.SCORED` is there for the grade that arrives later, often from a different actor. `XAPI_VERB_DISPLAY` supplies the `en-US` labels.
42
43
  - **`xapiDefinitionFor(data)`** — the xAPI interop descriptor (activity-type IRI, `cmi.interaction` type, `correctResponsesPattern`) for any registered type, so a consumer-registered activity gets correct interop with no component changes. Returns `{}` for an unregistered type, so it is always safe to spread.
43
- - **xAPI validator** — `validateXAPIStatement(statement)` (Zod-backed; throws on an invalid statement in development, warns in production).
44
+ - **xAPI validator** — `validateXAPIStatement(statement)` (throws on an invalid statement in development, warns in production).
44
45
  - **Errors** — `ActivitySchemaError`, `UnknownActivityTypeError`, `DeferredScoringError` and `RedactedScoringError`, all with structured payloads.
45
46
  - **Types** — `ActivityData`, `ActivityResult`, `ScoringResult`, `XAPIStatement`, `ThemeTokens`, … all exported with JSDoc.
46
47
 
@@ -114,7 +115,7 @@ result.passed; // boolean, or null while provisional. Never record a provision
114
115
  | Import | Contents |
115
116
  |---|---|
116
117
  | `@intellectif/lk-core` | Everything (barrel) |
117
- | `@intellectif/lk-core/schemas` | Zod schemas + `validateActivity` + JSON Schema export |
118
+ | `@intellectif/lk-core/schemas` | `validateActivity`, `validateItemGroup`, `validateMedia`, `validateOptionMedia`, `jsonSchemaFor` and the JSON Schemas, and the redacted types |
118
119
  | `@intellectif/lk-core/scoring` | `score`, `evaluate`, `composeAssessmentScore`, rounding, text matching |
119
120
  | `@intellectif/lk-core/xapi` | `xAPIBuilder`, `XAPIVerb`, `validateXAPIStatement` |
120
121
  | `@intellectif/lk-core/ai-check` | `runAiCheck`, `aiCheckCases`, `formatAiCheckReport` — test your AI prompts in CI |
@@ -123,8 +124,8 @@ The barrel re-exports everything, and it is the **only** entry point for attempt
123
124
  plans, attempt state, item groups, redaction, the type registry, authoring drafts
124
125
  and content hashing — those have no subpath of their own.
125
126
 
126
- All exports ship as ESM + CJS with `.d.ts` types. Tree-shakeable; `sideEffects: false`. Node >= 20. In browsers, the SDK's own code needs `Object.hasOwn` — Chrome and Edge 93, Firefox 92, Safari 15.4 — because output targets ES2022 and nothing is polyfilled.
127
- Zod is the single runtime dependency: the package depends on `zod@^3.25` and imports the **Zod 4 API** from its `zod/v4` subpath, so it coexists with an app still on Zod 3.
127
+ All exports ship as ESM + CJS with `.d.ts` types. Tree-shakeable; `sideEffects: false`. Node 22 or later. In browsers, the SDK's own code needs `Object.hasOwn` — Chrome and Edge 93, Firefox 92, Safari 15.4 — because output targets ES2022 and nothing is polyfilled.
128
+ Zod is the single runtime dependency, pinned to one exact version and private: no export is a zod schema and no published type names zod, so your app can use any version of zod, or none. The pin keeps validation to what the SDK tested — a new zod ships in a lk-core release, once the validation corpus replays unchanged — at the cost of a second copy of zod in a bundle whose own zod is another version. A type you register brings its own schema, from any library that implements [Standard Schema](https://standardschema.dev). What 1.x keeps stable is set out in [Stability](https://github.com/intellectif/learning-kit/blob/main/docs/stability.md).
128
129
 
129
130
  ## Releases & upgrading
130
131
 
@@ -224,7 +224,11 @@ interface GradeRecord {
224
224
  * one-word vocabulary item, say.
225
225
  */
226
226
  interface ActivityAiPermissions {
227
- /** An explanation of the learner's graded answer. */
227
+ /**
228
+ * An explanation of the learner's graded answer — and, on a written
229
+ * response, feedback on a draft: both are a model's words about the
230
+ * learner's own answer.
231
+ */
228
232
  explanations?: boolean;
229
233
  /** Hints before the learner submits. */
230
234
  hints?: boolean;
@@ -243,8 +247,8 @@ interface AiActivityInput {
243
247
  readonly redacted?: unknown;
244
248
  readonly ai?: unknown;
245
249
  }
246
- /** The two kinds of help a learner can be given. */
247
- type AiFeature = 'explanation' | 'hint';
250
+ /** The kinds of help a learner can be given. */
251
+ type AiFeature = 'explanation' | 'hint' | 'writing-feedback';
248
252
  /** The activity types the SDK builds facts for. */
249
253
  type AiSupportedActivityType = 'multiple-choice' | 'fill-in-the-blanks' | 'gap-select' | 'dictation';
250
254
  /**
@@ -404,8 +408,117 @@ interface AiTextResult {
404
408
  */
405
409
  usage?: GraderUsage;
406
410
  }
407
- /** Why a result was not shown. */
408
- type AiRefusal = 'malformed' | 'empty' | 'too-long' | 'contradicts-grade' | 'reveals-answer';
411
+ /**
412
+ * Why a result was not shown. `misquotes-answer` is writing feedback that
413
+ * corrects words the learner did not write: a correction whose quote is not in
414
+ * the draft, or not where it claims to be.
415
+ */
416
+ type AiRefusal = 'malformed' | 'empty' | 'too-long' | 'contradicts-grade' | 'reveals-answer' | 'misquotes-answer';
417
+ /** One criterion of a written response's rubric, as the author wrote it. */
418
+ interface AiRubricCriterionFact {
419
+ name: string;
420
+ description?: string;
421
+ weight: number;
422
+ }
423
+ /**
424
+ * What a model is told about a draft of a written response: the task as the
425
+ * learner saw it, the draft verbatim, and the rubric it will be graded on.
426
+ */
427
+ interface AiWritingFacts {
428
+ activityType: 'written-response';
429
+ activityId: string;
430
+ title: string;
431
+ /** The language the item is written in, when the author gave one. */
432
+ locale?: string;
433
+ prompt: string;
434
+ /** The draft, exactly as the learner wrote it. Every correction quotes it. */
435
+ text: string;
436
+ /** Recomputed with `countWords`, as the grader will count it. */
437
+ wordCount: number;
438
+ minWords: number;
439
+ maxWords: number;
440
+ withinWordBounds: boolean;
441
+ /** The rubric the answer will be graded on; `null` when the item has none. */
442
+ rubric: AiRubricCriterionFact[] | null;
443
+ /** The target language and level, when the author gave one (e.g. `"en-A2"`). */
444
+ languageTarget?: string;
445
+ }
446
+ /**
447
+ * Asks for feedback on a draft of a written response, before the learner
448
+ * submits it. Practice only.
449
+ */
450
+ interface AiWritingFeedbackRequest {
451
+ feature: 'writing-feedback';
452
+ facts: AiWritingFacts;
453
+ /** 1-based: which draft this is. */
454
+ draftNumber: number;
455
+ /** The text of the feedback already shown on earlier drafts, oldest first. */
456
+ previousFeedback: string[];
457
+ /** The language to write in: the learner's interface language, when known. */
458
+ learnerLocale?: string;
459
+ }
460
+ /**
461
+ * One correction a model proposes. `original` must be words the learner
462
+ * wrote; the SDK finds them in the draft itself, so a model need not count
463
+ * characters — leave `range` out unless you are sure of it, because a range
464
+ * that does not hold the quote is refused.
465
+ */
466
+ interface AiWritingCorrection {
467
+ original: string;
468
+ corrected: string;
469
+ explanation?: string;
470
+ /** An error-type tag, e.g. `"tense"`, `"article"`. */
471
+ category?: string;
472
+ range?: {
473
+ start: number;
474
+ end: number;
475
+ };
476
+ }
477
+ /**
478
+ * A model's judgement of one rubric criterion. The SDK attaches the author's
479
+ * weight; a weight sent here is ignored.
480
+ */
481
+ type AiCriterionJudgement = Omit<CriterionScore, 'weight'> & {
482
+ weight?: number;
483
+ };
484
+ /**
485
+ * What a host's `writingFeedback` port returns: the overall feedback as plain
486
+ * text, and optionally corrections and a judgement per rubric criterion.
487
+ */
488
+ interface AiWritingFeedbackResult {
489
+ /** The overall feedback, addressed to the learner. Plain text, never HTML. */
490
+ text: string;
491
+ corrections?: AiWritingCorrection[];
492
+ criteria?: AiCriterionJudgement[];
493
+ provenance?: AiProvenance;
494
+ usage?: GraderUsage;
495
+ }
496
+ /**
497
+ * Feedback on a draft, as the SDK accepted it: what a learner is shown.
498
+ */
499
+ interface AiWritingFeedback {
500
+ text: string;
501
+ /**
502
+ * Every correction, anchored in the draft: `range` is where the SDK found
503
+ * the quote, and `original` is the draft's own text at that range.
504
+ */
505
+ corrections: InlineCorrection[];
506
+ /** The model's judgements, with the rubric's weights. */
507
+ criteria: CriterionScore[];
508
+ /**
509
+ * The rubric's weighted total of the judgements, from 0 to 1, computed by
510
+ * the SDK as `gradeFromRubric` computes a grade — when every criterion of
511
+ * the rubric was judged; `null` otherwise, and on an item with no rubric.
512
+ *
513
+ * **An indication, never a grade:** it is a model's reading of a draft the
514
+ * learner has not submitted, and nothing in the SDK scores an answer with
515
+ * it. `ai-writing-feedback-shown` reports it, so a record can say what the
516
+ * learner was shown.
517
+ */
518
+ indicativeScore: number | null;
519
+ provenance?: AiProvenance;
520
+ usage?: GraderUsage;
521
+ }
409
522
 
410
523
  /**
411
524
  * An xAPI Activity object — the thing a statement is about.
@@ -1347,8 +1460,7 @@ interface ReadAloudLearnerResponse {
1347
1460
  takes?: number;
1348
1461
  }
1349
1462
  /**
1350
- * Fine-grained outcome of the learner's action on a single item, replacing the
1351
- * ambiguous {@link ScoringDetail.correct}:
1463
+ * Fine-grained outcome of the learner's action on a single item:
1352
1464
  * - `correct` — the learner selected/entered the right answer.
1353
1465
  * - `incorrect` — the learner selected/entered a wrong answer.
1354
1466
  * - `correct-omission` — the learner correctly left a non-answer unselected (multiple-choice only).
@@ -1361,20 +1473,17 @@ interface ScoringDetail {
1361
1473
  /** ID of the option, blank, gap or dictation word (`w1`…`wN`) this detail refers to. */
1362
1474
  itemId: string;
1363
1475
  /**
1364
- * @deprecated Ambiguous: for multiple-choice this means "the learner acted
1365
- * correctly on this option" (`wasSelected === option.isCorrect`), NOT "this
1366
- * option is the answer" — an unselected wrong option reads `correct: true`.
1367
- * Read {@link ScoringDetail.outcome} instead; `correct` remains written for
1368
- * backward compatibility and will be removed in v1.0.
1369
- */
1370
- correct: boolean;
1371
- /**
1372
- * Unambiguous outcome of the learner's action on this item. Optional in the
1373
- * type so 0.2-era consumer-constructed literals keep compiling, but ALWAYS
1374
- * written by every built-in scorer (by the first two since 0.3.0); becomes
1375
- * required in v1.0 when the deprecated `correct` is removed.
1476
+ * The outcome of the learner's action on this item. On a multiple-choice
1477
+ * option it says both whether the option was chosen and whether it is part
1478
+ * of the answer.
1479
+ *
1480
+ * Until 1.0 a detail also carried `correct`, which on a multiple-choice
1481
+ * option meant "the learner acted correctly on it" — an unselected wrong
1482
+ * option read `correct: true` — and a detail stored before 0.3 carries only
1483
+ * that. The SDK's components still read such a stored detail; a type written
1484
+ * against 1.0 does not describe it.
1376
1485
  */
1377
- outcome?: ScoringOutcome;
1486
+ outcome: ScoringOutcome;
1378
1487
  /** The learner's actual response for this item. */
1379
1488
  learnerResponse: string | string[];
1380
1489
  /** The expected correct response(s) for this item. */
@@ -1599,7 +1708,13 @@ type InteractionKind = 'option-selected' | 'option-deselected' | 'blank-filled'
1599
1708
  * watches its own model in production, where the development console warning
1600
1709
  * it accompanies is silent.
1601
1710
  */
1602
- | 'ai-help-refused' | (string & {});
1711
+ | 'ai-help-refused'
1712
+ /**
1713
+ * Feedback on a draft of a written response was shown (`draftNumber`, the
1714
+ * number of `corrections`, the `indicativeScore` when there was one, and the
1715
+ * port's `provenance` and `usage` when it sent them). Never the text.
1716
+ */
1717
+ | 'ai-writing-feedback-shown' | (string & {});
1603
1718
  /** Fired by activity components on every discrete learner interaction. */
1604
1719
  interface InteractionEvent {
1605
1720
  /** The kind of interaction that occurred. */
@@ -1612,4 +1727,4 @@ interface InteractionEvent {
1612
1727
  payload: Record<string, unknown>;
1613
1728
  }
1614
1729
 
1615
- export { type MediaPlaybackPolicy as $, type ActivityAiPermissions as A, type BlankConfig as B, type CriterionScore as C, type DeferredReason as D, type DictationData as E, type DictationEquivalence as F, type DictationLearnerResponse as G, type DictationSlowMedia as H, type DictationTolerance as I, type FillInTheBlanksData as J, type FillInTheBlanksLearnerResponse as K, type GapSelectBank as L, type GapSelectChoice as M, type GapSelectData as N, type GapSelectGap as O, type GapSelectLearnerResponse as P, type GradeRecord as Q, type Grader as R, type GraderKind as S, type GraderUsage as T, type GradingState as U, type InlineCorrection as V, type InteractionEvent as W, type InteractionKind as X, type ItemOutcome as Y, type LearnerResponse as Z, type LearnerResponseMap as _, type ActivityData as a, type MediaTrack as a0, type MultipleChoiceData as a1, type MultipleChoiceLearnerResponse as a2, type MultipleChoiceOption as a3, type MultipleChoiceOptionMedia as a4, type NativeControlHint as a5, type ReadAloudData as a6, type ReadAloudDimension as a7, type ReadAloudDimensionWeight as a8, type ReadAloudLearnerResponse as a9, type ReadAloudSlowMedia as aa, type RecordingBounds as ab, type RecordingRef as ac, type ScoringDetail as ad, type ScoringOutcome as ae, type ScoringResult as af, type TextMatchPolicy as ag, type TextMatchResult as ah, type ValidationError as ai, type ValidationResult as aj, type WrittenResponseData as ak, type WrittenResponseLearnerResponse as al, type WrittenResponseRubric as am, type WrittenResponseRubricCriterion as an, type XAPIActor as ao, type XAPIConfig as ap, type XAPIContext as aq, type XAPIContextActivities as ar, type XAPIError as as, type XAPIObject as at, type XAPIResult as au, type XAPIScore as av, type XAPIStatement as aw, type XAPIVerbObject as ax, levenshteinDistance as ay, matchText as az, type ActivityDataMap as b, type ActivityFeedback as c, type ActivityMedia as d, type ActivityResult as e, type ActivityType as f, type AiActivityInput as g, type AiBlankFact as h, type AiDictationFacts as i, type AiExplanationRequest as j, type AiFeature as k, type AiFillInTheBlanksFacts as l, type AiGapFact as m, type AiGapSelectFacts as n, type AiGrade as o, type AiHintRequest as p, type AiItemFacts as q, type AiMultipleChoiceFacts as r, type AiOptionFact as s, type AiProvenance as t, type AiRefusal as u, type AiSupportedActivityType as v, type AiTextResult as w, type AiVerdict as x, type AiWordFact as y, type DeferredScoringPartial as z };
1730
+ export { type GradingState as $, type ActivityAiPermissions as A, type AiWordFact as B, type AiWritingCorrection as C, type AiWritingFacts as D, type AiWritingFeedback as E, type AiWritingFeedbackRequest as F, type AiWritingFeedbackResult as G, type BlankConfig as H, type CriterionScore as I, type DeferredReason as J, type DeferredScoringPartial as K, type DictationData as L, type DictationEquivalence as M, type DictationLearnerResponse as N, type DictationSlowMedia as O, type DictationTolerance as P, type FillInTheBlanksData as Q, type FillInTheBlanksLearnerResponse as R, type GapSelectBank as S, type GapSelectChoice as T, type GapSelectData as U, type GapSelectGap as V, type GapSelectLearnerResponse as W, type GradeRecord as X, type Grader as Y, type GraderKind as Z, type GraderUsage as _, type ActivityData as a, type InlineCorrection as a0, type InteractionEvent as a1, type InteractionKind as a2, type ItemOutcome as a3, type LearnerResponse as a4, type LearnerResponseMap as a5, type MediaPlaybackPolicy as a6, type MediaTrack as a7, type MultipleChoiceData as a8, type MultipleChoiceLearnerResponse as a9, type XAPIObject as aA, type XAPIResult as aB, type XAPIScore as aC, type XAPIStatement as aD, type XAPIVerbObject as aE, levenshteinDistance as aF, matchText as aG, type MultipleChoiceOption as aa, type MultipleChoiceOptionMedia as ab, type NativeControlHint as ac, type ReadAloudData as ad, type ReadAloudDimension as ae, type ReadAloudDimensionWeight as af, type ReadAloudLearnerResponse as ag, type ReadAloudSlowMedia as ah, type RecordingBounds as ai, type RecordingRef as aj, type ScoringDetail as ak, type ScoringOutcome as al, type ScoringResult as am, type TextMatchPolicy as an, type TextMatchResult as ao, type ValidationError as ap, type ValidationResult as aq, type WrittenResponseData as ar, type WrittenResponseLearnerResponse as as, type WrittenResponseRubric as at, type WrittenResponseRubricCriterion as au, type XAPIActor as av, type XAPIConfig as aw, type XAPIContext as ax, type XAPIContextActivities as ay, type XAPIError as az, type ActivityDataMap as b, type ActivityFeedback as c, type ActivityMedia as d, type ActivityResult as e, type ActivityType as f, type AiActivityInput as g, type AiBlankFact as h, type AiCriterionJudgement as i, type AiDictationFacts as j, type AiExplanationRequest as k, type AiFeature as l, type AiFillInTheBlanksFacts as m, type AiGapFact as n, type AiGapSelectFacts as o, type AiGrade as p, type AiHintRequest as q, type AiItemFacts as r, type AiMultipleChoiceFacts as s, type AiOptionFact as t, type AiProvenance as u, type AiRefusal as v, type AiRubricCriterionFact as w, type AiSupportedActivityType as x, type AiTextResult as y, type AiVerdict as z };
@@ -224,7 +224,11 @@ interface GradeRecord {
224
224
  * one-word vocabulary item, say.
225
225
  */
226
226
  interface ActivityAiPermissions {
227
- /** An explanation of the learner's graded answer. */
227
+ /**
228
+ * An explanation of the learner's graded answer — and, on a written
229
+ * response, feedback on a draft: both are a model's words about the
230
+ * learner's own answer.
231
+ */
228
232
  explanations?: boolean;
229
233
  /** Hints before the learner submits. */
230
234
  hints?: boolean;
@@ -243,8 +247,8 @@ interface AiActivityInput {
243
247
  readonly redacted?: unknown;
244
248
  readonly ai?: unknown;
245
249
  }
246
- /** The two kinds of help a learner can be given. */
247
- type AiFeature = 'explanation' | 'hint';
250
+ /** The kinds of help a learner can be given. */
251
+ type AiFeature = 'explanation' | 'hint' | 'writing-feedback';
248
252
  /** The activity types the SDK builds facts for. */
249
253
  type AiSupportedActivityType = 'multiple-choice' | 'fill-in-the-blanks' | 'gap-select' | 'dictation';
250
254
  /**
@@ -404,8 +408,117 @@ interface AiTextResult {
404
408
  */
405
409
  usage?: GraderUsage;
406
410
  }
407
- /** Why a result was not shown. */
408
- type AiRefusal = 'malformed' | 'empty' | 'too-long' | 'contradicts-grade' | 'reveals-answer';
411
+ /**
412
+ * Why a result was not shown. `misquotes-answer` is writing feedback that
413
+ * corrects words the learner did not write: a correction whose quote is not in
414
+ * the draft, or not where it claims to be.
415
+ */
416
+ type AiRefusal = 'malformed' | 'empty' | 'too-long' | 'contradicts-grade' | 'reveals-answer' | 'misquotes-answer';
417
+ /** One criterion of a written response's rubric, as the author wrote it. */
418
+ interface AiRubricCriterionFact {
419
+ name: string;
420
+ description?: string;
421
+ weight: number;
422
+ }
423
+ /**
424
+ * What a model is told about a draft of a written response: the task as the
425
+ * learner saw it, the draft verbatim, and the rubric it will be graded on.
426
+ */
427
+ interface AiWritingFacts {
428
+ activityType: 'written-response';
429
+ activityId: string;
430
+ title: string;
431
+ /** The language the item is written in, when the author gave one. */
432
+ locale?: string;
433
+ prompt: string;
434
+ /** The draft, exactly as the learner wrote it. Every correction quotes it. */
435
+ text: string;
436
+ /** Recomputed with `countWords`, as the grader will count it. */
437
+ wordCount: number;
438
+ minWords: number;
439
+ maxWords: number;
440
+ withinWordBounds: boolean;
441
+ /** The rubric the answer will be graded on; `null` when the item has none. */
442
+ rubric: AiRubricCriterionFact[] | null;
443
+ /** The target language and level, when the author gave one (e.g. `"en-A2"`). */
444
+ languageTarget?: string;
445
+ }
446
+ /**
447
+ * Asks for feedback on a draft of a written response, before the learner
448
+ * submits it. Practice only.
449
+ */
450
+ interface AiWritingFeedbackRequest {
451
+ feature: 'writing-feedback';
452
+ facts: AiWritingFacts;
453
+ /** 1-based: which draft this is. */
454
+ draftNumber: number;
455
+ /** The text of the feedback already shown on earlier drafts, oldest first. */
456
+ previousFeedback: string[];
457
+ /** The language to write in: the learner's interface language, when known. */
458
+ learnerLocale?: string;
459
+ }
460
+ /**
461
+ * One correction a model proposes. `original` must be words the learner
462
+ * wrote; the SDK finds them in the draft itself, so a model need not count
463
+ * characters — leave `range` out unless you are sure of it, because a range
464
+ * that does not hold the quote is refused.
465
+ */
466
+ interface AiWritingCorrection {
467
+ original: string;
468
+ corrected: string;
469
+ explanation?: string;
470
+ /** An error-type tag, e.g. `"tense"`, `"article"`. */
471
+ category?: string;
472
+ range?: {
473
+ start: number;
474
+ end: number;
475
+ };
476
+ }
477
+ /**
478
+ * A model's judgement of one rubric criterion. The SDK attaches the author's
479
+ * weight; a weight sent here is ignored.
480
+ */
481
+ type AiCriterionJudgement = Omit<CriterionScore, 'weight'> & {
482
+ weight?: number;
483
+ };
484
+ /**
485
+ * What a host's `writingFeedback` port returns: the overall feedback as plain
486
+ * text, and optionally corrections and a judgement per rubric criterion.
487
+ */
488
+ interface AiWritingFeedbackResult {
489
+ /** The overall feedback, addressed to the learner. Plain text, never HTML. */
490
+ text: string;
491
+ corrections?: AiWritingCorrection[];
492
+ criteria?: AiCriterionJudgement[];
493
+ provenance?: AiProvenance;
494
+ usage?: GraderUsage;
495
+ }
496
+ /**
497
+ * Feedback on a draft, as the SDK accepted it: what a learner is shown.
498
+ */
499
+ interface AiWritingFeedback {
500
+ text: string;
501
+ /**
502
+ * Every correction, anchored in the draft: `range` is where the SDK found
503
+ * the quote, and `original` is the draft's own text at that range.
504
+ */
505
+ corrections: InlineCorrection[];
506
+ /** The model's judgements, with the rubric's weights. */
507
+ criteria: CriterionScore[];
508
+ /**
509
+ * The rubric's weighted total of the judgements, from 0 to 1, computed by
510
+ * the SDK as `gradeFromRubric` computes a grade — when every criterion of
511
+ * the rubric was judged; `null` otherwise, and on an item with no rubric.
512
+ *
513
+ * **An indication, never a grade:** it is a model's reading of a draft the
514
+ * learner has not submitted, and nothing in the SDK scores an answer with
515
+ * it. `ai-writing-feedback-shown` reports it, so a record can say what the
516
+ * learner was shown.
517
+ */
518
+ indicativeScore: number | null;
519
+ provenance?: AiProvenance;
520
+ usage?: GraderUsage;
521
+ }
409
522
 
410
523
  /**
411
524
  * An xAPI Activity object — the thing a statement is about.
@@ -1347,8 +1460,7 @@ interface ReadAloudLearnerResponse {
1347
1460
  takes?: number;
1348
1461
  }
1349
1462
  /**
1350
- * Fine-grained outcome of the learner's action on a single item, replacing the
1351
- * ambiguous {@link ScoringDetail.correct}:
1463
+ * Fine-grained outcome of the learner's action on a single item:
1352
1464
  * - `correct` — the learner selected/entered the right answer.
1353
1465
  * - `incorrect` — the learner selected/entered a wrong answer.
1354
1466
  * - `correct-omission` — the learner correctly left a non-answer unselected (multiple-choice only).
@@ -1361,20 +1473,17 @@ interface ScoringDetail {
1361
1473
  /** ID of the option, blank, gap or dictation word (`w1`…`wN`) this detail refers to. */
1362
1474
  itemId: string;
1363
1475
  /**
1364
- * @deprecated Ambiguous: for multiple-choice this means "the learner acted
1365
- * correctly on this option" (`wasSelected === option.isCorrect`), NOT "this
1366
- * option is the answer" — an unselected wrong option reads `correct: true`.
1367
- * Read {@link ScoringDetail.outcome} instead; `correct` remains written for
1368
- * backward compatibility and will be removed in v1.0.
1369
- */
1370
- correct: boolean;
1371
- /**
1372
- * Unambiguous outcome of the learner's action on this item. Optional in the
1373
- * type so 0.2-era consumer-constructed literals keep compiling, but ALWAYS
1374
- * written by every built-in scorer (by the first two since 0.3.0); becomes
1375
- * required in v1.0 when the deprecated `correct` is removed.
1476
+ * The outcome of the learner's action on this item. On a multiple-choice
1477
+ * option it says both whether the option was chosen and whether it is part
1478
+ * of the answer.
1479
+ *
1480
+ * Until 1.0 a detail also carried `correct`, which on a multiple-choice
1481
+ * option meant "the learner acted correctly on it" — an unselected wrong
1482
+ * option read `correct: true` — and a detail stored before 0.3 carries only
1483
+ * that. The SDK's components still read such a stored detail; a type written
1484
+ * against 1.0 does not describe it.
1376
1485
  */
1377
- outcome?: ScoringOutcome;
1486
+ outcome: ScoringOutcome;
1378
1487
  /** The learner's actual response for this item. */
1379
1488
  learnerResponse: string | string[];
1380
1489
  /** The expected correct response(s) for this item. */
@@ -1599,7 +1708,13 @@ type InteractionKind = 'option-selected' | 'option-deselected' | 'blank-filled'
1599
1708
  * watches its own model in production, where the development console warning
1600
1709
  * it accompanies is silent.
1601
1710
  */
1602
- | 'ai-help-refused' | (string & {});
1711
+ | 'ai-help-refused'
1712
+ /**
1713
+ * Feedback on a draft of a written response was shown (`draftNumber`, the
1714
+ * number of `corrections`, the `indicativeScore` when there was one, and the
1715
+ * port's `provenance` and `usage` when it sent them). Never the text.
1716
+ */
1717
+ | 'ai-writing-feedback-shown' | (string & {});
1603
1718
  /** Fired by activity components on every discrete learner interaction. */
1604
1719
  interface InteractionEvent {
1605
1720
  /** The kind of interaction that occurred. */
@@ -1612,4 +1727,4 @@ interface InteractionEvent {
1612
1727
  payload: Record<string, unknown>;
1613
1728
  }
1614
1729
 
1615
- export { type MediaPlaybackPolicy as $, type ActivityAiPermissions as A, type BlankConfig as B, type CriterionScore as C, type DeferredReason as D, type DictationData as E, type DictationEquivalence as F, type DictationLearnerResponse as G, type DictationSlowMedia as H, type DictationTolerance as I, type FillInTheBlanksData as J, type FillInTheBlanksLearnerResponse as K, type GapSelectBank as L, type GapSelectChoice as M, type GapSelectData as N, type GapSelectGap as O, type GapSelectLearnerResponse as P, type GradeRecord as Q, type Grader as R, type GraderKind as S, type GraderUsage as T, type GradingState as U, type InlineCorrection as V, type InteractionEvent as W, type InteractionKind as X, type ItemOutcome as Y, type LearnerResponse as Z, type LearnerResponseMap as _, type ActivityData as a, type MediaTrack as a0, type MultipleChoiceData as a1, type MultipleChoiceLearnerResponse as a2, type MultipleChoiceOption as a3, type MultipleChoiceOptionMedia as a4, type NativeControlHint as a5, type ReadAloudData as a6, type ReadAloudDimension as a7, type ReadAloudDimensionWeight as a8, type ReadAloudLearnerResponse as a9, type ReadAloudSlowMedia as aa, type RecordingBounds as ab, type RecordingRef as ac, type ScoringDetail as ad, type ScoringOutcome as ae, type ScoringResult as af, type TextMatchPolicy as ag, type TextMatchResult as ah, type ValidationError as ai, type ValidationResult as aj, type WrittenResponseData as ak, type WrittenResponseLearnerResponse as al, type WrittenResponseRubric as am, type WrittenResponseRubricCriterion as an, type XAPIActor as ao, type XAPIConfig as ap, type XAPIContext as aq, type XAPIContextActivities as ar, type XAPIError as as, type XAPIObject as at, type XAPIResult as au, type XAPIScore as av, type XAPIStatement as aw, type XAPIVerbObject as ax, levenshteinDistance as ay, matchText as az, type ActivityDataMap as b, type ActivityFeedback as c, type ActivityMedia as d, type ActivityResult as e, type ActivityType as f, type AiActivityInput as g, type AiBlankFact as h, type AiDictationFacts as i, type AiExplanationRequest as j, type AiFeature as k, type AiFillInTheBlanksFacts as l, type AiGapFact as m, type AiGapSelectFacts as n, type AiGrade as o, type AiHintRequest as p, type AiItemFacts as q, type AiMultipleChoiceFacts as r, type AiOptionFact as s, type AiProvenance as t, type AiRefusal as u, type AiSupportedActivityType as v, type AiTextResult as w, type AiVerdict as x, type AiWordFact as y, type DeferredScoringPartial as z };
1730
+ export { type GradingState as $, type ActivityAiPermissions as A, type AiWordFact as B, type AiWritingCorrection as C, type AiWritingFacts as D, type AiWritingFeedback as E, type AiWritingFeedbackRequest as F, type AiWritingFeedbackResult as G, type BlankConfig as H, type CriterionScore as I, type DeferredReason as J, type DeferredScoringPartial as K, type DictationData as L, type DictationEquivalence as M, type DictationLearnerResponse as N, type DictationSlowMedia as O, type DictationTolerance as P, type FillInTheBlanksData as Q, type FillInTheBlanksLearnerResponse as R, type GapSelectBank as S, type GapSelectChoice as T, type GapSelectData as U, type GapSelectGap as V, type GapSelectLearnerResponse as W, type GradeRecord as X, type Grader as Y, type GraderKind as Z, type GraderUsage as _, type ActivityData as a, type InlineCorrection as a0, type InteractionEvent as a1, type InteractionKind as a2, type ItemOutcome as a3, type LearnerResponse as a4, type LearnerResponseMap as a5, type MediaPlaybackPolicy as a6, type MediaTrack as a7, type MultipleChoiceData as a8, type MultipleChoiceLearnerResponse as a9, type XAPIObject as aA, type XAPIResult as aB, type XAPIScore as aC, type XAPIStatement as aD, type XAPIVerbObject as aE, levenshteinDistance as aF, matchText as aG, type MultipleChoiceOption as aa, type MultipleChoiceOptionMedia as ab, type NativeControlHint as ac, type ReadAloudData as ad, type ReadAloudDimension as ae, type ReadAloudDimensionWeight as af, type ReadAloudLearnerResponse as ag, type ReadAloudSlowMedia as ah, type RecordingBounds as ai, type RecordingRef as aj, type ScoringDetail as ak, type ScoringOutcome as al, type ScoringResult as am, type TextMatchPolicy as an, type TextMatchResult as ao, type ValidationError as ap, type ValidationResult as aq, type WrittenResponseData as ar, type WrittenResponseLearnerResponse as as, type WrittenResponseRubric as at, type WrittenResponseRubricCriterion as au, type XAPIActor as av, type XAPIConfig as aw, type XAPIContext as ax, type XAPIContextActivities as ay, type XAPIError as az, type ActivityDataMap as b, type ActivityFeedback as c, type ActivityMedia as d, type ActivityResult as e, type ActivityType as f, type AiActivityInput as g, type AiBlankFact as h, type AiCriterionJudgement as i, type AiDictationFacts as j, type AiExplanationRequest as k, type AiFeature as l, type AiFillInTheBlanksFacts as m, type AiGapFact as n, type AiGapSelectFacts as o, type AiGrade as p, type AiHintRequest as q, type AiItemFacts as r, type AiMultipleChoiceFacts as s, type AiOptionFact as t, type AiProvenance as u, type AiRefusal as v, type AiRubricCriterionFact as w, type AiSupportedActivityType as x, type AiTextResult as y, type AiVerdict as z };