@seanhogg/builderforce-memory 2026.6.18

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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +582 -0
  3. package/dist/agent/SSMAgent.d.ts +146 -0
  4. package/dist/agent/SSMAgent.d.ts.map +1 -0
  5. package/dist/agent/SSMAgent.js +231 -0
  6. package/dist/agent/SSMAgent.js.map +1 -0
  7. package/dist/agent/index.d.ts +3 -0
  8. package/dist/agent/index.d.ts.map +1 -0
  9. package/dist/agent/index.js +2 -0
  10. package/dist/agent/index.js.map +1 -0
  11. package/dist/bridges/AnthropicBridge.d.ts +47 -0
  12. package/dist/bridges/AnthropicBridge.d.ts.map +1 -0
  13. package/dist/bridges/AnthropicBridge.js +120 -0
  14. package/dist/bridges/AnthropicBridge.js.map +1 -0
  15. package/dist/bridges/CachingBridge.d.ts +44 -0
  16. package/dist/bridges/CachingBridge.d.ts.map +1 -0
  17. package/dist/bridges/CachingBridge.js +62 -0
  18. package/dist/bridges/CachingBridge.js.map +1 -0
  19. package/dist/bridges/FetchBridge.d.ts +30 -0
  20. package/dist/bridges/FetchBridge.d.ts.map +1 -0
  21. package/dist/bridges/FetchBridge.js +24 -0
  22. package/dist/bridges/FetchBridge.js.map +1 -0
  23. package/dist/bridges/OpenAIBridge.d.ts +33 -0
  24. package/dist/bridges/OpenAIBridge.d.ts.map +1 -0
  25. package/dist/bridges/OpenAIBridge.js +110 -0
  26. package/dist/bridges/OpenAIBridge.js.map +1 -0
  27. package/dist/bridges/ResponseCache.d.ts +65 -0
  28. package/dist/bridges/ResponseCache.d.ts.map +1 -0
  29. package/dist/bridges/ResponseCache.js +97 -0
  30. package/dist/bridges/ResponseCache.js.map +1 -0
  31. package/dist/bridges/SemanticCachingBridge.d.ts +31 -0
  32. package/dist/bridges/SemanticCachingBridge.d.ts.map +1 -0
  33. package/dist/bridges/SemanticCachingBridge.js +44 -0
  34. package/dist/bridges/SemanticCachingBridge.js.map +1 -0
  35. package/dist/bridges/TransformerBridge.d.ts +35 -0
  36. package/dist/bridges/TransformerBridge.d.ts.map +1 -0
  37. package/dist/bridges/TransformerBridge.js +10 -0
  38. package/dist/bridges/TransformerBridge.js.map +1 -0
  39. package/dist/bridges/index.d.ts +14 -0
  40. package/dist/bridges/index.d.ts.map +1 -0
  41. package/dist/bridges/index.js +7 -0
  42. package/dist/bridges/index.js.map +1 -0
  43. package/dist/cache/FetchSemanticCacheBackend.d.ts +40 -0
  44. package/dist/cache/FetchSemanticCacheBackend.d.ts.map +1 -0
  45. package/dist/cache/FetchSemanticCacheBackend.js +61 -0
  46. package/dist/cache/FetchSemanticCacheBackend.js.map +1 -0
  47. package/dist/cache/SemanticCache.d.ts +105 -0
  48. package/dist/cache/SemanticCache.d.ts.map +1 -0
  49. package/dist/cache/SemanticCache.js +130 -0
  50. package/dist/cache/SemanticCache.js.map +1 -0
  51. package/dist/cache/index.d.ts +5 -0
  52. package/dist/cache/index.d.ts.map +1 -0
  53. package/dist/cache/index.js +3 -0
  54. package/dist/cache/index.js.map +1 -0
  55. package/dist/distillation/DistillationEngine.d.ts +107 -0
  56. package/dist/distillation/DistillationEngine.d.ts.map +1 -0
  57. package/dist/distillation/DistillationEngine.js +152 -0
  58. package/dist/distillation/DistillationEngine.js.map +1 -0
  59. package/dist/distillation/index.d.ts +3 -0
  60. package/dist/distillation/index.d.ts.map +1 -0
  61. package/dist/distillation/index.js +2 -0
  62. package/dist/distillation/index.js.map +1 -0
  63. package/dist/errors/SSMError.d.ts +14 -0
  64. package/dist/errors/SSMError.d.ts.map +1 -0
  65. package/dist/errors/SSMError.js +18 -0
  66. package/dist/errors/SSMError.js.map +1 -0
  67. package/dist/errors/index.d.ts +3 -0
  68. package/dist/errors/index.d.ts.map +1 -0
  69. package/dist/errors/index.js +2 -0
  70. package/dist/errors/index.js.map +1 -0
  71. package/dist/index.d.ts +65 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +59 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/memory/MemoryStore.d.ts +152 -0
  76. package/dist/memory/MemoryStore.d.ts.map +1 -0
  77. package/dist/memory/MemoryStore.js +290 -0
  78. package/dist/memory/MemoryStore.js.map +1 -0
  79. package/dist/memory/index.d.ts +3 -0
  80. package/dist/memory/index.d.ts.map +1 -0
  81. package/dist/memory/index.js +2 -0
  82. package/dist/memory/index.js.map +1 -0
  83. package/dist/router/InferenceRouter.d.ts +92 -0
  84. package/dist/router/InferenceRouter.d.ts.map +1 -0
  85. package/dist/router/InferenceRouter.js +113 -0
  86. package/dist/router/InferenceRouter.js.map +1 -0
  87. package/dist/router/index.d.ts +3 -0
  88. package/dist/router/index.d.ts.map +1 -0
  89. package/dist/router/index.js +2 -0
  90. package/dist/router/index.js.map +1 -0
  91. package/dist/runtime/SSMRuntime.d.ts +167 -0
  92. package/dist/runtime/SSMRuntime.d.ts.map +1 -0
  93. package/dist/runtime/SSMRuntime.js +199 -0
  94. package/dist/runtime/SSMRuntime.js.map +1 -0
  95. package/dist/runtime/index.d.ts +3 -0
  96. package/dist/runtime/index.d.ts.map +1 -0
  97. package/dist/runtime/index.js +2 -0
  98. package/dist/runtime/index.js.map +1 -0
  99. package/dist/session/errors.d.ts +10 -0
  100. package/dist/session/errors.d.ts.map +1 -0
  101. package/dist/session/errors.js +14 -0
  102. package/dist/session/errors.js.map +1 -0
  103. package/dist/session/index.d.ts +11 -0
  104. package/dist/session/index.d.ts.map +1 -0
  105. package/dist/session/index.js +7 -0
  106. package/dist/session/index.js.map +1 -0
  107. package/dist/session/persistence.d.ts +14 -0
  108. package/dist/session/persistence.d.ts.map +1 -0
  109. package/dist/session/persistence.js +100 -0
  110. package/dist/session/persistence.js.map +1 -0
  111. package/dist/session/presets.d.ts +31 -0
  112. package/dist/session/presets.d.ts.map +1 -0
  113. package/dist/session/presets.js +91 -0
  114. package/dist/session/presets.js.map +1 -0
  115. package/dist/session/session.d.ts +186 -0
  116. package/dist/session/session.d.ts.map +1 -0
  117. package/dist/session/session.js +358 -0
  118. package/dist/session/session.js.map +1 -0
  119. package/dist/session/streaming.d.ts +13 -0
  120. package/dist/session/streaming.d.ts.map +1 -0
  121. package/dist/session/streaming.js +74 -0
  122. package/dist/session/streaming.js.map +1 -0
  123. package/dist/session/tokenizer.d.ts +18 -0
  124. package/dist/session/tokenizer.d.ts.map +1 -0
  125. package/dist/session/tokenizer.js +11 -0
  126. package/dist/session/tokenizer.js.map +1 -0
  127. package/dist/similarity/index.d.ts +19 -0
  128. package/dist/similarity/index.d.ts.map +1 -0
  129. package/dist/similarity/index.js +42 -0
  130. package/dist/similarity/index.js.map +1 -0
  131. package/package.json +120 -0
  132. package/src/agent/SSMAgent.ts +327 -0
  133. package/src/agent/index.ts +2 -0
  134. package/src/bridges/AnthropicBridge.ts +166 -0
  135. package/src/bridges/CachingBridge.ts +79 -0
  136. package/src/bridges/FetchBridge.ts +41 -0
  137. package/src/bridges/OpenAIBridge.ts +143 -0
  138. package/src/bridges/ResponseCache.ts +131 -0
  139. package/src/bridges/SemanticCachingBridge.ts +60 -0
  140. package/src/bridges/TransformerBridge.ts +38 -0
  141. package/src/bridges/index.ts +13 -0
  142. package/src/cache/FetchSemanticCacheBackend.ts +79 -0
  143. package/src/cache/SemanticCache.ts +196 -0
  144. package/src/cache/index.ts +9 -0
  145. package/src/distillation/DistillationEngine.ts +248 -0
  146. package/src/distillation/index.ts +2 -0
  147. package/src/errors/SSMError.ts +26 -0
  148. package/src/errors/index.ts +2 -0
  149. package/src/index.ts +128 -0
  150. package/src/memory/MemoryStore.ts +408 -0
  151. package/src/memory/index.ts +2 -0
  152. package/src/router/InferenceRouter.ts +201 -0
  153. package/src/router/index.ts +2 -0
  154. package/src/runtime/SSMRuntime.ts +309 -0
  155. package/src/runtime/index.ts +2 -0
  156. package/src/session/errors.ts +24 -0
  157. package/src/session/index.ts +25 -0
  158. package/src/session/persistence.ts +142 -0
  159. package/src/session/presets.ts +122 -0
  160. package/src/session/session.ts +657 -0
  161. package/src/session/streaming.ts +97 -0
  162. package/src/session/tokenizer.ts +18 -0
  163. package/src/similarity/index.ts +42 -0
