@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.
- package/LICENSE +21 -0
- package/README.md +582 -0
- package/dist/agent/SSMAgent.d.ts +146 -0
- package/dist/agent/SSMAgent.d.ts.map +1 -0
- package/dist/agent/SSMAgent.js +231 -0
- package/dist/agent/SSMAgent.js.map +1 -0
- package/dist/agent/index.d.ts +3 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/bridges/AnthropicBridge.d.ts +47 -0
- package/dist/bridges/AnthropicBridge.d.ts.map +1 -0
- package/dist/bridges/AnthropicBridge.js +120 -0
- package/dist/bridges/AnthropicBridge.js.map +1 -0
- package/dist/bridges/CachingBridge.d.ts +44 -0
- package/dist/bridges/CachingBridge.d.ts.map +1 -0
- package/dist/bridges/CachingBridge.js +62 -0
- package/dist/bridges/CachingBridge.js.map +1 -0
- package/dist/bridges/FetchBridge.d.ts +30 -0
- package/dist/bridges/FetchBridge.d.ts.map +1 -0
- package/dist/bridges/FetchBridge.js +24 -0
- package/dist/bridges/FetchBridge.js.map +1 -0
- package/dist/bridges/OpenAIBridge.d.ts +33 -0
- package/dist/bridges/OpenAIBridge.d.ts.map +1 -0
- package/dist/bridges/OpenAIBridge.js +110 -0
- package/dist/bridges/OpenAIBridge.js.map +1 -0
- package/dist/bridges/ResponseCache.d.ts +65 -0
- package/dist/bridges/ResponseCache.d.ts.map +1 -0
- package/dist/bridges/ResponseCache.js +97 -0
- package/dist/bridges/ResponseCache.js.map +1 -0
- package/dist/bridges/SemanticCachingBridge.d.ts +31 -0
- package/dist/bridges/SemanticCachingBridge.d.ts.map +1 -0
- package/dist/bridges/SemanticCachingBridge.js +44 -0
- package/dist/bridges/SemanticCachingBridge.js.map +1 -0
- package/dist/bridges/TransformerBridge.d.ts +35 -0
- package/dist/bridges/TransformerBridge.d.ts.map +1 -0
- package/dist/bridges/TransformerBridge.js +10 -0
- package/dist/bridges/TransformerBridge.js.map +1 -0
- package/dist/bridges/index.d.ts +14 -0
- package/dist/bridges/index.d.ts.map +1 -0
- package/dist/bridges/index.js +7 -0
- package/dist/bridges/index.js.map +1 -0
- package/dist/cache/FetchSemanticCacheBackend.d.ts +40 -0
- package/dist/cache/FetchSemanticCacheBackend.d.ts.map +1 -0
- package/dist/cache/FetchSemanticCacheBackend.js +61 -0
- package/dist/cache/FetchSemanticCacheBackend.js.map +1 -0
- package/dist/cache/SemanticCache.d.ts +105 -0
- package/dist/cache/SemanticCache.d.ts.map +1 -0
- package/dist/cache/SemanticCache.js +130 -0
- package/dist/cache/SemanticCache.js.map +1 -0
- package/dist/cache/index.d.ts +5 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +3 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/distillation/DistillationEngine.d.ts +107 -0
- package/dist/distillation/DistillationEngine.d.ts.map +1 -0
- package/dist/distillation/DistillationEngine.js +152 -0
- package/dist/distillation/DistillationEngine.js.map +1 -0
- package/dist/distillation/index.d.ts +3 -0
- package/dist/distillation/index.d.ts.map +1 -0
- package/dist/distillation/index.js +2 -0
- package/dist/distillation/index.js.map +1 -0
- package/dist/errors/SSMError.d.ts +14 -0
- package/dist/errors/SSMError.d.ts.map +1 -0
- package/dist/errors/SSMError.js +18 -0
- package/dist/errors/SSMError.js.map +1 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/MemoryStore.d.ts +152 -0
- package/dist/memory/MemoryStore.d.ts.map +1 -0
- package/dist/memory/MemoryStore.js +290 -0
- package/dist/memory/MemoryStore.js.map +1 -0
- package/dist/memory/index.d.ts +3 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/router/InferenceRouter.d.ts +92 -0
- package/dist/router/InferenceRouter.d.ts.map +1 -0
- package/dist/router/InferenceRouter.js +113 -0
- package/dist/router/InferenceRouter.js.map +1 -0
- package/dist/router/index.d.ts +3 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +2 -0
- package/dist/router/index.js.map +1 -0
- package/dist/runtime/SSMRuntime.d.ts +167 -0
- package/dist/runtime/SSMRuntime.d.ts.map +1 -0
- package/dist/runtime/SSMRuntime.js +199 -0
- package/dist/runtime/SSMRuntime.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/session/errors.d.ts +10 -0
- package/dist/session/errors.d.ts.map +1 -0
- package/dist/session/errors.js +14 -0
- package/dist/session/errors.js.map +1 -0
- package/dist/session/index.d.ts +11 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +7 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/persistence.d.ts +14 -0
- package/dist/session/persistence.d.ts.map +1 -0
- package/dist/session/persistence.js +100 -0
- package/dist/session/persistence.js.map +1 -0
- package/dist/session/presets.d.ts +31 -0
- package/dist/session/presets.d.ts.map +1 -0
- package/dist/session/presets.js +91 -0
- package/dist/session/presets.js.map +1 -0
- package/dist/session/session.d.ts +186 -0
- package/dist/session/session.d.ts.map +1 -0
- package/dist/session/session.js +358 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/streaming.d.ts +13 -0
- package/dist/session/streaming.d.ts.map +1 -0
- package/dist/session/streaming.js +74 -0
- package/dist/session/streaming.js.map +1 -0
- package/dist/session/tokenizer.d.ts +18 -0
- package/dist/session/tokenizer.d.ts.map +1 -0
- package/dist/session/tokenizer.js +11 -0
- package/dist/session/tokenizer.js.map +1 -0
- package/dist/similarity/index.d.ts +19 -0
- package/dist/similarity/index.d.ts.map +1 -0
- package/dist/similarity/index.js +42 -0
- package/dist/similarity/index.js.map +1 -0
- package/package.json +120 -0
- package/src/agent/SSMAgent.ts +327 -0
- package/src/agent/index.ts +2 -0
- package/src/bridges/AnthropicBridge.ts +166 -0
- package/src/bridges/CachingBridge.ts +79 -0
- package/src/bridges/FetchBridge.ts +41 -0
- package/src/bridges/OpenAIBridge.ts +143 -0
- package/src/bridges/ResponseCache.ts +131 -0
- package/src/bridges/SemanticCachingBridge.ts +60 -0
- package/src/bridges/TransformerBridge.ts +38 -0
- package/src/bridges/index.ts +13 -0
- package/src/cache/FetchSemanticCacheBackend.ts +79 -0
- package/src/cache/SemanticCache.ts +196 -0
- package/src/cache/index.ts +9 -0
- package/src/distillation/DistillationEngine.ts +248 -0
- package/src/distillation/index.ts +2 -0
- package/src/errors/SSMError.ts +26 -0
- package/src/errors/index.ts +2 -0
- package/src/index.ts +128 -0
- package/src/memory/MemoryStore.ts +408 -0
- package/src/memory/index.ts +2 -0
- package/src/router/InferenceRouter.ts +201 -0
- package/src/router/index.ts +2 -0
- package/src/runtime/SSMRuntime.ts +309 -0
- package/src/runtime/index.ts +2 -0
- package/src/session/errors.ts +24 -0
- package/src/session/index.ts +25 -0
- package/src/session/persistence.ts +142 -0
- package/src/session/presets.ts +122 -0
- package/src/session/session.ts +657 -0
- package/src/session/streaming.ts +97 -0
- package/src/session/tokenizer.ts +18 -0
- package/src/similarity/index.ts +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sean Hogg
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
# SSM.js
|
|
2
|
+
|
|
3
|
+
> **JavaScript-native AI runtime** — SSM execution + Transformer orchestration + online distillation + persistent agent memory.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@seanhogg/ssmjs)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
SSM.js is a complete, self-contained AI runtime built directly on top of [MambaCode.js](https://www.npmjs.com/package/@seanhogg/mambacode.js). It includes the full session layer (previously `@seanhogg/mambakit`) as an internal layer, so you only need one package.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
SSM.js is a JavaScript-native AI runtime that combines local SSM (State Space Model) inference with optional transformer bridge escalation, persistent semantic memory, and online distillation — all without leaving the browser or Node.js process.
|
|
15
|
+
|
|
16
|
+
The layered stack:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
MambaCode.js → WebGPU kernels (WGSL, Mamba-1/2/3 SSM math)
|
|
20
|
+
SSM.js → Session layer + Runtime orchestration (this package)
|
|
21
|
+
├── src/session/ MambaSession, tokenizer, persistence
|
|
22
|
+
├── src/runtime/ SSMRuntime, routing
|
|
23
|
+
├── src/memory/ MemoryStore
|
|
24
|
+
├── src/agent/ SSMAgent
|
|
25
|
+
└── src/distillation/ DistillationEngine
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| Capability | SSM.js |
|
|
29
|
+
|------------------------------|--------|
|
|
30
|
+
| Simple session API | ✅ |
|
|
31
|
+
| WebGPU execution | ✅ |
|
|
32
|
+
| SSM variants (1/2/3/hybrid) | ✅ |
|
|
33
|
+
| Transformer bridge | ✅ |
|
|
34
|
+
| Intelligent routing | ✅ |
|
|
35
|
+
| Online distillation | ✅ |
|
|
36
|
+
| Persistent semantic memory | ✅ |
|
|
37
|
+
| Agent workflows | ✅ |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @seanhogg/ssmjs
|
|
45
|
+
# or
|
|
46
|
+
pnpm add @seanhogg/ssmjs
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`@seanhogg/ssmjs` includes the full session layer (previously `@seanhogg/mambakit`).
|
|
50
|
+
`@seanhogg/mambacode.js` is a peer dependency — install it alongside:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install @seanhogg/ssmjs @seanhogg/mambacode.js
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Node.js requirements
|
|
57
|
+
|
|
58
|
+
Node.js 18+ is required. Two additional shims are needed for Node.js:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install @webgpu/node fake-indexeddb
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- `@webgpu/node` — Dawn-based WebGPU for Node.js; drives all WGSL compute kernels
|
|
65
|
+
- `fake-indexeddb` — in-memory IndexedDB compatible with the IDB spec; used by `MemoryStore`
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
### Browser
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { SSM, AnthropicBridge, SSMAgent, MemoryStore } from '@seanhogg/ssmjs';
|
|
75
|
+
|
|
76
|
+
const runtime = await SSM.create({
|
|
77
|
+
session: { modelSize: 'small', mambaVersion: 'mamba2' },
|
|
78
|
+
bridge : new AnthropicBridge({ apiKey: 'sk-ant-...' }),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Generate — routes to SSM or transformer automatically
|
|
82
|
+
const answer = await runtime.generate('What is a state space model?');
|
|
83
|
+
|
|
84
|
+
// Streaming — always SSM for low-latency output
|
|
85
|
+
for await (const token of runtime.stream('function fibonacci(')) {
|
|
86
|
+
process.stdout.write(token);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Fine-tune on your content
|
|
90
|
+
await runtime.adapt(myCodebase);
|
|
91
|
+
runtime.destroy();
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Node.js
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { create as createGPU } from '@webgpu/node';
|
|
98
|
+
import { IDBFactory } from 'fake-indexeddb';
|
|
99
|
+
import { SSM, MemoryStore, SSMAgent } from '@seanhogg/ssmjs';
|
|
100
|
+
|
|
101
|
+
const gpuAdapter = await createGPU().requestAdapter({ powerPreference: 'high-performance' });
|
|
102
|
+
const idbFactory = new IDBFactory();
|
|
103
|
+
|
|
104
|
+
const runtime = await SSM.create({
|
|
105
|
+
session: {
|
|
106
|
+
gpuAdapter,
|
|
107
|
+
idbFactory,
|
|
108
|
+
modelSize: 'small',
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const memory = new MemoryStore({ idbFactory });
|
|
113
|
+
const agent = new SSMAgent({ runtime, memory });
|
|
114
|
+
await agent.init(); // loads persisted history if present
|
|
115
|
+
|
|
116
|
+
const reply = await agent.think('Explain this codebase');
|
|
117
|
+
console.log(reply);
|
|
118
|
+
|
|
119
|
+
await agent.destroy(); // persists history, releases GPU
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Custom Tokenizers
|
|
125
|
+
|
|
126
|
+
By default, `MambaSession` uses the built-in Qwen2.5-Coder BPE tokenizer. You can override this by passing any object that satisfies the `Tokenizer` interface:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import type { Tokenizer } from '@seanhogg/ssmjs';
|
|
130
|
+
|
|
131
|
+
const myTokenizer: Tokenizer = {
|
|
132
|
+
encode(text: string): number[] { /* your encode implementation */ return []; },
|
|
133
|
+
decode(tokens: number[]): string { /* your decode implementation */ return ''; },
|
|
134
|
+
get vocabSize(): number { return 32000; },
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const runtime = await SSM.create({
|
|
138
|
+
session: {
|
|
139
|
+
tokenizer: myTokenizer, // replaces BPETokenizer entirely
|
|
140
|
+
modelSize: 'small',
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Use cases:
|
|
146
|
+
- **HuggingFace Transformers.js** tokenizer — wrap its `encode`/`decode` in the interface
|
|
147
|
+
- **Unit testing** — a stub tokenizer that maps words to sequential IDs, no network needed
|
|
148
|
+
- **Domain-specific vocabularies** — medical, legal, multilingual tokenizers
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Memory System
|
|
153
|
+
|
|
154
|
+
`MemoryStore` is a persistent, TTL-aware, tagged key-value fact store backed by IndexedDB.
|
|
155
|
+
|
|
156
|
+
### Basic usage
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { MemoryStore } from '@seanhogg/ssmjs';
|
|
160
|
+
|
|
161
|
+
const memory = new MemoryStore({
|
|
162
|
+
dbName : 'my-app',
|
|
163
|
+
defaultTtlMs: 7 * 24 * 60 * 60 * 1000, // 7-day default TTL
|
|
164
|
+
idbFactory, // Node.js only
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Store facts
|
|
168
|
+
await memory.remember('author', 'Sean Hogg');
|
|
169
|
+
await memory.remember('stack', 'React + TypeScript', {
|
|
170
|
+
tags : ['tech', 'project'],
|
|
171
|
+
importance: 0.8,
|
|
172
|
+
ttlMs : 30 * 24 * 60 * 60 * 1000, // 30 days
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Retrieve
|
|
176
|
+
const entry = await memory.recall('author');
|
|
177
|
+
|
|
178
|
+
// All non-expired facts, newest first
|
|
179
|
+
const all = await memory.recallAll();
|
|
180
|
+
|
|
181
|
+
// N most recent non-expired facts
|
|
182
|
+
const recent = await memory.recallRecent(10);
|
|
183
|
+
|
|
184
|
+
// Filter by tag
|
|
185
|
+
const techFacts = await memory.recallByTag('tech');
|
|
186
|
+
|
|
187
|
+
// Semantic similarity search (Jaccard word-overlap; SSM embeddings in future)
|
|
188
|
+
const similar = await memory.recallSimilar('who built this?', 5, runtime);
|
|
189
|
+
|
|
190
|
+
// Purge expired entries from storage
|
|
191
|
+
const deletedCount = await memory.purgeExpired();
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Cross-session memory merge
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
// Export all non-expired facts from sessionA
|
|
198
|
+
const exported = await memoryA.exportAll();
|
|
199
|
+
|
|
200
|
+
// Import into sessionB
|
|
201
|
+
await memoryB.importAll(exported, 'merge');
|
|
202
|
+
// 'merge' — only overwrites if incoming entry is newer
|
|
203
|
+
// 'overwrite' — writes all entries unconditionally
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Weight persistence
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
await memory.saveWeights(runtime); // saves model weights to IndexedDB
|
|
210
|
+
const loaded = await memory.loadWeights(runtime); // false if no checkpoint found
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### MemoryEntry schema
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
interface MemoryEntry {
|
|
217
|
+
key : string;
|
|
218
|
+
content : string;
|
|
219
|
+
timestamp : number;
|
|
220
|
+
ttlMs? : number; // optional TTL; entry filtered after timestamp + ttlMs
|
|
221
|
+
type? : FactType; // 'text' | 'json' | 'number' | 'boolean'
|
|
222
|
+
tags? : string[]; // for grouping/filtering
|
|
223
|
+
importance?: number; // 0–1, default 0.5; higher facts appear first in prompts
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Inference Routing
|
|
230
|
+
|
|
231
|
+
`InferenceRouter` decides whether each request goes to the local SSM or the transformer bridge. It is built into `SSMRuntime` — you don't need to instantiate it directly.
|
|
232
|
+
|
|
233
|
+
### Routing strategies
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
const runtime = await SSM.create({
|
|
237
|
+
session: { modelSize: 'nano' },
|
|
238
|
+
bridge : claude,
|
|
239
|
+
routingStrategy : 'auto', // 'auto' | 'ssm' | 'transformer'
|
|
240
|
+
longInputThreshold: 1200, // chars before preferring transformer (default: 1200)
|
|
241
|
+
perplexityThreshold: 80, // SSM perplexity cutoff (default: 80)
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Auto-routing heuristics (cheapest first):**
|
|
246
|
+
1. **Complexity patterns** — "step by step", "analyze", "compare and contrast" → transformer
|
|
247
|
+
2. **Input length** — over threshold → transformer
|
|
248
|
+
3. **SSM perplexity** — async probe; high perplexity = novel topic → transformer
|
|
249
|
+
|
|
250
|
+
### RoutingDecision type
|
|
251
|
+
|
|
252
|
+
`route()` now returns a structured `RoutingDecision` object:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
interface RoutingDecision {
|
|
256
|
+
target : 'ssm' | 'transformer';
|
|
257
|
+
reason : 'strategy' | 'complexity' | 'length' | 'perplexity' | 'no_bridge';
|
|
258
|
+
confidence: number; // 0–1
|
|
259
|
+
details? : string; // human-readable explanation
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Routing audit log
|
|
264
|
+
|
|
265
|
+
Every routing decision is appended to an in-memory audit log (last 500 entries):
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
const log = runtime.getRoutingAuditLog();
|
|
269
|
+
// log: RoutingAuditEntry[]
|
|
270
|
+
// { timestamp, inputLength, decision: RoutingDecision, durationMs }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Distillation
|
|
276
|
+
|
|
277
|
+
Teach the local SSM using a transformer teacher — runs entirely in the browser or Node.js.
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
import { DistillationEngine } from '@seanhogg/ssmjs';
|
|
281
|
+
|
|
282
|
+
const distiller = new DistillationEngine(runtime, claude);
|
|
283
|
+
|
|
284
|
+
// Single pass: claude generates → SSM adapts on output
|
|
285
|
+
const result = await distiller.distill('Explain WebGPU compute shaders', {
|
|
286
|
+
adapt : { wsla: true, epochs: 3 },
|
|
287
|
+
qualityGate: {
|
|
288
|
+
minLength : 50, // skip if teacher output < 50 chars
|
|
289
|
+
maxPerplexity: 15, // skip if SSM perplexity already < 15 (already learned)
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
console.log('skipped:', result.skipped, result.skipReason);
|
|
294
|
+
console.log('loss:', result.adaptResult.losses.at(-1));
|
|
295
|
+
|
|
296
|
+
// Batch distillation
|
|
297
|
+
const batch = await distiller.distillBatch([
|
|
298
|
+
'What is a Mamba block?',
|
|
299
|
+
'Explain WSLA adaptation.',
|
|
300
|
+
], { adapt: { wsla: true, epochs: 5 } });
|
|
301
|
+
|
|
302
|
+
console.log(`${batch.totalEpochs} epochs in ${batch.totalMs}ms`);
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Quality gates
|
|
306
|
+
|
|
307
|
+
| Gate option | Description |
|
|
308
|
+
|------------------|-------------|
|
|
309
|
+
| `minLength` | Skip if teacher output is shorter than N characters (low-quality response) |
|
|
310
|
+
| `maxPerplexity` | Skip if SSM perplexity on teacher output is already below threshold (already learned) |
|
|
311
|
+
|
|
312
|
+
### Distillation log
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
const log = distiller.getLog();
|
|
316
|
+
// log: DistillationLog[]
|
|
317
|
+
// { timestamp, input, teacherOutputLength, skipped, skipReason?, finalLoss?, epochs }
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
The log is bounded to the last 200 entries.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## SSMAgent
|
|
325
|
+
|
|
326
|
+
High-level orchestration: conversation history, routing, memory injection, and lifecycle.
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
import { SSMAgent, MemoryStore } from '@seanhogg/ssmjs';
|
|
330
|
+
|
|
331
|
+
const memory = new MemoryStore();
|
|
332
|
+
const agent = new SSMAgent({
|
|
333
|
+
runtime : runtime,
|
|
334
|
+
memory,
|
|
335
|
+
systemPrompt : 'You are a senior TypeScript engineer.',
|
|
336
|
+
maxHistoryTurns: 20,
|
|
337
|
+
persistHistory : true, // saves/loads history via memory on destroy/init
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Load persisted history from a prior session
|
|
341
|
+
await agent.init();
|
|
342
|
+
|
|
343
|
+
// Store project context
|
|
344
|
+
await agent.remember('stack', 'React 18, TypeScript 5, Vite');
|
|
345
|
+
|
|
346
|
+
// Multi-turn conversation — facts with highest importance appear first in context
|
|
347
|
+
const reply1 = await agent.think('What stack should I use?');
|
|
348
|
+
const reply2 = await agent.think('How do I handle concurrent edits?');
|
|
349
|
+
|
|
350
|
+
// Streaming
|
|
351
|
+
for await (const token of agent.thinkStream('Show me a WebSocket hook')) {
|
|
352
|
+
process.stdout.write(token);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Teach the agent from content
|
|
356
|
+
await agent.learn(myCodebase, { wsla: true, epochs: 3 });
|
|
357
|
+
|
|
358
|
+
console.log(agent.turnCount); // 2
|
|
359
|
+
|
|
360
|
+
// Persists history to memory, then destroys runtime
|
|
361
|
+
await agent.destroy();
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### History persistence
|
|
365
|
+
|
|
366
|
+
When `persistHistory: true` (default):
|
|
367
|
+
- On `agent.init()`: loads `__history__` from the `MemoryStore` and restores conversation turns.
|
|
368
|
+
- On `agent.destroy()`: serialises `_history` to JSON and writes it under `__history__`.
|
|
369
|
+
|
|
370
|
+
This enables multi-session continuity without external state management.
|
|
371
|
+
|
|
372
|
+
### Fact injection order
|
|
373
|
+
|
|
374
|
+
Facts retrieved from `MemoryStore` are sorted by `importance` descending before being injected into the prompt. Higher-importance facts appear first, giving the model the most relevant context regardless of insertion order.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Migration from MambaKit
|
|
379
|
+
|
|
380
|
+
`@seanhogg/mambakit` has been consolidated into this package. `MambaSession` and all related types are now exported directly from `@seanhogg/ssmjs`.
|
|
381
|
+
|
|
382
|
+
**Before:**
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
npm install @seanhogg/mambakit @seanhogg/ssmjs
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
```ts
|
|
389
|
+
import { MambaSession } from '@seanhogg/mambakit';
|
|
390
|
+
import type { MambaSessionOptions, Tokenizer } from '@seanhogg/mambakit';
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**After:**
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
npm install @seanhogg/ssmjs
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
import { MambaSession, SessionError } from '@seanhogg/ssmjs';
|
|
401
|
+
import type { MambaSessionOptions, Tokenizer } from '@seanhogg/ssmjs';
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
All types are re-exported unchanged — `MambaSessionOptions`, `CompleteOptions`, `AdaptOptions`,
|
|
405
|
+
`AdaptResult`, `SaveOptions`, `LoadOptions`, `StorageTarget`, `CreateCallbacks`,
|
|
406
|
+
`LayerSchedulePreset`, `MODEL_PRESETS`, `GpuMode`, and `Tokenizer`.
|
|
407
|
+
No logic changes are required, only the import path.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## BuilderForce Agents Integration
|
|
412
|
+
|
|
413
|
+
SSM.js serves as the **hippocampus** layer of [BuilderForce Agents](https://builderforce.ai)'s gateway — a persistent semantic memory and local inference engine running alongside the frontier LLM (Claude/GPT) cortex.
|
|
414
|
+
|
|
415
|
+
The `SsmMemoryService` class in BuilderForce Agents's `src/infra/ssm-memory-service.ts` wraps an `SSMRuntime` + `SSMAgent` + `MemoryStore` triplet:
|
|
416
|
+
|
|
417
|
+
```
|
|
418
|
+
BuilderForce Agents gateway
|
|
419
|
+
├── server-startup.ts ← initSsmMemoryService() on boot
|
|
420
|
+
├── infra/knowledge-loop.ts ← remember() + learn() on every agent run
|
|
421
|
+
├── infra/ssm-memory-service.ts ← SsmMemoryService wrapper
|
|
422
|
+
└── builderforce/orchestrator.ts ← recallSimilar() injected into task prompts
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Data flow:**
|
|
426
|
+
1. Agent run completes → `KnowledgeLoopService` derives activity summary
|
|
427
|
+
2. Summary is stored in `.builderforce/memory/YYYY-MM-DD.md` (markdown log)
|
|
428
|
+
3. Summary is also passed to `ssmSvc.remember()` (tagged + importance-weighted)
|
|
429
|
+
4. Summary is passed to `ssmSvc.learn()` → WSLA fine-tuning adapts the SSM
|
|
430
|
+
5. On next workflow task, `recallSimilar(taskDescription, 5)` injects relevant memories into the prompt as a `[Memory Context]` block
|
|
431
|
+
|
|
432
|
+
GPU init is optional: if `@webgpu/node` is unavailable, the service starts in memory-only mode (`gpuAvailable: false`) and SSM inference is skipped. The gateway never crashes due to a missing GPU.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Phase Roadmap
|
|
437
|
+
|
|
438
|
+
### Phase 1 — Foundations
|
|
439
|
+
- Session layer: `Tokenizer` interface + pluggable injection via `MambaSessionOptions.tokenizer`
|
|
440
|
+
- `MemoryStore`: TTL (`ttlMs`), `defaultTtlMs`, `purgeExpired()`, `recallRecent(n)`
|
|
441
|
+
- `MemoryStore`: `FactType`, `tags`, `importance` fields on `MemoryEntry`
|
|
442
|
+
- `MemoryStore`: updated `remember()` accepting `RememberOptions`
|
|
443
|
+
- `InferenceRouter`: `route()` now returns `RoutingDecision` object with `target`, `reason`, `confidence`, `details`
|
|
444
|
+
- `SSMAgent`: `persistHistory` option; `init()` loads `__history__`; `destroy()` saves it
|
|
445
|
+
- `SSMAgent`: fact injection sorted by `importance` descending
|
|
446
|
+
|
|
447
|
+
### Phase 2 — Semantic Memory
|
|
448
|
+
- `MemoryStore.recallSimilar(query, topK, runtime)` — Jaccard similarity; SSM embedding-based search in future
|
|
449
|
+
- `MemoryStore.recallByTag(tag)` — tag-based filtering
|
|
450
|
+
- `MemoryStore.exportAll()` / `importAll(entries, strategy)` — cross-session merge
|
|
451
|
+
|
|
452
|
+
### Phase 3 — BuilderForce Agents Integration
|
|
453
|
+
- `SsmMemoryService` in `src/infra/ssm-memory-service.ts` — singleton gateway service
|
|
454
|
+
- `server-startup.ts`: `initSsmMemoryService()` on boot; non-fatal GPU fallback
|
|
455
|
+
- `KnowledgeLoopService`: `remember()` + `learn()` on every agent run completion
|
|
456
|
+
- `AgentOrchestrator`: `recallSimilar()` injected as `[Memory Context]` before task dispatch
|
|
457
|
+
|
|
458
|
+
### Phase 4 — Feedback Loop
|
|
459
|
+
- `DistillationEngine`: `qualityGate` option (`minLength`, `maxPerplexity`)
|
|
460
|
+
- `DistillResult`: `skipped` + `skipReason` fields
|
|
461
|
+
- `DistillationEngine.getLog()` — bounded in-memory `DistillationLog[]`
|
|
462
|
+
- `InferenceRouter`: `RoutingAuditEntry` + `getAuditLog()` — bounded in-memory log
|
|
463
|
+
- `SSMRuntime.getRoutingAuditLog()` — delegates to router
|
|
464
|
+
- `SSMRuntime.getDistillationLog()` — stub; returns empty array (inline engine future work)
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## API Reference
|
|
469
|
+
|
|
470
|
+
### `SSM.create(opts)` / `SSMRuntime.create(opts)`
|
|
471
|
+
|
|
472
|
+
| Option | Type | Default | Description |
|
|
473
|
+
|---|---|---|---|
|
|
474
|
+
| `session` | `MambaSessionOptions` | required | Forwarded to `MambaSession.create()` |
|
|
475
|
+
| `bridge` | `TransformerBridge` | — | Transformer backend for routing/distillation |
|
|
476
|
+
| `routingStrategy` | `'auto'\|'ssm'\|'transformer'` | `'auto'` | Routing strategy |
|
|
477
|
+
| `longInputThreshold` | `number` | `1200` | Chars before auto-routing prefers transformer |
|
|
478
|
+
| `perplexityThreshold` | `number` | `80` | SSM perplexity cutoff |
|
|
479
|
+
| `callbacks` | `CreateCallbacks` | — | Progress callbacks |
|
|
480
|
+
|
|
481
|
+
### `runtime.generate(input, opts?)`
|
|
482
|
+
Generates a full response. Routes to SSM or transformer per strategy. Returns `Promise<string>`.
|
|
483
|
+
|
|
484
|
+
### `runtime.stream(input, opts?)`
|
|
485
|
+
`AsyncIterable<string>` — always uses SSM path for consistent latency.
|
|
486
|
+
|
|
487
|
+
### `runtime.streamHybrid(input, opts?)`
|
|
488
|
+
`AsyncIterable<string>` — routes like `generate()`, streams via bridge if available.
|
|
489
|
+
|
|
490
|
+
### `runtime.adapt(data, opts?)`
|
|
491
|
+
Pass-through to `session.adapt()`. Returns `AdaptResult`.
|
|
492
|
+
|
|
493
|
+
### `runtime.evaluate(text)`
|
|
494
|
+
Returns SSM perplexity. Used internally by auto-routing.
|
|
495
|
+
|
|
496
|
+
### `runtime.getRoutingAuditLog()`
|
|
497
|
+
Returns `RoutingAuditEntry[]` — last 500 routing decisions with timing.
|
|
498
|
+
|
|
499
|
+
### `runtime.getDistillationLog()`
|
|
500
|
+
Returns `DistillationLog[]` — last 200 distillation runs (stub; use `distiller.getLog()` directly).
|
|
501
|
+
|
|
502
|
+
### `runtime.save(opts?)` / `runtime.load(opts?)`
|
|
503
|
+
Weight persistence pass-throughs to `MambaSession`.
|
|
504
|
+
|
|
505
|
+
### `runtime.destroy()`
|
|
506
|
+
Releases GPU device and all buffers.
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## Error Handling
|
|
511
|
+
|
|
512
|
+
```ts
|
|
513
|
+
import { SSMError, SessionError } from '@seanhogg/ssmjs';
|
|
514
|
+
|
|
515
|
+
try {
|
|
516
|
+
const runtime = await SSM.create({ session: { modelSize: 'nano' } });
|
|
517
|
+
await runtime.generate('hello');
|
|
518
|
+
} catch (err) {
|
|
519
|
+
if (err instanceof SSMError) {
|
|
520
|
+
// Runtime-level error (bridge, distillation, memory)
|
|
521
|
+
console.error(err.code); // 'BRIDGE_REQUEST_FAILED' | 'RUNTIME_DESTROYED' | ...
|
|
522
|
+
}
|
|
523
|
+
if (err instanceof SessionError) {
|
|
524
|
+
// Session-level error (GPU init, tokenizer, checkpoint)
|
|
525
|
+
console.error(err.code); // 'GPU_UNAVAILABLE' | 'TOKENIZER_LOAD_FAILED' | ...
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## File Structure
|
|
533
|
+
|
|
534
|
+
```
|
|
535
|
+
src/
|
|
536
|
+
├── index.ts ← package entry + SSM namespace
|
|
537
|
+
├── session/ ← session layer (absorbed from @seanhogg/mambakit)
|
|
538
|
+
│ ├── session.ts ← MambaSession.create() — GPU, tokenizer, model, persistence
|
|
539
|
+
│ ├── tokenizer.ts ← Tokenizer interface (pluggable)
|
|
540
|
+
│ ├── presets.ts ← MODEL_PRESETS + layer schedule resolution
|
|
541
|
+
│ ├── persistence.ts ← IndexedDB / download / File System API helpers
|
|
542
|
+
│ ├── streaming.ts ← AsyncIterable token streaming
|
|
543
|
+
│ ├── errors.ts ← SessionError typed error class
|
|
544
|
+
│ └── index.ts ← barrel export
|
|
545
|
+
├── runtime/
|
|
546
|
+
│ └── SSMRuntime.ts ← core runtime, owns MambaSession
|
|
547
|
+
├── bridges/
|
|
548
|
+
│ ├── TransformerBridge.ts ← interface
|
|
549
|
+
│ ├── OpenAIBridge.ts ← OpenAI chat completions
|
|
550
|
+
│ ├── AnthropicBridge.ts ← Anthropic Messages API
|
|
551
|
+
│ └── FetchBridge.ts ← generic OpenAI-compatible endpoint
|
|
552
|
+
├── router/
|
|
553
|
+
│ └── InferenceRouter.ts ← SSM ↔ transformer routing + audit log
|
|
554
|
+
├── memory/
|
|
555
|
+
│ └── MemoryStore.ts ← IndexedDB fact store: TTL, tags, importance, export/import
|
|
556
|
+
├── distillation/
|
|
557
|
+
│ └── DistillationEngine.ts ← online teacher→student distillation + quality gates
|
|
558
|
+
├── agent/
|
|
559
|
+
│ └── SSMAgent.ts ← orchestration: history persistence + fact injection
|
|
560
|
+
└── errors/
|
|
561
|
+
└── SSMError.ts ← typed error class
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## Professional Platform
|
|
567
|
+
|
|
568
|
+
**SSM.js patterns are the architectural foundation of [Builderforce.ai](https://builderforce.ai)'s Agent Runtime.**
|
|
569
|
+
|
|
570
|
+
| SSM.js concept | Builderforce.ai equivalent |
|
|
571
|
+
|---|---|
|
|
572
|
+
| `SSMRuntime` | `AgentRuntime` (browser-native, ties to IDE project) |
|
|
573
|
+
| `DistillationEngine` | LLM-assisted dataset generation → in-browser LoRA training |
|
|
574
|
+
| `MemoryStore` | IndexedDB `MambaAgentState` + `AgentPackage` embedding |
|
|
575
|
+
| `SSMAgent` | Published workforce agent (Workforce Registry) |
|
|
576
|
+
| `TransformerBridge` | Cloudflare Workers AI / OpenRouter fallback |
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## License
|
|
581
|
+
|
|
582
|
+
MIT
|