@intellectif/lk-react 18.0.0 → 19.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 +74 -0
- package/README.md +4 -2
- package/dist/{WrittenResponse-B4kY-U0v.d.ts → WrittenResponse-CeHY5u3W.d.ts} +1 -1
- package/dist/{WrittenResponse-Dl3zah22.d.cts → WrittenResponse-DT_Yqbq1.d.cts} +1 -1
- package/dist/ai/useAiHelp.cjs +20 -0
- package/dist/ai/useAiHelp.cjs.map +1 -0
- package/dist/ai/useAiHelp.d.cts +146 -0
- package/dist/ai/useAiHelp.d.ts +146 -0
- package/dist/ai/useAiHelp.js +7 -0
- package/dist/ai/useAiHelp.js.map +1 -0
- package/dist/{chunk-XEGBGKHV.cjs → chunk-2X2NZF46.cjs} +206 -52
- package/dist/chunk-2X2NZF46.cjs.map +1 -0
- package/dist/{chunk-V5BTVGPA.js → chunk-4NERCBOW.js} +4 -3
- package/dist/chunk-4NERCBOW.js.map +1 -0
- package/dist/{chunk-Z5XY66PO.cjs → chunk-55W2472T.cjs} +16 -16
- package/dist/chunk-55W2472T.cjs.map +1 -0
- package/dist/{chunk-HZMILQYO.js → chunk-5QCZZBOX.js} +5 -4
- package/dist/chunk-5QCZZBOX.js.map +1 -0
- package/dist/{chunk-H3IRVX7J.js → chunk-7NNMDZUU.js} +9 -9
- package/dist/chunk-7NNMDZUU.js.map +1 -0
- package/dist/{chunk-BAKLJKFZ.cjs → chunk-APZ6JFN6.cjs} +4 -29
- package/dist/chunk-APZ6JFN6.cjs.map +1 -0
- package/dist/{chunk-H63O5HPW.cjs → chunk-CQNKZ435.cjs} +8 -7
- package/dist/chunk-CQNKZ435.cjs.map +1 -0
- package/dist/chunk-EANGKAKG.cjs +32 -0
- package/dist/chunk-EANGKAKG.cjs.map +1 -0
- package/dist/{chunk-YTGRXD23.js → chunk-FEOFX4QW.js} +4 -25
- package/dist/chunk-FEOFX4QW.js.map +1 -0
- package/dist/{chunk-QJW3K6JN.js → chunk-G7AGM2Y7.js} +4 -3
- package/dist/chunk-G7AGM2Y7.js.map +1 -0
- package/dist/chunk-JVWLXVYG.cjs +27 -0
- package/dist/chunk-JVWLXVYG.cjs.map +1 -0
- package/dist/chunk-KGDGYRBL.cjs +117 -0
- package/dist/chunk-KGDGYRBL.cjs.map +1 -0
- package/dist/{chunk-UYQBEPNZ.js → chunk-KOFA54C7.js} +15 -8
- package/dist/chunk-KOFA54C7.js.map +1 -0
- package/dist/{chunk-UQIRDE52.cjs → chunk-LX2X4KC7.cjs} +6 -5
- package/dist/chunk-LX2X4KC7.cjs.map +1 -0
- package/dist/{chunk-RZ52SEYV.cjs → chunk-NGFTSRKO.cjs} +10 -9
- package/dist/chunk-NGFTSRKO.cjs.map +1 -0
- package/dist/{chunk-ALH6TUX2.js → chunk-NLTU5JFD.js} +5 -4
- package/dist/chunk-NLTU5JFD.js.map +1 -0
- package/dist/{chunk-6RRFH7C4.cjs → chunk-NZM3M5IR.cjs} +39 -54
- package/dist/chunk-NZM3M5IR.cjs.map +1 -0
- package/dist/{chunk-KWKB74KL.js → chunk-OWV7VRMQ.js} +198 -44
- package/dist/chunk-OWV7VRMQ.js.map +1 -0
- package/dist/chunk-PPFVTXGJ.js +27 -0
- package/dist/chunk-PPFVTXGJ.js.map +1 -0
- package/dist/chunk-QRT2W5N5.js +114 -0
- package/dist/chunk-QRT2W5N5.js.map +1 -0
- package/dist/{chunk-QHK6PTUR.js → chunk-SEQTGOOU.js} +5 -4
- package/dist/chunk-SEQTGOOU.js.map +1 -0
- package/dist/chunk-SXU26SFO.cjs +253 -0
- package/dist/chunk-SXU26SFO.cjs.map +1 -0
- package/dist/chunk-TEAVPUMX.js +22 -0
- package/dist/chunk-TEAVPUMX.js.map +1 -0
- package/dist/{chunk-KP57YCYQ.js → chunk-UXV3V5NH.js} +23 -35
- package/dist/chunk-UXV3V5NH.js.map +1 -0
- package/dist/{chunk-3TJSFPO4.cjs → chunk-WKA6FUR4.cjs} +26 -19
- package/dist/chunk-WKA6FUR4.cjs.map +1 -0
- package/dist/{chunk-QA42VDTA.cjs → chunk-XAIJNGTU.cjs} +12 -11
- package/dist/chunk-XAIJNGTU.cjs.map +1 -0
- package/dist/{chunk-6DTW5T3Z.js → chunk-XHF376ES.js} +5 -4
- package/dist/chunk-XHF376ES.js.map +1 -0
- package/dist/{chunk-TI23GIFM.cjs → chunk-XUQ4KRTT.cjs} +12 -11
- package/dist/chunk-XUQ4KRTT.cjs.map +1 -0
- package/dist/chunk-YIYMBCPV.js +250 -0
- package/dist/chunk-YIYMBCPV.js.map +1 -0
- package/dist/{chunk-JKMBFHER.cjs → chunk-ZME5FMED.cjs} +12 -11
- package/dist/chunk-ZME5FMED.cjs.map +1 -0
- package/dist/components/ActivityPreview.cjs +14 -11
- package/dist/components/ActivityPreview.d.cts +7 -3
- package/dist/components/ActivityPreview.d.ts +7 -3
- package/dist/components/ActivityPreview.js +13 -10
- package/dist/components/ActivitySequence.cjs +14 -11
- package/dist/components/ActivitySequence.d.cts +75 -11
- package/dist/components/ActivitySequence.d.ts +75 -11
- package/dist/components/ActivitySequence.js +13 -10
- package/dist/components/Dictation.cjs +7 -4
- package/dist/components/Dictation.d.cts +1 -1
- package/dist/components/Dictation.d.ts +1 -1
- package/dist/components/Dictation.js +6 -3
- package/dist/components/FillInTheBlanks.cjs +7 -4
- package/dist/components/FillInTheBlanks.d.cts +1 -1
- package/dist/components/FillInTheBlanks.d.ts +1 -1
- package/dist/components/FillInTheBlanks.js +6 -3
- package/dist/components/GapSelect.cjs +7 -4
- package/dist/components/GapSelect.d.cts +1 -1
- package/dist/components/GapSelect.d.ts +1 -1
- package/dist/components/GapSelect.js +6 -3
- package/dist/components/InteractiveVideo.cjs +14 -11
- package/dist/components/InteractiveVideo.d.cts +2 -2
- package/dist/components/InteractiveVideo.d.ts +2 -2
- package/dist/components/InteractiveVideo.js +12 -9
- package/dist/components/MultipleChoice.cjs +7 -4
- package/dist/components/MultipleChoice.d.cts +1 -1
- package/dist/components/MultipleChoice.d.ts +1 -1
- package/dist/components/MultipleChoice.js +6 -3
- package/dist/components/PronunciationFeedback.cjs +4 -3
- package/dist/components/PronunciationFeedback.d.cts +1 -1
- package/dist/components/PronunciationFeedback.d.ts +1 -1
- package/dist/components/PronunciationFeedback.js +3 -2
- package/dist/components/ReadAloud.cjs +6 -4
- package/dist/components/ReadAloud.d.cts +2 -2
- package/dist/components/ReadAloud.d.ts +2 -2
- package/dist/components/ReadAloud.js +5 -3
- package/dist/components/StimulusPanel.d.cts +1 -1
- package/dist/components/StimulusPanel.d.ts +1 -1
- package/dist/components/WrittenResponse.cjs +4 -3
- package/dist/components/WrittenResponse.d.cts +3 -3
- package/dist/components/WrittenResponse.d.ts +3 -3
- package/dist/components/WrittenResponse.js +3 -2
- package/dist/i18n/LkIntlProvider.d.cts +2 -2
- package/dist/i18n/LkIntlProvider.d.ts +2 -2
- package/dist/index.cjs +34 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +15 -12
- package/dist/index.js.map +1 -1
- package/dist/{strings-PCYKWCwd.d.ts → types-BY-4S5Rd.d.ts} +761 -761
- package/dist/{strings-BOPKhnS-.d.cts → types-DtPYG1hh.d.cts} +761 -761
- package/package.json +13 -3
- package/dist/chunk-3TJSFPO4.cjs.map +0 -1
- package/dist/chunk-5F4Q6JT7.cjs +0 -289
- package/dist/chunk-5F4Q6JT7.cjs.map +0 -1
- package/dist/chunk-6DTW5T3Z.js.map +0 -1
- package/dist/chunk-6RRFH7C4.cjs.map +0 -1
- package/dist/chunk-ALH6TUX2.js.map +0 -1
- package/dist/chunk-BAKLJKFZ.cjs.map +0 -1
- package/dist/chunk-GR33G5QM.js +0 -286
- package/dist/chunk-GR33G5QM.js.map +0 -1
- package/dist/chunk-H3IRVX7J.js.map +0 -1
- package/dist/chunk-H63O5HPW.cjs.map +0 -1
- package/dist/chunk-HZMILQYO.js.map +0 -1
- package/dist/chunk-JKMBFHER.cjs.map +0 -1
- package/dist/chunk-KP57YCYQ.js.map +0 -1
- package/dist/chunk-KWKB74KL.js.map +0 -1
- package/dist/chunk-QA42VDTA.cjs.map +0 -1
- package/dist/chunk-QHK6PTUR.js.map +0 -1
- package/dist/chunk-QJW3K6JN.js.map +0 -1
- package/dist/chunk-RZ52SEYV.cjs.map +0 -1
- package/dist/chunk-TI23GIFM.cjs.map +0 -1
- package/dist/chunk-UQIRDE52.cjs.map +0 -1
- package/dist/chunk-UYQBEPNZ.js.map +0 -1
- package/dist/chunk-V5BTVGPA.js.map +0 -1
- package/dist/chunk-XEGBGKHV.cjs.map +0 -1
- package/dist/chunk-YTGRXD23.js.map +0 -1
- package/dist/chunk-Z5XY66PO.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
# @intellectif/lk-react
|
|
2
2
|
|
|
3
|
+
## 19.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- d576382: AI help now reports what it cost and what was refused.
|
|
8
|
+
|
|
9
|
+
- **`ai-hint-shown` and `ai-explanation-shown` carry `usage`** when your port sent it, beside the
|
|
10
|
+
`provenance` they already carried. What a learner was shown and what it cost are then one record,
|
|
11
|
+
keyed to the attempt — no second channel to reconcile.
|
|
12
|
+
- **`ai-help-refused` is new**, from the same one implementation the components and the hooks share
|
|
13
|
+
(`useAiHints`, `useAiExplanation`). It fires where a learner is told help is not available, with
|
|
14
|
+
`feature` (`hint` or `explanation`), `reason` (`reveals-answer`, `contradicts-grade`, `malformed`,
|
|
15
|
+
`empty`, `too-long`) and, for a hint, `hintNumber`. **The text is never carried:** a hint refused
|
|
16
|
+
for revealing the answer contains the answer, and interactions are logged.
|
|
17
|
+
|
|
18
|
+
A host that keeps every interaction will start seeing this kind. It is additive — nothing that
|
|
19
|
+
was emitted before has changed — but a `switch` over `InteractionKind` with no default will not
|
|
20
|
+
know it.
|
|
21
|
+
|
|
22
|
+
**Major** because the peer range moves to `@intellectif/lk-core@^0.19.0`, whose `ai-check` entry
|
|
23
|
+
point and `AiTextResult.usage` come with it. No React API was removed or renamed, and a host that
|
|
24
|
+
passes no AI port sees nothing new.
|
|
25
|
+
|
|
26
|
+
See `docs/ai.md`.
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- Updated dependencies [d576382]
|
|
31
|
+
- @intellectif/lk-core@0.19.0
|
|
32
|
+
|
|
33
|
+
## 18.1.0
|
|
34
|
+
|
|
35
|
+
### Minor Changes
|
|
36
|
+
|
|
37
|
+
- 50c3285: A question a host draws inside `<ActivitySequence>` gets everything one the SDK draws has, and the AI
|
|
38
|
+
rules are available without the SDK's buttons.
|
|
39
|
+
|
|
40
|
+
- **`renderers` overrides get a `question` prop** (`SequenceQuestion`), the pager's half of the
|
|
41
|
+
contract, as `renderQuestion` gave one to `<InteractiveVideo>` in 16.1.0:
|
|
42
|
+
- `active` — whether this is the question on screen. **Stop the microphone, any timer and any
|
|
43
|
+
speech when it turns `false`:** the pager pauses the media inside the question and stops the
|
|
44
|
+
recorders the SDK started, but cannot reach one it did not create;
|
|
45
|
+
- `setPending(true/false)` — work of your own is on its way (an upload, a save, a judgement).
|
|
46
|
+
`onFinished` and `onComplete` wait for it, so a set is never reported a moment before the last
|
|
47
|
+
answer settles. Call it with `false` however the work ends, a failure included;
|
|
48
|
+
- `portalContainer` — a node inside this question's own pane. Portal a popover into it rather than
|
|
49
|
+
into `document.body`, and it is hidden when the learner pages away and painted with the question
|
|
50
|
+
in fullscreen;
|
|
51
|
+
- `clear()` — the learner withdrew their answer: the slot holds nothing again, and the set is
|
|
52
|
+
unfinished until it is answered again;
|
|
53
|
+
- `emit(type, payload?)` — an interaction, with this question's `activityId` and the time filled
|
|
54
|
+
in;
|
|
55
|
+
- `slot` — the identity to store the answer against, the same object `onSubmit` is handed.
|
|
56
|
+
- **Every call keeps one identity for the life of the set**, `onSubmit` and `onComplete` included, so
|
|
57
|
+
a renderer may hold them in an effect and a host that re-renders on every keystroke does not re-run
|
|
58
|
+
it.
|
|
59
|
+
- **New: `useAiHints` and `useAiExplanation`** (`@intellectif/lk-react/ai/useAiHelp`, also on the
|
|
60
|
+
root) — AI help for a question you draw yourself: the same rules, facts, checks and records the
|
|
61
|
+
bundled components use, with your own markup. `ask` does nothing where the rules say no, so a page
|
|
62
|
+
drawing its own button reaches no model in an `exam`. The SDK's own components are built on these
|
|
63
|
+
hooks, so there is one implementation of the rules and not two.
|
|
64
|
+
- **The paper decides the mode.** A question inside `<ActivitySequence>` or `<InteractiveVideo>` now
|
|
65
|
+
knows the mode it is being delivered in, so the hooks refuse help on an `exam` paper even when the
|
|
66
|
+
host does not pass `renderMode` to them, or passes `practice` — which a component that defaults it
|
|
67
|
+
can do inside an exam. Without that, a host's own question under an `LkAiProvider` could reach a
|
|
68
|
+
model on a paper of record.
|
|
69
|
+
|
|
70
|
+
`ActivityRenderer` is now `ComponentType<ActivityProps & { question?: SequenceQuestion }>`. A
|
|
71
|
+
renderer written as `ComponentType<ActivityProps>` still fits and simply ignores the new prop; only
|
|
72
|
+
assigning an `ActivityRenderer` _back_ to a `ComponentType<ActivityProps>` variable needs a widened
|
|
73
|
+
annotation.
|
|
74
|
+
|
|
75
|
+
See `docs/ai.md` and the `renderers` documentation on `<ActivitySequence>`.
|
|
76
|
+
|
|
3
77
|
## 18.0.0
|
|
4
78
|
|
|
5
79
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ export function Demo() {
|
|
|
73
73
|
- **`<PronunciationFeedback>`** — the marks on their own, for a review screen that has evidence but no activity: the graded dimensions (accuracy, fluency, completeness, prosody — one the engine did not measure reads "not assessed", **never 0%**), and every word marked `correct` / `mispronounced` / `omitted` / `inserted` with a hidden sentence per word for screen readers and a glyph plus a text decoration for everyone else. A word opens onto its syllables, its sounds, what was heard instead, and a button that plays just that word. Evidence it cannot trust is checked before it is aligned, so in production a malformed assessment costs the word list — never the grade beside it.
|
|
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
|
-
- **AI help for learners** — "Explain my answer" after grading and "Get a hint" before submit, in `<MultipleChoice>`, `<FillInTheBlanks>`, `<GapSelect>` and `<Dictation>` (explanations only), 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`. See the [AI guide](https://github.com/intellectif/learning-kit/blob/main/docs/ai.md).
|
|
76
|
+
- **AI help for learners** — "Explain my answer" after grading and "Get a hint" before submit, in `<MultipleChoice>`, `<FillInTheBlanks>`, `<GapSelect>` and `<Dictation>` (explanations only), 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).
|
|
77
77
|
- **`<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).
|
|
78
78
|
- **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`.
|
|
79
79
|
- **`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.
|
|
@@ -82,7 +82,8 @@ export function Demo() {
|
|
|
82
82
|
- **`shuffleSeed`** — one seed drives question order *and* each item's option order, so a review render reproduces exactly the arrangement the learner sat. Shuffling in `exam` / `review` mode **requires** it.
|
|
83
83
|
- **`<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.
|
|
84
84
|
- **`<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.
|
|
85
|
-
- **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.
|
|
85
|
+
- **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.
|
|
86
|
+
- **AI help in a question you draw** — `useAiHints` and `useAiExplanation` 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.
|
|
86
87
|
- **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.)
|
|
87
88
|
- **Media per question** — optional `image` / `audio` / `video` / `embed` (YouTube/Vimeo iframe) above the question; alt-text required for `image`/`embed` (WCAG).
|
|
88
89
|
- **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.
|
|
@@ -116,6 +117,7 @@ export function Demo() {
|
|
|
116
117
|
| `@intellectif/lk-react/hooks/useSpeechRecorder` | Microphone capture to 16 kHz mono WAV, and `CAPTURE_PROCESSOR_SOURCE` for a self-hosted worklet |
|
|
117
118
|
| `@intellectif/lk-react/hooks/useXAPI` | LRS delivery (retry, never-throws) |
|
|
118
119
|
| `@intellectif/lk-react/ai/LkAiProvider` | `<LkAiProvider>`, `useLearnerAi`, and the `LearnerAi` type |
|
|
120
|
+
| `@intellectif/lk-react/ai/useAiHelp` | `useAiHints`, `useAiExplanation` — the AI rules without the SDK's own buttons |
|
|
119
121
|
| `@intellectif/lk-react/i18n/LkIntlProvider` | `<LkIntlProvider>`, `useLkStrings`, `useLkDirection`, `DEFAULT_STRINGS`, `mergeStrings`, `directionForLocale` |
|
|
120
122
|
| `@intellectif/lk-react/theme/ThemeProvider` | `<ThemeProvider>`, `darkTheme`, `useTheme`, `createTailwindTheme` |
|
|
121
123
|
| `@intellectif/lk-react/theme/defaults.css` | Tokens (required) |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { XAPIStatement, WrittenResponseData, LearnerResponse, ItemOutcome, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
|
|
2
|
-
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './
|
|
2
|
+
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-BY-4S5Rd.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Payload delivered when the learner submits a written response. Grading is
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { XAPIStatement, WrittenResponseData, LearnerResponse, ItemOutcome, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
|
|
2
|
-
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './
|
|
2
|
+
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-DtPYG1hh.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Payload delivered when the learner submits a written response. Grading is
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunkSXU26SFO_cjs = require('../chunk-SXU26SFO.cjs');
|
|
5
|
+
require('../chunk-ZDYNAWDZ.cjs');
|
|
6
|
+
require('../chunk-JVWLXVYG.cjs');
|
|
7
|
+
require('../chunk-EANGKAKG.cjs');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
Object.defineProperty(exports, "useAiExplanation", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkSXU26SFO_cjs.useAiExplanation; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "useAiHints", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return chunkSXU26SFO_cjs.useAiHints; }
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=useAiHelp.cjs.map
|
|
20
|
+
//# sourceMappingURL=useAiHelp.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"useAiHelp.cjs"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { AiTextResult, LearnerResponse, InteractionEvent, ItemOutcome } from '@intellectif/lk-core';
|
|
2
|
+
import { g as RenderableActivity, e as RenderMode } from '../types-DtPYG1hh.cjs';
|
|
3
|
+
import { LearnerAi } from './LkAiProvider.cjs';
|
|
4
|
+
import '../machine-CuwKqWXC.cjs';
|
|
5
|
+
import 'react';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The question AI help is being asked about, as the SDK's own components know
|
|
9
|
+
* it. A host drawing its own question passes what it has; everything optional
|
|
10
|
+
* defaults to what the components pass.
|
|
11
|
+
*/
|
|
12
|
+
interface AiHelpSituation {
|
|
13
|
+
/** The question, as `data` is given to any activity component. */
|
|
14
|
+
data: RenderableActivity;
|
|
15
|
+
/** The learner's answer as it stands: submitted, restored, or being written. */
|
|
16
|
+
response: LearnerResponse;
|
|
17
|
+
/** Whether the learner has committed that answer. */
|
|
18
|
+
submitted: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Pass on the `renderMode` your question was given. Left out, the paper
|
|
21
|
+
* around the question answers for it — a question inside `<ActivitySequence>`
|
|
22
|
+
* or `<InteractiveVideo>` knows its mode — and `practice` only where there is
|
|
23
|
+
* no paper at all. An `exam` around the question wins over anything passed
|
|
24
|
+
* here.
|
|
25
|
+
*/
|
|
26
|
+
renderMode?: RenderMode;
|
|
27
|
+
/**
|
|
28
|
+
* The AI ports to use, overriding {@link LkAiProvider}'s for this question.
|
|
29
|
+
* A question inside `<ActivitySequence>` or `<InteractiveVideo>` is handed
|
|
30
|
+
* the ports in force as `ai` — pass that straight in.
|
|
31
|
+
*/
|
|
32
|
+
ai?: LearnerAi;
|
|
33
|
+
/** The interface language: the default language for what a model writes. */
|
|
34
|
+
locale?: string;
|
|
35
|
+
/** Where `ai-hint-shown` and `ai-explanation-shown` go. */
|
|
36
|
+
onInteraction?: (event: InteractionEvent) => void;
|
|
37
|
+
}
|
|
38
|
+
interface AiExplanationInput extends AiHelpSituation {
|
|
39
|
+
/** The grade of record, which `review` explains. */
|
|
40
|
+
outcome?: ItemOutcome;
|
|
41
|
+
}
|
|
42
|
+
interface AiExplanationHelp {
|
|
43
|
+
/**
|
|
44
|
+
* Whether to offer the learner an explanation at all: a port is present, the
|
|
45
|
+
* answer is graded, the type is one the SDK explains, and the author left
|
|
46
|
+
* explanations on. False in `exam`, always.
|
|
47
|
+
*/
|
|
48
|
+
offered: boolean;
|
|
49
|
+
status: 'idle' | 'loading' | 'shown' | 'unavailable';
|
|
50
|
+
/** What to show, once it has arrived and been checked. Its `text` is text, never HTML. */
|
|
51
|
+
explanation: AiTextResult | null;
|
|
52
|
+
/**
|
|
53
|
+
* Asks the port, when the learner presses something. Does nothing while a
|
|
54
|
+
* call is on its way, and nothing at all where `offered` is false — so an
|
|
55
|
+
* exam cannot reach a model through this hook, whatever ports are in scope.
|
|
56
|
+
*
|
|
57
|
+
* One identity for the life of the question, so it is safe in an effect's
|
|
58
|
+
* dependencies.
|
|
59
|
+
*/
|
|
60
|
+
ask: () => void;
|
|
61
|
+
}
|
|
62
|
+
interface AiHintsInput extends AiHelpSituation {
|
|
63
|
+
/** A disabled question gives no hints, as it takes no answer. */
|
|
64
|
+
disabled?: boolean;
|
|
65
|
+
}
|
|
66
|
+
interface AiHintsHelp {
|
|
67
|
+
/**
|
|
68
|
+
* Whether the learner may ask for hints here at all: a port is present, the
|
|
69
|
+
* mode is `practice`, the answer is not in, the question is not disabled or
|
|
70
|
+
* redacted, the type takes hints and the author left them on. It stays true
|
|
71
|
+
* once `used` reaches `limit` — there are no more to give, but the question
|
|
72
|
+
* is still one that gives them.
|
|
73
|
+
*/
|
|
74
|
+
offered: boolean;
|
|
75
|
+
status: 'idle' | 'loading' | 'unavailable';
|
|
76
|
+
/** Every hint shown for this question, in the order they were given. */
|
|
77
|
+
hints: readonly AiTextResult[];
|
|
78
|
+
/** The host's `maxHints`, as a whole number from 1 to 10 (3 by default). */
|
|
79
|
+
limit: number;
|
|
80
|
+
/** How many hints have been shown. A refused hint is not counted. */
|
|
81
|
+
used: number;
|
|
82
|
+
/**
|
|
83
|
+
* Asks for the next hint. Does nothing at the limit, while a call is on its
|
|
84
|
+
* way, or where `offered` is false. One identity for the life of the
|
|
85
|
+
* question.
|
|
86
|
+
*/
|
|
87
|
+
ask: () => void;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* "Explain my answer", without the SDK's own button and panel: the rules, the
|
|
91
|
+
* call, the checks and the record, for a question you draw yourself.
|
|
92
|
+
*
|
|
93
|
+
* It is what `<MultipleChoice>` and the others use, so a host's own question
|
|
94
|
+
* offers help on exactly the same terms: never in `exam`, never where the
|
|
95
|
+
* item's author switched explanations off, and never an explanation whose
|
|
96
|
+
* verdict contradicts the grade the SDK computed.
|
|
97
|
+
*
|
|
98
|
+
* ```tsx
|
|
99
|
+
* const { offered, status, explanation, ask } = useAiExplanation({
|
|
100
|
+
* data, response, submitted, renderMode, outcome, ai: question.ai,
|
|
101
|
+
* });
|
|
102
|
+
* if (!offered) return null;
|
|
103
|
+
* return explanation === null ? (
|
|
104
|
+
* <button type="button" onClick={ask} aria-busy={status === 'loading'}>Explain my answer</button>
|
|
105
|
+
* ) : (
|
|
106
|
+
* <section>
|
|
107
|
+
* <p>{explanation.text}</p>
|
|
108
|
+
* <p>Written by AI. It can make mistakes.</p>
|
|
109
|
+
* </section>
|
|
110
|
+
* );
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* **Say who wrote it.** The SDK's own panel carries "Written by AI. It can make
|
|
114
|
+
* mistakes."; a page that drops that line passes a model's words off as the
|
|
115
|
+
* course's.
|
|
116
|
+
*
|
|
117
|
+
* When the answer or its grade changes, the explanation is dropped and a call
|
|
118
|
+
* still on its way is abandoned — a late explanation never lands beside an
|
|
119
|
+
* answer it was not written for — as it is when the caller unmounts.
|
|
120
|
+
*/
|
|
121
|
+
declare function useAiExplanation(input: AiExplanationInput): AiExplanationHelp;
|
|
122
|
+
/**
|
|
123
|
+
* "Get a hint", without the SDK's own button and list: the rules, the call, the
|
|
124
|
+
* checks and the record, for a question you draw yourself.
|
|
125
|
+
*
|
|
126
|
+
* It is what `<MultipleChoice>` and the others use, so a host's own question
|
|
127
|
+
* gives hints on exactly the same terms: only in `practice` before submit, up
|
|
128
|
+
* to the host's limit, never on a redacted item or a type the SDK does not hint
|
|
129
|
+
* for, and never a hint that gives the answer away — which is refused rather
|
|
130
|
+
* than shown, and not counted.
|
|
131
|
+
*
|
|
132
|
+
* ```tsx
|
|
133
|
+
* const { offered, status, hints, used, limit, ask } = useAiHints({
|
|
134
|
+
* data, response, submitted, renderMode, ai: question.ai,
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* **Say who wrote them**, as the SDK's own list does: "Written by AI. It can
|
|
139
|
+
* make mistakes."
|
|
140
|
+
*
|
|
141
|
+
* Keep the hints on screen after submit — the learner can see what they were
|
|
142
|
+
* given — while `offered` turns false. Another question starts with none.
|
|
143
|
+
*/
|
|
144
|
+
declare function useAiHints(input: AiHintsInput): AiHintsHelp;
|
|
145
|
+
|
|
146
|
+
export { type AiExplanationHelp, type AiExplanationInput, type AiHelpSituation, type AiHintsHelp, type AiHintsInput, useAiExplanation, useAiHints };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { AiTextResult, LearnerResponse, InteractionEvent, ItemOutcome } from '@intellectif/lk-core';
|
|
2
|
+
import { g as RenderableActivity, e as RenderMode } from '../types-BY-4S5Rd.js';
|
|
3
|
+
import { LearnerAi } from './LkAiProvider.js';
|
|
4
|
+
import '../machine-CuwKqWXC.js';
|
|
5
|
+
import 'react';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The question AI help is being asked about, as the SDK's own components know
|
|
9
|
+
* it. A host drawing its own question passes what it has; everything optional
|
|
10
|
+
* defaults to what the components pass.
|
|
11
|
+
*/
|
|
12
|
+
interface AiHelpSituation {
|
|
13
|
+
/** The question, as `data` is given to any activity component. */
|
|
14
|
+
data: RenderableActivity;
|
|
15
|
+
/** The learner's answer as it stands: submitted, restored, or being written. */
|
|
16
|
+
response: LearnerResponse;
|
|
17
|
+
/** Whether the learner has committed that answer. */
|
|
18
|
+
submitted: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Pass on the `renderMode` your question was given. Left out, the paper
|
|
21
|
+
* around the question answers for it — a question inside `<ActivitySequence>`
|
|
22
|
+
* or `<InteractiveVideo>` knows its mode — and `practice` only where there is
|
|
23
|
+
* no paper at all. An `exam` around the question wins over anything passed
|
|
24
|
+
* here.
|
|
25
|
+
*/
|
|
26
|
+
renderMode?: RenderMode;
|
|
27
|
+
/**
|
|
28
|
+
* The AI ports to use, overriding {@link LkAiProvider}'s for this question.
|
|
29
|
+
* A question inside `<ActivitySequence>` or `<InteractiveVideo>` is handed
|
|
30
|
+
* the ports in force as `ai` — pass that straight in.
|
|
31
|
+
*/
|
|
32
|
+
ai?: LearnerAi;
|
|
33
|
+
/** The interface language: the default language for what a model writes. */
|
|
34
|
+
locale?: string;
|
|
35
|
+
/** Where `ai-hint-shown` and `ai-explanation-shown` go. */
|
|
36
|
+
onInteraction?: (event: InteractionEvent) => void;
|
|
37
|
+
}
|
|
38
|
+
interface AiExplanationInput extends AiHelpSituation {
|
|
39
|
+
/** The grade of record, which `review` explains. */
|
|
40
|
+
outcome?: ItemOutcome;
|
|
41
|
+
}
|
|
42
|
+
interface AiExplanationHelp {
|
|
43
|
+
/**
|
|
44
|
+
* Whether to offer the learner an explanation at all: a port is present, the
|
|
45
|
+
* answer is graded, the type is one the SDK explains, and the author left
|
|
46
|
+
* explanations on. False in `exam`, always.
|
|
47
|
+
*/
|
|
48
|
+
offered: boolean;
|
|
49
|
+
status: 'idle' | 'loading' | 'shown' | 'unavailable';
|
|
50
|
+
/** What to show, once it has arrived and been checked. Its `text` is text, never HTML. */
|
|
51
|
+
explanation: AiTextResult | null;
|
|
52
|
+
/**
|
|
53
|
+
* Asks the port, when the learner presses something. Does nothing while a
|
|
54
|
+
* call is on its way, and nothing at all where `offered` is false — so an
|
|
55
|
+
* exam cannot reach a model through this hook, whatever ports are in scope.
|
|
56
|
+
*
|
|
57
|
+
* One identity for the life of the question, so it is safe in an effect's
|
|
58
|
+
* dependencies.
|
|
59
|
+
*/
|
|
60
|
+
ask: () => void;
|
|
61
|
+
}
|
|
62
|
+
interface AiHintsInput extends AiHelpSituation {
|
|
63
|
+
/** A disabled question gives no hints, as it takes no answer. */
|
|
64
|
+
disabled?: boolean;
|
|
65
|
+
}
|
|
66
|
+
interface AiHintsHelp {
|
|
67
|
+
/**
|
|
68
|
+
* Whether the learner may ask for hints here at all: a port is present, the
|
|
69
|
+
* mode is `practice`, the answer is not in, the question is not disabled or
|
|
70
|
+
* redacted, the type takes hints and the author left them on. It stays true
|
|
71
|
+
* once `used` reaches `limit` — there are no more to give, but the question
|
|
72
|
+
* is still one that gives them.
|
|
73
|
+
*/
|
|
74
|
+
offered: boolean;
|
|
75
|
+
status: 'idle' | 'loading' | 'unavailable';
|
|
76
|
+
/** Every hint shown for this question, in the order they were given. */
|
|
77
|
+
hints: readonly AiTextResult[];
|
|
78
|
+
/** The host's `maxHints`, as a whole number from 1 to 10 (3 by default). */
|
|
79
|
+
limit: number;
|
|
80
|
+
/** How many hints have been shown. A refused hint is not counted. */
|
|
81
|
+
used: number;
|
|
82
|
+
/**
|
|
83
|
+
* Asks for the next hint. Does nothing at the limit, while a call is on its
|
|
84
|
+
* way, or where `offered` is false. One identity for the life of the
|
|
85
|
+
* question.
|
|
86
|
+
*/
|
|
87
|
+
ask: () => void;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* "Explain my answer", without the SDK's own button and panel: the rules, the
|
|
91
|
+
* call, the checks and the record, for a question you draw yourself.
|
|
92
|
+
*
|
|
93
|
+
* It is what `<MultipleChoice>` and the others use, so a host's own question
|
|
94
|
+
* offers help on exactly the same terms: never in `exam`, never where the
|
|
95
|
+
* item's author switched explanations off, and never an explanation whose
|
|
96
|
+
* verdict contradicts the grade the SDK computed.
|
|
97
|
+
*
|
|
98
|
+
* ```tsx
|
|
99
|
+
* const { offered, status, explanation, ask } = useAiExplanation({
|
|
100
|
+
* data, response, submitted, renderMode, outcome, ai: question.ai,
|
|
101
|
+
* });
|
|
102
|
+
* if (!offered) return null;
|
|
103
|
+
* return explanation === null ? (
|
|
104
|
+
* <button type="button" onClick={ask} aria-busy={status === 'loading'}>Explain my answer</button>
|
|
105
|
+
* ) : (
|
|
106
|
+
* <section>
|
|
107
|
+
* <p>{explanation.text}</p>
|
|
108
|
+
* <p>Written by AI. It can make mistakes.</p>
|
|
109
|
+
* </section>
|
|
110
|
+
* );
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* **Say who wrote it.** The SDK's own panel carries "Written by AI. It can make
|
|
114
|
+
* mistakes."; a page that drops that line passes a model's words off as the
|
|
115
|
+
* course's.
|
|
116
|
+
*
|
|
117
|
+
* When the answer or its grade changes, the explanation is dropped and a call
|
|
118
|
+
* still on its way is abandoned — a late explanation never lands beside an
|
|
119
|
+
* answer it was not written for — as it is when the caller unmounts.
|
|
120
|
+
*/
|
|
121
|
+
declare function useAiExplanation(input: AiExplanationInput): AiExplanationHelp;
|
|
122
|
+
/**
|
|
123
|
+
* "Get a hint", without the SDK's own button and list: the rules, the call, the
|
|
124
|
+
* checks and the record, for a question you draw yourself.
|
|
125
|
+
*
|
|
126
|
+
* It is what `<MultipleChoice>` and the others use, so a host's own question
|
|
127
|
+
* gives hints on exactly the same terms: only in `practice` before submit, up
|
|
128
|
+
* to the host's limit, never on a redacted item or a type the SDK does not hint
|
|
129
|
+
* for, and never a hint that gives the answer away — which is refused rather
|
|
130
|
+
* than shown, and not counted.
|
|
131
|
+
*
|
|
132
|
+
* ```tsx
|
|
133
|
+
* const { offered, status, hints, used, limit, ask } = useAiHints({
|
|
134
|
+
* data, response, submitted, renderMode, ai: question.ai,
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* **Say who wrote them**, as the SDK's own list does: "Written by AI. It can
|
|
139
|
+
* make mistakes."
|
|
140
|
+
*
|
|
141
|
+
* Keep the hints on screen after submit — the learner can see what they were
|
|
142
|
+
* given — while `offered` turns false. Another question starts with none.
|
|
143
|
+
*/
|
|
144
|
+
declare function useAiHints(input: AiHintsInput): AiHintsHelp;
|
|
145
|
+
|
|
146
|
+
export { type AiExplanationHelp, type AiExplanationInput, type AiHelpSituation, type AiHintsHelp, type AiHintsInput, useAiExplanation, useAiHints };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"useAiHelp.js"}
|