@seanhogg/builderforce-memory-engine 2026.10.1 → 2026.10.3

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 (149) hide show
  1. package/dist/evermind/adapt.d.ts +7 -0
  2. package/dist/evermind/adapt.d.ts.map +1 -1
  3. package/dist/evermind/adapt.js +1 -1
  4. package/dist/evermind/adapt.js.map +1 -1
  5. package/dist/evermind/delta_wire.d.ts +16 -1
  6. package/dist/evermind/delta_wire.d.ts.map +1 -1
  7. package/dist/evermind/delta_wire.js +22 -2
  8. package/dist/evermind/delta_wire.js.map +1 -1
  9. package/dist/evermind/index.d.ts +2 -2
  10. package/dist/evermind/index.d.ts.map +1 -1
  11. package/dist/evermind/index.js +1 -1
  12. package/dist/evermind/index.js.map +1 -1
  13. package/dist/evermind/merge.d.ts +5 -2
  14. package/dist/evermind/merge.d.ts.map +1 -1
  15. package/dist/evermind/merge.js +5 -2
  16. package/dist/evermind/merge.js.map +1 -1
  17. package/dist/evermind/ml_head.d.ts +28 -0
  18. package/dist/evermind/ml_head.d.ts.map +1 -0
  19. package/dist/evermind/ml_head.js +47 -0
  20. package/dist/evermind/ml_head.js.map +1 -0
  21. package/dist/evermind/package.d.ts +2 -2
  22. package/dist/evermind/package.d.ts.map +1 -1
  23. package/dist/evermind/package.js +1 -1
  24. package/dist/evermind/package.js.map +1 -1
  25. package/dist/experience/index.d.ts +2 -2
  26. package/dist/experience/index.d.ts.map +1 -1
  27. package/dist/experience/index.js.map +1 -1
  28. package/dist/experience/store.d.ts +19 -1
  29. package/dist/experience/store.d.ts.map +1 -1
  30. package/dist/experience/store.js +14 -2
  31. package/dist/experience/store.js.map +1 -1
  32. package/dist/experience/types.d.ts +18 -0
  33. package/dist/experience/types.d.ts.map +1 -1
  34. package/dist/experience/types.js.map +1 -1
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/kernels/weight_update.d.ts.map +1 -1
  40. package/dist/kernels/weight_update.js +12 -0
  41. package/dist/kernels/weight_update.js.map +1 -1
  42. package/dist/limbic/limbic_model.d.ts.map +1 -1
  43. package/dist/limbic/limbic_model.js +1 -3
  44. package/dist/limbic/limbic_model.js.map +1 -1
  45. package/dist/ml/classical/anomaly_composite.d.ts +32 -0
  46. package/dist/ml/classical/anomaly_composite.d.ts.map +1 -0
  47. package/dist/ml/classical/anomaly_composite.js +29 -0
  48. package/dist/ml/classical/anomaly_composite.js.map +1 -0
  49. package/dist/ml/classical/ewma.d.ts +7 -1
  50. package/dist/ml/classical/ewma.d.ts.map +1 -1
  51. package/dist/ml/classical/ewma.js +6 -4
  52. package/dist/ml/classical/ewma.js.map +1 -1
  53. package/dist/ml/classical/gbm.d.ts.map +1 -1
  54. package/dist/ml/classical/gbm.js +2 -1
  55. package/dist/ml/classical/gbm.js.map +1 -1
  56. package/dist/ml/classical/index.d.ts +6 -2
  57. package/dist/ml/classical/index.d.ts.map +1 -1
  58. package/dist/ml/classical/index.js +5 -1
  59. package/dist/ml/classical/index.js.map +1 -1
  60. package/dist/ml/classical/kmeans.d.ts.map +1 -1
  61. package/dist/ml/classical/kmeans.js +23 -4
  62. package/dist/ml/classical/kmeans.js.map +1 -1
  63. package/dist/ml/classical/knn.d.ts +15 -5
  64. package/dist/ml/classical/knn.d.ts.map +1 -1
  65. package/dist/ml/classical/knn.js +28 -7
  66. package/dist/ml/classical/knn.js.map +1 -1
  67. package/dist/ml/classical/logistic.d.ts +1 -9
  68. package/dist/ml/classical/logistic.d.ts.map +1 -1
  69. package/dist/ml/classical/logistic.js +17 -9
  70. package/dist/ml/classical/logistic.js.map +1 -1
  71. package/dist/ml/classical/naive_bayes.d.ts +5 -1
  72. package/dist/ml/classical/naive_bayes.d.ts.map +1 -1
  73. package/dist/ml/classical/naive_bayes.js +8 -3
  74. package/dist/ml/classical/naive_bayes.js.map +1 -1
  75. package/dist/ml/classical/robust_z.d.ts +15 -1
  76. package/dist/ml/classical/robust_z.d.ts.map +1 -1
  77. package/dist/ml/classical/robust_z.js +6 -1
  78. package/dist/ml/classical/robust_z.js.map +1 -1
  79. package/dist/ml/eval_loss.d.ts +15 -0
  80. package/dist/ml/eval_loss.d.ts.map +1 -0
  81. package/dist/ml/eval_loss.js +20 -0
  82. package/dist/ml/eval_loss.js.map +1 -0
  83. package/dist/ml/federate.d.ts +11 -25
  84. package/dist/ml/federate.d.ts.map +1 -1
  85. package/dist/ml/federate.js +15 -38
  86. package/dist/ml/federate.js.map +1 -1
  87. package/dist/ml/head_trainer.d.ts +16 -2
  88. package/dist/ml/head_trainer.d.ts.map +1 -1
  89. package/dist/ml/head_trainer.js +64 -27
  90. package/dist/ml/head_trainer.js.map +1 -1
  91. package/dist/ml/run.d.ts +11 -2
  92. package/dist/ml/run.d.ts.map +1 -1
  93. package/dist/ml/run.js +56 -17
  94. package/dist/ml/run.js.map +1 -1
  95. package/dist/ml/tasks/experience.d.ts +95 -13
  96. package/dist/ml/tasks/experience.d.ts.map +1 -1
  97. package/dist/ml/tasks/experience.js +172 -20
  98. package/dist/ml/tasks/experience.js.map +1 -1
  99. package/dist/ml/tasks/run_anomaly.d.ts +37 -19
  100. package/dist/ml/tasks/run_anomaly.d.ts.map +1 -1
  101. package/dist/ml/tasks/run_anomaly.js +50 -31
  102. package/dist/ml/tasks/run_anomaly.js.map +1 -1
  103. package/dist/ml/train.d.ts +8 -7
  104. package/dist/ml/train.d.ts.map +1 -1
  105. package/dist/ml/train.js +21 -30
  106. package/dist/ml/train.js.map +1 -1
  107. package/dist/ml/types.d.ts +6 -3
  108. package/dist/ml/types.d.ts.map +1 -1
  109. package/dist/ml/types.js +3 -2
  110. package/dist/ml/types.js.map +1 -1
  111. package/dist/optim/adamw.d.ts +11 -5
  112. package/dist/optim/adamw.d.ts.map +1 -1
  113. package/dist/optim/adamw.js +19 -4
  114. package/dist/optim/adamw.js.map +1 -1
  115. package/package.json +1 -1
  116. package/src/evermind/adapt.ts +8 -2
  117. package/src/evermind/delta_wire.ts +173 -148
  118. package/src/evermind/index.ts +36 -35
  119. package/src/evermind/merge.ts +10 -4
  120. package/src/evermind/ml_head.ts +63 -0
  121. package/src/evermind/package.ts +488 -488
  122. package/src/experience/index.ts +2 -1
  123. package/src/experience/store.ts +35 -3
  124. package/src/experience/types.ts +19 -0
  125. package/src/index.ts +2 -0
  126. package/src/kernels/weight_update.ts +12 -0
  127. package/src/limbic/limbic_model.ts +1 -4
  128. package/src/limbic/limbic_trainer.ts +91 -91
  129. package/src/ml/classical/anomaly_composite.ts +46 -0
  130. package/src/ml/classical/ewma.ts +8 -2
  131. package/src/ml/classical/gbm.ts +144 -143
  132. package/src/ml/classical/index.ts +8 -2
  133. package/src/ml/classical/kmeans.ts +22 -4
  134. package/src/ml/classical/knn.ts +31 -8
  135. package/src/ml/classical/logistic.ts +9 -9
  136. package/src/ml/classical/math.ts +93 -93
  137. package/src/ml/classical/naive_bayes.ts +10 -3
  138. package/src/ml/classical/robust_z.ts +21 -2
  139. package/src/ml/eval_loss.ts +27 -0
  140. package/src/ml/federate.ts +22 -52
  141. package/src/ml/head_trainer.ts +66 -48
  142. package/src/ml/registry.ts +44 -44
  143. package/src/ml/run.ts +57 -13
  144. package/src/ml/tasks/experience.ts +222 -23
  145. package/src/ml/tasks/run_anomaly.ts +62 -37
  146. package/src/ml/train.ts +34 -31
  147. package/src/ml/types.ts +135 -132
  148. package/src/optim/adamw.ts +21 -5
  149. package/src/training/cpu_ops.ts +141 -141
