@pie-players/pie-assessment-toolkit 0.3.68 → 0.3.69
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 +80 -8
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +13 -13
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-pe5szfyx.js +46 -0
- package/dist/components/chunks/ItemToolBar-rd7te9r0.js +51 -0
- package/dist/policy/core/compose-decision.js +14 -0
- package/dist/policy/core/decision-types.d.ts +1 -1
- package/dist/policy/sources/PnpPolicySource.d.ts +8 -0
- package/dist/policy/sources/PnpPolicySource.js +19 -10
- package/dist/services/ToolRegistry.d.ts +34 -0
- package/dist/services/ToolRegistry.js +34 -0
- package/dist/services/tool-context.js +8 -3
- package/dist/services/tool-providers/CortexToolProvider.d.ts +18 -0
- package/dist/services/tool-providers/CortexToolProvider.js +32 -0
- package/dist/services/tool-providers/DesmosToolProvider.d.ts +13 -102
- package/dist/services/tool-providers/DesmosToolProvider.js +14 -145
- package/dist/services/tool-providers/GeoGebraToolProvider.d.ts +21 -0
- package/dist/services/tool-providers/GeoGebraToolProvider.js +32 -0
- package/dist/services/tool-providers/LazyCalculatorToolProvider.d.ts +35 -0
- package/dist/services/tool-providers/LazyCalculatorToolProvider.js +95 -0
- package/dist/services/tool-providers/index.d.ts +4 -0
- package/dist/services/tool-providers/index.js +2 -0
- package/dist/tools/client.d.ts +0 -1
- package/dist/tools/client.js +0 -2
- package/dist/tools/internal.d.ts +1 -1
- package/dist/tools/internal.js +1 -1
- package/dist/tools/types.d.ts +1 -66
- package/package.json +22 -12
- package/dist/components/chunks/ItemToolBar-38mhtjsq.js +0 -51
- package/dist/components/chunks/ItemToolBar-9ymm7pd1.js +0 -46
- package/dist/tools/library-loader.d.ts +0 -62
- package/dist/tools/library-loader.js +0 -261
|
@@ -483,6 +483,26 @@ export interface ToolRegistration {
|
|
|
483
483
|
* @returns true if tool should be visible, false to hide
|
|
484
484
|
*/
|
|
485
485
|
isVisibleInContext?(context: ToolContext): boolean;
|
|
486
|
+
/**
|
|
487
|
+
* Whether this tool can act on this content at all — a capability question,
|
|
488
|
+
* not a relevance heuristic. Answering `false` withdraws the tool even where
|
|
489
|
+
* a PNP grant would otherwise keep it, which {@link
|
|
490
|
+
* ToolRegistration.isVisibleInContext} deliberately cannot do.
|
|
491
|
+
*
|
|
492
|
+
* The two gates answer different questions, and most tools declare only the
|
|
493
|
+
* first. A calculator is *applicable* to every item — a learner granted one
|
|
494
|
+
* keeps it on an item that does not look mathematical — while its relevance
|
|
495
|
+
* is a guess about usefulness. An answer eliminator on an item with no choice
|
|
496
|
+
* interaction has nothing to strike through, so no grant can make it work.
|
|
497
|
+
*
|
|
498
|
+
* Declare this only where the tool's own controls provably do nothing:
|
|
499
|
+
* withdrawing a granted accommodation on a false negative is the more
|
|
500
|
+
* expensive failure. Omitting it means "applicable".
|
|
501
|
+
*
|
|
502
|
+
* @param context - The item or element context the tool would act on
|
|
503
|
+
* @returns false to withdraw the tool from this context
|
|
504
|
+
*/
|
|
505
|
+
isApplicableToContent?(context: ToolContext): boolean;
|
|
486
506
|
/**
|
|
487
507
|
* Toolbar render contract. Required for `toolbar-toggle` and
|
|
488
508
|
* `selection-gateway`; a region capability renders through
|
|
@@ -625,6 +645,20 @@ export declare class ToolRegistry {
|
|
|
625
645
|
* @returns Array of visible tool registrations
|
|
626
646
|
*/
|
|
627
647
|
filterVisibleInContext(allowedToolIds: string[], context: ToolContext): ToolRegistration[];
|
|
648
|
+
/**
|
|
649
|
+
* Whether a tool can act on any of the contexts it would be placed against.
|
|
650
|
+
* Unlike the relevance pass this is a veto: a `false` here removes the tool
|
|
651
|
+
* from a toolbar even when a grant protects it, so a tool answers `false`
|
|
652
|
+
* only where its controls provably do nothing.
|
|
653
|
+
*
|
|
654
|
+
* A tool that declares no applicability gate is applicable. So is one
|
|
655
|
+
* evaluated against no contexts — content that has not resolved yet cannot
|
|
656
|
+
* establish that a tool is useless.
|
|
657
|
+
*
|
|
658
|
+
* @param toolId - Tool to ask
|
|
659
|
+
* @param contexts - Every context the tool could act on at this placement
|
|
660
|
+
*/
|
|
661
|
+
isApplicableToAnyContext(toolId: string, contexts: readonly ToolContext[]): boolean;
|
|
628
662
|
/**
|
|
629
663
|
* Get tool metadata for building UIs
|
|
630
664
|
* Useful for building PNP configuration interfaces
|
|
@@ -164,6 +164,10 @@ function assertToolRegistrationShape(registration) {
|
|
|
164
164
|
typeof registration.isVisibleInContext !== "function") {
|
|
165
165
|
throw new Error(`Invalid tool registration "${registration.toolId}": "isVisibleInContext" must be a function when present.`);
|
|
166
166
|
}
|
|
167
|
+
if (registration.isApplicableToContent !== undefined &&
|
|
168
|
+
typeof registration.isApplicableToContent !== "function") {
|
|
169
|
+
throw new Error(`Invalid tool registration "${registration.toolId}": "isApplicableToContent" must be a function when present.`);
|
|
170
|
+
}
|
|
167
171
|
if (registration.requiresAuthoredContent !== undefined) {
|
|
168
172
|
if (typeof registration.requiresAuthoredContent !== "object" ||
|
|
169
173
|
registration.requiresAuthoredContent === null ||
|
|
@@ -442,6 +446,36 @@ export class ToolRegistry {
|
|
|
442
446
|
}
|
|
443
447
|
return visible;
|
|
444
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Whether a tool can act on any of the contexts it would be placed against.
|
|
451
|
+
* Unlike the relevance pass this is a veto: a `false` here removes the tool
|
|
452
|
+
* from a toolbar even when a grant protects it, so a tool answers `false`
|
|
453
|
+
* only where its controls provably do nothing.
|
|
454
|
+
*
|
|
455
|
+
* A tool that declares no applicability gate is applicable. So is one
|
|
456
|
+
* evaluated against no contexts — content that has not resolved yet cannot
|
|
457
|
+
* establish that a tool is useless.
|
|
458
|
+
*
|
|
459
|
+
* @param toolId - Tool to ask
|
|
460
|
+
* @param contexts - Every context the tool could act on at this placement
|
|
461
|
+
*/
|
|
462
|
+
isApplicableToAnyContext(toolId, contexts) {
|
|
463
|
+
const tool = this.get(toolId);
|
|
464
|
+
if (!tool?.isApplicableToContent)
|
|
465
|
+
return true;
|
|
466
|
+
if (contexts.length === 0)
|
|
467
|
+
return true;
|
|
468
|
+
return contexts.some((context) => {
|
|
469
|
+
try {
|
|
470
|
+
return tool.isApplicableToContent?.(context) ?? true;
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
console.error(`Error evaluating applicability for tool '${toolId}':`, error);
|
|
474
|
+
// A gate that throws has not established that the tool is useless.
|
|
475
|
+
return true;
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
}
|
|
445
479
|
/**
|
|
446
480
|
* Get tool metadata for building UIs
|
|
447
481
|
* Useful for building PNP configuration interfaces
|
|
@@ -300,9 +300,14 @@ export function hasChoiceInteraction(context) {
|
|
|
300
300
|
if (!m || typeof m !== "object")
|
|
301
301
|
return false;
|
|
302
302
|
const type = m.element || "";
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
//
|
|
303
|
+
// A model that names its element has answered the question, whichever way
|
|
304
|
+
// the answer falls. `choices` is carried by interactions that are not
|
|
305
|
+
// choice interactions at all — `placement-ordering`, `categorize` and
|
|
306
|
+
// `drag-in-the-blank` each hold their draggables there — so reading it on
|
|
307
|
+
// a named model showed the answer eliminator on items where the tool does
|
|
308
|
+
// nothing. The heuristic remains for configs that name no element.
|
|
309
|
+
if (type)
|
|
310
|
+
return interactionTypes.includes(type);
|
|
306
311
|
return Array.isArray(m.choices) && m.choices.length > 0;
|
|
307
312
|
});
|
|
308
313
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Fully bundled open-source calculator adapter for the tool-provider registry. */
|
|
2
|
+
import type { CalculatorToolProviderInitConfig } from "./LazyCalculatorToolProvider.js";
|
|
3
|
+
import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
|
|
4
|
+
import type { ToolProviderCapabilities } from "./ToolProviderApi.js";
|
|
5
|
+
export type CortexToolProviderConfig = CalculatorToolProviderInitConfig;
|
|
6
|
+
export declare class CortexToolProvider extends LazyCalculatorToolProvider<CortexToolProviderConfig> {
|
|
7
|
+
readonly providerId = "cortex-calculator";
|
|
8
|
+
readonly providerName = "PIE Open-Source Calculator";
|
|
9
|
+
readonly version = "1";
|
|
10
|
+
readonly requiresAuth = false;
|
|
11
|
+
protected getDefinition(): {
|
|
12
|
+
backend: string;
|
|
13
|
+
moduleImportOperation: string;
|
|
14
|
+
loadProvider: () => Promise<typeof import("@pie-players/pie-calculator-cortex").CortexCalculatorProvider>;
|
|
15
|
+
initializationErrorMessage: string;
|
|
16
|
+
};
|
|
17
|
+
getCapabilities(): ToolProviderCapabilities;
|
|
18
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Fully bundled open-source calculator adapter for the tool-provider registry. */
|
|
2
|
+
import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
|
|
3
|
+
export class CortexToolProvider extends LazyCalculatorToolProvider {
|
|
4
|
+
providerId = "cortex-calculator";
|
|
5
|
+
providerName = "PIE Open-Source Calculator";
|
|
6
|
+
version = "1";
|
|
7
|
+
requiresAuth = false;
|
|
8
|
+
getDefinition() {
|
|
9
|
+
return {
|
|
10
|
+
backend: "cortex",
|
|
11
|
+
moduleImportOperation: "cortex-provider-module-import",
|
|
12
|
+
loadProvider: async () => {
|
|
13
|
+
const module = await import("@pie-players/pie-calculator-cortex");
|
|
14
|
+
return module.CortexCalculatorProvider;
|
|
15
|
+
},
|
|
16
|
+
initializationErrorMessage: "Failed to initialize the PIE open-source calculator provider. Confirm that this browser supports module workers and that the bundled worker assets are available.",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
getCapabilities() {
|
|
20
|
+
return {
|
|
21
|
+
supportsOffline: true,
|
|
22
|
+
requiresAuth: false,
|
|
23
|
+
maxInstances: null,
|
|
24
|
+
features: {
|
|
25
|
+
basic: true,
|
|
26
|
+
scientific: true,
|
|
27
|
+
graphing: true,
|
|
28
|
+
fourFunction: true,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1,108 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* - Development: Pass apiKey directly for local testing
|
|
9
|
-
* - Production: Use proxyEndpoint or authFetcher to keep API key server-side
|
|
10
|
-
*
|
|
11
|
-
* Part of PIE Assessment Toolkit.
|
|
12
|
-
*/
|
|
13
|
-
import type { CalculatorProvider } from "@pie-players/pie-calculator";
|
|
14
|
-
import type { ToolProviderApi, ToolProviderCapabilities } from "./ToolProviderApi.js";
|
|
15
|
-
/**
|
|
16
|
-
* Desmos tool provider configuration
|
|
17
|
-
*
|
|
18
|
-
* Auth and telemetry only. Per-calculator Desmos options are owned by the
|
|
19
|
-
* calculator component, which derives them from the calculator type and passes
|
|
20
|
-
* them to `createCalculator()` directly — this provider never sees that config,
|
|
21
|
-
* so a defaults field here would silently do nothing.
|
|
22
|
-
*/
|
|
23
|
-
export interface DesmosToolProviderConfig {
|
|
24
|
-
/**
|
|
25
|
-
* Desmos API key (DEVELOPMENT ONLY)
|
|
26
|
-
* Never expose in production client code!
|
|
27
|
-
*
|
|
28
|
-
* Obtain from: https://www.desmos.com/api
|
|
29
|
-
*/
|
|
30
|
-
apiKey?: string;
|
|
31
|
-
/**
|
|
32
|
-
* Server proxy endpoint (PRODUCTION RECOMMENDED)
|
|
33
|
-
* Backend handles API key securely
|
|
34
|
-
*
|
|
35
|
-
* @example '/api/desmos/token'
|
|
36
|
-
* @example 'https://api.myapp.com/tools/desmos/auth'
|
|
37
|
-
*/
|
|
38
|
-
proxyEndpoint?: string;
|
|
39
|
-
/**
|
|
40
|
-
* Optional telemetry callback for tool/backend instrumentation.
|
|
41
|
-
*/
|
|
42
|
-
onTelemetry?: (eventName: string, payload?: Record<string, unknown>) => void | Promise<void>;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Desmos Calculator Tool Provider
|
|
46
|
-
*
|
|
47
|
-
* Wraps DesmosCalculatorProvider with the ToolProviderApi interface
|
|
48
|
-
* for use in the ToolProviderRegistry.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```typescript
|
|
52
|
-
* const provider = new DesmosToolProvider();
|
|
53
|
-
*
|
|
54
|
-
* await provider.initialize({
|
|
55
|
-
* apiKey: 'your-api-key', // Development only
|
|
56
|
-
* proxyEndpoint: '/api/desmos/token', // Production
|
|
57
|
-
* });
|
|
58
|
-
*
|
|
59
|
-
* const calculatorProvider = await provider.createInstance();
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
export declare class DesmosToolProvider implements ToolProviderApi<DesmosToolProviderConfig, CalculatorProvider> {
|
|
1
|
+
/** Desmos calculator adapter for the generic tool-provider registry. */
|
|
2
|
+
import type { CalculatorProviderInit } from "@pie-players/pie-calculator";
|
|
3
|
+
import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
|
|
4
|
+
import type { ToolProviderCapabilities } from "./ToolProviderApi.js";
|
|
5
|
+
/** Provider initialization is the provider-neutral calculator contract. */
|
|
6
|
+
export type DesmosToolProviderConfig = CalculatorProviderInit;
|
|
7
|
+
export declare class DesmosToolProvider extends LazyCalculatorToolProvider<DesmosToolProviderConfig> {
|
|
63
8
|
readonly providerId = "desmos-calculator";
|
|
64
9
|
readonly providerName = "Desmos Calculator";
|
|
65
|
-
readonly category: "calculator";
|
|
66
10
|
readonly version = "1.12";
|
|
67
11
|
readonly requiresAuth = true;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
* Loads the Desmos API library and authenticates with provided credentials.
|
|
75
|
-
*
|
|
76
|
-
* @param config Configuration with API key or proxy endpoint
|
|
77
|
-
* @throws Error if initialization fails
|
|
78
|
-
*/
|
|
79
|
-
initialize(config: DesmosToolProviderConfig): Promise<void>;
|
|
80
|
-
/**
|
|
81
|
-
* Create a calculator provider instance
|
|
82
|
-
*
|
|
83
|
-
* Returns the initialized Desmos calculator provider.
|
|
84
|
-
*
|
|
85
|
-
* @param config Optional instance-specific configuration (currently unused)
|
|
86
|
-
* @returns Desmos calculator provider
|
|
87
|
-
* @throws Error if provider not initialized
|
|
88
|
-
*/
|
|
89
|
-
createInstance(config?: Partial<DesmosToolProviderConfig>): Promise<CalculatorProvider>;
|
|
90
|
-
/**
|
|
91
|
-
* Get provider capabilities
|
|
92
|
-
*
|
|
93
|
-
* @returns Desmos calculator capabilities
|
|
94
|
-
*/
|
|
12
|
+
protected getDefinition(): {
|
|
13
|
+
backend: string;
|
|
14
|
+
moduleImportOperation: string;
|
|
15
|
+
loadProvider: () => Promise<typeof import("@pie-players/pie-calculator-desmos").DesmosCalculatorProvider>;
|
|
16
|
+
initializationErrorMessage: string;
|
|
17
|
+
};
|
|
95
18
|
getCapabilities(): ToolProviderCapabilities;
|
|
96
|
-
/**
|
|
97
|
-
* Check if provider is ready
|
|
98
|
-
*
|
|
99
|
-
* @returns true if provider is initialized
|
|
100
|
-
*/
|
|
101
|
-
isReady(): boolean;
|
|
102
|
-
/**
|
|
103
|
-
* Clean up provider resources
|
|
104
|
-
*
|
|
105
|
-
* Destroys the Desmos calculator provider and releases resources.
|
|
106
|
-
*/
|
|
107
|
-
destroy(): void;
|
|
108
19
|
}
|
|
@@ -1,136 +1,26 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Provides Desmos calculators (basic, scientific, graphing)
|
|
5
|
-
* with authentication and proxy support.
|
|
6
|
-
*
|
|
7
|
-
* SECURITY BEST PRACTICE:
|
|
8
|
-
* - Development: Pass apiKey directly for local testing
|
|
9
|
-
* - Production: Use proxyEndpoint or authFetcher to keep API key server-side
|
|
10
|
-
*
|
|
11
|
-
* Part of PIE Assessment Toolkit.
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* Desmos Calculator Tool Provider
|
|
15
|
-
*
|
|
16
|
-
* Wraps DesmosCalculatorProvider with the ToolProviderApi interface
|
|
17
|
-
* for use in the ToolProviderRegistry.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* const provider = new DesmosToolProvider();
|
|
22
|
-
*
|
|
23
|
-
* await provider.initialize({
|
|
24
|
-
* apiKey: 'your-api-key', // Development only
|
|
25
|
-
* proxyEndpoint: '/api/desmos/token', // Production
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* const calculatorProvider = await provider.createInstance();
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export class DesmosToolProvider {
|
|
1
|
+
/** Desmos calculator adapter for the generic tool-provider registry. */
|
|
2
|
+
import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
|
|
3
|
+
export class DesmosToolProvider extends LazyCalculatorToolProvider {
|
|
32
4
|
providerId = "desmos-calculator";
|
|
33
5
|
providerName = "Desmos Calculator";
|
|
34
|
-
category = "calculator";
|
|
35
6
|
version = "1.12";
|
|
36
7
|
requiresAuth = true;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
async emitTelemetry(eventName, payload) {
|
|
40
|
-
try {
|
|
41
|
-
await this.config?.onTelemetry?.(eventName, payload);
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
console.warn("[DesmosToolProvider] telemetry callback failed:", error);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Initialize Desmos calculator provider
|
|
49
|
-
*
|
|
50
|
-
* Loads the Desmos API library and authenticates with provided credentials.
|
|
51
|
-
*
|
|
52
|
-
* @param config Configuration with API key or proxy endpoint
|
|
53
|
-
* @throws Error if initialization fails
|
|
54
|
-
*/
|
|
55
|
-
async initialize(config) {
|
|
56
|
-
if (this.desmosProvider) {
|
|
57
|
-
console.warn("[DesmosToolProvider] Already initialized, skipping reinitialization");
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
this.config = config;
|
|
61
|
-
const moduleLoadStartedAt = Date.now();
|
|
62
|
-
await this.emitTelemetry("pie-tool-library-load-start", {
|
|
63
|
-
toolId: "calculator",
|
|
64
|
-
operation: "desmos-provider-module-import",
|
|
8
|
+
getDefinition() {
|
|
9
|
+
return {
|
|
65
10
|
backend: "desmos",
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
backend: "desmos",
|
|
74
|
-
duration: Date.now() - moduleLoadStartedAt,
|
|
75
|
-
});
|
|
76
|
-
return loaded;
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
await this.emitTelemetry("pie-tool-library-load-error", {
|
|
80
|
-
toolId: "calculator",
|
|
81
|
-
operation: "desmos-provider-module-import",
|
|
82
|
-
backend: "desmos",
|
|
83
|
-
duration: Date.now() - moduleLoadStartedAt,
|
|
84
|
-
errorType: "ToolLibraryLoadError",
|
|
85
|
-
message: error instanceof Error ? error.message : String(error),
|
|
86
|
-
});
|
|
87
|
-
throw error;
|
|
88
|
-
}
|
|
89
|
-
})();
|
|
90
|
-
this.desmosProvider = new desmosModule.DesmosCalculatorProvider();
|
|
91
|
-
// Initialize with API key or proxy
|
|
92
|
-
try {
|
|
93
|
-
await this.desmosProvider.initialize({
|
|
94
|
-
apiKey: config.apiKey,
|
|
95
|
-
proxyEndpoint: config.proxyEndpoint,
|
|
96
|
-
onTelemetry: config.onTelemetry,
|
|
97
|
-
});
|
|
98
|
-
console.log(`[DesmosToolProvider] Initialized successfully ${config.proxyEndpoint
|
|
99
|
-
? "(using proxy)"
|
|
100
|
-
: config.apiKey
|
|
101
|
-
? "(direct API key)"
|
|
102
|
-
: "(no auth)"}`);
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
console.error("[DesmosToolProvider] Initialization failed:", error);
|
|
106
|
-
throw new Error("Failed to initialize Desmos calculator provider. Check API key or proxy endpoint.");
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Create a calculator provider instance
|
|
111
|
-
*
|
|
112
|
-
* Returns the initialized Desmos calculator provider.
|
|
113
|
-
*
|
|
114
|
-
* @param config Optional instance-specific configuration (currently unused)
|
|
115
|
-
* @returns Desmos calculator provider
|
|
116
|
-
* @throws Error if provider not initialized
|
|
117
|
-
*/
|
|
118
|
-
async createInstance(config) {
|
|
119
|
-
if (!this.desmosProvider) {
|
|
120
|
-
throw new Error("[DesmosToolProvider] Provider not initialized. Call initialize() first.");
|
|
121
|
-
}
|
|
122
|
-
return this.desmosProvider;
|
|
11
|
+
moduleImportOperation: "desmos-provider-module-import",
|
|
12
|
+
loadProvider: async () => {
|
|
13
|
+
const module = await import("@pie-players/pie-calculator-desmos");
|
|
14
|
+
return module.DesmosCalculatorProvider;
|
|
15
|
+
},
|
|
16
|
+
initializationErrorMessage: "Failed to initialize Desmos calculator provider. Check the application key, preloaded API, runtime endpoint, or network access.",
|
|
17
|
+
};
|
|
123
18
|
}
|
|
124
|
-
/**
|
|
125
|
-
* Get provider capabilities
|
|
126
|
-
*
|
|
127
|
-
* @returns Desmos calculator capabilities
|
|
128
|
-
*/
|
|
129
19
|
getCapabilities() {
|
|
130
20
|
return {
|
|
131
|
-
supportsOffline: false,
|
|
21
|
+
supportsOffline: false,
|
|
132
22
|
requiresAuth: true,
|
|
133
|
-
maxInstances: null,
|
|
23
|
+
maxInstances: null,
|
|
134
24
|
features: {
|
|
135
25
|
basic: true,
|
|
136
26
|
scientific: true,
|
|
@@ -139,25 +29,4 @@ export class DesmosToolProvider {
|
|
|
139
29
|
},
|
|
140
30
|
};
|
|
141
31
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Check if provider is ready
|
|
144
|
-
*
|
|
145
|
-
* @returns true if provider is initialized
|
|
146
|
-
*/
|
|
147
|
-
isReady() {
|
|
148
|
-
return this.desmosProvider !== null;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Clean up provider resources
|
|
152
|
-
*
|
|
153
|
-
* Destroys the Desmos calculator provider and releases resources.
|
|
154
|
-
*/
|
|
155
|
-
destroy() {
|
|
156
|
-
if (this.desmosProvider) {
|
|
157
|
-
this.desmosProvider.destroy();
|
|
158
|
-
this.desmosProvider = null;
|
|
159
|
-
}
|
|
160
|
-
this.config = null;
|
|
161
|
-
console.log("[DesmosToolProvider] Destroyed");
|
|
162
|
-
}
|
|
163
32
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** GeoGebra calculator adapter for the generic tool-provider registry. */
|
|
2
|
+
import type { CalculatorToolProviderInitConfig } from "./LazyCalculatorToolProvider.js";
|
|
3
|
+
import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
|
|
4
|
+
import type { ToolProviderCapabilities } from "./ToolProviderApi.js";
|
|
5
|
+
export interface GeoGebraToolProviderConfig extends CalculatorToolProviderInitConfig {
|
|
6
|
+
scriptUrl?: string;
|
|
7
|
+
appletTimeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class GeoGebraToolProvider extends LazyCalculatorToolProvider<GeoGebraToolProviderConfig> {
|
|
10
|
+
readonly providerId = "geogebra-calculator";
|
|
11
|
+
readonly providerName = "GeoGebra Calculator";
|
|
12
|
+
readonly version = "6";
|
|
13
|
+
readonly requiresAuth = false;
|
|
14
|
+
protected getDefinition(): {
|
|
15
|
+
backend: string;
|
|
16
|
+
moduleImportOperation: string;
|
|
17
|
+
loadProvider: () => Promise<typeof import("@pie-players/pie-calculator-geogebra").GeoGebraCalculatorProvider>;
|
|
18
|
+
initializationErrorMessage: string;
|
|
19
|
+
};
|
|
20
|
+
getCapabilities(): ToolProviderCapabilities;
|
|
21
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** GeoGebra calculator adapter for the generic tool-provider registry. */
|
|
2
|
+
import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
|
|
3
|
+
export class GeoGebraToolProvider extends LazyCalculatorToolProvider {
|
|
4
|
+
providerId = "geogebra-calculator";
|
|
5
|
+
providerName = "GeoGebra Calculator";
|
|
6
|
+
version = "6";
|
|
7
|
+
requiresAuth = false;
|
|
8
|
+
getDefinition() {
|
|
9
|
+
return {
|
|
10
|
+
backend: "geogebra",
|
|
11
|
+
moduleImportOperation: "geogebra-provider-module-import",
|
|
12
|
+
loadProvider: async () => {
|
|
13
|
+
const module = await import("@pie-players/pie-calculator-geogebra");
|
|
14
|
+
return module.GeoGebraCalculatorProvider;
|
|
15
|
+
},
|
|
16
|
+
initializationErrorMessage: "Failed to initialize GeoGebra calculator provider. Confirm that the deployment may load GeoGebra and that its script URL is reachable.",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
getCapabilities() {
|
|
20
|
+
return {
|
|
21
|
+
supportsOffline: false,
|
|
22
|
+
requiresAuth: false,
|
|
23
|
+
maxInstances: null,
|
|
24
|
+
features: {
|
|
25
|
+
basic: true,
|
|
26
|
+
scientific: true,
|
|
27
|
+
graphing: true,
|
|
28
|
+
fourFunction: false,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CalculatorProvider, CalculatorProviderInit } from "@pie-players/pie-calculator";
|
|
2
|
+
import type { ToolProviderApi, ToolProviderCapabilities } from "./ToolProviderApi.js";
|
|
3
|
+
export type CalculatorToolProviderInitConfig = Pick<CalculatorProviderInit, "onTelemetry">;
|
|
4
|
+
type InitializableCalculatorProvider<TConfig> = CalculatorProvider & {
|
|
5
|
+
initialize(config: TConfig): Promise<void>;
|
|
6
|
+
};
|
|
7
|
+
interface LazyCalculatorProviderDefinition<TConfig> {
|
|
8
|
+
backend: string;
|
|
9
|
+
moduleImportOperation: string;
|
|
10
|
+
loadProvider: () => Promise<new () => InitializableCalculatorProvider<TConfig>>;
|
|
11
|
+
initializationErrorMessage: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Shared lazy-module and lifecycle implementation for calculator tool adapters.
|
|
15
|
+
* Concrete adapters own only their metadata, capabilities and provider import.
|
|
16
|
+
*/
|
|
17
|
+
export declare abstract class LazyCalculatorToolProvider<TConfig extends CalculatorToolProviderInitConfig> implements ToolProviderApi<TConfig, CalculatorProvider> {
|
|
18
|
+
abstract readonly providerId: string;
|
|
19
|
+
abstract readonly providerName: string;
|
|
20
|
+
readonly category: "calculator";
|
|
21
|
+
abstract readonly version: string;
|
|
22
|
+
abstract readonly requiresAuth: boolean;
|
|
23
|
+
protected abstract getDefinition(): LazyCalculatorProviderDefinition<TConfig>;
|
|
24
|
+
abstract getCapabilities(): ToolProviderCapabilities;
|
|
25
|
+
private calculatorProvider;
|
|
26
|
+
private initializationPromise;
|
|
27
|
+
private lifecycleGeneration;
|
|
28
|
+
private emitTelemetry;
|
|
29
|
+
initialize(config?: TConfig): Promise<void>;
|
|
30
|
+
private initializeProvider;
|
|
31
|
+
createInstance(): Promise<CalculatorProvider>;
|
|
32
|
+
isReady(): boolean;
|
|
33
|
+
destroy(): void;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared lazy-module and lifecycle implementation for calculator tool adapters.
|
|
3
|
+
* Concrete adapters own only their metadata, capabilities and provider import.
|
|
4
|
+
*/
|
|
5
|
+
export class LazyCalculatorToolProvider {
|
|
6
|
+
category = "calculator";
|
|
7
|
+
calculatorProvider = null;
|
|
8
|
+
initializationPromise = null;
|
|
9
|
+
lifecycleGeneration = 0;
|
|
10
|
+
async emitTelemetry(config, eventName, payload) {
|
|
11
|
+
try {
|
|
12
|
+
await config.onTelemetry?.(eventName, payload);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
console.warn(`[${this.providerName}] telemetry callback failed:`, error);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async initialize(config = {}) {
|
|
19
|
+
if (this.calculatorProvider)
|
|
20
|
+
return;
|
|
21
|
+
if (this.initializationPromise)
|
|
22
|
+
return this.initializationPromise;
|
|
23
|
+
const generation = ++this.lifecycleGeneration;
|
|
24
|
+
const initializationPromise = this.initializeProvider(config, generation);
|
|
25
|
+
this.initializationPromise = initializationPromise;
|
|
26
|
+
try {
|
|
27
|
+
await initializationPromise;
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
if (this.initializationPromise === initializationPromise) {
|
|
31
|
+
this.initializationPromise = null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async initializeProvider(config, generation) {
|
|
36
|
+
const definition = this.getDefinition();
|
|
37
|
+
const moduleLoadStartedAt = Date.now();
|
|
38
|
+
await this.emitTelemetry(config, "pie-tool-library-load-start", {
|
|
39
|
+
toolId: "calculator",
|
|
40
|
+
operation: definition.moduleImportOperation,
|
|
41
|
+
backend: definition.backend,
|
|
42
|
+
});
|
|
43
|
+
let ProviderConstructor;
|
|
44
|
+
try {
|
|
45
|
+
ProviderConstructor = await definition.loadProvider();
|
|
46
|
+
await this.emitTelemetry(config, "pie-tool-library-load-success", {
|
|
47
|
+
toolId: "calculator",
|
|
48
|
+
operation: definition.moduleImportOperation,
|
|
49
|
+
backend: definition.backend,
|
|
50
|
+
duration: Date.now() - moduleLoadStartedAt,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
await this.emitTelemetry(config, "pie-tool-library-load-error", {
|
|
55
|
+
toolId: "calculator",
|
|
56
|
+
operation: definition.moduleImportOperation,
|
|
57
|
+
backend: definition.backend,
|
|
58
|
+
duration: Date.now() - moduleLoadStartedAt,
|
|
59
|
+
errorType: "ToolLibraryLoadError",
|
|
60
|
+
message: error instanceof Error ? error.message : String(error),
|
|
61
|
+
});
|
|
62
|
+
throw new Error(definition.initializationErrorMessage, { cause: error });
|
|
63
|
+
}
|
|
64
|
+
if (generation !== this.lifecycleGeneration) {
|
|
65
|
+
throw new Error(`${this.providerName} initialization was cancelled`);
|
|
66
|
+
}
|
|
67
|
+
const candidate = new ProviderConstructor();
|
|
68
|
+
try {
|
|
69
|
+
await candidate.initialize(config);
|
|
70
|
+
if (generation !== this.lifecycleGeneration) {
|
|
71
|
+
throw new Error(`${this.providerName} initialization was cancelled`);
|
|
72
|
+
}
|
|
73
|
+
this.calculatorProvider = candidate;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
candidate.destroy();
|
|
77
|
+
throw new Error(definition.initializationErrorMessage, { cause: error });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async createInstance() {
|
|
81
|
+
if (!this.calculatorProvider) {
|
|
82
|
+
throw new Error(`[${this.providerName}] Provider not initialized. Call initialize() first.`);
|
|
83
|
+
}
|
|
84
|
+
return this.calculatorProvider;
|
|
85
|
+
}
|
|
86
|
+
isReady() {
|
|
87
|
+
return this.calculatorProvider !== null;
|
|
88
|
+
}
|
|
89
|
+
destroy() {
|
|
90
|
+
this.lifecycleGeneration += 1;
|
|
91
|
+
this.initializationPromise = null;
|
|
92
|
+
this.calculatorProvider?.destroy();
|
|
93
|
+
this.calculatorProvider = null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -11,5 +11,9 @@ export { ToolProviderRegistry } from "./ToolProviderRegistry.js";
|
|
|
11
11
|
export type { ToolProviderConfig } from "./ToolProviderRegistry.js";
|
|
12
12
|
export { DesmosToolProvider } from "./DesmosToolProvider.js";
|
|
13
13
|
export type { DesmosToolProviderConfig } from "./DesmosToolProvider.js";
|
|
14
|
+
export { CortexToolProvider } from "./CortexToolProvider.js";
|
|
15
|
+
export type { CortexToolProviderConfig } from "./CortexToolProvider.js";
|
|
16
|
+
export { GeoGebraToolProvider } from "./GeoGebraToolProvider.js";
|
|
17
|
+
export type { GeoGebraToolProviderConfig } from "./GeoGebraToolProvider.js";
|
|
14
18
|
export { TTSToolProvider } from "./TTSToolProvider.js";
|
|
15
19
|
export type { TTSToolProviderConfig, TTSBackend, } from "./TTSToolProvider.js";
|
|
@@ -10,4 +10,6 @@
|
|
|
10
10
|
export { ToolProviderRegistry } from "./ToolProviderRegistry.js";
|
|
11
11
|
// Concrete providers
|
|
12
12
|
export { DesmosToolProvider } from "./DesmosToolProvider.js";
|
|
13
|
+
export { CortexToolProvider } from "./CortexToolProvider.js";
|
|
14
|
+
export { GeoGebraToolProvider } from "./GeoGebraToolProvider.js";
|
|
13
15
|
export { TTSToolProvider } from "./TTSToolProvider.js";
|