claude-memory-layer 1.0.19 → 1.0.20
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/cli/index.js +161 -6
- package/dist/cli/index.js.map +2 -2
- package/dist/core/index.js +49 -4
- package/dist/core/index.js.map +2 -2
- package/dist/hooks/post-tool-use.js +134 -3
- package/dist/hooks/post-tool-use.js.map +2 -2
- package/dist/hooks/session-end.js +134 -3
- package/dist/hooks/session-end.js.map +2 -2
- package/dist/hooks/session-start.js +134 -3
- package/dist/hooks/session-start.js.map +2 -2
- package/dist/hooks/stop.js +134 -3
- package/dist/hooks/stop.js.map +2 -2
- package/dist/hooks/user-prompt-submit.js +134 -3
- package/dist/hooks/user-prompt-submit.js.map +2 -2
- package/dist/server/api/index.js +138 -3
- package/dist/server/api/index.js.map +2 -2
- package/dist/server/index.js +138 -3
- package/dist/server/index.js.map +2 -2
- package/dist/services/memory-service.js +134 -3
- package/dist/services/memory-service.js.map +2 -2
- package/dist/ui/app.js +126 -0
- package/dist/ui/index.html +39 -0
- package/dist/ui/style.css +7 -0
- package/package.json +1 -1
- package/src/cli/index.ts +23 -1
- package/src/core/embedder.ts +3 -2
- package/src/core/sqlite-event-store.ts +32 -0
- package/src/core/types.ts +2 -2
- package/src/core/vector-store.ts +20 -0
- package/src/server/api/events.ts +6 -0
- package/src/services/memory-service.ts +112 -2
- package/src/ui/app.js +126 -0
- package/src/ui/index.html +39 -0
- package/src/ui/style.css +7 -0
|
@@ -1599,6 +1599,33 @@ var SQLiteEventStore = class {
|
|
|
1599
1599
|
ids
|
|
1600
1600
|
);
|
|
1601
1601
|
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Clear embedding outbox (used for embedding model migration)
|
|
1604
|
+
*/
|
|
1605
|
+
async clearEmbeddingOutbox() {
|
|
1606
|
+
await this.initialize();
|
|
1607
|
+
sqliteRun(this.db, `DELETE FROM embedding_outbox`);
|
|
1608
|
+
}
|
|
1609
|
+
/**
|
|
1610
|
+
* Count total events
|
|
1611
|
+
*/
|
|
1612
|
+
async countEvents() {
|
|
1613
|
+
await this.initialize();
|
|
1614
|
+
const row = sqliteGet(this.db, `SELECT COUNT(*) as count FROM events`);
|
|
1615
|
+
return row?.count || 0;
|
|
1616
|
+
}
|
|
1617
|
+
/**
|
|
1618
|
+
* Get events page in timestamp ascending order (stable migration/reindex scans)
|
|
1619
|
+
*/
|
|
1620
|
+
async getEventsPage(limit = 1e3, offset = 0) {
|
|
1621
|
+
await this.initialize();
|
|
1622
|
+
const rows = sqliteAll(
|
|
1623
|
+
this.db,
|
|
1624
|
+
`SELECT * FROM events ORDER BY timestamp ASC LIMIT ? OFFSET ?`,
|
|
1625
|
+
[limit, offset]
|
|
1626
|
+
);
|
|
1627
|
+
return rows.map(this.rowToEvent);
|
|
1628
|
+
}
|
|
1602
1629
|
/**
|
|
1603
1630
|
* Mark outbox items as failed
|
|
1604
1631
|
*/
|
|
@@ -2564,6 +2591,23 @@ var VectorStore = class {
|
|
|
2564
2591
|
const result = await this.table.countRows();
|
|
2565
2592
|
return result;
|
|
2566
2593
|
}
|
|
2594
|
+
/**
|
|
2595
|
+
* Clear all vectors (used for embedding model migration)
|
|
2596
|
+
*/
|
|
2597
|
+
async clearAll() {
|
|
2598
|
+
await this.initialize();
|
|
2599
|
+
if (!this.db)
|
|
2600
|
+
return;
|
|
2601
|
+
try {
|
|
2602
|
+
if (typeof this.db.dropTable === "function") {
|
|
2603
|
+
await this.db.dropTable(this.tableName);
|
|
2604
|
+
} else if (typeof this.db.drop_table === "function") {
|
|
2605
|
+
await this.db.drop_table(this.tableName);
|
|
2606
|
+
}
|
|
2607
|
+
} catch {
|
|
2608
|
+
}
|
|
2609
|
+
this.table = null;
|
|
2610
|
+
}
|
|
2567
2611
|
/**
|
|
2568
2612
|
* Check if vector exists for event
|
|
2569
2613
|
*/
|
|
@@ -2581,7 +2625,7 @@ var Embedder = class {
|
|
|
2581
2625
|
pipeline = null;
|
|
2582
2626
|
modelName;
|
|
2583
2627
|
initialized = false;
|
|
2584
|
-
constructor(modelName = "
|
|
2628
|
+
constructor(modelName = "jinaai/jina-embeddings-v5-text-nano") {
|
|
2585
2629
|
this.modelName = modelName;
|
|
2586
2630
|
}
|
|
2587
2631
|
/**
|
|
@@ -2661,8 +2705,9 @@ var Embedder = class {
|
|
|
2661
2705
|
};
|
|
2662
2706
|
var defaultEmbedder = null;
|
|
2663
2707
|
function getDefaultEmbedder() {
|
|
2708
|
+
const envModel = process.env.CLAUDE_MEMORY_EMBEDDING_MODEL;
|
|
2664
2709
|
if (!defaultEmbedder) {
|
|
2665
|
-
defaultEmbedder = new Embedder();
|
|
2710
|
+
defaultEmbedder = new Embedder(envModel || void 0);
|
|
2666
2711
|
}
|
|
2667
2712
|
return defaultEmbedder;
|
|
2668
2713
|
}
|
|
@@ -5897,8 +5942,10 @@ var MemoryService = class {
|
|
|
5897
5942
|
readOnly;
|
|
5898
5943
|
lightweightMode;
|
|
5899
5944
|
mdMirror;
|
|
5945
|
+
storagePath;
|
|
5900
5946
|
constructor(config) {
|
|
5901
5947
|
const storagePath = this.expandPath(config.storagePath);
|
|
5948
|
+
this.storagePath = storagePath;
|
|
5902
5949
|
this.readOnly = config.readOnly ?? false;
|
|
5903
5950
|
this.lightweightMode = config.lightweightMode ?? false;
|
|
5904
5951
|
this.mdMirror = new MarkdownMirror2(process.cwd());
|
|
@@ -5934,7 +5981,8 @@ var MemoryService = class {
|
|
|
5934
5981
|
);
|
|
5935
5982
|
}
|
|
5936
5983
|
this.vectorStore = new VectorStore(path3.join(storagePath, "vectors"));
|
|
5937
|
-
|
|
5984
|
+
const embeddingModel = config.embeddingModel || process.env.CLAUDE_MEMORY_EMBEDDING_MODEL;
|
|
5985
|
+
this.embedder = embeddingModel ? new Embedder(embeddingModel) : getDefaultEmbedder();
|
|
5938
5986
|
this.matcher = getDefaultMatcher();
|
|
5939
5987
|
this.retriever = createRetriever(
|
|
5940
5988
|
this.sqliteStore,
|
|
@@ -6878,6 +6926,89 @@ var MemoryService = class {
|
|
|
6878
6926
|
recordMemoryAccess(eventId, sessionId, confidence = 1) {
|
|
6879
6927
|
this.graduation.recordAccess(eventId, sessionId, confidence);
|
|
6880
6928
|
}
|
|
6929
|
+
getEmbeddingModelName() {
|
|
6930
|
+
return this.embedder.getModelName();
|
|
6931
|
+
}
|
|
6932
|
+
/**
|
|
6933
|
+
* Ensure embedding model metadata is in sync and optionally migrate vectors.
|
|
6934
|
+
* Migration strategy: clear vector index + clear embedding outbox + re-enqueue all events.
|
|
6935
|
+
*/
|
|
6936
|
+
async ensureEmbeddingModelForImport(options) {
|
|
6937
|
+
await this.initialize();
|
|
6938
|
+
const currentModel = this.getEmbeddingModelName();
|
|
6939
|
+
const metaPath = path3.join(this.storagePath, "embedding-meta.json");
|
|
6940
|
+
let previousModel = null;
|
|
6941
|
+
try {
|
|
6942
|
+
if (fs4.existsSync(metaPath)) {
|
|
6943
|
+
const parsed = JSON.parse(fs4.readFileSync(metaPath, "utf-8"));
|
|
6944
|
+
previousModel = parsed?.model || null;
|
|
6945
|
+
}
|
|
6946
|
+
} catch {
|
|
6947
|
+
previousModel = null;
|
|
6948
|
+
}
|
|
6949
|
+
const stats = await this.getStats();
|
|
6950
|
+
const hasExistingVectors = (stats.vectorCount || 0) > 0;
|
|
6951
|
+
if (!previousModel && !hasExistingVectors) {
|
|
6952
|
+
fs4.writeFileSync(metaPath, JSON.stringify({ model: currentModel, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
|
|
6953
|
+
return { changed: false, previousModel: null, currentModel, enqueued: 0, reason: "initialized-meta" };
|
|
6954
|
+
}
|
|
6955
|
+
const modelChanged = previousModel !== currentModel;
|
|
6956
|
+
const legacyUnknownButVectorsExist = !previousModel && hasExistingVectors;
|
|
6957
|
+
if (!modelChanged && !legacyUnknownButVectorsExist) {
|
|
6958
|
+
return { changed: false, previousModel, currentModel, enqueued: 0 };
|
|
6959
|
+
}
|
|
6960
|
+
if (options?.autoMigrate === false) {
|
|
6961
|
+
return {
|
|
6962
|
+
changed: true,
|
|
6963
|
+
previousModel,
|
|
6964
|
+
currentModel,
|
|
6965
|
+
enqueued: 0,
|
|
6966
|
+
reason: legacyUnknownButVectorsExist ? "legacy-vectors-without-meta" : "model-mismatch"
|
|
6967
|
+
};
|
|
6968
|
+
}
|
|
6969
|
+
const wasRunning = this.vectorWorker?.isRunning() || false;
|
|
6970
|
+
if (wasRunning)
|
|
6971
|
+
this.vectorWorker?.stop();
|
|
6972
|
+
await this.vectorStore.clearAll();
|
|
6973
|
+
await this.sqliteStore.clearEmbeddingOutbox();
|
|
6974
|
+
const pageSize = 1e3;
|
|
6975
|
+
let offset = 0;
|
|
6976
|
+
let enqueued = 0;
|
|
6977
|
+
while (true) {
|
|
6978
|
+
const page = await this.sqliteStore.getEventsPage(pageSize, offset);
|
|
6979
|
+
if (page.length === 0)
|
|
6980
|
+
break;
|
|
6981
|
+
for (const event of page) {
|
|
6982
|
+
await this.sqliteStore.enqueueForEmbedding(event.id, event.content);
|
|
6983
|
+
enqueued += 1;
|
|
6984
|
+
}
|
|
6985
|
+
offset += page.length;
|
|
6986
|
+
if (page.length < pageSize)
|
|
6987
|
+
break;
|
|
6988
|
+
}
|
|
6989
|
+
fs4.writeFileSync(
|
|
6990
|
+
metaPath,
|
|
6991
|
+
JSON.stringify(
|
|
6992
|
+
{
|
|
6993
|
+
model: currentModel,
|
|
6994
|
+
previousModel,
|
|
6995
|
+
migratedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6996
|
+
enqueued
|
|
6997
|
+
},
|
|
6998
|
+
null,
|
|
6999
|
+
2
|
|
7000
|
+
)
|
|
7001
|
+
);
|
|
7002
|
+
if (wasRunning)
|
|
7003
|
+
this.vectorWorker?.start();
|
|
7004
|
+
return {
|
|
7005
|
+
changed: true,
|
|
7006
|
+
previousModel,
|
|
7007
|
+
currentModel,
|
|
7008
|
+
enqueued,
|
|
7009
|
+
reason: legacyUnknownButVectorsExist ? "legacy-vectors-without-meta" : "model-mismatch"
|
|
7010
|
+
};
|
|
7011
|
+
}
|
|
6881
7012
|
/**
|
|
6882
7013
|
* Backward-compatible alias used by some hooks
|
|
6883
7014
|
*/
|