@seanhogg/builderforce-memory-engine 2026.6.20 → 2026.6.28

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 (72) hide show
  1. package/dist/index.d.ts +9 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +8 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/kernels/limbic_affect.d.ts +2 -0
  6. package/dist/kernels/limbic_affect.d.ts.map +1 -0
  7. package/dist/kernels/limbic_affect.js +74 -0
  8. package/dist/kernels/limbic_affect.js.map +1 -0
  9. package/dist/limbic/index.d.ts +14 -0
  10. package/dist/limbic/index.d.ts.map +1 -0
  11. package/dist/limbic/index.js +11 -0
  12. package/dist/limbic/index.js.map +1 -0
  13. package/dist/limbic/limbic_model.d.ts +111 -0
  14. package/dist/limbic/limbic_model.d.ts.map +1 -0
  15. package/dist/limbic/limbic_model.js +299 -0
  16. package/dist/limbic/limbic_model.js.map +1 -0
  17. package/dist/limbic/limbic_trainer.d.ts +62 -0
  18. package/dist/limbic/limbic_trainer.d.ts.map +1 -0
  19. package/dist/limbic/limbic_trainer.js +172 -0
  20. package/dist/limbic/limbic_trainer.js.map +1 -0
  21. package/dist/limbic/regions.d.ts +79 -0
  22. package/dist/limbic/regions.d.ts.map +1 -0
  23. package/dist/limbic/regions.js +132 -0
  24. package/dist/limbic/regions.js.map +1 -0
  25. package/dist/lm/evermind_lm.d.ts +148 -0
  26. package/dist/lm/evermind_lm.d.ts.map +1 -0
  27. package/dist/lm/evermind_lm.js +479 -0
  28. package/dist/lm/evermind_lm.js.map +1 -0
  29. package/dist/lm/index.d.ts +6 -0
  30. package/dist/lm/index.d.ts.map +1 -0
  31. package/dist/lm/index.js +5 -0
  32. package/dist/lm/index.js.map +1 -0
  33. package/dist/model/attention_block.js +1 -1
  34. package/dist/model/attention_block.js.map +1 -1
  35. package/dist/model/mamba_model.js +1 -1
  36. package/dist/model/mamba_model.js.map +1 -1
  37. package/dist/moe/index.d.ts +10 -0
  38. package/dist/moe/index.d.ts.map +1 -0
  39. package/dist/moe/index.js +7 -0
  40. package/dist/moe/index.js.map +1 -0
  41. package/dist/moe/moe_model.d.ts +134 -0
  42. package/dist/moe/moe_model.d.ts.map +1 -0
  43. package/dist/moe/moe_model.js +415 -0
  44. package/dist/moe/moe_model.js.map +1 -0
  45. package/dist/moe/moe_package.d.ts +81 -0
  46. package/dist/moe/moe_package.d.ts.map +1 -0
  47. package/dist/moe/moe_package.js +157 -0
  48. package/dist/moe/moe_package.js.map +1 -0
  49. package/dist/moe/moe_trainer.d.ts +53 -0
  50. package/dist/moe/moe_trainer.d.ts.map +1 -0
  51. package/dist/moe/moe_trainer.js +93 -0
  52. package/dist/moe/moe_trainer.js.map +1 -0
  53. package/dist/optim/adamw.d.ts +32 -0
  54. package/dist/optim/adamw.d.ts.map +1 -0
  55. package/dist/optim/adamw.js +52 -0
  56. package/dist/optim/adamw.js.map +1 -0
  57. package/package.json +1 -1
  58. package/src/index.ts +59 -0
  59. package/src/kernels/limbic_affect.ts +74 -0
  60. package/src/limbic/index.ts +28 -0
  61. package/src/limbic/limbic_model.ts +373 -0
  62. package/src/limbic/limbic_trainer.ts +253 -0
  63. package/src/limbic/regions.ts +141 -0
  64. package/src/lm/evermind_lm.ts +558 -0
  65. package/src/lm/index.ts +6 -0
  66. package/src/model/attention_block.ts +1 -1
  67. package/src/model/mamba_model.ts +1 -1
  68. package/src/moe/index.ts +23 -0
  69. package/src/moe/moe_model.ts +475 -0
  70. package/src/moe/moe_package.ts +205 -0
  71. package/src/moe/moe_trainer.ts +134 -0
  72. package/src/optim/adamw.ts +72 -0
