@pie-players/pie-assessment-toolkit 0.3.74 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. package/README.md +658 -714
  2. package/custom-elements.json +1315 -0
  3. package/dist/attempt/TestSession.d.ts +1 -21
  4. package/dist/attempt/TestSession.js +16 -102
  5. package/dist/components/ItemScope.custom-element.d.ts +1 -0
  6. package/dist/components/ItemScope.custom-element.js +1 -0
  7. package/dist/components/ItemToolBar.custom-element.js +1 -1
  8. package/dist/components/PieAssessmentToolkit.custom-element.js +14 -14
  9. package/dist/components/SectionToolBar.custom-element.js +1 -1
  10. package/dist/components/chunks/ItemToolBar-3zrc4p3d.js +4 -0
  11. package/dist/components/chunks/ItemToolBar-66hcwmfw.js +2 -0
  12. package/dist/components/chunks/ItemToolBar-9gqhfxtn.js +40 -0
  13. package/dist/components/chunks/ItemToolBar-hzc5wyjp.js +2 -0
  14. package/dist/components/chunks/{ItemToolBar-gmrryv2v.js → ItemToolBar-kkj69ptr.js} +1 -1
  15. package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
  16. package/dist/components/chunks/sre-engine-bj997w4b.js +1 -0
  17. package/dist/components/item-scope-element.d.ts +2 -0
  18. package/dist/components/item-scope-element.js +2 -0
  19. package/dist/context/assessment-toolkit-context.d.ts +33 -6
  20. package/dist/index.d.ts +25 -50
  21. package/dist/index.js +15 -45
  22. package/dist/policy/core/PolicySource.d.ts +2 -2
  23. package/dist/policy/core/ToolPolicyEngine.d.ts +118 -34
  24. package/dist/policy/core/ToolPolicyEngine.js +203 -56
  25. package/dist/policy/core/compose-decision.d.ts +28 -7
  26. package/dist/policy/core/compose-decision.js +95 -74
  27. package/dist/policy/core/decision-types.d.ts +98 -55
  28. package/dist/policy/core/feature-decision.d.ts +28 -19
  29. package/dist/policy/core/feature-decision.js +15 -11
  30. package/dist/policy/core/pnp-policy-inputs.d.ts +29 -35
  31. package/dist/policy/core/pnp-policy-inputs.js +40 -88
  32. package/dist/policy/core/provenance.d.ts +10 -5
  33. package/dist/policy/core/provenance.js +1 -1
  34. package/dist/policy/core/tool-parameters.d.ts +11 -0
  35. package/dist/policy/core/tool-parameters.js +15 -0
  36. package/dist/policy/engine.d.ts +7 -23
  37. package/dist/policy/engine.js +5 -20
  38. package/dist/policy/sources/PnpPolicySource.d.ts +43 -68
  39. package/dist/policy/sources/PnpPolicySource.js +133 -132
  40. package/dist/runtime/SectionControllerBinding.d.ts +283 -0
  41. package/dist/runtime/SectionControllerBinding.js +456 -0
  42. package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
  43. package/dist/runtime/SectionRuntimeEngine.js +30 -372
  44. package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
  45. package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
  46. package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
  47. package/dist/runtime/adapter/dom-event-bridge.js +17 -44
  48. package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -3
  49. package/dist/runtime/adapter/subscriber-fanout.js +2 -6
  50. package/dist/runtime/catalog-context.d.ts +19 -0
  51. package/dist/runtime/catalog-context.js +28 -0
  52. package/dist/runtime/composition-emit-scheduler.d.ts +12 -18
  53. package/dist/runtime/composition-emit-scheduler.js +10 -16
  54. package/dist/runtime/content-language.d.ts +32 -0
  55. package/dist/runtime/content-language.js +46 -0
  56. package/dist/runtime/content-region.d.ts +13 -0
  57. package/dist/runtime/content-region.js +29 -0
  58. package/dist/runtime/content-registration.d.ts +13 -0
  59. package/dist/runtime/content-registration.js +25 -0
  60. package/dist/runtime/core/SectionEngineCore.d.ts +2 -4
  61. package/dist/runtime/core/SectionEngineCore.js +2 -6
  62. package/dist/runtime/core/cohort.d.ts +1 -6
  63. package/dist/runtime/core/cohort.js +1 -10
  64. package/dist/runtime/core/engine-input.d.ts +18 -30
  65. package/dist/runtime/core/engine-input.js +11 -12
  66. package/dist/runtime/core/engine-output.d.ts +17 -40
  67. package/dist/runtime/core/engine-output.js +9 -21
  68. package/dist/runtime/core/engine-readiness.d.ts +5 -37
  69. package/dist/runtime/core/engine-readiness.js +8 -41
  70. package/dist/runtime/core/engine-resolver.d.ts +46 -74
  71. package/dist/runtime/core/engine-resolver.js +18 -43
  72. package/dist/runtime/core/engine-state.d.ts +28 -36
  73. package/dist/runtime/core/engine-state.js +18 -21
  74. package/dist/runtime/core/engine-transition.d.ts +14 -19
  75. package/dist/runtime/core/engine-transition.js +74 -53
  76. package/dist/runtime/engine.d.ts +16 -19
  77. package/dist/runtime/engine.js +12 -19
  78. package/dist/runtime/page-warnings.d.ts +13 -0
  79. package/dist/runtime/page-warnings.js +22 -0
  80. package/dist/runtime/policy-input-forwarding.d.ts +25 -0
  81. package/dist/runtime/policy-input-forwarding.js +25 -0
  82. package/dist/runtime/registration-events.d.ts +22 -14
  83. package/dist/runtime/runtime-event-claim.d.ts +8 -0
  84. package/dist/runtime/runtime-event-claim.js +15 -0
  85. package/dist/runtime/runtime-id.d.ts +1 -1
  86. package/dist/runtime/runtime-id.js +1 -1
  87. package/dist/runtime/shell-event-bridge.d.ts +45 -0
  88. package/dist/runtime/shell-event-bridge.js +127 -0
  89. package/dist/runtime/shell-registration.d.ts +73 -0
  90. package/dist/runtime/shell-registration.js +95 -0
  91. package/dist/runtime/shell-scope.d.ts +68 -0
  92. package/dist/runtime/shell-scope.js +194 -0
  93. package/dist/runtime/tool-host-contract.d.ts +8 -14
  94. package/dist/runtime/tool-host-contract.js +12 -12
  95. package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
  96. package/dist/runtime/unclaimed-registration-watch.js +23 -0
  97. package/dist/services/AccessibilityCatalogResolver.d.ts +21 -31
  98. package/dist/services/AccessibilityCatalogResolver.js +29 -42
  99. package/dist/services/ElementToolStateStore.d.ts +42 -67
  100. package/dist/services/ElementToolStateStore.js +65 -71
  101. package/dist/services/HighlightCoordinator.d.ts +28 -40
  102. package/dist/services/HighlightCoordinator.js +459 -381
  103. package/dist/services/RangeSerializer.d.ts +11 -33
  104. package/dist/services/RangeSerializer.js +88 -59
  105. package/dist/services/SSMLExtractor.d.ts +8 -31
  106. package/dist/services/SSMLExtractor.js +18 -40
  107. package/dist/services/TTSService.d.ts +159 -119
  108. package/dist/services/TTSService.js +937 -822
  109. package/dist/services/ToolCoordinator.d.ts +42 -102
  110. package/dist/services/ToolCoordinator.js +178 -256
  111. package/dist/services/ToolRegistry.d.ts +152 -133
  112. package/dist/services/ToolRegistry.js +192 -178
  113. package/dist/services/ToolkitCoordinator.d.ts +233 -237
  114. package/dist/services/ToolkitCoordinator.js +615 -557
  115. package/dist/services/audio-handoff.d.ts +6 -7
  116. package/dist/services/audio-handoff.js +20 -14
  117. package/dist/services/catalog-owner.d.ts +0 -1
  118. package/dist/services/framework-error-bus.d.ts +3 -6
  119. package/dist/services/framework-error-bus.js +3 -6
  120. package/dist/services/framework-error.d.ts +51 -13
  121. package/dist/services/framework-error.js +19 -20
  122. package/dist/services/interfaces.d.ts +189 -184
  123. package/dist/services/section-controller-types.d.ts +7 -7
  124. package/dist/services/section-session-assignment.d.ts +21 -0
  125. package/dist/services/section-session-assignment.js +80 -0
  126. package/dist/services/spoken-audio-cards.d.ts +2 -6
  127. package/dist/services/spoken-audio-cards.js +2 -6
  128. package/dist/services/tool-config-defaults.d.ts +3 -3
  129. package/dist/services/tool-config-defaults.js +3 -3
  130. package/dist/services/tool-config-validation.d.ts +9 -12
  131. package/dist/services/tool-config-validation.js +47 -87
  132. package/dist/services/tool-context.d.ts +7 -31
  133. package/dist/services/tool-context.js +99 -65
  134. package/dist/services/tool-failure.d.ts +30 -0
  135. package/dist/services/tool-failure.js +11 -0
  136. package/dist/services/tool-icons.d.ts +5 -5
  137. package/dist/services/tool-icons.js +6 -5
  138. package/dist/services/tool-instance-id.d.ts +8 -7
  139. package/dist/services/tool-instance-id.js +12 -24
  140. package/dist/services/tool-providers/TTSToolProvider.d.ts +20 -58
  141. package/dist/services/tool-providers/TTSToolProvider.js +32 -85
  142. package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -11
  143. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +29 -60
  144. package/dist/services/tool-providers/ToolProviderRegistry.js +128 -144
  145. package/dist/services/tool-request.d.ts +31 -12
  146. package/dist/services/tool-request.js +31 -16
  147. package/dist/services/toolbar-decided-tools.d.ts +16 -0
  148. package/dist/services/toolbar-decided-tools.js +29 -0
  149. package/dist/services/toolbar-items.js +2 -5
  150. package/dist/services/tools-config-normalizer.d.ts +33 -29
  151. package/dist/services/tools-config-normalizer.js +26 -28
  152. package/dist/services/tts/browser-provider.d.ts +39 -6
  153. package/dist/services/tts/browser-provider.js +280 -160
  154. package/dist/services/tts/catalog-span-alignment.js +14 -7
  155. package/dist/services/tts/flat-tree.d.ts +64 -0
  156. package/dist/services/tts/flat-tree.js +269 -0
  157. package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
  158. package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
  159. package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
  160. package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
  161. package/dist/services/tts/generated-speech/dom/to-chunk-inputs.d.ts +2 -2
  162. package/dist/services/tts/generated-speech/index.d.ts +1 -1
  163. package/dist/services/tts/generated-speech/index.js +1 -1
  164. package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
  165. package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
  166. package/dist/services/tts/generated-speech/types.d.ts +1 -1
  167. package/dist/services/tts/generated-speech/types.js +1 -1
  168. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +22 -16
  169. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
  170. package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
  171. package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
  172. package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
  173. package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
  174. package/dist/services/tts/highlight-target-resolver.d.ts +12 -0
  175. package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
  176. package/dist/services/tts/math-aware-text-processing.js +42 -47
  177. package/dist/services/tts/math-control-names.d.ts +21 -0
  178. package/dist/services/tts/math-control-names.js +142 -0
  179. package/dist/services/tts/math-speech.d.ts +12 -1
  180. package/dist/services/tts/math-speech.js +54 -18
  181. package/dist/services/tts/mathml-sanitization.d.ts +7 -0
  182. package/dist/services/tts/mathml-sanitization.js +9 -1
  183. package/dist/services/tts/provider-options.d.ts +52 -0
  184. package/dist/services/tts/provider-options.js +1 -0
  185. package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
  186. package/dist/services/tts/ssml/spoken-text.js +29 -0
  187. package/dist/services/tts/start-failure.d.ts +4 -0
  188. package/dist/services/tts/start-failure.js +19 -0
  189. package/dist/services/tts/text-processing.d.ts +9 -0
  190. package/dist/services/tts/text-processing.js +46 -33
  191. package/dist/services/tts/text-segmentation.d.ts +12 -0
  192. package/dist/services/tts/text-segmentation.js +60 -10
  193. package/dist/services/tts-runtime-config.d.ts +54 -26
  194. package/dist/services/tts-runtime-config.js +27 -112
  195. package/dist/tools/content-capability-resolution.d.ts +9 -11
  196. package/dist/tools/content-capability-resolution.js +8 -45
  197. package/dist/tools/registration.d.ts +59 -0
  198. package/dist/tools/registration.js +55 -0
  199. package/dist/tools/registrations/toolbar-registration-helpers.d.ts +6 -0
  200. package/dist/tools/registrations/toolbar-registration-helpers.js +8 -2
  201. package/dist/tools/tool-surface-host.d.ts +6 -10
  202. package/dist/tools/tool-surface-host.js +45 -50
  203. package/dist/tools/tool-tag-map.d.ts +5 -15
  204. package/dist/tools/tool-tag-map.js +6 -20
  205. package/dist/utils/structural-equality.d.ts +11 -0
  206. package/dist/utils/structural-equality.js +47 -0
  207. package/package.json +15 -29
  208. package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
  209. package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
  210. package/dist/components/chunks/ItemToolBar-b9dz5jvd.js +0 -40
  211. package/dist/components/chunks/ItemToolBar-h4xap0t0.js +0 -4
  212. package/dist/components/chunks/ItemToolBar-wr2myaah.js +0 -2
  213. package/dist/components/chunks/sre-engine-wf9s43gg.js +0 -1
  214. package/dist/context/runtime-context-consumer.d.ts +0 -13
  215. package/dist/context/runtime-context-consumer.js +0 -18
  216. package/dist/item-loader.d.ts +0 -44
  217. package/dist/item-loader.js +0 -61
  218. package/dist/policy/core/engine-context.d.ts +0 -29
  219. package/dist/policy/core/engine-context.js +0 -27
  220. package/dist/policy/core/policy-source-tag.d.ts +0 -31
  221. package/dist/policy/core/policy-source-tag.js +0 -28
  222. package/dist/policy/internal.d.ts +0 -25
  223. package/dist/policy/internal.js +0 -25
  224. package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
  225. package/dist/runtime/adapter/coordinator-bridge.js +0 -126
  226. package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
  227. package/dist/runtime/adapter/framework-error-bridge.js +0 -46
  228. package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
  229. package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
  230. package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
  231. package/dist/runtime/core/engine-stage-derivation.js +0 -29
  232. package/dist/runtime/engine-context.d.ts +0 -39
  233. package/dist/runtime/engine-context.js +0 -31
  234. package/dist/runtime/internal.d.ts +0 -43
  235. package/dist/runtime/internal.js +0 -45
  236. package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -74
  237. package/dist/runtime/section-runtime-engine-host-context.js +0 -57
  238. package/dist/runtime/stage-emit-gate.d.ts +0 -92
  239. package/dist/runtime/stage-emit-gate.js +0 -82
  240. package/dist/services/ContextVariableStore.d.ts +0 -113
  241. package/dist/services/ContextVariableStore.js +0 -206
  242. package/dist/services/I18nService.d.ts +0 -47
  243. package/dist/services/I18nService.js +0 -84
  244. package/dist/services/ThemeProvider.d.ts +0 -95
  245. package/dist/services/ThemeProvider.js +0 -334
  246. package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
  247. package/dist/services/defaultPersonalNeedsProfile.js +0 -26
  248. package/dist/services/pnp-standard-features.d.ts +0 -238
  249. package/dist/services/pnp-standard-features.js +0 -338
  250. package/dist/services/tts-control-events.d.ts +0 -13
  251. package/dist/services/tts-control-events.js +0 -7
  252. package/dist/tools/client.d.ts +0 -10
  253. package/dist/tools/client.js +0 -10
  254. package/dist/tools/internal.d.ts +0 -44
  255. package/dist/tools/internal.js +0 -39
  256. package/dist/utils/logger.d.ts +0 -6
  257. package/dist/utils/logger.js +0 -10
