@seanhogg/builderforce-memory-mcp 2026.9.33 → 2026.10.1
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/dist/backends/memory-store.d.ts +25 -0
- package/dist/backends/memory-store.d.ts.map +1 -1
- package/dist/backends/memory-store.js +22 -2
- package/dist/backends/memory-store.js.map +1 -1
- package/dist/experience/train.d.ts +16 -3
- package/dist/experience/train.d.ts.map +1 -1
- package/dist/experience/train.js +6 -3
- package/dist/experience/train.js.map +1 -1
- package/package.json +5 -5
- package/server.json +2 -2
- package/src/backends/memory-store.ts +44 -2
- package/src/experience/train.ts +116 -96
|
@@ -84,7 +84,32 @@ export interface LocalBackendOptions {
|
|
|
84
84
|
* see {@link DiskPersistedBackend} for the loop guard.
|
|
85
85
|
*/
|
|
86
86
|
persistFile?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Hard cap on stored facts. Each write evicts the lowest-value entries
|
|
89
|
+
* (expired first, then lowest importance, then oldest).
|
|
90
|
+
*
|
|
91
|
+
* This was left unset by the local backend, which passed only `dbName` to
|
|
92
|
+
* `MemoryStore` — and `maxEntries` is undefined-by-default there, so the store
|
|
93
|
+
* grew without bound: every `memory_remember` added a fact that was never
|
|
94
|
+
* evicted, and the mirror file grew forever. Unbounded is fine for a
|
|
95
|
+
* short-lived test, not for the long-lived MCP server this is the default
|
|
96
|
+
* backend for. Defaults to {@link DEFAULT_MAX_ENTRIES} rather than requiring
|
|
97
|
+
* every caller to remember to pass one.
|
|
98
|
+
*/
|
|
99
|
+
maxEntries?: number;
|
|
100
|
+
/**
|
|
101
|
+
* Set false to keep recall lexical even when a model is configured. The local
|
|
102
|
+
* store otherwise wires in {@link createRecallEmbedder}, which only resolves
|
|
103
|
+
* when `BUILDERFORCE_MEMORY_MODEL` is set, so this is mostly for tests.
|
|
104
|
+
*/
|
|
105
|
+
semanticRecall?: false;
|
|
87
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Default cap on locally-stored facts. Large enough that a normal workspace never
|
|
109
|
+
* notices eviction, small enough that the IndexedDB shim, the embedding cache and
|
|
110
|
+
* the mirrored JSON file stay bounded on a host with no eviction policy of its own.
|
|
111
|
+
*/
|
|
112
|
+
export declare const DEFAULT_MAX_ENTRIES = 10000;
|
|
88
113
|
/**
|
|
89
114
|
* Builds a MemoryStoreBackend over a fresh MemoryStore, wiring fake-indexeddb in
|
|
90
115
|
* Node exactly as SsmMemoryService does. @seanhogg/builderforce-memory and fake-indexeddb
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/backends/memory-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAM3F,UAAU,eAAe;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,eAAe;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IAC1D,SAAS,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACxC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACrD,kFAAkF;IAClF,YAAY,CACR,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,eAAe,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;IACxG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAaD,qBAAa,kBAAmB,YAAW,aAAa;IAEhD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAFR,KAAK,EAAE,eAAe;IACvC,wEAAwE;IACvD,OAAO,CAAC,EAAE,OAAO,YAAA;IAGtC,oFAAoF;IAC9E,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAIzD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAKhE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAKhD,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAK7D,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD,qFAAqF;IAC/E,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3C;AAED,yDAAyD;AACzD,MAAM,WAAW,mBAAmB;IAChC,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;OAaG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/backends/memory-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -66,6 +66,12 @@ export class MemoryStoreBackend {
|
|
|
66
66
|
await this.store.forget(key);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Default cap on locally-stored facts. Large enough that a normal workspace never
|
|
71
|
+
* notices eviction, small enough that the IndexedDB shim, the embedding cache and
|
|
72
|
+
* the mirrored JSON file stay bounded on a host with no eviction policy of its own.
|
|
73
|
+
*/
|
|
74
|
+
export const DEFAULT_MAX_ENTRIES = 10_000;
|
|
69
75
|
/** Parse a snapshot's text into its durable entries, or null when unusable. */
|
|
70
76
|
function parseSnapshot(text) {
|
|
71
77
|
let parsed;
|
|
@@ -202,8 +208,22 @@ export async function createLocalMemoryStoreBackend(opts = {}) {
|
|
|
202
208
|
catch {
|
|
203
209
|
// Browser or a host that provides global indexedDB — MemoryStore handles it.
|
|
204
210
|
}
|
|
205
|
-
const
|
|
206
|
-
|
|
211
|
+
const maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
212
|
+
// A local store with no embedder degrades to lexical-only recall, which is why
|
|
213
|
+
// recall stopped finding paraphrases on a headless host. Wire the CPU Evermind
|
|
214
|
+
// embedder in when the caller supplied no runtime and a model is configured.
|
|
215
|
+
// `createRecallEmbedder` returns null when no model is set, or when the model
|
|
216
|
+
// fails to stand up — both are correct degrades, not failures to boot.
|
|
217
|
+
let runtime = opts.runtime;
|
|
218
|
+
if (runtime === undefined && opts.semanticRecall !== false) {
|
|
219
|
+
const embed = await import("../embedding/index.js");
|
|
220
|
+
runtime =
|
|
221
|
+
(await embed.createRecallEmbedder({
|
|
222
|
+
memoryFile: opts.persistFile ?? opts.dbName ?? "",
|
|
223
|
+
})) ?? undefined;
|
|
224
|
+
}
|
|
225
|
+
const store = new MemoryStore({ idbFactory, dbName: opts.dbName, maxEntries });
|
|
226
|
+
const backend = new MemoryStoreBackend(store, runtime);
|
|
207
227
|
if (!opts.persistFile)
|
|
208
228
|
return backend;
|
|
209
229
|
// Disk-mirror requested. node:fs/path are loaded indirectly so a browser
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../src/backends/memory-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAqB,MAAM,oCAAoC,CAAC;AA0BvF,SAAS,KAAK,CAAC,CAAkB,EAAE,KAAc;IAC7C,OAAO;QACH,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,SAAS,EAAE,CAAC,CAAC,SAAS;KACzB,CAAC;AACN,CAAC;AAED,MAAM,OAAO,kBAAkB;IAEN;IAEA;IAHrB,YACqB,KAAsB;IACvC,wEAAwE;IACvD,OAAiB;QAFjB,UAAK,GAAL,KAAK,CAAiB;QAEtB,YAAO,GAAP,OAAO,CAAU;IACnC,CAAC;IAEJ,oFAAoF;IACpF,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,IAAY;QACpC,OAAO,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,IAAY;QAC1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC5F,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACjB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,GAAW,EAAE,KAAa;QACxC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAClD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAoB;QAC/B,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE;YAChD,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,UAAU,EAAE,KAAK,CAAC,UAAU;SAC/B,CAAC,CAAC;IACP,CAAC;IAED,qFAAqF;IACrF,KAAK,CAAC,YAAY,CAAC,MAAuB;QACtC,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACpB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;CACJ;
|
|
1
|
+
{"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../src/backends/memory-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* re-teaches what the discarded version had learned, and a fresh base (no suffix,
|
|
14
14
|
* N = 0) — a newly downloaded Evermind — gets every procedure again.
|
|
15
15
|
*/
|
|
16
|
-
import type { adaptPackage, experienceDocuments, packDocuments, ExperienceStore } from "@seanhogg/builderforce-memory-engine";
|
|
16
|
+
import type { adaptPackage, experienceDocuments, packDocuments, ExperienceDocument, ExperienceStore } from "@seanhogg/builderforce-memory-engine";
|
|
17
17
|
import type { LoadedEvermind } from "../model/evermind-package.js";
|
|
18
18
|
/** The engine functions training needs, passed in so the peer stays optional. */
|
|
19
19
|
export interface TrainEngine {
|
|
@@ -30,6 +30,10 @@ export type TrainOutcome = {
|
|
|
30
30
|
status: "no_window";
|
|
31
31
|
pending: number;
|
|
32
32
|
version: string;
|
|
33
|
+
} | {
|
|
34
|
+
status: "curated_out";
|
|
35
|
+
pending: number;
|
|
36
|
+
version: string;
|
|
33
37
|
} | {
|
|
34
38
|
status: "trained";
|
|
35
39
|
learned: number;
|
|
@@ -43,6 +47,15 @@ export declare function nextExperienceVersion(version: string): string;
|
|
|
43
47
|
/** Which adaptation produced this model: N for `+expN`, 0 for a base that has none. */
|
|
44
48
|
export declare function experienceIndex(version: string): number;
|
|
45
49
|
/** Procedures the model has not learned yet. */
|
|
46
|
-
export declare function pendingDocuments(store: ExperienceStore, engine: TrainEngine, modelVersion: string): Promise<
|
|
47
|
-
export
|
|
50
|
+
export declare function pendingDocuments(store: ExperienceStore, engine: TrainEngine, modelVersion: string): Promise<ExperienceDocument[]>;
|
|
51
|
+
export interface TrainExperienceOptions {
|
|
52
|
+
/**
|
|
53
|
+
* Opt-in curation between "what is new" and the adaptation passes — typically the
|
|
54
|
+
* engine's `curateExperience` (quality filter + near-duplicate removal, docs/ml-task-catalog.md
|
|
55
|
+
* §4.2). Absent ⇒ every pending procedure is learned, exactly as before. A procedure
|
|
56
|
+
* curation drops is NOT recorded as learned, so a later pass reconsiders it.
|
|
57
|
+
*/
|
|
58
|
+
curate?: (docs: ExperienceDocument[]) => Promise<ExperienceDocument[]> | ExperienceDocument[];
|
|
59
|
+
}
|
|
60
|
+
export declare function trainExperience(store: ExperienceStore, engine: TrainEngine, model: LoadedEvermind, modelFile: string, opts?: TrainExperienceOptions): Promise<TrainOutcome>;
|
|
48
61
|
//# sourceMappingURL=train.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"train.d.ts","sourceRoot":"","sources":["../../src/experience/train.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"train.d.ts","sourceRoot":"","sources":["../../src/experience/train.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACR,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,eAAe,EAClB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,iFAAiF;AACjF,MAAM,WAAW,WAAW;IACxB,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,wBAAwB,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,MAAM,YAAY,GAClB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAInH,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,gDAAgD;AAChD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iCAQvG;AAED,MAAM,WAAW,sBAAsB;IACnC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,OAAO,CAAC,kBAAkB,EAAE,CAAC,GAAG,kBAAkB,EAAE,CAAC;CACjG;AAED,wBAAsB,eAAe,CACjC,KAAK,EAAE,eAAe,EACtB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,cAAc,EACrB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,sBAA2B,GAClC,OAAO,CAAC,YAAY,CAAC,CAmCvB"}
|
package/dist/experience/train.js
CHANGED
|
@@ -34,11 +34,14 @@ export async function pendingDocuments(store, engine, modelVersion) {
|
|
|
34
34
|
};
|
|
35
35
|
return engine.experienceDocuments(snap.episodes, snap.skills).filter((d) => !known(d.id));
|
|
36
36
|
}
|
|
37
|
-
export async function trainExperience(store, engine, model, modelFile) {
|
|
37
|
+
export async function trainExperience(store, engine, model, modelFile, opts = {}) {
|
|
38
38
|
const version = model.pkg.manifest.version ?? "0";
|
|
39
|
-
const
|
|
40
|
-
if (
|
|
39
|
+
const pending = await pendingDocuments(store, engine, version);
|
|
40
|
+
if (pending.length === 0)
|
|
41
41
|
return { status: "nothing_new", pending: 0, version };
|
|
42
|
+
const docs = opts.curate ? await opts.curate(pending) : pending;
|
|
43
|
+
if (docs.length === 0)
|
|
44
|
+
return { status: "curated_out", pending: pending.length, version };
|
|
42
45
|
const next = nextExperienceVersion(version);
|
|
43
46
|
// The engine's package type; the structural view is what was loaded from disk.
|
|
44
47
|
let pkg = model.pkg;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"train.js","sourceRoot":"","sources":["../../src/experience/train.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"train.js","sourceRoot":"","sources":["../../src/experience/train.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seanhogg/builderforce-memory-mcp",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.10.1",
|
|
4
4
|
"mcpName": "io.github.SeanHogg/builderforce-memory",
|
|
5
5
|
"description": "BuilderForce Agent Memory — MCP transport. Exposes @seanhogg/builderforce-memory to any MCP client (Claude Agent SDK in-process, stdio, or HTTP) over a pluggable MemoryBackend, with token-saving fetch-on-demand recall.",
|
|
6
6
|
"type": "module",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@anthropic-ai/claude-agent-sdk": ">=0.1.0",
|
|
59
|
-
"@seanhogg/builderforce-memory": "^2026.
|
|
60
|
-
"@seanhogg/builderforce-memory-engine": "^2026.
|
|
59
|
+
"@seanhogg/builderforce-memory": "^2026.10.1",
|
|
60
|
+
"@seanhogg/builderforce-memory-engine": "^2026.10.1",
|
|
61
61
|
"fake-indexeddb": "^6.0.0"
|
|
62
62
|
},
|
|
63
63
|
"peerDependenciesMeta": {
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"fake-indexeddb": "^6.0.0",
|
|
84
84
|
"typescript": "^6.0.3",
|
|
85
85
|
"@typescript/native-preview": "7.0.0-dev.20260627.2",
|
|
86
|
-
"@seanhogg/builderforce-memory": "2026.
|
|
87
|
-
"@seanhogg/builderforce-memory
|
|
86
|
+
"@seanhogg/builderforce-memory-engine": "2026.10.1",
|
|
87
|
+
"@seanhogg/builderforce-memory": "2026.10.1"
|
|
88
88
|
},
|
|
89
89
|
"engines": {
|
|
90
90
|
"node": ">=18.0.0"
|
package/server.json
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
"source": "github",
|
|
9
9
|
"subfolder": "packages/memory-mcp"
|
|
10
10
|
},
|
|
11
|
-
"version": "2026.
|
|
11
|
+
"version": "2026.10.1",
|
|
12
12
|
"websiteUrl": "https://builderforce.ai",
|
|
13
13
|
"packages": [
|
|
14
14
|
{
|
|
15
15
|
"registryType": "npm",
|
|
16
16
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
17
17
|
"identifier": "@seanhogg/builderforce-memory-mcp",
|
|
18
|
-
"version": "2026.
|
|
18
|
+
"version": "2026.10.1",
|
|
19
19
|
"transport": {
|
|
20
20
|
"type": "stdio"
|
|
21
21
|
},
|
|
@@ -125,8 +125,34 @@ export interface LocalBackendOptions {
|
|
|
125
125
|
* see {@link DiskPersistedBackend} for the loop guard.
|
|
126
126
|
*/
|
|
127
127
|
persistFile?: string;
|
|
128
|
+
/**
|
|
129
|
+
* Hard cap on stored facts. Each write evicts the lowest-value entries
|
|
130
|
+
* (expired first, then lowest importance, then oldest).
|
|
131
|
+
*
|
|
132
|
+
* This was left unset by the local backend, which passed only `dbName` to
|
|
133
|
+
* `MemoryStore` — and `maxEntries` is undefined-by-default there, so the store
|
|
134
|
+
* grew without bound: every `memory_remember` added a fact that was never
|
|
135
|
+
* evicted, and the mirror file grew forever. Unbounded is fine for a
|
|
136
|
+
* short-lived test, not for the long-lived MCP server this is the default
|
|
137
|
+
* backend for. Defaults to {@link DEFAULT_MAX_ENTRIES} rather than requiring
|
|
138
|
+
* every caller to remember to pass one.
|
|
139
|
+
*/
|
|
140
|
+
maxEntries?: number;
|
|
141
|
+
/**
|
|
142
|
+
* Set false to keep recall lexical even when a model is configured. The local
|
|
143
|
+
* store otherwise wires in {@link createRecallEmbedder}, which only resolves
|
|
144
|
+
* when `BUILDERFORCE_MEMORY_MODEL` is set, so this is mostly for tests.
|
|
145
|
+
*/
|
|
146
|
+
semanticRecall?: false;
|
|
128
147
|
}
|
|
129
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Default cap on locally-stored facts. Large enough that a normal workspace never
|
|
151
|
+
* notices eviction, small enough that the IndexedDB shim, the embedding cache and
|
|
152
|
+
* the mirrored JSON file stay bounded on a host with no eviction policy of its own.
|
|
153
|
+
*/
|
|
154
|
+
export const DEFAULT_MAX_ENTRIES = 10_000;
|
|
155
|
+
|
|
130
156
|
/** The on-disk snapshot shape — a flat array of durable entries. */
|
|
131
157
|
interface SnapshotEntry {
|
|
132
158
|
key: string;
|
|
@@ -278,8 +304,24 @@ export async function createLocalMemoryStoreBackend(opts: LocalBackendOptions =
|
|
|
278
304
|
// Browser or a host that provides global indexedDB — MemoryStore handles it.
|
|
279
305
|
}
|
|
280
306
|
|
|
281
|
-
const
|
|
282
|
-
|
|
307
|
+
const maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
308
|
+
|
|
309
|
+
// A local store with no embedder degrades to lexical-only recall, which is why
|
|
310
|
+
// recall stopped finding paraphrases on a headless host. Wire the CPU Evermind
|
|
311
|
+
// embedder in when the caller supplied no runtime and a model is configured.
|
|
312
|
+
// `createRecallEmbedder` returns null when no model is set, or when the model
|
|
313
|
+
// fails to stand up — both are correct degrades, not failures to boot.
|
|
314
|
+
let runtime = opts.runtime;
|
|
315
|
+
if (runtime === undefined && opts.semanticRecall !== false) {
|
|
316
|
+
const embed = await import("../embedding/index.js");
|
|
317
|
+
runtime =
|
|
318
|
+
(await embed.createRecallEmbedder({
|
|
319
|
+
memoryFile: opts.persistFile ?? opts.dbName ?? "",
|
|
320
|
+
})) ?? undefined;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const store = new MemoryStore({ idbFactory, dbName: opts.dbName, maxEntries });
|
|
324
|
+
const backend = new MemoryStoreBackend(store, runtime);
|
|
283
325
|
|
|
284
326
|
if (!opts.persistFile) return backend;
|
|
285
327
|
|
package/src/experience/train.ts
CHANGED
|
@@ -1,96 +1,116 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Teach the person's private Evermind what they have done.
|
|
3
|
-
*
|
|
4
|
-
* Experience becomes text through the engine (`experienceDocuments`: each skill or
|
|
5
|
-
* uncompiled demonstration as a written procedure), and the text becomes weights
|
|
6
|
-
* through the engine's ONE adaptation recipe (`adaptPackage`). This module only
|
|
7
|
-
* decides what is new, runs the passes over the local model file and writes the
|
|
8
|
-
* result back, keeping the previous model beside it.
|
|
9
|
-
*
|
|
10
|
-
* "What is new" is the store's learned ledger. Every adaptation writes `<base>+expN`
|
|
11
|
-
* and records N against each procedure it learned, so a loaded model trusts exactly
|
|
12
|
-
* the entries at or below its own N: rolling back to `<model>.prev` (+exp N-1)
|
|
13
|
-
* re-teaches what the discarded version had learned, and a fresh base (no suffix,
|
|
14
|
-
* N = 0) — a newly downloaded Evermind — gets every procedure again.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import type {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
model.
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Teach the person's private Evermind what they have done.
|
|
3
|
+
*
|
|
4
|
+
* Experience becomes text through the engine (`experienceDocuments`: each skill or
|
|
5
|
+
* uncompiled demonstration as a written procedure), and the text becomes weights
|
|
6
|
+
* through the engine's ONE adaptation recipe (`adaptPackage`). This module only
|
|
7
|
+
* decides what is new, runs the passes over the local model file and writes the
|
|
8
|
+
* result back, keeping the previous model beside it.
|
|
9
|
+
*
|
|
10
|
+
* "What is new" is the store's learned ledger. Every adaptation writes `<base>+expN`
|
|
11
|
+
* and records N against each procedure it learned, so a loaded model trusts exactly
|
|
12
|
+
* the entries at or below its own N: rolling back to `<model>.prev` (+exp N-1)
|
|
13
|
+
* re-teaches what the discarded version had learned, and a fresh base (no suffix,
|
|
14
|
+
* N = 0) — a newly downloaded Evermind — gets every procedure again.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
adaptPackage,
|
|
19
|
+
experienceDocuments,
|
|
20
|
+
packDocuments,
|
|
21
|
+
ExperienceDocument,
|
|
22
|
+
ExperienceStore,
|
|
23
|
+
} from "@seanhogg/builderforce-memory-engine";
|
|
24
|
+
import type { LoadedEvermind } from "../model/evermind-package.js";
|
|
25
|
+
|
|
26
|
+
/** The engine functions training needs, passed in so the peer stays optional. */
|
|
27
|
+
export interface TrainEngine {
|
|
28
|
+
experienceDocuments: typeof experienceDocuments;
|
|
29
|
+
packDocuments: typeof packDocuments;
|
|
30
|
+
adaptPackage: typeof adaptPackage;
|
|
31
|
+
EVERMIND_ADAPT_MAX_CHARS: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type TrainOutcome =
|
|
35
|
+
| { status: "nothing_new"; pending: 0; version: string }
|
|
36
|
+
| { status: "no_window"; pending: number; version: string }
|
|
37
|
+
| { status: "curated_out"; pending: number; version: string }
|
|
38
|
+
| { status: "trained"; learned: number; passes: number; loss: number; version: string; previousModel: string };
|
|
39
|
+
|
|
40
|
+
const EXP_SUFFIX = /\+exp(\d+)$/;
|
|
41
|
+
|
|
42
|
+
/** The version an adaptation writes: `<base>+exp1`, then `+exp2`, … */
|
|
43
|
+
export function nextExperienceVersion(version: string): string {
|
|
44
|
+
const m = EXP_SUFFIX.exec(version);
|
|
45
|
+
return m ? version.replace(EXP_SUFFIX, `+exp${Number(m[1]) + 1}`) : `${version}+exp1`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Which adaptation produced this model: N for `+expN`, 0 for a base that has none. */
|
|
49
|
+
export function experienceIndex(version: string): number {
|
|
50
|
+
const m = EXP_SUFFIX.exec(version);
|
|
51
|
+
return m ? Number(m[1]) : 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Procedures the model has not learned yet. */
|
|
55
|
+
export async function pendingDocuments(store: ExperienceStore, engine: TrainEngine, modelVersion: string) {
|
|
56
|
+
const snap = await store.snapshot();
|
|
57
|
+
const current = experienceIndex(modelVersion);
|
|
58
|
+
const known = (id: string) => {
|
|
59
|
+
const n = snap.learned[id];
|
|
60
|
+
return typeof n === "number" && n >= 1 && n <= current;
|
|
61
|
+
};
|
|
62
|
+
return engine.experienceDocuments(snap.episodes, snap.skills).filter((d) => !known(d.id));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface TrainExperienceOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Opt-in curation between "what is new" and the adaptation passes — typically the
|
|
68
|
+
* engine's `curateExperience` (quality filter + near-duplicate removal, docs/ml-task-catalog.md
|
|
69
|
+
* §4.2). Absent ⇒ every pending procedure is learned, exactly as before. A procedure
|
|
70
|
+
* curation drops is NOT recorded as learned, so a later pass reconsiders it.
|
|
71
|
+
*/
|
|
72
|
+
curate?: (docs: ExperienceDocument[]) => Promise<ExperienceDocument[]> | ExperienceDocument[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function trainExperience(
|
|
76
|
+
store: ExperienceStore,
|
|
77
|
+
engine: TrainEngine,
|
|
78
|
+
model: LoadedEvermind,
|
|
79
|
+
modelFile: string,
|
|
80
|
+
opts: TrainExperienceOptions = {},
|
|
81
|
+
): Promise<TrainOutcome> {
|
|
82
|
+
const version = model.pkg.manifest.version ?? "0";
|
|
83
|
+
const pending = await pendingDocuments(store, engine, version);
|
|
84
|
+
if (pending.length === 0) return { status: "nothing_new", pending: 0, version };
|
|
85
|
+
const docs = opts.curate ? await opts.curate(pending) : pending;
|
|
86
|
+
if (docs.length === 0) return { status: "curated_out", pending: pending.length, version };
|
|
87
|
+
|
|
88
|
+
const next = nextExperienceVersion(version);
|
|
89
|
+
// The engine's package type; the structural view is what was loaded from disk.
|
|
90
|
+
let pkg = model.pkg as unknown as Parameters<typeof adaptPackage>[0];
|
|
91
|
+
const learned: string[] = [];
|
|
92
|
+
let lossSum = 0;
|
|
93
|
+
let passes = 0;
|
|
94
|
+
for (const pass of engine.packDocuments(docs, engine.EVERMIND_ADAPT_MAX_CHARS)) {
|
|
95
|
+
const r = engine.adaptPackage(pkg, model.codec, pass.map((d) => d.text).join("\n\n"), next);
|
|
96
|
+
if (!r) continue;
|
|
97
|
+
pkg = r.pkg;
|
|
98
|
+
lossSum += r.loss;
|
|
99
|
+
passes++;
|
|
100
|
+
learned.push(...pass.map((d) => d.id));
|
|
101
|
+
}
|
|
102
|
+
if (passes === 0) return { status: "no_window", pending: docs.length, version };
|
|
103
|
+
|
|
104
|
+
const loss = lossSum / passes;
|
|
105
|
+
// Keep the model this pass started from, so one bad adaptation is one rename away
|
|
106
|
+
// from undone. The new model is written beside the old one and renamed into place,
|
|
107
|
+
// so a crash mid-write never leaves a truncated model. The ledger is written only
|
|
108
|
+
// after the new model is on disk.
|
|
109
|
+
const previousModel = `${modelFile}.prev`;
|
|
110
|
+
model.fs.copyFileSync(modelFile, previousModel);
|
|
111
|
+
const staged = `${modelFile}.next`;
|
|
112
|
+
model.fs.writeFileSync(staged, new Uint8Array(pkg.toBlob()));
|
|
113
|
+
model.fs.renameSync(staged, modelFile);
|
|
114
|
+
await store.recordAdaptation({ index: experienceIndex(next), version: next, learned, passes, loss, at: Date.now() });
|
|
115
|
+
return { status: "trained", learned: learned.length, passes, loss, version: next, previousModel };
|
|
116
|
+
}
|