@pie-players/pie-assessment-toolkit 0.3.75 → 1.0.0-beta.1
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 +451 -541
- package/custom-elements.json +1315 -0
- package/dist/attempt/TestSession.d.ts +0 -1
- package/dist/attempt/TestSession.js +10 -5
- 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 +8 -8
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/{ItemToolBar-7tt7v2xp.js → ItemToolBar-3zrc4p3d.js} +4 -4
- package/dist/components/chunks/{ItemToolBar-jx38w99s.js → ItemToolBar-66hcwmfw.js} +2 -2
- package/dist/components/chunks/ItemToolBar-asenkvx6.js +40 -0
- package/dist/components/chunks/ItemToolBar-hzc5wyjp.js +2 -0
- package/dist/components/chunks/{ItemToolBar-97hx60z4.js → ItemToolBar-kkj69ptr.js} +1 -1
- package/dist/components/chunks/sre-engine-bj997w4b.js +1 -0
- package/dist/context/assessment-toolkit-context.d.ts +6 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +4 -10
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +46 -7
- package/dist/policy/core/ToolPolicyEngine.js +73 -16
- package/dist/policy/core/compose-decision.d.ts +3 -3
- package/dist/policy/core/compose-decision.js +32 -30
- package/dist/policy/core/decision-types.d.ts +51 -34
- package/dist/policy/core/feature-decision.d.ts +17 -15
- package/dist/policy/core/feature-decision.js +11 -13
- package/dist/policy/core/pnp-policy-inputs.d.ts +7 -3
- package/dist/policy/core/pnp-policy-inputs.js +17 -33
- package/dist/policy/core/provenance.d.ts +2 -2
- package/dist/policy/core/tool-parameters.d.ts +12 -0
- package/dist/policy/core/tool-parameters.js +27 -0
- package/dist/policy/engine.d.ts +1 -1
- package/dist/policy/sources/PnpPolicySource.d.ts +18 -24
- package/dist/policy/sources/PnpPolicySource.js +57 -29
- package/dist/runtime/SectionControllerBinding.d.ts +6 -2
- package/dist/runtime/SectionControllerBinding.js +21 -15
- package/dist/runtime/adapter/subscriber-fanout.d.ts +0 -1
- package/dist/runtime/adapter/subscriber-fanout.js +1 -4
- package/dist/runtime/composition-emit-scheduler.d.ts +3 -3
- package/dist/runtime/composition-emit-scheduler.js +1 -1
- package/dist/runtime/content-region.d.ts +0 -4
- package/dist/runtime/content-region.js +2 -2
- package/dist/runtime/core/SectionEngineCore.d.ts +0 -2
- package/dist/runtime/core/SectionEngineCore.js +0 -4
- package/dist/runtime/core/cohort.d.ts +0 -5
- package/dist/runtime/core/cohort.js +0 -9
- package/dist/runtime/core/engine-output.d.ts +3 -2
- package/dist/runtime/core/engine-transition.js +3 -2
- package/dist/runtime/registration-events.d.ts +11 -14
- package/dist/runtime/runtime-id.d.ts +1 -1
- package/dist/runtime/runtime-id.js +1 -1
- package/dist/runtime/shell-scope.d.ts +4 -4
- package/dist/runtime/shell-scope.js +15 -9
- package/dist/runtime/tool-host-contract.d.ts +0 -4
- package/dist/runtime/tool-host-contract.js +1 -1
- package/dist/services/AccessibilityCatalogResolver.d.ts +21 -31
- package/dist/services/AccessibilityCatalogResolver.js +29 -42
- package/dist/services/ElementToolStateStore.d.ts +32 -61
- package/dist/services/ElementToolStateStore.js +37 -67
- package/dist/services/HighlightCoordinator.d.ts +9 -21
- package/dist/services/HighlightCoordinator.js +52 -80
- package/dist/services/RangeSerializer.d.ts +4 -35
- package/dist/services/RangeSerializer.js +4 -48
- package/dist/services/SSMLExtractor.d.ts +8 -31
- package/dist/services/SSMLExtractor.js +18 -40
- package/dist/services/TTSService.d.ts +51 -57
- package/dist/services/TTSService.js +323 -284
- package/dist/services/ToolCoordinator.d.ts +6 -49
- package/dist/services/ToolCoordinator.js +25 -61
- package/dist/services/ToolRegistry.d.ts +83 -80
- package/dist/services/ToolRegistry.js +91 -67
- package/dist/services/ToolkitCoordinator.d.ts +83 -81
- package/dist/services/ToolkitCoordinator.js +186 -174
- package/dist/services/framework-error.d.ts +30 -7
- package/dist/services/framework-error.js +10 -13
- package/dist/services/interfaces.d.ts +51 -71
- package/dist/services/section-controller-types.d.ts +7 -7
- package/dist/services/section-session-assignment.js +6 -8
- package/dist/services/spoken-audio-cards.d.ts +2 -4
- package/dist/services/spoken-audio-cards.js +2 -4
- package/dist/services/tool-config-validation.d.ts +5 -7
- package/dist/services/tool-config-validation.js +11 -26
- package/dist/services/tool-context.d.ts +39 -24
- package/dist/services/tool-context.js +158 -92
- package/dist/services/tool-failure.d.ts +30 -0
- package/dist/services/tool-failure.js +11 -0
- package/dist/services/tool-icons.d.ts +1 -2
- package/dist/services/tool-icons.js +2 -2
- package/dist/services/tool-instance-id.d.ts +8 -6
- package/dist/services/tool-instance-id.js +12 -18
- package/dist/services/tool-providers/TTSToolProvider.d.ts +6 -43
- package/dist/services/tool-providers/TTSToolProvider.js +7 -63
- package/dist/services/tool-providers/ToolProviderApi.d.ts +0 -7
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +7 -42
- package/dist/services/tool-providers/ToolProviderRegistry.js +21 -63
- package/dist/services/tool-request.d.ts +4 -0
- package/dist/services/tool-request.js +7 -2
- package/dist/services/toolbar-decided-tools.d.ts +2 -0
- package/dist/services/toolbar-decided-tools.js +2 -0
- package/dist/services/toolbar-items.js +2 -5
- package/dist/services/tools-config-normalizer.d.ts +18 -9
- package/dist/services/tools-config-normalizer.js +25 -19
- package/dist/services/tts/browser-provider.d.ts +2 -5
- package/dist/services/tts/browser-provider.js +13 -22
- package/dist/services/tts/catalog-span-alignment.js +14 -7
- package/dist/services/tts/flat-tree.d.ts +0 -7
- package/dist/services/tts/flat-tree.js +2 -2
- package/dist/services/tts/generated-speech/dom/to-chunk-inputs.d.ts +2 -2
- package/dist/services/tts/generated-speech/index.d.ts +1 -1
- package/dist/services/tts/generated-speech/index.js +1 -1
- package/dist/services/tts/generated-speech/types.d.ts +1 -1
- package/dist/services/tts/generated-speech/types.js +1 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +10 -12
- package/dist/services/tts/highlight-target-resolver.d.ts +12 -0
- package/dist/services/tts/math-aware-text-processing.js +10 -29
- package/dist/services/tts/math-speech.d.ts +1 -1
- package/dist/services/tts/math-speech.js +3 -0
- package/dist/services/tts/mathml-sanitization.d.ts +7 -0
- package/dist/services/tts/mathml-sanitization.js +9 -1
- package/dist/services/tts/provider-options.d.ts +12 -1
- package/dist/services/tts/ssml/spoken-text.js +1 -1
- package/dist/services/tts/start-failure.d.ts +0 -7
- package/dist/services/tts/start-failure.js +1 -1
- package/dist/services/tts/text-segmentation.d.ts +5 -0
- package/dist/services/tts/text-segmentation.js +13 -10
- package/dist/services/tts-runtime-config.d.ts +32 -12
- package/dist/services/tts-runtime-config.js +14 -20
- package/dist/tools/content-capability-resolution.d.ts +2 -2
- package/dist/tools/registration.d.ts +7 -6
- package/dist/tools/registration.js +10 -9
- package/dist/tools/registrations/toolbar-registration-helpers.d.ts +6 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +6 -0
- package/dist/tools/tool-surface-host.js +1 -8
- package/package.json +8 -6
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +0 -2
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +0 -40
- package/dist/components/chunks/sre-engine-jd8cc08x.js +0 -1
- package/dist/services/ContextVariableStore.d.ts +0 -113
- package/dist/services/ContextVariableStore.js +0 -206
- package/dist/services/tts-control-events.d.ts +0 -13
- package/dist/services/tts-control-events.js +0 -7
- package/dist/utils/logger.d.ts +0 -6
- package/dist/utils/logger.js +0 -10
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
* `polly` and `google` run on the `pie` transport; `custom` runs on the
|
|
8
8
|
* `custom` transport to a host's own service, which takes `lang_id`,
|
|
9
9
|
* `speedRate` and `cache`
|
|
10
|
-
*
|
|
11
|
-
* Part of PIE Assessment Toolkit.
|
|
12
10
|
*/
|
|
13
11
|
import { createPieLogger, isTtsDebugEnabled, } from "@pie-players/pie-players-shared/pie";
|
|
14
12
|
import { BrowserTTSProvider } from "../../services/tts/browser-provider.js";
|
|
@@ -23,8 +21,6 @@ const logger = createPieLogger("tts-tool-provider", isTtsDebugEnabled);
|
|
|
23
21
|
function bindServerBackendConfig(provider, bound) {
|
|
24
22
|
return {
|
|
25
23
|
providerId: provider.providerId,
|
|
26
|
-
providerName: provider.providerName,
|
|
27
|
-
version: provider.version,
|
|
28
24
|
initialize: (config) => {
|
|
29
25
|
const runtime = config;
|
|
30
26
|
const merged = {
|
|
@@ -84,24 +80,15 @@ export class TTSToolProvider {
|
|
|
84
80
|
console.warn("[TTSToolProvider] telemetry callback failed:", error);
|
|
85
81
|
}
|
|
86
82
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Create TTS tool provider
|
|
89
|
-
*
|
|
90
|
-
* @param backend TTS backend to use (default: 'browser')
|
|
91
|
-
* @param options Loader for the server adapter, required by server backends
|
|
92
|
-
*/
|
|
83
|
+
/** A server backend needs `options.loadServerProvider`. */
|
|
93
84
|
constructor(backend = "browser", options = {}) {
|
|
94
85
|
this.backend = backend;
|
|
95
86
|
this.requiresAuth = backend !== "browser";
|
|
96
87
|
this.loadServerProvider = options.loadServerProvider;
|
|
97
88
|
}
|
|
98
89
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* Sets up the appropriate TTS backend.
|
|
102
|
-
*
|
|
103
|
-
* @param config Runtime configuration and credentials
|
|
104
|
-
* @throws Error if initialization fails or required config missing
|
|
90
|
+
* Set up the backend's TTS provider. Throws when the backend is unavailable
|
|
91
|
+
* or its required config is missing. Once initialized, a call only warns.
|
|
105
92
|
*/
|
|
106
93
|
async initialize(config) {
|
|
107
94
|
if (this.ttsProvider) {
|
|
@@ -111,7 +98,7 @@ export class TTSToolProvider {
|
|
|
111
98
|
this.config = config;
|
|
112
99
|
switch (this.backend) {
|
|
113
100
|
case "browser":
|
|
114
|
-
await this._initializeBrowserTTS(
|
|
101
|
+
await this._initializeBrowserTTS();
|
|
115
102
|
break;
|
|
116
103
|
case "server":
|
|
117
104
|
await this._initializeServerTTS(config);
|
|
@@ -121,20 +108,13 @@ export class TTSToolProvider {
|
|
|
121
108
|
}
|
|
122
109
|
logger.debug(`initialized (backend: ${this.backend})`);
|
|
123
110
|
}
|
|
124
|
-
|
|
125
|
-
* Initialize browser TTS (Web Speech API)
|
|
126
|
-
*/
|
|
127
|
-
async _initializeBrowserTTS(config) {
|
|
128
|
-
// Check if Web Speech API is available
|
|
111
|
+
async _initializeBrowserTTS() {
|
|
129
112
|
if (typeof window === "undefined" || !("speechSynthesis" in window)) {
|
|
130
113
|
throw new Error("[TTSToolProvider] Browser TTS not supported (Web Speech API not available)");
|
|
131
114
|
}
|
|
132
115
|
this.ttsProvider = new BrowserTTSProvider();
|
|
133
116
|
logger.debug("browser TTS initialized (Web Speech API)");
|
|
134
117
|
}
|
|
135
|
-
/**
|
|
136
|
-
* Initialize server-based TTS
|
|
137
|
-
*/
|
|
138
118
|
async _initializeServerTTS(config) {
|
|
139
119
|
if (!config.apiEndpoint) {
|
|
140
120
|
throw new Error("[TTSToolProvider] apiEndpoint required for server-based TTS backends");
|
|
@@ -178,13 +158,8 @@ export class TTSToolProvider {
|
|
|
178
158
|
logger.debug(`server TTS initialized (provider: ${serverProvider})`);
|
|
179
159
|
}
|
|
180
160
|
/**
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* Returns the initialized TTS provider.
|
|
184
|
-
*
|
|
185
|
-
* @param config Optional instance-specific configuration (currently unused)
|
|
186
|
-
* @returns TTS provider
|
|
187
|
-
* @throws Error if provider not initialized
|
|
161
|
+
* The initialized TTS provider; every call returns the same one and ignores
|
|
162
|
+
* `config`. Throws before `initialize`.
|
|
188
163
|
*/
|
|
189
164
|
async createInstance(config) {
|
|
190
165
|
if (!this.ttsProvider) {
|
|
@@ -192,40 +167,9 @@ export class TTSToolProvider {
|
|
|
192
167
|
}
|
|
193
168
|
return this.ttsProvider;
|
|
194
169
|
}
|
|
195
|
-
/**
|
|
196
|
-
* The backend's capabilities. Its features are the speech provider's own,
|
|
197
|
-
* and all false before {@link initialize} creates it.
|
|
198
|
-
*/
|
|
199
|
-
getCapabilities() {
|
|
200
|
-
const isBrowser = this.backend === "browser";
|
|
201
|
-
const speech = this.ttsProvider?.getCapabilities();
|
|
202
|
-
return {
|
|
203
|
-
supportsOffline: isBrowser,
|
|
204
|
-
requiresAuth: !isBrowser,
|
|
205
|
-
maxInstances: 1, // Single TTS instance (playback is sequential)
|
|
206
|
-
features: {
|
|
207
|
-
wordBoundary: speech?.supportsWordBoundary ?? false,
|
|
208
|
-
pause: speech?.supportsPause ?? false,
|
|
209
|
-
resume: speech?.supportsResume ?? false,
|
|
210
|
-
rateControl: speech?.supportsRateControl ?? false,
|
|
211
|
-
pitchControl: speech?.supportsPitchControl ?? false,
|
|
212
|
-
voiceSelection: speech?.supportsVoiceSelection ?? false,
|
|
213
|
-
},
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Check if provider is ready
|
|
218
|
-
*
|
|
219
|
-
* @returns true if provider is initialized
|
|
220
|
-
*/
|
|
221
170
|
isReady() {
|
|
222
171
|
return this.ttsProvider !== null;
|
|
223
172
|
}
|
|
224
|
-
/**
|
|
225
|
-
* Clean up provider resources
|
|
226
|
-
*
|
|
227
|
-
* Destroys the TTS provider and releases resources.
|
|
228
|
-
*/
|
|
229
173
|
destroy() {
|
|
230
174
|
if (this.ttsProvider) {
|
|
231
175
|
this.ttsProvider.destroy();
|
|
@@ -5,12 +5,6 @@
|
|
|
5
5
|
* configuration, authentication, or external services.
|
|
6
6
|
*/
|
|
7
7
|
export type ToolCategory = "calculator" | "tts" | "translation" | "annotation" | "accessibility" | "other";
|
|
8
|
-
export interface ToolProviderCapabilities {
|
|
9
|
-
supportsOffline: boolean;
|
|
10
|
-
requiresAuth: boolean;
|
|
11
|
-
maxInstances?: number | null;
|
|
12
|
-
features: Record<string, boolean>;
|
|
13
|
-
}
|
|
14
8
|
/**
|
|
15
9
|
* A tool's provider. It registers under its tool's id, which is how the toolkit
|
|
16
10
|
* and the tool find it; it carries no id of its own.
|
|
@@ -25,7 +19,6 @@ export interface ToolProviderApi<TInstance = any> {
|
|
|
25
19
|
readonly requiresAuth: boolean;
|
|
26
20
|
initialize(config: unknown): Promise<void>;
|
|
27
21
|
createInstance(config?: unknown): Promise<TInstance>;
|
|
28
|
-
getCapabilities(): ToolProviderCapabilities;
|
|
29
22
|
isReady(): boolean;
|
|
30
23
|
destroy(): void;
|
|
31
24
|
}
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Centralized registry for managing tool providers.
|
|
5
5
|
* Handles initialization, authentication, and lazy loading.
|
|
6
|
-
*
|
|
7
|
-
* Part of PIE Assessment Toolkit.
|
|
8
6
|
*/
|
|
9
7
|
import type { ToolProviderApi, ToolCategory } from "./ToolProviderApi.js";
|
|
10
8
|
/**
|
|
@@ -36,7 +34,7 @@ export interface ToolProviderRegistration<TConfig = any> {
|
|
|
36
34
|
* @example
|
|
37
35
|
* ```typescript
|
|
38
36
|
* authFetcher: async () => {
|
|
39
|
-
* const response = await fetch('/api/desmos/
|
|
37
|
+
* const response = await fetch('/api/tools/desmos/auth');
|
|
40
38
|
* return response.json(); // { apiKey: '...' }
|
|
41
39
|
* }
|
|
42
40
|
* ```
|
|
@@ -90,9 +88,6 @@ export declare class ToolProviderRegistry {
|
|
|
90
88
|
* A registration under an id already registered replaces it: the replaced
|
|
91
89
|
* provider is destroyed once a start in progress settles, and a caller
|
|
92
90
|
* waiting on that start gets the replacement.
|
|
93
|
-
*
|
|
94
|
-
* @param toolId Id of the tool the provider serves
|
|
95
|
-
* @param config Provider configuration
|
|
96
91
|
*/
|
|
97
92
|
register(toolId: string, config: ToolProviderRegistration): void;
|
|
98
93
|
/**
|
|
@@ -100,10 +95,7 @@ export declare class ToolProviderRegistry {
|
|
|
100
95
|
*
|
|
101
96
|
* Fetches auth if needed and initializes the provider.
|
|
102
97
|
* Safe to call multiple times - subsequent calls wait for first initialization.
|
|
103
|
-
*
|
|
104
|
-
* @param toolId Tool whose provider to initialize
|
|
105
|
-
* @returns Promise that resolves when initialization complete
|
|
106
|
-
* @throws Error if provider not registered or initialization fails
|
|
98
|
+
* Throws when the provider is not registered or its initialization fails.
|
|
107
99
|
*/
|
|
108
100
|
initialize(toolId: string): Promise<void>;
|
|
109
101
|
/** Whether a registration replaced `provider` under `toolId`. */
|
|
@@ -117,51 +109,24 @@ export declare class ToolProviderRegistry {
|
|
|
117
109
|
* Get a provider instance
|
|
118
110
|
*
|
|
119
111
|
* Retrieves a registered provider. If autoInitialize is true and provider
|
|
120
|
-
* is not initialized, initializes it first.
|
|
121
|
-
*
|
|
122
|
-
* @param toolId Id of the tool the provider serves
|
|
123
|
-
* @param autoInitialize Auto-initialize if not ready (default: true)
|
|
124
|
-
* @returns Provider instance
|
|
125
|
-
* @throws Error if provider not registered
|
|
112
|
+
* is not initialized, initializes it first. Throws when the provider is not
|
|
113
|
+
* registered.
|
|
126
114
|
*/
|
|
127
115
|
getProvider<T extends ToolProviderApi = ToolProviderApi>(toolId: string, autoInitialize?: boolean): Promise<T>;
|
|
128
|
-
/**
|
|
129
|
-
* The ids of the tools whose provider is in `category`.
|
|
130
|
-
*
|
|
131
|
-
* @param category Tool category to filter by
|
|
132
|
-
*/
|
|
116
|
+
/** The ids of the tools whose provider is in `category`. */
|
|
133
117
|
getProvidersByCategory(category: ToolCategory): string[];
|
|
134
118
|
/**
|
|
135
119
|
* The ids of the tools with a registered provider.
|
|
136
120
|
*/
|
|
137
121
|
getProviderIds(): string[];
|
|
138
|
-
/**
|
|
139
|
-
* Check if provider is registered
|
|
140
|
-
*
|
|
141
|
-
* @param toolId Id of the tool the provider serves
|
|
142
|
-
* @returns true if provider is registered
|
|
143
|
-
*/
|
|
144
122
|
has(toolId: string): boolean;
|
|
145
|
-
/**
|
|
146
|
-
* Check if provider is initialized
|
|
147
|
-
*
|
|
148
|
-
* @param toolId Id of the tool the provider serves
|
|
149
|
-
* @returns true if provider is initialized
|
|
150
|
-
*/
|
|
151
123
|
isInitialized(toolId: string): boolean;
|
|
152
|
-
/**
|
|
153
|
-
* Check if provider is currently initializing
|
|
154
|
-
*
|
|
155
|
-
* @param toolId Id of the tool the provider serves
|
|
156
|
-
* @returns true if initialization in progress
|
|
157
|
-
*/
|
|
158
124
|
isInitializing(toolId: string): boolean;
|
|
159
125
|
/**
|
|
160
126
|
* Unregister and destroy a provider
|
|
161
127
|
*
|
|
162
|
-
* Removes the provider from the registry and calls its destroy method
|
|
163
|
-
*
|
|
164
|
-
* @param toolId Tool whose provider to unregister
|
|
128
|
+
* Removes the provider from the registry and calls its destroy method,
|
|
129
|
+
* after any start in progress settles.
|
|
165
130
|
*/
|
|
166
131
|
unregister(toolId: string): Promise<void>;
|
|
167
132
|
/**
|
|
@@ -3,12 +3,17 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Centralized registry for managing tool providers.
|
|
5
5
|
* Handles initialization, authentication, and lazy loading.
|
|
6
|
-
*
|
|
7
|
-
* Part of PIE Assessment Toolkit.
|
|
8
6
|
*/
|
|
9
7
|
import { createPieLogger, isGlobalDebugEnabled, } from "@pie-players/pie-players-shared/pie";
|
|
10
8
|
// Lifecycle lines need `window.PIE_DEBUG = true`, read on each line.
|
|
11
9
|
const logger = createPieLogger("ToolProviderRegistry", isGlobalDebugEnabled);
|
|
10
|
+
/** The `backend` a provider config names, for telemetry payloads. */
|
|
11
|
+
function telemetryBackend(value) {
|
|
12
|
+
const backend = value && typeof value === "object"
|
|
13
|
+
? value.backend
|
|
14
|
+
: undefined;
|
|
15
|
+
return typeof backend === "string" && backend ? backend : "unknown";
|
|
16
|
+
}
|
|
12
17
|
/**
|
|
13
18
|
* Tool Provider Registry
|
|
14
19
|
*
|
|
@@ -59,9 +64,6 @@ export class ToolProviderRegistry {
|
|
|
59
64
|
* A registration under an id already registered replaces it: the replaced
|
|
60
65
|
* provider is destroyed once a start in progress settles, and a caller
|
|
61
66
|
* waiting on that start gets the replacement.
|
|
62
|
-
*
|
|
63
|
-
* @param toolId Id of the tool the provider serves
|
|
64
|
-
* @param config Provider configuration
|
|
65
67
|
*/
|
|
66
68
|
register(toolId, config) {
|
|
67
69
|
const replaced = this.providers.get(toolId);
|
|
@@ -81,7 +83,6 @@ export class ToolProviderRegistry {
|
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
logger.debug(`${replaced ? "Replaced" : "Registered"} provider "${toolId}" (${config.provider.providerName})`);
|
|
84
|
-
// Initialize immediately if not lazy
|
|
85
86
|
if (config.lazy === false) {
|
|
86
87
|
this.initialize(toolId).catch((error) => {
|
|
87
88
|
console.error(`[ToolProviderRegistry] Failed to initialize provider "${toolId}":`, error);
|
|
@@ -93,22 +94,16 @@ export class ToolProviderRegistry {
|
|
|
93
94
|
*
|
|
94
95
|
* Fetches auth if needed and initializes the provider.
|
|
95
96
|
* Safe to call multiple times - subsequent calls wait for first initialization.
|
|
96
|
-
*
|
|
97
|
-
* @param toolId Tool whose provider to initialize
|
|
98
|
-
* @returns Promise that resolves when initialization complete
|
|
99
|
-
* @throws Error if provider not registered or initialization fails
|
|
97
|
+
* Throws when the provider is not registered or its initialization fails.
|
|
100
98
|
*/
|
|
101
99
|
async initialize(toolId) {
|
|
102
|
-
// Already initialized
|
|
103
100
|
if (this.initialized.get(toolId)) {
|
|
104
101
|
return;
|
|
105
102
|
}
|
|
106
|
-
// Initialization in progress - wait for it
|
|
107
103
|
const existingPromise = this.initializationPromises.get(toolId);
|
|
108
104
|
if (existingPromise) {
|
|
109
105
|
return existingPromise;
|
|
110
106
|
}
|
|
111
|
-
// Start new initialization
|
|
112
107
|
const provider = this.providers.get(toolId);
|
|
113
108
|
const initPromise = this._doInitialize(toolId);
|
|
114
109
|
this.initializationPromises.set(toolId, initPromise);
|
|
@@ -116,6 +111,8 @@ export class ToolProviderRegistry {
|
|
|
116
111
|
await initPromise;
|
|
117
112
|
}
|
|
118
113
|
catch (error) {
|
|
114
|
+
// When a registration replaced the provider mid-start, this caller
|
|
115
|
+
// gets the replacement, so the old start's failure is dropped.
|
|
119
116
|
if (!this.isReplaced(toolId, provider))
|
|
120
117
|
throw error;
|
|
121
118
|
}
|
|
@@ -150,26 +147,18 @@ export class ToolProviderRegistry {
|
|
|
150
147
|
if (!provider || !config) {
|
|
151
148
|
throw new Error(`[ToolProviderRegistry] Provider "${toolId}" not registered`);
|
|
152
149
|
}
|
|
153
|
-
// Start with base config
|
|
154
150
|
let providerConfig = { ...config.config };
|
|
155
|
-
const deriveBackend = (value) => {
|
|
156
|
-
const backend = value && typeof value === "object"
|
|
157
|
-
? value.backend
|
|
158
|
-
: undefined;
|
|
159
|
-
return typeof backend === "string" && backend ? backend : "unknown";
|
|
160
|
-
};
|
|
161
151
|
const providerInitStartedAt = Date.now();
|
|
162
152
|
await this.emitTelemetry(config, "pie-tool-init-start", {
|
|
163
153
|
toolId,
|
|
164
|
-
backend:
|
|
154
|
+
backend: telemetryBackend(providerConfig),
|
|
165
155
|
operation: "provider-initialize",
|
|
166
156
|
});
|
|
167
|
-
// Fetch auth if needed
|
|
168
157
|
if (provider.requiresAuth && config.authFetcher) {
|
|
169
158
|
const authFetchStartedAt = Date.now();
|
|
170
159
|
await this.emitTelemetry(config, "pie-tool-backend-call-start", {
|
|
171
160
|
toolId,
|
|
172
|
-
backend:
|
|
161
|
+
backend: telemetryBackend(providerConfig),
|
|
173
162
|
operation: "auth-fetch",
|
|
174
163
|
});
|
|
175
164
|
logger.debug(`Fetching auth for "${toolId}"...`);
|
|
@@ -178,7 +167,7 @@ export class ToolProviderRegistry {
|
|
|
178
167
|
providerConfig = { ...providerConfig, ...authData };
|
|
179
168
|
await this.emitTelemetry(config, "pie-tool-backend-call-success", {
|
|
180
169
|
toolId,
|
|
181
|
-
backend:
|
|
170
|
+
backend: telemetryBackend(providerConfig),
|
|
182
171
|
operation: "auth-fetch",
|
|
183
172
|
duration: Date.now() - authFetchStartedAt,
|
|
184
173
|
});
|
|
@@ -186,7 +175,7 @@ export class ToolProviderRegistry {
|
|
|
186
175
|
catch (error) {
|
|
187
176
|
await this.emitTelemetry(config, "pie-tool-backend-call-error", {
|
|
188
177
|
toolId,
|
|
189
|
-
backend:
|
|
178
|
+
backend: telemetryBackend(providerConfig),
|
|
190
179
|
operation: "auth-fetch",
|
|
191
180
|
duration: Date.now() - authFetchStartedAt,
|
|
192
181
|
errorType: "ProviderAuthFetchError",
|
|
@@ -196,7 +185,6 @@ export class ToolProviderRegistry {
|
|
|
196
185
|
throw new Error(`Failed to fetch auth credentials for provider "${toolId}"`);
|
|
197
186
|
}
|
|
198
187
|
}
|
|
199
|
-
// Initialize provider
|
|
200
188
|
try {
|
|
201
189
|
await provider.initialize(providerConfig);
|
|
202
190
|
if (this.providers.get(toolId) === provider) {
|
|
@@ -204,7 +192,7 @@ export class ToolProviderRegistry {
|
|
|
204
192
|
}
|
|
205
193
|
await this.emitTelemetry(config, "pie-tool-init-success", {
|
|
206
194
|
toolId,
|
|
207
|
-
backend:
|
|
195
|
+
backend: telemetryBackend(providerConfig),
|
|
208
196
|
operation: "provider-initialize",
|
|
209
197
|
duration: Date.now() - providerInitStartedAt,
|
|
210
198
|
});
|
|
@@ -213,7 +201,7 @@ export class ToolProviderRegistry {
|
|
|
213
201
|
catch (error) {
|
|
214
202
|
await this.emitTelemetry(config, "pie-tool-init-error", {
|
|
215
203
|
toolId,
|
|
216
|
-
backend:
|
|
204
|
+
backend: telemetryBackend(providerConfig),
|
|
217
205
|
operation: "provider-initialize",
|
|
218
206
|
duration: Date.now() - providerInitStartedAt,
|
|
219
207
|
errorType: "ProviderInitializationError",
|
|
@@ -227,12 +215,8 @@ export class ToolProviderRegistry {
|
|
|
227
215
|
* Get a provider instance
|
|
228
216
|
*
|
|
229
217
|
* Retrieves a registered provider. If autoInitialize is true and provider
|
|
230
|
-
* is not initialized, initializes it first.
|
|
231
|
-
*
|
|
232
|
-
* @param toolId Id of the tool the provider serves
|
|
233
|
-
* @param autoInitialize Auto-initialize if not ready (default: true)
|
|
234
|
-
* @returns Provider instance
|
|
235
|
-
* @throws Error if provider not registered
|
|
218
|
+
* is not initialized, initializes it first. Throws when the provider is not
|
|
219
|
+
* registered.
|
|
236
220
|
*/
|
|
237
221
|
async getProvider(toolId, autoInitialize = true) {
|
|
238
222
|
const provider = this.providers.get(toolId);
|
|
@@ -243,18 +227,13 @@ export class ToolProviderRegistry {
|
|
|
243
227
|
});
|
|
244
228
|
throw new Error(`[ToolProviderRegistry] Provider "${toolId}" not registered`);
|
|
245
229
|
}
|
|
246
|
-
// Auto-initialize if needed
|
|
247
230
|
if (autoInitialize && !this.initialized.get(toolId)) {
|
|
248
231
|
logger.debug("Auto-initializing provider:", toolId);
|
|
249
232
|
await this.initialize(toolId);
|
|
250
233
|
}
|
|
251
234
|
return provider;
|
|
252
235
|
}
|
|
253
|
-
/**
|
|
254
|
-
* The ids of the tools whose provider is in `category`.
|
|
255
|
-
*
|
|
256
|
-
* @param category Tool category to filter by
|
|
257
|
-
*/
|
|
236
|
+
/** The ids of the tools whose provider is in `category`. */
|
|
258
237
|
getProvidersByCategory(category) {
|
|
259
238
|
return Array.from(this.providers.entries())
|
|
260
239
|
.filter(([_, provider]) => provider.category === category)
|
|
@@ -266,44 +245,24 @@ export class ToolProviderRegistry {
|
|
|
266
245
|
getProviderIds() {
|
|
267
246
|
return Array.from(this.providers.keys());
|
|
268
247
|
}
|
|
269
|
-
/**
|
|
270
|
-
* Check if provider is registered
|
|
271
|
-
*
|
|
272
|
-
* @param toolId Id of the tool the provider serves
|
|
273
|
-
* @returns true if provider is registered
|
|
274
|
-
*/
|
|
275
248
|
has(toolId) {
|
|
276
249
|
return this.providers.has(toolId);
|
|
277
250
|
}
|
|
278
|
-
/**
|
|
279
|
-
* Check if provider is initialized
|
|
280
|
-
*
|
|
281
|
-
* @param toolId Id of the tool the provider serves
|
|
282
|
-
* @returns true if provider is initialized
|
|
283
|
-
*/
|
|
284
251
|
isInitialized(toolId) {
|
|
285
252
|
return this.initialized.get(toolId) === true;
|
|
286
253
|
}
|
|
287
|
-
/**
|
|
288
|
-
* Check if provider is currently initializing
|
|
289
|
-
*
|
|
290
|
-
* @param toolId Id of the tool the provider serves
|
|
291
|
-
* @returns true if initialization in progress
|
|
292
|
-
*/
|
|
293
254
|
isInitializing(toolId) {
|
|
294
255
|
return this.initializationPromises.has(toolId);
|
|
295
256
|
}
|
|
296
257
|
/**
|
|
297
258
|
* Unregister and destroy a provider
|
|
298
259
|
*
|
|
299
|
-
* Removes the provider from the registry and calls its destroy method
|
|
300
|
-
*
|
|
301
|
-
* @param toolId Tool whose provider to unregister
|
|
260
|
+
* Removes the provider from the registry and calls its destroy method,
|
|
261
|
+
* after any start in progress settles.
|
|
302
262
|
*/
|
|
303
263
|
async unregister(toolId) {
|
|
304
264
|
const provider = this.providers.get(toolId);
|
|
305
265
|
if (provider) {
|
|
306
|
-
// Wait for any pending initialization
|
|
307
266
|
const initPromise = this.initializationPromises.get(toolId);
|
|
308
267
|
if (initPromise) {
|
|
309
268
|
try {
|
|
@@ -318,7 +277,6 @@ export class ToolProviderRegistry {
|
|
|
318
277
|
return;
|
|
319
278
|
}
|
|
320
279
|
this.destroyProvider(toolId, provider);
|
|
321
|
-
// Remove from registry
|
|
322
280
|
this.providers.delete(toolId);
|
|
323
281
|
this.configs.delete(toolId);
|
|
324
282
|
this.initialized.delete(toolId);
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* Core names no capability. The requester supplies the tool id, which is why the
|
|
20
20
|
* pairing of a selection action to a dictionary lives in the composition layer.
|
|
21
21
|
*/
|
|
22
|
+
import type { ToolFailurePhase } from "./tool-failure.js";
|
|
22
23
|
import type { ToolPlacementLevel } from "./tools-config-normalizer.js";
|
|
23
24
|
/** Level a request resolves against when the requester names none. */
|
|
24
25
|
export declare const DEFAULT_TOOL_REQUEST_LEVEL: ToolPlacementLevel;
|
|
@@ -79,8 +80,11 @@ export interface ToolRequestTarget {
|
|
|
79
80
|
* earlier one is still mounted does not displace it.
|
|
80
81
|
*/
|
|
81
82
|
export declare class ToolRequestRegistry {
|
|
83
|
+
private readonly onTargetFailure;
|
|
82
84
|
private readonly targets;
|
|
83
85
|
private readonly changeListeners;
|
|
86
|
+
/** `onTargetFailure` receives a target's throw, which the registry recovers from. */
|
|
87
|
+
constructor(onTargetFailure?: (toolId: string, phase: ToolFailurePhase, error: unknown) => void);
|
|
84
88
|
registerTarget(target: ToolRequestTarget): () => void;
|
|
85
89
|
/**
|
|
86
90
|
* Whether a request for this tool would reach a toolbar.
|
|
@@ -28,8 +28,13 @@ export const DEFAULT_TOOL_REQUEST_LEVEL = "section";
|
|
|
28
28
|
* earlier one is still mounted does not displace it.
|
|
29
29
|
*/
|
|
30
30
|
export class ToolRequestRegistry {
|
|
31
|
+
onTargetFailure;
|
|
31
32
|
targets = new Set();
|
|
32
33
|
changeListeners = new Set();
|
|
34
|
+
/** `onTargetFailure` receives a target's throw, which the registry recovers from. */
|
|
35
|
+
constructor(onTargetFailure = (toolId, phase, error) => console.error(`[ToolRequestRegistry] "${toolId}" ${phase} failed:`, error)) {
|
|
36
|
+
this.onTargetFailure = onTargetFailure;
|
|
37
|
+
}
|
|
33
38
|
registerTarget(target) {
|
|
34
39
|
this.targets.add(target);
|
|
35
40
|
this.notifyTargetsChange();
|
|
@@ -58,7 +63,7 @@ export class ToolRequestRegistry {
|
|
|
58
63
|
target.open(request.toolId, request.params);
|
|
59
64
|
}
|
|
60
65
|
catch (error) {
|
|
61
|
-
|
|
66
|
+
this.onTargetFailure(request.toolId, "tool-request-open", error);
|
|
62
67
|
return false;
|
|
63
68
|
}
|
|
64
69
|
return true;
|
|
@@ -115,7 +120,7 @@ export class ToolRequestRegistry {
|
|
|
115
120
|
return target.hostsTool(toolId) === true;
|
|
116
121
|
}
|
|
117
122
|
catch (error) {
|
|
118
|
-
|
|
123
|
+
this.onTargetFailure(toolId, "tool-request-host-check", error);
|
|
119
124
|
return false;
|
|
120
125
|
}
|
|
121
126
|
}
|
|
@@ -17,6 +17,8 @@ export function createDecidedToolsTracker() {
|
|
|
17
17
|
toolId: entry.toolId,
|
|
18
18
|
required: entry.required,
|
|
19
19
|
alwaysAvailable: entry.alwaysAvailable,
|
|
20
|
+
activateAtInit: entry.activateAtInit,
|
|
21
|
+
parameters: entry.parameters,
|
|
20
22
|
}));
|
|
21
23
|
if (last?.renderVersion === renderVersion &&
|
|
22
24
|
structurallyEqual(last.tools, tools)) {
|
|
@@ -19,13 +19,10 @@ export function isValidToolbarItemShape(value) {
|
|
|
19
19
|
return false;
|
|
20
20
|
if (item.disabled !== undefined && typeof item.disabled !== "boolean")
|
|
21
21
|
return false;
|
|
22
|
+
// A link or a button: exactly one of `href` and `onClick`.
|
|
22
23
|
const hasHref = typeof item.href === "string";
|
|
23
24
|
const hasOnClick = typeof item.onClick === "function";
|
|
24
|
-
|
|
25
|
-
return false;
|
|
26
|
-
if (hasHref)
|
|
27
|
-
return true;
|
|
28
|
-
return hasOnClick;
|
|
25
|
+
return hasHref !== hasOnClick;
|
|
29
26
|
}
|
|
30
27
|
export function isInlineSvgIcon(icon) {
|
|
31
28
|
return typeof icon === "string" && icon.trimStart().startsWith("<svg");
|
|
@@ -76,16 +76,16 @@ export interface ToolProvidersConfig {
|
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
78
78
|
* PNP/profile enforcement mode, set as `tools.pnpEnforcement` (on a section
|
|
79
|
-
* player, `runtime.tools.pnpEnforcement`)
|
|
79
|
+
* player, `runtime.tools.pnpEnforcement`) or through `setPnpEnforcement`.
|
|
80
80
|
*
|
|
81
|
-
* - `"on"` —
|
|
82
|
-
* - `"off"` —
|
|
83
|
-
* - omitted
|
|
84
|
-
*
|
|
85
|
-
*
|
|
81
|
+
* - `"on"` — toolbar decisions apply PNP/profile policy.
|
|
82
|
+
* - `"off"` — toolbar decisions skip it. Feature decisions read it either way.
|
|
83
|
+
* - omitted — auto-mode (the default): on when the bound assessment carries
|
|
84
|
+
* PNP/profile policy material, or, for a decision scoped to an item, when
|
|
85
|
+
* that item's settings require or restrict a tool. See
|
|
86
86
|
* `resolveDefaultPnpEnforcement` in `policy/core/pnp-policy-inputs.ts`.
|
|
87
87
|
*/
|
|
88
|
-
export type
|
|
88
|
+
export type PnpEnforcementMode = "on" | "off";
|
|
89
89
|
export interface CanonicalToolsConfig {
|
|
90
90
|
policy: ToolPolicyConfig;
|
|
91
91
|
placement: Required<ToolPlacementConfig>;
|
|
@@ -93,9 +93,9 @@ export interface CanonicalToolsConfig {
|
|
|
93
93
|
/**
|
|
94
94
|
* Optional PNP/profile enforcement override, read by
|
|
95
95
|
* `<pie-assessment-toolkit>` and `ToolkitCoordinator`. See
|
|
96
|
-
* {@link
|
|
96
|
+
* {@link PnpEnforcementMode} for semantics.
|
|
97
97
|
*/
|
|
98
|
-
pnpEnforcement?:
|
|
98
|
+
pnpEnforcement?: PnpEnforcementMode;
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* The tools config a host supplies. Every part is optional, placement levels
|
|
@@ -104,6 +104,15 @@ export interface CanonicalToolsConfig {
|
|
|
104
104
|
export type ToolsConfigInput = Omit<Partial<CanonicalToolsConfig>, "placement"> & {
|
|
105
105
|
placement?: ToolPlacementConfig;
|
|
106
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* Tool ids trimmed, with empty ones dropped and duplicates removed in
|
|
109
|
+
* first-seen order. Throws on a non-string entry.
|
|
110
|
+
*/
|
|
107
111
|
export declare function normalizeToolList(toolIds: string[] | undefined | null): string[];
|
|
108
112
|
export declare function parseToolList(input: string | undefined | null): string[];
|
|
113
|
+
/**
|
|
114
|
+
* Check a host's tools config shape, throwing at the first malformed field, and
|
|
115
|
+
* return it canonical: tool lists trimmed and deduplicated, and every placement
|
|
116
|
+
* level that names no tool filled with its default.
|
|
117
|
+
*/
|
|
109
118
|
export declare function normalizeToolsConfig(input?: ToolsConfigInput | null): CanonicalToolsConfig;
|