@memory-river/core 0.2.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/LICENSE +201 -0
- package/README.md +222 -0
- package/README.zh-TW.md +186 -0
- package/dist/api.d.ts +100 -0
- package/dist/api.js +156 -0
- package/dist/cognition/causal-attribution.d.ts +36 -0
- package/dist/cognition/causal-attribution.js +239 -0
- package/dist/cognition/causal-engine.d.ts +105 -0
- package/dist/cognition/causal-engine.js +150 -0
- package/dist/cognition/conflict-detector.d.ts +39 -0
- package/dist/cognition/conflict-detector.js +193 -0
- package/dist/cognition/global-working-memory.d.ts +53 -0
- package/dist/cognition/global-working-memory.js +211 -0
- package/dist/cognition/hooks-engine.d.ts +99 -0
- package/dist/cognition/hooks-engine.js +672 -0
- package/dist/cognition/ralph-core.d.ts +28 -0
- package/dist/cognition/ralph-core.js +104 -0
- package/dist/distill/concentrator-adapter.d.ts +167 -0
- package/dist/distill/concentrator-adapter.js +1876 -0
- package/dist/engine.d.ts +402 -0
- package/dist/engine.js +2254 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/lifecycle/cleanup-engine.d.ts +80 -0
- package/dist/lifecycle/cleanup-engine.js +162 -0
- package/dist/lifecycle/cleanup-state.d.ts +34 -0
- package/dist/lifecycle/cleanup-state.js +50 -0
- package/dist/lifecycle/night-consolidation.d.ts +102 -0
- package/dist/lifecycle/night-consolidation.js +640 -0
- package/dist/lifecycle/night-recovery.d.ts +40 -0
- package/dist/lifecycle/night-recovery.js +107 -0
- package/dist/paths.d.ts +17 -0
- package/dist/paths.js +16 -0
- package/dist/pipeline/capsule-bridge.d.ts +35 -0
- package/dist/pipeline/capsule-bridge.js +86 -0
- package/dist/pipeline/compact-request.d.ts +30 -0
- package/dist/pipeline/compact-request.js +66 -0
- package/dist/pipeline/inbox-watcher.d.ts +112 -0
- package/dist/pipeline/inbox-watcher.js +1039 -0
- package/dist/ports.d.ts +29 -0
- package/dist/ports.js +1 -0
- package/dist/providers/embedder-v5.d.ts +46 -0
- package/dist/providers/embedder-v5.js +155 -0
- package/dist/providers/ollama-embedding.d.ts +25 -0
- package/dist/providers/ollama-embedding.js +166 -0
- package/dist/retrieval/abstractness-judge.d.ts +14 -0
- package/dist/retrieval/abstractness-judge.js +87 -0
- package/dist/retrieval/coverage-selection.d.ts +3 -0
- package/dist/retrieval/coverage-selection.js +53 -0
- package/dist/retrieval/cross-encoder-gate.d.ts +40 -0
- package/dist/retrieval/cross-encoder-gate.js +239 -0
- package/dist/retrieval/retriever-v4.d.ts +78 -0
- package/dist/retrieval/retriever-v4.js +1200 -0
- package/dist/skills/validate.d.ts +6 -0
- package/dist/skills/validate.js +69 -0
- package/dist/storage.d.ts +19 -0
- package/dist/storage.js +54 -0
- package/dist/store/aux-table-maintenance.d.ts +5 -0
- package/dist/store/aux-table-maintenance.js +64 -0
- package/dist/store/graph-enumerator.d.ts +21 -0
- package/dist/store/graph-enumerator.js +185 -0
- package/dist/store/graph-store.d.ts +107 -0
- package/dist/store/graph-store.js +478 -0
- package/dist/store/status-manager.d.ts +44 -0
- package/dist/store/status-manager.js +235 -0
- package/dist/store/store-v4.d.ts +339 -0
- package/dist/store/store-v4.js +2871 -0
- package/dist/transcript/keyword-search.d.ts +9 -0
- package/dist/transcript/keyword-search.js +67 -0
- package/dist/transcript/rehydrate-keyword.d.ts +6 -0
- package/dist/transcript/rehydrate-keyword.js +29 -0
- package/dist/transcript/rehydrate.d.ts +33 -0
- package/dist/transcript/rehydrate.js +285 -0
- package/dist/transcript/transcript-archive.d.ts +46 -0
- package/dist/transcript/transcript-archive.js +516 -0
- package/dist/types.d.ts +409 -0
- package/dist/types.js +104 -0
- package/dist/util/bounded-map.d.ts +1 -0
- package/dist/util/bounded-map.js +8 -0
- package/dist/util/rate-limiter.d.ts +12 -0
- package/dist/util/rate-limiter.js +54 -0
- package/dist/util/session-identity.d.ts +65 -0
- package/dist/util/session-identity.js +227 -0
- package/dist/util/util-hash.d.ts +1 -0
- package/dist/util/util-hash.js +4 -0
- package/package.json +59 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StatusManager — 記憶狀態單一所有人(P0-3)
|
|
3
|
+
*
|
|
4
|
+
* 所有 status 變更(active / superseded / deprecated / archived / trashed)必須經過此模組。
|
|
5
|
+
* 內部同時更新 metadata.status + row.status(雙欄位同步),並寫入 audit log。
|
|
6
|
+
*
|
|
7
|
+
* 設計原則:
|
|
8
|
+
* - 純 class,只依賴 MemoryStore
|
|
9
|
+
* - changeStatus() 走 store.update()(自動進 WAL exactly-once 保護)
|
|
10
|
+
* - 所有成功/失敗都記 audit row
|
|
11
|
+
* - changeStatusBatch() 逐筆 try/catch,單筆失敗不中斷整 batch
|
|
12
|
+
*/
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
export class StatusManager {
|
|
15
|
+
store;
|
|
16
|
+
constructor(store) {
|
|
17
|
+
this.store = store;
|
|
18
|
+
}
|
|
19
|
+
// ========================================================================
|
|
20
|
+
// 主寫入 API — 所有 status 變更走這
|
|
21
|
+
// ========================================================================
|
|
22
|
+
async changeStatus(req) {
|
|
23
|
+
const auditRowId = randomUUID();
|
|
24
|
+
let fromStatus = null;
|
|
25
|
+
try {
|
|
26
|
+
// 1. 取出當前記憶
|
|
27
|
+
const entry = await this.store.getById(req.memoryId, true);
|
|
28
|
+
if (!entry) {
|
|
29
|
+
// 記憶不存在 — 記 audit(失敗)並回傳
|
|
30
|
+
await this.safeRecordAudit({
|
|
31
|
+
memoryId: req.memoryId,
|
|
32
|
+
fromStatus: null,
|
|
33
|
+
toStatus: req.toStatus,
|
|
34
|
+
reason: req.reason,
|
|
35
|
+
source: req.source,
|
|
36
|
+
supersededBy: req.supersededBy ?? null,
|
|
37
|
+
meta: req.meta ? JSON.stringify(req.meta) : null,
|
|
38
|
+
canonicalKey: null,
|
|
39
|
+
partial: false,
|
|
40
|
+
}, auditRowId);
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
memoryId: req.memoryId,
|
|
44
|
+
fromStatus: null,
|
|
45
|
+
toStatus: req.toStatus,
|
|
46
|
+
auditRowId,
|
|
47
|
+
error: 'memory_not_found',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// 2. 解析當前 metadata,取得 fromStatus
|
|
51
|
+
const meta = this.parseMetadata(entry.metadata);
|
|
52
|
+
fromStatus = meta.status ?? null;
|
|
53
|
+
// 3. 更新 metadata 欄位
|
|
54
|
+
meta.status = req.toStatus;
|
|
55
|
+
// 設置時間戳和額外欄位(保持與現有寫入者行為一致)
|
|
56
|
+
if (req.toStatus === 'superseded') {
|
|
57
|
+
meta.supersededAt = Date.now();
|
|
58
|
+
if (req.supersededBy) {
|
|
59
|
+
meta.supersededBy = req.supersededBy;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (req.toStatus === 'deprecated') {
|
|
63
|
+
meta.deprecatedAt = Date.now();
|
|
64
|
+
if (req.supersededBy) {
|
|
65
|
+
meta.supersededBy = req.supersededBy;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (req.toStatus === 'trashed') {
|
|
69
|
+
meta.trashedAt = Date.now();
|
|
70
|
+
}
|
|
71
|
+
// 合併額外 meta 資訊(如 consolidationReason)
|
|
72
|
+
if (req.meta) {
|
|
73
|
+
for (const [key, value] of Object.entries(req.meta)) {
|
|
74
|
+
meta[key] = value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// 4. 同時更新 metadata + row.status(單一 store.update() 呼叫 → 單一 WAL entry)
|
|
78
|
+
let partial = false;
|
|
79
|
+
try {
|
|
80
|
+
await this.store.update(req.memoryId, {
|
|
81
|
+
metadata: JSON.stringify(meta),
|
|
82
|
+
status: req.toStatus,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (updateErr) {
|
|
86
|
+
// row.status 補寫可能失敗(例如 LanceDB schema 不含 status column)
|
|
87
|
+
// 退回只更新 metadata 的安全路徑
|
|
88
|
+
console.warn(`[StatusManager] Dual-field update failed; falling back to metadata-only: ${updateErr.message}`);
|
|
89
|
+
try {
|
|
90
|
+
await this.store.update(req.memoryId, {
|
|
91
|
+
metadata: JSON.stringify(meta),
|
|
92
|
+
});
|
|
93
|
+
partial = true; // metadata 成功但 row.status 未寫入
|
|
94
|
+
}
|
|
95
|
+
catch (fallbackErr) {
|
|
96
|
+
// 兩條路徑都失敗 — 記 audit 並回傳錯誤
|
|
97
|
+
await this.safeRecordAudit({
|
|
98
|
+
memoryId: req.memoryId,
|
|
99
|
+
fromStatus: fromStatus,
|
|
100
|
+
toStatus: req.toStatus,
|
|
101
|
+
reason: req.reason,
|
|
102
|
+
source: req.source,
|
|
103
|
+
supersededBy: req.supersededBy ?? null,
|
|
104
|
+
meta: JSON.stringify({ error: fallbackErr.message, ...(req.meta ?? {}) }),
|
|
105
|
+
canonicalKey: null,
|
|
106
|
+
partial: false,
|
|
107
|
+
}, auditRowId);
|
|
108
|
+
return {
|
|
109
|
+
ok: false,
|
|
110
|
+
memoryId: req.memoryId,
|
|
111
|
+
fromStatus,
|
|
112
|
+
toStatus: req.toStatus,
|
|
113
|
+
auditRowId,
|
|
114
|
+
error: `update_failed: ${fallbackErr.message}`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// 5. 寫入 audit log(成功)
|
|
119
|
+
await this.safeRecordAudit({
|
|
120
|
+
memoryId: req.memoryId,
|
|
121
|
+
fromStatus: fromStatus,
|
|
122
|
+
toStatus: req.toStatus,
|
|
123
|
+
reason: req.reason,
|
|
124
|
+
source: req.source,
|
|
125
|
+
supersededBy: req.supersededBy ?? null,
|
|
126
|
+
meta: req.meta ? JSON.stringify(req.meta) : null,
|
|
127
|
+
canonicalKey: null,
|
|
128
|
+
partial,
|
|
129
|
+
}, auditRowId);
|
|
130
|
+
return {
|
|
131
|
+
ok: true,
|
|
132
|
+
memoryId: req.memoryId,
|
|
133
|
+
fromStatus,
|
|
134
|
+
toStatus: req.toStatus,
|
|
135
|
+
auditRowId,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
// 未預期錯誤 — 嘗試記 audit
|
|
140
|
+
await this.safeRecordAudit({
|
|
141
|
+
memoryId: req.memoryId,
|
|
142
|
+
fromStatus: fromStatus,
|
|
143
|
+
toStatus: req.toStatus,
|
|
144
|
+
reason: req.reason,
|
|
145
|
+
source: req.source,
|
|
146
|
+
supersededBy: req.supersededBy ?? null,
|
|
147
|
+
meta: JSON.stringify({ error: err.message, ...(req.meta ?? {}) }),
|
|
148
|
+
canonicalKey: null,
|
|
149
|
+
partial: false,
|
|
150
|
+
}, auditRowId);
|
|
151
|
+
return {
|
|
152
|
+
ok: false,
|
|
153
|
+
memoryId: req.memoryId,
|
|
154
|
+
fromStatus,
|
|
155
|
+
toStatus: req.toStatus,
|
|
156
|
+
auditRowId,
|
|
157
|
+
error: err.message,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// ========================================================================
|
|
162
|
+
// 批次 API — NightConsolidator 用
|
|
163
|
+
// ========================================================================
|
|
164
|
+
/**
|
|
165
|
+
* 逐筆呼叫 changeStatus(),單筆失敗不中斷整 batch。
|
|
166
|
+
* 每 20 筆輸出 progress log,避免凌晨 batch 卡住時無感。
|
|
167
|
+
*/
|
|
168
|
+
async changeStatusBatch(reqs) {
|
|
169
|
+
const results = [];
|
|
170
|
+
const total = reqs.length;
|
|
171
|
+
const mainReason = reqs[0]?.reason ?? 'unknown';
|
|
172
|
+
for (let i = 0; i < total; i++) {
|
|
173
|
+
try {
|
|
174
|
+
const result = await this.changeStatus(reqs[i]);
|
|
175
|
+
results.push(result);
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
// changeStatus 內部已有 try/catch,理論上不會走到這
|
|
179
|
+
// 但防禦性程式設計:記錄失敗結果,繼續下一筆
|
|
180
|
+
results.push({
|
|
181
|
+
ok: false,
|
|
182
|
+
memoryId: reqs[i].memoryId,
|
|
183
|
+
fromStatus: null,
|
|
184
|
+
toStatus: reqs[i].toStatus,
|
|
185
|
+
auditRowId: '',
|
|
186
|
+
error: `batch_unexpected: ${err.message}`,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
// 每 20 筆輸出 progress log
|
|
190
|
+
if ((i + 1) % 20 === 0 || i === total - 1) {
|
|
191
|
+
const succeeded = results.filter(r => r.ok).length;
|
|
192
|
+
const failed = results.length - succeeded;
|
|
193
|
+
console.log(`[StatusManager] batch progress: ${i + 1}/${total} (reason=${mainReason}, ok=${succeeded}, fail=${failed})`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return results;
|
|
197
|
+
}
|
|
198
|
+
// ========================================================================
|
|
199
|
+
// 查詢 audit log(觀測用)
|
|
200
|
+
// ========================================================================
|
|
201
|
+
async queryAuditLog(opts) {
|
|
202
|
+
return this.store.queryStatusAudit(opts);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 新記憶建立時,row.status 與 metadata.status 已在 store.store() 一次寫入;
|
|
206
|
+
* 這裡只補 audit log,避免再次觸發 LanceDB update metadata parser。
|
|
207
|
+
*/
|
|
208
|
+
async recordCreation(req) {
|
|
209
|
+
return this.store.recordCreationAudit(req);
|
|
210
|
+
}
|
|
211
|
+
// ========================================================================
|
|
212
|
+
// 內部工具
|
|
213
|
+
// ========================================================================
|
|
214
|
+
/**
|
|
215
|
+
* 安全寫入 audit log — 失敗只 warn,不影響主流程
|
|
216
|
+
*/
|
|
217
|
+
async safeRecordAudit(audit, id) {
|
|
218
|
+
try {
|
|
219
|
+
await this.store.recordStatusAudit({ ...audit, id });
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
console.warn(`[StatusManager] Failed to write audit log (memoryId=${audit.memoryId}): ${err.message}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
parseMetadata(metaStr) {
|
|
226
|
+
if (!metaStr)
|
|
227
|
+
return {};
|
|
228
|
+
try {
|
|
229
|
+
return typeof metaStr === 'string' ? JSON.parse(metaStr) : metaStr;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return {};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LanceDB Store - RAM + SSD Dual-Write Architecture with WAL
|
|
3
|
+
* memory-river v4
|
|
4
|
+
*
|
|
5
|
+
* 核心原則:
|
|
6
|
+
* - RAM Disk (/dev/shm) 為主要讀寫目標(極速)
|
|
7
|
+
* - SSD 為異步備份(持久化)
|
|
8
|
+
* - WAL (Write-Ahead Log) 保護 update/delete 一致性
|
|
9
|
+
* - store() WAL + RAM 同步,SSD 異步寫入
|
|
10
|
+
* - update/delete 必須 WAL 先行 → 雙寫 → WAL commit
|
|
11
|
+
* - 讀取全部走 RAM(速度優先)
|
|
12
|
+
* - crash recovery replays every WAL change at-least-once, including unacknowledged deletes
|
|
13
|
+
*/
|
|
14
|
+
import type { ConcentratorStat, MemoryEntry, MemorySearchResult, MemoryHealth, SkillCapsule, StatusAuditRow, SubsystemEffectivenessEvent, SubsystemEffectivenessQueryFilter, SubsystemEffectivenessRow, TranscriptWatermarkRow } from "../types.js";
|
|
15
|
+
export declare class SchemaViolationError extends Error {
|
|
16
|
+
readonly violations: string[];
|
|
17
|
+
constructor(message: string, violations: string[]);
|
|
18
|
+
}
|
|
19
|
+
declare const DEFAULT_HEALTH_CONFIG: {
|
|
20
|
+
initialScore: number;
|
|
21
|
+
coreCategories: string[];
|
|
22
|
+
coreImportanceThreshold: number;
|
|
23
|
+
skillDecayFactor: number;
|
|
24
|
+
};
|
|
25
|
+
export declare function sqlStringLiteral(value: string): string;
|
|
26
|
+
export declare function normalizeLanceUpdateValues(values: Record<string, unknown>): Record<string, unknown>;
|
|
27
|
+
type DecayOptions = {
|
|
28
|
+
coreCategories?: string[];
|
|
29
|
+
coreImportanceThreshold?: number;
|
|
30
|
+
skillCapsuleProtection?: boolean;
|
|
31
|
+
dryRun?: boolean;
|
|
32
|
+
deleteWith?: (id: string) => Promise<boolean>;
|
|
33
|
+
maxDelete?: number;
|
|
34
|
+
maxDecay?: number;
|
|
35
|
+
};
|
|
36
|
+
type StoreEntryInput = Omit<MemoryEntry, "id" | "createdAt" | "updatedAt" | "textTokens"> & {
|
|
37
|
+
creationAuditSource?: string | null;
|
|
38
|
+
creationAuditMeta?: Record<string, unknown>;
|
|
39
|
+
};
|
|
40
|
+
type ConcentratorStatInput = Omit<ConcentratorStat, "id" | "createdAt"> & {
|
|
41
|
+
id?: string;
|
|
42
|
+
createdAt?: number;
|
|
43
|
+
};
|
|
44
|
+
type ConflictStatInput = {
|
|
45
|
+
ts?: number;
|
|
46
|
+
operationName: string;
|
|
47
|
+
callerPath?: string | null;
|
|
48
|
+
attempt: number;
|
|
49
|
+
finalOutcome: string;
|
|
50
|
+
fragmentId?: string | number | null;
|
|
51
|
+
};
|
|
52
|
+
type NightConsolidationStatInput = {
|
|
53
|
+
id?: string;
|
|
54
|
+
runId: string;
|
|
55
|
+
phase: string;
|
|
56
|
+
ts?: number;
|
|
57
|
+
outcome?: string | null;
|
|
58
|
+
durationMs?: number | null;
|
|
59
|
+
candidateCount?: number | null;
|
|
60
|
+
scannedCount?: number | null;
|
|
61
|
+
decisionCount?: number | null;
|
|
62
|
+
mergeCount?: number | null;
|
|
63
|
+
deleteCount?: number | null;
|
|
64
|
+
deprecatedCount?: number | null;
|
|
65
|
+
updateCount?: number | null;
|
|
66
|
+
keepCount?: number | null;
|
|
67
|
+
attemptedCount?: number | null;
|
|
68
|
+
failedCount?: number | null;
|
|
69
|
+
batchIndex?: number | null;
|
|
70
|
+
batchSize?: number | null;
|
|
71
|
+
driftMs?: number | null;
|
|
72
|
+
scheduledFor?: number | null;
|
|
73
|
+
errorMessage?: string | null;
|
|
74
|
+
metadata?: string | Record<string, unknown> | null;
|
|
75
|
+
};
|
|
76
|
+
export declare class MemoryStore {
|
|
77
|
+
private readonly dbPath;
|
|
78
|
+
private readonly ramDbPath;
|
|
79
|
+
private readonly vectorDim;
|
|
80
|
+
private readonly ssdRecoveryProbeIntervalMs;
|
|
81
|
+
private ramDb;
|
|
82
|
+
private ramTable;
|
|
83
|
+
private ssdDb;
|
|
84
|
+
private ssdTable;
|
|
85
|
+
private subsystemEffectivenessRamTable;
|
|
86
|
+
private subsystemEffectivenessSsdTable;
|
|
87
|
+
private concentratorStatsRamTable;
|
|
88
|
+
private concentratorStatsSsdTable;
|
|
89
|
+
private conflictStatsRamTable;
|
|
90
|
+
private conflictStatsSsdTable;
|
|
91
|
+
private nightConsolidationStatsRamTable;
|
|
92
|
+
private nightConsolidationStatsSsdTable;
|
|
93
|
+
private walMetadataRamTable;
|
|
94
|
+
private walMetadataSsdTable;
|
|
95
|
+
private statusAuditLogRamTable;
|
|
96
|
+
private statusAuditLogSsdTable;
|
|
97
|
+
private transcriptWatermarkRamTable;
|
|
98
|
+
private transcriptWatermarkSsdTable;
|
|
99
|
+
private shutdownHooks;
|
|
100
|
+
private initPromise;
|
|
101
|
+
private healthConfig;
|
|
102
|
+
private readonly _embedder?;
|
|
103
|
+
private readonly walDir;
|
|
104
|
+
private readonly walPath;
|
|
105
|
+
private walRecovered;
|
|
106
|
+
private walTxnCounter;
|
|
107
|
+
private lastCheckpointTxnId;
|
|
108
|
+
private walCheckpointInitialized;
|
|
109
|
+
private walCheckpointUpdateQueue;
|
|
110
|
+
private ssdAvailable;
|
|
111
|
+
private ssdConsecutiveFailures;
|
|
112
|
+
private ssdRecoveryProbeTimer;
|
|
113
|
+
private ssdRecoveryProbeInFlight;
|
|
114
|
+
private ftsAvailable;
|
|
115
|
+
private readonly ssdFallback;
|
|
116
|
+
constructor(dbPath: string, // SSD 持久化路徑
|
|
117
|
+
ramDbPath: string, // RAM Disk 路徑
|
|
118
|
+
vectorDim: number, walFileOrHealthConfig?: string | typeof DEFAULT_HEALTH_CONFIG, healthConfigOrEmbedder?: typeof DEFAULT_HEALTH_CONFIG | {
|
|
119
|
+
embed(text: string): Promise<number[]>;
|
|
120
|
+
}, embedder?: {
|
|
121
|
+
embed(text: string): Promise<number[]>;
|
|
122
|
+
}, ssdRecoveryProbeIntervalMs?: number);
|
|
123
|
+
get db(): any;
|
|
124
|
+
/** SSD 持久化連接(供 GraphStore 共用) */
|
|
125
|
+
get ssd(): any;
|
|
126
|
+
onShutdown(fn: () => Promise<void>): void;
|
|
127
|
+
ensureInitialized(): Promise<void>;
|
|
128
|
+
private doInitialize;
|
|
129
|
+
private initTable;
|
|
130
|
+
private ensureHasHooksColumnAndIndex;
|
|
131
|
+
private ensureFtsIndex;
|
|
132
|
+
/**
|
|
133
|
+
* 寫入一筆 WAL 條目,自動附加單調遞增的 txnId。
|
|
134
|
+
* ⚠️ txnId 是精確的 replay 順序控制依據,不可重複使用。
|
|
135
|
+
*/
|
|
136
|
+
private appendWal;
|
|
137
|
+
private restoreWalTxnCounter;
|
|
138
|
+
/**
|
|
139
|
+
* 更新 wal_metadata 表的 last_committed_txn_id。
|
|
140
|
+
* 寫入後即表示這筆 txnId 及之前的操作已安全落地。
|
|
141
|
+
* ⚠️ 必須在 WAL commit line 寫入磁碟成功後才能更新(嚴格 ordered)。
|
|
142
|
+
*/
|
|
143
|
+
private updateWalMetadata;
|
|
144
|
+
/**
|
|
145
|
+
* 查詢目前已 commit 的最大 txnId(用於 recovery 起點)。
|
|
146
|
+
* 回傳 0 表示尚無任何 commit 記錄。
|
|
147
|
+
*/
|
|
148
|
+
private getLastCommittedTxnId;
|
|
149
|
+
private commitWal;
|
|
150
|
+
/**
|
|
151
|
+
* WAL Recovery - 從上次已知的安全 checkpoint 開始 replay。
|
|
152
|
+
*
|
|
153
|
+
* At-least-once recovery:
|
|
154
|
+
* 1. 所有已進 WAL 的變更都以冪等方式 replay(包括尚未 ack 的操作)
|
|
155
|
+
* 2. 每筆 replay 成功後,立即更新 last_committed_txn_id(寫入 wal_metadata)
|
|
156
|
+
* 3. 若 replay 到一半再次當機,下次重啟會重試保留的 WAL 條目
|
|
157
|
+
*
|
|
158
|
+
* ⚠️ txnId 小的先 replay(嚴格ordered),避免因果鏈順序錯亂。
|
|
159
|
+
*/
|
|
160
|
+
private recoverFromWal;
|
|
161
|
+
private rewriteWal;
|
|
162
|
+
private clearWal;
|
|
163
|
+
private handleSsdSuccess;
|
|
164
|
+
private handleSsdError;
|
|
165
|
+
private startSsdRecoveryProbe;
|
|
166
|
+
private probeSsdRecovery;
|
|
167
|
+
private stopSsdRecoveryProbe;
|
|
168
|
+
private ensureConcentratorStatsTable;
|
|
169
|
+
private ensureConcentratorStatsTables;
|
|
170
|
+
private ensureConflictStatsTable;
|
|
171
|
+
private ensureConflictStatsTables;
|
|
172
|
+
private ensureNightConsolidationStatsTable;
|
|
173
|
+
private ensureNightConsolidationStatsTables;
|
|
174
|
+
private ensureWalMetadataTable;
|
|
175
|
+
private ensureWalMetadataTables;
|
|
176
|
+
private cleanupLegacyWalMetadataRow;
|
|
177
|
+
private tokenizeChinese;
|
|
178
|
+
private toJsVector;
|
|
179
|
+
private parseMetadata;
|
|
180
|
+
private hasHooksFromMetadata;
|
|
181
|
+
/**
|
|
182
|
+
* 🛡️ LanceDB Optimistic Concurrency 緩解器
|
|
183
|
+
* 遇到 'Commit conflict' 時,隨機等待後重試 (Jitter Backoff)
|
|
184
|
+
* 這對於雙寫與頻繁背景任務至關重要。
|
|
185
|
+
*/
|
|
186
|
+
private lancedbRetry;
|
|
187
|
+
private extractFragmentId;
|
|
188
|
+
private extractCallerPath;
|
|
189
|
+
private extractCallerPathFrames;
|
|
190
|
+
private recordConflictStatBestEffort;
|
|
191
|
+
private recordConflictStatRow;
|
|
192
|
+
recordConflictStat(stat: ConflictStatInput): Promise<void>;
|
|
193
|
+
recordNightConsolidationStat(stat: NightConsolidationStatInput): Promise<void>;
|
|
194
|
+
private validateEntrySchema;
|
|
195
|
+
private rejectSchemaViolation;
|
|
196
|
+
/**
|
|
197
|
+
* store() - append-only,風險最低
|
|
198
|
+
* RAM 同步寫(快),SSD 異步寫(fire-and-forget)
|
|
199
|
+
* WAL 在回應前同步落地,SSD 若未完成可於重啟時補寫
|
|
200
|
+
*/
|
|
201
|
+
private static readonly MAX_TEXT_LENGTH;
|
|
202
|
+
store(entry: StoreEntryInput): Promise<MemoryEntry>;
|
|
203
|
+
/**
|
|
204
|
+
* update() - 危險操作,WAL 先行
|
|
205
|
+
* 1. append WAL(先寫 log)
|
|
206
|
+
* 2. RAM + SSD 同時更新
|
|
207
|
+
* 3. WAL commit
|
|
208
|
+
*/
|
|
209
|
+
update(id: string, updates: Partial<Omit<MemoryEntry, "id" | "createdAt">>, newVector?: number[]): Promise<boolean>;
|
|
210
|
+
/**
|
|
211
|
+
* delete() - 危險操作,WAL 先行
|
|
212
|
+
* 1. WAL 先行
|
|
213
|
+
* 2. RAM + SSD 同時刪
|
|
214
|
+
* 3. WAL commit
|
|
215
|
+
*/
|
|
216
|
+
delete(id: string): Promise<boolean>;
|
|
217
|
+
private static readonly UUID_RE;
|
|
218
|
+
private validateId;
|
|
219
|
+
getById(id: string, includeAllStatus?: boolean): Promise<MemoryEntry | null>;
|
|
220
|
+
getByIds(ids: string[], includeAllStatus?: boolean): Promise<MemoryEntry[]>;
|
|
221
|
+
count(): Promise<number>;
|
|
222
|
+
private ensureSubsystemEffectivenessTable;
|
|
223
|
+
initSubsystemEffectivenessTable(): Promise<void>;
|
|
224
|
+
recordSubsystemEffectiveness(event: SubsystemEffectivenessEvent): Promise<void>;
|
|
225
|
+
querySubsystemEffectiveness(filter?: SubsystemEffectivenessQueryFilter): Promise<SubsystemEffectivenessRow[]>;
|
|
226
|
+
recordConcentratorStat(stat: ConcentratorStatInput): Promise<void>;
|
|
227
|
+
queryConcentratorStats(opts?: {
|
|
228
|
+
since?: number;
|
|
229
|
+
provider?: ConcentratorStat["provider"];
|
|
230
|
+
outcome?: ConcentratorStat["outcome"];
|
|
231
|
+
canonicalKey?: string;
|
|
232
|
+
limit?: number;
|
|
233
|
+
}): Promise<ConcentratorStat[]>;
|
|
234
|
+
getRecentConcentratorStats(limit?: number): Promise<ConcentratorStat[]>;
|
|
235
|
+
private ensureStatusAuditLogTable;
|
|
236
|
+
private ensureStatusAuditLogTables;
|
|
237
|
+
/**
|
|
238
|
+
* P0-3 Schema Migration: 確保 memories table 有 `status` column (Utf8, nullable)。
|
|
239
|
+
* 舊資料全部預設為 'active'。使用 LanceDB addColumns API,idempotent。
|
|
240
|
+
*/
|
|
241
|
+
private ensureStatusColumn;
|
|
242
|
+
recordStatusAudit(audit: Omit<StatusAuditRow, "id" | "timestamp"> & {
|
|
243
|
+
id?: string;
|
|
244
|
+
timestamp?: number;
|
|
245
|
+
}): Promise<string>;
|
|
246
|
+
recordCreationAudit(req: {
|
|
247
|
+
memoryId: string;
|
|
248
|
+
source: string;
|
|
249
|
+
meta?: Record<string, unknown>;
|
|
250
|
+
}): Promise<string>;
|
|
251
|
+
/**
|
|
252
|
+
* 查詢 status_audit_log(觀測用)。
|
|
253
|
+
*
|
|
254
|
+
* @note volatile — 只讀 RAM,重啟後遺失歷史。
|
|
255
|
+
* 長期 audit 查詢需另開 P1 任務支援 readFromSsd 選項。
|
|
256
|
+
*/
|
|
257
|
+
queryStatusAudit(opts?: {
|
|
258
|
+
memoryId?: string;
|
|
259
|
+
since?: number;
|
|
260
|
+
source?: string;
|
|
261
|
+
limit?: number;
|
|
262
|
+
}): Promise<StatusAuditRow[]>;
|
|
263
|
+
private initializeCreationStatus;
|
|
264
|
+
private safeRecordCreationAudit;
|
|
265
|
+
private ensureTranscriptWatermarkTable;
|
|
266
|
+
private ensureTranscriptWatermarkTables;
|
|
267
|
+
setTranscriptWatermark(canonicalKey: string, sessionId: string | null, lineCount: number): Promise<void>;
|
|
268
|
+
getTranscriptWatermark(canonicalKey: string): Promise<(TranscriptWatermarkRow & {
|
|
269
|
+
sessionId: string | null;
|
|
270
|
+
}) | null>;
|
|
271
|
+
vectorSearch(vector: number[], limit?: number): Promise<MemorySearchResult[]>;
|
|
272
|
+
ftsSearch(query: string, limit?: number): Promise<MemorySearchResult[]>;
|
|
273
|
+
/**
|
|
274
|
+
* hybridVectorSearch - 統一混合搜尋(向量 + FTS + RRF Fusion)
|
|
275
|
+
* 替代所有純向量搜尋調用
|
|
276
|
+
*/
|
|
277
|
+
hybridVectorSearch(query: string, limit?: number): Promise<MemorySearchResult[]>;
|
|
278
|
+
private _embed;
|
|
279
|
+
/**
|
|
280
|
+
* hybridSkillCapsuleSearch - 技能膠囊混合搜尋(hybridVectorSearch + keyword match)
|
|
281
|
+
* 用於 autoRecall 結果組裝階段
|
|
282
|
+
*/
|
|
283
|
+
hybridSkillCapsuleSearch(query: string, limit?: number, filters?: {
|
|
284
|
+
capsuleVersion?: number;
|
|
285
|
+
status?: string;
|
|
286
|
+
}): Promise<SkillCapsule[]>;
|
|
287
|
+
query(predicate: string, limit?: number, includeAllStatus?: boolean): Promise<MemoryEntry[]>;
|
|
288
|
+
queryAll(limit?: number): Promise<MemoryEntry[]>;
|
|
289
|
+
queryHookBearing(): Promise<MemoryEntry[]>;
|
|
290
|
+
queryAllWithMeta(limit?: number): Promise<Array<MemoryEntry & {
|
|
291
|
+
metadataObj: Record<string, any>;
|
|
292
|
+
}>>;
|
|
293
|
+
recordMemoryRecalls(entries: Array<MemoryEntry | {
|
|
294
|
+
id: string;
|
|
295
|
+
}>, recalledAt?: number): Promise<void>;
|
|
296
|
+
getRecallStats(memoryId: string): Promise<{
|
|
297
|
+
lastRecalledAt: number | null;
|
|
298
|
+
recallCount: number;
|
|
299
|
+
ageInDays: number;
|
|
300
|
+
dormancyInDays: number | null;
|
|
301
|
+
} | null>;
|
|
302
|
+
/**
|
|
303
|
+
* searchBySlotKey - 精準查詢同 slotKey 的所有版本
|
|
304
|
+
* 用於 Structured Slot 的 supersedes 鏈查找
|
|
305
|
+
*/
|
|
306
|
+
searchBySlotKey(slotKey: string): Promise<MemoryEntry[]>;
|
|
307
|
+
boostHealth(id: string): Promise<boolean>;
|
|
308
|
+
/**
|
|
309
|
+
* 批次更新多筆記錄的 metadata(不走一筆一筆 WAL,直接寫 table + 單筆 batch WAL entry)。
|
|
310
|
+
* 用於 decayMemories 批次收集完後一次性寫入,減少 O(N) WAL I/O。
|
|
311
|
+
*
|
|
312
|
+
* ⚠️ 犧牲了逐筆 WAL entry 的精細度,但換來批次效能。
|
|
313
|
+
* 萬一寫入中途當機,batch 內部分記錄可能未落地,需靠下次 recovery 重跑。
|
|
314
|
+
*/
|
|
315
|
+
batchUpdateMemories(updates: Array<{
|
|
316
|
+
id: string;
|
|
317
|
+
metadata: string;
|
|
318
|
+
}>): Promise<void>;
|
|
319
|
+
decayMemories(decayPerRun?: number, deleteThreshold?: number, options?: DecayOptions): Promise<{
|
|
320
|
+
decayed: number;
|
|
321
|
+
deleted: number;
|
|
322
|
+
coreProtected: number;
|
|
323
|
+
wouldDecay: number;
|
|
324
|
+
wouldDelete: number;
|
|
325
|
+
deferredDecay: number;
|
|
326
|
+
deferredDelete: number;
|
|
327
|
+
deleteCandidateSummary: {
|
|
328
|
+
count: number;
|
|
329
|
+
firstId: string | null;
|
|
330
|
+
lastId: string | null;
|
|
331
|
+
minCreatedAt: number | null;
|
|
332
|
+
maxCreatedAt: number | null;
|
|
333
|
+
createdAtByDay: Record<string, number>;
|
|
334
|
+
};
|
|
335
|
+
}>;
|
|
336
|
+
getHealthStats(): Promise<any>;
|
|
337
|
+
shutdown(): Promise<void>;
|
|
338
|
+
}
|
|
339
|
+
export type { MemoryEntry, MemorySearchResult, MemoryHealth, SkillCapsule };
|