@pie-players/pie-assessment-toolkit 0.3.67 → 0.3.68
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/README.md +1 -1
- package/dist/attempt/AssessmentSession.d.ts +7 -27
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +13 -13
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-38mhtjsq.js +51 -0
- package/dist/components/chunks/ItemToolBar-9ymm7pd1.js +46 -0
- package/dist/components/item-toolbar-element.js +1 -0
- package/dist/components/pie-assessment-toolkit-element.js +1 -0
- package/dist/components/section-toolbar-element.js +1 -0
- package/dist/context/assessment-toolkit-context.d.ts +28 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.js +4 -2
- package/dist/runtime/SectionRuntimeEngine.d.ts +56 -0
- package/dist/runtime/SectionRuntimeEngine.js +66 -1
- package/dist/runtime/core/engine-resolver.d.ts +25 -1
- package/dist/runtime/registration-events.d.ts +52 -0
- package/dist/runtime/registration-events.js +2 -0
- package/dist/services/AccessibilityCatalogResolver.js +21 -5
- package/dist/services/I18nService.d.ts +28 -100
- package/dist/services/I18nService.js +43 -233
- package/dist/services/TTSService.d.ts +12 -0
- package/dist/services/TTSService.js +18 -17
- package/dist/services/ToolRegistry.d.ts +86 -2
- package/dist/services/ToolRegistry.js +30 -0
- package/dist/services/ToolkitCoordinator.d.ts +39 -37
- package/dist/services/ToolkitCoordinator.js +40 -0
- package/dist/services/audio-handoff.d.ts +39 -0
- package/dist/services/audio-handoff.js +58 -0
- package/dist/services/catalog-media.d.ts +35 -4
- package/dist/services/catalog-media.js +92 -3
- package/dist/services/framework-error.d.ts +15 -1
- package/dist/services/interfaces.d.ts +28 -0
- package/dist/services/pnp-standard-features.d.ts +1 -1
- package/dist/services/section-controller-types.d.ts +218 -7
- package/dist/services/selection-action.d.ts +49 -0
- package/dist/services/selection-action.js +10 -0
- package/dist/services/spoken-audio-cards.js +5 -1
- package/dist/services/tool-context.d.ts +6 -5
- package/dist/services/tool-context.js +197 -152
- package/dist/services/tool-icons.d.ts +18 -0
- package/dist/services/tool-icons.js +31 -0
- package/dist/services/tool-providers/DesmosToolProvider.d.ts +6 -5
- package/dist/services/tool-request.d.ts +106 -0
- package/dist/services/tool-request.js +127 -0
- package/dist/services/toolbar-items.d.ts +6 -0
- package/dist/tools/client.d.ts +0 -1
- package/dist/tools/client.js +0 -2
- package/dist/tools/internal.d.ts +6 -0
- package/dist/tools/internal.js +7 -0
- package/dist/tools/tool-surface-host.d.ts +57 -0
- package/dist/tools/tool-surface-host.js +610 -0
- package/package.json +10 -10
- package/dist/components/chunks/ItemToolBar-8jgdz50p.js +0 -51
- package/dist/components/chunks/ItemToolBar-cvs646j3.js +0 -36
- package/dist/tools/calculators/desmos-provider.d.ts +0 -46
- package/dist/tools/calculators/desmos-provider.js +0 -393
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import type { FormativeFeedbackReveal, FormativeMasteryRollup, FormativeSectionProjection, FormativeTryOutcome } from "@pie-players/pie-players-shared/formative";
|
|
2
|
+
import type { MediaTimeSource, TimedMediaDegradation, TimedMediaSectionProjection, TimedMediaValidationError } from "@pie-players/pie-players-shared/timed-media";
|
|
3
|
+
import type { SectionControllerSessionState } from "@pie-players/pie-players-shared/types";
|
|
4
|
+
/**
|
|
5
|
+
* Re-exported so every existing import site keeps its specifier. The shape is
|
|
6
|
+
* canonical in `@pie-players/pie-players-shared/types`, beside
|
|
7
|
+
* `AssessmentSection` and the delivery slices it carries.
|
|
8
|
+
*/
|
|
9
|
+
export type { SectionControllerSessionState };
|
|
1
10
|
export interface SectionControllerKey {
|
|
2
11
|
assessmentId: string;
|
|
3
12
|
sectionId: string;
|
|
@@ -62,11 +71,6 @@ export interface SectionControllerRuntimeState {
|
|
|
62
71
|
*/
|
|
63
72
|
loadedRenderables?: ReadonlyArray<SectionControllerLoadedRenderable>;
|
|
64
73
|
}
|
|
65
|
-
export interface SectionControllerSessionState {
|
|
66
|
-
currentItemIndex?: number;
|
|
67
|
-
visitedItemIdentifiers?: string[];
|
|
68
|
-
itemSessions: Record<string, unknown>;
|
|
69
|
-
}
|
|
70
74
|
type SectionControllerEventBase = {
|
|
71
75
|
timestamp: number;
|
|
72
76
|
};
|
|
@@ -156,7 +160,100 @@ export type SectionControllerSectionErrorEvent = SectionControllerEventBase & {
|
|
|
156
160
|
contentKind?: "item" | "passage" | "rubric" | "unknown";
|
|
157
161
|
currentItemIndex: number;
|
|
158
162
|
};
|
|
159
|
-
export type
|
|
163
|
+
export type SectionControllerFormativeTryRecordedEvent = SectionControllerEventBase & {
|
|
164
|
+
type: "formative-try-recorded";
|
|
165
|
+
itemId: string;
|
|
166
|
+
canonicalItemId: string;
|
|
167
|
+
tryCount: number;
|
|
168
|
+
outcome: FormativeTryOutcome;
|
|
169
|
+
/** Whether feedback is now on screen for this item. */
|
|
170
|
+
revealed: boolean;
|
|
171
|
+
currentItemIndex: number;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* The reveal state changed without a Try being recorded: a learner dismissed
|
|
175
|
+
* feedback to edit again, or a host forced a reveal or withdrew one.
|
|
176
|
+
*
|
|
177
|
+
* A Try that reveals reports through `formative-try-recorded`, which carries its
|
|
178
|
+
* own `revealed`. This event is for every other transition.
|
|
179
|
+
*/
|
|
180
|
+
export type SectionControllerFormativeRevealChangedEvent = SectionControllerEventBase & {
|
|
181
|
+
type: "formative-reveal-changed";
|
|
182
|
+
itemId: string;
|
|
183
|
+
canonicalItemId: string;
|
|
184
|
+
revealed: boolean;
|
|
185
|
+
/** Reveal level in force, when a host overrode the policy's. */
|
|
186
|
+
feedback?: FormativeFeedbackReveal;
|
|
187
|
+
/** Tries already spent; none of these transitions consume one. */
|
|
188
|
+
tryCount: number;
|
|
189
|
+
source: "learner" | "host";
|
|
190
|
+
currentItemIndex: number;
|
|
191
|
+
};
|
|
192
|
+
export type SectionControllerSectionMasteryChangedEvent = SectionControllerEventBase & {
|
|
193
|
+
type: "section-mastery-changed";
|
|
194
|
+
mastery: FormativeMasteryRollup;
|
|
195
|
+
currentItemIndex: number;
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Cue state changed: a cue activated, a gate released, or the section's
|
|
199
|
+
* aggregate completion flipped.
|
|
200
|
+
*
|
|
201
|
+
* Deliberately not emitted for media position. A `timeupdate` fires about four
|
|
202
|
+
* times a second and moves nothing a layout renders — the media element draws its
|
|
203
|
+
* own clock — so position is recorded in the session slice and reported here only
|
|
204
|
+
* through the cue transitions it caused.
|
|
205
|
+
*/
|
|
206
|
+
export type SectionControllerTimedMediaCueChangedEvent = SectionControllerEventBase & {
|
|
207
|
+
type: "timed-media-cue-changed";
|
|
208
|
+
/** The cue that activated in this transition, where one did. */
|
|
209
|
+
activatedCueIdentifier?: string;
|
|
210
|
+
/** The gate that released in this transition, where one did. */
|
|
211
|
+
releasedCueIdentifier?: string;
|
|
212
|
+
activeCueIdentifier?: string;
|
|
213
|
+
visitedCueIdentifiers: string[];
|
|
214
|
+
completedCueIdentifiers: string[];
|
|
215
|
+
/** Canonical ids of every item a visited cue has revealed. */
|
|
216
|
+
revealedItemIds: string[];
|
|
217
|
+
/** The gate holding playback, or `null`. */
|
|
218
|
+
gateCueIdentifier: string | null;
|
|
219
|
+
mediaCompleted: boolean;
|
|
220
|
+
aggregateComplete: boolean;
|
|
221
|
+
currentItemIndex: number;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Media audio is now running, so any other audio owner must yield.
|
|
225
|
+
*
|
|
226
|
+
* Emitted only where playback actually stood: a gate that re-paused on the same
|
|
227
|
+
* `play` produced no audio. Carries no payload — that media audio started is the
|
|
228
|
+
* whole fact, and cue state travels on `timed-media-cue-changed`.
|
|
229
|
+
*/
|
|
230
|
+
export type SectionControllerTimedMediaAudioStartedEvent = SectionControllerEventBase & {
|
|
231
|
+
type: "timed-media-audio-started";
|
|
232
|
+
currentItemIndex: number;
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* A playback policy the attached media time source cannot carry out, reported so
|
|
236
|
+
* the gap is visible rather than silent. Cues still fire and state is still
|
|
237
|
+
* recorded; only enforcement is lost.
|
|
238
|
+
*/
|
|
239
|
+
export type SectionControllerTimedMediaPolicyDegradedEvent = SectionControllerEventBase & {
|
|
240
|
+
type: "timed-media-policy-degraded";
|
|
241
|
+
degradations: TimedMediaDegradation[];
|
|
242
|
+
currentItemIndex: number;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* Authored `timedMedia` this section cannot deliver — an unresolvable
|
|
246
|
+
* `stimulusRef`, a cue naming an item the section does not hold, a gate on
|
|
247
|
+
* correctness with no `onUnknownCorrectness`. The section still renders, as an
|
|
248
|
+
* ordinary section with every item visible, because cues that silently never fire
|
|
249
|
+
* is the failure mode this contract exists to avoid.
|
|
250
|
+
*/
|
|
251
|
+
export type SectionControllerTimedMediaInvalidEvent = SectionControllerEventBase & {
|
|
252
|
+
type: "timed-media-invalid";
|
|
253
|
+
errors: TimedMediaValidationError[];
|
|
254
|
+
currentItemIndex: number;
|
|
255
|
+
};
|
|
256
|
+
export type SectionControllerEvent = SectionControllerItemSessionDataChangedEvent | SectionControllerItemSessionMetaChangedEvent | SectionControllerItemSelectedEvent | SectionControllerSectionNavigationChangedEvent | SectionControllerSectionSessionAppliedEvent | SectionControllerContentLoadedEvent | SectionControllerItemPlayerErrorEvent | SectionControllerItemCompleteChangedEvent | SectionControllerSectionLoadingCompleteEvent | SectionControllerSectionItemsCompleteChangedEvent | SectionControllerSectionErrorEvent | SectionControllerFormativeTryRecordedEvent | SectionControllerFormativeRevealChangedEvent | SectionControllerSectionMasteryChangedEvent | SectionControllerTimedMediaCueChangedEvent | SectionControllerTimedMediaAudioStartedEvent | SectionControllerTimedMediaPolicyDegradedEvent | SectionControllerTimedMediaInvalidEvent;
|
|
160
257
|
export type SectionControllerEventType = SectionControllerEvent["type"];
|
|
161
258
|
/**
|
|
162
259
|
* Host-facing controller for a single section cohort.
|
|
@@ -295,6 +392,121 @@ export interface SectionControllerHandle {
|
|
|
295
392
|
* is what the strategy load/save methods exchange.
|
|
296
393
|
*/
|
|
297
394
|
configureSessionPersistence?(config: SectionSessionPersistenceConfig): void | Promise<void>;
|
|
395
|
+
/**
|
|
396
|
+
* Record one Try for an item: derive correctness from the element outcomes,
|
|
397
|
+
* increment the Try count, and reveal feedback if the item's resolved
|
|
398
|
+
* formative policy says so.
|
|
399
|
+
*
|
|
400
|
+
* `outcomes` is what `pie-item-player.provideScore()` returned. The caller
|
|
401
|
+
* does not interpret it — correctness derivation belongs to the controller so
|
|
402
|
+
* one aggregation policy applies everywhere.
|
|
403
|
+
*
|
|
404
|
+
* No-op when the item's policy is disabled, when feedback is already
|
|
405
|
+
* revealed, or when Tries are spent, which makes a double submit safe.
|
|
406
|
+
*/
|
|
407
|
+
recordFormativeTry?(args: {
|
|
408
|
+
itemId: string;
|
|
409
|
+
outcomes?: unknown[];
|
|
410
|
+
}): void;
|
|
411
|
+
/**
|
|
412
|
+
* Dismiss a revealed item's feedback and reopen it for editing. Withdrawing
|
|
413
|
+
* the reveal is what withdraws the `mode: "evaluate"` projection.
|
|
414
|
+
*
|
|
415
|
+
* The learner action, so it respects the Try budget: no-op when nothing is
|
|
416
|
+
* revealed or Tries are spent. Use `hideFormativeItem` for host authority.
|
|
417
|
+
*/
|
|
418
|
+
retryFormativeItem?(args: {
|
|
419
|
+
itemId: string;
|
|
420
|
+
}): void;
|
|
421
|
+
/**
|
|
422
|
+
* Reveal an item on host authority — a teacher-driven "show the answer".
|
|
423
|
+
*
|
|
424
|
+
* Spends no Try and ignores the Try budget and `revealOn`, none of which bound
|
|
425
|
+
* a decision the host has already taken. Works on an item with no Try yet.
|
|
426
|
+
*
|
|
427
|
+
* `feedback` is stated rather than taken from the policy, because a reveal
|
|
428
|
+
* under `feedback: "none"` would project nothing.
|
|
429
|
+
*/
|
|
430
|
+
revealFormativeItem?(args: {
|
|
431
|
+
itemId: string;
|
|
432
|
+
feedback: "correctness" | "solution";
|
|
433
|
+
}): void;
|
|
434
|
+
/**
|
|
435
|
+
* Withdraw a reveal on host authority. Unlike `retryFormativeItem` this
|
|
436
|
+
* ignores the Try budget, so a host that revealed a spent item can put it
|
|
437
|
+
* back.
|
|
438
|
+
*/
|
|
439
|
+
hideFormativeItem?(args: {
|
|
440
|
+
itemId: string;
|
|
441
|
+
}): void;
|
|
442
|
+
/**
|
|
443
|
+
* The section's formative projection — resolved policies, per-item state, and
|
|
444
|
+
* the mastery rollup.
|
|
445
|
+
*
|
|
446
|
+
* `null` when no item in the section delivers formatively. The same
|
|
447
|
+
* projection rides on the composition model, so layouts normally read it from
|
|
448
|
+
* there rather than calling this.
|
|
449
|
+
*/
|
|
450
|
+
getFormativeProjection?(): FormativeSectionProjection | null;
|
|
451
|
+
/**
|
|
452
|
+
* Bind the section's Media Time Source — the only way it reaches media.
|
|
453
|
+
*
|
|
454
|
+
* Called by the stimulus card once it has a media element to adapt, and
|
|
455
|
+
* callable directly by a host that supplies its own port: a third-party embed,
|
|
456
|
+
* a remote-controlled player, anything that can report time. That is the point
|
|
457
|
+
* of the port. Attaching replaces any previous source.
|
|
458
|
+
*
|
|
459
|
+
* The port declares `canPause` / `canRestrictSeeking`; where a capability is
|
|
460
|
+
* missing the matching policy degrades to advisory and the controller emits
|
|
461
|
+
* `timed-media-policy-degraded` rather than appearing to enforce.
|
|
462
|
+
*
|
|
463
|
+
* No-op on a section that carries no valid `timedMedia`.
|
|
464
|
+
*/
|
|
465
|
+
attachMediaTimeSource?(source: MediaTimeSource, options?: {
|
|
466
|
+
/**
|
|
467
|
+
* `"native-adapter"` marks the stimulus card's own discovery, which never
|
|
468
|
+
* displaces a source a host attached explicitly.
|
|
469
|
+
*/
|
|
470
|
+
origin?: "native-adapter" | "host";
|
|
471
|
+
/**
|
|
472
|
+
* The renderable the source was found in. Checked against the renderable
|
|
473
|
+
* `stimulusRef` resolved to, so a second video passage's adapter cannot
|
|
474
|
+
* drive the timeline. Omitted by a host attaching its own port, which names
|
|
475
|
+
* no renderable and is taken at its word.
|
|
476
|
+
*/
|
|
477
|
+
renderableId?: string;
|
|
478
|
+
}): void;
|
|
479
|
+
/**
|
|
480
|
+
* Release the current source. Cue state is kept; nothing advances it.
|
|
481
|
+
*
|
|
482
|
+
* A `"native-adapter"` detach is ignored while a host-attached source is live:
|
|
483
|
+
* the stimulus card tears its adapter down whenever its content re-renders, and
|
|
484
|
+
* that must not take a host's own player with it.
|
|
485
|
+
*/
|
|
486
|
+
detachMediaTimeSource?(options?: {
|
|
487
|
+
origin?: "native-adapter" | "host";
|
|
488
|
+
}): void;
|
|
489
|
+
/**
|
|
490
|
+
* Silence media audio so read-aloud can speak over the same stimulus.
|
|
491
|
+
*
|
|
492
|
+
* One half of the TTS/media handoff. The section stops media and announces
|
|
493
|
+
* `timed-media-audio-started` when media audio resumes; the toolkit owns the
|
|
494
|
+
* policy, because only the toolkit holds both the TTS service and the section.
|
|
495
|
+
*
|
|
496
|
+
* Returns whether media audio is now silent — `false` for a playing source that
|
|
497
|
+
* reports no `canPause`, where the overlap stands rather than read-aloud being
|
|
498
|
+
* withheld.
|
|
499
|
+
*/
|
|
500
|
+
pauseMediaForCompetingAudio?(): boolean;
|
|
501
|
+
/**
|
|
502
|
+
* The section's timed-media projection — cues, enforcement, revealed items and
|
|
503
|
+
* the gate currently holding playback.
|
|
504
|
+
*
|
|
505
|
+
* `null` when the section is not timed media or its `timedMedia` failed
|
|
506
|
+
* validation. The same projection rides on the composition model, so layouts
|
|
507
|
+
* read it from there rather than calling this.
|
|
508
|
+
*/
|
|
509
|
+
getTimedMediaProjection?(): TimedMediaSectionProjection | null;
|
|
298
510
|
}
|
|
299
511
|
export interface SectionControllerFactoryDefaults {
|
|
300
512
|
createDefaultController: () => SectionControllerHandle | Promise<SectionControllerHandle>;
|
|
@@ -302,4 +514,3 @@ export interface SectionControllerFactoryDefaults {
|
|
|
302
514
|
export interface SectionPersistenceFactoryDefaults {
|
|
303
515
|
createDefaultPersistence: () => SectionSessionPersistenceStrategy | Promise<SectionSessionPersistenceStrategy>;
|
|
304
516
|
}
|
|
305
|
-
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-supplied actions on a text selection.
|
|
3
|
+
*
|
|
4
|
+
* The contract between a selection gateway and whoever composes it. The gateway
|
|
5
|
+
* renders the actions it is handed and knows nothing about what they do; the
|
|
6
|
+
* composer knows which capabilities exist and pairs them up. That split is what
|
|
7
|
+
* keeps a gateway from naming a dictionary, and what lets a host contribute an
|
|
8
|
+
* action for a capability PIE does not ship.
|
|
9
|
+
*/
|
|
10
|
+
/** What the gateway hands an action when the learner activates it. */
|
|
11
|
+
export interface ToolSelectionContext {
|
|
12
|
+
/** The selected text, trimmed and whitespace-collapsed by the gateway. */
|
|
13
|
+
text: string;
|
|
14
|
+
/**
|
|
15
|
+
* The live range, or `null` when the gateway has already lost it.
|
|
16
|
+
*
|
|
17
|
+
* An action that only needs the words should use `text`; the range is for an
|
|
18
|
+
* action that has to know where in the content the words were.
|
|
19
|
+
*/
|
|
20
|
+
range: Range | null;
|
|
21
|
+
}
|
|
22
|
+
export interface ToolSelectionAction {
|
|
23
|
+
/** Stable id, used as the button's key and its `data-pie-selection-action`. */
|
|
24
|
+
id: string;
|
|
25
|
+
/** Visible and accessible name. */
|
|
26
|
+
label: string;
|
|
27
|
+
/**
|
|
28
|
+
* Inline SVG markup for the button face.
|
|
29
|
+
*
|
|
30
|
+
* Markup rather than an icon name because a gateway has no icon registry, and
|
|
31
|
+
* the composer already resolves names through the toolkit's own map. Rendered
|
|
32
|
+
* into the gateway's shadow root and treated as trusted composer-authored
|
|
33
|
+
* markup, on the same footing as the shell's own action icons — never a place
|
|
34
|
+
* to put anything that reached the composer from content or a service.
|
|
35
|
+
*/
|
|
36
|
+
iconSvg?: string;
|
|
37
|
+
/** Longer tooltip, when the label alone reads as terse in a strip of icons. */
|
|
38
|
+
tooltip?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Whether to offer the action at all, asked on each render.
|
|
41
|
+
*
|
|
42
|
+
* An action whose target capability is not available answers `false` rather
|
|
43
|
+
* than being offered and failing: an affordance that does nothing costs a
|
|
44
|
+
* learner a keystroke and their confidence in the rest of the strip.
|
|
45
|
+
*/
|
|
46
|
+
isAvailable?: () => boolean;
|
|
47
|
+
/** Perform the action. */
|
|
48
|
+
run: (selection: ToolSelectionContext) => void;
|
|
49
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-supplied actions on a text selection.
|
|
3
|
+
*
|
|
4
|
+
* The contract between a selection gateway and whoever composes it. The gateway
|
|
5
|
+
* renders the actions it is handed and knows nothing about what they do; the
|
|
6
|
+
* composer knows which capabilities exist and pairs them up. That split is what
|
|
7
|
+
* keeps a gateway from naming a dictionary, and what lets a host contribute an
|
|
8
|
+
* action for a capability PIE does not ship.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
* Part of PIE Assessment Toolkit.
|
|
22
22
|
*/
|
|
23
|
-
import { normalizeMediaFragment, normalizeMediaSources, trimmedOrUndefined, } from "./catalog-media.js";
|
|
23
|
+
import { isUnsupportedMediaAssetVersion, normalizeMediaFragment, normalizeMediaSources, trimmedOrUndefined, } from "./catalog-media.js";
|
|
24
24
|
/** Catalog type token for spoken alternates. Matches QTI 3's `support` value. */
|
|
25
25
|
export const SPOKEN_CATALOG_TYPE = "spoken";
|
|
26
26
|
/**
|
|
@@ -46,6 +46,10 @@ export function resolveSpokenAudioMedia(card) {
|
|
|
46
46
|
console.warn("[spoken-audio] card carries a `payload` with no `media`; recorded speech needs `media.sources`, so this card is ignored and read-aloud falls back to the script or generated speech");
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
|
+
if (isUnsupportedMediaAssetVersion(media.version)) {
|
|
50
|
+
console.warn(`[spoken-audio] card's media declares version ${String(media.version)}, which this build does not render; the card is ignored and read-aloud falls back to the script or generated speech`);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
49
53
|
// A signing video filed under `spoken` is a mis-authored card, not an audio
|
|
50
54
|
// track to guess at. Refusing it keeps the two card types from quietly
|
|
51
55
|
// swapping roles.
|
|
@@ -125,14 +125,15 @@ export declare function isRubricContext(context: ToolContext): context is Rubric
|
|
|
125
125
|
* Type guard to check if context is at element level
|
|
126
126
|
*/
|
|
127
127
|
export declare function isElementContext(context: ToolContext): context is ElementToolContext;
|
|
128
|
-
/**
|
|
129
|
-
* Helper to extract text content from an item or element for analysis
|
|
130
|
-
*/
|
|
128
|
+
/** The plain text a context carries, tags removed. */
|
|
131
129
|
export declare function extractTextContent(context: ToolContext): string;
|
|
132
130
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
131
|
+
* The authored markup a context carries, tags intact.
|
|
132
|
+
*
|
|
133
|
+
* For indicators that live in the markup rather than in the prose — `<math>`
|
|
134
|
+
* above all, whose whole signal is the element name.
|
|
135
135
|
*/
|
|
136
|
+
export declare function extractMarkupContent(context: ToolContext): string;
|
|
136
137
|
export declare function hasMathContent(context: ToolContext): boolean;
|
|
137
138
|
/**
|
|
138
139
|
* Helper to check if context contains choice-based interactions
|