@equationalapplications/core-llm-wiki 2.4.0 → 2.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/dist/index.d.mts CHANGED
@@ -16,6 +16,8 @@ interface SQLiteAdapter {
16
16
  }
17
17
  interface WikiConfig {
18
18
  tablePrefix?: string;
19
+ maxResults?: number;
20
+ /** @deprecated Use maxResults */
19
21
  maxFtsResults?: number;
20
22
  pruneEventsAfter?: number;
21
23
  pruneRetainSoftDeletedFor?: number;
@@ -26,15 +28,6 @@ interface WikiConfig {
26
28
  maxChunkLength?: number;
27
29
  chunkOverlap?: number;
28
30
  chunkConcurrency?: number;
29
- /**
30
- * Static caller-supplied synonym expansions applied at query time.
31
- * Keys must match the same normalization pipeline used by query formatting:
32
- * the query is lowercased, stripped to `[a-z0-9 ]`, split into tokens, and
33
- * only tokens with length >= 3 are considered for synonym lookup.
34
- * Values are appended to the FTS5 query token list (multi-word values are
35
- * split into tokens), then deduped and sliced to 12.
36
- */
37
- synonymMap?: Record<string, string[]>;
38
31
  }
39
32
  interface WikiFact {
40
33
  id: string;
@@ -95,10 +88,28 @@ interface LLMProvider {
95
88
  systemPrompt: string;
96
89
  userPrompt: string;
97
90
  }) => Promise<string>;
91
+ /**
92
+ * Optional. When provided, enables semantic similarity search in `read()`.
93
+ * Must return a stable-dimension float array for any input text.
94
+ * Called once per fact on creation/update, and once per `read()` query.
95
+ * When absent or throws, `read()` falls back to MiniSearch.
96
+ */
97
+ embed?: (text: string) => Promise<number[]>;
98
98
  }
99
99
  interface WikiOptions {
100
100
  config?: WikiConfig;
101
101
  llmProvider: LLMProvider;
102
+ /**
103
+ * Called when embedding-based retrieval is unavailable during `read()` and
104
+ * MiniSearch keyword search is used instead. This can happen when:
105
+ * - `embed()` throws (e.g. network error, model unavailable)
106
+ * - `embed()` returns a vector with non-finite values (NaN / Infinity)
107
+ * - The query vector's dimension doesn't match stored embeddings (model switch;
108
+ * resolve by calling `runReembed()`)
109
+ *
110
+ * `read()` still returns keyword-search results — this is a notification, not an error path.
111
+ */
112
+ onRetrievalFallback?: (error: Error) => void;
102
113
  }
