@intellectif/lk-react 20.0.0 → 22.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.
- package/CHANGELOG.md +42 -0
- package/README.md +33 -5
- package/dist/{WrittenResponse-D2YI8xOK.d.ts → WrittenResponse-CgRrjM4S.d.ts} +14 -4
- package/dist/{WrittenResponse-obIDDYDH.d.cts → WrittenResponse-D2K1VW_V.d.cts} +14 -4
- package/dist/ai/LkAiProvider.cjs +3 -3
- package/dist/ai/LkAiProvider.d.cts +17 -4
- package/dist/ai/LkAiProvider.d.ts +17 -4
- package/dist/ai/LkAiProvider.js +1 -1
- package/dist/ai/useAiHelp.cjs +9 -5
- package/dist/ai/useAiHelp.d.cts +58 -3
- package/dist/ai/useAiHelp.d.ts +58 -3
- package/dist/ai/useAiHelp.js +3 -3
- package/dist/{chunk-BGA2IVQY.js → chunk-3GLYK37F.js} +119 -26
- package/dist/chunk-3GLYK37F.js.map +1 -0
- package/dist/{chunk-LX2X4KC7.cjs → chunk-5YGVGMMV.cjs} +7 -7
- package/dist/{chunk-LX2X4KC7.cjs.map → chunk-5YGVGMMV.cjs.map} +1 -1
- package/dist/{chunk-3XP6VO4G.js → chunk-62K4Q565.js} +139 -45
- package/dist/chunk-62K4Q565.js.map +1 -0
- package/dist/{chunk-CEUEXISZ.cjs → chunk-6QY7GC55.cjs} +131 -50
- package/dist/chunk-6QY7GC55.cjs.map +1 -0
- package/dist/chunk-7EEKZWTQ.js +241 -0
- package/dist/chunk-7EEKZWTQ.js.map +1 -0
- package/dist/{chunk-3FBBP5QR.cjs → chunk-B4JRBV56.cjs} +6 -6
- package/dist/{chunk-3FBBP5QR.cjs.map → chunk-B4JRBV56.cjs.map} +1 -1
- package/dist/{chunk-RT2PP4SO.cjs → chunk-BL5SIBQA.cjs} +30 -30
- package/dist/{chunk-RT2PP4SO.cjs.map → chunk-BL5SIBQA.cjs.map} +1 -1
- package/dist/{chunk-YRNEOBXA.js → chunk-C4PSJ3ZC.js} +19 -2
- package/dist/chunk-C4PSJ3ZC.js.map +1 -0
- package/dist/{chunk-FEOFX4QW.js → chunk-FB47DQPS.js} +3 -3
- package/dist/{chunk-FEOFX4QW.js.map → chunk-FB47DQPS.js.map} +1 -1
- package/dist/chunk-FKNEHCNT.cjs +251 -0
- package/dist/chunk-FKNEHCNT.cjs.map +1 -0
- package/dist/{chunk-AG7MWZYZ.js → chunk-FPM2GQZY.js} +144 -55
- package/dist/chunk-FPM2GQZY.js.map +1 -0
- package/dist/{chunk-NWNQ2PHT.js → chunk-HNZ3JMAN.js} +8 -8
- package/dist/{chunk-NWNQ2PHT.js.map → chunk-HNZ3JMAN.js.map} +1 -1
- package/dist/{chunk-BY4UQH2Y.js → chunk-HYOUMTPW.js} +3 -3
- package/dist/{chunk-BY4UQH2Y.js.map → chunk-HYOUMTPW.js.map} +1 -1
- package/dist/{chunk-7K4B2EMU.js → chunk-HZIT24BK.js} +4 -4
- package/dist/{chunk-7K4B2EMU.js.map → chunk-HZIT24BK.js.map} +1 -1
- package/dist/{chunk-BJLQKJZX.cjs → chunk-J2QIHZ3H.cjs} +2 -2
- package/dist/chunk-J2QIHZ3H.cjs.map +1 -0
- package/dist/{chunk-DZVF3IGB.cjs → chunk-JII7XSCT.cjs} +59 -25
- package/dist/chunk-JII7XSCT.cjs.map +1 -0
- package/dist/{chunk-HI6BUUIJ.js → chunk-KFPCZ7N3.js} +48 -14
- package/dist/chunk-KFPCZ7N3.js.map +1 -0
- package/dist/{chunk-W6DMHN33.js → chunk-LRWFU3KS.js} +10 -10
- package/dist/{chunk-W6DMHN33.js.map → chunk-LRWFU3KS.js.map} +1 -1
- package/dist/{chunk-G7AGM2Y7.js → chunk-LX4JI262.js} +4 -4
- package/dist/{chunk-G7AGM2Y7.js.map → chunk-LX4JI262.js.map} +1 -1
- package/dist/{chunk-IXMT7X3E.cjs → chunk-M4UJBLVR.cjs} +17 -6
- package/dist/chunk-M4UJBLVR.cjs.map +1 -0
- package/dist/{chunk-AHGB5HH6.cjs → chunk-NFGUJ52G.cjs} +19 -2
- package/dist/chunk-NFGUJ52G.cjs.map +1 -0
- package/dist/{chunk-PWLJDP3X.cjs → chunk-NP5YC4NV.cjs} +95 -27
- package/dist/chunk-NP5YC4NV.cjs.map +1 -0
- package/dist/{chunk-ZDYNAWDZ.cjs → chunk-OJGTJOWI.cjs} +2 -2
- package/dist/chunk-OJGTJOWI.cjs.map +1 -0
- package/dist/{chunk-ORBU3XKH.js → chunk-PJMXHDY5.js} +16 -5
- package/dist/chunk-PJMXHDY5.js.map +1 -0
- package/dist/{chunk-TRMWBJWT.cjs → chunk-PZVRZ6OX.cjs} +141 -10
- package/dist/chunk-PZVRZ6OX.cjs.map +1 -0
- package/dist/{chunk-QKW2GGTV.js → chunk-R4ZNFDTK.js} +84 -16
- package/dist/chunk-R4ZNFDTK.js.map +1 -0
- package/dist/{chunk-YNDKAYW3.js → chunk-RX3A6KIY.js} +2 -2
- package/dist/chunk-RX3A6KIY.js.map +1 -0
- package/dist/{chunk-UHIOVOFK.cjs → chunk-TQN5CJO6.cjs} +125 -32
- package/dist/chunk-TQN5CJO6.cjs.map +1 -0
- package/dist/{chunk-AQIAQHJC.js → chunk-TRXUZSOY.js} +138 -8
- package/dist/chunk-TRXUZSOY.js.map +1 -0
- package/dist/{chunk-WBLYD5QA.js → chunk-U4KTOH7C.js} +2 -2
- package/dist/chunk-U4KTOH7C.js.map +1 -0
- package/dist/{chunk-L7WY5YFQ.cjs → chunk-UKUHVCZX.cjs} +5 -5
- package/dist/{chunk-L7WY5YFQ.cjs.map → chunk-UKUHVCZX.cjs.map} +1 -1
- package/dist/{chunk-HREA5SMB.cjs → chunk-UWFJGFB6.cjs} +116 -47
- package/dist/chunk-UWFJGFB6.cjs.map +1 -0
- package/dist/{chunk-JLDSCHY5.cjs → chunk-UXTYFEIC.cjs} +150 -61
- package/dist/chunk-UXTYFEIC.cjs.map +1 -0
- package/dist/{chunk-5GI53C6T.js → chunk-V2QZM2P2.js} +109 -40
- package/dist/chunk-V2QZM2P2.js.map +1 -0
- package/dist/{chunk-6S2CKZ4H.cjs → chunk-WFGDKBBP.cjs} +145 -51
- package/dist/chunk-WFGDKBBP.cjs.map +1 -0
- package/dist/{chunk-APZ6JFN6.cjs → chunk-Y5H4NOM6.cjs} +5 -5
- package/dist/{chunk-APZ6JFN6.cjs.map → chunk-Y5H4NOM6.cjs.map} +1 -1
- package/dist/{chunk-IQ55QNBI.js → chunk-YIXO6C4Z.js} +125 -44
- package/dist/chunk-YIXO6C4Z.js.map +1 -0
- package/dist/{chunk-LK5VXNMR.cjs → chunk-ZUE32Z67.cjs} +18 -18
- package/dist/{chunk-LK5VXNMR.cjs.map → chunk-ZUE32Z67.cjs.map} +1 -1
- package/dist/components/ActivityPreview.cjs +17 -17
- package/dist/components/ActivityPreview.d.cts +2 -2
- package/dist/components/ActivityPreview.d.ts +2 -2
- package/dist/components/ActivityPreview.js +16 -16
- package/dist/components/ActivitySequence.cjs +18 -18
- package/dist/components/ActivitySequence.d.cts +22 -4
- package/dist/components/ActivitySequence.d.ts +22 -4
- package/dist/components/ActivitySequence.js +17 -17
- package/dist/components/Dictation.cjs +10 -10
- package/dist/components/Dictation.d.cts +1 -1
- package/dist/components/Dictation.d.ts +1 -1
- package/dist/components/Dictation.js +9 -9
- package/dist/components/FillInTheBlanks.cjs +10 -10
- package/dist/components/FillInTheBlanks.d.cts +1 -1
- package/dist/components/FillInTheBlanks.d.ts +1 -1
- package/dist/components/FillInTheBlanks.js +9 -9
- package/dist/components/GapSelect.cjs +10 -10
- package/dist/components/GapSelect.d.cts +1 -1
- package/dist/components/GapSelect.d.ts +1 -1
- package/dist/components/GapSelect.js +9 -9
- package/dist/components/InteractiveVideo.cjs +17 -17
- package/dist/components/InteractiveVideo.d.cts +19 -3
- package/dist/components/InteractiveVideo.d.ts +19 -3
- package/dist/components/InteractiveVideo.js +15 -15
- package/dist/components/MultipleChoice.cjs +10 -10
- package/dist/components/MultipleChoice.d.cts +1 -1
- package/dist/components/MultipleChoice.d.ts +1 -1
- package/dist/components/MultipleChoice.js +9 -9
- package/dist/components/PronunciationFeedback.cjs +4 -4
- package/dist/components/PronunciationFeedback.d.cts +1 -1
- package/dist/components/PronunciationFeedback.d.ts +1 -1
- package/dist/components/PronunciationFeedback.js +3 -3
- package/dist/components/ReadAloud.cjs +8 -8
- package/dist/components/ReadAloud.d.cts +2 -2
- package/dist/components/ReadAloud.d.ts +2 -2
- package/dist/components/ReadAloud.js +7 -7
- package/dist/components/StimulusPanel.cjs +4 -4
- package/dist/components/StimulusPanel.d.cts +1 -1
- package/dist/components/StimulusPanel.d.ts +1 -1
- package/dist/components/StimulusPanel.js +3 -3
- package/dist/components/WrittenResponse.cjs +9 -7
- package/dist/components/WrittenResponse.d.cts +3 -3
- package/dist/components/WrittenResponse.d.ts +3 -3
- package/dist/components/WrittenResponse.js +8 -6
- package/dist/i18n/LkIntlProvider.cjs +7 -7
- package/dist/i18n/LkIntlProvider.d.cts +2 -2
- package/dist/i18n/LkIntlProvider.d.ts +2 -2
- package/dist/i18n/LkIntlProvider.js +1 -1
- package/dist/index.cjs +45 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +19 -19
- package/dist/index.js.map +1 -1
- package/dist/theme/skin.css +78 -0
- package/dist/{types-B_PCcqO-.d.cts → types-CO0XLEN6.d.cts} +67 -1
- package/dist/{types-C-GMCJ0g.d.ts → types-CrtIcRcK.d.ts} +67 -1
- package/package.json +3 -3
- package/dist/chunk-3XP6VO4G.js.map +0 -1
- package/dist/chunk-5GI53C6T.js.map +0 -1
- package/dist/chunk-6S2CKZ4H.cjs.map +0 -1
- package/dist/chunk-AG7MWZYZ.js.map +0 -1
- package/dist/chunk-AHGB5HH6.cjs.map +0 -1
- package/dist/chunk-AQIAQHJC.js.map +0 -1
- package/dist/chunk-BGA2IVQY.js.map +0 -1
- package/dist/chunk-BJLQKJZX.cjs.map +0 -1
- package/dist/chunk-CEUEXISZ.cjs.map +0 -1
- package/dist/chunk-DZVF3IGB.cjs.map +0 -1
- package/dist/chunk-HI6BUUIJ.js.map +0 -1
- package/dist/chunk-HREA5SMB.cjs.map +0 -1
- package/dist/chunk-IQ55QNBI.js.map +0 -1
- package/dist/chunk-IXMT7X3E.cjs.map +0 -1
- package/dist/chunk-JLDSCHY5.cjs.map +0 -1
- package/dist/chunk-NOC2M6LU.cjs +0 -118
- package/dist/chunk-NOC2M6LU.cjs.map +0 -1
- package/dist/chunk-ORBU3XKH.js.map +0 -1
- package/dist/chunk-PWLJDP3X.cjs.map +0 -1
- package/dist/chunk-QKW2GGTV.js.map +0 -1
- package/dist/chunk-RUS42NMN.js +0 -115
- package/dist/chunk-RUS42NMN.js.map +0 -1
- package/dist/chunk-TRMWBJWT.cjs.map +0 -1
- package/dist/chunk-UHIOVOFK.cjs.map +0 -1
- package/dist/chunk-WBLYD5QA.js.map +0 -1
- package/dist/chunk-YNDKAYW3.js.map +0 -1
- package/dist/chunk-YRNEOBXA.js.map +0 -1
- package/dist/chunk-ZDYNAWDZ.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# @intellectif/lk-react
|
|
2
2
|
|
|
3
|
+
## 22.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#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.
|
|
8
|
+
|
|
9
|
+
**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`.
|
|
10
|
+
|
|
11
|
+
- **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.
|
|
12
|
+
- **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.
|
|
13
|
+
- **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'`.
|
|
14
|
+
- **ai-check:** a `writingFeedback` port runs four writing cases: a draft with mistakes, one without, a revision, and feedback asked for in Spanish.
|
|
15
|
+
- Eight new strings: `aiWritingFeedback`, `aiWritingFeedbackLoading`, `aiWritingFeedbackHeading`, `aiWritingFeedbackUnavailable`, `aiNoMoreWritingFeedback`, `aiWritingFeedbackOutdated`, `aiCorrections`, `aiIndicativeScore`.
|
|
16
|
+
|
|
17
|
+
Guide: https://github.com/intellectif/learning-kit/blob/main/docs/ai.md#feedback-on-writing
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [[`782b01b`](https://github.com/intellectif/learning-kit/commit/782b01ba697a90583b472ab1a7a2be102fd888c4)]:
|
|
22
|
+
- @intellectif/lk-core@0.22.0
|
|
23
|
+
|
|
24
|
+
## 21.0.0
|
|
25
|
+
|
|
26
|
+
### Major Changes
|
|
27
|
+
|
|
28
|
+
- [#78](https://github.com/intellectif/learning-kit/pull/78) [`30a9b3d`](https://github.com/intellectif/learning-kit/commit/30a9b3da9be60589d63516752a02cc2f44bdf73b) Thanks [@diego28e](https://github.com/diego28e)! - **Scoring policies**: "Try again" in practice, which try counts, and what tries and hints cost — set per paper, recorded in the plan, and no grade moves without one.
|
|
29
|
+
|
|
30
|
+
**Action required:** only if you build an `InteractiveVideoQuestion` by hand (add `scoring`, e.g. `DEFAULT_ITEM_SCORING_POLICY`) or implement a complete `LkStrings` of your own (nine new keys). Everyone else upgrades with no change.
|
|
31
|
+
|
|
32
|
+
- **lk-core:** `ItemScoringPolicy` — `retries` (0–10), `counts` (`'first'` by default, `'best'`, `'last'`), `retryPenalty` and `hintPenalty` (fractions of the marks). `scoreTries` does the arithmetic: a cost is subtracted, never below zero, with floating-point residue under a pass line removed. `evaluate(item, response, { scoring })` charges the response's hints; `evaluateTries(item, responses, { scoring })` picks the try that counts. `validateItemScoringPolicy` and `resolveItemScoringPolicy` refuse a policy that cannot be applied — a `RangeError`, never a guess. `planAttempt(…, { scoring })` records it in the plan and `planHash`, and `verifyAttemptPlan` reports `scoringChanged`. With no policy every number is what it was; 43 new grade vectors pin the arithmetic.
|
|
33
|
+
- **Responses:** multiple-choice, fill-in-the-blanks and gap-select responses gain an optional `hintsRevealed`, as dictation's already had: in `practice`, the hints a learner was shown, counted from the start of the question.
|
|
34
|
+
- **lk-react:** `scoring` on every activity, `<ActivitySequence>` and `<InteractiveVideo>`; the paper's policy wins over a question's. "Try again" after an answer short of full marks keeps the answer and clears the marks; "Show answer" (or "Keep this answer") ends the tries. While a try is on offer the right answer and "Explain my answer" wait. `onComplete` fires after every try with the question's score so far. A set waits for any question being tried again, and for the question on screen while it offers a try, and closes every question's tries once it reports; the video closes them at Finish.
|
|
35
|
+
- **Fixed:** a dictation under `delivery={{ solutions: false }}` hid "Show solution" but its marks still named every word they corrected. They now say a word is wrong or missing without naming it, and draw no letter diff.
|
|
36
|
+
- Nine new strings: `tryAgain`, `showAnswer`, `keepAnswer`, `triesLeft`, `countedTry`, `scoreBeforeCosts`, `hintCost`, `dictationWordWrongUnnamed`, `dictationWordMissingUnnamed`.
|
|
37
|
+
|
|
38
|
+
Guide: https://github.com/intellectif/learning-kit/blob/main/docs/scoring.md
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
- Updated dependencies [[`30a9b3d`](https://github.com/intellectif/learning-kit/commit/30a9b3da9be60589d63516752a02cc2f44bdf73b)]:
|
|
43
|
+
- @intellectif/lk-core@0.21.0
|
|
44
|
+
|
|
3
45
|
## 20.0.0
|
|
4
46
|
|
|
5
47
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -74,7 +74,8 @@ export function Demo() {
|
|
|
74
74
|
- **`<WrittenResponse>`** — free-text writing with a live word counter and bounds messaging, graded **asynchronously**: it emits an ungraded submission (never a fake zero) and a SUBMITTED-verb xAPI statement, and renders a returned `GradeRecord` in `review` mode with per-criterion scores and inline corrections.
|
|
75
75
|
- **`<InteractiveVideo>`** — a video that stops at each quiz and asks its questions over itself, then plays on. **A formative tool**, for lessons and practice — deliver official summative exams with `<ActivitySequence>`. One player: a progress bar that marks every quiz and previews the caption under the pointer, speed, volume, captions drawn from WebVTT it parses itself (through a `captionsLoader` when the file needs the learner's credentials) — in one language or two at once, a second line under the first for a learner matching what they hear to what it means — a contents and transcript panel, picture-in-picture, fullscreen and a keyboard map with a shortcut sheet. A quiz covers the video and grows the player rather than scrolling inside it, every question of an opened quiz stays mounted so a rewind loses no answer, the controls are `inert` while it is open, and a **required** quiz holds both playback and seeking until it is answered. Answers report with the slot the question sits in and the quiz it belongs to, and `onProgress` gives a resume point that is never past an unanswered required quiz. A host with renderers of its own draws any question itself through `renderQuestion` — the video still counts it, tells it when it leaves the screen so it can stop its microphone, and holds Finish while its answer is still on its way. See the [interactive video guide](https://github.com/intellectif/learning-kit/blob/main/docs/interactive-video.md).
|
|
76
76
|
- **Delivery policies** — `delivery` on any activity, `<ActivitySequence>` or `<InteractiveVideo>` switches off feedback, solutions, hints or AI help for that paper, so one question serves practice and a final without being authored twice. It can only take away, an empty policy is exactly the default, and a pager's policy holds in every question it holds — a host's own renderer included. See [Delivery policies](https://github.com/intellectif/learning-kit/blob/main/docs/delivery.md).
|
|
77
|
-
- **
|
|
77
|
+
- **Scoring policies** — `scoring` on any activity, `<ActivitySequence>` or `<InteractiveVideo>` gives a practice question "Try again", chooses which try counts, and charges for tries and hints, saying what a hint costs before the learner asks. The right answer and "Explain my answer" wait until the tries end, a set waits for a question being tried again, and no policy changes nothing. See [Scoring policies](https://github.com/intellectif/learning-kit/blob/main/docs/scoring.md).
|
|
78
|
+
- **AI help for learners** — "Explain my answer" after grading and "Get a hint" before submit, in `<MultipleChoice>`, `<FillInTheBlanks>`, `<GapSelect>` and `<Dictation>` (explanations only), and "Get feedback on my draft" in `<WrittenResponse>` in practice — revise and ask again, and a correction that quotes words the learner never wrote refuses the feedback — through ports **you** supply with `<LkAiProvider>` or an `ai` prop (also on `<ActivitySequence>` and `<InteractiveVideo>`). The SDK never calls a model or holds a key: it builds the facts your model is given, refuses an explanation that contradicts the grade and a hint that contains the answer, marks everything a model wrote, and drops a late answer. Never in `exam`. What was shown reaches `onInteraction` with the model that wrote it and what the call cost; what was refused reaches it with the reason, and never the text. See the [AI guide](https://github.com/intellectif/learning-kit/blob/main/docs/ai.md).
|
|
78
79
|
- **`<ActivitySequence>`** — in-place "question set" pager (Previous/Next, "Question X of N", no scrolling, focus-managed). Accepts item groups and keeps their stimulus beside every question; `onSubmit` reports every raw answer with its `slotId`, which is the only response channel an `exam` sequence has. `onFinished` is the completion signal for a set that mixes scored and deferred-graded items, where `onComplete` can never fire. A read-aloud slot takes its storage from `recordingBinding`, whose methods are told which slot a take belongs to, and a `review` its per-word marks from `assessments`, keyed by `slotId` — there is a [worked example](https://github.com/intellectif/learning-kit/blob/main/docs/speech-assessment.md#in-a-question-set).
|
|
79
80
|
- **Resume and review a whole attempt** — `<ActivitySequence>` takes `defaultIndex`, `responses` and `submittedSlotIds` (read at mount; remount with a `key` to show a different attempt), so an interrupted paper reopens on the right question with the right answers and already-committed questions still committed. `onIndexChange` reports every position the pager lands on, including a clamp it had to apply. Pass `renderMode="review"` plus server-computed `outcomes` to render a finished attempt read-only. Pairs with `serializeAttemptState` / `restoreAttemptState` in `lk-core`.
|
|
80
81
|
- **`renderMode`** — `practice` (default: the component scores locally and reveals correctness), `exam` (never scores, never reveals; submit emits the raw response for the server to grade), `review` (read-only, marks correctness only from an `outcome` you supply). This is the single switch that takes grading off the client.
|
|
@@ -84,7 +85,7 @@ export function Demo() {
|
|
|
84
85
|
- **`<StimulusPanel>`** — a shared passage / recording / image (an item group's stimulus) as a landmark region; the sequence uses it, and a custom runner can too.
|
|
85
86
|
- **`<ActivityPreview>`** — an editor's preview. Renders a draft in any `renderMode` with a simulated `response` (marked with `evaluate()` in `review`), and a translatable notice — or your `fallback`, handed the issues — while `validateDraft` says the draft is not finished. Nothing it renders is recorded, and a recording's play limit is counted in memory only.
|
|
86
87
|
- **Custom activity types** — `renderers={{ 'my-type': MyRenderer }}` on the sequence; a key matching a built-in overrides it, so you can replace a bundled renderer without forking the sequencer. A renderer is given the same contract the SDK's own components have: a `question` prop that says when it is the question on screen (so it can stop its microphone), holds the set while its own work is in flight, gives it somewhere to portal a popover, and reports what the learner did through calls that keep one identity.
|
|
87
|
-
- **AI help in a question you draw** — `useAiHints` and `
|
|
88
|
+
- **AI help in a question you draw** — `useAiHints`, `useAiExplanation` and `useAiWritingFeedback` give a host's own renderer the rules, the facts and the refusals the bundled components use, without their buttons. `ask` does nothing where the rules say no, so an exam reaches no model however the page asks.
|
|
88
89
|
- **Rich text, opt-in** — `sanitizeHtml` renders author-supplied `questionHtml` / `promptHtml`. The SDK ships **no** sanitiser and injects no HTML without one; without it the escaped plain-text field is used. (`FillInTheBlanks` ignores `passageHtml` by design — its passage hosts the answer inputs.)
|
|
89
90
|
- **Media per question** — optional `image` / `audio` / `video` / `embed` (YouTube/Vimeo iframe) above the question; alt-text required for `image`/`embed` (WCAG).
|
|
90
91
|
- **Playback policy for listening papers** — an audio recording can declare `maxPlays`, `seek: 'none'` and `rate: 'fixed'`. The SDK then renders its own accessible transport (44px targets, a live plays-remaining status, an exhausted button that stays focusable and says why) and enforces the policy from the element's own events, so a hardware media key goes through the budget too. Wire `mediaBudget` on `<ActivitySequence>` to make a play budget survive a refresh.
|
|
@@ -94,7 +95,7 @@ export function Demo() {
|
|
|
94
95
|
- **`useSpeechRecorder(options)`** — the capture half of a read-aloud, usable on its own: microphone permission, an RMS level for a meter, a minimum take length, and an auto-stop measured from the **sample count** rather than a timer, so a take can never outrun its own limit. It yields **16 kHz mono 16-bit PCM WAV** — the one format `inspectWav` in `lk-core` measures without a decoder. SSR-safe by construction (support is discovered inside `start()`, never probed during render, so a server render and its hydration cannot disagree), and the microphone and the audio context are released on stop, discard, error and unmount alike. Where a Content-Security-Policy's `script-src` does not allow `blob:`, serve `CAPTURE_PROCESSOR_SOURCE` — exported beside the hook, with the contract it meets written on it — and pass its URL as `workletUrl`. A `workletUrl` that fails to load is not reported: the hook falls back to the main-thread `ScriptProcessorNode`, so check that the module is fetched.
|
|
95
96
|
- **`<ThemeProvider>` + `defaults.css`** — `--lk-*` design-token system; automatic dark mode via `prefers-color-scheme` (SSR-safe with `useSyncExternalStore`).
|
|
96
97
|
- **`createTailwindTheme(theme)`** — optional Tailwind interop; consume the SDK palette from your own utilities.
|
|
97
|
-
- **`<LkIntlProvider>`** — all
|
|
98
|
+
- **`<LkIntlProvider>`** — all 196 strings the SDK's own chrome renders, replaceable in one place, with a per-component `strings` prop for the exceptions. Interpolation and plurals are **functions**, not format strings, so your `Intl.PluralRules` does the work and TypeScript checks the arity. `locale` sets `lang` and derives `dir`; the skin uses logical properties, so RTL follows. The SDK ships the mechanism and **English only** — see [docs/i18n.md](https://github.com/intellectif/learning-kit/blob/main/docs/i18n.md).
|
|
98
99
|
- **WCAG 2.2 AA** — axe-clean unit + Playwright e2e tests; full keyboard operability; numerically-verified contrast.
|
|
99
100
|
- **RSC-compatible** — every component carries `'use client'` and hydrates inside a React Server Component tree.
|
|
100
101
|
|
|
@@ -118,7 +119,7 @@ export function Demo() {
|
|
|
118
119
|
| `@intellectif/lk-react/hooks/useSpeechRecorder` | Microphone capture to 16 kHz mono WAV, and `CAPTURE_PROCESSOR_SOURCE` for a self-hosted worklet |
|
|
119
120
|
| `@intellectif/lk-react/hooks/useXAPI` | LRS delivery (retry, never-throws) |
|
|
120
121
|
| `@intellectif/lk-react/ai/LkAiProvider` | `<LkAiProvider>`, `useLearnerAi`, and the `LearnerAi` type |
|
|
121
|
-
| `@intellectif/lk-react/ai/useAiHelp` | `useAiHints`, `useAiExplanation` — the AI rules without the SDK's own buttons |
|
|
122
|
+
| `@intellectif/lk-react/ai/useAiHelp` | `useAiHints`, `useAiExplanation`, `useAiWritingFeedback` — the AI rules without the SDK's own buttons |
|
|
122
123
|
| `@intellectif/lk-react/i18n/LkIntlProvider` | `<LkIntlProvider>`, `useLkStrings`, `useLkDirection`, `DEFAULT_STRINGS`, `mergeStrings`, `directionForLocale` |
|
|
123
124
|
| `@intellectif/lk-react/theme/ThemeProvider` | `<ThemeProvider>`, `darkTheme`, `useTheme`, `createTailwindTheme` |
|
|
124
125
|
| `@intellectif/lk-react/theme/defaults.css` | Tokens (required) |
|
|
@@ -159,15 +160,42 @@ that an exhaustive `switch` must handle, and a changed reset target for
|
|
|
159
160
|
[CHANGELOG](https://github.com/intellectif/learning-kit/blob/main/packages/lk-react/CHANGELOG.md)
|
|
160
161
|
before assuming a migration is needed.
|
|
161
162
|
|
|
163
|
+
## Releases & upgrading
|
|
164
|
+
|
|
165
|
+
- **What is supported, and since when** — [Features](https://github.com/intellectif/learning-kit/blob/main/docs/features.md): every activity and capability, the `lk-core` / `lk-react` versions it arrived in, and its guide.
|
|
166
|
+
- **What changed** — [GitHub Releases](https://github.com/intellectif/learning-kit/releases), one per package version, and the same notes in each package's `CHANGELOG.md` (it ships in the npm package, so it is in your `node_modules` too). Notes written since release notes gained a template — every release after lk-core 0.20.0 / lk-react 20.0.0 — start with a one-line summary and **Action required**: `none`, or what to do. Earlier notes lead with the detail; the version map in the upgrading guide says what each one asks of you.
|
|
167
|
+
- **How to upgrade** — [Upgrading](https://github.com/intellectif/learning-kit/blob/main/docs/upgrading.md): which `lk-core` goes with which `lk-react`, and a section per release saying what, if anything, you need to change. A `lk-react` major is often only the `lk-core` peer bump; the map says so.
|
|
168
|
+
- **Hearing about a release** — on GitHub, **Watch → Custom → Releases**, or subscribe to [the releases feed](https://github.com/intellectif/learning-kit/releases.atom). Better still, let your dependency bot bring each release to you as a pull request, with its notes — and keep the two packages together in one, since they move together:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
# .github/dependabot.yml — one entry per directory with a package.json
|
|
172
|
+
version: 2
|
|
173
|
+
updates:
|
|
174
|
+
- package-ecosystem: npm
|
|
175
|
+
directory: /
|
|
176
|
+
schedule: { interval: weekly }
|
|
177
|
+
groups:
|
|
178
|
+
learning-kit:
|
|
179
|
+
patterns: ["@intellectif/lk-*"]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
With Renovate: `"packageRules": [{ "matchPackageNames": ["@intellectif/lk-core", "@intellectif/lk-react"], "groupName": "learning-kit" }]`.
|
|
183
|
+
|
|
184
|
+
`lk-core` is still `0.x`, and a caret range on a `0.x` version matches only that minor: `^0.18.0` never installs `0.19.0`. A bot is how you find out there is one.
|
|
185
|
+
|
|
162
186
|
## Documentation
|
|
163
187
|
|
|
164
|
-
- [
|
|
188
|
+
- [Features](https://github.com/intellectif/learning-kit/blob/main/docs/features.md) — everything supported, and the versions each arrived in.
|
|
189
|
+
- [Upgrading](https://github.com/intellectif/learning-kit/blob/main/docs/upgrading.md) — which `lk-core` goes with which `lk-react`, and what each release asks of you.
|
|
165
190
|
- [Changelog](https://github.com/intellectif/learning-kit/blob/main/packages/lk-react/CHANGELOG.md) — every release, with the reasoning.
|
|
166
191
|
- [Authoring & content storage](https://github.com/intellectif/learning-kit/blob/main/docs/authoring.md)
|
|
167
192
|
- [Styling](https://github.com/intellectif/learning-kit/blob/main/docs/styling.md) — tokens, the skin, overrides, dark mode, Tailwind.
|
|
168
193
|
- [Internationalisation](https://github.com/intellectif/learning-kit/blob/main/docs/i18n.md) — the full string surface, precedence, plurals, RTL.
|
|
169
194
|
- [Interactive video](https://github.com/intellectif/learning-kit/blob/main/docs/interactive-video.md) — the timeline model, the player's props, captions, resume and required quizzes.
|
|
170
195
|
- [Speech assessment](https://github.com/intellectif/learning-kit/blob/main/docs/speech-assessment.md) — the read-aloud item, the evidence an assessor must produce, and how a grade is computed.
|
|
196
|
+
- [Delivery policies](https://github.com/intellectif/learning-kit/blob/main/docs/delivery.md) — what a school lets a learner see: feedback, solutions, hints and AI help, per paper.
|
|
197
|
+
- [Scoring policies](https://github.com/intellectif/learning-kit/blob/main/docs/scoring.md) — "Try again", which try counts, and what tries and hints cost, per paper.
|
|
198
|
+
- [AI help for learners](https://github.com/intellectif/learning-kit/blob/main/docs/ai.md) — connecting your model, what it is given, what the SDK refuses to show, and testing your prompts.
|
|
171
199
|
- [Project README](https://github.com/intellectif/learning-kit#readme) — full picture & monorepo layout.
|
|
172
200
|
|
|
173
201
|
## License
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { XAPIStatement, WrittenResponseData, LearnerResponse, ItemOutcome, InteractionEvent, ThemeTokens, DeliveryPolicy } from '@intellectif/lk-core';
|
|
2
|
-
import {
|
|
2
|
+
import { LearnerAi } from './ai/LkAiProvider.js';
|
|
3
|
+
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-CrtIcRcK.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Payload delivered when the learner submits a written response. Grading is
|
|
@@ -95,11 +96,20 @@ interface WrittenResponseProps {
|
|
|
95
96
|
locale?: string;
|
|
96
97
|
disabled?: boolean;
|
|
97
98
|
/**
|
|
98
|
-
* The delivery policy. An essay is graded later, so
|
|
99
|
-
*
|
|
100
|
-
* `
|
|
99
|
+
* The delivery policy. An essay is graded later, so `feedback` reaches it —
|
|
100
|
+
* `false` reads a returned grade back as nothing in `review` — and so does
|
|
101
|
+
* AI feedback on a draft, which needs `feedback`, `solutions` and
|
|
102
|
+
* `ai.explanations`. See `DeliveryPolicy` in lk-core.
|
|
101
103
|
*/
|
|
102
104
|
delivery?: DeliveryPolicy | null;
|
|
105
|
+
/**
|
|
106
|
+
* The host's AI ports, overriding `LkAiProvider`'s. With a `writingFeedback`
|
|
107
|
+
* port, a learner in `practice` can ask for feedback on a draft before
|
|
108
|
+
* submitting it — up to `maxWritingFeedback` times — and revise. Every
|
|
109
|
+
* correction in it quotes the learner's own words, or the SDK refuses it.
|
|
110
|
+
* Never in `exam` or `review`. See {@link LearnerAi}.
|
|
111
|
+
*/
|
|
112
|
+
ai?: LearnerAi;
|
|
103
113
|
}
|
|
104
114
|
|
|
105
115
|
export type { WrittenResponseProps as W, WrittenResponseSubmission as a };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { XAPIStatement, WrittenResponseData, LearnerResponse, ItemOutcome, InteractionEvent, ThemeTokens, DeliveryPolicy } from '@intellectif/lk-core';
|
|
2
|
-
import {
|
|
2
|
+
import { LearnerAi } from './ai/LkAiProvider.cjs';
|
|
3
|
+
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-CO0XLEN6.cjs';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Payload delivered when the learner submits a written response. Grading is
|
|
@@ -95,11 +96,20 @@ interface WrittenResponseProps {
|
|
|
95
96
|
locale?: string;
|
|
96
97
|
disabled?: boolean;
|
|
97
98
|
/**
|
|
98
|
-
* The delivery policy. An essay is graded later, so
|
|
99
|
-
*
|
|
100
|
-
* `
|
|
99
|
+
* The delivery policy. An essay is graded later, so `feedback` reaches it —
|
|
100
|
+
* `false` reads a returned grade back as nothing in `review` — and so does
|
|
101
|
+
* AI feedback on a draft, which needs `feedback`, `solutions` and
|
|
102
|
+
* `ai.explanations`. See `DeliveryPolicy` in lk-core.
|
|
101
103
|
*/
|
|
102
104
|
delivery?: DeliveryPolicy | null;
|
|
105
|
+
/**
|
|
106
|
+
* The host's AI ports, overriding `LkAiProvider`'s. With a `writingFeedback`
|
|
107
|
+
* port, a learner in `practice` can ask for feedback on a draft before
|
|
108
|
+
* submitting it — up to `maxWritingFeedback` times — and revise. Every
|
|
109
|
+
* correction in it quotes the learner's own words, or the SDK refuses it.
|
|
110
|
+
* Never in `exam` or `review`. See {@link LearnerAi}.
|
|
111
|
+
*/
|
|
112
|
+
ai?: LearnerAi;
|
|
103
113
|
}
|
|
104
114
|
|
|
105
115
|
export type { WrittenResponseProps as W, WrittenResponseSubmission as a };
|
package/dist/ai/LkAiProvider.cjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkOJGTJOWI_cjs = require('../chunk-OJGTJOWI.cjs');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
Object.defineProperty(exports, "LkAiProvider", {
|
|
9
9
|
enumerable: true,
|
|
10
|
-
get: function () { return
|
|
10
|
+
get: function () { return chunkOJGTJOWI_cjs.LkAiProvider; }
|
|
11
11
|
});
|
|
12
12
|
Object.defineProperty(exports, "useLearnerAi", {
|
|
13
13
|
enumerable: true,
|
|
14
|
-
get: function () { return
|
|
14
|
+
get: function () { return chunkOJGTJOWI_cjs.useLearnerAi; }
|
|
15
15
|
});
|
|
16
16
|
//# sourceMappingURL=LkAiProvider.cjs.map
|
|
17
17
|
//# sourceMappingURL=LkAiProvider.cjs.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AiExplanationRequest, AiTextResult, AiHintRequest } from '@intellectif/lk-core';
|
|
1
|
+
import { AiExplanationRequest, AiTextResult, AiHintRequest, AiWritingFeedbackRequest, AiWritingFeedbackResult } from '@intellectif/lk-core';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -29,9 +29,22 @@ interface LearnerAi {
|
|
|
29
29
|
/** The most hints a learner can ask for on one question. Default 3, at most 10. */
|
|
30
30
|
maxHints?: number;
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
32
|
+
* Gives feedback on a draft of a written response, before the learner
|
|
33
|
+
* submits it: the overall feedback as text, corrections that quote the
|
|
34
|
+
* draft, and a judgement per rubric criterion. See `checkAiWritingFeedback`
|
|
35
|
+
* in lk-core for what is refused.
|
|
36
|
+
*/
|
|
37
|
+
writingFeedback?: (request: AiWritingFeedbackRequest, options: {
|
|
38
|
+
signal: AbortSignal;
|
|
39
|
+
}) => Promise<AiWritingFeedbackResult>;
|
|
40
|
+
/** How many times a learner can ask for feedback on one written response. Default 3, at most 10. */
|
|
41
|
+
maxWritingFeedback?: number;
|
|
42
|
+
/**
|
|
43
|
+
* The language to write explanations and hints in, as a tag (`es`,
|
|
44
|
+
* `pt-BR`). Defaults to the component's `locale`: the interface language,
|
|
45
|
+
* which the buttons around the help are in, and usually the right one. In a
|
|
46
|
+
* language course it need not be the item's — English items, explained in
|
|
47
|
+
* Spanish — and the item's own language reaches your port as `facts.locale`.
|
|
35
48
|
*/
|
|
36
49
|
learnerLocale?: string;
|
|
37
50
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AiExplanationRequest, AiTextResult, AiHintRequest } from '@intellectif/lk-core';
|
|
1
|
+
import { AiExplanationRequest, AiTextResult, AiHintRequest, AiWritingFeedbackRequest, AiWritingFeedbackResult } from '@intellectif/lk-core';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -29,9 +29,22 @@ interface LearnerAi {
|
|
|
29
29
|
/** The most hints a learner can ask for on one question. Default 3, at most 10. */
|
|
30
30
|
maxHints?: number;
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
32
|
+
* Gives feedback on a draft of a written response, before the learner
|
|
33
|
+
* submits it: the overall feedback as text, corrections that quote the
|
|
34
|
+
* draft, and a judgement per rubric criterion. See `checkAiWritingFeedback`
|
|
35
|
+
* in lk-core for what is refused.
|
|
36
|
+
*/
|
|
37
|
+
writingFeedback?: (request: AiWritingFeedbackRequest, options: {
|
|
38
|
+
signal: AbortSignal;
|
|
39
|
+
}) => Promise<AiWritingFeedbackResult>;
|
|
40
|
+
/** How many times a learner can ask for feedback on one written response. Default 3, at most 10. */
|
|
41
|
+
maxWritingFeedback?: number;
|
|
42
|
+
/**
|
|
43
|
+
* The language to write explanations and hints in, as a tag (`es`,
|
|
44
|
+
* `pt-BR`). Defaults to the component's `locale`: the interface language,
|
|
45
|
+
* which the buttons around the help are in, and usually the right one. In a
|
|
46
|
+
* language course it need not be the item's — English items, explained in
|
|
47
|
+
* Spanish — and the item's own language reaches your port as `facts.locale`.
|
|
35
48
|
*/
|
|
36
49
|
learnerLocale?: string;
|
|
37
50
|
}
|
package/dist/ai/LkAiProvider.js
CHANGED
package/dist/ai/useAiHelp.cjs
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
5
|
-
require('../chunk-
|
|
6
|
-
require('../chunk-
|
|
4
|
+
var chunkPZVRZ6OX_cjs = require('../chunk-PZVRZ6OX.cjs');
|
|
5
|
+
require('../chunk-OJGTJOWI.cjs');
|
|
6
|
+
require('../chunk-J2QIHZ3H.cjs');
|
|
7
7
|
require('../chunk-EANGKAKG.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
Object.defineProperty(exports, "useAiExplanation", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkPZVRZ6OX_cjs.useAiExplanation; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "useAiHints", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkPZVRZ6OX_cjs.useAiHints; }
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, "useAiWritingFeedback", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return chunkPZVRZ6OX_cjs.useAiWritingFeedback; }
|
|
18
22
|
});
|
|
19
23
|
//# sourceMappingURL=useAiHelp.cjs.map
|
|
20
24
|
//# sourceMappingURL=useAiHelp.cjs.map
|
package/dist/ai/useAiHelp.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AiTextResult, LearnerResponse, InteractionEvent, DeliveryPolicy, ItemOutcome } from '@intellectif/lk-core';
|
|
2
|
-
import { g as RenderableActivity, e as RenderMode } from '../types-
|
|
1
|
+
import { AiTextResult, LearnerResponse, InteractionEvent, DeliveryPolicy, ItemOutcome, AiWritingFeedback } from '@intellectif/lk-core';
|
|
2
|
+
import { g as RenderableActivity, e as RenderMode } from '../types-CO0XLEN6.cjs';
|
|
3
3
|
import { LearnerAi } from './LkAiProvider.cjs';
|
|
4
4
|
import '../machine-CuwKqWXC.cjs';
|
|
5
5
|
import 'react';
|
|
@@ -148,5 +148,60 @@ declare function useAiExplanation(input: AiExplanationInput): AiExplanationHelp;
|
|
|
148
148
|
* given — while `offered` turns false. Another question starts with none.
|
|
149
149
|
*/
|
|
150
150
|
declare function useAiHints(input: AiHintsInput): AiHintsHelp;
|
|
151
|
+
interface AiWritingFeedbackInput extends AiHelpSituation {
|
|
152
|
+
/** A disabled question takes no feedback, as it takes no answer. */
|
|
153
|
+
disabled?: boolean;
|
|
154
|
+
}
|
|
155
|
+
interface AiWritingFeedbackHelp {
|
|
156
|
+
/**
|
|
157
|
+
* Whether the learner may ask for feedback here at all: a port is present,
|
|
158
|
+
* the mode is `practice`, the answer is not in, the question is a written
|
|
159
|
+
* response that is not disabled or redacted, its author left explanations on,
|
|
160
|
+
* and the paper shows feedback and solutions and allows AI explanations. It
|
|
161
|
+
* stays true once `used` reaches `limit`.
|
|
162
|
+
*/
|
|
163
|
+
offered: boolean;
|
|
164
|
+
status: 'idle' | 'loading' | 'unavailable';
|
|
165
|
+
/** Every piece of feedback shown for this question, oldest first. */
|
|
166
|
+
feedback: readonly AiWritingFeedback[];
|
|
167
|
+
/** The latest, or `null` before any. Its `text` is text, never HTML. */
|
|
168
|
+
latest: AiWritingFeedback | null;
|
|
169
|
+
/**
|
|
170
|
+
* Whether `latest` is about the draft as it stands. Once the learner revises,
|
|
171
|
+
* its corrections point at words that may no longer be there: say so.
|
|
172
|
+
*/
|
|
173
|
+
current: boolean;
|
|
174
|
+
/** The host's `maxWritingFeedback`, as a whole number from 1 to 10 (3 by default). */
|
|
175
|
+
limit: number;
|
|
176
|
+
/** How many times feedback has been shown. A refused reply is not counted. */
|
|
177
|
+
used: number;
|
|
178
|
+
/**
|
|
179
|
+
* Asks for feedback on the draft as it stands. Does nothing at the limit,
|
|
180
|
+
* while a call is on its way, on an empty draft, or where `offered` is false.
|
|
181
|
+
* One identity for the life of the question.
|
|
182
|
+
*/
|
|
183
|
+
ask: () => void;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* "Get feedback on my draft", without the SDK's own button and panel: the
|
|
187
|
+
* rules, the call, the checks and the record, for a written response you draw
|
|
188
|
+
* yourself.
|
|
189
|
+
*
|
|
190
|
+
* It is what `<WrittenResponse>` uses, so a host's own essay box gets feedback
|
|
191
|
+
* on the same terms: only in `practice` before submit, up to the host's limit,
|
|
192
|
+
* and never feedback that corrects words the learner did not write — which is
|
|
193
|
+
* refused rather than shown, and not counted.
|
|
194
|
+
*
|
|
195
|
+
* ```tsx
|
|
196
|
+
* const { offered, status, latest, current, used, limit, ask } = useAiWritingFeedback({
|
|
197
|
+
* data, response, submitted, renderMode, ai: question.ai,
|
|
198
|
+
* });
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* **Say who wrote it**, as the SDK's own panel does: "Written by AI. It can make
|
|
202
|
+
* mistakes." And show `indicativeScore` as what it is — an indication, not a
|
|
203
|
+
* grade.
|
|
204
|
+
*/
|
|
205
|
+
declare function useAiWritingFeedback(input: AiWritingFeedbackInput): AiWritingFeedbackHelp;
|
|
151
206
|
|
|
152
|
-
export { type AiExplanationHelp, type AiExplanationInput, type AiHelpSituation, type AiHintsHelp, type AiHintsInput, useAiExplanation, useAiHints };
|
|
207
|
+
export { type AiExplanationHelp, type AiExplanationInput, type AiHelpSituation, type AiHintsHelp, type AiHintsInput, type AiWritingFeedbackHelp, type AiWritingFeedbackInput, useAiExplanation, useAiHints, useAiWritingFeedback };
|
package/dist/ai/useAiHelp.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AiTextResult, LearnerResponse, InteractionEvent, DeliveryPolicy, ItemOutcome } from '@intellectif/lk-core';
|
|
2
|
-
import { g as RenderableActivity, e as RenderMode } from '../types-
|
|
1
|
+
import { AiTextResult, LearnerResponse, InteractionEvent, DeliveryPolicy, ItemOutcome, AiWritingFeedback } from '@intellectif/lk-core';
|
|
2
|
+
import { g as RenderableActivity, e as RenderMode } from '../types-CrtIcRcK.js';
|
|
3
3
|
import { LearnerAi } from './LkAiProvider.js';
|
|
4
4
|
import '../machine-CuwKqWXC.js';
|
|
5
5
|
import 'react';
|
|
@@ -148,5 +148,60 @@ declare function useAiExplanation(input: AiExplanationInput): AiExplanationHelp;
|
|
|
148
148
|
* given — while `offered` turns false. Another question starts with none.
|
|
149
149
|
*/
|
|
150
150
|
declare function useAiHints(input: AiHintsInput): AiHintsHelp;
|
|
151
|
+
interface AiWritingFeedbackInput extends AiHelpSituation {
|
|
152
|
+
/** A disabled question takes no feedback, as it takes no answer. */
|
|
153
|
+
disabled?: boolean;
|
|
154
|
+
}
|
|
155
|
+
interface AiWritingFeedbackHelp {
|
|
156
|
+
/**
|
|
157
|
+
* Whether the learner may ask for feedback here at all: a port is present,
|
|
158
|
+
* the mode is `practice`, the answer is not in, the question is a written
|
|
159
|
+
* response that is not disabled or redacted, its author left explanations on,
|
|
160
|
+
* and the paper shows feedback and solutions and allows AI explanations. It
|
|
161
|
+
* stays true once `used` reaches `limit`.
|
|
162
|
+
*/
|
|
163
|
+
offered: boolean;
|
|
164
|
+
status: 'idle' | 'loading' | 'unavailable';
|
|
165
|
+
/** Every piece of feedback shown for this question, oldest first. */
|
|
166
|
+
feedback: readonly AiWritingFeedback[];
|
|
167
|
+
/** The latest, or `null` before any. Its `text` is text, never HTML. */
|
|
168
|
+
latest: AiWritingFeedback | null;
|
|
169
|
+
/**
|
|
170
|
+
* Whether `latest` is about the draft as it stands. Once the learner revises,
|
|
171
|
+
* its corrections point at words that may no longer be there: say so.
|
|
172
|
+
*/
|
|
173
|
+
current: boolean;
|
|
174
|
+
/** The host's `maxWritingFeedback`, as a whole number from 1 to 10 (3 by default). */
|
|
175
|
+
limit: number;
|
|
176
|
+
/** How many times feedback has been shown. A refused reply is not counted. */
|
|
177
|
+
used: number;
|
|
178
|
+
/**
|
|
179
|
+
* Asks for feedback on the draft as it stands. Does nothing at the limit,
|
|
180
|
+
* while a call is on its way, on an empty draft, or where `offered` is false.
|
|
181
|
+
* One identity for the life of the question.
|
|
182
|
+
*/
|
|
183
|
+
ask: () => void;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* "Get feedback on my draft", without the SDK's own button and panel: the
|
|
187
|
+
* rules, the call, the checks and the record, for a written response you draw
|
|
188
|
+
* yourself.
|
|
189
|
+
*
|
|
190
|
+
* It is what `<WrittenResponse>` uses, so a host's own essay box gets feedback
|
|
191
|
+
* on the same terms: only in `practice` before submit, up to the host's limit,
|
|
192
|
+
* and never feedback that corrects words the learner did not write — which is
|
|
193
|
+
* refused rather than shown, and not counted.
|
|
194
|
+
*
|
|
195
|
+
* ```tsx
|
|
196
|
+
* const { offered, status, latest, current, used, limit, ask } = useAiWritingFeedback({
|
|
197
|
+
* data, response, submitted, renderMode, ai: question.ai,
|
|
198
|
+
* });
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* **Say who wrote it**, as the SDK's own panel does: "Written by AI. It can make
|
|
202
|
+
* mistakes." And show `indicativeScore` as what it is — an indication, not a
|
|
203
|
+
* grade.
|
|
204
|
+
*/
|
|
205
|
+
declare function useAiWritingFeedback(input: AiWritingFeedbackInput): AiWritingFeedbackHelp;
|
|
151
206
|
|
|
152
|
-
export { type AiExplanationHelp, type AiExplanationInput, type AiHelpSituation, type AiHintsHelp, type AiHintsInput, useAiExplanation, useAiHints };
|
|
207
|
+
export { type AiExplanationHelp, type AiExplanationInput, type AiHelpSituation, type AiHintsHelp, type AiHintsInput, type AiWritingFeedbackHelp, type AiWritingFeedbackInput, useAiExplanation, useAiHints, useAiWritingFeedback };
|
package/dist/ai/useAiHelp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
export { useAiExplanation, useAiHints } from '../chunk-
|
|
3
|
-
import '../chunk-
|
|
4
|
-
import '../chunk-
|
|
2
|
+
export { useAiExplanation, useAiHints, useAiWritingFeedback } from '../chunk-TRXUZSOY.js';
|
|
3
|
+
import '../chunk-RX3A6KIY.js';
|
|
4
|
+
import '../chunk-U4KTOH7C.js';
|
|
5
5
|
import '../chunk-PPFVTXGJ.js';
|
|
6
6
|
//# sourceMappingURL=useAiHelp.js.map
|
|
7
7
|
//# sourceMappingURL=useAiHelp.js.map
|