@@ -1,488 +1,488 @@
1
- /**
2
- * evermind/package.ts — EvermindModelPackage: the portable, publishable AI artifact.
3
- *
4
- * This is the unit a creator publishes to the marketplace and a buyer downloads
5
- * and runs: a self-describing manifest (name, version, config, model card,
6
- * integrity checksum) bundled with the trained checkpoint into one `.evermind`
7
- * blob. It is the contract every downstream consumer (marketplace listing,
8
- * purchase entitlement, workflow generator) reads — define it once, here.
9
- *
10
- * Zero-dep and isomorphic: serialises via TextEncoder/TextDecoder, runs in the
11
- * browser (where models are trained) and in Node/Workers (where they execute).
12
- */
13
-
14
- import { SharedExpertMoE, type MoEConfig } from "../moe/moe_model.js";
15
- import { EvermindLM, type EvermindLMConfig } from "../lm/evermind_lm.js";
16
- import { VideoRVQCodec } from "../codec/video_rvq.js";
17
- import { BPETokenizer } from "../tokenizer/bpe.js";
18
- import { mlHeadUnusableReason, type EvermindMlHead } from "../ml/federate.js";
19
-
20
- export type { EvermindMlHead } from "../ml/federate.js";
21
-
22
- /** First 4 bytes of a serialised package: "EVM1". */
23
- const PKG_MAGIC = 0x45564d31;
24
- /** magic, format version, manifest length — three u32s ahead of the manifest. */
25
- export const PACKAGE_HEADER_BYTES = 12;
26
- const PKG_VERSION = 1;
27
-
28
- /** The kinds of model an `.evermind` package can carry. */
29
- export type EvermindModelType = "shared-expert-moe" | "evermind-lm";
30
-
31
- /** Output modality. `text` (default) needs no codec; `video`/`image` bundle a VRQ codec. */
32
- export type EvermindModality = "text" | "video" | "image";
33
-
34
- /** Human-facing description published with the model (the "model card"). */
35
- export interface EvermindModelCard {
36
- description: string;
37
- /** What it was trained on / intended for. */
38
- trainingSummary?: string;
39
- /** SPDX id or free text (e.g. "MIT", "proprietary"). */
40
- license?: string;
41
- author?: string;
42
- tags?: string[];
43
- }
44
-
45
- /** Self-describing header for a published Evermind model. */
46
- export interface EvermindModelManifest {
47
- schema: "evermind.model/1";
48
- name: string;
49
- version: string;
50
- modelType: EvermindModelType;
51
- /** Output modality; absent ⇒ "text". Video/image also carry a `codec` section. */
52
- modality?: EvermindModality;
53
- /** Flat numeric model config (the constructor args), serialised verbatim. */
54
- config: Record<string, number>;
55
- /** Total trainable scalar parameters (for sizing / pricing / display). */
56
- paramCount: number;
57
- checkpointFormat: "MoE0" | "EVL0";
58
- checkpointFp16: boolean;
59
- /**
60
- * Byte length of the checkpoint section — REQUIRED when a codec section follows
61
- * (so the reader knows where the checkpoint ends). Absent ⇒ checkpoint runs to
62
- * end-of-blob (the original text-only layout, still read verbatim).
63
- */
64
- checkpointBytes?: number;
65
- /** 32-bit FNV-1a over the checkpoint bytes — integrity for download/purchase. */
66
- checksum: number;
67
- /** Media codec section format (present for video/image packages). */
68
- codecFormat?: "VRQ0";
69
- /**
70
- * Byte length of the codec section — REQUIRED when a tokenizer section follows.
71
- * Absent ⇒ the codec runs to end-of-blob (the original media layout).
72
- */
73
- codecBytes?: number;
74
- /** 32-bit FNV-1a over the codec bytes — integrity for the bundled codec. */
75
- codecChecksum?: number;
76
- /**
77
- * Embedded-tokenizer section format. Token ids are meaningless without the exact
78
- * vocabulary that produced them, so a package that carries one is self-contained:
79
- * a consumer no longer has to source the matching vocab separately (and can no
80
- * longer pair the wrong one with it). Absent ⇒ no tokenizer embedded, which every
81
- * package written before this field is — those still load exactly as before.
82
- */
83
- tokenizerFormat?: "BPE0";
84
- /** Byte length of the tokenizer section (always last). */
85
- tokenizerBytes?: number;
86
- /** 32-bit FNV-1a over the tokenizer bytes. */
87
- tokenizerChecksum?: number;
88
- /** Vocabulary size of the embedded tokenizer — cross-checked against the model's. */
89
- tokenizerVocabSize?: number;
90
- card: EvermindModelCard;
91
- /** ISO timestamp, caller-supplied (the engine avoids Date for determinism). */
92
- createdAt?: string;
93
- /** Trained ML-catalog heads that travel (and merge) with this model. Absent ⇒ none. */
94
- mlHeads?: EvermindMlHead[];
95
- }
96
-
97
- export interface PackageMeta {
98
- name: string;
99
- version: string;
100
- card: EvermindModelCard;
101
- /** Store the checkpoint in fp16 (half the size). Default false. */
102
- fp16?: boolean;
103
- /**
104
- * Embed this tokenizer in the package, making the artifact self-contained.
105
- * Its `vocabSize` must equal the model's, or packaging throws — a mismatched
106
- * pair produces confident nonsense, which is worse than a failure to publish.
107
- */
108
- tokenizer?: BPETokenizer;
109
- createdAt?: string;
110
- }
111
-
112
- export interface ValidationResult {
113
- ok: boolean;
114
- errors: string[];
115
- }
116
-
117
- /** 32-bit FNV-1a hash — dependency-free integrity check over the checkpoint. */
118
- function fnv1a(bytes: Uint8Array): number {
119
- let h = 0x811c9dc5;
120
- for (let i = 0; i < bytes.length; i++) {
121
- h ^= bytes[i]!;
122
- h = Math.imul(h, 0x01000193);
123
- }
124
- return h >>> 0;
125
- }
126
-
127
- /**
128
- * A trained model packaged for publishing: manifest + checkpoint. Build one with
129
- * {@link EvermindModelPackage.fromModel}, ship {@link toBlob}, and a buyer
130
- * reconstitutes it with {@link fromBlob} → {@link validate} → {@link loadModel}.
131
- */
132
- export class EvermindModelPackage {
133
- constructor(
134
- readonly manifest: EvermindModelManifest,
135
- readonly checkpoint: ArrayBuffer,
136
- /** Serialized media codec ("VRQ0" blob), present for video/image packages. */
137
- readonly codec?: ArrayBuffer,
138
- /** Serialized BPE tokenizer ("BPE0" blob) — present when the package embeds one. */
139
- readonly tokenizer?: ArrayBuffer,
140
- ) {}
141
-
142
- /**
143
- * Serialise `meta.tokenizer` and the manifest fields describing it, or `{}` when
144
- * no tokenizer was supplied. Shared by every `from*` factory so the vocab-size
145
- * cross-check exists in exactly one place.
146
- */
147
- private static _tokenizerSection(
148
- meta: PackageMeta,
149
- modelVocabSize: number | undefined,
150
- ): { blob?: ArrayBuffer; fields: Partial<EvermindModelManifest> } {
151
- if (!meta.tokenizer) return { fields: {} };
152
- const vocabSize = meta.tokenizer.vocabSize;
153
- if (modelVocabSize != null && vocabSize !== modelVocabSize) {
154
- throw new Error(
155
- `EvermindModelPackage: tokenizer vocabSize (${vocabSize}) must equal the model's (${modelVocabSize}) — ` +
156
- "a mismatched pair decodes to nonsense.",
157
- );
158
- }
159
- const blob = meta.tokenizer.serialize();
160
- return {
161
- blob,
162
- fields: {
163
- tokenizerFormat: "BPE0",
164
- tokenizerBytes: blob.byteLength,
165
- tokenizerChecksum: fnv1a(new Uint8Array(blob)),
166
- tokenizerVocabSize: vocabSize,
167
- },
168
- };
169
- }
170
-
171
- /** Package a trained model with its publishing metadata. */
172
- static fromModel(model: SharedExpertMoE, meta: PackageMeta): EvermindModelPackage {
173
- const fp16 = meta.fp16 ?? false;
174
- const checkpoint = model.exportWeights({ fp16 });
175
- // A bare MoE layer has no vocabulary of its own, so there is nothing to cross-check.
176
- const tokenizer = EvermindModelPackage._tokenizerSection(meta, undefined);
177
- const manifest: EvermindModelManifest = {
178
- schema: "evermind.model/1",
179
- name: meta.name,
180
- version: meta.version,
181
- modelType: "shared-expert-moe",
182
- config: model.config,
183
- paramCount: model.parameters().reduce((n, p) => n + p.numel, 0),
184
- checkpointFormat: "MoE0",
185
- checkpointFp16: fp16,
186
- ...(tokenizer.blob ? { checkpointBytes: checkpoint.byteLength } : {}),
187
- checksum: fnv1a(new Uint8Array(checkpoint)),
188
- ...tokenizer.fields,
189
- card: meta.card,
190
- ...(meta.createdAt ? { createdAt: meta.createdAt } : {}),
191
- };
192
- return new EvermindModelPackage(manifest, checkpoint, undefined, tokenizer.blob);
193
- }
194
-
195
- /** Package a trained generative {@link EvermindLM} — the runnable marketplace AI. */
196
- static fromLM(lm: EvermindLM, meta: PackageMeta): EvermindModelPackage {
197
- const fp16 = meta.fp16 ?? false;
198
- const checkpoint = lm.exportWeights({ fp16 });
199
- const tokenizer = EvermindModelPackage._tokenizerSection(meta, lm.config.vocabSize);
200
- const manifest: EvermindModelManifest = {
201
- schema: "evermind.model/1",
202
- name: meta.name,
203
- version: meta.version,
204
- modelType: "evermind-lm",
205
- config: lm.config as unknown as Record<string, number>,
206
- paramCount: lm.parameters().reduce((n, p) => n + p.data.length, 0),
207
- checkpointFormat: "EVL0",
208
- checkpointFp16: fp16,
209
- ...(tokenizer.blob ? { checkpointBytes: checkpoint.byteLength } : {}),
210
- checksum: fnv1a(new Uint8Array(checkpoint)),
211
- ...tokenizer.fields,
212
- card: meta.card,
213
- ...(meta.createdAt ? { createdAt: meta.createdAt } : {}),
214
- };
215
- return new EvermindModelPackage(manifest, checkpoint, undefined, tokenizer.blob);
216
- }
217
-
218
- /**
219
- * Package a video/image generative model: its {@link EvermindLM} weights AND the
220
- * {@link VideoRVQCodec} needed to turn generated tokens back into frames. Without
221
- * the bundled codec a served media model would emit undecodable token ids — this
222
- * is what makes an `.evermind` media artifact self-contained and servable.
223
- */
224
- static fromMediaLM(
225
- lm: EvermindLM,
226
- codec: VideoRVQCodec,
227
- meta: PackageMeta & { modality: "video" | "image" },
228
- ): EvermindModelPackage {
229
- if (lm.config.vocabSize !== codec.vocabSize) {
230
- throw new Error(
231
- `fromMediaLM: LM vocabSize (${lm.config.vocabSize}) must equal codec.vocabSize (${codec.vocabSize})`,
232
- );
233
- }
234
- const fp16 = meta.fp16 ?? false;
235
- const checkpoint = lm.exportWeights({ fp16 });
236
- const codecBlob = codec.serialize();
237
- const tokenizer = EvermindModelPackage._tokenizerSection(meta, lm.config.vocabSize);
238
- const manifest: EvermindModelManifest = {
239
- schema: "evermind.model/1",
240
- name: meta.name,
241
- version: meta.version,
242
- modelType: "evermind-lm",
243
- modality: meta.modality,
244
- config: lm.config as unknown as Record<string, number>,
245
- paramCount: lm.parameters().reduce((n, p) => n + p.data.length, 0),
246
- checkpointFormat: "EVL0",
247
- checkpointFp16: fp16,
248
- checkpointBytes: checkpoint.byteLength,
249
- checksum: fnv1a(new Uint8Array(checkpoint)),
250
- codecFormat: "VRQ0",
251
- ...(tokenizer.blob ? { codecBytes: codecBlob.byteLength } : {}),
252
- codecChecksum: fnv1a(new Uint8Array(codecBlob)),
253
- ...tokenizer.fields,
254
- card: meta.card,
255
- ...(meta.createdAt ? { createdAt: meta.createdAt } : {}),
256
- };
257
- return new EvermindModelPackage(manifest, checkpoint, codecBlob, tokenizer.blob);
258
- }
259
-
260
- /**
261
- * Serialise to a single `.evermind` blob: magic, version, manifest, checkpoint
262
- * [, codec][, tokenizer]. Each section's length is fixed in the manifest whenever
263
- * another section follows it, so the reader never has to guess where one ends.
264
- */
265
- toBlob(): ArrayBuffer {
266
- const manifestBytes = new TextEncoder().encode(JSON.stringify(this.manifest));
267
- const headerBytes = PACKAGE_HEADER_BYTES;
268
- const codecBytes = this.codec?.byteLength ?? 0;
269
- const tokBytes = this.tokenizer?.byteLength ?? 0;
270
- const out = new ArrayBuffer(
271
- headerBytes + manifestBytes.byteLength + this.checkpoint.byteLength + codecBytes + tokBytes,
272
- );
273
- const head = new Uint32Array(out, 0, 3);
274
- head[0] = PKG_MAGIC;
275
- head[1] = PKG_VERSION;
276
- head[2] = manifestBytes.byteLength;
277
- let o = headerBytes;
278
- new Uint8Array(out, o, manifestBytes.byteLength).set(manifestBytes);
279
- o += manifestBytes.byteLength;
280
- new Uint8Array(out, o, this.checkpoint.byteLength).set(new Uint8Array(this.checkpoint));
281
- o += this.checkpoint.byteLength;
282
- if (this.codec) {
283
- new Uint8Array(out, o, codecBytes).set(new Uint8Array(this.codec));
284
- o += codecBytes;
285
- }
286
- if (this.tokenizer) new Uint8Array(out, o, tokBytes).set(new Uint8Array(this.tokenizer));
287
- return out;
288
- }
289
-
290
- /**
291
- * This package carrying a new checkpoint of the same model (an adapted copy): the
292
- * checksum and the checkpoint's section length are recomputed, config, codec and
293
- * tokenizer are kept, so the result validates and round-trips like the original.
294
- */
295
- withCheckpoint(checkpoint: ArrayBuffer, version: string = this.manifest.version): EvermindModelPackage {
296
- const manifest: EvermindModelManifest = {
297
- ...this.manifest,
298
- version,
299
- ...(this.manifest.checkpointBytes !== undefined ? { checkpointBytes: checkpoint.byteLength } : {}),
300
- checksum: fnv1a(new Uint8Array(checkpoint)),
301
- };
302
- return new EvermindModelPackage(manifest, checkpoint, this.codec, this.tokenizer);
303
- }
304
-
305
- /**
306
- * This package carrying `heads` as its trained ML heads (replacing any it had);
307
- * checkpoint, codec and tokenizer are kept. An empty list removes the field.
308
- */
309
- withMlHeads(heads: readonly EvermindMlHead[]): EvermindModelPackage {
310
- const manifest: EvermindModelManifest = { ...this.manifest };
311
- delete manifest.mlHeads;
312
- if (heads.length) manifest.mlHeads = [...heads];
313
- return new EvermindModelPackage(manifest, this.checkpoint, this.codec, this.tokenizer);
314
- }
315
-
316
- /** Parse a `.evermind` blob. Throws on bad magic / truncation. */
317
- /**
318
- * How many leading bytes of a package hold its header and manifest, from its first
319
- * {@link PACKAGE_HEADER_BYTES}. With {@link readManifest}, a host reads a model's
320
- * identity (version, checksum) without loading the checkpoint. Throws on bad magic.
321
- */
322
- static manifestEnd(header: ArrayBuffer): number {
323
- if (header.byteLength < PACKAGE_HEADER_BYTES) throw new Error("EvermindModelPackage: truncated (no header)");
324
- const head = new Uint32Array(header, 0, 3);
325
- if (head[0] !== PKG_MAGIC) throw new Error("EvermindModelPackage: bad magic (not an .evermind package)");
326
- return PACKAGE_HEADER_BYTES + head[2]!;
327
- }
328
-
329
- /** The manifest of a package, from a prefix at least {@link manifestEnd} bytes long. */
330
- static readManifest(prefix: ArrayBuffer): EvermindModelManifest {
331
- const end = EvermindModelPackage.manifestEnd(prefix);
332
- if (end > prefix.byteLength) throw new Error("EvermindModelPackage: truncated (manifest length exceeds blob)");
333
- const bytes = new Uint8Array(prefix, PACKAGE_HEADER_BYTES, end - PACKAGE_HEADER_BYTES);
334
- return JSON.parse(new TextDecoder().decode(bytes)) as EvermindModelManifest;
335
- }
336
-
337
- static fromBlob(buffer: ArrayBuffer): EvermindModelPackage {
338
- const manifest = EvermindModelPackage.readManifest(buffer);
339
- const bodyStart = EvermindModelPackage.manifestEnd(buffer);
340
- // Sections run checkpoint -> codec -> tokenizer, each present only when the
341
- // manifest says so. A section's length is explicit whenever another follows it;
342
- // the last section runs to end-of-blob. That keeps every package written before
343
- // the codec and tokenizer sections existed readable byte for byte.
344
- const cpBytes = manifest.checkpointBytes;
345
- if (cpBytes == null) return new EvermindModelPackage(manifest, buffer.slice(bodyStart));
346
- if (bodyStart + cpBytes > buffer.byteLength) {
347
- throw new Error("EvermindModelPackage.fromBlob: truncated (checkpointBytes exceeds blob)");
348
- }
349
- const checkpoint = buffer.slice(bodyStart, bodyStart + cpBytes);
350
- let o = bodyStart + cpBytes;
351
-
352
- const tokBytes = manifest.tokenizerBytes ?? 0;
353
- if (o + tokBytes > buffer.byteLength) {
354
- throw new Error("EvermindModelPackage.fromBlob: truncated (tokenizerBytes exceeds blob)");
355
- }
356
- const tokStart = buffer.byteLength - tokBytes;
357
-
358
- let codec: ArrayBuffer | undefined;
359
- if (o < tokStart) {
360
- const codecEnd = manifest.codecBytes != null ? o + manifest.codecBytes : tokStart;
361
- if (codecEnd > tokStart) {
362
- throw new Error("EvermindModelPackage.fromBlob: truncated (codecBytes overruns the tokenizer section)");
363
- }
364
- codec = buffer.slice(o, codecEnd);
365
- o = codecEnd;
366
- }
367
- const tokenizer = tokBytes > 0 ? buffer.slice(tokStart) : undefined;
368
- return new EvermindModelPackage(manifest, checkpoint, codec, tokenizer);
369
- }
370
-
371
- /** Verify integrity + structural sanity before trusting a downloaded package. */
372
- validate(): ValidationResult {
373
- const errors: string[] = [];
374
- if (this.manifest.schema !== "evermind.model/1") errors.push(`unknown schema: ${this.manifest.schema}`);
375
- const c = this.manifest.config;
376
- if (this.manifest.modelType === "shared-expert-moe") {
377
- if (!c || c.modelDim! <= 0 || c.hiddenDim! <= 0 || c.numExperts! <= 0 || c.topK! < 1 || c.topK! > c.numExperts!) {
378
- errors.push("invalid config");
379
- }
380
- } else if (this.manifest.modelType === "evermind-lm") {
381
- if (!c || c.vocabSize! <= 0 || c.dModel! <= 0 || c.numLayers! <= 0 || c.numExperts! <= 0 || c.topK! < 1 || c.topK! > c.numExperts!) {
382
- errors.push("invalid config");
383
- }
384
- } else {
385
- errors.push(`unsupported modelType: ${String(this.manifest.modelType)}`);
386
- }
387
- const actual = fnv1a(new Uint8Array(this.checkpoint));
388
- if (actual !== this.manifest.checksum) {
389
- errors.push(`checksum mismatch (manifest ${this.manifest.checksum}, actual ${actual}) — corrupt or tampered checkpoint`);
390
- }
391
- // Media packages must carry an integral codec — a served media model can't
392
- // decode tokens → frames without it.
393
- const modality = this.manifest.modality ?? "text";
394
- if (modality === "video" || modality === "image") {
395
- if (!this.codec) {
396
- errors.push(`modality '${modality}' package is missing its codec section`);
397
- } else {
398
- const codecActual = fnv1a(new Uint8Array(this.codec));
399
- if (codecActual !== this.manifest.codecChecksum) {
400
- errors.push(`codec checksum mismatch (manifest ${this.manifest.codecChecksum}, actual ${codecActual}) — corrupt codec`);
401
- }
402
- }
403
- }
404
- // An embedded tokenizer must be intact AND agree with the model's vocabulary —
405
- // a corrupt or mismatched one decodes confidently into nonsense.
406
- if (this.manifest.tokenizerFormat) {
407
- if (!this.tokenizer) {
408
- errors.push("manifest declares an embedded tokenizer but the package has no tokenizer section");
409
- } else {
410
- const tokActual = fnv1a(new Uint8Array(this.tokenizer));
411
- if (tokActual !== this.manifest.tokenizerChecksum) {
412
- errors.push(
413
- `tokenizer checksum mismatch (manifest ${this.manifest.tokenizerChecksum}, actual ${tokActual}) - corrupt tokenizer`,
414
- );
415
- }
416
- const modelVocab = this.manifest.config?.['vocabSize'];
417
- const tokVocab = this.manifest.tokenizerVocabSize;
418
- if (modelVocab != null && tokVocab != null && modelVocab !== tokVocab) {
419
- errors.push(`tokenizer vocabSize (${tokVocab}) does not match the model's (${modelVocab})`);
420
- }
421
- }
422
- }
423
- for (const h of this.manifest.mlHeads ?? []) {
424
- const why = mlHeadUnusableReason(h);
425
- if (why) errors.push(`ml head '${String(h?.task)}': ${why}`);
426
- }
427
- if (new Set((this.manifest.mlHeads ?? []).map((h) => h.task)).size !== (this.manifest.mlHeads ?? []).length) {
428
- errors.push("ml heads: a task appears more than once");
429
- }
430
- return { ok: errors.length === 0, errors };
431
- }
432
-
433
- /**
434
- * The tokenizer embedded in this package, or `null` when it carries none.
435
- *
436
- * A package WITH one is self-contained: a consumer runs `loadLM()` +
437
- * `loadTokenizer()` and can turn text into tokens and back with the exact
438
- * vocabulary the model was trained on. A package without one still loads — every
439
- * artifact published before this section existed is in that shape — but the
440
- * consumer must supply the matching vocabulary itself.
441
- */
442
- loadTokenizer(): BPETokenizer | null {
443
- if (!this.manifest.tokenizerFormat || !this.tokenizer) return null;
444
- const v = this.validate();
445
- if (!v.ok) throw new Error(`EvermindModelPackage.loadTokenizer: ${v.errors.join("; ")}`);
446
- return BPETokenizer.deserialize(this.tokenizer);
447
- }
448
-
449
- /** Reconstruct the bare MoE layer. Validates first; throws if invalid / wrong type. */
450
- loadModel(): SharedExpertMoE {
451
- const v = this.validate();
452
- if (!v.ok) throw new Error(`EvermindModelPackage.loadModel: ${v.errors.join("; ")}`);
453
- if (this.manifest.modelType !== "shared-expert-moe") {
454
- throw new Error(`loadModel: package is '${this.manifest.modelType}', use loadLM()`);
455
- }
456
- const model = new SharedExpertMoE(this.manifest.config as Partial<MoEConfig>);
457
- model.loadWeights(this.checkpoint);
458
- return model;
459
- }
460
-
461
- /** Reconstruct the runnable generative model — what a marketplace buyer runs. */
462
- loadLM(): EvermindLM {
463
- const v = this.validate();
464
- if (!v.ok) throw new Error(`EvermindModelPackage.loadLM: ${v.errors.join("; ")}`);
465
- if (this.manifest.modelType !== "evermind-lm") {
466
- throw new Error(`loadLM: package is '${this.manifest.modelType}', use loadModel()`);
467
- }
468
- const lm = new EvermindLM(this.manifest.config as unknown as EvermindLMConfig);
469
- lm.loadWeights(this.checkpoint);
470
- return lm;
471
- }
472
-
473
- /**
474
- * Reconstruct a video/image model: the generative {@link EvermindLM} plus its
475
- * {@link VideoRVQCodec}. Pair with `generateVideo` / `generateImage` to produce
476
- * frames. This is what a media-serving path (gateway) loads and runs.
477
- */
478
- loadMediaLM(): { lm: EvermindLM; codec: VideoRVQCodec; modality: EvermindModality } {
479
- const v = this.validate();
480
- if (!v.ok) throw new Error(`EvermindModelPackage.loadMediaLM: ${v.errors.join("; ")}`);
481
- const modality = this.manifest.modality ?? "text";
482
- if (modality !== "video" && modality !== "image") {
483
- throw new Error(`loadMediaLM: package modality is '${modality}', use loadLM()`);
484
- }
485
- return { lm: this.loadLM(), codec: VideoRVQCodec.deserialize(this.codec!), modality };
486
- }
487
- }
488
-
1
+ /**
2
+ * evermind/package.ts — EvermindModelPackage: the portable, publishable AI artifact.
3
+ *
4
+ * This is the unit a creator publishes to the marketplace and a buyer downloads
5
+ * and runs: a self-describing manifest (name, version, config, model card,
6
+ * integrity checksum) bundled with the trained checkpoint into one `.evermind`
7
+ * blob. It is the contract every downstream consumer (marketplace listing,
8
+ * purchase entitlement, workflow generator) reads — define it once, here.
9
+ *
10
+ * Zero-dep and isomorphic: serialises via TextEncoder/TextDecoder, runs in the
11
+ * browser (where models are trained) and in Node/Workers (where they execute).
12
+ */
13
+
14
+ import { SharedExpertMoE, type MoEConfig } from "../moe/moe_model.js";
15
+ import { EvermindLM, type EvermindLMConfig } from "../lm/evermind_lm.js";
16
+ import { VideoRVQCodec } from "../codec/video_rvq.js";
17
+ import { BPETokenizer } from "../tokenizer/bpe.js";
18
+ import { mlHeadUnusableReason, type EvermindMlHead } from "./ml_head.js";
19
+
20
+ export type { EvermindMlHead } from "./ml_head.js";
21
+
22
+ /** First 4 bytes of a serialised package: "EVM1". */
23
+ const PKG_MAGIC = 0x45564d31;
24
+ /** magic, format version, manifest length — three u32s ahead of the manifest. */
25
+ export const PACKAGE_HEADER_BYTES = 12;
26
+ const PKG_VERSION = 1;
27
+
28
+ /** The kinds of model an `.evermind` package can carry. */
29
+ export type EvermindModelType = "shared-expert-moe" | "evermind-lm";
30
+
31
+ /** Output modality. `text` (default) needs no codec; `video`/`image` bundle a VRQ codec. */
32
+ export type EvermindModality = "text" | "video" | "image";
33
+
34
+ /** Human-facing description published with the model (the "model card"). */
35
+ export interface EvermindModelCard {
36
+ description: string;
37
+ /** What it was trained on / intended for. */
38
+ trainingSummary?: string;
39
+ /** SPDX id or free text (e.g. "MIT", "proprietary"). */
40
+ license?: string;
41
+ author?: string;
42
+ tags?: string[];
43
+ }
44
+
45
+ /** Self-describing header for a published Evermind model. */
46
+ export interface EvermindModelManifest {
47
+ schema: "evermind.model/1";
48
+ name: string;
49
+ version: string;
50
+ modelType: EvermindModelType;
51
+ /** Output modality; absent ⇒ "text". Video/image also carry a `codec` section. */
52
+ modality?: EvermindModality;
53
+ /** Flat numeric model config (the constructor args), serialised verbatim. */
54
+ config: Record<string, number>;
55
+ /** Total trainable scalar parameters (for sizing / pricing / display). */
56
+ paramCount: number;
57
+ checkpointFormat: "MoE0" | "EVL0";
58
+ checkpointFp16: boolean;
59
+ /**
60
+ * Byte length of the checkpoint section — REQUIRED when a codec section follows
61
+ * (so the reader knows where the checkpoint ends). Absent ⇒ checkpoint runs to
62
+ * end-of-blob (the original text-only layout, still read verbatim).
63
+ */
64
+ checkpointBytes?: number;
65
+ /** 32-bit FNV-1a over the checkpoint bytes — integrity for download/purchase. */
66
+ checksum: number;
67
+ /** Media codec section format (present for video/image packages). */
68
+ codecFormat?: "VRQ0";
69
+ /**
70
+ * Byte length of the codec section — REQUIRED when a tokenizer section follows.
71
+ * Absent ⇒ the codec runs to end-of-blob (the original media layout).
72
+ */
73
+ codecBytes?: number;
74
+ /** 32-bit FNV-1a over the codec bytes — integrity for the bundled codec. */
75
+ codecChecksum?: number;
76
+ /**
77
+ * Embedded-tokenizer section format. Token ids are meaningless without the exact
78
+ * vocabulary that produced them, so a package that carries one is self-contained:
79
+ * a consumer no longer has to source the matching vocab separately (and can no
80
+ * longer pair the wrong one with it). Absent ⇒ no tokenizer embedded, which every
81
+ * package written before this field is — those still load exactly as before.
82
+ */
83
+ tokenizerFormat?: "BPE0";
84
+ /** Byte length of the tokenizer section (always last). */
85
+ tokenizerBytes?: number;
86
+ /** 32-bit FNV-1a over the tokenizer bytes. */
87
+ tokenizerChecksum?: number;
88
+ /** Vocabulary size of the embedded tokenizer — cross-checked against the model's. */
89
+ tokenizerVocabSize?: number;
90
+ card: EvermindModelCard;
91
+ /** ISO timestamp, caller-supplied (the engine avoids Date for determinism). */
92
+ createdAt?: string;
93
+ /** Trained ML-catalog heads that travel (and merge) with this model. Absent ⇒ none. */
94
+ mlHeads?: EvermindMlHead[];
95
+ }
96
+
97
+ export interface PackageMeta {
98
+ name: string;
99
+ version: string;
100
+ card: EvermindModelCard;
101
+ /** Store the checkpoint in fp16 (half the size). Default false. */
102
+ fp16?: boolean;
103
+ /**
104
+ * Embed this tokenizer in the package, making the artifact self-contained.
105
+ * Its `vocabSize` must equal the model's, or packaging throws — a mismatched
106
+ * pair produces confident nonsense, which is worse than a failure to publish.
107
+ */
108
+ tokenizer?: BPETokenizer;
109
+ createdAt?: string;
110
+ }
111
+
112
+ export interface ValidationResult {
113
+ ok: boolean;
114
+ errors: string[];
115
+ }
116
+
117
+ /** 32-bit FNV-1a hash — dependency-free integrity check over the checkpoint. */
118
+ function fnv1a(bytes: Uint8Array): number {
119
+ let h = 0x811c9dc5;
120
+ for (let i = 0; i < bytes.length; i++) {
121
+ h ^= bytes[i]!;
122
+ h = Math.imul(h, 0x01000193);
123
+ }
124
+ return h >>> 0;
125
+ }
126
+
127
+ /**
128
+ * A trained model packaged for publishing: manifest + checkpoint. Build one with
129
+ * {@link EvermindModelPackage.fromModel}, ship {@link toBlob}, and a buyer
130
+ * reconstitutes it with {@link fromBlob} → {@link validate} → {@link loadModel}.
131
+ */
132
+ export class EvermindModelPackage {
133
+ constructor(
134
+ readonly manifest: EvermindModelManifest,
135
+ readonly checkpoint: ArrayBuffer,
136
+ /** Serialized media codec ("VRQ0" blob), present for video/image packages. */
137
+ readonly codec?: ArrayBuffer,
138
+ /** Serialized BPE tokenizer ("BPE0" blob) — present when the package embeds one. */
139
+ readonly tokenizer?: ArrayBuffer,
140
+ ) {}
141
+
142
+ /**
143
+ * Serialise `meta.tokenizer` and the manifest fields describing it, or `{}` when
144
+ * no tokenizer was supplied. Shared by every `from*` factory so the vocab-size
145
+ * cross-check exists in exactly one place.
146
+ */
147
+ private static _tokenizerSection(
148
+ meta: PackageMeta,
149
+ modelVocabSize: number | undefined,
150
+ ): { blob?: ArrayBuffer; fields: Partial<EvermindModelManifest> } {
151
+ if (!meta.tokenizer) return { fields: {} };
152
+ const vocabSize = meta.tokenizer.vocabSize;
153
+ if (modelVocabSize != null && vocabSize !== modelVocabSize) {
154
+ throw new Error(
155
+ `EvermindModelPackage: tokenizer vocabSize (${vocabSize}) must equal the model's (${modelVocabSize}) — ` +
156
+ "a mismatched pair decodes to nonsense.",
157
+ );
158
+ }
159
+ const blob = meta.tokenizer.serialize();
160
+ return {
161
+ blob,
162
+ fields: {
163
+ tokenizerFormat: "BPE0",
164
+ tokenizerBytes: blob.byteLength,
165
+ tokenizerChecksum: fnv1a(new Uint8Array(blob)),
166
+ tokenizerVocabSize: vocabSize,
167
+ },
168
+ };
169
+ }
170
+
171
+ /** Package a trained model with its publishing metadata. */
172
+ static fromModel(model: SharedExpertMoE, meta: PackageMeta): EvermindModelPackage {
173
+ const fp16 = meta.fp16 ?? false;
174
+ const checkpoint = model.exportWeights({ fp16 });
175
+ // A bare MoE layer has no vocabulary of its own, so there is nothing to cross-check.
176
+ const tokenizer = EvermindModelPackage._tokenizerSection(meta, undefined);
177
+ const manifest: EvermindModelManifest = {
178
+ schema: "evermind.model/1",
179
+ name: meta.name,
180
+ version: meta.version,
181
+ modelType: "shared-expert-moe",
182
+ config: model.config,
183
+ paramCount: model.parameters().reduce((n, p) => n + p.numel, 0),
184
+ checkpointFormat: "MoE0",
185
+ checkpointFp16: fp16,
186
+ ...(tokenizer.blob ? { checkpointBytes: checkpoint.byteLength } : {}),
187
+ checksum: fnv1a(new Uint8Array(checkpoint)),
188
+ ...tokenizer.fields,
189
+ card: meta.card,
190
+ ...(meta.createdAt ? { createdAt: meta.createdAt } : {}),
191
+ };
192
+ return new EvermindModelPackage(manifest, checkpoint, undefined, tokenizer.blob);
193
+ }
194
+
195
+ /** Package a trained generative {@link EvermindLM} — the runnable marketplace AI. */
196
+ static fromLM(lm: EvermindLM, meta: PackageMeta): EvermindModelPackage {
197
+ const fp16 = meta.fp16 ?? false;
198
+ const checkpoint = lm.exportWeights({ fp16 });
199
+ const tokenizer = EvermindModelPackage._tokenizerSection(meta, lm.config.vocabSize);
200
+ const manifest: EvermindModelManifest = {
201
+ schema: "evermind.model/1",
202
+ name: meta.name,
203
+ version: meta.version,
204
+ modelType: "evermind-lm",
205
+ config: lm.config as unknown as Record<string, number>,
206
+ paramCount: lm.parameters().reduce((n, p) => n + p.data.length, 0),
207
+ checkpointFormat: "EVL0",
208
+ checkpointFp16: fp16,
209
+ ...(tokenizer.blob ? { checkpointBytes: checkpoint.byteLength } : {}),
210
+ checksum: fnv1a(new Uint8Array(checkpoint)),
211
+ ...tokenizer.fields,
212
+ card: meta.card,
213
+ ...(meta.createdAt ? { createdAt: meta.createdAt } : {}),
214
+ };
215
+ return new EvermindModelPackage(manifest, checkpoint, undefined, tokenizer.blob);
216
+ }
217
+
218
+ /**
219
+ * Package a video/image generative model: its {@link EvermindLM} weights AND the
220
+ * {@link VideoRVQCodec} needed to turn generated tokens back into frames. Without
221
+ * the bundled codec a served media model would emit undecodable token ids — this
222
+ * is what makes an `.evermind` media artifact self-contained and servable.
223
+ */
224
+ static fromMediaLM(
225
+ lm: EvermindLM,
226
+ codec: VideoRVQCodec,
227
+ meta: PackageMeta & { modality: "video" | "image" },
228
+ ): EvermindModelPackage {
229
+ if (lm.config.vocabSize !== codec.vocabSize) {
230
+ throw new Error(
231
+ `fromMediaLM: LM vocabSize (${lm.config.vocabSize}) must equal codec.vocabSize (${codec.vocabSize})`,
232
+ );
233
+ }
234
+ const fp16 = meta.fp16 ?? false;
235
+ const checkpoint = lm.exportWeights({ fp16 });
236
+ const codecBlob = codec.serialize();
237
+ const tokenizer = EvermindModelPackage._tokenizerSection(meta, lm.config.vocabSize);
238
+ const manifest: EvermindModelManifest = {
239
+ schema: "evermind.model/1",
240
+ name: meta.name,
241
+ version: meta.version,
242
+ modelType: "evermind-lm",
243
+ modality: meta.modality,
244
+ config: lm.config as unknown as Record<string, number>,
245
+ paramCount: lm.parameters().reduce((n, p) => n + p.data.length, 0),
246
+ checkpointFormat: "EVL0",
247
+ checkpointFp16: fp16,
248
+ checkpointBytes: checkpoint.byteLength,
249
+ checksum: fnv1a(new Uint8Array(checkpoint)),
250
+ codecFormat: "VRQ0",
251
+ ...(tokenizer.blob ? { codecBytes: codecBlob.byteLength } : {}),
252
+ codecChecksum: fnv1a(new Uint8Array(codecBlob)),
253
+ ...tokenizer.fields,
254
+ card: meta.card,
255
+ ...(meta.createdAt ? { createdAt: meta.createdAt } : {}),
256
+ };
257
+ return new EvermindModelPackage(manifest, checkpoint, codecBlob, tokenizer.blob);
258
+ }
259
+
260
+ /**
261
+ * Serialise to a single `.evermind` blob: magic, version, manifest, checkpoint
262
+ * [, codec][, tokenizer]. Each section's length is fixed in the manifest whenever
263
+ * another section follows it, so the reader never has to guess where one ends.
264
+ */
265
+ toBlob(): ArrayBuffer {
266
+ const manifestBytes = new TextEncoder().encode(JSON.stringify(this.manifest));
267
+ const headerBytes = PACKAGE_HEADER_BYTES;
268
+ const codecBytes = this.codec?.byteLength ?? 0;
269
+ const tokBytes = this.tokenizer?.byteLength ?? 0;
270
+ const out = new ArrayBuffer(
271
+ headerBytes + manifestBytes.byteLength + this.checkpoint.byteLength + codecBytes + tokBytes,
272
+ );
273
+ const head = new Uint32Array(out, 0, 3);
274
+ head[0] = PKG_MAGIC;
275
+ head[1] = PKG_VERSION;
276
+ head[2] = manifestBytes.byteLength;
277
+ let o = headerBytes;
278
+ new Uint8Array(out, o, manifestBytes.byteLength).set(manifestBytes);
279
+ o += manifestBytes.byteLength;
280
+ new Uint8Array(out, o, this.checkpoint.byteLength).set(new Uint8Array(this.checkpoint));
281
+ o += this.checkpoint.byteLength;
282
+ if (this.codec) {
283
+ new Uint8Array(out, o, codecBytes).set(new Uint8Array(this.codec));
284
+ o += codecBytes;
285
+ }
286
+ if (this.tokenizer) new Uint8Array(out, o, tokBytes).set(new Uint8Array(this.tokenizer));
287
+ return out;
288
+ }
289
+
290
+ /**
291
+ * This package carrying a new checkpoint of the same model (an adapted copy): the
292
+ * checksum and the checkpoint's section length are recomputed, config, codec and
293
+ * tokenizer are kept, so the result validates and round-trips like the original.
294
+ */
295
+ withCheckpoint(checkpoint: ArrayBuffer, version: string = this.manifest.version): EvermindModelPackage {
296
+ const manifest: EvermindModelManifest = {
297
+ ...this.manifest,
298
+ version,
299
+ ...(this.manifest.checkpointBytes !== undefined ? { checkpointBytes: checkpoint.byteLength } : {}),
300
+ checksum: fnv1a(new Uint8Array(checkpoint)),
301
+ };
302
+ return new EvermindModelPackage(manifest, checkpoint, this.codec, this.tokenizer);
303
+ }
304
+
305
+ /**
306
+ * This package carrying `heads` as its trained ML heads (replacing any it had);
307
+ * checkpoint, codec and tokenizer are kept. An empty list removes the field.
308
+ */
309
+ withMlHeads(heads: readonly EvermindMlHead[]): EvermindModelPackage {
310
+ const manifest: EvermindModelManifest = { ...this.manifest };
311
+ delete manifest.mlHeads;
312
+ if (heads.length) manifest.mlHeads = [...heads];
313
+ return new EvermindModelPackage(manifest, this.checkpoint, this.codec, this.tokenizer);
314
+ }
315
+
316
+ /** Parse a `.evermind` blob. Throws on bad magic / truncation. */
317
+ /**
318
+ * How many leading bytes of a package hold its header and manifest, from its first
319
+ * {@link PACKAGE_HEADER_BYTES}. With {@link readManifest}, a host reads a model's
320
+ * identity (version, checksum) without loading the checkpoint. Throws on bad magic.
321
+ */
322
+ static manifestEnd(header: ArrayBuffer): number {
323
+ if (header.byteLength < PACKAGE_HEADER_BYTES) throw new Error("EvermindModelPackage: truncated (no header)");
324
+ const head = new Uint32Array(header, 0, 3);
325
+ if (head[0] !== PKG_MAGIC) throw new Error("EvermindModelPackage: bad magic (not an .evermind package)");
326
+ return PACKAGE_HEADER_BYTES + head[2]!;
327
+ }
328
+
329
+ /** The manifest of a package, from a prefix at least {@link manifestEnd} bytes long. */
330
+ static readManifest(prefix: ArrayBuffer): EvermindModelManifest {
331
+ const end = EvermindModelPackage.manifestEnd(prefix);
332
+ if (end > prefix.byteLength) throw new Error("EvermindModelPackage: truncated (manifest length exceeds blob)");
333
+ const bytes = new Uint8Array(prefix, PACKAGE_HEADER_BYTES, end - PACKAGE_HEADER_BYTES);
334
+ return JSON.parse(new TextDecoder().decode(bytes)) as EvermindModelManifest;
335
+ }
336
+
337
+ static fromBlob(buffer: ArrayBuffer): EvermindModelPackage {
338
+ const manifest = EvermindModelPackage.readManifest(buffer);
339
+ const bodyStart = EvermindModelPackage.manifestEnd(buffer);
340
+ // Sections run checkpoint -> codec -> tokenizer, each present only when the
341
+ // manifest says so. A section's length is explicit whenever another follows it;
342
+ // the last section runs to end-of-blob. That keeps every package written before
343
+ // the codec and tokenizer sections existed readable byte for byte.
344
+ const cpBytes = manifest.checkpointBytes;
345
+ if (cpBytes == null) return new EvermindModelPackage(manifest, buffer.slice(bodyStart));
346
+ if (bodyStart + cpBytes > buffer.byteLength) {
347
+ throw new Error("EvermindModelPackage.fromBlob: truncated (checkpointBytes exceeds blob)");
348
+ }
349
+ const checkpoint = buffer.slice(bodyStart, bodyStart + cpBytes);
350
+ let o = bodyStart + cpBytes;
351
+
352
+ const tokBytes = manifest.tokenizerBytes ?? 0;
353
+ if (o + tokBytes > buffer.byteLength) {
354
+ throw new Error("EvermindModelPackage.fromBlob: truncated (tokenizerBytes exceeds blob)");
355
+ }
356
+ const tokStart = buffer.byteLength - tokBytes;
357
+
358
+ let codec: ArrayBuffer | undefined;
359
+ if (o < tokStart) {
360
+ const codecEnd = manifest.codecBytes != null ? o + manifest.codecBytes : tokStart;
361
+ if (codecEnd > tokStart) {
362
+ throw new Error("EvermindModelPackage.fromBlob: truncated (codecBytes overruns the tokenizer section)");
363
+ }
364
+ codec = buffer.slice(o, codecEnd);
365
+ o = codecEnd;
366
+ }
367
+ const tokenizer = tokBytes > 0 ? buffer.slice(tokStart) : undefined;
368
+ return new EvermindModelPackage(manifest, checkpoint, codec, tokenizer);
369
+ }
370
+
371
+ /** Verify integrity + structural sanity before trusting a downloaded package. */
372
+ validate(): ValidationResult {
373
+ const errors: string[] = [];
374
+ if (this.manifest.schema !== "evermind.model/1") errors.push(`unknown schema: ${this.manifest.schema}`);
375
+ const c = this.manifest.config;
376
+ if (this.manifest.modelType === "shared-expert-moe") {
377
+ if (!c || c.modelDim! <= 0 || c.hiddenDim! <= 0 || c.numExperts! <= 0 || c.topK! < 1 || c.topK! > c.numExperts!) {
378
+ errors.push("invalid config");
379
+ }
380
+ } else if (this.manifest.modelType === "evermind-lm") {
381
+ if (!c || c.vocabSize! <= 0 || c.dModel! <= 0 || c.numLayers! <= 0 || c.numExperts! <= 0 || c.topK! < 1 || c.topK! > c.numExperts!) {
382
+ errors.push("invalid config");
383
+ }
384
+ } else {
385
+ errors.push(`unsupported modelType: ${String(this.manifest.modelType)}`);
386
+ }
387
+ const actual = fnv1a(new Uint8Array(this.checkpoint));
388
+ if (actual !== this.manifest.checksum) {
389
+ errors.push(`checksum mismatch (manifest ${this.manifest.checksum}, actual ${actual}) — corrupt or tampered checkpoint`);
390
+ }
391
+ // Media packages must carry an integral codec — a served media model can't
392
+ // decode tokens → frames without it.
393
+ const modality = this.manifest.modality ?? "text";
394
+ if (modality === "video" || modality === "image") {
395
+ if (!this.codec) {
396
+ errors.push(`modality '${modality}' package is missing its codec section`);
397
+ } else {
398
+ const codecActual = fnv1a(new Uint8Array(this.codec));
399
+ if (codecActual !== this.manifest.codecChecksum) {
400
+ errors.push(`codec checksum mismatch (manifest ${this.manifest.codecChecksum}, actual ${codecActual}) — corrupt codec`);
401
+ }
402
+ }
403
+ }
404
+ // An embedded tokenizer must be intact AND agree with the model's vocabulary —
405
+ // a corrupt or mismatched one decodes confidently into nonsense.
406
+ if (this.manifest.tokenizerFormat) {
407
+ if (!this.tokenizer) {
408
+ errors.push("manifest declares an embedded tokenizer but the package has no tokenizer section");
409
+ } else {
410
+ const tokActual = fnv1a(new Uint8Array(this.tokenizer));
411
+ if (tokActual !== this.manifest.tokenizerChecksum) {
412
+ errors.push(
413
+ `tokenizer checksum mismatch (manifest ${this.manifest.tokenizerChecksum}, actual ${tokActual}) - corrupt tokenizer`,
414
+ );
415
+ }
416
+ const modelVocab = this.manifest.config?.['vocabSize'];
417
+ const tokVocab = this.manifest.tokenizerVocabSize;
418
+ if (modelVocab != null && tokVocab != null && modelVocab !== tokVocab) {
419
+ errors.push(`tokenizer vocabSize (${tokVocab}) does not match the model's (${modelVocab})`);
420
+ }
421
+ }
422
+ }
423
+ for (const h of this.manifest.mlHeads ?? []) {
424
+ const why = mlHeadUnusableReason(h);
425
+ if (why) errors.push(`ml head '${String(h?.task)}': ${why}`);
426
+ }
427
+ if (new Set((this.manifest.mlHeads ?? []).map((h) => h.task)).size !== (this.manifest.mlHeads ?? []).length) {
428
+ errors.push("ml heads: a task appears more than once");
429
+ }
430
+ return { ok: errors.length === 0, errors };
431
+ }
432
+
433
+ /**
434
+ * The tokenizer embedded in this package, or `null` when it carries none.
435
+ *
436
+ * A package WITH one is self-contained: a consumer runs `loadLM()` +
437
+ * `loadTokenizer()` and can turn text into tokens and back with the exact
438
+ * vocabulary the model was trained on. A package without one still loads — every
439
+ * artifact published before this section existed is in that shape — but the
440
+ * consumer must supply the matching vocabulary itself.
441
+ */
442
+ loadTokenizer(): BPETokenizer | null {
443
+ if (!this.manifest.tokenizerFormat || !this.tokenizer) return null;
444
+ const v = this.validate();
445
+ if (!v.ok) throw new Error(`EvermindModelPackage.loadTokenizer: ${v.errors.join("; ")}`);
446
+ return BPETokenizer.deserialize(this.tokenizer);
447
+ }
448
+
449
+ /** Reconstruct the bare MoE layer. Validates first; throws if invalid / wrong type. */
450
+ loadModel(): SharedExpertMoE {
451
+ const v = this.validate();
452
+ if (!v.ok) throw new Error(`EvermindModelPackage.loadModel: ${v.errors.join("; ")}`);
453
+ if (this.manifest.modelType !== "shared-expert-moe") {
454
+ throw new Error(`loadModel: package is '${this.manifest.modelType}', use loadLM()`);
455
+ }
456
+ const model = new SharedExpertMoE(this.manifest.config as Partial<MoEConfig>);
457
+ model.loadWeights(this.checkpoint);
458
+ return model;
459
+ }
460
+
461
+ /** Reconstruct the runnable generative model — what a marketplace buyer runs. */
462
+ loadLM(): EvermindLM {
463
+ const v = this.validate();
464
+ if (!v.ok) throw new Error(`EvermindModelPackage.loadLM: ${v.errors.join("; ")}`);
465
+ if (this.manifest.modelType !== "evermind-lm") {
466
+ throw new Error(`loadLM: package is '${this.manifest.modelType}', use loadModel()`);
467
+ }
468
+ const lm = new EvermindLM(this.manifest.config as unknown as EvermindLMConfig);
469
+ lm.loadWeights(this.checkpoint);
470
+ return lm;
471
+ }
472
+
473
+ /**
474
+ * Reconstruct a video/image model: the generative {@link EvermindLM} plus its
475
+ * {@link VideoRVQCodec}. Pair with `generateVideo` / `generateImage` to produce
476
+ * frames. This is what a media-serving path (gateway) loads and runs.
477
+ */
478
+ loadMediaLM(): { lm: EvermindLM; codec: VideoRVQCodec; modality: EvermindModality } {
479
+ const v = this.validate();
480
+ if (!v.ok) throw new Error(`EvermindModelPackage.loadMediaLM: ${v.errors.join("; ")}`);
481
+ const modality = this.manifest.modality ?? "text";
482
+ if (modality !== "video" && modality !== "image") {
483
+ throw new Error(`loadMediaLM: package modality is '${modality}', use loadLM()`);
484
+ }
485
+ return { lm: this.loadLM(), codec: VideoRVQCodec.deserialize(this.codec!), modality };
486
+ }
487
+ }
488
+