qlm-measure 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +54 -0
  2. package/NOTICE +13 -0
  3. package/README.md +152 -0
  4. package/dist/clients/engine-client.d.ts +51 -0
  5. package/dist/clients/engine-client.d.ts.map +1 -0
  6. package/dist/clients/engine-client.js +59 -0
  7. package/dist/clients/engine-client.js.map +1 -0
  8. package/dist/clients/index.d.ts +5 -0
  9. package/dist/clients/index.d.ts.map +1 -0
  10. package/dist/clients/index.js +3 -0
  11. package/dist/clients/index.js.map +1 -0
  12. package/dist/clients/ontology-client.d.ts +57 -0
  13. package/dist/clients/ontology-client.d.ts.map +1 -0
  14. package/dist/clients/ontology-client.js +47 -0
  15. package/dist/clients/ontology-client.js.map +1 -0
  16. package/dist/emitter/index.d.ts +3 -0
  17. package/dist/emitter/index.d.ts.map +1 -0
  18. package/dist/emitter/index.js +2 -0
  19. package/dist/emitter/index.js.map +1 -0
  20. package/dist/emitter/measurement-emitter.d.ts +33 -0
  21. package/dist/emitter/measurement-emitter.d.ts.map +1 -0
  22. package/dist/emitter/measurement-emitter.js +98 -0
  23. package/dist/emitter/measurement-emitter.js.map +1 -0
  24. package/dist/index.d.ts +36 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +31 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/schema/enums.d.ts +19 -0
  29. package/dist/schema/enums.d.ts.map +1 -0
  30. package/dist/schema/enums.js +24 -0
  31. package/dist/schema/enums.js.map +1 -0
  32. package/dist/schema/evidence-record.d.ts +70 -0
  33. package/dist/schema/evidence-record.d.ts.map +1 -0
  34. package/dist/schema/evidence-record.js +11 -0
  35. package/dist/schema/evidence-record.js.map +1 -0
  36. package/dist/schema/index.d.ts +7 -0
  37. package/dist/schema/index.d.ts.map +1 -0
  38. package/dist/schema/index.js +3 -0
  39. package/dist/schema/index.js.map +1 -0
  40. package/dist/schema/measurement-event.d.ts +35 -0
  41. package/dist/schema/measurement-event.d.ts.map +1 -0
  42. package/dist/schema/measurement-event.js +7 -0
  43. package/dist/schema/measurement-event.js.map +1 -0
  44. package/dist/schema/observation-event.d.ts +58 -0
  45. package/dist/schema/observation-event.d.ts.map +1 -0
  46. package/dist/schema/observation-event.js +12 -0
  47. package/dist/schema/observation-event.js.map +1 -0
  48. package/dist/verifier/hash.d.ts +28 -0
  49. package/dist/verifier/hash.d.ts.map +1 -0
  50. package/dist/verifier/hash.js +75 -0
  51. package/dist/verifier/hash.js.map +1 -0
  52. package/dist/verifier/index.d.ts +5 -0
  53. package/dist/verifier/index.d.ts.map +1 -0
  54. package/dist/verifier/index.js +4 -0
  55. package/dist/verifier/index.js.map +1 -0
  56. package/dist/verifier/replay.d.ts +34 -0
  57. package/dist/verifier/replay.d.ts.map +1 -0
  58. package/dist/verifier/replay.js +51 -0
  59. package/dist/verifier/replay.js.map +1 -0
  60. package/dist/verifier/verify-record.d.ts +48 -0
  61. package/dist/verifier/verify-record.d.ts.map +1 -0
  62. package/dist/verifier/verify-record.js +163 -0
  63. package/dist/verifier/verify-record.js.map +1 -0
  64. package/package.json +63 -0
