@memtensor/memos-local-openclaw-plugin 0.1.3 → 0.1.4
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/.env.example +13 -5
- package/README.md +177 -97
- package/dist/capture/index.d.ts +5 -7
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +72 -43
- package/dist/capture/index.js.map +1 -1
- package/dist/ingest/providers/anthropic.d.ts +2 -0
- package/dist/ingest/providers/anthropic.d.ts.map +1 -1
- package/dist/ingest/providers/anthropic.js +110 -1
- package/dist/ingest/providers/anthropic.js.map +1 -1
- package/dist/ingest/providers/bedrock.d.ts +2 -5
- package/dist/ingest/providers/bedrock.d.ts.map +1 -1
- package/dist/ingest/providers/bedrock.js +110 -6
- package/dist/ingest/providers/bedrock.js.map +1 -1
- package/dist/ingest/providers/gemini.d.ts +2 -0
- package/dist/ingest/providers/gemini.d.ts.map +1 -1
- package/dist/ingest/providers/gemini.js +106 -1
- package/dist/ingest/providers/gemini.js.map +1 -1
- package/dist/ingest/providers/index.d.ts +9 -0
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +66 -4
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/ingest/providers/openai.d.ts +2 -0
- package/dist/ingest/providers/openai.d.ts.map +1 -1
- package/dist/ingest/providers/openai.js +112 -1
- package/dist/ingest/providers/openai.js.map +1 -1
- package/dist/ingest/task-processor.d.ts +63 -0
- package/dist/ingest/task-processor.d.ts.map +1 -0
- package/dist/ingest/task-processor.js +339 -0
- package/dist/ingest/task-processor.js.map +1 -0
- package/dist/ingest/worker.d.ts +1 -1
- package/dist/ingest/worker.d.ts.map +1 -1
- package/dist/ingest/worker.js +18 -13
- package/dist/ingest/worker.js.map +1 -1
- package/dist/recall/engine.d.ts +1 -0
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +21 -11
- package/dist/recall/engine.js.map +1 -1
- package/dist/recall/mmr.d.ts.map +1 -1
- package/dist/recall/mmr.js +3 -1
- package/dist/recall/mmr.js.map +1 -1
- package/dist/storage/sqlite.d.ts +67 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +251 -5
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +919 -123
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +3 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +59 -1
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +217 -42
- package/openclaw.plugin.json +20 -45
- package/package.json +3 -4
- package/skill/SKILL.md +59 -0
- package/src/capture/index.ts +85 -45
- package/src/ingest/providers/anthropic.ts +128 -1
- package/src/ingest/providers/bedrock.ts +130 -6
- package/src/ingest/providers/gemini.ts +128 -1
- package/src/ingest/providers/index.ts +74 -8
- package/src/ingest/providers/openai.ts +130 -1
- package/src/ingest/task-processor.ts +380 -0
- package/src/ingest/worker.ts +21 -15
- package/src/recall/engine.ts +22 -12
- package/src/recall/mmr.ts +3 -1
- package/src/storage/sqlite.ts +298 -5
- package/src/types.ts +19 -0
- package/src/viewer/html.ts +919 -123
- package/src/viewer/server.ts +63 -1
- package/SKILL.md +0 -43
- package/www/index.html +0 -632
package/dist/ingest/worker.js
CHANGED
|
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.IngestWorker = void 0;
|
|
4
4
|
const uuid_1 = require("uuid");
|
|
5
5
|
const providers_1 = require("./providers");
|
|
6
|
-
const chunker_1 = require("./chunker");
|
|
7
6
|
const dedup_1 = require("./dedup");
|
|
7
|
+
const task_processor_1 = require("./task-processor");
|
|
8
8
|
class IngestWorker {
|
|
9
9
|
store;
|
|
10
10
|
embedder;
|
|
11
11
|
ctx;
|
|
12
12
|
summarizer;
|
|
13
|
+
taskProcessor;
|
|
13
14
|
queue = [];
|
|
14
15
|
processing = false;
|
|
15
16
|
flushResolvers = [];
|
|
@@ -18,6 +19,7 @@ class IngestWorker {
|
|
|
18
19
|
this.embedder = embedder;
|
|
19
20
|
this.ctx = ctx;
|
|
20
21
|
this.summarizer = new providers_1.Summarizer(ctx.config.summarizer, ctx.log);
|
|
22
|
+
this.taskProcessor = new task_processor_1.TaskProcessor(store, ctx);
|
|
21
23
|
}
|
|
22
24
|
enqueue(messages) {
|
|
23
25
|
this.queue.push(...messages);
|
|
@@ -38,35 +40,37 @@ class IngestWorker {
|
|
|
38
40
|
}
|
|
39
41
|
async processQueue() {
|
|
40
42
|
this.processing = true;
|
|
43
|
+
let lastSessionKey;
|
|
44
|
+
let lastTimestamp = 0;
|
|
41
45
|
while (this.queue.length > 0) {
|
|
42
46
|
const msg = this.queue.shift();
|
|
43
47
|
try {
|
|
44
48
|
await this.ingestMessage(msg);
|
|
49
|
+
lastSessionKey = msg.sessionKey;
|
|
50
|
+
lastTimestamp = Math.max(lastTimestamp, msg.timestamp);
|
|
45
51
|
}
|
|
46
52
|
catch (err) {
|
|
47
53
|
this.ctx.log.error(`Failed to ingest message turn=${msg.turnId}: ${err}`);
|
|
48
54
|
}
|
|
49
55
|
}
|
|
56
|
+
if (lastSessionKey) {
|
|
57
|
+
this.ctx.log.debug(`Calling TaskProcessor.onChunksIngested session=${lastSessionKey} ts=${lastTimestamp}`);
|
|
58
|
+
this.taskProcessor
|
|
59
|
+
.onChunksIngested(lastSessionKey, lastTimestamp)
|
|
60
|
+
.catch((err) => this.ctx.log.error(`TaskProcessor post-ingest error: ${err}`));
|
|
61
|
+
}
|
|
50
62
|
this.processing = false;
|
|
51
63
|
for (const resolve of this.flushResolvers)
|
|
52
64
|
resolve();
|
|
53
65
|
this.flushResolvers = [];
|
|
54
66
|
}
|
|
55
67
|
async ingestMessage(msg) {
|
|
56
|
-
if (msg.role
|
|
57
|
-
|
|
68
|
+
if (this.store.chunkExistsByContent(msg.sessionKey, msg.role, msg.content)) {
|
|
69
|
+
this.ctx.log.debug(`Skipping duplicate message: session=${msg.sessionKey} role=${msg.role} len=${msg.content.length}`);
|
|
58
70
|
return;
|
|
59
71
|
}
|
|
60
|
-
const
|
|
61
|
-
this.
|
|
62
|
-
for (let seq = 0; seq < rawChunks.length; seq++) {
|
|
63
|
-
const raw = rawChunks[seq];
|
|
64
|
-
await this.storeChunk(msg, raw.content, raw.kind, seq);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
async ingestToolResult(msg) {
|
|
68
|
-
this.ctx.log.debug(`Ingesting tool result turn=${msg.turnId} tool=${msg.toolName ?? "unknown"} len=${msg.content.length}`);
|
|
69
|
-
await this.storeChunk(msg, msg.content, "tool_result", 0);
|
|
72
|
+
const kind = msg.role === "tool" ? "tool_result" : "paragraph";
|
|
73
|
+
await this.storeChunk(msg, msg.content, kind, 0);
|
|
70
74
|
}
|
|
71
75
|
async storeChunk(msg, content, kind, seq) {
|
|
72
76
|
const chunkId = (0, uuid_1.v4)();
|
|
@@ -97,6 +101,7 @@ class IngestWorker {
|
|
|
97
101
|
kind,
|
|
98
102
|
summary,
|
|
99
103
|
embedding: null,
|
|
104
|
+
taskId: null,
|
|
100
105
|
createdAt: msg.timestamp,
|
|
101
106
|
updatedAt: msg.timestamp,
|
|
102
107
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/ingest/worker.ts"],"names":[],"mappings":";;;AAAA,+BAAkC;
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/ingest/worker.ts"],"names":[],"mappings":"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"}
|
package/dist/recall/engine.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/recall/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAa,YAAY,EAAE,MAAM,UAAU,CAAC;AAMvE,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/recall/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAa,YAAY,EAAE,MAAM,UAAU,CAAC;AAMvE,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,qBAAa,YAAY;IAIrB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,GAAG;IALb,OAAO,CAAC,aAAa,CAAwF;gBAGnG,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,aAAa;IAGtB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAsHxD;;;OAGG;IACH,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,WAAW;CAapB"}
|
package/dist/recall/engine.js
CHANGED
|
@@ -21,6 +21,7 @@ class RecallEngine {
|
|
|
21
21
|
const maxResults = Math.min(opts.maxResults ?? recallCfg.maxResultsDefault, recallCfg.maxResultsMax);
|
|
22
22
|
const minScore = opts.minScore ?? recallCfg.minScoreDefault;
|
|
23
23
|
const query = opts.query ?? "";
|
|
24
|
+
const roleFilter = opts.role;
|
|
24
25
|
const repeatNote = this.checkRepeat(query, maxResults, minScore);
|
|
25
26
|
const candidatePool = maxResults * 5;
|
|
26
27
|
// Step 1: Gather candidates from both FTS and vector search
|
|
@@ -64,23 +65,31 @@ class RecallEngine {
|
|
|
64
65
|
return { ...r, createdAt: chunk?.createdAt ?? 0 };
|
|
65
66
|
});
|
|
66
67
|
const decayed = (0, recency_1.applyRecencyDecay)(withTs, recallCfg.recencyHalfLifeDays);
|
|
67
|
-
// Step 5:
|
|
68
|
-
const
|
|
69
|
-
const
|
|
68
|
+
// Step 5: Apply relative threshold on raw scores, then normalize to [0,1]
|
|
69
|
+
const sorted = [...decayed].sort((a, b) => b.score - a.score);
|
|
70
|
+
const topScore = sorted.length > 0 ? sorted[0].score : 0;
|
|
71
|
+
const absoluteFloor = topScore * minScore * 0.3;
|
|
72
|
+
// When role filter is active, keep a larger pool before slicing so we don't
|
|
73
|
+
// discard target-role candidates that rank below non-target ones.
|
|
74
|
+
const preSliceLimit = roleFilter ? maxResults * 5 : maxResults;
|
|
75
|
+
const filtered = sorted
|
|
76
|
+
.filter((d) => d.score >= absoluteFloor)
|
|
77
|
+
.slice(0, preSliceLimit);
|
|
78
|
+
const displayMax = filtered.length > 0 ? filtered[0].score : 1;
|
|
79
|
+
const normalized = filtered.map((d) => ({
|
|
70
80
|
...d,
|
|
71
|
-
score: d.score /
|
|
81
|
+
score: d.score / displayMax,
|
|
72
82
|
}));
|
|
73
|
-
// Step 6:
|
|
74
|
-
const filtered = normalized
|
|
75
|
-
.filter((d) => d.score >= minScore)
|
|
76
|
-
.sort((a, b) => b.score - a.score)
|
|
77
|
-
.slice(0, maxResults);
|
|
78
|
-
// Step 7: Build hits
|
|
83
|
+
// Step 6: Build hits (with optional role filter), applying maxResults cap at the end
|
|
79
84
|
const hits = [];
|
|
80
|
-
for (const candidate of
|
|
85
|
+
for (const candidate of normalized) {
|
|
86
|
+
if (hits.length >= maxResults)
|
|
87
|
+
break;
|
|
81
88
|
const chunk = this.store.getChunk(candidate.id);
|
|
82
89
|
if (!chunk)
|
|
83
90
|
continue;
|
|
91
|
+
if (roleFilter && chunk.role !== roleFilter)
|
|
92
|
+
continue;
|
|
84
93
|
hits.push({
|
|
85
94
|
summary: chunk.summary,
|
|
86
95
|
original_excerpt: makeExcerpt(chunk.content),
|
|
@@ -91,6 +100,7 @@ class RecallEngine {
|
|
|
91
100
|
seq: chunk.seq,
|
|
92
101
|
},
|
|
93
102
|
score: Math.round(candidate.score * 1000) / 1000,
|
|
103
|
+
taskId: chunk.taskId,
|
|
94
104
|
source: {
|
|
95
105
|
ts: chunk.createdAt,
|
|
96
106
|
role: chunk.role,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/recall/engine.ts"],"names":[],"mappings":";;;AAGA,8CAAiD;AACjD,+BAAgC;AAChC,+BAAkC;AAClC,uCAA8C;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/recall/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/recall/mmr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mmr.d.ts","sourceRoot":"","sources":["../../src/recall/mmr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAChD,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,MAAY,EACpB,IAAI,GAAE,MAAW,GAChB,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"mmr.d.ts","sourceRoot":"","sources":["../../src/recall/mmr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAChD,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,MAAY,EACpB,IAAI,GAAE,MAAW,GAChB,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA6CtC"}
|
package/dist/recall/mmr.js
CHANGED
|
@@ -44,7 +44,9 @@ function mmrRerank(candidates, store, lambda = 0.7, topK = 20) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
const chosen = remaining.splice(bestIdx, 1)[0];
|
|
47
|
-
|
|
47
|
+
// Preserve original RRF score for downstream filtering;
|
|
48
|
+
// MMR only determines selection order, not the score value.
|
|
49
|
+
selected.push({ id: chosen.id, score: chosen.score });
|
|
48
50
|
}
|
|
49
51
|
return selected;
|
|
50
52
|
}
|
package/dist/recall/mmr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mmr.js","sourceRoot":"","sources":["../../src/recall/mmr.ts"],"names":[],"mappings":";;AAWA,
|
|
1
|
+
{"version":3,"file":"mmr.js","sourceRoot":"","sources":["../../src/recall/mmr.ts"],"names":[],"mappings":";;AAWA,8BAkDC;AA7DD,8CAAqD;AAGrD;;;;;;;GAOG;AACH,SAAgB,SAAS,CACvB,UAAgD,EAChD,KAAkB,EAClB,SAAiB,GAAG,EACpB,OAAe,EAAE;IAEjB,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,UAAU,CAAC;IAE9C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,GAAG;YAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,QAAQ,GAAyC,EAAE,CAAC;IAC1D,MAAM,SAAS,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;IAElC,OAAO,QAAQ,CAAC,MAAM,GAAG,IAAI,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtD,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,QAAQ,CAAC;QAExB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAExC,IAAI,gBAAgB,GAAG,CAAC,CAAC;YACzB,IAAI,OAAO,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;oBACzB,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAClC,IAAI,IAAI,EAAE,CAAC;wBACT,MAAM,GAAG,GAAG,IAAA,yBAAgB,EAAC,OAAO,EAAE,IAAI,CAAC,CAAC;wBAC5C,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;oBACrD,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,gBAAgB,CAAC;YACvE,IAAI,QAAQ,GAAG,OAAO,EAAE,CAAC;gBACvB,OAAO,GAAG,QAAQ,CAAC;gBACnB,OAAO,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,wDAAwD;QACxD,4DAA4D;QAC5D,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/storage/sqlite.d.ts
CHANGED
|
@@ -1,9 +1,37 @@
|
|
|
1
|
-
import type { Chunk, ChunkRef, Logger } from "../types";
|
|
1
|
+
import type { Chunk, ChunkRef, Task, TaskStatus, Logger } from "../types";
|
|
2
2
|
export declare class SqliteStore {
|
|
3
3
|
private log;
|
|
4
4
|
private db;
|
|
5
5
|
constructor(dbPath: string, log: Logger);
|
|
6
6
|
private migrate;
|
|
7
|
+
private migrateTaskId;
|
|
8
|
+
private migrateContentHash;
|
|
9
|
+
/** Record a viewer API call for analytics (list, search, etc.). */
|
|
10
|
+
recordViewerEvent(eventType: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Return metrics for the last N days: writes per day (from chunks), viewer calls per day.
|
|
13
|
+
*/
|
|
14
|
+
getMetrics(days: number): {
|
|
15
|
+
writesPerDay: Array<{
|
|
16
|
+
date: string;
|
|
17
|
+
count: number;
|
|
18
|
+
}>;
|
|
19
|
+
viewerCallsPerDay: Array<{
|
|
20
|
+
date: string;
|
|
21
|
+
list: number;
|
|
22
|
+
search: number;
|
|
23
|
+
total: number;
|
|
24
|
+
}>;
|
|
25
|
+
roleBreakdown: Record<string, number>;
|
|
26
|
+
kindBreakdown: Record<string, number>;
|
|
27
|
+
totals: {
|
|
28
|
+
memories: number;
|
|
29
|
+
sessions: number;
|
|
30
|
+
embeddings: number;
|
|
31
|
+
todayWrites: number;
|
|
32
|
+
todayViewerCalls: number;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
7
35
|
insertChunk(chunk: Chunk): void;
|
|
8
36
|
updateSummary(chunkId: string, summary: string): void;
|
|
9
37
|
upsertEmbedding(chunkId: string, vector: number[]): void;
|
|
@@ -14,6 +42,15 @@ export declare class SqliteStore {
|
|
|
14
42
|
chunkId: string;
|
|
15
43
|
score: number;
|
|
16
44
|
}>;
|
|
45
|
+
patternSearch(patterns: string[], opts?: {
|
|
46
|
+
role?: string;
|
|
47
|
+
limit?: number;
|
|
48
|
+
}): Array<{
|
|
49
|
+
chunkId: string;
|
|
50
|
+
content: string;
|
|
51
|
+
role: string;
|
|
52
|
+
createdAt: number;
|
|
53
|
+
}>;
|
|
17
54
|
getAllEmbeddings(): Array<{
|
|
18
55
|
chunkId: string;
|
|
19
56
|
vector: number[];
|
|
@@ -28,7 +65,36 @@ export declare class SqliteStore {
|
|
|
28
65
|
deleteChunk(chunkId: string): boolean;
|
|
29
66
|
deleteSession(sessionKey: string): number;
|
|
30
67
|
deleteAll(): number;
|
|
68
|
+
insertTask(task: Task): void;
|
|
69
|
+
getTask(taskId: string): Task | null;
|
|
70
|
+
getActiveTask(sessionKey: string): Task | null;
|
|
71
|
+
getAllActiveTasks(): Task[];
|
|
72
|
+
updateTask(taskId: string, fields: {
|
|
73
|
+
title?: string;
|
|
74
|
+
summary?: string;
|
|
75
|
+
status?: TaskStatus;
|
|
76
|
+
endedAt?: number;
|
|
77
|
+
}): boolean;
|
|
78
|
+
getChunksByTask(taskId: string): Chunk[];
|
|
79
|
+
listTasks(opts?: {
|
|
80
|
+
status?: string;
|
|
81
|
+
limit?: number;
|
|
82
|
+
offset?: number;
|
|
83
|
+
}): {
|
|
84
|
+
tasks: Task[];
|
|
85
|
+
total: number;
|
|
86
|
+
};
|
|
87
|
+
countChunksByTask(taskId: string): number;
|
|
88
|
+
setChunkTaskId(chunkId: string, taskId: string): void;
|
|
89
|
+
getUnassignedChunks(sessionKey: string): Chunk[];
|
|
90
|
+
/**
|
|
91
|
+
* Check if a chunk with the same (session_key, role, content_hash) already exists.
|
|
92
|
+
* Uses indexed content_hash for O(1) lookup to prevent duplicate ingestion
|
|
93
|
+
* when agent_end sends the full conversation history every turn.
|
|
94
|
+
*/
|
|
95
|
+
chunkExistsByContent(sessionKey: string, role: string, content: string): boolean;
|
|
31
96
|
getRecentChunkIds(limit: number): string[];
|
|
97
|
+
countChunks(): number;
|
|
32
98
|
close(): void;
|
|
33
99
|
}
|
|
34
100
|
//# sourceMappingURL=sqlite.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/storage/sqlite.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/storage/sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/storage/sqlite.js
CHANGED
|
@@ -38,6 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.SqliteStore = void 0;
|
|
40
40
|
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
41
|
+
const crypto_1 = require("crypto");
|
|
41
42
|
const fs = __importStar(require("fs"));
|
|
42
43
|
const path = __importStar(require("path"));
|
|
43
44
|
class SqliteStore {
|
|
@@ -105,16 +106,121 @@ class SqliteStore {
|
|
|
105
106
|
dimensions INTEGER NOT NULL,
|
|
106
107
|
updated_at INTEGER NOT NULL
|
|
107
108
|
);
|
|
109
|
+
|
|
110
|
+
CREATE TABLE IF NOT EXISTS viewer_events (
|
|
111
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
112
|
+
event_type TEXT NOT NULL,
|
|
113
|
+
created_at INTEGER NOT NULL
|
|
114
|
+
);
|
|
115
|
+
CREATE INDEX IF NOT EXISTS idx_viewer_events_created ON viewer_events(created_at);
|
|
116
|
+
CREATE INDEX IF NOT EXISTS idx_viewer_events_type ON viewer_events(event_type);
|
|
117
|
+
|
|
118
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
119
|
+
id TEXT PRIMARY KEY,
|
|
120
|
+
session_key TEXT NOT NULL,
|
|
121
|
+
title TEXT NOT NULL DEFAULT '',
|
|
122
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
123
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
124
|
+
started_at INTEGER NOT NULL,
|
|
125
|
+
ended_at INTEGER,
|
|
126
|
+
updated_at INTEGER NOT NULL
|
|
127
|
+
);
|
|
128
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_key);
|
|
129
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
|
108
130
|
`);
|
|
131
|
+
this.migrateTaskId();
|
|
132
|
+
this.migrateContentHash();
|
|
109
133
|
this.log.debug("Database schema initialized");
|
|
110
134
|
}
|
|
135
|
+
migrateTaskId() {
|
|
136
|
+
const cols = this.db.prepare("PRAGMA table_info(chunks)").all();
|
|
137
|
+
if (!cols.some((c) => c.name === "task_id")) {
|
|
138
|
+
this.db.exec("ALTER TABLE chunks ADD COLUMN task_id TEXT REFERENCES tasks(id)");
|
|
139
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_chunks_task ON chunks(task_id)");
|
|
140
|
+
this.log.info("Migrated: added task_id column to chunks");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
migrateContentHash() {
|
|
144
|
+
const cols = this.db.prepare("PRAGMA table_info(chunks)").all();
|
|
145
|
+
if (!cols.some((c) => c.name === "content_hash")) {
|
|
146
|
+
this.db.exec("ALTER TABLE chunks ADD COLUMN content_hash TEXT");
|
|
147
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_chunks_dedup ON chunks(session_key, role, content_hash)");
|
|
148
|
+
// Backfill existing rows
|
|
149
|
+
const rows = this.db.prepare("SELECT id, content FROM chunks WHERE content_hash IS NULL").all();
|
|
150
|
+
const updateStmt = this.db.prepare("UPDATE chunks SET content_hash = ? WHERE id = ?");
|
|
151
|
+
for (const r of rows) {
|
|
152
|
+
updateStmt.run(contentHash(r.content), r.id);
|
|
153
|
+
}
|
|
154
|
+
if (rows.length > 0) {
|
|
155
|
+
this.log.info(`Migrated: backfilled content_hash for ${rows.length} chunks`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Record a viewer API call for analytics (list, search, etc.). */
|
|
160
|
+
recordViewerEvent(eventType) {
|
|
161
|
+
this.db.prepare("INSERT INTO viewer_events (event_type, created_at) VALUES (?, ?)").run(eventType, Date.now());
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Return metrics for the last N days: writes per day (from chunks), viewer calls per day.
|
|
165
|
+
*/
|
|
166
|
+
getMetrics(days) {
|
|
167
|
+
const since = Date.now() - days * 86400 * 1000;
|
|
168
|
+
const now = new Date();
|
|
169
|
+
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
|
|
170
|
+
const writesRows = this.db
|
|
171
|
+
.prepare(`SELECT date(created_at/1000, 'unixepoch', 'localtime') as d, COUNT(*) as c
|
|
172
|
+
FROM chunks WHERE created_at >= ? GROUP BY d ORDER BY d`)
|
|
173
|
+
.all(since);
|
|
174
|
+
const writesPerDay = writesRows.map((r) => ({ date: r.d, count: r.c }));
|
|
175
|
+
const eventsRows = this.db
|
|
176
|
+
.prepare(`SELECT date(created_at/1000, 'unixepoch', 'localtime') as d, event_type, COUNT(*) as c
|
|
177
|
+
FROM viewer_events WHERE created_at >= ? GROUP BY d, event_type ORDER BY d`)
|
|
178
|
+
.all(since);
|
|
179
|
+
const byDate = new Map();
|
|
180
|
+
for (const r of eventsRows) {
|
|
181
|
+
let row = byDate.get(r.d);
|
|
182
|
+
if (!row) {
|
|
183
|
+
row = { list: 0, search: 0 };
|
|
184
|
+
byDate.set(r.d, row);
|
|
185
|
+
}
|
|
186
|
+
if (r.event_type === "list")
|
|
187
|
+
row.list += r.c;
|
|
188
|
+
else if (r.event_type === "search")
|
|
189
|
+
row.search += r.c;
|
|
190
|
+
}
|
|
191
|
+
const viewerCallsPerDay = Array.from(byDate.entries())
|
|
192
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
193
|
+
.map(([date, v]) => ({ date, list: v.list, search: v.search, total: v.list + v.search }));
|
|
194
|
+
const roles = this.db.prepare("SELECT role, COUNT(*) as count FROM chunks GROUP BY role").all();
|
|
195
|
+
const kinds = this.db.prepare("SELECT kind, COUNT(*) as count FROM chunks GROUP BY kind").all();
|
|
196
|
+
const roleBreakdown = Object.fromEntries(roles.map((r) => [r.role, r.count]));
|
|
197
|
+
const kindBreakdown = Object.fromEntries(kinds.map((k) => [k.kind, k.count]));
|
|
198
|
+
const totalChunks = this.db.prepare("SELECT COUNT(*) as c FROM chunks").get().c;
|
|
199
|
+
const totalSessions = this.db.prepare("SELECT COUNT(DISTINCT session_key) as c FROM chunks").get().c;
|
|
200
|
+
const totalEmbeddings = this.db.prepare("SELECT COUNT(*) as c FROM embeddings").get().c;
|
|
201
|
+
const todayWrites = this.db.prepare("SELECT COUNT(*) as c FROM chunks WHERE created_at >= ?").get(todayStart).c;
|
|
202
|
+
const todayViewerCalls = this.db.prepare("SELECT COUNT(*) as c FROM viewer_events WHERE created_at >= ?").get(todayStart).c;
|
|
203
|
+
return {
|
|
204
|
+
writesPerDay,
|
|
205
|
+
viewerCallsPerDay,
|
|
206
|
+
roleBreakdown,
|
|
207
|
+
kindBreakdown,
|
|
208
|
+
totals: {
|
|
209
|
+
memories: totalChunks,
|
|
210
|
+
sessions: totalSessions,
|
|
211
|
+
embeddings: totalEmbeddings,
|
|
212
|
+
todayWrites,
|
|
213
|
+
todayViewerCalls,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
111
217
|
// ─── Write ───
|
|
112
218
|
insertChunk(chunk) {
|
|
113
219
|
const stmt = this.db.prepare(`
|
|
114
|
-
INSERT OR REPLACE INTO chunks (id, session_key, turn_id, seq, role, content, kind, summary, created_at, updated_at)
|
|
115
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
220
|
+
INSERT OR REPLACE INTO chunks (id, session_key, turn_id, seq, role, content, kind, summary, task_id, content_hash, created_at, updated_at)
|
|
221
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
116
222
|
`);
|
|
117
|
-
stmt.run(chunk.id, chunk.sessionKey, chunk.turnId, chunk.seq, chunk.role, chunk.content, chunk.kind, chunk.summary, chunk.createdAt, chunk.updatedAt);
|
|
223
|
+
stmt.run(chunk.id, chunk.sessionKey, chunk.turnId, chunk.seq, chunk.role, chunk.content, chunk.kind, chunk.summary, chunk.taskId, contentHash(chunk.content), chunk.createdAt, chunk.updatedAt);
|
|
118
224
|
}
|
|
119
225
|
updateSummary(chunkId, summary) {
|
|
120
226
|
this.db.prepare("UPDATE chunks SET summary = ?, updated_at = ? WHERE id = ?").run(summary, Date.now(), chunkId);
|
|
@@ -175,6 +281,37 @@ class SqliteStore {
|
|
|
175
281
|
return [];
|
|
176
282
|
}
|
|
177
283
|
}
|
|
284
|
+
// ─── Pattern Search (LIKE-based, for CJK text where FTS tokenization is weak) ───
|
|
285
|
+
patternSearch(patterns, opts = {}) {
|
|
286
|
+
if (patterns.length === 0)
|
|
287
|
+
return [];
|
|
288
|
+
const limit = opts.limit ?? 10;
|
|
289
|
+
const conditions = patterns.map(() => "c.content LIKE ?");
|
|
290
|
+
const whereClause = conditions.join(" OR ");
|
|
291
|
+
const roleClause = opts.role ? " AND c.role = ?" : "";
|
|
292
|
+
const params = patterns.map(p => `%${p}%`);
|
|
293
|
+
if (opts.role)
|
|
294
|
+
params.push(opts.role);
|
|
295
|
+
params.push(limit);
|
|
296
|
+
try {
|
|
297
|
+
const rows = this.db.prepare(`
|
|
298
|
+
SELECT c.id as chunk_id, c.content, c.role, c.created_at
|
|
299
|
+
FROM chunks c
|
|
300
|
+
WHERE (${whereClause})${roleClause}
|
|
301
|
+
ORDER BY c.created_at DESC
|
|
302
|
+
LIMIT ?
|
|
303
|
+
`).all(...params);
|
|
304
|
+
return rows.map(r => ({
|
|
305
|
+
chunkId: r.chunk_id,
|
|
306
|
+
content: r.content,
|
|
307
|
+
role: r.role,
|
|
308
|
+
createdAt: r.created_at,
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return [];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
178
315
|
// ─── Vector Search ───
|
|
179
316
|
getAllEmbeddings() {
|
|
180
317
|
const rows = this.db.prepare("SELECT chunk_id, vector, dimensions FROM embeddings").all();
|
|
@@ -227,14 +364,107 @@ class SqliteStore {
|
|
|
227
364
|
return result.changes;
|
|
228
365
|
}
|
|
229
366
|
deleteAll() {
|
|
230
|
-
|
|
231
|
-
|
|
367
|
+
this.db.prepare("DELETE FROM chunks").run();
|
|
368
|
+
this.db.prepare("DELETE FROM tasks").run();
|
|
369
|
+
this.db.prepare("DELETE FROM viewer_events").run();
|
|
370
|
+
const remaining = this.countChunks();
|
|
371
|
+
return remaining === 0 ? 1 : 0;
|
|
372
|
+
}
|
|
373
|
+
// ─── Task CRUD ───
|
|
374
|
+
insertTask(task) {
|
|
375
|
+
this.db.prepare(`
|
|
376
|
+
INSERT OR REPLACE INTO tasks (id, session_key, title, summary, status, started_at, ended_at, updated_at)
|
|
377
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
378
|
+
`).run(task.id, task.sessionKey, task.title, task.summary, task.status, task.startedAt, task.endedAt, task.updatedAt);
|
|
379
|
+
}
|
|
380
|
+
getTask(taskId) {
|
|
381
|
+
const row = this.db.prepare("SELECT * FROM tasks WHERE id = ?").get(taskId);
|
|
382
|
+
return row ? rowToTask(row) : null;
|
|
383
|
+
}
|
|
384
|
+
getActiveTask(sessionKey) {
|
|
385
|
+
const row = this.db.prepare("SELECT * FROM tasks WHERE session_key = ? AND status = 'active' ORDER BY started_at DESC LIMIT 1").get(sessionKey);
|
|
386
|
+
return row ? rowToTask(row) : null;
|
|
387
|
+
}
|
|
388
|
+
getAllActiveTasks() {
|
|
389
|
+
const rows = this.db.prepare("SELECT * FROM tasks WHERE status = 'active' ORDER BY started_at DESC").all();
|
|
390
|
+
return rows.map(rowToTask);
|
|
391
|
+
}
|
|
392
|
+
updateTask(taskId, fields) {
|
|
393
|
+
const sets = [];
|
|
394
|
+
const params = [];
|
|
395
|
+
if (fields.title !== undefined) {
|
|
396
|
+
sets.push("title = ?");
|
|
397
|
+
params.push(fields.title);
|
|
398
|
+
}
|
|
399
|
+
if (fields.summary !== undefined) {
|
|
400
|
+
sets.push("summary = ?");
|
|
401
|
+
params.push(fields.summary);
|
|
402
|
+
}
|
|
403
|
+
if (fields.status !== undefined) {
|
|
404
|
+
sets.push("status = ?");
|
|
405
|
+
params.push(fields.status);
|
|
406
|
+
}
|
|
407
|
+
if (fields.endedAt !== undefined) {
|
|
408
|
+
sets.push("ended_at = ?");
|
|
409
|
+
params.push(fields.endedAt);
|
|
410
|
+
}
|
|
411
|
+
if (sets.length === 0)
|
|
412
|
+
return false;
|
|
413
|
+
sets.push("updated_at = ?");
|
|
414
|
+
params.push(Date.now());
|
|
415
|
+
params.push(taskId);
|
|
416
|
+
const result = this.db.prepare(`UPDATE tasks SET ${sets.join(", ")} WHERE id = ?`).run(...params);
|
|
417
|
+
return result.changes > 0;
|
|
418
|
+
}
|
|
419
|
+
getChunksByTask(taskId) {
|
|
420
|
+
const rows = this.db.prepare("SELECT * FROM chunks WHERE task_id = ? ORDER BY created_at, seq").all(taskId);
|
|
421
|
+
return rows.map(rowToChunk);
|
|
422
|
+
}
|
|
423
|
+
listTasks(opts = {}) {
|
|
424
|
+
const conditions = [];
|
|
425
|
+
const params = [];
|
|
426
|
+
if (opts.status) {
|
|
427
|
+
conditions.push("status = ?");
|
|
428
|
+
params.push(opts.status);
|
|
429
|
+
}
|
|
430
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
431
|
+
const countRow = this.db.prepare(`SELECT COUNT(*) as c FROM tasks ${whereClause}`).get(...params);
|
|
432
|
+
const total = countRow.c;
|
|
433
|
+
const limit = opts.limit ?? 50;
|
|
434
|
+
const offset = opts.offset ?? 0;
|
|
435
|
+
const rows = this.db.prepare(`SELECT * FROM tasks ${whereClause} ORDER BY started_at DESC LIMIT ? OFFSET ?`).all(...params, limit, offset);
|
|
436
|
+
return { tasks: rows.map(rowToTask), total };
|
|
437
|
+
}
|
|
438
|
+
countChunksByTask(taskId) {
|
|
439
|
+
const row = this.db.prepare("SELECT COUNT(*) as c FROM chunks WHERE task_id = ?").get(taskId);
|
|
440
|
+
return row.c;
|
|
441
|
+
}
|
|
442
|
+
setChunkTaskId(chunkId, taskId) {
|
|
443
|
+
this.db.prepare("UPDATE chunks SET task_id = ?, updated_at = ? WHERE id = ?").run(taskId, Date.now(), chunkId);
|
|
444
|
+
}
|
|
445
|
+
getUnassignedChunks(sessionKey) {
|
|
446
|
+
const rows = this.db.prepare("SELECT * FROM chunks WHERE session_key = ? AND task_id IS NULL ORDER BY created_at, seq").all(sessionKey);
|
|
447
|
+
return rows.map(rowToChunk);
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Check if a chunk with the same (session_key, role, content_hash) already exists.
|
|
451
|
+
* Uses indexed content_hash for O(1) lookup to prevent duplicate ingestion
|
|
452
|
+
* when agent_end sends the full conversation history every turn.
|
|
453
|
+
*/
|
|
454
|
+
chunkExistsByContent(sessionKey, role, content) {
|
|
455
|
+
const hash = contentHash(content);
|
|
456
|
+
const row = this.db.prepare("SELECT 1 FROM chunks WHERE session_key = ? AND role = ? AND content_hash = ? LIMIT 1").get(sessionKey, role, hash);
|
|
457
|
+
return !!row;
|
|
232
458
|
}
|
|
233
459
|
// ─── Util ───
|
|
234
460
|
getRecentChunkIds(limit) {
|
|
235
461
|
const rows = this.db.prepare("SELECT id FROM chunks ORDER BY created_at DESC LIMIT ?").all(limit);
|
|
236
462
|
return rows.map((r) => r.id);
|
|
237
463
|
}
|
|
464
|
+
countChunks() {
|
|
465
|
+
const row = this.db.prepare("SELECT COUNT(*) AS cnt FROM chunks").get();
|
|
466
|
+
return row.cnt;
|
|
467
|
+
}
|
|
238
468
|
close() {
|
|
239
469
|
this.db.close();
|
|
240
470
|
}
|
|
@@ -267,8 +497,24 @@ function rowToChunk(row) {
|
|
|
267
497
|
kind: row.kind,
|
|
268
498
|
summary: row.summary,
|
|
269
499
|
embedding: null,
|
|
500
|
+
taskId: row.task_id,
|
|
270
501
|
createdAt: row.created_at,
|
|
271
502
|
updatedAt: row.updated_at,
|
|
272
503
|
};
|
|
273
504
|
}
|
|
505
|
+
function rowToTask(row) {
|
|
506
|
+
return {
|
|
507
|
+
id: row.id,
|
|
508
|
+
sessionKey: row.session_key,
|
|
509
|
+
title: row.title,
|
|
510
|
+
summary: row.summary,
|
|
511
|
+
status: row.status,
|
|
512
|
+
startedAt: row.started_at,
|
|
513
|
+
endedAt: row.ended_at,
|
|
514
|
+
updatedAt: row.updated_at,
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function contentHash(content) {
|
|
518
|
+
return (0, crypto_1.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
519
|
+
}
|
|
274
520
|
//# sourceMappingURL=sqlite.js.map
|