@pie-players/pie-assessment-toolkit 1.0.0-beta.7 → 1.0.0-beta.9
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/custom-elements.json +7 -0
- package/dist/components/ItemScope.custom-element.js +1 -1
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +7 -7
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-bsww9e8f.js +4 -0
- package/dist/components/chunks/ItemToolBar-eg8jarh0.js +2 -0
- package/dist/components/chunks/{ItemToolBar-pxan157g.js → ItemToolBar-gsb96731.js} +2 -2
- package/dist/components/chunks/ItemToolBar-na4e5vwt.js +2 -0
- package/dist/components/chunks/{ItemToolBar-xwjrpdmz.js → ItemToolBar-wcw4yxjy.js} +1 -1
- package/dist/components/chunks/ItemToolBar-zvy0hskj.js +40 -0
- package/dist/components/chunks/sre-engine-wazxma67.js +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/runtime/SectionControllerBinding.d.ts +16 -5
- package/dist/runtime/SectionControllerBinding.js +14 -6
- package/dist/runtime/registration-events.d.ts +31 -4
- package/dist/runtime/registration-events.js +20 -1
- package/dist/runtime/shell-event-bridge.d.ts +7 -1
- package/dist/runtime/shell-event-bridge.js +44 -1
- package/dist/runtime/shell-scope.d.ts +2 -2
- package/dist/runtime/shell-scope.js +14 -5
- package/dist/services/SSMLExtractor.js +8 -23
- package/dist/services/ToolRegistry.d.ts +11 -3
- package/dist/services/ToolRegistry.js +8 -4
- package/dist/services/ToolkitCoordinator.d.ts +12 -47
- package/dist/services/ToolkitCoordinator.js +45 -284
- package/dist/services/section-controller-types.d.ts +71 -20
- package/dist/services/tool-config-validation.d.ts +1 -1
- package/dist/services/tool-context.js +94 -11
- package/dist/services/tool-icons.js +2 -0
- package/dist/services/tool-provider-defaults.d.ts +13 -0
- package/dist/services/tool-provider-defaults.js +20 -0
- package/dist/services/tts/browser-provider.js +3 -1
- package/dist/services/tts/tts-lifecycle.d.ts +142 -0
- package/dist/services/tts/tts-lifecycle.js +341 -0
- package/dist/tools/content-surfaces.d.ts +35 -0
- package/dist/tools/content-surfaces.js +35 -0
- package/dist/tools/registration.d.ts +2 -0
- package/dist/tools/registration.js +5 -0
- package/package.json +8 -8
- package/dist/components/chunks/ItemToolBar-4vq9nbxz.js +0 -2
- package/dist/components/chunks/ItemToolBar-f971t0cw.js +0 -4
- package/dist/components/chunks/ItemToolBar-n05xjkp8.js +0 -2
- package/dist/components/chunks/ItemToolBar-rgmvw9sm.js +0 -40
- package/dist/components/chunks/sre-engine-dq0w45fv.js +0 -1
|
@@ -31,6 +31,45 @@ function isElementContext(context) {
|
|
|
31
31
|
return context.level === "element";
|
|
32
32
|
}
|
|
33
33
|
const stripHtml = (value) => value.replace(/<[^>]*>/g, " ").trim();
|
|
34
|
+
// The digit fold mirrors pie-elements-ng's response normalizer
|
|
35
|
+
// (`controller-utils/src/response-normalizer.ts`), so tool visibility and
|
|
36
|
+
// scoring read one number the same way. The separators fold to the
|
|
37
|
+
// point-decimal marks the patterns below are written in.
|
|
38
|
+
const DECIMAL_DIGIT = /\p{Nd}/u;
|
|
39
|
+
const NON_ASCII_DIGITS = /(?![0-9])\p{Nd}/gu;
|
|
40
|
+
// ALM, LRM, RLM, the embeddings and overrides, the isolates, and tatweel.
|
|
41
|
+
const BIDI_CONTROLS_AND_TATWEEL = /[\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069\u0640]/g;
|
|
42
|
+
const digitValues = new Map();
|
|
43
|
+
/**
|
|
44
|
+
* A decimal digit's value: its offset into its run of ten. Unicode assigns
|
|
45
|
+
* decimal digits only in ascending runs from zero, and runs can abut, hence the
|
|
46
|
+
* modulo.
|
|
47
|
+
*/
|
|
48
|
+
function digitValue(codePoint) {
|
|
49
|
+
const cached = digitValues.get(codePoint);
|
|
50
|
+
if (cached !== undefined)
|
|
51
|
+
return cached;
|
|
52
|
+
let offset = 0;
|
|
53
|
+
while (DECIMAL_DIGIT.test(String.fromCodePoint(codePoint - offset - 1))) {
|
|
54
|
+
offset += 1;
|
|
55
|
+
}
|
|
56
|
+
const value = offset % 10;
|
|
57
|
+
digitValues.set(codePoint, value);
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Text with every decimal digit in ASCII, the Arabic decimal, thousands and
|
|
62
|
+
* percent signs as `.`, `,` and `%`, and bidi controls and tatweel removed, so
|
|
63
|
+
* the patterns below match `٣٫٥ × ٢ = ٧` as they match `3.5 × 2 = 7`.
|
|
64
|
+
*/
|
|
65
|
+
function foldNumerals(text) {
|
|
66
|
+
return text
|
|
67
|
+
.replace(BIDI_CONTROLS_AND_TATWEEL, "")
|
|
68
|
+
.replace(NON_ASCII_DIGITS, (digit) => String(digitValue(digit.codePointAt(0))))
|
|
69
|
+
.replace(/\u066B/g, ".")
|
|
70
|
+
.replace(/\u066C/g, ",")
|
|
71
|
+
.replace(/\u066A/g, "%");
|
|
72
|
+
}
|
|
34
73
|
/**
|
|
35
74
|
* A config's `models` as a list, whether it was authored as an array or as a
|
|
36
75
|
* record keyed by element id. Both forms are in the wild.
|
|
@@ -155,6 +194,10 @@ function extractContent(context, transform) {
|
|
|
155
194
|
function extractTextContent(context) {
|
|
156
195
|
return extractContent(context, stripHtml);
|
|
157
196
|
}
|
|
197
|
+
/** The plain text a context carries, with its numerals folded for matching. */
|
|
198
|
+
function extractMatchableText(context) {
|
|
199
|
+
return foldNumerals(extractTextContent(context));
|
|
200
|
+
}
|
|
158
201
|
/**
|
|
159
202
|
* The authored markup a context carries, tags intact.
|
|
160
203
|
*
|
|
@@ -250,10 +293,24 @@ function hasSpacedSubtraction(text) {
|
|
|
250
293
|
});
|
|
251
294
|
}
|
|
252
295
|
const PERCENTAGE = /\d\s*%/;
|
|
253
|
-
/**
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
296
|
+
/**
|
|
297
|
+
* A percentage taken of a number: `20% of 50`, `15% of $80`, `el 20% de 50`,
|
|
298
|
+
* `٢٠٪ من ٥٠`.
|
|
299
|
+
*/
|
|
300
|
+
const PERCENTAGE_OF_NUMBER = /\d\s*%\s+(?:of|de|van|من)\s+\p{Sc}?\s?\d/iu;
|
|
301
|
+
/** A money amount: `$40`, `€ 12`, `12,50 €`, `٥٠ ؋`. */
|
|
302
|
+
const MONEY = /\p{Sc}\s?\d|\d\s?\p{Sc}/u;
|
|
303
|
+
/**
|
|
304
|
+
* Currencies written as a word after the amount, by content language.
|
|
305
|
+
*
|
|
306
|
+
* Arabic writes most currencies as a word or an abbreviation where English
|
|
307
|
+
* writes a sign: `٥٠ ريالًا`, `١٢ د.إ`. English has no set, because its
|
|
308
|
+
* spelled-out "40 dollars" never counted. Script-disjoint, so every set is
|
|
309
|
+
* tried. The Arabic set is pending the native review (PIE-1364).
|
|
310
|
+
*/
|
|
311
|
+
const CURRENCY_WORDS = {
|
|
312
|
+
ar: /\d\s*(?:ريال|دينار|درهم|جنيه|دولار|يورو|ليرة|ر\.س|د\.إ|د\.ك|ج\.م)/u,
|
|
313
|
+
};
|
|
257
314
|
/**
|
|
258
315
|
* Whether the text applies a percentage to a quantity.
|
|
259
316
|
*
|
|
@@ -265,7 +322,10 @@ const MONEY = /[$€£]\s?\d|\d\s?[€£]/;
|
|
|
265
322
|
function hasAppliedPercentage(text) {
|
|
266
323
|
if (PERCENTAGE_OF_NUMBER.test(text))
|
|
267
324
|
return true;
|
|
268
|
-
|
|
325
|
+
if (!PERCENTAGE.test(text))
|
|
326
|
+
return false;
|
|
327
|
+
return (MONEY.test(text) ||
|
|
328
|
+
Object.values(CURRENCY_WORDS).some((pattern) => pattern.test(text)));
|
|
269
329
|
}
|
|
270
330
|
/**
|
|
271
331
|
* Helper to check if context contains mathematical content
|
|
@@ -283,7 +343,7 @@ export function hasMathContent(context) {
|
|
|
283
343
|
];
|
|
284
344
|
if (structuralIndicators.some((pattern) => pattern.test(markup)))
|
|
285
345
|
return true;
|
|
286
|
-
const text =
|
|
346
|
+
const text = extractMatchableText(context);
|
|
287
347
|
// No bare-operator pattern: a lone hyphen or slash matches "well-known" and
|
|
288
348
|
// "and/or", which would make nearly every item mathematical. An operator
|
|
289
349
|
// counts only with operands around it, or when the character has no prose
|
|
@@ -399,16 +459,39 @@ export function hasSpokenContent(context) {
|
|
|
399
459
|
* (Basic heuristic - can be overridden by tools)
|
|
400
460
|
*/
|
|
401
461
|
export function hasScienceContent(context) {
|
|
402
|
-
const text =
|
|
462
|
+
const text = extractMatchableText(context);
|
|
403
463
|
if (hasChemicalFormula(text))
|
|
404
464
|
return true;
|
|
405
465
|
if (/[A-Z][a-z]?[\u2080-\u2089]/.test(text))
|
|
406
466
|
return true; // Subscripted: H₂O, CO₂
|
|
407
|
-
|
|
467
|
+
return Object.values(SCIENCE_KEYWORDS).some((patterns) => patterns.some((pattern) => pattern.test(text)));
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Science vocabulary by content language, one pattern per field: chemistry,
|
|
471
|
+
* element naming, biology, physics.
|
|
472
|
+
*
|
|
473
|
+
* Every set is tried, because the sets are script-disjoint and content often
|
|
474
|
+
* declares no language: an Arabic pattern cannot match English text. A language
|
|
475
|
+
* is added as a set of its own.
|
|
476
|
+
*
|
|
477
|
+
* Arabic attaches the conjunction, prepositions and article to the word, so its
|
|
478
|
+
* patterns match stems unanchored. The exceptions are قوة (force) and طاقة
|
|
479
|
+
* (energy), bounded the way `\bforce\b` is: unbounded, بطاقة (card) and بقوة
|
|
480
|
+
* (strongly) would match. "compound" has no Arabic entry, since مركب is also a
|
|
481
|
+
* vehicle; كيميائي covers a chemical compound. The Arabic set is pending the
|
|
482
|
+
* native review (PIE-1364).
|
|
483
|
+
*/
|
|
484
|
+
const SCIENCE_KEYWORDS = {
|
|
485
|
+
en: [
|
|
408
486
|
/chemistry|chemical|molecule|compound|periodic\s+table/i,
|
|
409
487
|
/\bchemical\s+element\b|\belement\s+symbol\b/i,
|
|
410
488
|
/biology|organism|\bDNA\b|\bRNA\b|protein|photosynthesis|ecosystem/i,
|
|
411
489
|
/physics|\bforce\b|\benergy\b|velocity|acceleration|momentum/i,
|
|
412
|
-
]
|
|
413
|
-
|
|
414
|
-
|
|
490
|
+
],
|
|
491
|
+
ar: [
|
|
492
|
+
/كيمياء|كيميائي|جزيء|جزيئ|جدول\s+(?:ال)?دوري/u,
|
|
493
|
+
/رمز\s+(?:ال)?عنصر/u,
|
|
494
|
+
/علم\s+الأحياء|كائن(?:ات)?\s+(?:ال)?حي|حمض\s+(?:ال)?نووي|بروتين|(?:بناء|تمثيل)\s+(?:ال)?ضوئي|(?:نظام|نظم|أنظمة)\s+(?:ال)?بيئي/u,
|
|
495
|
+
/فيزياء|فيزيائي|(?<!\p{L})(?:و|ال|وال)?(?:قوة|قوى|طاقة)(?!\p{L})|سرعة\s+(?:ال)?متجهة|تسارع|كمية\s+(?:ال)?حركة/u,
|
|
496
|
+
],
|
|
497
|
+
};
|
|
@@ -25,6 +25,8 @@ const TOOL_FALLBACK_ICONS = {
|
|
|
25
25
|
"magnifying-glass": '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.5 14h-.79l-.28-.27A6.47 6.47 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16a6.47 6.47 0 0 0 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5Zm-6 0A4.5 4.5 0 1 1 14 9.5 4.49 4.49 0 0 1 9.5 14ZM12 10h-2v2H9v-2H7V9h2V7h1v2h2v1Z" fill="currentColor"/></svg>',
|
|
26
26
|
ruler: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m8.8 10.95 2.15-2.175-1.4-1.425-1.1 1.1-1.4-1.4 1.075-1.1L7 4.825 4.825 7 8.8 10.95Zm8.2 8.225L19.175 17l-1.125-1.125-1.1 1.075-1.4-1.4 1.075-1.1-1.425-1.4-2.15 2.15L17 19.175ZM7.25 21H3v-4.25l4.375-4.375L2 7l5-5 5.4 5.4 3.775-3.8c.2-.2.425-.35.675-.45a2.068 2.068 0 0 1 1.55 0c.25.1.475.25.675.45L20.4 4.95c.2.2.35.425.45.675.1.25.15.508.15.775a1.975 1.975 0 0 1-.6 1.425l-3.775 3.8L22 17l-5 5-5.375-5.375L7.25 21ZM5 19h1.4l9.8-9.775L14.775 7.8 5 17.6V19Z" fill="currentColor"/></svg>',
|
|
27
27
|
"book-open": '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 6.25a6.6 6.6 0 0 0-2.3-1.32A8.6 8.6 0 0 0 7 4.5c-.63 0-1.25.06-1.85.18-.6.12-1.19.3-1.76.54a1.5 1.5 0 0 0-.93 1.4v10.1c0 .52.26.98.68 1.24.42.26.92.28 1.35.06.36-.18.75-.31 1.18-.4.42-.09.86-.13 1.33-.13.78 0 1.53.14 2.24.42.7.28 1.35.7 1.93 1.24l.83-.75.83.75c.58-.54 1.22-.96 1.93-1.24a6.1 6.1 0 0 1 2.24-.42c.47 0 .91.04 1.33.13.43.09.82.22 1.18.4.43.22.93.2 1.35-.06.42-.26.68-.72.68-1.24V6.62c0-.6-.36-1.15-.93-1.4a9.3 9.3 0 0 0-1.76-.54A9.8 9.8 0 0 0 17 4.5a8.6 8.6 0 0 0-2.7.43A6.6 6.6 0 0 0 12 6.25Zm1 10.06V8.02c.55-.5 1.16-.88 1.84-1.13A6 6 0 0 1 17 6.5c.45 0 .89.04 1.32.11.43.08.85.19 1.26.34v9.24a8.2 8.2 0 0 0-1.28-.24A10 10 0 0 0 17 15.85c-.72 0-1.42.09-2.09.26a7.7 7.7 0 0 0-1.91.8Zm-2 0a7.7 7.7 0 0 0-1.91-.8 8.4 8.4 0 0 0-2.09-.26c-.44 0-.87.02-1.3.07-.43.05-.86.13-1.28.24V6.95c.41-.15.83-.26 1.26-.34A7.7 7.7 0 0 1 7 6.5c.76 0 1.48.13 2.16.39.68.25 1.29.63 1.84 1.13Z" fill="currentColor"/></svg>',
|
|
28
|
+
highlighter: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22 24H2v-4h20v4ZM13.06 5.19l3.75 3.75L7.75 18H4v-3.75l9.06-9.06Zm4.82 2.68-3.75-3.75 1.83-1.83a1 1 0 0 1 1.41 0l2.34 2.34a1 1 0 0 1 0 1.41l-1.83 1.83Z" fill="currentColor"/></svg>',
|
|
29
|
+
strikethrough: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2Zm-3.4 14L12 13.4 8.4 17 7 15.6l3.6-3.6L7 8.4 8.4 7l3.6 3.6L15.6 7 17 8.4 13.4 12l3.6 3.6-1.4 1.4Z" fill="currentColor"/></svg>',
|
|
28
30
|
photo: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 21c-.55 0-1.02-.2-1.41-.59A1.93 1.93 0 0 1 2 19V5c0-.55.2-1.02.59-1.41A1.93 1.93 0 0 1 4 3h16c.55 0 1.02.2 1.41.59.39.39.59.86.59 1.41v14c0 .55-.2 1.02-.59 1.41-.39.39-.86.59-1.41.59H4Zm0-2h16V5H4v14Zm1.5-2.5h13l-4.1-5.47-3.4 4.47-2.5-3.25L5.5 16.5ZM8.5 10a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z" fill="currentColor"/></svg>',
|
|
29
31
|
};
|
|
30
32
|
/** Icon markup for `name`, or `null` when nothing built in matches. */
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provider configs a coordinator applies when the host's tools config
|
|
3
|
+
* names none for a capability.
|
|
4
|
+
*
|
|
5
|
+
* This module names capabilities on purpose, like `services/support-conflicts.ts`:
|
|
6
|
+
* a default is a statement about which capabilities a deployment starts with,
|
|
7
|
+
* which is not a decision the capability-neutral coordination layer gets to
|
|
8
|
+
* make. The coordinator applies the table without naming its entries —
|
|
9
|
+
* `check-capability-neutrality` holds it to that. These are the coordinator's
|
|
10
|
+
* previous inline defaults, moved verbatim.
|
|
11
|
+
*/
|
|
12
|
+
import type { ToolProvidersConfig } from "./tools-config-normalizer.js";
|
|
13
|
+
export declare const DEFAULT_TOOL_PROVIDERS: ToolProvidersConfig;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provider configs a coordinator applies when the host's tools config
|
|
3
|
+
* names none for a capability.
|
|
4
|
+
*
|
|
5
|
+
* This module names capabilities on purpose, like `services/support-conflicts.ts`:
|
|
6
|
+
* a default is a statement about which capabilities a deployment starts with,
|
|
7
|
+
* which is not a decision the capability-neutral coordination layer gets to
|
|
8
|
+
* make. The coordinator applies the table without naming its entries —
|
|
9
|
+
* `check-capability-neutrality` holds it to that. These are the coordinator's
|
|
10
|
+
* previous inline defaults, moved verbatim.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_TOOL_PROVIDERS = {
|
|
13
|
+
textToSpeech: {
|
|
14
|
+
enabled: true,
|
|
15
|
+
backend: "browser",
|
|
16
|
+
},
|
|
17
|
+
annotationToolbar: {
|
|
18
|
+
enabled: true,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Text-to-speech provider using the browser's Web Speech API.
|
|
5
5
|
* Works in all modern browsers that support SpeechSynthesis.
|
|
6
6
|
*/
|
|
7
|
+
import { languageTagWithoutVariants } from "@pie-players/pie-players-shared/i18n/language-tags";
|
|
7
8
|
import { createPieLogger, isTtsDebugEnabled, } from "@pie-players/pie-players-shared/pie";
|
|
8
9
|
import { extractSpokenText, isSsmlDocument } from "./ssml/spoken-text.js";
|
|
9
10
|
import { segmentSentences as segmentTextToSentences } from "./text-segmentation.js";
|
|
@@ -383,10 +384,11 @@ class BrowserTTSProviderImpl {
|
|
|
383
384
|
* The language of the content being read, which the toolkit sets per speak as
|
|
384
385
|
* `providerOptions.contentLanguage` when the content or the host names one.
|
|
385
386
|
*/
|
|
387
|
+
/** The content language without variant or private-use subtags, which voices lack. */
|
|
386
388
|
getContentLocale() {
|
|
387
389
|
const language = this.config?.providerOptions?.contentLanguage;
|
|
388
390
|
return typeof language === "string" && language.trim()
|
|
389
|
-
? language
|
|
391
|
+
? languageTagWithoutVariants(language)
|
|
390
392
|
: undefined;
|
|
391
393
|
}
|
|
392
394
|
getSegmentationPolicy() {
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The text-to-speech lifecycle of a `ToolkitCoordinator`: initialization from
|
|
3
|
+
* the tool config, readiness, reconfiguration, and the missing-provider report.
|
|
4
|
+
*
|
|
5
|
+
* This module is the one place in the toolkit's coordination layer allowed to
|
|
6
|
+
* name the read-aloud capability, the same way `services/tts/**` already is:
|
|
7
|
+
* the coordinator stays capability-agnostic — it hands this lifecycle the
|
|
8
|
+
* services it needs through `TtsLifecycleHost` and answers only generic
|
|
9
|
+
* questions (`ownsTool`, `isStarted`) about it — and
|
|
10
|
+
* `check-capability-neutrality` holds the coordinator to that, with one
|
|
11
|
+
* documented allowance for its public `textToSpeech`-typed config accessors.
|
|
12
|
+
*
|
|
13
|
+
* Behavior is moved, not redesigned: each method here was a private
|
|
14
|
+
* `ToolkitCoordinator` member, and the host adapters bind the same calls the
|
|
15
|
+
* members made.
|
|
16
|
+
*/
|
|
17
|
+
import type { AccessibilityCatalogResolver } from "../AccessibilityCatalogResolver.js";
|
|
18
|
+
import type { ToolProviderConfig, ToolProvidersConfig } from "../tools-config-normalizer.js";
|
|
19
|
+
import type { TTSService } from "../TTSService.js";
|
|
20
|
+
import type { ToolProviderApi } from "../tool-providers/ToolProviderApi.js";
|
|
21
|
+
import type { ToolRegistration } from "../ToolRegistry.js";
|
|
22
|
+
/** The tool id the read-aloud capability registers under. */
|
|
23
|
+
export declare const TTS_TOOL_ID = "textToSpeech";
|
|
24
|
+
/**
|
|
25
|
+
* The coordinator services the TTS lifecycle runs against. The coordinator
|
|
26
|
+
* binds these once, to its own members, so its privates stay private and the
|
|
27
|
+
* seam between the generic coordinator and the capability stays explicit.
|
|
28
|
+
*/
|
|
29
|
+
export interface TtsLifecycleHost {
|
|
30
|
+
/** Throws `ToolkitCoordinatorDisposedError` once the coordinator is disposed. */
|
|
31
|
+
assertNotDisposed(): void;
|
|
32
|
+
/** Whether disposal has started; in-flight work stops instead of finishing. */
|
|
33
|
+
isDisposalStarted(): boolean;
|
|
34
|
+
/** Whether the error is the coordinator's own disposed signal, to rethrow. */
|
|
35
|
+
isDisposalError(error: unknown): boolean;
|
|
36
|
+
emitTelemetry(eventName: string, payload?: Record<string, unknown>): Promise<void>;
|
|
37
|
+
hooks: {
|
|
38
|
+
onBeforeTTSInit?: ((context: {
|
|
39
|
+
phase: "tts-init";
|
|
40
|
+
details: {
|
|
41
|
+
backend: string;
|
|
42
|
+
};
|
|
43
|
+
}) => void | Promise<void>) | undefined;
|
|
44
|
+
onTTSReady?: (() => void | Promise<void>) | undefined;
|
|
45
|
+
};
|
|
46
|
+
toolProviderRegistry: {
|
|
47
|
+
has(toolId: string): boolean;
|
|
48
|
+
unregister(toolId: string): Promise<void>;
|
|
49
|
+
};
|
|
50
|
+
initializeProvider(toolId: string, fallbackFollows: boolean): Promise<ToolProviderApi>;
|
|
51
|
+
ttsService: TTSService;
|
|
52
|
+
catalogResolver: AccessibilityCatalogResolver;
|
|
53
|
+
clearDegradedTool(toolId: string): void;
|
|
54
|
+
reportStartFailure(error: unknown, context: {
|
|
55
|
+
phase: "tts-init";
|
|
56
|
+
}, toolIds: Iterable<string>): void;
|
|
57
|
+
isToolGranted(toolId: string): boolean;
|
|
58
|
+
/** Whether provider initialization waits for a policy grant. */
|
|
59
|
+
lazyInit: boolean;
|
|
60
|
+
/** Whether the tool registry may still be replaced by a bound toolkit's. */
|
|
61
|
+
isToolRegistryPending(): boolean;
|
|
62
|
+
/** The validated `tools.providers` config, defaults applied. */
|
|
63
|
+
providersConfig(): ToolProvidersConfig | undefined;
|
|
64
|
+
getProviderDescriptorTools(): ToolRegistration[];
|
|
65
|
+
registerProviderFromTool(tool: ToolRegistration, replace?: boolean): Promise<void>;
|
|
66
|
+
notifyReadyChange(): void;
|
|
67
|
+
}
|
|
68
|
+
/** The read-aloud-specific merge in a generic tool-config update. */
|
|
69
|
+
export declare function deepMergeMathSpeech(toolId: string, current: Partial<ToolProviderConfig>, updates: Partial<ToolProviderConfig>): Record<string, unknown> | undefined;
|
|
70
|
+
export declare class TtsLifecycle {
|
|
71
|
+
private readonly host;
|
|
72
|
+
private initialized;
|
|
73
|
+
/** Text-to-speech failed to start and policy does not grant it. */
|
|
74
|
+
private degraded;
|
|
75
|
+
private initPromise?;
|
|
76
|
+
private reconfigurePromise?;
|
|
77
|
+
/**
|
|
78
|
+
* Whether {@link TtsLifecycle.initializeIfNeeded} has already reported a
|
|
79
|
+
* non-browser backend falling back to browser speech because no
|
|
80
|
+
* text-to-speech provider is registered. Once per coordinator: a
|
|
81
|
+
* text-to-speech config change re-runs initialization, and the missing
|
|
82
|
+
* provider is the same gap each time.
|
|
83
|
+
*/
|
|
84
|
+
private reportedMissingProvider;
|
|
85
|
+
/**
|
|
86
|
+
* The backend of a fallback missing-provider report held back while the
|
|
87
|
+
* registry was unsettled, reported if the bound toolkit has no registry.
|
|
88
|
+
*/
|
|
89
|
+
private heldMissingProviderBackend;
|
|
90
|
+
constructor(host: TtsLifecycleHost);
|
|
91
|
+
get started(): boolean;
|
|
92
|
+
get failedUngranted(): boolean;
|
|
93
|
+
/** Whether `toolId` is the tool this lifecycle brings up. */
|
|
94
|
+
ownsTool(toolId: string): boolean;
|
|
95
|
+
/** Whether initialization or a reconfiguration is in flight. */
|
|
96
|
+
isStarted(): boolean;
|
|
97
|
+
/** The in-flight initialization and reconfiguration, for disposal flushes. */
|
|
98
|
+
flushInitPromises(pending: Set<Promise<unknown>>): void;
|
|
99
|
+
/**
|
|
100
|
+
* The runtime `mathSpeech` provider options for the current tool config, as
|
|
101
|
+
* the TTS service's math-speech source reads them.
|
|
102
|
+
*/
|
|
103
|
+
mathSpeechRuntimeOptions(): import("./math-speech.js").SREMathSpeechOptions | undefined;
|
|
104
|
+
/**
|
|
105
|
+
* Initialize the TTS service from the `textToSpeech` tool config.
|
|
106
|
+
*/
|
|
107
|
+
ensureReady(): Promise<void>;
|
|
108
|
+
private waitForPendingReconfigure;
|
|
109
|
+
private initializeIfNeeded;
|
|
110
|
+
private resolveToolConfig;
|
|
111
|
+
private initializeService;
|
|
112
|
+
private reportMissingProvider;
|
|
113
|
+
/**
|
|
114
|
+
* Report a missing-provider report held back while the registry was
|
|
115
|
+
* unsettled, now that the registry has settled without one.
|
|
116
|
+
*/
|
|
117
|
+
reportHeldMissingProvider(): void;
|
|
118
|
+
/**
|
|
119
|
+
* Drop a held missing-provider report without reporting it: a real registry
|
|
120
|
+
* settled, so the stale gap never applied.
|
|
121
|
+
*/
|
|
122
|
+
discardHeldMissingProvider(): void;
|
|
123
|
+
/**
|
|
124
|
+
* Readiness waits for text-to-speech when it is enabled and either starts
|
|
125
|
+
* eagerly or is granted: a granted read-aloud fails before the learner starts.
|
|
126
|
+
*/
|
|
127
|
+
requiredForReadiness(): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Starts text-to-speech for readiness. A failure policy does not grant leaves
|
|
130
|
+
* the tool degraded, reporting itself unavailable, and readiness settles; a
|
|
131
|
+
* granted tool's failure rejects.
|
|
132
|
+
*/
|
|
133
|
+
startForReadiness(): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Re-register the text-to-speech provider for the current config and registry,
|
|
136
|
+
* then re-initialize unless initialization is lazy. An initialization already
|
|
137
|
+
* running finishes first: it would otherwise mark its provider ready after the
|
|
138
|
+
* reset.
|
|
139
|
+
*/
|
|
140
|
+
scheduleReconfigure(): void;
|
|
141
|
+
private reconfigure;
|
|
142
|
+
}
|