@equationalapplications/core-llm-wiki 4.7.0 → 4.9.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/README.md +81 -0
- package/dist/chunk-6FWG2DG4.mjs +2547 -0
- package/dist/chunk-6FWG2DG4.mjs.map +1 -0
- package/dist/index.d.mts +4 -530
- package/dist/index.d.ts +4 -530
- package/dist/index.js +2489 -2020
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +200 -2274
- package/dist/index.mjs.map +1 -1
- package/dist/testing-CDIDE4Jd.d.mts +1141 -0
- package/dist/testing-CDIDE4Jd.d.ts +1141 -0
- package/dist/testing.d.mts +2 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.js +2552 -0
- package/dist/testing.js.map +1 -0
- package/dist/testing.mjs +3 -0
- package/dist/testing.mjs.map +1 -0
- package/package.json +6 -1
|
@@ -0,0 +1,1141 @@
|
|
|
1
|
+
import { SearchResult } from 'minisearch';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Platform-agnostic SQLite driver interface.
|
|
5
|
+
* Each platform package (wiki-expo, wiki-react) provides an adapter
|
|
6
|
+
* that wraps its native driver behind this interface.
|
|
7
|
+
*/
|
|
8
|
+
interface SQLiteAdapter {
|
|
9
|
+
execAsync(sql: string): Promise<void>;
|
|
10
|
+
runAsync(sql: string, params?: unknown[]): Promise<{
|
|
11
|
+
changes: number;
|
|
12
|
+
lastInsertRowId: number;
|
|
13
|
+
}>;
|
|
14
|
+
getAllAsync<T>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
15
|
+
getFirstAsync<T>(sql: string, params?: unknown[]): Promise<T | null>;
|
|
16
|
+
withTransactionAsync<T>(fn: (tx: SQLiteAdapter) => Promise<T>): Promise<T>;
|
|
17
|
+
closeAsync(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
interface PromptOverrides {
|
|
20
|
+
ingestSystemPrompt?: string;
|
|
21
|
+
librarianSystemPrompt?: string;
|
|
22
|
+
healSystemPrompt?: string;
|
|
23
|
+
}
|
|
24
|
+
interface WikiConfig {
|
|
25
|
+
tablePrefix?: string;
|
|
26
|
+
maxResults?: number;
|
|
27
|
+
/** @deprecated Use maxResults */
|
|
28
|
+
maxFtsResults?: number;
|
|
29
|
+
pruneEventsAfter?: number;
|
|
30
|
+
pruneRetainSoftDeletedFor?: number;
|
|
31
|
+
autoLibrarianThreshold?: number;
|
|
32
|
+
autoHealThreshold?: number;
|
|
33
|
+
orphanAfterDays?: number | null;
|
|
34
|
+
staleInferredAfterDays?: number | null;
|
|
35
|
+
maxChunkLength?: number;
|
|
36
|
+
chunkOverlap?: number;
|
|
37
|
+
chunkConcurrency?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Max MiniSearch candidates passed to cosine scoring.
|
|
40
|
+
* When set, MiniSearch pre-filters before the cosine scan.
|
|
41
|
+
* Only applies when embed is provided and succeeds.
|
|
42
|
+
* Default: undefined (full scan).
|
|
43
|
+
*/
|
|
44
|
+
preFilterLimit?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Hybrid blend weight (0.0–1.0).
|
|
47
|
+
* 0.0 = pure keyword (skips embed() entirely).
|
|
48
|
+
* 1.0 = pure semantic.
|
|
49
|
+
* Values outside [0,1] are clamped. Ignored when embed is absent or throws.
|
|
50
|
+
* Default: undefined (pure semantic when embed provided).
|
|
51
|
+
*/
|
|
52
|
+
hybridWeight?: number;
|
|
53
|
+
/** Global prompt overrides for text generation calls (`ingestDocument`, `runLibrarian`, `runHeal`). Does not affect embedding generation. Runtime overrides on individual method calls take precedence. */
|
|
54
|
+
prompts?: PromptOverrides;
|
|
55
|
+
/**
|
|
56
|
+
* When true, entry and task mutations append an event to the internal outbox table.
|
|
57
|
+
* The table is always created; this flag only controls whether writes occur.
|
|
58
|
+
* @default false
|
|
59
|
+
*/
|
|
60
|
+
enableOutbox?: boolean;
|
|
61
|
+
}
|
|
62
|
+
interface ReadOptions {
|
|
63
|
+
maxResults?: number;
|
|
64
|
+
/**
|
|
65
|
+
* undefined → use WikiConfig.preFilterLimit (or no pre-filter if also unset).
|
|
66
|
+
* null → explicitly disable a config-level preFilterLimit for this call.
|
|
67
|
+
*/
|
|
68
|
+
preFilterLimit?: number | null;
|
|
69
|
+
hybridWeight?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Per-entity score multiplier for multi-entity reads. Missing entries default to 1.0.
|
|
72
|
+
* Entities with weight 0 are skipped during scored retrieval unless
|
|
73
|
+
* `includeZeroWeightEntities` is true; in that case they rank below all finite scores.
|
|
74
|
+
* Only meaningful when `entityId` is an array; ignored for single-string calls.
|
|
75
|
+
*/
|
|
76
|
+
tierWeights?: Record<string, number>;
|
|
77
|
+
/**
|
|
78
|
+
* When true, entities with a tier weight of 0 are included in scored retrieval
|
|
79
|
+
* as bottom fillers (ranked below every finite-scored candidate).
|
|
80
|
+
* When false (default), zero-weight entities are skipped entirely.
|
|
81
|
+
* Only meaningful when `entityId` is an array; ignored for single-string calls.
|
|
82
|
+
*/
|
|
83
|
+
includeZeroWeightEntities?: boolean;
|
|
84
|
+
}
|
|
85
|
+
interface WikiFact {
|
|
86
|
+
id: string;
|
|
87
|
+
entity_id: string;
|
|
88
|
+
title: string;
|
|
89
|
+
body: string;
|
|
90
|
+
tags: string[];
|
|
91
|
+
confidence: 'certain' | 'inferred' | 'tentative';
|
|
92
|
+
/**
|
|
93
|
+
* Source type of this fact.
|
|
94
|
+
* - 'immutable_document': From ingestDocument(), cannot be modified by system (librarian/heal).
|
|
95
|
+
* Only removable via forget() or replaced via re-ingest.
|
|
96
|
+
* - 'librarian_inferred': Created by runLibrarian() from events, or by runHeal() when synthesizing new inferred facts.
|
|
97
|
+
* - 'user_stated': Direct user statement.
|
|
98
|
+
* - 'user_confirmed': User-confirmed fact.
|
|
99
|
+
*/
|
|
100
|
+
source_type: 'user_stated' | 'librarian_inferred' | 'user_confirmed' | 'immutable_document';
|
|
101
|
+
source_hash: string | null;
|
|
102
|
+
source_ref: string | null;
|
|
103
|
+
created_at: number;
|
|
104
|
+
updated_at: number;
|
|
105
|
+
/**
|
|
106
|
+
* Raw Float32Array bytes for the fact's embedding vector.
|
|
107
|
+
* Set when the fact was fetched via exportDump() with blob preservation.
|
|
108
|
+
* Accepted in importDump() as a real Uint8Array (in-memory round-trip),
|
|
109
|
+
* a Node.js Buffer JSON shape `{ type: 'Buffer', data: number[] }`,
|
|
110
|
+
* or a numeric-keyed plain object `{ 0: byte, 1: byte, ... }` produced
|
|
111
|
+
* by JSON.stringify(Uint8Array).
|
|
112
|
+
*/
|
|
113
|
+
embedding_blob?: Uint8Array | {
|
|
114
|
+
type: 'Buffer';
|
|
115
|
+
data: number[];
|
|
116
|
+
} | Record<string, number> | null;
|
|
117
|
+
last_accessed_at: number | null;
|
|
118
|
+
access_count: number;
|
|
119
|
+
deleted_at: number | null;
|
|
120
|
+
}
|
|
121
|
+
interface WikiTask {
|
|
122
|
+
id: string;
|
|
123
|
+
entity_id: string;
|
|
124
|
+
description: string;
|
|
125
|
+
status: 'pending' | 'in_progress' | 'done' | 'abandoned';
|
|
126
|
+
priority: number;
|
|
127
|
+
created_at: number;
|
|
128
|
+
updated_at: number;
|
|
129
|
+
resolved_at: number | null;
|
|
130
|
+
deleted_at: number | null;
|
|
131
|
+
}
|
|
132
|
+
interface WikiEvent {
|
|
133
|
+
id: string;
|
|
134
|
+
entity_id: string;
|
|
135
|
+
event_type: 'observation' | 'decision' | 'action' | 'outcome';
|
|
136
|
+
summary: string;
|
|
137
|
+
related_entry_id?: string | null;
|
|
138
|
+
created_at: number;
|
|
139
|
+
}
|
|
140
|
+
interface WikiCheckpoint {
|
|
141
|
+
entity_id: string;
|
|
142
|
+
heal_checkpoint: number;
|
|
143
|
+
memory_checkpoint: number;
|
|
144
|
+
}
|
|
145
|
+
interface ExtractedFact {
|
|
146
|
+
title: string;
|
|
147
|
+
body: string;
|
|
148
|
+
tags: string[];
|
|
149
|
+
confidence: 'certain' | 'inferred' | 'tentative';
|
|
150
|
+
}
|
|
151
|
+
interface ExtractedTask {
|
|
152
|
+
description: string;
|
|
153
|
+
priority: number;
|
|
154
|
+
}
|
|
155
|
+
interface LLMProvider {
|
|
156
|
+
/**
|
|
157
|
+
* Generates text using the developer's LLM of choice.
|
|
158
|
+
* Expected to return the raw text response (typically a JSON string).
|
|
159
|
+
*/
|
|
160
|
+
generateText: (params: {
|
|
161
|
+
systemPrompt: string;
|
|
162
|
+
userPrompt: string;
|
|
163
|
+
}) => Promise<string>;
|
|
164
|
+
/**
|
|
165
|
+
* Optional. When provided, enables semantic similarity search in `read()`.
|
|
166
|
+
* Must return a stable-dimension float array for any input text.
|
|
167
|
+
* Called once per fact on creation/update, and once per `read()` query.
|
|
168
|
+
* When absent or throws, `read()` falls back to MiniSearch.
|
|
169
|
+
*/
|
|
170
|
+
embed?: (text: string) => Promise<number[]>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Result of semantic ranking for a single fact.
|
|
174
|
+
*/
|
|
175
|
+
interface VectorRankerSemanticResult {
|
|
176
|
+
id: string;
|
|
177
|
+
/** Cosine similarity in [-1, 1] when exact; implementations MAY document other monotonic scales. */
|
|
178
|
+
semanticScore: number;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Arguments passed to VectorRanker.rankBySimilarity.
|
|
182
|
+
*/
|
|
183
|
+
interface VectorRankerRankArgs {
|
|
184
|
+
entityId: string;
|
|
185
|
+
/**
|
|
186
|
+
* Query embedding. Treat as readonly — core provides a defensive copy,
|
|
187
|
+
* but adapters MUST NOT mutate this array. Mutation can corrupt
|
|
188
|
+
* WikiMemory's internal vector cache and JS-cosine fallback path.
|
|
189
|
+
*/
|
|
190
|
+
queryVec: Float32Array | number[];
|
|
191
|
+
/**
|
|
192
|
+
* When set (MiniSearch pre-filter path): ranker MUST only produce results for ids in this set.
|
|
193
|
+
* When omitted (full-entity semantic path): ranker scopes by entityId per its backing store contract.
|
|
194
|
+
*/
|
|
195
|
+
candidateIds?: readonly string[];
|
|
196
|
+
/**
|
|
197
|
+
* Upper bound on how many distinct fact ids should receive a semanticScore in this call.
|
|
198
|
+
* WikiMemory derives this from maxResults / candidate cardinality / documented oversampling policy.
|
|
199
|
+
*/
|
|
200
|
+
limit: number;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Optional backend for semantic candidate scoring / top-k retrieval.
|
|
204
|
+
* When omitted, WikiMemory scores rows with embedding_blob / embedding TEXT in JS (cosine).
|
|
205
|
+
*/
|
|
206
|
+
interface VectorRanker {
|
|
207
|
+
/**
|
|
208
|
+
* Return semantic scores for facts in scope, sorted descending by semanticScore (stable tie-breaking
|
|
209
|
+
* not required — WikiMemory reapplies existing tie-breakers after blending).
|
|
210
|
+
* Implementations SHOULD omit facts with no usable vector; callers treat missing ids like today's
|
|
211
|
+
* "no embedding" rows (pure semantic: -2; hybrid: keyword-only portion).
|
|
212
|
+
*/
|
|
213
|
+
rankBySimilarity(args: VectorRankerRankArgs): Promise<VectorRankerSemanticResult[]>;
|
|
214
|
+
/**
|
|
215
|
+
* Called after a fact's embedding is successfully persisted to embedding_blob (or cleared).
|
|
216
|
+
* Hosts use this to keep sqlite-vec / external indexes consistent with SQLite as source of truth.
|
|
217
|
+
*
|
|
218
|
+
* On deletion paths (forget, prune, hard-delete), core awaits this hook to ensure ANN cleanup
|
|
219
|
+
* completes before the deletion call resolves (GDPR compliance). Hook failures or timeouts on
|
|
220
|
+
* those paths reject the deletion call.
|
|
221
|
+
*
|
|
222
|
+
* Treat `vector` as readonly — core provides a defensive copy, but adapters MUST NOT mutate.
|
|
223
|
+
*
|
|
224
|
+
* Optional: if omitted, hosts MUST document "index rebuilt separately" and accept stale ANN until rebuild.
|
|
225
|
+
*/
|
|
226
|
+
onEmbeddingPersisted?(event: {
|
|
227
|
+
entityId: string;
|
|
228
|
+
factId: string;
|
|
229
|
+
vector: Float32Array | null;
|
|
230
|
+
}): void | Promise<void>;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Fallback policy when rankBySimilarity rejects.
|
|
234
|
+
*/
|
|
235
|
+
type VectorRankerFallback = 'js-cosine' | 'keyword' | 'empty' | 'throw';
|
|
236
|
+
interface WikiOptions {
|
|
237
|
+
config?: WikiConfig;
|
|
238
|
+
llmProvider: LLMProvider;
|
|
239
|
+
/**
|
|
240
|
+
* Called when embedding-based retrieval is degraded or unavailable during `read()`.
|
|
241
|
+
* This can happen when:
|
|
242
|
+
* - `embed()` throws (e.g. network error, model unavailable) → falls back to keyword search
|
|
243
|
+
* - `embed()` returns a vector with non-finite values (NaN / Infinity) → falls back to keyword search
|
|
244
|
+
* - The query vector's dimension doesn't match stored embeddings (model switch;
|
|
245
|
+
* resolve by calling `runReembed()`) → falls back to keyword search
|
|
246
|
+
* - `vectorRanker` returns IDs that don't belong to the requested entity or don't exist
|
|
247
|
+
* (ranker integrity issue; returned rows will be filtered out, reducing result count) →
|
|
248
|
+
* may still use semantic ranking, but with degraded quality
|
|
249
|
+
*
|
|
250
|
+
* `read()` returns results (keyword fallback or degraded semantic) — this is a notification, not an error path.
|
|
251
|
+
*/
|
|
252
|
+
onRetrievalFallback?: (error: Error) => void;
|
|
253
|
+
/**
|
|
254
|
+
* Optional backend for semantic candidate scoring / top-k retrieval.
|
|
255
|
+
* When omitted, WikiMemory scores rows with embedding_blob / embedding TEXT in JS (cosine).
|
|
256
|
+
*/
|
|
257
|
+
vectorRanker?: VectorRanker;
|
|
258
|
+
/**
|
|
259
|
+
* When rankBySimilarity throws. Default `'js-cosine'`.
|
|
260
|
+
* Ignored when vectorRanker is undefined.
|
|
261
|
+
*/
|
|
262
|
+
vectorRankerFallback?: VectorRankerFallback;
|
|
263
|
+
/**
|
|
264
|
+
* Called only when rankBySimilarity rejects (after embeddings path succeeded).
|
|
265
|
+
* Invoked before applying vectorRankerFallback when that policy recovers or before rejecting when policy is 'throw'.
|
|
266
|
+
*/
|
|
267
|
+
onVectorRankerFallback?: (info: {
|
|
268
|
+
error: Error;
|
|
269
|
+
/** Effective policy core will apply for this read (same as WikiOptions.vectorRankerFallback, default js-cosine). */
|
|
270
|
+
policy: VectorRankerFallback;
|
|
271
|
+
}) => void;
|
|
272
|
+
/**
|
|
273
|
+
* When true: after rankBySimilarity failure, once the recoverable fallback has finished
|
|
274
|
+
* and read() will resolve, invoke onRetrievalFallback — after onVectorRankerFallback if set.
|
|
275
|
+
* Ignored when vectorRankerFallback is 'throw'. Default false.
|
|
276
|
+
*/
|
|
277
|
+
propagateRankerFailureToRetrievalFallback?: boolean;
|
|
278
|
+
/**
|
|
279
|
+
* When true (default), sanitize ranker errors before exposing via error.cause
|
|
280
|
+
* to prevent credential leakage in host telemetry. Disable only when you
|
|
281
|
+
* control the ranker implementation.
|
|
282
|
+
*
|
|
283
|
+
* Sanitization replaces error message/stack with a generic message preserving
|
|
284
|
+
* only the error type (constructor name).
|
|
285
|
+
*/
|
|
286
|
+
sanitizeRankerErrors?: boolean;
|
|
287
|
+
/**
|
|
288
|
+
* Timeout (ms) for onEmbeddingPersisted hook on GDPR deletion paths
|
|
289
|
+
* (forget, _doPrune). Hook must complete within this window or the
|
|
290
|
+
* deletion operation rejects. Default 30000.
|
|
291
|
+
* Lower for interactive deletes; raise for slow remote ANN backends.
|
|
292
|
+
*/
|
|
293
|
+
deletionHookTimeoutMs?: number;
|
|
294
|
+
/**
|
|
295
|
+
* Escape hatch: skip onEmbeddingPersisted on deletion paths entirely.
|
|
296
|
+
* Use ONLY when the ANN backend is permanently decommissioned. Vectors
|
|
297
|
+
* orphaned in the (unreachable) external index are accepted as a tradeoff.
|
|
298
|
+
* NOT GDPR-safe for live indexes. Default false.
|
|
299
|
+
*/
|
|
300
|
+
forceDeleteIgnoreRankerHook?: boolean;
|
|
301
|
+
}
|
|
302
|
+
interface MemoryBundle {
|
|
303
|
+
facts: WikiFact[];
|
|
304
|
+
tasks: WikiTask[];
|
|
305
|
+
events: WikiEvent[];
|
|
306
|
+
factScores?: Record<string, number>;
|
|
307
|
+
metadata?: {
|
|
308
|
+
query: string;
|
|
309
|
+
entityIds: string[];
|
|
310
|
+
tierWeights?: Record<string, number>;
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
interface MemoryDump {
|
|
314
|
+
generatedAt: number;
|
|
315
|
+
entities: Record<string, MemoryBundle>;
|
|
316
|
+
}
|
|
317
|
+
interface FormattedMemoryDump {
|
|
318
|
+
manifest: string;
|
|
319
|
+
files: Array<{
|
|
320
|
+
name: string;
|
|
321
|
+
content: string;
|
|
322
|
+
}>;
|
|
323
|
+
}
|
|
324
|
+
interface FormatContextOptions {
|
|
325
|
+
format?: 'markdown' | 'plain';
|
|
326
|
+
maxFacts?: number;
|
|
327
|
+
maxTasks?: number;
|
|
328
|
+
maxEvents?: number;
|
|
329
|
+
includeConfidence?: boolean;
|
|
330
|
+
includeTags?: boolean;
|
|
331
|
+
includeEntityIds?: boolean;
|
|
332
|
+
includeFactScores?: boolean;
|
|
333
|
+
factWeights?: {
|
|
334
|
+
confidence?: number;
|
|
335
|
+
accessCount?: number;
|
|
336
|
+
recency?: number;
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
interface EntityStatus {
|
|
340
|
+
ingesting: boolean;
|
|
341
|
+
librarian: boolean;
|
|
342
|
+
heal: boolean;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* All operations that can appear in a {@link WikiBusyError}.
|
|
346
|
+
*
|
|
347
|
+
* @remarks **Breaking change from v2.x** — the union previously only contained
|
|
348
|
+
* `'ingest' | 'librarian' | 'heal' | 'prune' | 'reembed'`. The values `'import'`
|
|
349
|
+
* and `'forget'` were added in v3.0. Exhaustive `switch` / narrowing on this type
|
|
350
|
+
* must be updated (or given a `default` arm) to compile without errors.
|
|
351
|
+
*/
|
|
352
|
+
type WikiBusyOperation = 'ingest' | 'librarian' | 'heal' | 'prune' | 'reembed' | 'import' | 'forget';
|
|
353
|
+
/**
|
|
354
|
+
* Thrown when a background mutator is already running for the requested entity.
|
|
355
|
+
*/
|
|
356
|
+
declare class WikiBusyError extends Error {
|
|
357
|
+
readonly operation: WikiBusyOperation;
|
|
358
|
+
readonly entityId: string;
|
|
359
|
+
constructor(operation: WikiBusyOperation, entityId: string);
|
|
360
|
+
}
|
|
361
|
+
declare class PrunePartialFailureError extends Error {
|
|
362
|
+
readonly deleted: number;
|
|
363
|
+
readonly failedAt: string;
|
|
364
|
+
readonly remaining: number;
|
|
365
|
+
readonly deletedTasks: number;
|
|
366
|
+
readonly deletedEvents: number;
|
|
367
|
+
readonly cause: Error;
|
|
368
|
+
constructor(deleted: number, failedAt: string, remaining: number, cause: Error, deletedTasks?: number, deletedEvents?: number);
|
|
369
|
+
}
|
|
370
|
+
declare const HOOK_TIMEOUT_MARKER: unique symbol;
|
|
371
|
+
|
|
372
|
+
interface WikiOutboxEvent<T = unknown> {
|
|
373
|
+
id: string;
|
|
374
|
+
entity_id: string;
|
|
375
|
+
table_name: string;
|
|
376
|
+
record_id: string;
|
|
377
|
+
operation: 'INSERT' | 'UPDATE' | 'DELETE';
|
|
378
|
+
payload: T;
|
|
379
|
+
created_at: number;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Abstract base for all repositories.
|
|
384
|
+
* Provides db accessor + prefix-aware helpers.
|
|
385
|
+
*/
|
|
386
|
+
declare abstract class BaseRepository {
|
|
387
|
+
protected db: SQLiteAdapter;
|
|
388
|
+
protected prefix: string;
|
|
389
|
+
constructor(db: SQLiteAdapter, prefix: string);
|
|
390
|
+
/**
|
|
391
|
+
* Return the DB executor for a given transaction handle.
|
|
392
|
+
* If tx is provided, use it; otherwise fall back to this.db.
|
|
393
|
+
*/
|
|
394
|
+
protected getExecutor(tx?: SQLiteAdapter): SQLiteAdapter;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
declare class OutboxRepository extends BaseRepository {
|
|
398
|
+
private enableOutbox;
|
|
399
|
+
constructor(db: SQLiteAdapter, prefix: string, enableOutbox?: boolean);
|
|
400
|
+
/**
|
|
401
|
+
* Insert a new outbox event within the provided transaction.
|
|
402
|
+
* No-op when enableOutbox is false.
|
|
403
|
+
* `tx` is required — callers must always pass the active transaction
|
|
404
|
+
* so the write is atomic with the main table mutation.
|
|
405
|
+
*/
|
|
406
|
+
push(params: {
|
|
407
|
+
entityId: string;
|
|
408
|
+
tableName: string;
|
|
409
|
+
recordId: string;
|
|
410
|
+
operation: 'INSERT' | 'UPDATE' | 'DELETE';
|
|
411
|
+
payload: any;
|
|
412
|
+
}, tx: SQLiteAdapter): Promise<void>;
|
|
413
|
+
/**
|
|
414
|
+
* Fetch pending outbox rows ordered by created_at ASC, rowid ASC.
|
|
415
|
+
* Reads directly from `this.db` (not a transaction).
|
|
416
|
+
*/
|
|
417
|
+
fetchPending(limit?: number): Promise<any[]>;
|
|
418
|
+
/**
|
|
419
|
+
* Delete acknowledged outbox rows by their IDs.
|
|
420
|
+
* No-op when `ids` is empty.
|
|
421
|
+
* Deletes directly from `this.db` (not a transaction).
|
|
422
|
+
*/
|
|
423
|
+
acknowledge(ids: string[]): Promise<void>;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
type EntryRowMetadata = {
|
|
427
|
+
id: string;
|
|
428
|
+
entity_id: string;
|
|
429
|
+
updated_at: number | null;
|
|
430
|
+
access_count: number | null;
|
|
431
|
+
};
|
|
432
|
+
type EntryRowWithEmbeddings = EntryRowMetadata & {
|
|
433
|
+
embedding_blob: Uint8Array | null;
|
|
434
|
+
embedding: string | null;
|
|
435
|
+
};
|
|
436
|
+
declare class EntryRepository extends BaseRepository {
|
|
437
|
+
private outbox;
|
|
438
|
+
private chunkSize;
|
|
439
|
+
constructor(db: SQLiteAdapter, prefix: string, outbox: OutboxRepository);
|
|
440
|
+
/**
|
|
441
|
+
* Fetch facts by IDs, optionally scoped to entity IDs.
|
|
442
|
+
* Returns facts in the order of the input IDs (first match wins).
|
|
443
|
+
*/
|
|
444
|
+
findByIds(ids: readonly string[], scopedEntityIds?: readonly string[], tx?: SQLiteAdapter): Promise<WikiFact[]>;
|
|
445
|
+
/**
|
|
446
|
+
* Upsert a WikiFact. Nullable fields set to null when fact value is null.
|
|
447
|
+
* Returns { changes, lastInsertRowId }.
|
|
448
|
+
* `tx` is REQUIRED to ensure atomic outbox staging.
|
|
449
|
+
*/
|
|
450
|
+
upsert(fact: WikiFact, tx: SQLiteAdapter): Promise<{
|
|
451
|
+
changes: number;
|
|
452
|
+
lastInsertRowId: number;
|
|
453
|
+
}>;
|
|
454
|
+
/**
|
|
455
|
+
* Normalize an embedding blob value to Uint8Array or null.
|
|
456
|
+
*/
|
|
457
|
+
private normalizeEmbeddingBlob;
|
|
458
|
+
/**
|
|
459
|
+
* Fetch existing rows by IDs and return id/entity_id/updated_at for import collision resolution.
|
|
460
|
+
*/
|
|
461
|
+
findExistingMetadataByIds(ids: readonly string[], tx?: SQLiteAdapter): Promise<Array<{
|
|
462
|
+
id: string;
|
|
463
|
+
entity_id: string;
|
|
464
|
+
updated_at: number;
|
|
465
|
+
}>>;
|
|
466
|
+
findIdById(id: string, entityId: string, tx?: SQLiteAdapter): Promise<string | null>;
|
|
467
|
+
findIdsBySource(entityId: string, sourceRef: string | null, sourceHash: string | null, tx?: SQLiteAdapter, includeDeleted?: boolean): Promise<string[]>;
|
|
468
|
+
upsertForImport(fact: WikiFact, tx: SQLiteAdapter): Promise<{
|
|
469
|
+
changes: number;
|
|
470
|
+
lastInsertRowId: number;
|
|
471
|
+
}>;
|
|
472
|
+
/**
|
|
473
|
+
* Soft-delete a single entry by ID scoped to entityId. Sets deleted_at + updated_at.
|
|
474
|
+
* `tx` is REQUIRED to ensure atomic outbox staging.
|
|
475
|
+
*/
|
|
476
|
+
softDelete(entryId: string, entityId: string, tx: SQLiteAdapter): Promise<{
|
|
477
|
+
changes: number;
|
|
478
|
+
}>;
|
|
479
|
+
/**
|
|
480
|
+
* Soft-delete entries by source_ref and/or source_hash within a transaction.
|
|
481
|
+
* Stages a DELETE outbox entry for each row in the same transaction.
|
|
482
|
+
* `tx` is REQUIRED.
|
|
483
|
+
* Returns the number of rows deleted.
|
|
484
|
+
*/
|
|
485
|
+
softDeleteBySource(entityId: string, tx: SQLiteAdapter, sourceRef?: string | null, sourceHash?: string | null): Promise<number>;
|
|
486
|
+
/**
|
|
487
|
+
* Fetch IDs + entity_ids of soft-deleted rows older than cutoff for a given entity.
|
|
488
|
+
* Used by runPrune().
|
|
489
|
+
*/
|
|
490
|
+
getPrunableMetadata(entityId: string, cutoff: number, tx?: SQLiteAdapter): Promise<Array<{
|
|
491
|
+
id: string;
|
|
492
|
+
entity_id: string;
|
|
493
|
+
}>>;
|
|
494
|
+
/**
|
|
495
|
+
* Fetch all non-deleted entries for an entity, ordered by updated_at DESC.
|
|
496
|
+
* Used by _getFullBundle().
|
|
497
|
+
*/
|
|
498
|
+
findAllByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<WikiFact[]>;
|
|
499
|
+
/**
|
|
500
|
+
* Fetch recent non-deleted entries for an entity (limited), ordered by updated_at DESC.
|
|
501
|
+
* Used by MaintenanceService.doRunLibrarian().
|
|
502
|
+
*/
|
|
503
|
+
findRecentByEntityId(entityId: string, limit: number, tx?: SQLiteAdapter): Promise<WikiFact[]>;
|
|
504
|
+
/**
|
|
505
|
+
* Fetch all non-deleted entries for an entity with embedding blobs preserved.
|
|
506
|
+
* Used by ImportExportService for export/import round-tripping.
|
|
507
|
+
*/
|
|
508
|
+
findAllByEntityIdWithBlobs(entityId: string, tx?: SQLiteAdapter): Promise<WikiFact[]>;
|
|
509
|
+
/**
|
|
510
|
+
* Count non-deleted entries for the given entities whose embedding_blob dimension
|
|
511
|
+
* doesn't match queryVecLength. Used by read() to detect model-switch mismatches.
|
|
512
|
+
*/
|
|
513
|
+
countDimensionMismatched(entityIds: readonly string[], queryVecLength: number, tx?: SQLiteAdapter): Promise<number>;
|
|
514
|
+
/**
|
|
515
|
+
* Count non-deleted entries for entityId that are stale relative to targetDim
|
|
516
|
+
* (either no blob or wrong dimension). Used by runReembed() per-entity skip logic.
|
|
517
|
+
*/
|
|
518
|
+
countStaleForEntity(entityId: string, targetDim: number, tx?: SQLiteAdapter): Promise<number>;
|
|
519
|
+
/**
|
|
520
|
+
* Count non-deleted entries with stale or unconverted embeddings relative to `dim`.
|
|
521
|
+
* Used by _reconcileEmbeddingDimension() to decide when to promote the pending
|
|
522
|
+
* embedding_dimension value.
|
|
523
|
+
*/
|
|
524
|
+
countStaleEmbeddings(dim: number, tx?: SQLiteAdapter): Promise<number>;
|
|
525
|
+
/**
|
|
526
|
+
* Bulk delete pruned entries (already soft-deleted) by IDs.
|
|
527
|
+
* Used by runPrune(). Returns total number of deleted rows.
|
|
528
|
+
* `tx` is REQUIRED so outbox deletion events are staged atomically.
|
|
529
|
+
*/
|
|
530
|
+
bulkDeletePruned(entityId: string, cutoff: number, ids: string[], tx: SQLiteAdapter): Promise<number>;
|
|
531
|
+
/**
|
|
532
|
+
* Mark orphaned entries (never accessed, old) as deleted.
|
|
533
|
+
* Used by MaintenanceService.doRunHeal().
|
|
534
|
+
*/
|
|
535
|
+
markOrphaned(entityId: string, orphanThreshold: number, tx: SQLiteAdapter): Promise<string[]>;
|
|
536
|
+
/**
|
|
537
|
+
* Downgrade stale inferred entries to 'tentative'.
|
|
538
|
+
* Used by MaintenanceService.doRunHeal().
|
|
539
|
+
*/
|
|
540
|
+
downgradeStaleInferred(entityId: string, staleThreshold: number, tx: SQLiteAdapter): Promise<number>;
|
|
541
|
+
/**
|
|
542
|
+
* Downgrade specific entries to 'tentative' by IDs.
|
|
543
|
+
* Used by MaintenanceService.doRunHeal().
|
|
544
|
+
*/
|
|
545
|
+
downgradeByIds(ids: string[], entityId: string, tx: SQLiteAdapter): Promise<void>;
|
|
546
|
+
/**
|
|
547
|
+
* Soft-delete specific entries by IDs.
|
|
548
|
+
* Used by MaintenanceService.doRunHeal().
|
|
549
|
+
*/
|
|
550
|
+
softDeleteByIds(ids: string[], entityId: string, tx: SQLiteAdapter): Promise<void>;
|
|
551
|
+
/**
|
|
552
|
+
* Bulk soft-delete all entries for an entity.
|
|
553
|
+
* Stages DELETE outbox entries for each row in the same transaction.
|
|
554
|
+
* `tx` is REQUIRED.
|
|
555
|
+
*/
|
|
556
|
+
bulkSoftDeleteByEntityId(entityId: string, tx: SQLiteAdapter): Promise<number>;
|
|
557
|
+
findMiniSearchRows(entityId?: string, tx?: SQLiteAdapter): Promise<Array<{
|
|
558
|
+
id: string;
|
|
559
|
+
entity_id: string;
|
|
560
|
+
title: string;
|
|
561
|
+
body: string;
|
|
562
|
+
tags: string;
|
|
563
|
+
}>>;
|
|
564
|
+
updateEmbeddingBlob(id: string, blob: Uint8Array, tx?: SQLiteAdapter): Promise<void>;
|
|
565
|
+
hasLegacySourceTypes(tx?: SQLiteAdapter): Promise<boolean>;
|
|
566
|
+
countLegacySourceTypes(tx?: SQLiteAdapter): Promise<number>;
|
|
567
|
+
findAllForReembed(entityId?: string, tx?: SQLiteAdapter): Promise<Array<WikiFact & {
|
|
568
|
+
embedding_blob?: Uint8Array | null;
|
|
569
|
+
}>>;
|
|
570
|
+
findRowsForSourceRefMigration(tx?: SQLiteAdapter): Promise<Array<{
|
|
571
|
+
rowid: number;
|
|
572
|
+
source_ref: string;
|
|
573
|
+
}>>;
|
|
574
|
+
updateSourceRefByRowid(rowid: number, sourceRef: string | null, tx: SQLiteAdapter): Promise<void>;
|
|
575
|
+
findLatestSourceHash(entityId: string, sourceRef: string, tx?: SQLiteAdapter): Promise<string | null>;
|
|
576
|
+
findMetadataByIds(ids: readonly string[], tx?: SQLiteAdapter): Promise<EntryRowMetadata[]>;
|
|
577
|
+
findWithEmbeddingsByIds(ids: readonly string[], tx?: SQLiteAdapter): Promise<EntryRowWithEmbeddings[]>;
|
|
578
|
+
findMetadataByEntityIds(entityIds: readonly string[], tx?: SQLiteAdapter): Promise<EntryRowMetadata[]>;
|
|
579
|
+
findWithEmbeddingsByEntityIds(entityIds: readonly string[], tx?: SQLiteAdapter): Promise<EntryRowWithEmbeddings[]>;
|
|
580
|
+
findEmbeddingsByIds(ids: readonly string[], tx?: SQLiteAdapter): Promise<Array<{
|
|
581
|
+
id: string;
|
|
582
|
+
embedding_blob: Uint8Array | null;
|
|
583
|
+
embedding: string | null;
|
|
584
|
+
}>>;
|
|
585
|
+
trackAccess(ids: readonly string[], now: number, tx?: SQLiteAdapter): Promise<void>;
|
|
586
|
+
getLegacyMigrationSQL(): string;
|
|
587
|
+
findRecentByEntityIds(entityIds: readonly string[], limit: number, tx?: SQLiteAdapter): Promise<WikiFact[]>;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
declare class MetadataRepository extends BaseRepository {
|
|
591
|
+
getCheckpoint(entityId: string, tx: SQLiteAdapter): Promise<{
|
|
592
|
+
memory?: number;
|
|
593
|
+
heal?: number;
|
|
594
|
+
}>;
|
|
595
|
+
updateCheckpoint(entityId: string, updates: {
|
|
596
|
+
memory?: number;
|
|
597
|
+
heal?: number;
|
|
598
|
+
}, tx: SQLiteAdapter): Promise<void>;
|
|
599
|
+
deleteCheckpoint(entityId: string, tx: SQLiteAdapter): Promise<void>;
|
|
600
|
+
getMeta(key: string, tx?: SQLiteAdapter): Promise<string | null>;
|
|
601
|
+
setMeta(key: string, value: string, tx: SQLiteAdapter): Promise<void>;
|
|
602
|
+
clearDimensionMismatch(tx: SQLiteAdapter): Promise<void>;
|
|
603
|
+
tableExists(tableName: string, tx?: SQLiteAdapter): Promise<boolean>;
|
|
604
|
+
getTableDdl(tableName: string, tx?: SQLiteAdapter): Promise<string | null>;
|
|
605
|
+
vacuum(): Promise<void>;
|
|
606
|
+
getDistinctEntityIds(tx?: SQLiteAdapter): Promise<string[]>;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
interface ScoredRow {
|
|
610
|
+
id: string;
|
|
611
|
+
entity_id: string;
|
|
612
|
+
score: number;
|
|
613
|
+
updated_at: number | null;
|
|
614
|
+
access_count: number | null;
|
|
615
|
+
}
|
|
616
|
+
interface RankSemanticArgs {
|
|
617
|
+
entityId: string;
|
|
618
|
+
queryVec: Float32Array | number[];
|
|
619
|
+
candidateRows: Array<{
|
|
620
|
+
id: string;
|
|
621
|
+
entity_id: string;
|
|
622
|
+
embedding_blob: Uint8Array | null;
|
|
623
|
+
embedding: string | null;
|
|
624
|
+
updated_at: number | null;
|
|
625
|
+
access_count: number | null;
|
|
626
|
+
}>;
|
|
627
|
+
weight: number | undefined;
|
|
628
|
+
miniSearchScores: Map<string, number> | undefined;
|
|
629
|
+
populateCache: boolean;
|
|
630
|
+
limit: number;
|
|
631
|
+
skipSort?: boolean;
|
|
632
|
+
}
|
|
633
|
+
declare class SearchService {
|
|
634
|
+
private entryRepo;
|
|
635
|
+
/**
|
|
636
|
+
* Maximum number of entities whose parsed embedding vectors are held in
|
|
637
|
+
* memory. This cap is intentionally conservative so the cache remains safe
|
|
638
|
+
* on memory-constrained runtimes (e.g., mobile/Expo).
|
|
639
|
+
*/
|
|
640
|
+
private static readonly MAX_VECTOR_CACHE_ENTITIES;
|
|
641
|
+
/**
|
|
642
|
+
* Maximum number of fact vectors cached per entity. Keep this high enough to
|
|
643
|
+
* preserve the parsed-embedding reuse optimization for common mid-sized
|
|
644
|
+
* entities while still maintaining a bounded memory footprint.
|
|
645
|
+
*/
|
|
646
|
+
private static readonly MAX_VECTOR_CACHE_FACTS_PER_ENTITY;
|
|
647
|
+
private miniSearch;
|
|
648
|
+
private miniSearchEntryIdsByEntity;
|
|
649
|
+
private vectorCache;
|
|
650
|
+
constructor(entryRepo: EntryRepository);
|
|
651
|
+
/**
|
|
652
|
+
* Rebuilds the search index and clears the vector cache for a given entity.
|
|
653
|
+
* A direct replacement for manually syncing state after a DB transaction.
|
|
654
|
+
*/
|
|
655
|
+
sync(entityId?: string): Promise<void>;
|
|
656
|
+
/**
|
|
657
|
+
* Clears the parsed vector cache. Useful for mid-loop flush guarantees
|
|
658
|
+
* or memory pressure evictions.
|
|
659
|
+
*/
|
|
660
|
+
evictCache(entityId?: string): void;
|
|
661
|
+
/**
|
|
662
|
+
* Fully resets the search service.
|
|
663
|
+
*/
|
|
664
|
+
clearAll(): void;
|
|
665
|
+
/**
|
|
666
|
+
* Executes a keyword search against the active MiniSearch index.
|
|
667
|
+
*/
|
|
668
|
+
searchKeyword(query: string, entityIds: string[], limit: number): SearchResult[];
|
|
669
|
+
/**
|
|
670
|
+
* Pre-fetches MiniSearch scores for candidate hydration, used during hybrid weighting.
|
|
671
|
+
*/
|
|
672
|
+
getMiniSearchScores(query: string, entityIds: string[], preFilterLimit?: number): Map<string, number>;
|
|
673
|
+
/**
|
|
674
|
+
* Score candidate rows using in-process JS cosine similarity.
|
|
675
|
+
* Applies hybrid blending (if weight set) and tie-break sorting before returning.
|
|
676
|
+
*/
|
|
677
|
+
rankSemantic(args: RankSemanticArgs): Promise<ScoredRow[]>;
|
|
678
|
+
private rebuildIndex;
|
|
679
|
+
private normalizeMiniSearchRow;
|
|
680
|
+
private _tieBreakSort;
|
|
681
|
+
private _compareScoredRows;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
type OperationType = 'prune' | 'librarian' | 'heal' | 'ingest' | 'reembed' | 'global_reembed' | 'import' | 'global_import' | 'forget';
|
|
685
|
+
declare class JobManager {
|
|
686
|
+
private prefix;
|
|
687
|
+
private activeMaintenanceJobs;
|
|
688
|
+
private activeIngestJobs;
|
|
689
|
+
private statusSubscribers;
|
|
690
|
+
constructor(prefix: string);
|
|
691
|
+
private _pruneKey;
|
|
692
|
+
private _reembedKey;
|
|
693
|
+
private _globalReembedKey;
|
|
694
|
+
private _importKey;
|
|
695
|
+
private _globalImportKey;
|
|
696
|
+
private _forgetKey;
|
|
697
|
+
private _librarianKey;
|
|
698
|
+
private _healKey;
|
|
699
|
+
private _isReembedActive;
|
|
700
|
+
private _isImportActiveFor;
|
|
701
|
+
private _isForgetActiveFor;
|
|
702
|
+
private _isAnyMaintenanceActiveWithSuffix;
|
|
703
|
+
private _hasIngestJob;
|
|
704
|
+
private _addIngestJob;
|
|
705
|
+
private _removeIngestJob;
|
|
706
|
+
private _isIngestActiveFor;
|
|
707
|
+
acquireLock(operation: OperationType, entityId: string, sourceRef?: string): void;
|
|
708
|
+
releaseLock(operation: OperationType, entityId: string, sourceRef?: string): void;
|
|
709
|
+
/**
|
|
710
|
+
* Returns true if acquireLock(operation, entityId) would throw WikiBusyError.
|
|
711
|
+
* Use for non-throwing conflict checks (e.g. auto-trigger gating in write()).
|
|
712
|
+
*/
|
|
713
|
+
isBlocked(operation: OperationType, entityId: string): boolean;
|
|
714
|
+
/**
|
|
715
|
+
* Auto-heal historically only gated on the heal self-key. Keep that behavior
|
|
716
|
+
* for write() auto-trigger paths while preserving stricter checks in acquireLock().
|
|
717
|
+
*/
|
|
718
|
+
tryAcquireAutoHealLock(entityId: string): boolean;
|
|
719
|
+
/**
|
|
720
|
+
* Validates then acquires global + per-entity import locks atomically.
|
|
721
|
+
* Validates all entities before acquiring any lock (same as current importDump semantics).
|
|
722
|
+
*/
|
|
723
|
+
acquireImportLocks(entityIds: string[]): void;
|
|
724
|
+
releaseImportLocks(entityIds: string[]): void;
|
|
725
|
+
getEntityStatus(entityId: string): EntityStatus;
|
|
726
|
+
subscribeEntityStatus(entityId: string, callback: (status: EntityStatus) => void): () => void;
|
|
727
|
+
private _copyEntityStatus;
|
|
728
|
+
private _notifyStatusSubscribers;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
declare class EmbeddingService {
|
|
732
|
+
private db;
|
|
733
|
+
private options;
|
|
734
|
+
private entryRepo;
|
|
735
|
+
private metadataRepo;
|
|
736
|
+
constructor(db: SQLiteAdapter, options: WikiOptions, entryRepo: EntryRepository, metadataRepo: MetadataRepository);
|
|
737
|
+
storeEmbeddingDimension(dim: number): Promise<void>;
|
|
738
|
+
/** Promotes embedding_dimension_mismatch to canonical embedding_dimension when safe. */
|
|
739
|
+
reconcileEmbeddingDimension(): Promise<void>;
|
|
740
|
+
embedFact(fact: {
|
|
741
|
+
id: string;
|
|
742
|
+
entity_id: string;
|
|
743
|
+
title: string;
|
|
744
|
+
body: string;
|
|
745
|
+
tags: string | string[];
|
|
746
|
+
}): Promise<boolean>;
|
|
747
|
+
notifyEmbeddingPersisted(entityId: string, factId: string, vector: Float32Array | null): Promise<void>;
|
|
748
|
+
notifyEmbeddingPersistedOrThrow(entityId: string, factId: string, vector: Float32Array | null): Promise<void>;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
declare class PromptService {
|
|
752
|
+
private globalOverrides?;
|
|
753
|
+
constructor(globalOverrides?: PromptOverrides | undefined);
|
|
754
|
+
private hydrate;
|
|
755
|
+
buildIngestPrompt(documentChunk: string, runtimeOverride?: string): {
|
|
756
|
+
systemPrompt: string;
|
|
757
|
+
userPrompt: string;
|
|
758
|
+
};
|
|
759
|
+
buildLibrarianPrompt(events: unknown[], currentFacts: unknown[], runtimeOverride?: string): {
|
|
760
|
+
systemPrompt: string;
|
|
761
|
+
userPrompt: string;
|
|
762
|
+
};
|
|
763
|
+
buildHealPrompt(healCandidates: unknown[], documentAnchors: unknown[], allTasks: unknown[], recentEvents: unknown[], runtimeOverride?: string): {
|
|
764
|
+
systemPrompt: string;
|
|
765
|
+
userPrompt: string;
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
declare class IngestionService {
|
|
770
|
+
private db;
|
|
771
|
+
private prefix;
|
|
772
|
+
private options;
|
|
773
|
+
private entryRepo;
|
|
774
|
+
private searchService;
|
|
775
|
+
private jobManager;
|
|
776
|
+
private embeddingService;
|
|
777
|
+
private promptService;
|
|
778
|
+
constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService);
|
|
779
|
+
ingestDocument(entityId: string, params: {
|
|
780
|
+
sourceRef: string;
|
|
781
|
+
sourceHash: string;
|
|
782
|
+
documentChunk: string;
|
|
783
|
+
maxChunkLength?: number;
|
|
784
|
+
chunkOverlap?: number;
|
|
785
|
+
chunkConcurrency?: number;
|
|
786
|
+
promptOverride?: string;
|
|
787
|
+
}): Promise<{
|
|
788
|
+
truncated: boolean;
|
|
789
|
+
chunks: number;
|
|
790
|
+
}>;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
declare class TaskRepository extends BaseRepository {
|
|
794
|
+
private outbox;
|
|
795
|
+
constructor(db: SQLiteAdapter, prefix: string, outbox: OutboxRepository);
|
|
796
|
+
/**
|
|
797
|
+
* Fetch a single task by ID. Returns null if not found or soft-deleted.
|
|
798
|
+
*/
|
|
799
|
+
findById(id: string): Promise<WikiTask | null>;
|
|
800
|
+
/**
|
|
801
|
+
* Fetch all pending/in_progress tasks for the given entity IDs.
|
|
802
|
+
* Returns empty array when entityIds is empty.
|
|
803
|
+
*/
|
|
804
|
+
findAllPending(entityIds: string[], limit?: number): Promise<WikiTask[]>;
|
|
805
|
+
findExistingMetadataByIds(ids: readonly string[], tx?: SQLiteAdapter): Promise<Array<{
|
|
806
|
+
id: string;
|
|
807
|
+
entity_id: string;
|
|
808
|
+
updated_at: number;
|
|
809
|
+
}>>;
|
|
810
|
+
/**
|
|
811
|
+
* Upsert a WikiTask within the provided transaction.
|
|
812
|
+
* Uses ON CONFLICT(id) DO UPDATE (not INSERT OR REPLACE).
|
|
813
|
+
* Stages an outbox entry in the same transaction.
|
|
814
|
+
* `tx` is REQUIRED.
|
|
815
|
+
*/
|
|
816
|
+
upsert(task: WikiTask, tx: SQLiteAdapter, updatedAt?: number): Promise<void>;
|
|
817
|
+
upsertForImport(task: WikiTask, tx: SQLiteAdapter, updatedAt?: number): Promise<void>;
|
|
818
|
+
/**
|
|
819
|
+
* Soft-delete a task by ID. Sets deleted_at and updated_at.
|
|
820
|
+
* Stages a DELETE outbox entry in the same transaction.
|
|
821
|
+
* `tx` is REQUIRED.
|
|
822
|
+
*/
|
|
823
|
+
softDelete(id: string, entityId: string, tx: SQLiteAdapter): Promise<void>;
|
|
824
|
+
/**
|
|
825
|
+
* Fetch all non-deleted tasks for an entity, ordered by priority DESC, created_at ASC.
|
|
826
|
+
* Used by _getFullBundle().
|
|
827
|
+
*/
|
|
828
|
+
findAllByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<WikiTask[]>;
|
|
829
|
+
/**
|
|
830
|
+
* Bulk delete pruned tasks (already soft-deleted) by cutoff date.
|
|
831
|
+
* Used by runPrune(). Returns number of deleted rows.
|
|
832
|
+
*/
|
|
833
|
+
bulkDeletePruned(entityId: string, cutoff: number, tx: SQLiteAdapter): Promise<number>;
|
|
834
|
+
/**
|
|
835
|
+
* Soft-delete a task by ID within a transaction.
|
|
836
|
+
* Stages a DELETE outbox entry in the same transaction.
|
|
837
|
+
* `tx` is REQUIRED.
|
|
838
|
+
*/
|
|
839
|
+
softDeleteById(id: string, entityId: string, tx: SQLiteAdapter): Promise<{
|
|
840
|
+
changes: number;
|
|
841
|
+
}>;
|
|
842
|
+
/**
|
|
843
|
+
* Bulk soft-delete all tasks for an entity.
|
|
844
|
+
* Stages DELETE outbox entries for each row in the same transaction.
|
|
845
|
+
* `tx` is REQUIRED.
|
|
846
|
+
*/
|
|
847
|
+
bulkSoftDeleteByEntityId(entityId: string, tx: SQLiteAdapter): Promise<number>;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
declare class EventRepository extends BaseRepository {
|
|
851
|
+
/**
|
|
852
|
+
* Insert a new event row.
|
|
853
|
+
* Pass `tx` to participate in a caller-owned transaction; omit to run against the default db.
|
|
854
|
+
*/
|
|
855
|
+
add(event: WikiEvent, tx?: SQLiteAdapter): Promise<void>;
|
|
856
|
+
addIgnoreDuplicate(event: WikiEvent, tx?: SQLiteAdapter): Promise<void>;
|
|
857
|
+
/**
|
|
858
|
+
* Return the most recent events for an entity, newest first.
|
|
859
|
+
* Defaults to a limit of 50.
|
|
860
|
+
*/
|
|
861
|
+
getRecent(entityId: string, limit?: number): Promise<WikiEvent[]>;
|
|
862
|
+
/**
|
|
863
|
+
* Return the most recent events for the given entity IDs, newest first.
|
|
864
|
+
* Defaults to a limit of 50.
|
|
865
|
+
*/
|
|
866
|
+
getRecentForEntities(entityIds: string[], limit?: number): Promise<WikiEvent[]>;
|
|
867
|
+
/**
|
|
868
|
+
* Delete events for an entity that were created at or before the given cutoff timestamp.
|
|
869
|
+
* Returns the number of deleted rows.
|
|
870
|
+
*/
|
|
871
|
+
prune(entityId: string, cutoff: number): Promise<{
|
|
872
|
+
changes: number;
|
|
873
|
+
}>;
|
|
874
|
+
/**
|
|
875
|
+
* Return the total number of events stored for an entity.
|
|
876
|
+
* `tx` is optional — pass an active transaction handle for atomic reads.
|
|
877
|
+
*/
|
|
878
|
+
count(entityId: string, tx?: SQLiteAdapter): Promise<number>;
|
|
879
|
+
/**
|
|
880
|
+
* Return all events for an entity in chronological (ASC) order.
|
|
881
|
+
* When limit is provided, fetches newest-first then reverses to preserve chronological order.
|
|
882
|
+
*/
|
|
883
|
+
getByEntityId(entityId: string, limit?: number): Promise<WikiEvent[]>;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
declare class MaintenanceService {
|
|
887
|
+
private db;
|
|
888
|
+
private prefix;
|
|
889
|
+
private options;
|
|
890
|
+
private entryRepo;
|
|
891
|
+
private taskRepo;
|
|
892
|
+
private eventRepo;
|
|
893
|
+
private metadataRepo;
|
|
894
|
+
private searchService;
|
|
895
|
+
private jobManager;
|
|
896
|
+
private embeddingService;
|
|
897
|
+
private promptService;
|
|
898
|
+
constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService);
|
|
899
|
+
runPrune(entityId: string, options?: {
|
|
900
|
+
retainSoftDeletedFor?: number | null;
|
|
901
|
+
retainEventsFor?: number | null;
|
|
902
|
+
vacuum?: boolean;
|
|
903
|
+
}): Promise<{
|
|
904
|
+
entries: number;
|
|
905
|
+
tasks: number;
|
|
906
|
+
events: number;
|
|
907
|
+
}>;
|
|
908
|
+
runLibrarian(entityId: string, options?: {
|
|
909
|
+
promptOverride?: string;
|
|
910
|
+
}): Promise<void>;
|
|
911
|
+
runHeal(entityId: string, options?: {
|
|
912
|
+
promptOverride?: string;
|
|
913
|
+
}): Promise<void>;
|
|
914
|
+
runReembed(entityId?: string, opts?: {
|
|
915
|
+
force?: boolean;
|
|
916
|
+
skipExisting?: boolean;
|
|
917
|
+
}): Promise<{
|
|
918
|
+
embedded: number;
|
|
919
|
+
skipped: number;
|
|
920
|
+
failed: number;
|
|
921
|
+
}>;
|
|
922
|
+
forget(entityId: string, params: {
|
|
923
|
+
entryId?: string;
|
|
924
|
+
taskId?: string;
|
|
925
|
+
sourceRef?: string;
|
|
926
|
+
sourceHash?: string;
|
|
927
|
+
clearAll?: boolean;
|
|
928
|
+
}): Promise<{
|
|
929
|
+
deleted: {
|
|
930
|
+
entries: number;
|
|
931
|
+
tasks: number;
|
|
932
|
+
};
|
|
933
|
+
}>;
|
|
934
|
+
/** Core librarian pass (locks handled by {@link runLibrarian}). Package-internal orchestration hook. */
|
|
935
|
+
doRunLibrarian(entityId: string, promptOverride?: string): Promise<void>;
|
|
936
|
+
/** Core heal pass (locks handled by {@link runHeal}). Package-internal orchestration hook. */
|
|
937
|
+
doRunHeal(entityId: string, promptOverride?: string): Promise<void>;
|
|
938
|
+
private _validatePruneDuration;
|
|
939
|
+
private _sanitizeRankerError;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
declare class ImportExportService {
|
|
943
|
+
private db;
|
|
944
|
+
private entryRepo;
|
|
945
|
+
private taskRepo;
|
|
946
|
+
private eventRepo;
|
|
947
|
+
private metadataRepo;
|
|
948
|
+
private searchService;
|
|
949
|
+
private jobManager;
|
|
950
|
+
private embeddingService;
|
|
951
|
+
constructor(db: SQLiteAdapter, entryRepo: EntryRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService);
|
|
952
|
+
exportDump(entityIds?: string[]): Promise<MemoryDump>;
|
|
953
|
+
importDump(dump: MemoryDump, opts?: {
|
|
954
|
+
merge?: boolean;
|
|
955
|
+
}): Promise<void>;
|
|
956
|
+
getFullBundle(entityId: string, opts?: {
|
|
957
|
+
maxEvents?: number;
|
|
958
|
+
includeBlobs?: boolean;
|
|
959
|
+
}): Promise<MemoryBundle>;
|
|
960
|
+
/** Single-entity import transaction + post-processing; package-internal hook for tests. */
|
|
961
|
+
doImportEntity(entityId: string, bundle: MemoryBundle, merge: boolean): Promise<void>;
|
|
962
|
+
private _warnCrossEntityCollision;
|
|
963
|
+
private _normalizeImportedSourceType;
|
|
964
|
+
assertNoLegacySourceTypes(): Promise<void>;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
declare class RetrievalService {
|
|
968
|
+
private options;
|
|
969
|
+
private entryRepo;
|
|
970
|
+
private taskRepo;
|
|
971
|
+
private eventRepo;
|
|
972
|
+
private metadataRepo;
|
|
973
|
+
private searchService;
|
|
974
|
+
constructor(options: WikiOptions, entryRepo: EntryRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService);
|
|
975
|
+
read(entityId: string | string[], query: string, options?: ReadOptions): Promise<MemoryBundle>;
|
|
976
|
+
/**
|
|
977
|
+
* Returns entity IDs that will participate in scored retrieval.
|
|
978
|
+
* Excludes zero-weight entities unless includeZeroWeightEntities is true.
|
|
979
|
+
*/
|
|
980
|
+
private _filterScoredEntities;
|
|
981
|
+
/**
|
|
982
|
+
* Stable tie-break sort: score desc → access_count desc → updated_at desc → id asc.
|
|
983
|
+
*/
|
|
984
|
+
private _tieBreakSort;
|
|
985
|
+
/**
|
|
986
|
+
* Comparator for score + deterministic tie-break fields.
|
|
987
|
+
* Negative return means "a ranks ahead of b" for descending score order.
|
|
988
|
+
*/
|
|
989
|
+
private _compareScoredRows;
|
|
990
|
+
/**
|
|
991
|
+
* Hydrate full facts by ID. Pass scopedEntityIds to restrict to requested namespaces in SQL
|
|
992
|
+
* (defense-in-depth against a rogue VectorRanker returning cross-entity IDs).
|
|
993
|
+
*/
|
|
994
|
+
private _hydrateFactsByIds;
|
|
995
|
+
private _sanitizeRankerError;
|
|
996
|
+
/**
|
|
997
|
+
* Delegate semantic ranking to the injected VectorRanker.
|
|
998
|
+
* Caller should pass an oversampledLimit to preserve recall after re-ranking.
|
|
999
|
+
* Returns scored results ready for hybrid blending and tie-break sorting.
|
|
1000
|
+
*/
|
|
1001
|
+
private _rankWithVectorRanker;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
declare class WriteService {
|
|
1005
|
+
private db;
|
|
1006
|
+
private options;
|
|
1007
|
+
private eventRepo;
|
|
1008
|
+
private metadataRepo;
|
|
1009
|
+
private jobManager;
|
|
1010
|
+
private maintenanceService;
|
|
1011
|
+
constructor(db: SQLiteAdapter, options: WikiOptions, eventRepo: EventRepository, metadataRepo: MetadataRepository, jobManager: JobManager, maintenanceService: MaintenanceService);
|
|
1012
|
+
write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
|
|
1013
|
+
private runLibrarianThenMaybeHeal;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/** Typed escape hatch for tests — not part of the supported consumer API. */
|
|
1017
|
+
interface WikiMemoryTestAccess {
|
|
1018
|
+
embeddingService: EmbeddingService;
|
|
1019
|
+
importExportService: ImportExportService;
|
|
1020
|
+
ingestionService: IngestionService;
|
|
1021
|
+
maintenanceService: MaintenanceService;
|
|
1022
|
+
retrievalService: RetrievalService;
|
|
1023
|
+
searchService: SearchService;
|
|
1024
|
+
writeService: WriteService;
|
|
1025
|
+
promptService: PromptService;
|
|
1026
|
+
entryRepo: EntryRepository;
|
|
1027
|
+
metadataRepo: MetadataRepository;
|
|
1028
|
+
jobManager: JobManager;
|
|
1029
|
+
}
|
|
1030
|
+
declare class WikiMemory {
|
|
1031
|
+
#private;
|
|
1032
|
+
private db;
|
|
1033
|
+
private prefix;
|
|
1034
|
+
private options;
|
|
1035
|
+
private entryRepo;
|
|
1036
|
+
private outboxRepo;
|
|
1037
|
+
private taskRepo;
|
|
1038
|
+
private eventRepo;
|
|
1039
|
+
private metadataRepo;
|
|
1040
|
+
private embeddingService;
|
|
1041
|
+
private searchService;
|
|
1042
|
+
private jobManager;
|
|
1043
|
+
private ingestionService;
|
|
1044
|
+
private maintenanceService;
|
|
1045
|
+
private importExportService;
|
|
1046
|
+
private retrievalService;
|
|
1047
|
+
private writeService;
|
|
1048
|
+
private promptService;
|
|
1049
|
+
constructor(db: SQLiteAdapter, options: WikiOptions);
|
|
1050
|
+
/**
|
|
1051
|
+
* Explicit escape hatch for test suites: typed access to composed services for mocks/spies.
|
|
1052
|
+
* If `NODE_ENV` is not `"test"`, emits a single `console.warn` per instance (skipped when `process` is undefined).
|
|
1053
|
+
*/
|
|
1054
|
+
get __testAccess(): WikiMemoryTestAccess;
|
|
1055
|
+
setup(): Promise<void>;
|
|
1056
|
+
hasChanged(entityId: string, sourceRef: string, sourceHash: string): Promise<boolean>;
|
|
1057
|
+
runPrune(entityId: string, options?: {
|
|
1058
|
+
retainSoftDeletedFor?: number | null;
|
|
1059
|
+
retainEventsFor?: number | null;
|
|
1060
|
+
vacuum?: boolean;
|
|
1061
|
+
}): Promise<{
|
|
1062
|
+
entries: number;
|
|
1063
|
+
tasks: number;
|
|
1064
|
+
events: number;
|
|
1065
|
+
}>;
|
|
1066
|
+
read(entityId: string | string[], query: string, options?: ReadOptions): Promise<MemoryBundle>;
|
|
1067
|
+
getMemoryBundle(entityId: string): Promise<MemoryBundle>;
|
|
1068
|
+
write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
|
|
1069
|
+
/**
|
|
1070
|
+
* @param options.promptOverride - Applies only to this manual call. Does NOT affect
|
|
1071
|
+
* WriteService-triggered auto-runs. For persistent prompt customization across auto-runs,
|
|
1072
|
+
* set `options.config.prompts.librarianSystemPrompt` at WikiMemory construction time.
|
|
1073
|
+
*/
|
|
1074
|
+
runLibrarian(entityId: string, options?: {
|
|
1075
|
+
promptOverride?: string;
|
|
1076
|
+
}): Promise<void>;
|
|
1077
|
+
/**
|
|
1078
|
+
* @param options.promptOverride - Applies only to this manual call. Does NOT affect
|
|
1079
|
+
* WriteService-triggered auto-runs. For persistent prompt customization across auto-runs,
|
|
1080
|
+
* set `options.config.prompts.healSystemPrompt` at WikiMemory construction time.
|
|
1081
|
+
*/
|
|
1082
|
+
runHeal(entityId: string, options?: {
|
|
1083
|
+
promptOverride?: string;
|
|
1084
|
+
}): Promise<void>;
|
|
1085
|
+
runReembed(entityId?: string, opts?: {
|
|
1086
|
+
force?: boolean;
|
|
1087
|
+
skipExisting?: boolean;
|
|
1088
|
+
}): Promise<{
|
|
1089
|
+
embedded: number;
|
|
1090
|
+
skipped: number;
|
|
1091
|
+
failed: number;
|
|
1092
|
+
}>;
|
|
1093
|
+
getEntityStatus(entityId: string): EntityStatus;
|
|
1094
|
+
subscribeEntityStatus(entityId: string, callback: (status: EntityStatus) => void): () => void;
|
|
1095
|
+
clearVectorCache(): void;
|
|
1096
|
+
exportDump(entityIds?: string[]): Promise<MemoryDump>;
|
|
1097
|
+
importDump(dump: MemoryDump, opts?: {
|
|
1098
|
+
merge?: boolean;
|
|
1099
|
+
}): Promise<void>;
|
|
1100
|
+
forget(entityId: string, params: {
|
|
1101
|
+
entryId?: string;
|
|
1102
|
+
taskId?: string;
|
|
1103
|
+
sourceRef?: string;
|
|
1104
|
+
sourceHash?: string;
|
|
1105
|
+
clearAll?: boolean;
|
|
1106
|
+
}): Promise<{
|
|
1107
|
+
deleted: {
|
|
1108
|
+
entries: number;
|
|
1109
|
+
tasks: number;
|
|
1110
|
+
};
|
|
1111
|
+
}>;
|
|
1112
|
+
/**
|
|
1113
|
+
* @param params.promptOverride - Overrides the system prompt for this ingest call only.
|
|
1114
|
+
* For persistent customization, set `options.config.prompts.ingestSystemPrompt` at
|
|
1115
|
+
* WikiMemory construction time.
|
|
1116
|
+
*/
|
|
1117
|
+
ingestDocument(entityId: string, params: {
|
|
1118
|
+
sourceRef: string;
|
|
1119
|
+
sourceHash: string;
|
|
1120
|
+
documentChunk: string;
|
|
1121
|
+
maxChunkLength?: number;
|
|
1122
|
+
chunkOverlap?: number;
|
|
1123
|
+
chunkConcurrency?: number;
|
|
1124
|
+
promptOverride?: string;
|
|
1125
|
+
}): Promise<{
|
|
1126
|
+
truncated: boolean;
|
|
1127
|
+
chunks: number;
|
|
1128
|
+
}>;
|
|
1129
|
+
/**
|
|
1130
|
+
* Returns up to `limit` unprocessed outbox events, oldest first.
|
|
1131
|
+
* Works regardless of enableOutbox value — allows draining after disabling.
|
|
1132
|
+
*/
|
|
1133
|
+
getUnprocessedOutboxEvents(limit?: number): Promise<WikiOutboxEvent[]>;
|
|
1134
|
+
/**
|
|
1135
|
+
* Deletes the given event IDs from the outbox table.
|
|
1136
|
+
* Call after successfully committing events to the external system.
|
|
1137
|
+
*/
|
|
1138
|
+
markOutboxEventsProcessed(eventIds: string[]): Promise<void>;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
export { type EntityStatus as E, type FormatContextOptions as F, HOOK_TIMEOUT_MARKER as H, ImportExportService as I, JobManager as J, type LLMProvider as L, type MemoryBundle as M, type PromptOverrides as P, type ReadOptions as R, type SQLiteAdapter as S, type VectorRanker as V, type WikiOptions as W, type MemoryDump as a, type FormattedMemoryDump as b, WikiMemory as c, type ExtractedFact as d, type ExtractedTask as e, PromptService as f, PrunePartialFailureError as g, type VectorRankerFallback as h, type VectorRankerRankArgs as i, type VectorRankerSemanticResult as j, WikiBusyError as k, type WikiBusyOperation as l, type WikiCheckpoint as m, type WikiConfig as n, type WikiEvent as o, type WikiFact as p, type WikiMemoryTestAccess as q, type WikiOutboxEvent as r, type WikiTask as s, EmbeddingService as t, IngestionService as u, MaintenanceService as v, RetrievalService as w, SearchService as x, WriteService as y };
|