@@ -0,0 +1,80 @@
1
+ /**
2
+ * A host-assigned section session, resolved against the session a live
3
+ * controller already holds.
4
+ *
5
+ * The rules are the ones `ItemController.setSession` applies to one item:
6
+ * - a value whose content equals the current session is a no-op, so echoing a
7
+ * snapshot back into the `session` property applies nothing;
8
+ * - an item session with neither a response value nor a response field leaves
9
+ * an item session that holds responses in place. The embedded item player
10
+ * applies the same rule when the section hands the session down, so applying
11
+ * it at section level keeps the controller and its item players from
12
+ * diverging.
13
+ *
14
+ * A controller that holds no session yet takes the value as assigned.
15
+ */
16
+ import { hasResponseField, hasResponseValue, } from "@pie-players/pie-players-shared/pie";
17
+ import { structurallyEqual } from "../utils/structural-equality.js";
18
+ import { isPlainRecord } from "@pie-players/pie-players-shared/object";
19
+ /** An entry is canonical (`{ itemIdentifier, session, ... }`) or the raw item session. */
20
+ function itemSessionOf(entry) {
21
+ return isPlainRecord(entry) && isPlainRecord(entry.session) ? entry.session : entry;
22
+ }
23
+ function sameItemSessions(next, current) {
24
+ const nextSessions = isPlainRecord(next) ? next : {};
25
+ const currentSessions = isPlainRecord(current) ? current : {};
26
+ const itemIds = new Set([
27
+ ...Object.keys(nextSessions),
28
+ ...Object.keys(currentSessions),
29
+ ]);
30
+ for (const itemId of itemIds) {
31
+ if (!structurallyEqual(itemSessionOf(nextSessions[itemId]), itemSessionOf(currentSessions[itemId]))) {
32
+ return false;
33
+ }
34
+ }
35
+ return true;
36
+ }
37
+ /**
38
+ * Whether applying `next` would leave `current` as it is. A field `next` leaves
39
+ * out is unchanged, and item sessions compare by their session payload, so a
40
+ * raw `{ id, data }` matches the canonical entry the controller stored for it.
41
+ */
42
+ function sameSessionContent(next, current) {
43
+ for (const [key, value] of Object.entries(next)) {
44
+ if (value === undefined)
45
+ continue;
46
+ if (key === "itemSessions") {
47
+ if (!sameItemSessions(value, current.itemSessions))
48
+ return false;
49
+ continue;
50
+ }
51
+ if (!structurallyEqual(value, current[key])) {
52
+ return false;
53
+ }
54
+ }
55
+ return true;
56
+ }
57
+ /**
58
+ * The session to apply in replace mode, or `null` when applying `next` would
59
+ * change nothing.
60
+ */
61
+ export function resolveSectionSessionAssignment(current, next) {
62
+ if (!current)
63
+ return next;
64
+ const itemSessions = isPlainRecord(next.itemSessions)
65
+ ? { ...next.itemSessions }
66
+ : {};
67
+ const currentItemSessions = isPlainRecord(current.itemSessions)
68
+ ? current.itemSessions
69
+ : {};
70
+ for (const [itemId, currentEntry] of Object.entries(currentItemSessions)) {
71
+ if (!hasResponseValue(itemSessionOf(currentEntry)))
72
+ continue;
73
+ const assigned = itemSessionOf(itemSessions[itemId]);
74
+ if (hasResponseValue(assigned) || hasResponseField(assigned))
75
+ continue;
76
+ itemSessions[itemId] = currentEntry;
77
+ }
78
+ const resolved = { ...next, itemSessions };
79
+ return sameSessionContent(resolved, current) ? null : resolved;
80
+ }
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * QTI 3 treats a recording and synthesized speech as the *same* support — both
5
5
  * are `spoken`, and a card carries recorded audio through `qti-file-href` plus a