@@ -0,0 +1,205 @@
1
+ /**
2
+ * moe_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_model.js";
15
+ import { EvermindLM, type EvermindLMConfig } from "../lm/evermind_lm.js";
16
+
17
+ /** First 4 bytes of a serialised package: "EVM1". */
18
+ const PKG_MAGIC = 0x45564d31;
19
+ const PKG_VERSION = 1;
20
+
21
+ /** The kinds of model an `.evermind` package can carry. */
22
+ export type EvermindModelType = "shared-expert-moe" | "evermind-lm";
23
+
24
+ /** Human-facing description published with the model (the "model card"). */
25
+ export interface EvermindModelCard {
26
+ description: string;
27
+ /** What it was trained on / intended for. */
28
+ trainingSummary?: string;
29
+ /** SPDX id or free text (e.g. "MIT", "proprietary"). */
30
+ license?: string;
31
+ author?: string;
32
+ tags?: string[];
33
+ }
34
+
35
+ /** Self-describing header for a published Evermind model. */
36
+ export interface EvermindModelManifest {
37
+ schema: "evermind.model/1";
38
+ name: string;
39
+ version: string;
40
+ modelType: EvermindModelType;
41
+ /** Flat numeric model config (the constructor args), serialised verbatim. */
42
+ config: Record<string, number>;
43
+ /** Total trainable scalar parameters (for sizing / pricing / display). */
44
+ paramCount: number;
45
+ checkpointFormat: "MoE0" | "EVL0";
46
+ checkpointFp16: boolean;
47
+ /** 32-bit FNV-1a over the checkpoint bytes — integrity for download/purchase. */
48
+ checksum: number;
49
+ card: EvermindModelCard;
50
+ /** ISO timestamp, caller-supplied (the engine avoids Date for determinism). */
51
+ createdAt?: string;
52
+ }
53
+
54
+ export interface PackageMeta {
55
+ name: string;
56
+ version: string;
57
+ card: EvermindModelCard;
58
+ /** Store the checkpoint in fp16 (half the size). Default false. */
59
+ fp16?: boolean;
60
+ createdAt?: string;
61
+ }
62
+
63
+ export interface ValidationResult {
64
+ ok: boolean;
65
+ errors: string[];
66
+ }
67
+
68
+ /** 32-bit FNV-1a hash — dependency-free integrity check over the checkpoint. */
69
+ function fnv1a(bytes: Uint8Array): number {
70
+ let h = 0x811c9dc5;
71
+ for (let i = 0; i < bytes.length; i++) {
72
+ h ^= bytes[i]!;
73
+ h = Math.imul(h, 0x01000193);
74
+ }
75
+ return h >>> 0;
76
+ }
77
+
78
+ /**
79
+ * A trained model packaged for publishing: manifest + checkpoint. Build one with
80
+ * {@link EvermindModelPackage.fromModel}, ship {@link toBlob}, and a buyer
81
+ * reconstitutes it with {@link fromBlob} → {@link validate} → {@link loadModel}.
82
+ */
83
+ export class EvermindModelPackage {
84
+ constructor(
85
+ readonly manifest: EvermindModelManifest,
86
+ readonly checkpoint: ArrayBuffer,
87
+ ) {}
88
+
89
+ /** Package a trained model with its publishing metadata. */
90
+ static fromModel(model: SharedExpertMoE, meta: PackageMeta): EvermindModelPackage {
91
+ const fp16 = meta.fp16 ?? false;
92
+ const checkpoint = model.exportWeights({ fp16 });
93
+ const manifest: EvermindModelManifest = {
94
+ schema: "evermind.model/1",
95
+ name: meta.name,
96
+ version: meta.version,
97
+ modelType: "shared-expert-moe",
98
+ config: model.config,
99
+ paramCount: model.parameters().reduce((n, p) => n + p.numel, 0),
100
+ checkpointFormat: "MoE0",
101
+ checkpointFp16: fp16,
102
+ checksum: fnv1a(new Uint8Array(checkpoint)),
103
+ card: meta.card,
104
+ ...(meta.createdAt ? { createdAt: meta.createdAt } : {}),
105
+ };
106
+ return new EvermindModelPackage(manifest, checkpoint);
107
+ }
108
+
109
+ /** Package a trained generative {@link EvermindLM} — the runnable marketplace AI. */
110
+ static fromLM(lm: EvermindLM, meta: PackageMeta): EvermindModelPackage {
111
+ const fp16 = meta.fp16 ?? false;
112
+ const checkpoint = lm.exportWeights({ fp16 });
113
+ const manifest: EvermindModelManifest = {
114
+ schema: "evermind.model/1",
115
+ name: meta.name,
116
+ version: meta.version,
117
+ modelType: "evermind-lm",
118
+ config: lm.config as unknown as Record<string, number>,
119
+ paramCount: lm.parameters().reduce((n, p) => n + p.data.length, 0),
120
+ checkpointFormat: "EVL0",
121
+ checkpointFp16: fp16,
122
+ checksum: fnv1a(new Uint8Array(checkpoint)),
123
+ card: meta.card,
124
+ ...(meta.createdAt ? { createdAt: meta.createdAt } : {}),
125
+ };
126
+ return new EvermindModelPackage(manifest, checkpoint);
127
+ }
128
+
129
+ /** Serialise to a single `.evermind` blob: magic, version, manifest, checkpoint. */
130
+ toBlob(): ArrayBuffer {
131
+ const manifestBytes = new TextEncoder().encode(JSON.stringify(this.manifest));
132
+ const headerBytes = 12; // magic, version, manifestLen
133
+ const out = new ArrayBuffer(headerBytes + manifestBytes.byteLength + this.checkpoint.byteLength);
134
+ const head = new Uint32Array(out, 0, 3);
135
+ head[0] = PKG_MAGIC;
136
+ head[1] = PKG_VERSION;
137
+ head[2] = manifestBytes.byteLength;
138
+ new Uint8Array(out, headerBytes, manifestBytes.byteLength).set(manifestBytes);
139
+ new Uint8Array(out, headerBytes + manifestBytes.byteLength).set(new Uint8Array(this.checkpoint));
140
+ return out;
141
+ }
142
+
143
+ /** Parse a `.evermind` blob. Throws on bad magic / truncation. */
144
+ static fromBlob(buffer: ArrayBuffer): EvermindModelPackage {
145
+ if (buffer.byteLength < 12) throw new Error("EvermindModelPackage.fromBlob: truncated (no header)");
146
+ const head = new Uint32Array(buffer, 0, 3);
147
+ if (head[0] !== PKG_MAGIC) throw new Error("EvermindModelPackage.fromBlob: bad magic (not an .evermind package)");
148
+ const manifestLen = head[2]!;
149
+ const headerBytes = 12;
150
+ if (headerBytes + manifestLen > buffer.byteLength) {
151
+ throw new Error("EvermindModelPackage.fromBlob: truncated (manifest length exceeds blob)");
152
+ }
153
+ const manifestBytes = new Uint8Array(buffer, headerBytes, manifestLen);
154
+ const manifest = JSON.parse(new TextDecoder().decode(manifestBytes)) as EvermindModelManifest;
155
+ const checkpoint = buffer.slice(headerBytes + manifestLen);
156
+ return new EvermindModelPackage(manifest, checkpoint);
157
+ }
158
+
159
+ /** Verify integrity + structural sanity before trusting a downloaded package. */
160
+ validate(): ValidationResult {
161
+ const errors: string[] = [];
162
+ if (this.manifest.schema !== "evermind.model/1") errors.push(`unknown schema: ${this.manifest.schema}`);
163
+ const c = this.manifest.config;
164
+ if (this.manifest.modelType === "shared-expert-moe") {
165
+ if (!c || c.modelDim! <= 0 || c.hiddenDim! <= 0 || c.numExperts! <= 0 || c.topK! < 1 || c.topK! > c.numExperts!) {
166
+ errors.push("invalid config");
167
+ }
168
+ } else if (this.manifest.modelType === "evermind-lm") {
169
+ if (!c || c.vocabSize! <= 0 || c.dModel! <= 0 || c.numLayers! <= 0 || c.numExperts! <= 0 || c.topK! < 1 || c.topK! > c.numExperts!) {
170
+ errors.push("invalid config");
171
+ }
172
+ } else {
173
+ errors.push(`unsupported modelType: ${String(this.manifest.modelType)}`);
174
+ }
175
+ const actual = fnv1a(new Uint8Array(this.checkpoint));
176
+ if (actual !== this.manifest.checksum) {
177
+ errors.push(`checksum mismatch (manifest ${this.manifest.checksum}, actual ${actual}) — corrupt or tampered checkpoint`);
178
+ }
179
+ return { ok: errors.length === 0, errors };
180
+ }
181
+
182
+ /** Reconstruct the bare MoE layer. Validates first; throws if invalid / wrong type. */
183
+ loadModel(): SharedExpertMoE {
184
+ const v = this.validate();
185
+ if (!v.ok) throw new Error(`EvermindModelPackage.loadModel: ${v.errors.join("; ")}`);
186
+ if (this.manifest.modelType !== "shared-expert-moe") {
187
+ throw new Error(`loadModel: package is '${this.manifest.modelType}', use loadLM()`);
188
+ }
189
+ const model = new SharedExpertMoE(this.manifest.config as Partial<MoEConfig>);
190
+ model.loadWeights(this.checkpoint);
191
+ return model;
192
+ }
193
+
194
+ /** Reconstruct the runnable generative model — what a marketplace buyer runs. */
195
+ loadLM(): EvermindLM {
196
+ const v = this.validate();
197
+ if (!v.ok) throw new Error(`EvermindModelPackage.loadLM: ${v.errors.join("; ")}`);
198
+ if (this.manifest.modelType !== "evermind-lm") {
199
+ throw new Error(`loadLM: package is '${this.manifest.modelType}', use loadModel()`);
200
+ }
201
+ const lm = new EvermindLM(this.manifest.config as unknown as EvermindLMConfig);
202
+ lm.loadWeights(this.checkpoint);
203
+ return lm;
204
+ }
205
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * moe_trainer.ts — AdamW training loop for {@link SharedExpertMoE}.
3
+ *
4
+ * Makes "train your own Evermind AI" real: given labelled (input → target)
5
+ * samples, runs minibatch AdamW over the flat parameters with the load-balancing
6
+ * auxiliary loss mixed in (so the router spreads load instead of collapsing onto
7
+ * a few experts). Pure CPU, deterministic given a seeded model — the same loop a
8
+ * WebGPU optimiser kernel would accelerate.
9
+ */
10
+
11
+ import { SharedExpertMoE } from "./moe_model.js";
12
+ import { AdamW } from "../optim/adamw.js";
13
+
14
+ export interface MoESample {
15
+ input: ArrayLike<number>;
16
+ target: ArrayLike<number>;
17
+ }
18
+
19
+ export interface MoETrainOptions {
20
+ /** Learning rate. Default 0.01. */
21
+ lr?: number;
22
+ /** AdamW β1. Default 0.9. */
23
+ beta1?: number;
24
+ /** AdamW β2. Default 0.999. */
25
+ beta2?: number;
26
+ /** AdamW ε. Default 1e-8. */
27
+ eps?: number;
28
+ /** Decoupled weight decay. Default 0. */
29
+ weightDecay?: number;
30
+ /** Weight of the load-balancing auxiliary loss. Default 0.01. */
31
+ auxWeight?: number;
32
+ /** Minibatch size. Default = all samples (full batch). */
33
+ batchSize?: number;
34
+ /** Passes over the dataset. Default 1. */
35
+ epochs?: number;
36
+ }
37
+
38
+ export interface MoEEpochResult {
39
+ /** Mean per-sample task (MSE·½) loss over the epoch. */
40
+ loss: number;
41
+ /** Load-balancing auxiliary loss at the end of the epoch (≈1 balanced … E collapsed). */
42
+ auxLoss: number;
43
+ }
44
+
45
+ /**
46
+ * AdamW optimiser over a model's flat parameter list. State (m, v) is keyed by
47
+ * parameter index and persists across {@link step} calls.
48
+ */
49
+ export class MoETrainer {
50
+ private readonly adam: AdamW;
51
+ private readonly opt: Required<MoETrainOptions>;
52
+
53
+ constructor(
54
+ private readonly model: SharedExpertMoE,
55
+ options: MoETrainOptions = {},
56
+ ) {
57
+ this.opt = {
58
+ lr: options.lr ?? 0.01,
59
+ beta1: options.beta1 ?? 0.9,
60
+ beta2: options.beta2 ?? 0.999,
61
+ eps: options.eps ?? 1e-8,
62
+ weightDecay: options.weightDecay ?? 0,
63
+ auxWeight: options.auxWeight ?? 0.01,
64
+ batchSize: options.batchSize ?? 0,
65
+ epochs: options.epochs ?? 1,
66
+ };
67
+ this.adam = new AdamW(model, this.opt);
68
+ }
69
+
70
+ /** Train for the configured epochs. Returns the per-epoch loss history. */
71
+ fit(samples: MoESample[]): MoEEpochResult[] {
72
+ const history: MoEEpochResult[] = [];
73
+ for (let e = 0; e < this.opt.epochs; e++) history.push(this.runEpoch(samples));
74
+ return history;
75
+ }
76
+
77
+ private runEpoch(samples: MoESample[]): MoEEpochResult {
78
+ const batchSize = this.opt.batchSize > 0 ? this.opt.batchSize : samples.length;
79
+ const { numExperts, modelDim } = this.model.config;
80
+ let epochLoss = 0;
81
+ let lastAux = 0;
82
+
83
+ for (let start = 0; start < samples.length; start += batchSize) {
84
+ const batch = samples.slice(start, start + batchSize);
85
+ this.model.zeroGrad();
86
+
87
+ // Forward + task backward, retaining (x, probs) for the batch aux gradient.
88
+ const xs: Float32Array[] = [];
89
+ const probsList: Float32Array[] = [];
90
+ const counts = new Float32Array(numExperts);
91
+ let batchLoss = 0;
92
+
93
+ for (const s of batch) {
94
+ const f = this.model.forward(s.input);
95
+ const dOut = new Float32Array(modelDim);
96
+ for (let d = 0; d < modelDim; d++) {
97
+ const diff = f.output[d]! - (s.target[d] ?? 0);
98
+ dOut[d] = diff;
99
+ batchLoss += 0.5 * diff * diff;
100
+ }
101
+ this.model.backward(dOut, f.cache);
102
+ xs.push(f.cache.x);
103
+ probsList.push(f.route.probs);
104
+ for (const ex of f.route.experts) counts[ex] = counts[ex]! + 1;
105
+ }
106
+
107
+ // Load-balancing aux gradient (batch-level): f = dispatch fractions.
108
+ const dispatched = counts.reduce((a, b) => a + b, 0) || 1;
109
+ const fVec = Float32Array.from(counts, (c) => c / dispatched);
110
+ const scale = (this.opt.auxWeight * numExperts) / batch.length;
111
+ for (let i = 0; i < xs.length; i++) {
112
+ this.model.auxGradStep(xs[i]!, probsList[i]!, fVec, scale);
113
+ }
114
+
115
+ // Average the task gradient over the batch, then AdamW step.
116
+ this.scaleGradients(1 / batch.length);
117
+ this.adam.step();
118
+
119
+ epochLoss += batchLoss;
120
+ lastAux = numExperts * fVec.reduce((sum, f, e) => sum + f * (probsList.length
121
+ ? probsList.reduce((s, p) => s + p[e]!, 0) / probsList.length
122
+ : 0), 0);
123
+ }
124
+
125
+ return { loss: epochLoss / Math.max(1, samples.length), auxLoss: lastAux };
126
+ }
127
+
128
+ private scaleGradients(k: number): void {
129
+ if (k === 1) return;
130
+ for (const g of this.model.gradients()) {
131
+ for (let i = 0; i < g.data.length; i++) g.data[i] = g.data[i]! * k;
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * adamw.ts — AdamW optimiser over a model's flat parameter list.
3
+ *
4
+ * Shared by every CPU-reference trainer in the engine (MoE FFN, the full
5
+ * EvermindLM) so the optimiser maths lives in exactly one place. Operates on any
6
+ * object exposing index-aligned `parameters()` / `gradients()` Float32Arrays.
7
+ */
8
+
9
+ export interface OptimParam {
10
+ data: Float32Array;
11
+ }
12
+
13
+ export interface OptimTarget {
14
+ parameters(): OptimParam[];
15
+ gradients(): OptimParam[];
16
+ }
17
+
18
+ export interface AdamWOptions {
19
+ lr?: number;
20
+ beta1?: number;
21
+ beta2?: number;
22
+ eps?: number;
23
+ weightDecay?: number;
24
+ }
25
+
26
+ export class AdamW {
27
+ private readonly m: Float32Array[] = [];
28
+ private readonly v: Float32Array[] = [];
29
+ private t = 0;
30
+ private readonly opt: Required<AdamWOptions>;
31
+
32
+ constructor(
33
+ private readonly target: OptimTarget,
34
+ options: AdamWOptions = {},
35
+ ) {
36
+ this.opt = {
37
+ lr: options.lr ?? 0.01,
38
+ beta1: options.beta1 ?? 0.9,
39
+ beta2: options.beta2 ?? 0.999,
40
+ eps: options.eps ?? 1e-8,
41
+ weightDecay: options.weightDecay ?? 0,
42
+ };
43
+ for (const p of target.parameters()) {
44
+ this.m.push(new Float32Array(p.data.length));
45
+ this.v.push(new Float32Array(p.data.length));
46
+ }
47
+ }
48
+
49
+ /** One optimiser step from the currently-accumulated gradients. */
50
+ step(): void {
51
+ this.t++;
52
+ const { lr, beta1, beta2, eps, weightDecay } = this.opt;
53
+ const params = this.target.parameters();
54
+ const grads = this.target.gradients();
55
+ const bc1 = 1 - Math.pow(beta1, this.t);
56
+ const bc2 = 1 - Math.pow(beta2, this.t);
57
+ for (let p = 0; p < params.length; p++) {
58
+ const w = params[p]!.data;
59
+ const g = grads[p]!.data;
60
+ const m = this.m[p]!;
61
+ const v = this.v[p]!;
62
+ for (let i = 0; i < w.length; i++) {
63
+ const gi = g[i]!;
64
+ m[i] = beta1 * m[i]! + (1 - beta1) * gi;
65
+ v[i] = beta2 * v[i]! + (1 - beta2) * gi * gi;
66
+ const mh = m[i]! / bc1;
67
+ const vh = v[i]! / bc2;
68
+ w[i] = w[i]! - lr * (mh / (Math.sqrt(vh) + eps) + weightDecay * w[i]!);
69
+ }
70
+ }
71
+ }
72
+ }