103
114
  interface MemoryBundle {
104
115
  facts: WikiFact[];
@@ -135,9 +146,9 @@ interface EntityStatus {
135
146
  heal: boolean;
136
147
  }
137
148
  declare class WikiBusyError extends Error {
138
- readonly operation: 'ingest' | 'librarian' | 'heal' | 'prune';
149
+ readonly operation: 'ingest' | 'librarian' | 'heal' | 'prune' | 'reembed';
139
150
  readonly entityId: string;
140
- constructor(operation: 'ingest' | 'librarian' | 'heal' | 'prune', entityId: string);
151
+ constructor(operation: 'ingest' | 'librarian' | 'heal' | 'prune' | 'reembed', entityId: string);
141
152
  }
142
153
 
143
154
  declare class WikiMemory {
@@ -146,6 +157,19 @@ declare class WikiMemory {
146
157
  private options;
147
158
  private activeMaintenanceJobs;
148
159
  private activeIngestJobs;
160
+ private miniSearch;
161
+ private miniSearchEntryIdsByEntity;
162
+ private normalizeMiniSearchRow;
163
+ private rebuildMiniSearchIndex;
164
+ private storeEmbeddingDimension;
165
+ /**
166
+ * After a successful runReembed(), promote the pending `embedding_dimension_mismatch`
167
+ * value to the canonical `embedding_dimension` key and clear the mismatch flag.
168
+ * This ensures future read() calls use embedding-based retrieval rather than staying
169
+ * stuck on the MiniSearch fallback.
170
+ */
171
+ private _reconcileEmbeddingDimension;
172
+ private embedFact;
149
173
  private _librarianKey;
150
174
  private _healKey;
151
175
  private _warnCrossEntityCollision;
@@ -153,6 +177,13 @@ declare class WikiMemory {
153
177
  setup(): Promise<void>;
154
178
  hasChanged(entityId: string, sourceRef: string, sourceHash: string): Promise<boolean>;
155
179
  private _pruneKey;
180
+ private _reembedKey;
181
+ private _globalReembedKey;
182
+ private _isReembedActive;
183
+ /** Returns true if any maintenance job has the given operation suffix (e.g. ':prune'). */
184
+ private _isAnyMaintenanceActiveWithSuffix;
185
+ /** Returns true if any ingest job is active for the given entity. */
186
+ private _isIngestActiveFor;
156
187
  private _validatePruneDuration;
157
188
  runPrune(entityId: string, options?: {
158
189
  retainSoftDeletedFor?: number | null;
@@ -163,7 +194,6 @@ declare class WikiMemory {
163
194
  tasks: number;
164
195
  events: number;
165
196
  }>;
166
- private formatSearchQuery;
167
197
  read(entityId: string, query: string): Promise<MemoryBundle>;
168
198
  getMemoryBundle(entityId: string): Promise<MemoryBundle>;
169
199
  write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
@@ -172,6 +202,10 @@ declare class WikiMemory {
172
202
  private _doRunHeal;
173
203
  runLibrarian(entityId: string): Promise<void>;
174
204
  runHeal(entityId: string): Promise<void>;
205
+ runReembed(entityId?: string): Promise<{
206
+ embedded: number;
207
+ skipped: number;
208
+ }>;
175
209
  getEntityStatus(entityId: string): EntityStatus;
176
210
  private _getFullBundle;
177
211
  exportDump(entityIds?: string[]): Promise<MemoryDump>;
package/dist/index.d.ts CHANGED
@@ -16,6 +16,8 @@ interface SQLiteAdapter {
16
16
  }
17
17
  interface WikiConfig {
18
18
  tablePrefix?: string;
19
+ maxResults?: number;
20
+ /** @deprecated Use maxResults */
19
21
  maxFtsResults?: number;
20
22
  pruneEventsAfter?: number;
21
23
  pruneRetainSoftDeletedFor?: number;
@@ -26,15 +28,6 @@ interface WikiConfig {
26
28
  maxChunkLength?: number;
27
29
  chunkOverlap?: number;
28
30
  chunkConcurrency?: number;
29
- /**
30
- * Static caller-supplied synonym expansions applied at query time.
31
- * Keys must match the same normalization pipeline used by query formatting:
32
- * the query is lowercased, stripped to `[a-z0-9 ]`, split into tokens, and
33
- * only tokens with length >= 3 are considered for synonym lookup.
34
- * Values are appended to the FTS5 query token list (multi-word values are
35
- * split into tokens), then deduped and sliced to 12.
36
- */
37
- synonymMap?: Record<string, string[]>;
38
31
  }
39
32
  interface WikiFact {
40
33
  id: string;
@@ -95,10 +88,28 @@ interface LLMProvider {
95
88
  systemPrompt: string;
96
89
  userPrompt: string;
97
90
  }) => Promise<string>;
91
+ /**
92
+ * Optional. When provided, enables semantic similarity search in `read()`.
93
+ * Must return a stable-dimension float array for any input text.
94
+ * Called once per fact on creation/update, and once per `read()` query.
95
+ * When absent or throws, `read()` falls back to MiniSearch.
96
+ */
97
+ embed?: (text: string) => Promise<number[]>;
98
98
  }
99
99
  interface WikiOptions {
100
100
  config?: WikiConfig;
101
101
  llmProvider: LLMProvider;
102
+ /**
103
+ * Called when embedding-based retrieval is unavailable during `read()` and
104
+ * MiniSearch keyword search is used instead. This can happen when:
105
+ * - `embed()` throws (e.g. network error, model unavailable)
106
+ * - `embed()` returns a vector with non-finite values (NaN / Infinity)
107
+ * - The query vector's dimension doesn't match stored embeddings (model switch;
108
+ * resolve by calling `runReembed()`)
109
+ *
110
+ * `read()` still returns keyword-search results — this is a notification, not an error path.
111
+ */
112
+ onRetrievalFallback?: (error: Error) => void;
102
113
  }
103
114
  interface MemoryBundle {
104
115
  facts: WikiFact[];
@@ -135,9 +146,9 @@ interface EntityStatus {
135
146
  heal: boolean;
136
147
  }
137
148
  declare class WikiBusyError extends Error {
138
- readonly operation: 'ingest' | 'librarian' | 'heal' | 'prune';
149
+ readonly operation: 'ingest' | 'librarian' | 'heal' | 'prune' | 'reembed';
139
150
  readonly entityId: string;
140
- constructor(operation: 'ingest' | 'librarian' | 'heal' | 'prune', entityId: string);
151
+ constructor(operation: 'ingest' | 'librarian' | 'heal' | 'prune' | 'reembed', entityId: string);
141
152
  }
142
153
 
143
154
  declare class WikiMemory {
@@ -146,6 +157,19 @@ declare class WikiMemory {
146
157
  private options;
147
158
  private activeMaintenanceJobs;
148
159
  private activeIngestJobs;
160
+ private miniSearch;
161
+ private miniSearchEntryIdsByEntity;
162
+ private normalizeMiniSearchRow;
163
+ private rebuildMiniSearchIndex;
164
+ private storeEmbeddingDimension;
165
+ /**
166
+ * After a successful runReembed(), promote the pending `embedding_dimension_mismatch`
167
+ * value to the canonical `embedding_dimension` key and clear the mismatch flag.
168
+ * This ensures future read() calls use embedding-based retrieval rather than staying
169
+ * stuck on the MiniSearch fallback.
170
+ */
171
+ private _reconcileEmbeddingDimension;
172
+ private embedFact;
149
173
  private _librarianKey;
150
174
  private _healKey;
151
175
  private _warnCrossEntityCollision;
@@ -153,6 +177,13 @@ declare class WikiMemory {
153
177
  setup(): Promise<void>;
154
178
  hasChanged(entityId: string, sourceRef: string, sourceHash: string): Promise<boolean>;
155
179
  private _pruneKey;
180
+ private _reembedKey;
181
+ private _globalReembedKey;
182
+ private _isReembedActive;
183
+ /** Returns true if any maintenance job has the given operation suffix (e.g. ':prune'). */
184
+ private _isAnyMaintenanceActiveWithSuffix;
185
+ /** Returns true if any ingest job is active for the given entity. */
186
+ private _isIngestActiveFor;
156
187
  private _validatePruneDuration;
157
188
  runPrune(entityId: string, options?: {
158
189
  retainSoftDeletedFor?: number | null;
@@ -163,7 +194,6 @@ declare class WikiMemory {
163
194
  tasks: number;
164
195
  events: number;
165
196
  }>;
166
- private formatSearchQuery;
167
197
  read(entityId: string, query: string): Promise<MemoryBundle>;
168
198
  getMemoryBundle(entityId: string): Promise<MemoryBundle>;
169
199
  write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
@@ -172,6 +202,10 @@ declare class WikiMemory {
172
202
  private _doRunHeal;
173
203
  runLibrarian(entityId: string): Promise<void>;
174
204
  runHeal(entityId: string): Promise<void>;
205
+ runReembed(entityId?: string): Promise<{
206
+ embedded: number;
207
+ skipped: number;
208
+ }>;
175
209
  getEntityStatus(entityId: string): EntityStatus;
176
210
  private _getFullBundle;
177
211
  exportDump(entityIds?: string[]): Promise<MemoryDump>;