6
- * MIME type — so this is not a new accommodation but the other form the existing
7
- * one can take. Some programs prefer a human voice to synthesis; PIE's `spoken`
6
+ * MIME type — so a recording is the other form the existing support takes.
7
+ * Some programs prefer a human voice to synthesis; PIE's `spoken`
8
8
  * card was string-only, so it had no way to say "play this file for this node".
9
9
  *
10
10
  * A node commonly carries both forms in the same language: the reading script
@@ -17,12 +17,8 @@
17
17
  * Validation posture matches sign-language cards: "treat as absent, never as
18
18
  * partially valid". A malformed payload must not produce a silent player that
19
19
  * looks like read-aloud is working.
20
- *
21
- * Part of PIE Assessment Toolkit.
22
20
  */
23
21
  import type { CatalogCardPayload, MediaFragmentRange, MediaSource } from "@pie-players/pie-players-shared/types";
24
- /** Catalog type token for spoken alternates. Matches QTI 3's `support` value. */
25
- export declare const SPOKEN_CATALOG_TYPE = "spoken";
26
22
  /** A validated recorded spoken alternate, flattened for playback. */
27
23
  export interface SpokenAudioMedia {
28
24
  /**
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * QTI 3 treats a recording and synthesized speech as the *same* support — both
5
5
  * are `spoken`, and a card carries recorded audio through `qti-file-href` plus a
6
- * MIME type — so this is not a new accommodation but the other form the existing
7
- * one can take. Some programs prefer a human voice to synthesis; PIE's `spoken`
6
+ * MIME type — so a recording is the other form the existing support takes.
7
+ * Some programs prefer a human voice to synthesis; PIE's `spoken`
8
8
  * card was string-only, so it had no way to say "play this file for this node".
9
9
  *
10
10
  * A node commonly carries both forms in the same language: the reading script
@@ -17,12 +17,8 @@
17
17
  * Validation posture matches sign-language cards: "treat as absent, never as
18
18
  * partially valid". A malformed payload must not produce a silent player that
19
19
  * looks like read-aloud is working.
20
- *
21
- * Part of PIE Assessment Toolkit.
22
20
  */
23
21
  import { isUnsupportedMediaAssetVersion, normalizeMediaFragment, normalizeMediaSources, trimmedOrUndefined, } from "@pie-players/pie-players-shared/media";
24
- /** Catalog type token for spoken alternates. Matches QTI 3's `support` value. */
25
- export const SPOKEN_CATALOG_TYPE = "spoken";
26
22
  /**
27
23
  * Validate a `spoken` card's payload into something playable, or `null`.
28
24
  *
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Placement defaults this package can hold.
3
3
  *
4
- * Only the empty one. `PACKAGED_TOOL_PLACEMENT` and
5
- * `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` name capabilities, so they moved to
6
- * the composition layer (`@pie-players/pie-default-tool-loaders`).
4
+ * Only the empty one. `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` names
5
+ * capabilities, so it lives in the composition layer
6
+ * (`@pie-players/pie-default-tool-loaders`).
7
7
  */
8
8
  export declare const DEFAULT_TOOL_PLACEMENT: {
9
9
  readonly assessment: readonly [];
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Placement defaults this package can hold.
3
3
  *
4
- * Only the empty one. `PACKAGED_TOOL_PLACEMENT` and
5
- * `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` name capabilities, so they moved to
6
- * the composition layer (`@pie-players/pie-default-tool-loaders`).
4
+ * Only the empty one. `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` names
5
+ * capabilities, so it lives in the composition layer
6
+ * (`@pie-players/pie-default-tool-loaders`).
7
7
  */
8
8
  export const DEFAULT_TOOL_PLACEMENT = {
9
9
  assessment: [],
@@ -1,15 +1,13 @@
1
1
  import { type CanonicalToolsConfig, type ToolsConfigInput } from "./tools-config-normalizer.js";
2
- import { type FrameworkErrorModel } from "./framework-error.js";
3
2
  import type { ToolRegistry } from "./ToolRegistry.js";
4
3
  export type ToolConfigStrictness = "off" | "warn" | "error";
5
4
  export type ToolConfigDiagnosticSeverity = "warning" | "error";
6
5
  export interface ToolConfigDiagnostic {
7
- code: "tools.unknownToolId" | "tools.unsupportedLevel" | "tools.unplaceableActivation" | "tools.registryUnavailable" | "tools.unknownProviderKey" | "tools.removedProviderKey" | "tools.providerSanitizeFailed" | "tools.providerValidateFailed" | "tools.invalidProviderValidation";
6
+ code: "tools.unknownToolId" | "tools.unsupportedLevel" | "tools.unplaceableActivation" | "tools.registryUnavailable" | "tools.unknownProviderKey" | "tools.providerSanitizeFailed" | "tools.providerValidateFailed" | "tools.invalidProviderValidation";
8
7
  severity: ToolConfigDiagnosticSeverity;
9
8
  path: string;
10
9
  message: string;
11
10
  toolId?: string;
12
- providerId?: string;
13
11
  }
14
12
  export interface ToolConfigValidationOptions {
15
13
  strictness?: ToolConfigStrictness;
@@ -20,13 +18,12 @@ export interface ToolConfigValidationResult {
20
18
  config: CanonicalToolsConfig;
21
19
  diagnostics: ToolConfigDiagnostic[];
22
20
  }
23
- export declare function frameworkErrorFromToolConfigValidation(args: {
24
- source: string;
25
- diagnostics?: ToolConfigDiagnostic[] | null;
26
- error?: unknown;
27
- recoverable?: boolean;
28
- }): FrameworkErrorModel;
29
21
  export declare function normalizeToolConfigStrictness(value: unknown): ToolConfigStrictness;
22
+ /**
23
+ * Normalize a tools config, sanitize and validate each provider entry with its
24
+ * registration's hooks, check ids and levels against `options.toolRegistry`,
25
+ * and report the diagnostics by `options.strictness` (default `"error"`).
26
+ */
30
27
  export declare function normalizeAndValidateToolsConfig(input?: ToolsConfigInput | null, options?: ToolConfigValidationOptions): ToolConfigValidationResult;
31
28
  /**
32
29
  * The normalization and diagnostics of {@link normalizeAndValidateToolsConfig},
@@ -34,8 +31,8 @@ export declare function normalizeAndValidateToolsConfig(input?: ToolsConfigInput
34
31
  */
35
32
  export declare function collectToolConfigDiagnostics(input: ToolsConfigInput | null | undefined, toolRegistry: ToolRegistry | null | undefined): ToolConfigValidationResult;
36
33
  /**
37
- * Report diagnostics as {@link normalizeAndValidateToolsConfig} does: a removed
38
- * provider key throws at every strictness, `"warn"` prints every diagnostic, and
39
- * `"error"` throws the blocking ones or, when there are none, prints the rest.
34
+ * Report diagnostics as {@link normalizeAndValidateToolsConfig} does: `"warn"`
35
+ * prints every diagnostic, and `"error"` throws the blocking ones or, when there
36
+ * are none, prints the rest.
40
37
  */
41
38
  export declare function reportToolConfigDiagnostics(diagnostics: ToolConfigDiagnostic[], options?: Pick<ToolConfigValidationOptions, "strictness" | "source">): void;
@@ -1,20 +1,4 @@
1
1
  import { normalizeToolsConfig, } from "./tools-config-normalizer.js";
2
- import { frameworkErrorFromToolConfigDiagnostics, frameworkErrorFromUnknown, } from "./framework-error.js";
3
- export function frameworkErrorFromToolConfigValidation(args) {
4
- if (Array.isArray(args.diagnostics) && args.diagnostics.length > 0) {
5
- return frameworkErrorFromToolConfigDiagnostics({
6
- source: args.source,
7
- diagnostics: args.diagnostics,
8
- recoverable: args.recoverable,
9
- });
10
- }
11
- return frameworkErrorFromUnknown({
12
- kind: "tool-config",
13
- source: args.source,
14
- error: args.error ?? new Error("Invalid tools config"),
15
- recoverable: args.recoverable,
16
- });
17
- }
18
2
  const DEFAULT_STRICTNESS = "error";
19
3
  export function normalizeToolConfigStrictness(value) {
20
4
  if (value === "off" || value === "warn" || value === "error") {
@@ -34,21 +18,20 @@ function getRegistryToolMap(toolRegistry) {
34
18
  .sort((left, right) => left.toolId.localeCompare(right.toolId))
35
19
  .map((tool) => [tool.toolId, tool]));
36
20
  }
37
- function sanitizeProviderConfig(providerId, providerConfig, tool, diagnostics) {
38
- if (!providerConfig || !tool?.provider?.sanitizeConfig)
21
+ function sanitizeToolConfig(toolId, providerConfig, tool, diagnostics) {
22
+ if (!providerConfig || !tool?.sanitizeConfig)
39
23
  return providerConfig;
40
24
  try {
41
- const sanitized = tool.provider.sanitizeConfig(providerConfig);
25
+ const sanitized = tool.sanitizeConfig(providerConfig);
42
26
  if (!sanitized ||
43
27
  typeof sanitized !== "object" ||
44
28
  Array.isArray(sanitized)) {
45
29
  diagnostics.push(createDiagnostic({
46
30
  code: "tools.providerSanitizeFailed",
47
31
  severity: "error",
48
- path: `providers.${providerId}`,
49
- message: `Provider sanitizer for "${providerId}" must return an object.`,
50
- providerId,
51
- toolId: providerId,
32
+ path: `providers.${toolId}`,
33
+ message: `Config sanitizer of tool "${toolId}" must return an object.`,
34
+ toolId,
52
35
  }));
53
36
  return providerConfig;
54
37
  }
@@ -58,36 +41,33 @@ function sanitizeProviderConfig(providerId, providerConfig, tool, diagnostics) {
58
41
  diagnostics.push(createDiagnostic({
59
42
  code: "tools.providerSanitizeFailed",
60
43
  severity: "error",
61
- path: `providers.${providerId}`,
62
- message: `Provider sanitizer failed for "${providerId}": ${error instanceof Error ? error.message : String(error)}`,
63
- providerId,
64
- toolId: providerId,
44
+ path: `providers.${toolId}`,
45
+ message: `Config sanitizer of tool "${toolId}" failed: ${error instanceof Error ? error.message : String(error)}`,
46
+ toolId,
65
47
  }));
66
48
  return providerConfig;
67
49
  }
68
50
  }
69
- function validateProviderConfig(providerId, providerConfig, tool, diagnostics) {
70
- if (!providerConfig || !tool?.provider?.validateConfig)
51
+ function validateToolConfig(toolId, providerConfig, tool, diagnostics) {
52
+ if (!providerConfig || !tool?.validateConfig)
71
53
  return;
72
54
  try {
73
- const providerDiagnostics = tool.provider.validateConfig(providerConfig);
74
- if (!Array.isArray(providerDiagnostics)) {
55
+ const toolDiagnostics = tool.validateConfig(providerConfig);
56
+ if (!Array.isArray(toolDiagnostics)) {
75
57
  diagnostics.push(createDiagnostic({
76
58
  code: "tools.invalidProviderValidation",
77
59
  severity: "error",
78
- path: `providers.${providerId}`,
79
- message: `Provider validator for "${providerId}" must return an array.`,
80
- providerId,
81
- toolId: providerId,
60
+ path: `providers.${toolId}`,
61
+ message: `Config validator of tool "${toolId}" must return an array.`,
62
+ toolId,
82
63
  }));
83
64
  return;
84
65
  }
85
- for (const diagnostic of providerDiagnostics) {
66
+ for (const diagnostic of toolDiagnostics) {
86
67
  diagnostics.push({
87
68
  ...diagnostic,
88
- path: diagnostic.path || `providers.${providerId}`,
89
- providerId: diagnostic.providerId || providerId,
90
- toolId: diagnostic.toolId || providerId,
69
+ path: diagnostic.path || `providers.${toolId}`,
70
+ toolId: diagnostic.toolId || toolId,
91
71
  });
92
72
  }
93
73
  }
@@ -95,10 +75,9 @@ function validateProviderConfig(providerId, providerConfig, tool, diagnostics) {
95
75
  diagnostics.push(createDiagnostic({
96
76
  code: "tools.providerValidateFailed",
97
77
  severity: "error",
98
- path: `providers.${providerId}`,
99
- message: `Provider validator failed for "${providerId}": ${error instanceof Error ? error.message : String(error)}`,
100
- providerId,
101
- toolId: providerId,
78
+ path: `providers.${toolId}`,
79
+ message: `Config validator of tool "${toolId}" failed: ${error instanceof Error ? error.message : String(error)}`,
80
+ toolId,
102
81
  }));
103
82
  }
104
83
  }
@@ -176,27 +155,16 @@ function collectPolicyDiagnostics(config, toolMap, diagnostics) {
176
155
  }));
177
156
  }
178
157
  }
179
- function collectProviderKeyDiagnostics(config, toolMap, hasRemovedTtsKey, diagnostics) {
180
- if (hasRemovedTtsKey) {
181
- diagnostics.push(createDiagnostic({
182
- code: "tools.removedProviderKey",
183
- severity: "error",
184
- path: "providers.tts",
185
- message: `Provider key "tts" is no longer supported. Use "providers.textToSpeech".`,
186
- providerId: "tts",
187
- toolId: "textToSpeech",
188
- }));
189
- }
190
- for (const providerId of Object.keys(config.providers).sort()) {
191
- if (toolMap.size === 0 || toolMap.has(providerId))
158
+ function collectProviderKeyDiagnostics(config, toolMap, diagnostics) {
159
+ for (const key of Object.keys(config.providers).sort()) {
160
+ if (toolMap.size === 0 || toolMap.has(key))
192
161
  continue;
193
162
  diagnostics.push(createDiagnostic({
194
163
  code: "tools.unknownProviderKey",
195
164
  severity: "error",
196
- path: `providers.${providerId}`,
197
- message: `Unknown provider key "${providerId}".`,
198
- providerId,
199
- toolId: providerId,
165
+ path: `providers.${key}`,
166
+ message: `Unknown provider key "${key}".`,
167
+ toolId: key,
200
168
  }));
201
169
  }
202
170
  }
@@ -214,6 +182,11 @@ function throwValidationError(diagnostics, source) {
214
182
  .join("\n");
215
183
  throw new Error(`[tool-config-validation:${source}] Invalid tools config:\n${formatted}`);
216
184
  }
185
+ /**
186
+ * Normalize a tools config, sanitize and validate each provider entry with its
187
+ * registration's hooks, check ids and levels against `options.toolRegistry`,
188
+ * and report the diagnostics by `options.strictness` (default `"error"`).
189
+ */
217
190
  export function normalizeAndValidateToolsConfig(input, options = {}) {
218
191
  const result = collectToolConfigDiagnostics(input, options.toolRegistry);
219
192
  reportToolConfigDiagnostics(result.diagnostics, options);
@@ -228,11 +201,9 @@ export function collectToolConfigDiagnostics(input, toolRegistry) {
228
201
  const normalized = normalizeToolsConfig(input);
229
202
  const diagnostics = [];
230
203
  // Tool-id and provider checks need a registry to check against, and every
231
- // collector below returns early without one. Say so: this package no longer
232
- // falls back to a packaged registry, so a caller that used to get id
233
- // validation for free now gets none, and a silent downgrade of "your ids are
234
- // valid" to "nobody looked" is the kind of change that surfaces as a typo
235
- // reaching a learner.
204
+ // collector below returns early without one. Say so, since there is no
205
+ // packaged fallback registry: silence would read as "your ids are valid" when
206
+ // nobody looked, and a typo would reach a learner.
236
207
  const hasConfiguredTools = Object.values(normalized.placement).some((ids) => ids.length > 0) ||
237
208
  Object.keys(normalized.providers).length > 0 ||
238
209
  (normalized.policy.allowed?.length ?? 0) > 0 ||
@@ -245,18 +216,13 @@ export function collectToolConfigDiagnostics(input, toolRegistry) {
245
216
  message: 'No tool registry was supplied, so tool ids, placement levels and provider config were not validated, and a coordinator without one registers no tool providers. Pass `toolRegistry` to the coordinator or the toolkit it is bound to — for the packaged capability set, `createPackagedToolRegistry()` from "@pie-players/pie-default-tool-loaders".',
246
217
  }));
247
218
  }
248
- const hasRemovedTtsKey = Object.hasOwn(normalized.providers, "tts");
249
219
  const nextProviders = {
250
220
  ...(normalized.providers || {}),
251
221
  };
252
- for (const providerId of Object.keys(nextProviders).sort()) {
253
- if (providerId === "tts") {
254
- delete nextProviders.tts;
255
- continue;
256
- }
257
- const tool = registryTools.get(providerId);
258
- nextProviders[providerId] = sanitizeProviderConfig(providerId, nextProviders[providerId], tool, diagnostics);
259
- validateProviderConfig(providerId, nextProviders[providerId], tool, diagnostics);
222
+ for (const toolId of Object.keys(nextProviders).sort()) {
223
+ const tool = registryTools.get(toolId);
224
+ nextProviders[toolId] = sanitizeToolConfig(toolId, nextProviders[toolId], tool, diagnostics);
225
+ validateToolConfig(toolId, nextProviders[toolId], tool, diagnostics);
260
226
  }
261
227
  const nextConfig = {
262
228
  ...normalized,
@@ -264,32 +230,26 @@ export function collectToolConfigDiagnostics(input, toolRegistry) {
264
230
  };
265
231
  collectPlacementDiagnostics(nextConfig, registryTools, diagnostics);
266
232
  collectPolicyDiagnostics(nextConfig, registryTools, diagnostics);
267
- collectProviderKeyDiagnostics(nextConfig, registryTools, hasRemovedTtsKey, diagnostics);
233
+ collectProviderKeyDiagnostics(nextConfig, registryTools, diagnostics);
268
234
  return {
269
235
  config: nextConfig,
270
236
  diagnostics,
271
237
  };
272
238
  }
273
239
  /**
274
- * Report diagnostics as {@link normalizeAndValidateToolsConfig} does: a removed
275
- * provider key throws at every strictness, `"warn"` prints every diagnostic, and
276
- * `"error"` throws the blocking ones or, when there are none, prints the rest.
240
+ * Report diagnostics as {@link normalizeAndValidateToolsConfig} does: `"warn"`
241
+ * prints every diagnostic, and `"error"` throws the blocking ones or, when there
242
+ * are none, prints the rest.
277
243
  */
278
244
  export function reportToolConfigDiagnostics(diagnostics, options = {}) {
279
245
  const strictness = normalizeToolConfigStrictness(options.strictness);
280
246
  const source = options.source ?? "tools";
281
- const removedKeys = diagnostics.filter((entry) => entry.code === "tools.removedProviderKey");
282
- if (removedKeys.length > 0) {
283
- throwValidationError(removedKeys, source);
284
- }
285
247
  if (strictness === "warn") {
286
248
  emitWarnings(diagnostics, source);
287
249
  }
288
- // Severity decides what `strictness: "error"` rejects. Every diagnostic was
289
- // `"error"` until `tools.registryUnavailable`, which reports that validation
290
- // could not run rather than that the config is wrong — throwing on it would
291
- // turn "no registry supplied" from a host's existing, working setup into a
292
- // construction failure.
250
+ // Severity decides what `strictness: "error"` rejects. `tools.registryUnavailable`
251
+ // is a warning: it reports that validation could not run, and throwing on it
252
+ // would fail construction for a host whose setup works without a registry.
293
253
  const blocking = diagnostics.filter((entry) => entry.severity === "error");
294
254
  if (strictness === "error" && blocking.length > 0) {
295
255
  throwValidationError(blocking, source);
@@ -102,38 +102,9 @@ export interface ElementToolContext extends BaseToolContext {
102
102
  */
103
103
  export type ToolContext = AssessmentToolContext | SectionToolContext | ItemToolContext | PassageToolContext | RubricToolContext | ElementToolContext;
104
104
  /**
105
- * Type guard to check if context is at assessment level
106
- */
107
- export declare function isAssessmentContext(context: ToolContext): context is AssessmentToolContext;
108
- /**
109
- * Type guard to check if context is at section level
110
- */
111
- export declare function isSectionContext(context: ToolContext): context is SectionToolContext;
112
- /**
113
- * Type guard to check if context is at item level
114
- */
115
- export declare function isItemContext(context: ToolContext): context is ItemToolContext;
116
- /**
117
- * Type guard to check if context is at passage level
118
- */
119
- export declare function isPassageContext(context: ToolContext): context is PassageToolContext;
120
- /**
121
- * Type guard to check if context is at rubric level
122
- */
123
- export declare function isRubricContext(context: ToolContext): context is RubricToolContext;
124
- /**
125
- * Type guard to check if context is at element level
126
- */
127
- export declare function isElementContext(context: ToolContext): context is ElementToolContext;
128
- /** The plain text a context carries, tags removed. */
129
- export declare function extractTextContent(context: ToolContext): string;
130
- /**
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.
105
+ * Helper to check if context contains mathematical content
106
+ * (Basic heuristic - can be overridden by tools)
135
107
  */
136
- export declare function extractMarkupContent(context: ToolContext): string;
137
108
  export declare function hasMathContent(context: ToolContext): boolean;
138
109
  /**
139
110
  * Helper to check if context contains choice-based interactions
@@ -143,6 +114,11 @@ export declare function hasChoiceInteraction(context: ToolContext): boolean;
143
114
  * Helper to check if context contains text that can be read aloud
144
115
  */
145
116
  export declare function hasReadableText(context: ToolContext): boolean;
117
+ /**
118
+ * Whether read-aloud has something to read: readable text, or markup carrying
119
+ * a catalog idref, whose spoken card reads for content with no text.
120
+ */
121
+ export declare function hasSpokenContent(context: ToolContext): boolean;
146
122
  /**
147
123
  * Helper to check if context contains science content
148
124
  * (Basic heuristic - can be overridden by tools)