@@ -0,0 +1,91 @@
1
+ /**
2
+ * presets.ts – Model size presets and config resolver for the MambaSession layer.
3
+ */
4
+ // ── Model size presets ────────────────────────────────────────────────────────
5
+ /**
6
+ * Pre-defined model size presets.
7
+ * nHeads is used by Mamba-2/3 and Attention layers; ignored for Mamba-1.
8
+ */
9
+ export const MODEL_PRESETS = {
10
+ nano: { dModel: 128, numLayers: 4, dState: 16, dConv: 4, expand: 2, nHeads: 4 },
11
+ small: { dModel: 256, numLayers: 6, dState: 16, dConv: 4, expand: 2, nHeads: 8 },
12
+ medium: { dModel: 512, numLayers: 8, dState: 16, dConv: 4, expand: 2, nHeads: 8 },
13
+ large: { dModel: 768, numLayers: 12, dState: 16, dConv: 4, expand: 2, nHeads: 12 },
14
+ };
15
+ const DEFAULT_PRESET = 'nano';
16
+ /**
17
+ * Resolve a layer schedule from a preset name, explicit array, or undefined.
18
+ *
19
+ * 'jamba' — Jamba-style: every 4th layer (index 3, 7, 11…) is attention, rest mamba2
20
+ * 'zamba' — Zamba-style: every 6th layer (index 5, 11…) is attention, rest mamba3
21
+ */
22
+ export function resolveLayerSchedule(schedule, numLayers, defaultType) {
23
+ if (!schedule) {
24
+ return Array.from({ length: numLayers }, () => ({ type: defaultType }));
25
+ }
26
+ if (schedule === 'jamba') {
27
+ return Array.from({ length: numLayers }, (_, i) => ({
28
+ type: (i % 4 === 3 ? 'attention' : 'mamba2'),
29
+ }));
30
+ }
31
+ if (schedule === 'zamba') {
32
+ return Array.from({ length: numLayers }, (_, i) => ({
33
+ type: (i % 6 === 5 ? 'attention' : 'mamba3'),
34
+ }));
35
+ }
36
+ return schedule;
37
+ }
38
+ // ── Config resolution ─────────────────────────────────────────────────────────
39
+ /**
40
+ * Resolves a fully-populated HybridMambaModelConfig from session options and
41
+ * the actual tokenizer vocab size.
42
+ *
43
+ * Resolution order:
44
+ * 1. Preset fields (default: 'nano')
45
+ * 2. modelConfig overrides (only applied when modelSize === 'custom')
46
+ * 3. vocabSize from the tokenizer
47
+ * 4. mambaVersion → default layer type for schedule resolution
48
+ * 5. layerSchedule → per-layer type array (preset string or explicit array)
49
+ */
50
+ export function resolveModelConfig(options, vocabSize) {
51
+ const presetName = options.modelSize === 'custom' || options.modelSize == null
52
+ ? DEFAULT_PRESET
53
+ : options.modelSize;
54
+ const preset = MODEL_PRESETS[presetName] ?? MODEL_PRESETS[DEFAULT_PRESET];
55
+ const overrides = options.modelSize === 'custom' && options.modelConfig
56
+ ? options.modelConfig
57
+ : {};
58
+ const dModel = overrides.dModel ?? preset.dModel ?? 128;
59
+ const numLayers = overrides.numLayers ?? preset.numLayers ?? 4;
60
+ const dState = overrides.dState ?? preset.dState ?? 16;
61
+ const dConv = overrides.dConv ?? preset.dConv ?? 4;
62
+ const expand = overrides.expand ?? preset.expand ?? 2;
63
+ const nHeads = overrides.nHeads ?? preset.nHeads ?? 4;
64
+ const nGroups = overrides.nGroups ?? preset.nGroups ?? 1;
65
+ const chunkLen = overrides.chunkLen ?? preset.chunkLen ?? 256;
66
+ const mimoGroup = overrides.mimoGroup ?? preset.mimoGroup ?? 1;
67
+ const eosId = overrides.eosId ?? preset.eosId ?? -1;
68
+ // Validate nHeads divides dModel for multi-head blocks
69
+ if (dModel % nHeads !== 0) {
70
+ throw new Error(`resolveModelConfig: dModel (${dModel}) must be divisible by nHeads (${nHeads}).`);
71
+ }
72
+ // Layer schedule
73
+ const defaultType = options.mambaVersion ?? 'mamba1';
74
+ const layers = resolveLayerSchedule(options.layerSchedule, numLayers, defaultType);
75
+ return {
76
+ vocabSize,
77
+ dModel,
78
+ numLayers,
79
+ dState,
80
+ dConv,
81
+ expand,
82
+ nHeads,
83
+ nGroups,
84
+ chunkLen,
85
+ mimoGroup,
86
+ eosId,
87
+ layers,
88
+ seed: options.seed,
89
+ };
90
+ }
91
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/session/presets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ /**
2
+ * session.ts – MambaSession: the single entry point for all session-layer functionality.
3
+ *
4
+ * MambaSession is a facade over MambaCode.js that collapses the 8-step
5
+ * async setup sequence into a single `MambaSession.create()` call.
6
+ *
7
+ * Part of the @seanhogg/ssmjs session layer.
8
+ */
9
+ import { BPETokenizer, HybridMambaModel, MambaTrainer, type HybridMambaModelConfig, type LayerSpec, type LayerType } from '@seanhogg/builderforce-memory-engine';
10
+ import type { Tokenizer } from './tokenizer.js';
11
+ export interface MambaSessionOptions {
12
+ /** URL to a .bin checkpoint file. Optional — model starts with random weights if omitted. */
13
+ checkpointUrl?: string;
14
+ /**
15
+ * Pre-read checkpoint bytes. Takes precedence over `checkpointUrl` and is
16
+ * loaded directly via `model.loadWeights()` with no network fetch.
17
+ * Use this in Node.js, where `fetch()` cannot read local file paths — read
18
+ * the .bin with `fs` and pass the resulting ArrayBuffer here.
19
+ */
20
+ checkpointBuffer?: ArrayBuffer;
21
+ /** URL to vocab.json. Defaults to the Qwen2.5-Coder vocabulary. */
22
+ vocabUrl?: string;
23
+ /** URL to merges.txt. Defaults to the Qwen2.5-Coder merge rules. */
24
+ mergesUrl?: string;
25
+ /** In-memory vocabulary object — alternative to vocabUrl. */
26
+ vocabObject?: Record<string, number>;
27
+ /** In-memory merges array — alternative to mergesUrl. */
28
+ mergesArray?: string[];
29
+ /**
30
+ * A fully-constructed tokenizer to use instead of BPETokenizer.
31
+ * When provided, `vocabUrl`, `mergesUrl`, `vocabObject`, and `mergesArray`
32
+ * are all ignored — MambaSession will use this tokenizer directly.
33
+ * The tokenizer must satisfy the `Tokenizer` interface.
34
+ */
35
+ tokenizer?: Tokenizer;
36
+ /** Unique name for this session, used as the IndexedDB key. Default: 'default'. */
37
+ name?: string;
38
+ /**
39
+ * Model size preset. Overrides individual model config fields.
40
+ * - 'nano' : dModel=128, numLayers=4
41
+ * - 'small' : dModel=256, numLayers=6
42
+ * - 'medium' : dModel=512, numLayers=8 (default)
43
+ * - 'large' : dModel=768, numLayers=12
44
+ * - 'custom' : use modelConfig directly
45
+ */
46
+ modelSize?: 'nano' | 'small' | 'medium' | 'large' | 'custom';
47
+ /** Fine-grained model configuration. Only used when modelSize is 'custom'. */
48
+ modelConfig?: Partial<HybridMambaModelConfig>;
49
+ /**
50
+ * SSM variant applied to all layers when no layerSchedule is given.
51
+ * Default: 'mamba1' (existing behaviour).
52
+ */
53
+ mambaVersion?: LayerType extends 'attention' ? never : 'mamba1' | 'mamba2' | 'mamba3';
54
+ /**
55
+ * Per-layer type schedule. Length must equal the resolved numLayers.
56
+ * Overrides mambaVersion when provided.
57
+ *
58
+ * Preset strings:
59
+ * 'jamba' — every 4th layer is attention, rest mamba2
60
+ * 'zamba' — every 6th layer is attention, rest mamba3
61
+ */
62
+ layerSchedule?: LayerSpec[] | 'jamba' | 'zamba';
63
+ /**
64
+ * Pre-created GPUAdapter to use instead of calling navigator.gpu.requestAdapter().
65
+ * Use this in Node.js environments with @webgpu/node:
66
+ * import { create as createGPU } from '@webgpu/node';
67
+ * const gpuAdapter = await createGPU().requestAdapter();
68
+ * When provided, `powerPreference` and `allowCpuFallback` are ignored.
69
+ */
70
+ gpuAdapter?: GPUAdapter;
71
+ /**
72
+ * IDBFactory to use instead of the global `indexedDB`.
73
+ * Use this in Node.js environments with fake-indexeddb:
74
+ * import { IDBFactory } from 'fake-indexeddb';
75
+ * const idbFactory = new IDBFactory();
76
+ * When provided, the 'indexedDB' storage target uses this factory.
77
+ */
78
+ idbFactory?: IDBFactory;
79
+ /** WebGPU power preference. Default: 'high-performance'. */
80
+ powerPreference?: 'high-performance' | 'low-power';
81
+ /**
82
+ * When true, MambaSession will attempt to obtain a software (CPU) WebGPU
83
+ * adapter if the preferred GPU adapter is unavailable — for example in
84
+ * environments that lack a discrete GPU or where the browser has disabled
85
+ * WebGPU. Performance will be significantly degraded, but the session will
86
+ * still initialise and produce correct output.
87
+ *
88
+ * Requires a browser/runtime that supports `forceFallbackAdapter: true` on
89
+ * `navigator.gpu.requestAdapter()`. Node.js environments may not have a
90
+ * software adapter available; an error is thrown in that case.
91
+ *
92
+ * Default: false (a missing GPU is a hard error).
93
+ */
94
+ allowCpuFallback?: boolean;
95
+ /** Number of times to retry a failed checkpoint fetch. Default: 2. */
96
+ fetchRetries?: number;
97
+ /**
98
+ * Deterministic seed for weight initialisation. When set, a model created
99
+ * without a checkpoint initialises reproducibly — the same seed yields
100
+ * byte-identical weights on any machine. Omit for non-reproducible
101
+ * `Math.random` init (the default).
102
+ */
103
+ seed?: number;
104
+ }
105
+ export interface CompleteOptions {
106
+ maxNewTokens?: number;
107
+ temperature?: number;
108
+ topK?: number;
109
+ topP?: number;
110
+ }
111
+ export interface AdaptOptions {
112
+ epochs?: number;
113
+ learningRate?: number;
114
+ seqLen?: number;
115
+ wsla?: boolean;
116
+ fullTrain?: boolean;
117
+ onProgress?: (epoch: number, loss: number) => void;
118
+ }
119
+ export interface AdaptResult {
120
+ losses: number[];
121
+ epochCount: number;
122
+ durationMs: number;
123
+ }
124
+ export type StorageTarget = 'indexedDB' | 'download' | 'fileSystem';
125
+ export interface SaveOptions {
126
+ storage?: StorageTarget;
127
+ filename?: string;
128
+ key?: string;
129
+ }
130
+ export interface LoadOptions {
131
+ storage?: StorageTarget;
132
+ url?: string;
133
+ key?: string;
134
+ }
135
+ export type CreateStage = 'gpu' | 'tokenizer' | 'model' | 'weights';
136
+ export interface CreateProgressEvent {
137
+ stage: CreateStage;
138
+ progress: number;
139
+ message: string;
140
+ }
141
+ export interface SessionInternals {
142
+ device: GPUDevice;
143
+ model: HybridMambaModel;
144
+ trainer: MambaTrainer;
145
+ tokenizer: BPETokenizer;
146
+ }
147
+ export interface CreateCallbacks {
148
+ onProgress?: (event: CreateProgressEvent) => void;
149
+ }
150
+ export type GpuMode = 'webgpu' | 'cpu-fallback';
151
+ export declare class MambaSession {
152
+ private _device;
153
+ private _tokenizer;
154
+ private _model;
155
+ private _trainer;
156
+ private _name;
157
+ private _destroyed;
158
+ private _gpuMode;
159
+ private _idbFactory;
160
+ /**
161
+ * Whether the session is running on a real GPU ('webgpu') or a software
162
+ * CPU fallback ('cpu-fallback'). Only 'cpu-fallback' when
163
+ * `allowCpuFallback: true` was passed and no GPU was available.
164
+ */
165
+ get gpuMode(): GpuMode;
166
+ private constructor();
167
+ static create(options: MambaSessionOptions, callbacks?: CreateCallbacks): Promise<MambaSession>;
168
+ complete(prompt: string, options?: CompleteOptions): Promise<string>;
169
+ completeStream(prompt: string, options?: CompleteOptions): AsyncIterable<string>;
170
+ /**
171
+ * Returns a fixed-length (`dModel`) L2-normalised embedding for `text`,
172
+ * derived from the model's final hidden state. Suitable for cosine-similarity
173
+ * semantic search (see MemoryStore.recallSimilar).
174
+ *
175
+ * Returns a zero vector for empty input.
176
+ */
177
+ embed(text: string): Promise<Float32Array>;
178
+ adapt(text: string, options?: AdaptOptions): Promise<AdaptResult>;
179
+ evaluate(text: string): Promise<number>;
180
+ save(options?: SaveOptions): Promise<void>;
181
+ load(options?: LoadOptions): Promise<boolean>;
182
+ destroy(): void;
183
+ get internals(): SessionInternals;
184
+ private _assertNotDestroyed;
185
+ }
186
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/session/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,358 @@
1
+ /**
2
+ * session.ts – MambaSession: the single entry point for all session-layer functionality.
3
+ *
4
+ * MambaSession is a facade over MambaCode.js that collapses the 8-step
5
+ * async setup sequence into a single `MambaSession.create()` call.
6
+ *
7
+ * Part of the @seanhogg/ssmjs session layer.
8
+ */
9
+ import { initWebGPU, BPETokenizer, HybridMambaModel, MambaTrainer, } from '@seanhogg/builderforce-memory-engine';
10
+ import { SessionError } from './errors.js';
11
+ // ── Opinionated defaults ───────────────────────────────────────────────────────
12
+ /** Default tokenizer: Qwen2.5-Coder BPE vocabulary (Apache 2.0). */
13
+ const DEFAULT_VOCAB_URL = 'https://huggingface.co/Qwen/Qwen2.5-Coder-1.5B-Instruct/resolve/main/vocab.json';
14
+ const DEFAULT_MERGES_URL = 'https://huggingface.co/Qwen/Qwen2.5-Coder-1.5B-Instruct/resolve/main/merges.txt';
15
+ // Checkpoint provenance
16
+ // ----------------------
17
+ // There is intentionally no hard-coded default checkpoint URL. A model with no
18
+ // checkpoint starts from initialised weights and generates poorly until trained
19
+ // or adapted — callers must opt in to a checkpoint explicitly via one of:
20
+ // • `checkpointUrl` — fetch a hosted .bin (browser or any fetch-capable env)
21
+ // • `checkpointBuffer` — load an already-read ArrayBuffer (Node/local files;
22
+ // fetch() cannot read local paths in Node)
23
+ // To produce a checkpoint without a hosted model:
24
+ // • Untrained (deterministic seed): `node tools/generate-bin.js --size nano`
25
+ // • Trained: open tools/pretrain.html, train on a corpus, download the .bin
26
+ import { resolveModelConfig } from './presets.js';
27
+ import { saveToIndexedDB, loadFromIndexedDB, triggerDownload, saveViaFileSystemAPI, loadViaFileSystemAPI, } from './persistence.js';
28
+ import { tokenStream } from './streaming.js';
29
+ /** Base delay (ms) for the first checkpoint fetch retry. Subsequent retries double this. */
30
+ const RETRY_BASE_DELAY_MS = 500;
31
+ /** Multiplier applied to delay on each successive retry. */
32
+ const RETRY_BACKOFF_FACTOR = 2;
33
+ export class MambaSession {
34
+ _device;
35
+ _tokenizer;
36
+ _model;
37
+ _trainer;
38
+ _name;
39
+ _destroyed = false;
40
+ _gpuMode = 'webgpu';
41
+ _idbFactory;
42
+ /**
43
+ * Whether the session is running on a real GPU ('webgpu') or a software
44
+ * CPU fallback ('cpu-fallback'). Only 'cpu-fallback' when
45
+ * `allowCpuFallback: true` was passed and no GPU was available.
46
+ */
47
+ get gpuMode() { return this._gpuMode; }
48
+ constructor(device, tokenizer, model, trainer, name, gpuMode = 'webgpu', idbFactory) {
49
+ this._device = device;
50
+ this._tokenizer = tokenizer;
51
+ this._model = model;
52
+ this._trainer = trainer;
53
+ this._name = name;
54
+ this._gpuMode = gpuMode;
55
+ this._idbFactory = idbFactory;
56
+ }
57
+ // ── Static factory ─────────────────────────────────────────────────────────
58
+ static async create(options, callbacks = {}) {
59
+ const { onProgress } = callbacks;
60
+ const name = options.name ?? 'default';
61
+ const fetchRetries = options.fetchRetries ?? 2;
62
+ const emit = (stage, progress, message) => {
63
+ onProgress?.({ stage, progress, message });
64
+ };
65
+ // Step 1 — GPU
66
+ emit('gpu', 0.0, 'Initialising WebGPU…');
67
+ let device;
68
+ let gpuMode = 'webgpu';
69
+ if (options.gpuAdapter != null) {
70
+ // Adapter injected externally (e.g. @webgpu/node in Node.js)
71
+ try {
72
+ device = await options.gpuAdapter.requestDevice();
73
+ }
74
+ catch (err) {
75
+ throw new SessionError('GPU_UNAVAILABLE', `Failed to acquire GPUDevice from provided gpuAdapter: ${err.message}`, err);
76
+ }
77
+ emit('gpu', 1.0, 'WebGPU ready (injected adapter)');
78
+ }
79
+ else {
80
+ try {
81
+ const result = await initWebGPU({
82
+ powerPreference: options.powerPreference ?? 'high-performance',
83
+ });
84
+ device = result.device;
85
+ }
86
+ catch (primaryErr) {
87
+ if (!options.allowCpuFallback) {
88
+ throw new SessionError('GPU_UNAVAILABLE', `WebGPU initialisation failed: ${primaryErr.message}. ` +
89
+ `Set allowCpuFallback: true to attempt a software (CPU) fallback.`, primaryErr);
90
+ }
91
+ // Attempt software (CPU) adapter — available in Chrome with
92
+ // --enable-unsafe-webgpu or in environments with a WARP/SwiftShader adapter.
93
+ emit('gpu', 0.4, `WebGPU unavailable (${primaryErr.message}); ` +
94
+ `attempting CPU software fallback — performance will be degraded.`);
95
+ if (typeof navigator === 'undefined' || !navigator.gpu) {
96
+ throw new SessionError('GPU_UNAVAILABLE', 'WebGPU is not available in this environment and no software adapter can be requested.', primaryErr);
97
+ }
98
+ try {
99
+ const fallbackAdapter = await navigator.gpu.requestAdapter({
100
+ powerPreference: 'low-power',
101
+ forceFallbackAdapter: true,
102
+ });
103
+ if (!fallbackAdapter)
104
+ throw new Error('requestAdapter returned null');
105
+ device = await fallbackAdapter.requestDevice();
106
+ gpuMode = 'cpu-fallback';
107
+ }
108
+ catch (fallbackErr) {
109
+ throw new SessionError('GPU_UNAVAILABLE', `WebGPU unavailable and CPU fallback failed: ${fallbackErr.message}`, fallbackErr);
110
+ }
111
+ }
112
+ emit('gpu', 1.0, gpuMode === 'cpu-fallback'
113
+ ? 'CPU software adapter ready (degraded performance)'
114
+ : 'WebGPU ready');
115
+ }
116
+ // Step 2 — Tokenizer
117
+ emit('tokenizer', 0.0, 'Loading tokenizer…');
118
+ let tokenizer;
119
+ if (options.tokenizer != null) {
120
+ // Custom tokenizer injected — skip BPETokenizer construction entirely.
121
+ // Wrap it in a BPETokenizer-shaped proxy so the rest of the code is unchanged.
122
+ const custom = options.tokenizer;
123
+ tokenizer = Object.assign(new BPETokenizer(), {
124
+ encode: (text) => custom.encode(text),
125
+ decode: (ids) => custom.decode(ids),
126
+ get vocabSize() { return custom.vocabSize; },
127
+ });
128
+ }
129
+ else {
130
+ tokenizer = new BPETokenizer();
131
+ try {
132
+ if (options.vocabObject != null && options.mergesArray != null) {
133
+ tokenizer.loadFromObjects(options.vocabObject, options.mergesArray);
134
+ }
135
+ else {
136
+ const vocabUrl = options.vocabUrl ?? DEFAULT_VOCAB_URL;
137
+ const mergesUrl = options.mergesUrl ?? DEFAULT_MERGES_URL;
138
+ await tokenizer.load(vocabUrl, mergesUrl);
139
+ }
140
+ }
141
+ catch (err) {
142
+ throw new SessionError('TOKENIZER_LOAD_FAILED', `Tokenizer failed to load: ${err.message}`, err);
143
+ }
144
+ }
145
+ emit('tokenizer', 1.0, 'Tokenizer ready');
146
+ // Step 3 — Model & Trainer
147
+ emit('model', 0.0, 'Building model…');
148
+ const vocabSize = tokenizer.vocabSize > 0 ? tokenizer.vocabSize : 1;
149
+ const config = resolveModelConfig(options, vocabSize);
150
+ const model = new HybridMambaModel(device, config);
151
+ const trainer = new MambaTrainer(model, tokenizer);
152
+ emit('model', 1.0, 'Model ready');
153
+ // Step 4 — Checkpoint (optional)
154
+ // A pre-read buffer takes precedence over a URL (Node/local-file path);
155
+ // fetch() is only used when a URL is supplied.
156
+ if (options.checkpointBuffer != null) {
157
+ emit('weights', 0.0, 'Loading checkpoint…');
158
+ try {
159
+ await model.loadWeights(options.checkpointBuffer);
160
+ }
161
+ catch (err) {
162
+ throw new SessionError('CHECKPOINT_INVALID', `Checkpoint buffer is invalid or incompatible: ${err.message}`, err);
163
+ }
164
+ emit('weights', 1.0, 'Checkpoint loaded');
165
+ }
166
+ else if (options.checkpointUrl != null) {
167
+ emit('weights', 0.0, 'Fetching checkpoint…');
168
+ let buffer = null;
169
+ let lastErr;
170
+ for (let attempt = 0; attempt <= fetchRetries; attempt++) {
171
+ try {
172
+ const res = await fetch(options.checkpointUrl);
173
+ if (!res.ok) {
174
+ throw new Error(`HTTP ${res.status} ${res.statusText}`);
175
+ }
176
+ buffer = await res.arrayBuffer();
177
+ break;
178
+ }
179
+ catch (err) {
180
+ lastErr = err;
181
+ if (attempt < fetchRetries) {
182
+ await sleep(RETRY_BASE_DELAY_MS * Math.pow(RETRY_BACKOFF_FACTOR, attempt));
183
+ }
184
+ }
185
+ }
186
+ if (buffer == null) {
187
+ throw new SessionError('CHECKPOINT_FETCH_FAILED', `Failed to fetch checkpoint from "${options.checkpointUrl}" after ${fetchRetries + 1} attempt(s): ${lastErr.message}`, lastErr);
188
+ }
189
+ try {
190
+ await model.loadWeights(buffer);
191
+ }
192
+ catch (err) {
193
+ throw new SessionError('CHECKPOINT_INVALID', `Checkpoint file is invalid or incompatible: ${err.message}`, err);
194
+ }
195
+ emit('weights', 1.0, 'Checkpoint loaded');
196
+ }
197
+ return new MambaSession(device, tokenizer, model, trainer, name, gpuMode, options.idbFactory);
198
+ }
199
+ // ── Text generation ────────────────────────────────────────────────────────
200
+ async complete(prompt, options = {}) {
201
+ this._assertNotDestroyed();
202
+ const { maxNewTokens = 200, temperature = 0.8, topK = 50, topP = 0.9, } = options;
203
+ const promptIds = this._tokenizer.encode(prompt);
204
+ const outputIds = await this._model.generate(promptIds, maxNewTokens, {
205
+ temperature,
206
+ topK,
207
+ topP,
208
+ });
209
+ // Return the continuation only (not the original prompt tokens)
210
+ const continuationIds = outputIds.slice(promptIds.length);
211
+ return this._tokenizer.decode(continuationIds);
212
+ }
213
+ async *completeStream(prompt, options = {}) {
214
+ this._assertNotDestroyed();
215
+ const { maxNewTokens = 200, temperature = 0.8, topK = 50, topP = 0.9, } = options;
216
+ const promptIds = this._tokenizer.encode(prompt);
217
+ for await (const tokenId of tokenStream(this._model, promptIds, maxNewTokens, {
218
+ temperature,
219
+ topK,
220
+ topP,
221
+ })) {
222
+ yield this._tokenizer.decode([tokenId]);
223
+ }
224
+ }
225
+ // ── Embedding ──────────────────────────────────────────────────────────────
226
+ /**
227
+ * Returns a fixed-length (`dModel`) L2-normalised embedding for `text`,
228
+ * derived from the model's final hidden state. Suitable for cosine-similarity
229
+ * semantic search (see MemoryStore.recallSimilar).
230
+ *
231
+ * Returns a zero vector for empty input.
232
+ */
233
+ async embed(text) {
234
+ this._assertNotDestroyed();
235
+ const ids = this._tokenizer.encode(text);
236
+ if (ids.length === 0) {
237
+ return new Float32Array(this._model.config.dModel);
238
+ }
239
+ return this._model.embed(ids);
240
+ }
241
+ // ── Fine-tuning ────────────────────────────────────────────────────────────
242
+ async adapt(text, options = {}) {
243
+ this._assertNotDestroyed();
244
+ let { epochs = 3, wsla = true, } = options;
245
+ const { learningRate = 1e-4, seqLen = 512, fullTrain = false, onProgress, } = options;
246
+ // Convenience alias: fullTrain overrides wsla and epoch defaults
247
+ if (fullTrain) {
248
+ wsla = false;
249
+ epochs = options.epochs ?? 5;
250
+ }
251
+ const encoded = this._tokenizer.encode(text);
252
+ if (encoded.length < 2) {
253
+ throw new SessionError('INPUT_TOO_SHORT', 'The input text encodes to fewer than 2 tokens and cannot be used for training.');
254
+ }
255
+ const startTime = Date.now();
256
+ const losses = await this._trainer.train(text, {
257
+ epochs,
258
+ learningRate,
259
+ seqLen,
260
+ wsla,
261
+ onEpochEnd: onProgress ?? null,
262
+ });
263
+ return {
264
+ losses,
265
+ epochCount: losses.length,
266
+ durationMs: Date.now() - startTime,
267
+ };
268
+ }
269
+ // ── Evaluation ─────────────────────────────────────────────────────────────
270
+ async evaluate(text) {
271
+ this._assertNotDestroyed();
272
+ return this._trainer.evaluate(text);
273
+ }
274
+ // ── Persistence ────────────────────────────────────────────────────────────
275
+ async save(options = {}) {
276
+ this._assertNotDestroyed();
277
+ const storage = options.storage ?? 'indexedDB';
278
+ const key = options.key ?? this._name;
279
+ const filename = options.filename ?? `${this._name}.bin`;
280
+ const buffer = await this._model.exportWeights();
281
+ switch (storage) {
282
+ case 'indexedDB':
283
+ await saveToIndexedDB(key, buffer, this._idbFactory);
284
+ break;
285
+ case 'download':
286
+ await triggerDownload(filename, buffer);
287
+ break;
288
+ case 'fileSystem':
289
+ await saveViaFileSystemAPI(filename, buffer);
290
+ break;
291
+ default:
292
+ throw new SessionError('STORAGE_UNAVAILABLE', `Unknown storage target: "${storage}"`);
293
+ }
294
+ }
295
+ async load(options = {}) {
296
+ this._assertNotDestroyed();
297
+ const storage = options.storage ?? 'indexedDB';
298
+ const key = options.key ?? this._name;
299
+ let buffer;
300
+ switch (storage) {
301
+ case 'indexedDB': {
302
+ buffer = await loadFromIndexedDB(key, this._idbFactory);
303
+ break;
304
+ }
305
+ case 'fileSystem': {
306
+ buffer = await loadViaFileSystemAPI();
307
+ break;
308
+ }
309
+ default: {
310
+ // Treat any other string as a URL fetch (covers custom `url` option)
311
+ const url = options.url;
312
+ if (!url) {
313
+ throw new SessionError('STORAGE_UNAVAILABLE', 'load() with storage other than "indexedDB" or "fileSystem" requires a url option.');
314
+ }
315
+ const res = await fetch(url);
316
+ if (!res.ok) {
317
+ throw new SessionError('CHECKPOINT_FETCH_FAILED', `Failed to fetch checkpoint from "${url}": HTTP ${res.status}`);
318
+ }
319
+ buffer = await res.arrayBuffer();
320
+ }
321
+ }
322
+ if (buffer == null)
323
+ return false;
324
+ try {
325
+ await this._model.loadWeights(buffer);
326
+ }
327
+ catch (err) {
328
+ throw new SessionError('CHECKPOINT_INVALID', `Saved checkpoint is invalid or incompatible: ${err.message}`, err);
329
+ }
330
+ return true;
331
+ }
332
+ // ── Resource cleanup ───────────────────────────────────────────────────────
333
+ destroy() {
334
+ if (this._destroyed)
335
+ return;
336
+ this._destroyed = true;
337
+ this._device.destroy();
338
+ }
339
+ // ── Escape hatch ───────────────────────────────────────────────────────────
340
+ get internals() {
341
+ return {
342
+ device: this._device,
343
+ model: this._model,
344
+ trainer: this._trainer,
345
+ tokenizer: this._tokenizer,
346
+ };
347
+ }
348
+ // ── Private helpers ────────────────────────────────────────────────────────
349
+ _assertNotDestroyed() {
350
+ if (this._destroyed) {
351
+ throw new SessionError('SESSION_DESTROYED', 'This MambaSession has been destroyed. Create a new session with MambaSession.create().');
352
+ }
353
+ }
354
+ }
355
+ function sleep(ms) {
356
+ return new Promise(resolve => setTimeout(resolve, ms));
357
+ }
358
+ //# sourceMappingURL=session.js.map