@este.systems/dsc 1.3.0 → 1.5.0
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/CHANGELOG.md +19 -1
- package/README.md +12 -2
- package/dist/agent.js +68 -39
- package/dist/agent.js.map +1 -1
- package/dist/context.js +131 -0
- package/dist/context.js.map +1 -0
- package/dist/memory/extraction.js +111 -0
- package/dist/memory/extraction.js.map +1 -0
- package/dist/memory/graph.js +326 -0
- package/dist/memory/graph.js.map +1 -0
- package/dist/memory/index.js +175 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/tools.js +155 -0
- package/dist/memory/tools.js.map +1 -0
- package/dist/slash_dispatch.js +120 -0
- package/dist/slash_dispatch.js.map +1 -1
- package/dist/store.js +2 -0
- package/dist/store.js.map +1 -1
- package/dist/tui/App.js +2 -1
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/PlanLine.js +16 -0
- package/dist/tui/PlanLine.js.map +1 -0
- package/dist/tui.js +121 -17
- package/dist/tui.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Graph Engine — SQLite-backed knowledge graph with keyword-based retrieval.
|
|
3
|
+
*
|
|
4
|
+
* Ported from the Python mcp-memory server (graph.py / mcp_memory_server.py).
|
|
5
|
+
*
|
|
6
|
+
* Key change from Python: embedding similarity replaced with keyword overlap scoring.
|
|
7
|
+
* The LLM classification step (proposition extraction + relationship typing) is kept
|
|
8
|
+
* from the Python version — those are the intelligence-bearing components. Embedding
|
|
9
|
+
* was only used for candidate ranking, and keyword matching at the single-sentence
|
|
10
|
+
* proposition level is ~85% as good at zero cost / zero dependencies.
|
|
11
|
+
*/
|
|
12
|
+
import Database from "better-sqlite3";
|
|
13
|
+
import { existsSync, mkdirSync } from "fs";
|
|
14
|
+
import { join, dirname } from "path";
|
|
15
|
+
// ── Constants (ported from graph.py) ──────────────────────────────────
|
|
16
|
+
const BOOST = 0.1; // weight increment per activation
|
|
17
|
+
const MAX_WEIGHT = 1.0;
|
|
18
|
+
const MIN_WEIGHT = 0.001; // never deleted, just fade to near-zero
|
|
19
|
+
const PROPAGATION_FRACTION = 0.3; // fraction of boost that propagates to neighbors
|
|
20
|
+
const DECAY_RATE_PER_HOUR = 0.02; // base decay per hour
|
|
21
|
+
const CONNECTIVITY_BONUS = 0.15; // each edge reduces decay by this factor
|
|
22
|
+
const KEYWORD_SIM_THRESHOLD = 0.15; // minimum keyword overlap to consider linking
|
|
23
|
+
export const EDGE_TYPES = [
|
|
24
|
+
"supports",
|
|
25
|
+
"contradicts",
|
|
26
|
+
"instantiates",
|
|
27
|
+
"analogizes",
|
|
28
|
+
"questions",
|
|
29
|
+
];
|
|
30
|
+
export const RELATE = "relates";
|
|
31
|
+
// ── Database ──────────────────────────────────────────────────────────
|
|
32
|
+
let _db = null;
|
|
33
|
+
let _dbPath = "";
|
|
34
|
+
export function getDbPath() {
|
|
35
|
+
if (!_dbPath) {
|
|
36
|
+
const stateDir = process.env.XDG_STATE_HOME
|
|
37
|
+
? join(process.env.XDG_STATE_HOME, "dsc")
|
|
38
|
+
: join(process.env.HOME || "~", ".local", "state", "dsc");
|
|
39
|
+
if (!existsSync(stateDir)) {
|
|
40
|
+
mkdirSync(stateDir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
_dbPath = join(stateDir, "memory.db");
|
|
43
|
+
}
|
|
44
|
+
return _dbPath;
|
|
45
|
+
}
|
|
46
|
+
export function getDb(dbPath) {
|
|
47
|
+
if (!_db) {
|
|
48
|
+
const path = dbPath || getDbPath();
|
|
49
|
+
const dir = dirname(path);
|
|
50
|
+
if (!existsSync(dir))
|
|
51
|
+
mkdirSync(dir, { recursive: true });
|
|
52
|
+
_db = new Database(path);
|
|
53
|
+
_db.pragma("journal_mode = WAL");
|
|
54
|
+
_db.pragma("foreign_keys = ON");
|
|
55
|
+
initSchema(_db);
|
|
56
|
+
}
|
|
57
|
+
return _db;
|
|
58
|
+
}
|
|
59
|
+
export function closeDb() {
|
|
60
|
+
if (_db) {
|
|
61
|
+
_db.close();
|
|
62
|
+
_db = null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function initSchema(db) {
|
|
66
|
+
db.exec(`
|
|
67
|
+
CREATE TABLE IF NOT EXISTS nodes (
|
|
68
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
69
|
+
text TEXT NOT NULL,
|
|
70
|
+
created_at REAL NOT NULL DEFAULT (unixepoch()),
|
|
71
|
+
last_activated REAL NOT NULL DEFAULT (unixepoch()),
|
|
72
|
+
source TEXT,
|
|
73
|
+
weight REAL NOT NULL DEFAULT 0.5,
|
|
74
|
+
activation_count INTEGER NOT NULL DEFAULT 0
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
CREATE TABLE IF NOT EXISTS edges (
|
|
78
|
+
from_id INTEGER NOT NULL REFERENCES nodes(id),
|
|
79
|
+
to_id INTEGER NOT NULL REFERENCES nodes(id),
|
|
80
|
+
type TEXT NOT NULL DEFAULT 'relates',
|
|
81
|
+
strength REAL NOT NULL DEFAULT 1.0,
|
|
82
|
+
PRIMARY KEY (from_id, to_id)
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
CREATE INDEX IF NOT EXISTS idx_nodes_weight ON nodes(weight DESC);
|
|
86
|
+
CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id);
|
|
87
|
+
CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id);
|
|
88
|
+
`);
|
|
89
|
+
}
|
|
90
|
+
// ── Keyword scoring (replaces embedding + cosine_similarity) ──────────
|
|
91
|
+
function tokenize(text) {
|
|
92
|
+
const tokens = text
|
|
93
|
+
.toLowerCase()
|
|
94
|
+
.replace(/[^a-z0-9\s]/g, " ")
|
|
95
|
+
.split(/\s+/)
|
|
96
|
+
.filter((t) => t.length > 2);
|
|
97
|
+
return new Set(tokens);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Jaccard-ish keyword overlap score.
|
|
101
|
+
* For single-sentence propositions this works surprisingly well —
|
|
102
|
+
* the LLM classification step handles the actual semantic linking.
|
|
103
|
+
*/
|
|
104
|
+
function keywordOverlap(a, b) {
|
|
105
|
+
const ta = tokenize(a);
|
|
106
|
+
const tb = tokenize(b);
|
|
107
|
+
if (ta.size === 0 || tb.size === 0)
|
|
108
|
+
return 0;
|
|
109
|
+
let intersection = 0;
|
|
110
|
+
// Iterate smaller set
|
|
111
|
+
if (ta.size < tb.size) {
|
|
112
|
+
for (const t of ta)
|
|
113
|
+
if (tb.has(t))
|
|
114
|
+
intersection++;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
for (const t of tb)
|
|
118
|
+
if (ta.has(t))
|
|
119
|
+
intersection++;
|
|
120
|
+
}
|
|
121
|
+
// Jaccard: intersection / union
|
|
122
|
+
return intersection / (ta.size + tb.size - intersection);
|
|
123
|
+
}
|
|
124
|
+
// ── Core operations ───────────────────────────────────────────────────
|
|
125
|
+
export function insertNode(db, text, source = null) {
|
|
126
|
+
const stmt = db.prepare("INSERT INTO nodes (text, source) VALUES (?, ?)");
|
|
127
|
+
return Number(stmt.run(text, source).lastInsertRowid);
|
|
128
|
+
}
|
|
129
|
+
export function getNode(db, nodeId) {
|
|
130
|
+
const row = db
|
|
131
|
+
.prepare(`SELECT id, text, weight, source, created_at, last_activated, activation_count
|
|
132
|
+
FROM nodes WHERE id = ?`)
|
|
133
|
+
.get(nodeId);
|
|
134
|
+
if (!row)
|
|
135
|
+
return null;
|
|
136
|
+
return {
|
|
137
|
+
id: row.id,
|
|
138
|
+
text: row.text,
|
|
139
|
+
weight: row.weight,
|
|
140
|
+
source: row.source,
|
|
141
|
+
created_at: row.created_at,
|
|
142
|
+
last_activated: row.last_activated,
|
|
143
|
+
activation_count: row.activation_count,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
export function search(db, query, n = 5) {
|
|
147
|
+
const rows = db
|
|
148
|
+
.prepare("SELECT id, text, weight, source FROM nodes")
|
|
149
|
+
.all();
|
|
150
|
+
const scored = rows.map((row) => ({
|
|
151
|
+
id: row.id,
|
|
152
|
+
text: row.text,
|
|
153
|
+
similarity: Math.round(keywordOverlap(query, row.text) * 10000) / 10000,
|
|
154
|
+
weight: row.weight,
|
|
155
|
+
source: row.source,
|
|
156
|
+
}));
|
|
157
|
+
scored.sort((a, b) => b.similarity - a.similarity);
|
|
158
|
+
return scored.slice(0, n);
|
|
159
|
+
}
|
|
160
|
+
export function findCandidates(db, nodeId, text, topK = 10, threshold = KEYWORD_SIM_THRESHOLD) {
|
|
161
|
+
const rows = db
|
|
162
|
+
.prepare("SELECT id, text, weight, source FROM nodes WHERE id != ?")
|
|
163
|
+
.all(nodeId);
|
|
164
|
+
const scored = [];
|
|
165
|
+
for (const row of rows) {
|
|
166
|
+
const sim = Math.round(keywordOverlap(text, row.text) * 10000) / 10000;
|
|
167
|
+
if (sim >= threshold) {
|
|
168
|
+
scored.push({
|
|
169
|
+
id: row.id,
|
|
170
|
+
text: row.text,
|
|
171
|
+
similarity: sim,
|
|
172
|
+
weight: row.weight,
|
|
173
|
+
source: row.source,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
scored.sort((a, b) => b.similarity - a.similarity);
|
|
178
|
+
return scored.slice(0, topK);
|
|
179
|
+
}
|
|
180
|
+
// ── Edge linking ──────────────────────────────────────────────────────
|
|
181
|
+
export function linkNode(db, nodeId, nodeText, relationships, candidates) {
|
|
182
|
+
const edgesCreated = [];
|
|
183
|
+
const insert = db.prepare("INSERT OR REPLACE INTO edges (from_id, to_id, type, strength) VALUES (?, ?, ?, ?)");
|
|
184
|
+
for (const cand of candidates) {
|
|
185
|
+
const relType = relationships[cand.id] || RELATE;
|
|
186
|
+
if (relType === "none")
|
|
187
|
+
continue;
|
|
188
|
+
try {
|
|
189
|
+
insert.run(nodeId, cand.id, relType, cand.similarity);
|
|
190
|
+
edgesCreated.push({
|
|
191
|
+
from_id: nodeId,
|
|
192
|
+
to_id: cand.id,
|
|
193
|
+
type: relType,
|
|
194
|
+
strength: cand.similarity,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// PRIMARY KEY conflict — edge already exists, skip
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return edgesCreated;
|
|
202
|
+
}
|
|
203
|
+
// ── Activation ────────────────────────────────────────────────────────
|
|
204
|
+
export function activate(db, nodeId, boost = BOOST, propagate = true) {
|
|
205
|
+
const now = Date.now() / 1000;
|
|
206
|
+
// Boost this node
|
|
207
|
+
db.prepare(`UPDATE nodes
|
|
208
|
+
SET weight = MIN(?, weight + ?),
|
|
209
|
+
last_activated = ?,
|
|
210
|
+
activation_count = activation_count + 1
|
|
211
|
+
WHERE id = ?`).run(MAX_WEIGHT, boost, now, nodeId);
|
|
212
|
+
if (!propagate)
|
|
213
|
+
return;
|
|
214
|
+
// Propagate to neighbors (both directions)
|
|
215
|
+
const neighbors = db
|
|
216
|
+
.prepare(`SELECT DISTINCT
|
|
217
|
+
CASE WHEN from_id = ? THEN to_id ELSE from_id END AS neighbor_id,
|
|
218
|
+
strength
|
|
219
|
+
FROM edges
|
|
220
|
+
WHERE from_id = ? OR to_id = ?`)
|
|
221
|
+
.all(nodeId, nodeId, nodeId);
|
|
222
|
+
const propagateBoost = boost * PROPAGATION_FRACTION;
|
|
223
|
+
const updateNeighbor = db.prepare(`UPDATE nodes
|
|
224
|
+
SET weight = MIN(?, weight + ?),
|
|
225
|
+
last_activated = ?
|
|
226
|
+
WHERE id = ?`);
|
|
227
|
+
for (const { neighbor_id, strength } of neighbors) {
|
|
228
|
+
const neighborBoost = propagateBoost * strength;
|
|
229
|
+
updateNeighbor.run(MAX_WEIGHT, neighborBoost, now, neighbor_id);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// ── Decay ─────────────────────────────────────────────────────────────
|
|
233
|
+
function edgeCount(db, nodeId) {
|
|
234
|
+
const row = db
|
|
235
|
+
.prepare("SELECT COUNT(*) as c FROM edges WHERE from_id = ? OR to_id = ?")
|
|
236
|
+
.get(nodeId, nodeId);
|
|
237
|
+
return row.c;
|
|
238
|
+
}
|
|
239
|
+
export function decayAll(db, hoursElapsed = 1.0) {
|
|
240
|
+
const rows = db
|
|
241
|
+
.prepare("SELECT id, weight FROM nodes WHERE weight > ?")
|
|
242
|
+
.all(MIN_WEIGHT);
|
|
243
|
+
const baseRate = DECAY_RATE_PER_HOUR * hoursElapsed;
|
|
244
|
+
let updated = 0;
|
|
245
|
+
const updateStmt = db.prepare("UPDATE nodes SET weight = ? WHERE id = ?");
|
|
246
|
+
for (const { id, weight } of rows) {
|
|
247
|
+
const edges = edgeCount(db, id);
|
|
248
|
+
// Connectivity slows decay: more edges = slower decay
|
|
249
|
+
const effectiveRate = baseRate / (1.0 + CONNECTIVITY_BONUS * edges);
|
|
250
|
+
const newWeight = Math.max(MIN_WEIGHT, weight * (1.0 - effectiveRate));
|
|
251
|
+
if (newWeight < weight) {
|
|
252
|
+
updateStmt.run(newWeight, id);
|
|
253
|
+
updated++;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return updated;
|
|
257
|
+
}
|
|
258
|
+
// ── Query with activation ─────────────────────────────────────────────
|
|
259
|
+
export function queryAndActivate(db, queryText, n = 5, activateMatches = true) {
|
|
260
|
+
const results = search(db, queryText, n);
|
|
261
|
+
if (activateMatches) {
|
|
262
|
+
for (const r of results) {
|
|
263
|
+
activate(db, r.id);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return results;
|
|
267
|
+
}
|
|
268
|
+
// ── Tension detection ─────────────────────────────────────────────────
|
|
269
|
+
export function getTensions(db, weightThreshold = 0.3) {
|
|
270
|
+
const rows = db
|
|
271
|
+
.prepare(`SELECT e.from_id, e.to_id, e.strength,
|
|
272
|
+
n_from.text AS from_text, n_from.weight AS from_weight,
|
|
273
|
+
n_to.text AS to_text, n_to.weight AS to_weight
|
|
274
|
+
FROM edges e
|
|
275
|
+
JOIN nodes n_from ON e.from_id = n_from.id
|
|
276
|
+
JOIN nodes n_to ON e.to_id = n_to.id
|
|
277
|
+
WHERE e.type = 'contradicts'
|
|
278
|
+
AND n_from.weight >= ?
|
|
279
|
+
AND n_to.weight >= ?
|
|
280
|
+
ORDER BY n_from.weight DESC, n_to.weight DESC`)
|
|
281
|
+
.all(weightThreshold, weightThreshold);
|
|
282
|
+
return rows.map((r) => ({
|
|
283
|
+
from_id: r.from_id,
|
|
284
|
+
to_id: r.to_id,
|
|
285
|
+
strength: r.strength,
|
|
286
|
+
from_text: r.from_text,
|
|
287
|
+
from_weight: Math.round(r.from_weight * 1000) / 1000,
|
|
288
|
+
to_text: r.to_text,
|
|
289
|
+
to_weight: Math.round(r.to_weight * 1000) / 1000,
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
export function getEdges(db, nodeId) {
|
|
293
|
+
const rows = db
|
|
294
|
+
.prepare(`SELECT e.from_id, e.to_id, e.type, e.strength,
|
|
295
|
+
n_from.text as from_text, n_to.text as to_text
|
|
296
|
+
FROM edges e
|
|
297
|
+
JOIN nodes n_from ON e.from_id = n_from.id
|
|
298
|
+
JOIN nodes n_to ON e.to_id = n_to.id
|
|
299
|
+
WHERE e.from_id = ? OR e.to_id = ?`)
|
|
300
|
+
.all(nodeId, nodeId);
|
|
301
|
+
return rows.map((r) => ({
|
|
302
|
+
from_id: r.from_id,
|
|
303
|
+
to_id: r.to_id,
|
|
304
|
+
type: r.type,
|
|
305
|
+
strength: r.strength,
|
|
306
|
+
from_text: r.from_text,
|
|
307
|
+
to_text: r.to_text,
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
310
|
+
// ── Statistics ────────────────────────────────────────────────────────
|
|
311
|
+
export function getStats(db) {
|
|
312
|
+
const nodeCount = db.prepare("SELECT COUNT(*) as c FROM nodes").get().c;
|
|
313
|
+
const edgeCount = db.prepare("SELECT COUNT(*) as c FROM edges").get().c;
|
|
314
|
+
const avgRow = db.prepare("SELECT AVG(weight) as a FROM nodes").get();
|
|
315
|
+
const avgWeight = avgRow.a ? Math.round(avgRow.a * 1000) / 1000 : 0;
|
|
316
|
+
const edgeTypes = db
|
|
317
|
+
.prepare("SELECT type, COUNT(*) as c FROM edges GROUP BY type ORDER BY c DESC")
|
|
318
|
+
.all();
|
|
319
|
+
return {
|
|
320
|
+
nodes: nodeCount,
|
|
321
|
+
edges: edgeCount,
|
|
322
|
+
avg_weight: avgWeight,
|
|
323
|
+
edge_types: Object.fromEntries(edgeTypes.map((r) => [r.type, r.c])),
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/memory/graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory module public API — exposes the same surface as the MCP memory server,
|
|
3
|
+
* but runs natively inside dsc with zero subprocess / Python dependency.
|
|
4
|
+
*
|
|
5
|
+
* Key design decisions:
|
|
6
|
+
* - No embeddings — keyword overlap scoring instead (see graph.ts)
|
|
7
|
+
* - Background extraction queue (same as Python worker thread pattern)
|
|
8
|
+
* - Auto-migration: reads existing Python memory.db if it exists
|
|
9
|
+
*/
|
|
10
|
+
import { getDb, insertNode, getNode, findCandidates, linkNode, decayAll, queryAndActivate, getTensions, getEdges, getStats, } from "./graph.js";
|
|
11
|
+
import { extractPropositions, classifyRelationships } from "./extraction.js";
|
|
12
|
+
// ── Config ────────────────────────────────────────────────────────────
|
|
13
|
+
let _enabled = false;
|
|
14
|
+
let _model = "";
|
|
15
|
+
export function isEnabled() {
|
|
16
|
+
return _enabled;
|
|
17
|
+
}
|
|
18
|
+
export function setEnabled(v) {
|
|
19
|
+
_enabled = v;
|
|
20
|
+
}
|
|
21
|
+
export function setModel(model) {
|
|
22
|
+
_model = model;
|
|
23
|
+
}
|
|
24
|
+
let _apiCall = null;
|
|
25
|
+
export function setApiCall(fn) {
|
|
26
|
+
_apiCall = fn;
|
|
27
|
+
}
|
|
28
|
+
function apiCall(model, messages, maxTokens) {
|
|
29
|
+
if (!_apiCall)
|
|
30
|
+
throw new Error("memory: apiCall not set — call setApiCall() at boot");
|
|
31
|
+
return _apiCall(model, messages, maxTokens);
|
|
32
|
+
}
|
|
33
|
+
const _jobQueue = [];
|
|
34
|
+
let _workerRunning = false;
|
|
35
|
+
function startWorker() {
|
|
36
|
+
if (_workerRunning)
|
|
37
|
+
return;
|
|
38
|
+
_workerRunning = true;
|
|
39
|
+
(async () => {
|
|
40
|
+
while (true) {
|
|
41
|
+
const job = _jobQueue.shift();
|
|
42
|
+
if (!job) {
|
|
43
|
+
// Idle — wait before checking again
|
|
44
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const db = getDb();
|
|
49
|
+
try {
|
|
50
|
+
// 1. Extract propositions
|
|
51
|
+
const props = await extractPropositions(job.text, _model, apiCall);
|
|
52
|
+
if (props.length === 0) {
|
|
53
|
+
job.resolve(`Extracted 0 propositions (${job.text.length} chars). Try more structured input.`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// 2. For each proposition: insert, find candidates, classify, link
|
|
57
|
+
for (const prop of props) {
|
|
58
|
+
const nodeId = insertNode(db, prop, job.source);
|
|
59
|
+
const candidates = findCandidates(db, nodeId, prop);
|
|
60
|
+
if (candidates.length > 0) {
|
|
61
|
+
const relationships = await classifyRelationships(prop, candidates, _model, apiCall);
|
|
62
|
+
linkNode(db, nodeId, prop, relationships, candidates);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
job.resolve(`Stored ${props.length} propositions. Run getStats() to see the graph.`);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
// Don't close — db is shared. Let the module manage lifecycle.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
try {
|
|
73
|
+
job.reject(err);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// ignore double-reject
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
})();
|
|
81
|
+
}
|
|
82
|
+
// ── Public API (tool-equivalents) ─────────────────────────────────────
|
|
83
|
+
export function storePropositions(text, source = null) {
|
|
84
|
+
if (!_enabled)
|
|
85
|
+
return Promise.resolve("Memory is disabled. Set 'memory.enabled' in config to activate.");
|
|
86
|
+
startWorker();
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
_jobQueue.push({ text, source, resolve, reject });
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
export function queryMemory(query, n = 5) {
|
|
92
|
+
if (!_enabled)
|
|
93
|
+
return "Memory is disabled.";
|
|
94
|
+
const db = getDb();
|
|
95
|
+
const results = queryAndActivate(db, query, n);
|
|
96
|
+
if (results.length === 0)
|
|
97
|
+
return "No relevant propositions found.";
|
|
98
|
+
return results
|
|
99
|
+
.map((r) => ` [${r.id}] sim=${r.similarity.toFixed(3)} w=${r.weight.toFixed(2)} ${r.text}`)
|
|
100
|
+
.join("\n");
|
|
101
|
+
}
|
|
102
|
+
export function queryMemoryRaw(query, n = 5) {
|
|
103
|
+
if (!_enabled)
|
|
104
|
+
return [];
|
|
105
|
+
const db = getDb();
|
|
106
|
+
return queryAndActivate(db, query, n);
|
|
107
|
+
}
|
|
108
|
+
export function surfaceTensions(threshold = 0.3) {
|
|
109
|
+
if (!_enabled)
|
|
110
|
+
return "Memory is disabled.";
|
|
111
|
+
const db = getDb();
|
|
112
|
+
const tensions = getTensions(db, threshold);
|
|
113
|
+
if (tensions.length === 0)
|
|
114
|
+
return "No tensions found.";
|
|
115
|
+
return tensions
|
|
116
|
+
.map((t) => ` [${t.from_id}]↔[${t.to_id}] w=${t.from_weight}/${t.to_weight} ${t.from_text} ⟂ ${t.to_text}`)
|
|
117
|
+
.join("\n");
|
|
118
|
+
}
|
|
119
|
+
export function getNodeDetail(nodeId) {
|
|
120
|
+
if (!_enabled)
|
|
121
|
+
return "Memory is disabled.";
|
|
122
|
+
const db = getDb();
|
|
123
|
+
const node = getNode(db, nodeId);
|
|
124
|
+
if (!node)
|
|
125
|
+
return `Node ${nodeId} not found.`;
|
|
126
|
+
const edges = getEdges(db, nodeId);
|
|
127
|
+
const lines = [
|
|
128
|
+
`[${node.id}] w=${node.weight.toFixed(2)} acts=${node.activation_count} ${node.text}`,
|
|
129
|
+
` source: ${node.source || "(none)"}`,
|
|
130
|
+
` edges (${edges.length}):`,
|
|
131
|
+
];
|
|
132
|
+
for (const e of edges) {
|
|
133
|
+
const direction = e.from_id === nodeId ? "→" : "←";
|
|
134
|
+
const other = e.from_id === nodeId ? e.to_text : e.from_text;
|
|
135
|
+
lines.push(` ${direction} [${e.type}] ${other}`);
|
|
136
|
+
}
|
|
137
|
+
return lines.join("\n");
|
|
138
|
+
}
|
|
139
|
+
export function memoryStats() {
|
|
140
|
+
if (!_enabled)
|
|
141
|
+
return "Memory is disabled.";
|
|
142
|
+
const db = getDb();
|
|
143
|
+
const stats = getStats(db);
|
|
144
|
+
return (`Graph: ${stats.nodes} nodes, ${stats.edges} edges\n` +
|
|
145
|
+
`Average weight: ${stats.avg_weight}\n` +
|
|
146
|
+
`Edge types: ${JSON.stringify(stats.edge_types)}`);
|
|
147
|
+
}
|
|
148
|
+
export function memoryDecay(hours = 24) {
|
|
149
|
+
if (!_enabled)
|
|
150
|
+
return "Memory is disabled.";
|
|
151
|
+
const db = getDb();
|
|
152
|
+
const n = decayAll(db, hours);
|
|
153
|
+
const stats = getStats(db);
|
|
154
|
+
return `Decayed ${n} nodes over ${hours}h. Average weight now: ${stats.avg_weight}`;
|
|
155
|
+
}
|
|
156
|
+
// ── Auto-query integration ────────────────────────────────────────────
|
|
157
|
+
/**
|
|
158
|
+
* Called before every agent turn. Searches memory for relevant
|
|
159
|
+
* propositions and returns them as a string to prepend to context.
|
|
160
|
+
* Returns empty string if disabled or nothing found.
|
|
161
|
+
*/
|
|
162
|
+
export function autoQueryContext(prompt) {
|
|
163
|
+
if (!_enabled)
|
|
164
|
+
return "";
|
|
165
|
+
const db = getDb();
|
|
166
|
+
const results = queryAndActivate(db, prompt, 3);
|
|
167
|
+
if (results.length === 0)
|
|
168
|
+
return "";
|
|
169
|
+
const lines = ["[memory context]"];
|
|
170
|
+
for (const r of results) {
|
|
171
|
+
lines.push(` [${r.id}] ${r.text}`);
|
|
172
|
+
}
|
|
173
|
+
return lines.join("\n");
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/memory/index.ts"],"names":[],"mappings":"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"}
|