package/LICENSE ADDED
@@ -0,0 +1,54 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+ "License" shall mean the terms and conditions for use, reproduction,
9
+ and distribution as defined by Sections 1 through 9 of this document.
10
+ "Licensor" shall mean the copyright owner or entity authorized by
11
+ the copyright owner that is granting the License.
12
+ "Legal Entity" shall mean the union of the acting entity and all
13
+ other entities that control, are controlled by, or are under common
14
+ control with that entity.
15
+ "You" (or "Your") shall mean an individual or Legal Entity
16
+ exercising permissions granted by this License.
17
+ "Source" form shall mean the preferred form for making modifications.
18
+ "Object" form shall mean any form resulting from mechanical
19
+ transformation or translation of a Source form.
20
+ "Work" shall mean the work of authorship made available under the License.
21
+ "Derivative Works" shall mean any work that is based on the Work.
22
+ "Contribution" shall mean any work of authorship submitted to the
23
+ Licensor for inclusion in the Work.
24
+ "Contributor" shall mean Licensor and any Legal Entity on behalf of
25
+ whom a Contribution has been received by the Licensor.
26
+
27
+ 2. Grant of Copyright License. Subject to the terms and conditions of
28
+ this License, each Contributor hereby grants to You a perpetual,
29
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
30
+ copyright license to reproduce, prepare Derivative Works of,
31
+ publicly display, publicly perform, sublicense, and distribute the
32
+ Work and such Derivative Works in Source or Object form.
33
+
34
+ 3. Grant of Patent License. Subject to the terms and conditions of
35
+ this License, each Contributor hereby grants to You a perpetual,
36
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
37
+ patent license to make, have made, use, offer to sell, sell, import,
38
+ and otherwise transfer the Work.
39
+
40
+ 4-9. [Standard Apache 2.0 terms apply]
41
+
42
+ Copyright 2026 Quantum Learning Machines
43
+
44
+ Licensed under the Apache License, Version 2.0 (the "License");
45
+ you may not use this file except in compliance with the License.
46
+ You may obtain a copy of the License at
47
+
48
+ http://www.apache.org/licenses/LICENSE-2.0
49
+
50
+ Unless required by applicable law or agreed to in writing, software
51
+ distributed under the License is distributed on an "AS IS" BASIS,
52
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
53
+ See the License for the specific language governing permissions and
54
+ limitations under the License.
package/NOTICE ADDED
@@ -0,0 +1,13 @@
1
+ qlm-measure
2
+ Copyright 2026 Quantum Learning Machines
3
+
4
+ This product includes software developed at
5
+ Quantum Learning Machines (https://quantumlearningmachines.com).
6
+
7
+ This SDK provides the public interface layer for the QLM measurement
8
+ infrastructure. The estimation engine (Bayesian posteriors, IRT ability
9
+ estimation, calibration, and cognitive dimension tracking) is a separate
10
+ hosted service operated by Quantum Learning Machines.
11
+
12
+ The SDK itself (event schema, emitter, verifier, and dataset clients)
13
+ is licensed under the Apache License, Version 2.0.
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # @qlm/measure
2
+
3
+ Open measurement SDK for education AI — evidence events, record verification, and dataset clients.
4
+
5
+ **v0.1.0 · Apache-2.0 · [Documentation](https://play.quantumlearningmachines.com/developer) · [Manifesto](https://play.quantumlearningmachines.com/resources/open-measurement-layer)**
6
+
7
+ ## Limitations (read first)
8
+
9
+ - This SDK is the **public interface layer**, not the measurement engine. The estimation service (Bayesian posteriors, IRT ability estimation, calibration) is QLM's hosted engine.
10
+ - The verifier checks **bookkeeping integrity**, not estimation correctness. It can tell you if a record was tampered with. It cannot tell you if the posteriors are accurate. That distinction is the design.
11
+ - Evidence event schemas are **v0.1** and may change in minor versions. Pin your dependency.
12
+ - The ontology client requires the QLM API to be reachable. No offline mode.
13
+ - Classifier runners require model weights downloaded separately from Hugging Face.
14
+
15
+ ## What it is
16
+
17
+ 1. **Typed evidence-event vocabulary** (`ObservationEvent`) — a schema any tool can emit to describe a student interaction, with scaffold level, depth, epistemic mode.
18
+ 2. **Buffered telemetry emitter** (`MeasurementEmitter`) — sends events to the measurement service with sendBeacon fallback.
19
+ 3. **Evidence record format + replay verifier** (`verifyRecord`, `replayToVersion`) — audits a record's hash-chain and posterior-chain integrity without containing any estimation mathematics.
20
+ 4. **Dataset clients** (`OntologyClient`) — typed wrappers over the public misconception ontology, learning graph, and standards alignment APIs.
21
+ 5. **Engine client** (`EngineClient`) — commercial boundary for the hosted measurement service.
22
+
23
+ ## What it is NOT
24
+
25
+ - Not the estimation engine (that runs server-side at QLM)
26
+ - Not a standalone learning analytics system
27
+ - Not a replacement for the measurement service
28
+ - Not a classifier or scorer (those are separate open-weights releases)
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ npm install @qlm/measure
34
+ ```
35
+
36
+ ## Quickstart
37
+
38
+ ### 1. Query the misconception ontology (no auth)
39
+
40
+ ```typescript
41
+ import { OntologyClient } from "@qlm/measure/clients";
42
+
43
+ const client = new OntologyClient();
44
+ const misconceptions = await client.getMisconceptions("math");
45
+ console.log(`${misconceptions.length} math misconceptions`);
46
+ ```
47
+
48
+ ### 2. Emit measurement events
49
+
50
+ ```typescript
51
+ import { MeasurementEmitter } from "@qlm/measure/emitter";
52
+
53
+ const emitter = new MeasurementEmitter({
54
+ baseUrl: "https://play.quantumlearningmachines.com",
55
+ product: "my-tool",
56
+ });
57
+
58
+ emitter.emit({
59
+ eventType: "answer_submitted",
60
+ eventCategory: "learning",
61
+ domain: "math",
62
+ topic: "fractions",
63
+ payload: { questionId: "q1", correct: true },
64
+ });
65
+ ```
66
+
67
+ ### 3. Verify an evidence record (tamper detection)
68
+
69
+ ```typescript
70
+ import { verifyRecord } from "@qlm/measure/verifier";
71
+
72
+ const result = verifyRecord(record);
73
+ if (!result.valid) {
74
+ for (const v of result.violations) {
75
+ console.log(`[${v.category}] v${v.version}: ${v.message}`);
76
+ }
77
+ }
78
+ ```
79
+
80
+ ## Schema Reference
81
+
82
+ ### ObservationEvent (evidence input)
83
+
84
+ | Field | Type | Required | Description |
85
+ |-------|------|----------|-------------|
86
+ | studentId | string | yes | Pseudonymous ID (no PII) |
87
+ | sessionId | string | yes | Session identifier |
88
+ | source | string | yes | Source system |
89
+ | timestamp | string | yes | ISO 8601 |
90
+ | correct | boolean | yes | Was the response correct? |
91
+ | responseTimeMs | number | yes | Response time in ms |
92
+ | domain | string | yes | Subject domain |
93
+ | scaffoldType | ScaffoldType | no | What preceded this response |
94
+ | misconceptionId | string | no | Detected misconception ID |
95
+ | classifierConfidence | number | no | Classifier confidence (0-1) |
96
+ | skillId | string | no | Skill being assessed |
97
+ | score | number | no | Response score (0-1) |
98
+ | difficulty | number | no | Item difficulty (0-1) |
99
+ | epistemicMode | EpistemicMode | no | How student arrived at answer |
100
+ | ext | Record | no | Extension namespace |
101
+
102
+ ### Enums
103
+
104
+ **ScaffoldType:** `none`, `socratic`, `probing`, `metacognitive`, `scaffolding`, `explain`, `hint`, `demonstrate`
105
+
106
+ **EpistemicMode:** `experience`, `inference`, `analogy`, `testimony`
107
+
108
+ **DepthLevel:** `surface`, `conceptual`, `transfer`, `integration`
109
+
110
+ **TriageResult:** `correct`, `slip`, `misconception`, `disengagement`, `ambiguous`
111
+
112
+ ## Verifier
113
+
114
+ The verifier checks:
115
+ - Schema validity (required fields, correct types)
116
+ - Strictly monotonic version numbers
117
+ - Timestamp monotonicity (configurable tolerance)
118
+ - Hash-chain integrity (prevHash linkage, entryHash recompute)
119
+ - Posterior chain consistency (each prior = previous updated)
120
+ - Compaction-boundary integrity
121
+ - Enum validity
122
+
123
+ What it deliberately **cannot** check:
124
+ - Whether posteriors are correctly computed (that requires the engine)
125
+ - Whether evidential weights are appropriate (those are calibrated server-side)
126
+ - Whether triage classifications are accurate (those use rules not in this package)
127
+
128
+ This is the design: **verify instead of trust**.
129
+
130
+ ## Privacy
131
+
132
+ - `studentId` MUST be a pseudonymous identifier. Never include names, emails, or other PII.
133
+ - Events are buffered locally and sent via sendBeacon/fetch. No cookies are set.
134
+ - The SDK does not store any data persistently.
135
+
136
+ ## Versioning
137
+
138
+ - Semver from 0.1.0.
139
+ - Schema changes in minor versions (0.2, 0.3).
140
+ - Breaking changes in major versions (1.0).
141
+ - Pin your dependency version.
142
+
143
+ ## Links
144
+
145
+ - [Developer portal](https://play.quantumlearningmachines.com/developer)
146
+ - [Open Measurement Manifesto](https://play.quantumlearningmachines.com/resources/open-measurement-layer)
147
+ - [Misconception ontology](https://play.quantumlearningmachines.com/developer)
148
+ - [Model cards on Hugging Face](https://huggingface.co/QuantumLearningMachines)
149
+
150
+ ## License
151
+
152
+ Apache-2.0. See [LICENSE](./LICENSE).
@@ -0,0 +1,51 @@
1
+ /**
2
+ * EngineClient — Commercial boundary for the QLM measurement engine.
3
+ *
4
+ * The estimation service is QLM's hosted engine. This client wraps the
5
+ * API for submitting observations and retrieving student model state.
6
+ *
7
+ * Authentication is required. Contact QLM for API access.
8
+ */
9
+ import type { ObservationEvent } from "../schema/observation-event";
10
+ export interface EngineClientConfig {
11
+ /** Base URL of the QLM measurement service. */
12
+ baseUrl: string;
13
+ /** API key for authentication. */
14
+ apiKey: string;
15
+ }
16
+ export interface ModelStateSummary {
17
+ studentId: string;
18
+ totalSessions: number;
19
+ totalEvidenceEvents: number;
20
+ lastSessionAt: string | null;
21
+ /** Top misconceptions with posterior > 0.3 */
22
+ activeMisconceptions: Array<{
23
+ id: string;
24
+ posterior: number;
25
+ persistence: string;
26
+ detections: number;
27
+ }>;
28
+ /** Triage summary */
29
+ triage: {
30
+ correct: number;
31
+ slips: number;
32
+ misconceptions: number;
33
+ disengagements: number;
34
+ };
35
+ }
36
+ export declare class EngineClient {
37
+ private readonly config;
38
+ constructor(config: EngineClientConfig);
39
+ /**
40
+ * Submit a student observation to the measurement engine.
41
+ *
42
+ * The engine runs the full measurement pipeline and returns
43
+ * a summary of the updated state.
44
+ */
45
+ updateStudentModel(observation: ObservationEvent): Promise<ModelStateSummary>;
46
+ /**
47
+ * Retrieve the current model state for a student.
48
+ */
49
+ getState(studentId: string): Promise<ModelStateSummary>;
50
+ }
51
+ //# sourceMappingURL=engine-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-client.d.ts","sourceRoot":"","sources":["../../src/clients/engine-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,MAAM,WAAW,kBAAkB;IACjC,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,8CAA8C;IAC9C,oBAAoB,EAAE,KAAK,CAAC;QAC1B,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,qBAAqB;IACrB,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;gBAEhC,MAAM,EAAE,kBAAkB;IAItC;;;;;OAKG;IACG,kBAAkB,CAAC,WAAW,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA0BnF;;OAEG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAiB9D"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * EngineClient — Commercial boundary for the QLM measurement engine.
3
+ *
4
+ * The estimation service is QLM's hosted engine. This client wraps the
5
+ * API for submitting observations and retrieving student model state.
6
+ *
7
+ * Authentication is required. Contact QLM for API access.
8
+ */
9
+ import { toPublicEpistemicMode } from "../schema/enums";
10
+ export class EngineClient {
11
+ config;
12
+ constructor(config) {
13
+ this.config = config;
14
+ }
15
+ /**
16
+ * Submit a student observation to the measurement engine.
17
+ *
18
+ * The engine runs the full measurement pipeline and returns
19
+ * a summary of the updated state.
20
+ */
21
+ async updateStudentModel(observation) {
22
+ // Map public epistemic mode to internal at the boundary
23
+ const mapped = {
24
+ ...observation,
25
+ epistemicMode: observation.epistemicMode
26
+ ? toPublicEpistemicMode(observation.epistemicMode)
27
+ : undefined,
28
+ };
29
+ const response = await fetch(`${this.config.baseUrl}/api/student-model/update`, {
30
+ method: "POST",
31
+ headers: {
32
+ "Content-Type": "application/json",
33
+ "Authorization": `Bearer ${this.config.apiKey}`,
34
+ },
35
+ body: JSON.stringify(mapped),
36
+ });
37
+ if (!response.ok) {
38
+ const body = await response.text().catch(() => "");
39
+ throw new Error(`EngineClient.updateStudentModel: ${response.status} ${response.statusText} — ${body}`);
40
+ }
41
+ return response.json();
42
+ }
43
+ /**
44
+ * Retrieve the current model state for a student.
45
+ */
46
+ async getState(studentId) {
47
+ const response = await fetch(`${this.config.baseUrl}/api/student-model/state?studentId=${encodeURIComponent(studentId)}`, {
48
+ headers: {
49
+ "Authorization": `Bearer ${this.config.apiKey}`,
50
+ },
51
+ });
52
+ if (!response.ok) {
53
+ const body = await response.text().catch(() => "");
54
+ throw new Error(`EngineClient.getState: ${response.status} ${response.statusText} — ${body}`);
55
+ }
56
+ return response.json();
57
+ }
58
+ }
59
+ //# sourceMappingURL=engine-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-client.js","sourceRoot":"","sources":["../../src/clients/engine-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AA8BxD,MAAM,OAAO,YAAY;IACN,MAAM,CAAqB;IAE5C,YAAY,MAA0B;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,kBAAkB,CAAC,WAA6B;QACpD,wDAAwD;QACxD,MAAM,MAAM,GAAG;YACb,GAAG,WAAW;YACd,aAAa,EAAE,WAAW,CAAC,aAAa;gBACtC,CAAC,CAAC,qBAAqB,CAAC,WAAW,CAAC,aAAa,CAAC;gBAClD,CAAC,CAAC,SAAS;SACd,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,2BAA2B,EAAE;YAC9E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;aAChD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;SAC7B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,MAAM,IAAI,EAAE,CAAC,CAAC;QAC1G,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,SAAiB;QAC9B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,sCAAsC,kBAAkB,CAAC,SAAS,CAAC,EAAE,EAC3F;YACE,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;aAChD;SACF,CACF,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,MAAM,IAAI,EAAE,CAAC,CAAC;QAChG,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgC,CAAC;IACvD,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ export { OntologyClient } from "./ontology-client";
2
+ export type { OntologyClientConfig, DatasetName, MisconceptionEntry, LearningGraphNode, StandardAlignment } from "./ontology-client";
3
+ export { EngineClient } from "./engine-client";
4
+ export type { EngineClientConfig, ModelStateSummary } from "./engine-client";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/clients/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,WAAW,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACrI,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { OntologyClient } from "./ontology-client";
2
+ export { EngineClient } from "./engine-client";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/clients/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * OntologyClient — Typed wrapper over the QLM dataset export API.
3
+ *
4
+ * Zero-auth. Queries the public misconception ontology, learning graph,
5
+ * and standards alignment datasets.
6
+ */
7
+ export type DatasetName = "misconceptions" | "learning-graph" | "standards" | "assistments-alignment";
8
+ export interface OntologyClientConfig {
9
+ /** Base URL of the QLM API. Default: https://play.quantumlearningmachines.com */
10
+ baseUrl?: string;
11
+ }
12
+ export interface MisconceptionEntry {
13
+ id: string;
14
+ domain: string;
15
+ topic: string;
16
+ label: string;
17
+ description: string;
18
+ triggerPatterns: string[];
19
+ correctivePrompts: string[];
20
+ gradeRange?: string;
21
+ severity?: string;
22
+ }
23
+ export interface LearningGraphNode {
24
+ id: string;
25
+ label: string;
26
+ domain: string;
27
+ prerequisites: string[];
28
+ relatedMisconceptions: string[];
29
+ }
30
+ export interface StandardAlignment {
31
+ standardCode: string;
32
+ framework: string;
33
+ description: string;
34
+ mappedConstructIds: string[];
35
+ }
36
+ export declare class OntologyClient {
37
+ private readonly baseUrl;
38
+ constructor(config?: OntologyClientConfig);
39
+ /**
40
+ * Fetch a dataset from the public export API.
41
+ *
42
+ * @param dataset The dataset name to fetch.
43
+ * @param options Optional query parameters (domain, format).
44
+ * @returns Parsed JSON response.
45
+ */
46
+ fetchDataset<T = unknown>(dataset: DatasetName, options?: {
47
+ domain?: string;
48
+ format?: string;
49
+ }): Promise<T>;
50
+ /** Fetch the misconception ontology. */
51
+ getMisconceptions(domain?: string): Promise<MisconceptionEntry[]>;
52
+ /** Fetch the learning graph. */
53
+ getLearningGraph(domain?: string): Promise<LearningGraphNode[]>;
54
+ /** Fetch standards alignment data. */
55
+ getStandards(domain?: string): Promise<StandardAlignment[]>;
56
+ }
57
+ //# sourceMappingURL=ontology-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ontology-client.d.ts","sourceRoot":"","sources":["../../src/clients/ontology-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,WAAW,GACnB,gBAAgB,GAChB,gBAAgB,GAChB,WAAW,GACX,uBAAuB,CAAC;AAE5B,MAAM,WAAW,oBAAoB;IACnC,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,CAAC,EAAE,oBAAoB;IAIzC;;;;;;OAMG;IACG,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5B,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,CAAC,CAAC;IAiBb,wCAAwC;IAClC,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAIvE,gCAAgC;IAC1B,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAIrE,sCAAsC;IAChC,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;CAGlE"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * OntologyClient — Typed wrapper over the QLM dataset export API.
3
+ *
4
+ * Zero-auth. Queries the public misconception ontology, learning graph,
5
+ * and standards alignment datasets.
6
+ */
7
+ export class OntologyClient {
8
+ baseUrl;
9
+ constructor(config) {
10
+ this.baseUrl = config?.baseUrl ?? "https://play.quantumlearningmachines.com";
11
+ }
12
+ /**
13
+ * Fetch a dataset from the public export API.
14
+ *
15
+ * @param dataset The dataset name to fetch.
16
+ * @param options Optional query parameters (domain, format).
17
+ * @returns Parsed JSON response.
18
+ */
19
+ async fetchDataset(dataset, options) {
20
+ const params = new URLSearchParams({ dataset });
21
+ if (options?.domain)
22
+ params.set("domain", options.domain);
23
+ if (options?.format)
24
+ params.set("format", options.format);
25
+ const url = `${this.baseUrl}/api/labpath/dataset-export?${params.toString()}`;
26
+ const response = await fetch(url, {
27
+ headers: { Accept: "application/json" },
28
+ });
29
+ if (!response.ok) {
30
+ throw new Error(`OntologyClient: ${response.status} ${response.statusText} for ${dataset}`);
31
+ }
32
+ return response.json();
33
+ }
34
+ /** Fetch the misconception ontology. */
35
+ async getMisconceptions(domain) {
36
+ return this.fetchDataset("misconceptions", { domain });
37
+ }
38
+ /** Fetch the learning graph. */
39
+ async getLearningGraph(domain) {
40
+ return this.fetchDataset("learning-graph", { domain });
41
+ }
42
+ /** Fetch standards alignment data. */
43
+ async getStandards(domain) {
44
+ return this.fetchDataset("standards", { domain });
45
+ }
46
+ }
47
+ //# sourceMappingURL=ontology-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ontology-client.js","sourceRoot":"","sources":["../../src/clients/ontology-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwCH,MAAM,OAAO,cAAc;IACR,OAAO,CAAS;IAEjC,YAAY,MAA6B;QACvC,IAAI,CAAC,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,0CAA0C,CAAC;IAC/E,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,YAAY,CAChB,OAAoB,EACpB,OAA8C;QAE9C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;QAChD,IAAI,OAAO,EAAE,MAAM;YAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1D,IAAI,OAAO,EAAE,MAAM;YAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAE1D,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,+BAA+B,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;QAC9E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;SACxC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,QAAQ,OAAO,EAAE,CAAC,CAAC;QAC9F,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;IACvC,CAAC;IAED,wCAAwC;IACxC,KAAK,CAAC,iBAAiB,CAAC,MAAe;QACrC,OAAO,IAAI,CAAC,YAAY,CAAuB,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,gCAAgC;IAChC,KAAK,CAAC,gBAAgB,CAAC,MAAe;QACpC,OAAO,IAAI,CAAC,YAAY,CAAsB,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,sCAAsC;IACtC,KAAK,CAAC,YAAY,CAAC,MAAe;QAChC,OAAO,IAAI,CAAC,YAAY,CAAsB,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export { MeasurementEmitter } from "./measurement-emitter";
2
+ export type { EmitterConfig } from "./measurement-emitter";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/emitter/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { MeasurementEmitter } from "./measurement-emitter";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/emitter/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Measurement Emitter — Buffered telemetry for the open measurement layer.
3
+ *
4
+ * Buffers events and flushes via sendBeacon (browser) or fetch (Node).
5
+ * Survives page unload. Configurable endpoint and buffer size.
6
+ */
7
+ import type { MeasurementEvent } from "../schema/measurement-event";
8
+ export interface EmitterConfig {
9
+ /** Base URL of the measurement service. */
10
+ baseUrl: string;
11
+ /** API key for authentication (optional for public endpoints). */
12
+ apiKey?: string;
13
+ /** Product identifier. */
14
+ product?: string;
15
+ /** Maximum events to buffer before auto-flush. Default: 20. */
16
+ bufferSize?: number;
17
+ /** Flush interval in milliseconds. Default: 5000. */
18
+ flushIntervalMs?: number;
19
+ }
20
+ export declare class MeasurementEmitter {
21
+ private buffer;
22
+ private timer;
23
+ private readonly config;
24
+ private readonly ingestUrl;
25
+ constructor(config: EmitterConfig);
26
+ /** Emit a measurement event. Buffered until flush. */
27
+ emit(event: MeasurementEvent): void;
28
+ /** Flush all buffered events to the measurement service. */
29
+ flush(): void;
30
+ /** Stop the auto-flush timer. */
31
+ destroy(): void;
32
+ }
33
+ //# sourceMappingURL=measurement-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measurement-emitter.d.ts","sourceRoot":"","sources":["../../src/emitter/measurement-emitter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAWD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,EAAE,aAAa;IAmBjC,sDAAsD;IACtD,IAAI,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAgBnC,4DAA4D;IAC5D,KAAK,IAAI,IAAI;IA2Cb,iCAAiC;IACjC,OAAO,IAAI,IAAI;CAOhB"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Measurement Emitter — Buffered telemetry for the open measurement layer.
3
+ *
4
+ * Buffers events and flushes via sendBeacon (browser) or fetch (Node).
5
+ * Survives page unload. Configurable endpoint and buffer size.
6
+ */
7
+ function generateEventId(product) {
8
+ return `${product}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
9
+ }
10
+ export class MeasurementEmitter {
11
+ buffer = [];
12
+ timer = null;
13
+ config;
14
+ ingestUrl;
15
+ constructor(config) {
16
+ this.config = {
17
+ baseUrl: config.baseUrl,
18
+ apiKey: config.apiKey ?? "",
19
+ product: config.product ?? "external",
20
+ bufferSize: config.bufferSize ?? 20,
21
+ flushIntervalMs: config.flushIntervalMs ?? 5000,
22
+ };
23
+ this.ingestUrl = `${this.config.baseUrl}/api/measurement/ingest`;
24
+ // Auto-flush on page visibility change (browser only)
25
+ if (typeof window !== "undefined") {
26
+ window.addEventListener("visibilitychange", () => {
27
+ if (document.visibilityState === "hidden")
28
+ this.flush();
29
+ });
30
+ window.addEventListener("pagehide", () => this.flush());
31
+ }
32
+ }
33
+ /** Emit a measurement event. Buffered until flush. */
34
+ emit(event) {
35
+ this.buffer.push({
36
+ ...event,
37
+ event_id: generateEventId(this.config.product),
38
+ created_at: new Date().toISOString(),
39
+ });
40
+ if (this.buffer.length >= this.config.bufferSize) {
41
+ this.flush();
42
+ }
43
+ if (!this.timer) {
44
+ this.timer = setInterval(() => this.flush(), this.config.flushIntervalMs);
45
+ }
46
+ }
47
+ /** Flush all buffered events to the measurement service. */
48
+ flush() {
49
+ if (this.buffer.length === 0)
50
+ return;
51
+ const batch = this.buffer.splice(0);
52
+ const body = JSON.stringify({
53
+ product: this.config.product,
54
+ events: batch.map((e) => ({
55
+ event_id: e.event_id,
56
+ event_type: e.eventType,
57
+ event_category: e.eventCategory,
58
+ session_id: e.sessionId ?? null,
59
+ classroom_id: e.classroomId ?? null,
60
+ domain: e.domain ?? null,
61
+ topic: e.topic ?? null,
62
+ mode: e.mode ?? null,
63
+ difficulty: e.difficulty ?? null,
64
+ payload: e.payload ?? {},
65
+ quality_signal: e.qualitySignal ?? null,
66
+ confidence: e.confidence ?? null,
67
+ duration_ms: e.durationMs ?? null,
68
+ parent_event_id: e.parentEventId ?? null,
69
+ created_at: e.created_at,
70
+ })),
71
+ });
72
+ const headers = { "Content-Type": "application/json" };
73
+ if (this.config.apiKey) {
74
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
75
+ }
76
+ // sendBeacon in browser (survives page unload)
77
+ if (typeof navigator !== "undefined" && navigator.sendBeacon) {
78
+ navigator.sendBeacon(this.ingestUrl, new Blob([body], { type: "application/json" }));
79
+ }
80
+ else {
81
+ fetch(this.ingestUrl, {
82
+ method: "POST",
83
+ headers,
84
+ body,
85
+ keepalive: true,
86
+ }).catch(() => { });
87
+ }
88
+ }
89
+ /** Stop the auto-flush timer. */
90
+ destroy() {
91
+ if (this.timer) {
92
+ clearInterval(this.timer);
93
+ this.timer = null;
94
+ }
95
+ this.flush();
96
+ }
97
+ }
98
+ //# sourceMappingURL=measurement-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measurement-emitter.js","sourceRoot":"","sources":["../../src/emitter/measurement-emitter.ts"],"names":[],"mappings":"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"}