@equationalapplications/core-llm-wiki 4.15.3 → 4.17.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.
@@ -21,6 +21,54 @@ interface PromptOverrides {
21
21
  librarianSystemPrompt?: string;
22
22
  healSystemPrompt?: string;
23
23
  }
24
+ type OntologyMode = 'strict' | 'emergent' | 'off';
25
+ interface OntologyNodeType {
26
+ type: string;
27
+ description: string;
28
+ }
29
+ interface OntologyEdgeType {
30
+ type: string;
31
+ source_type: string;
32
+ target_type: string;
33
+ description: string;
34
+ }
35
+ /**
36
+ * Allowed node and edge types for an entity's ontology graph.
37
+ * Persisted per entity and injected into librarian/ingest prompts when mode ≠ `off`.
38
+ */
39
+ interface OntologyManifest {
40
+ node_types: OntologyNodeType[];
41
+ edge_types: OntologyEdgeType[];
42
+ }
43
+ /**
44
+ * Global ontology defaults and bootstrap manifests for known entities.
45
+ * Per-entity mode and manifest overrides are stored in SQLite and managed via
46
+ * `WikiMemory.getOntologyManifest` / `setOntologyManifest`.
47
+ */
48
+ interface OntologyConfig {
49
+ /** Global default mode. Default: `'off'` (backward compatible — no typed extraction). */
50
+ mode?: OntologyMode;
51
+ /**
52
+ * Bootstrap manifests for known entities at construction time.
53
+ * Written to the database on first access if no row exists for that entity.
54
+ */
55
+ seedManifests?: Record<string, {
56
+ manifest: OntologyManifest;
57
+ mode?: OntologyMode;
58
+ }>;
59
+ }
60
+ interface ExtractedFactEdge {
61
+ edge_type: string;
62
+ target_title: string;
63
+ }
64
+ interface OntologyUpdates {
65
+ node_types?: OntologyNodeType[];
66
+ edge_types?: OntologyEdgeType[];
67
+ }
68
+ interface OntologyPromptContext {
69
+ ontologyManifest: string;
70
+ ontologyModeInstructions: string;
71
+ }
24
72
  interface WikiConfig {
25
73
  /**
26
74
  * Prefix applied to every SQL table/index/trigger name. Must match
@@ -64,6 +112,15 @@ interface WikiConfig {
64
112
  * @default false
65
113
  */
66
114
  enableOutbox?: boolean;
115
+ ontology?: OntologyConfig;
116
+ /** Default node cap for traverseGraph(), unless overridden per-call. Default 20. */
117
+ maxTraversalNodes?: number;
118
+ /** Default minimum confidence tier for discovered traversal nodes. Default 'tentative'. */
119
+ minTraversalConfidence?: 'certain' | 'inferred' | 'tentative';
120
+ /** Default traversal direction. Default 'both'. */
121
+ traversalDirection?: 'inbound' | 'outbound' | 'both';
122
+ /** Default source_type dead-end list for discovered traversal nodes. Default []. */
123
+ excludeSourceTypes?: Array<WikiFact['source_type']>;
67
124
  }
68
125
  interface ReadOptions {
69
126
  maxResults?: number;
@@ -159,6 +216,30 @@ interface WikiEdge {
159
216
  edge_type: string;
160
217
  created_at: number;
161
218
  }
219
+ interface GraphTraversalOptions {
220
+ sourceId: string;
221
+ /** Hop count. Default 1. Clamped to [1, 3] regardless of input. */
222
+ maxDepth?: number;
223
+ /** Default 'both'. Falls back to WikiConfig.traversalDirection, then 'both'. */
224
+ direction?: 'inbound' | 'outbound' | 'both';
225
+ /**
226
+ * Allowed edge types. `undefined` = no filter (all types).
227
+ * `[]` (explicit empty array) = match nothing — distinct from `undefined`.
228
+ */
229
+ edgeTypes?: string[];
230
+ /** Total node cap (anchor + neighbors). Default 20 via WikiConfig.maxTraversalNodes. */
231
+ maxTraversalNodes?: number;
232
+ /** Minimum confidence tier for *discovered* nodes. Does not gate the anchor. Default 'tentative'. */
233
+ minTraversalConfidence?: 'certain' | 'inferred' | 'tentative';
234
+ /** source_type values to dead-end on for *discovered* nodes. Does not gate the anchor. Default []. */
235
+ excludeSourceTypes?: Array<WikiFact['source_type']>;
236
+ }
237
+ interface GraphNeighborhood {
238
+ /** Anchor node first, then discovered neighbors ordered by depth ASC, then updated_at DESC. */
239
+ nodes: WikiFact[];
240
+ /** Only edges where both endpoints are present in `nodes`. */
241
+ edges: WikiEdge[];
242
+ }
162
243
  interface WikiCheckpoint {
163
244
  entity_id: string;
164
245
  heal_checkpoint: number;
@@ -170,6 +251,10 @@ interface ExtractedFact {
170
251
  tags: string[];
171
252
  confidence: 'certain' | 'inferred' | 'tentative';
172
253
  }
254
+ interface ExtractedFactWithOntology extends ExtractedFact {
255
+ okf_type?: string;
256
+ edges?: ExtractedFactEdge[];
257
+ }
173
258
  interface ExtractedTask {
174
259
  description: string;
175
260
  priority: number;
@@ -627,6 +712,15 @@ declare class MetadataRepository extends BaseRepository {
627
712
  getTableDdl(tableName: string, tx?: SQLiteAdapter): Promise<string | null>;
628
713
  vacuum(): Promise<void>;
629
714
  getDistinctEntityIds(tx?: SQLiteAdapter): Promise<string[]>;
715
+ getManifest(entityId: string, tx?: SQLiteAdapter): Promise<{
716
+ mode: OntologyMode;
717
+ manifest: OntologyManifest;
718
+ } | null>;
719
+ setManifest(entityId: string, data: {
720
+ mode: OntologyMode;
721
+ manifest: OntologyManifest;
722
+ }, tx: SQLiteAdapter): Promise<void>;
723
+ mergeManifestUpdates(entityId: string, updates: OntologyUpdates, tx: SQLiteAdapter): Promise<OntologyManifest>;
630
724
  }
631
725
 
632
726
  interface ScoredRow {
@@ -778,15 +872,76 @@ declare class EmbeddingService {
778
872
  notifyEmbeddingPersistedOrThrow(entityId: string, factId: string, vector: Float32Array | null): Promise<void>;
779
873
  }
780
874
 
875
+ interface NeighborhoodQueryOptions {
876
+ maxDepth: number;
877
+ direction: 'inbound' | 'outbound' | 'both';
878
+ edgeTypes?: string[];
879
+ minConfidence: 'certain' | 'inferred' | 'tentative';
880
+ excludeSourceTypes: string[];
881
+ maxNodes: number;
882
+ }
883
+ declare class EdgeRepository extends BaseRepository {
884
+ /**
885
+ * Insert an edge, silently skipping on primary-key or uniqueness conflicts.
886
+ * Throws when the insert was skipped due to an id collision with a different edge tuple.
887
+ */
888
+ addIgnoreDuplicate(edge: WikiEdge, tx?: SQLiteAdapter): Promise<void>;
889
+ getByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<WikiEdge[]>;
890
+ /** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
891
+ bulkDeleteByEntityId(entityId: string, tx: SQLiteAdapter): Promise<void>;
892
+ /**
893
+ * Multi-hop traversal from `sourceId` via SQLite `WITH RECURSIVE`. All filtering,
894
+ * dead-ending, cycle-guarding, capping, and ordering happens in this one query.
895
+ * The anchor is validated (exists, right entity, not soft-deleted) but never gated
896
+ * by confidence/source_type — only nodes discovered beyond it are.
897
+ */
898
+ getNeighborhood(entityId: string, sourceId: string, opts: NeighborhoodQueryOptions, tx?: SQLiteAdapter): Promise<{
899
+ nodeIds: string[];
900
+ edges: WikiEdge[];
901
+ }>;
902
+ }
903
+
904
+ type TitleIndexEntry = {
905
+ id: string;
906
+ okf_type: string | null;
907
+ };
908
+ /**
909
+ * Coordinates ontology mode resolution, manifest caching, LLM output validation, and edge persistence.
910
+ * Cache is per WikiMemory instance (single-process); not shared across instances.
911
+ */
912
+ declare class OntologyService {
913
+ private metadataRepo;
914
+ private edgeRepo;
915
+ private ontologyConfig?;
916
+ private cache;
917
+ constructor(metadataRepo: MetadataRepository, edgeRepo: EdgeRepository, ontologyConfig?: OntologyConfig | undefined);
918
+ resolveMode(storedMode?: OntologyMode): OntologyMode;
919
+ invalidateCache(entityId: string): void;
920
+ getEffectiveState(entityId: string, tx?: SQLiteAdapter): Promise<{
921
+ mode: OntologyMode;
922
+ manifest: OntologyManifest;
923
+ }>;
924
+ buildPromptContext(entityId: string): Promise<OntologyPromptContext | null>;
925
+ mergeEmergentUpdates(entityId: string, updates: OntologyUpdates, tx: SQLiteAdapter): Promise<OntologyManifest>;
926
+ validateAndNormalizeFact(fact: ExtractedFactWithOntology, manifest: OntologyManifest): {
927
+ okf_type: string | null;
928
+ edges: ExtractedFactEdge[];
929
+ };
930
+ resolveAndPersistEdges(entityId: string, sourceId: string, sourceType: string | null, edges: ExtractedFactEdge[], manifest: OntologyManifest, titleIndex: Map<string, TitleIndexEntry>, tx: SQLiteAdapter, now: number): Promise<void>;
931
+ }
932
+
781
933
  declare class PromptService {
782
934
  private globalOverrides?;
783
935
  constructor(globalOverrides?: PromptOverrides | undefined);
784
936
  private hydrate;
785
- buildIngestPrompt(documentChunk: string, runtimeOverride?: string): {
937
+ private hasOntologyPlaceholders;
938
+ private buildSystemPrompt;
939
+ private appendOntology;
940
+ buildIngestPrompt(documentChunk: string, runtimeOverride?: string, ontologyContext?: OntologyPromptContext | null): {
786
941
  systemPrompt: string;
787
942
  userPrompt: string;
788
943
  };
789
- buildLibrarianPrompt(events: unknown[], currentFacts: unknown[], runtimeOverride?: string): {
944
+ buildLibrarianPrompt(events: unknown[], currentFacts: unknown[], runtimeOverride?: string, ontologyContext?: OntologyPromptContext | null): {
790
945
  systemPrompt: string;
791
946
  userPrompt: string;
792
947
  };
@@ -804,8 +959,9 @@ declare class IngestionService {
804
959
  private searchService;
805
960
  private jobManager;
806
961
  private embeddingService;
962
+ private ontologyService?;
807
963
  private promptService;
808
- constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService);
964
+ constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
809
965
  ingestDocument(entityId: string, params: {
810
966
  sourceRef: string;
811
967
  sourceHash: string;
@@ -924,8 +1080,9 @@ declare class MaintenanceService {
924
1080
  private searchService;
925
1081
  private jobManager;
926
1082
  private embeddingService;
1083
+ private ontologyService?;
927
1084
  private promptService;
928
- constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService);
1085
+ constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
929
1086
  runPrune(entityId: string, options?: {
930
1087
  retainSoftDeletedFor?: number | null;
931
1088
  retainEventsFor?: number | null;
@@ -969,17 +1126,6 @@ declare class MaintenanceService {
969
1126
  private _sanitizeRankerError;
970
1127
  }
971
1128
 
972
- declare class EdgeRepository extends BaseRepository {
973
- /**
974
- * Insert an edge, silently skipping on primary-key or uniqueness conflicts.
975
- * Throws when the insert was skipped due to an id collision with a different edge tuple.
976
- */
977
- addIgnoreDuplicate(edge: WikiEdge, tx?: SQLiteAdapter): Promise<void>;
978
- getByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<WikiEdge[]>;
979
- /** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
980
- bulkDeleteByEntityId(entityId: string, tx: SQLiteAdapter): Promise<void>;
981
- }
982
-
983
1129
  declare class ImportExportService {
984
1130
  private db;
985
1131
  private entryRepo;
@@ -1056,6 +1202,18 @@ declare class WriteService {
1056
1202
  private runLibrarianThenMaybeHeal;
1057
1203
  }
1058
1204
 
1205
+ /**
1206
+ * Pure orchestrator — no SQL. Merges WikiConfig defaults with per-call options,
1207
+ * delegates the recursive walk to EdgeRepository, then hydrates node IDs into facts.
1208
+ */
1209
+ declare class GraphTraversalService {
1210
+ private edgeRepo;
1211
+ private entryRepo;
1212
+ private config;
1213
+ constructor(edgeRepo: EdgeRepository, entryRepo: EntryRepository, config: WikiConfig);
1214
+ traverseGraph(entityId: string, options: GraphTraversalOptions): Promise<GraphNeighborhood>;
1215
+ }
1216
+
1059
1217
  /** Typed escape hatch for tests — not part of the supported consumer API. */
1060
1218
  interface WikiMemoryTestAccess {
1061
1219
  embeddingService: EmbeddingService;
@@ -1066,6 +1224,7 @@ interface WikiMemoryTestAccess {
1066
1224
  searchService: SearchService;
1067
1225
  writeService: WriteService;
1068
1226
  promptService: PromptService;
1227
+ graphTraversalService: GraphTraversalService;
1069
1228
  entryRepo: EntryRepository;
1070
1229
  metadataRepo: MetadataRepository;
1071
1230
  jobManager: JobManager;
@@ -1090,6 +1249,8 @@ declare class WikiMemory {
1090
1249
  private retrievalService;
1091
1250
  private writeService;
1092
1251
  private promptService;
1252
+ private ontologyService;
1253
+ private graphTraversalService;
1093
1254
  constructor(db: SQLiteAdapter, options: WikiOptions);
1094
1255
  /**
1095
1256
  * Explicit escape hatch for test suites: typed access to composed services for mocks/spies.
@@ -1108,6 +1269,7 @@ declare class WikiMemory {
1108
1269
  events: number;
1109
1270
  }>;
1110
1271
  read(entityId: string | string[], query: string, options?: ReadOptions): Promise<MemoryBundle>;
1272
+ traverseGraph(entityId: string, options: GraphTraversalOptions): Promise<GraphNeighborhood>;
1111
1273
  getMemoryBundle(entityId: string): Promise<MemoryBundle>;
1112
1274
  write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
1113
1275
  /**
@@ -1180,6 +1342,22 @@ declare class WikiMemory {
1180
1342
  * Call after successfully committing events to the external system.
1181
1343
  */
1182
1344
  markOutboxEventsProcessed(eventIds: string[]): Promise<void>;
1345
+ /**
1346
+ * Returns the effective ontology mode and manifest for an entity.
1347
+ * Resolution order: persisted DB row → `WikiConfig.ontology.seedManifests[entityId]` → `null`.
1348
+ */
1349
+ getOntologyManifest(entityId: string): Promise<{
1350
+ mode: OntologyMode;
1351
+ manifest: OntologyManifest;
1352
+ } | null>;
1353
+ /**
1354
+ * Seeds or replaces an entity's ontology manifest and optional mode override.
1355
+ * Validates manifest invariants (unique type slugs, edge endpoints reference node types).
1356
+ * Invalidates the in-memory ontology cache for this entity.
1357
+ */
1358
+ setOntologyManifest(entityId: string, manifest: OntologyManifest, options?: {
1359
+ mode?: OntologyMode;
1360
+ }): Promise<void>;
1183
1361
  }
1184
1362
 
1185
- 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 WikiEdge as o, type WikiEvent as p, type WikiFact as q, type WikiMemoryTestAccess as r, type WikiOutboxEvent as s, type WikiTask as t, EmbeddingService as u, IngestionService as v, MaintenanceService as w, RetrievalService as x, SearchService as y, WriteService as z };
1363
+ export { type WikiMemoryTestAccess as A, type WikiOutboxEvent as B, type WikiTask as C, EmbeddingService as D, type EntityStatus as E, type FormatContextOptions as F, type GraphNeighborhood as G, HOOK_TIMEOUT_MARKER as H, ImportExportService as I, IngestionService as J, JobManager as K, type LLMProvider as L, type MemoryBundle as M, MaintenanceService as N, type OntologyConfig as O, type PromptOverrides as P, RetrievalService as Q, type ReadOptions as R, type SQLiteAdapter as S, SearchService as T, WriteService as U, type VectorRanker as V, type WikiOptions as W, type MemoryDump as a, type FormattedMemoryDump as b, WikiMemory as c, type ExtractedFact as d, type ExtractedFactEdge as e, type ExtractedFactWithOntology as f, type ExtractedTask as g, type GraphTraversalOptions as h, type OntologyEdgeType as i, type OntologyManifest as j, type OntologyMode as k, type OntologyNodeType as l, type OntologyPromptContext as m, type OntologyUpdates as n, PromptService as o, PrunePartialFailureError as p, type VectorRankerFallback as q, type VectorRankerRankArgs as r, type VectorRankerSemanticResult as s, WikiBusyError as t, type WikiBusyOperation as u, type WikiCheckpoint as v, type WikiConfig as w, type WikiEdge as x, type WikiEvent as y, type WikiFact as z };
@@ -21,6 +21,54 @@ interface PromptOverrides {
21
21
  librarianSystemPrompt?: string;
22
22
  healSystemPrompt?: string;
23
23
  }
24
+ type OntologyMode = 'strict' | 'emergent' | 'off';
25
+ interface OntologyNodeType {
26
+ type: string;
27
+ description: string;
28
+ }
29
+ interface OntologyEdgeType {
30
+ type: string;
31
+ source_type: string;
32
+ target_type: string;
33
+ description: string;
34
+ }
35
+ /**
36
+ * Allowed node and edge types for an entity's ontology graph.
37
+ * Persisted per entity and injected into librarian/ingest prompts when mode ≠ `off`.
38
+ */
39
+ interface OntologyManifest {
40
+ node_types: OntologyNodeType[];
41
+ edge_types: OntologyEdgeType[];
42
+ }
43
+ /**
44
+ * Global ontology defaults and bootstrap manifests for known entities.
45
+ * Per-entity mode and manifest overrides are stored in SQLite and managed via
46
+ * `WikiMemory.getOntologyManifest` / `setOntologyManifest`.
47
+ */
48
+ interface OntologyConfig {
49
+ /** Global default mode. Default: `'off'` (backward compatible — no typed extraction). */
50
+ mode?: OntologyMode;
51
+ /**
52
+ * Bootstrap manifests for known entities at construction time.
53
+ * Written to the database on first access if no row exists for that entity.
54
+ */
55
+ seedManifests?: Record<string, {
56
+ manifest: OntologyManifest;
57
+ mode?: OntologyMode;
58
+ }>;
59
+ }
60
+ interface ExtractedFactEdge {
61
+ edge_type: string;
62
+ target_title: string;
63
+ }
64
+ interface OntologyUpdates {
65
+ node_types?: OntologyNodeType[];
66
+ edge_types?: OntologyEdgeType[];
67
+ }
68
+ interface OntologyPromptContext {
69
+ ontologyManifest: string;
70
+ ontologyModeInstructions: string;
71
+ }
24
72
  interface WikiConfig {
25
73
  /**
26
74
  * Prefix applied to every SQL table/index/trigger name. Must match
@@ -64,6 +112,15 @@ interface WikiConfig {
64
112
  * @default false
65
113
  */
66
114
  enableOutbox?: boolean;
115
+ ontology?: OntologyConfig;
116
+ /** Default node cap for traverseGraph(), unless overridden per-call. Default 20. */
117
+ maxTraversalNodes?: number;
118
+ /** Default minimum confidence tier for discovered traversal nodes. Default 'tentative'. */
119
+ minTraversalConfidence?: 'certain' | 'inferred' | 'tentative';
120
+ /** Default traversal direction. Default 'both'. */
121
+ traversalDirection?: 'inbound' | 'outbound' | 'both';
122
+ /** Default source_type dead-end list for discovered traversal nodes. Default []. */
123
+ excludeSourceTypes?: Array<WikiFact['source_type']>;
67
124
  }
68
125
  interface ReadOptions {
69
126
  maxResults?: number;
@@ -159,6 +216,30 @@ interface WikiEdge {
159
216
  edge_type: string;
160
217
  created_at: number;
161
218
  }
219
+ interface GraphTraversalOptions {
220
+ sourceId: string;
221
+ /** Hop count. Default 1. Clamped to [1, 3] regardless of input. */
222
+ maxDepth?: number;
223
+ /** Default 'both'. Falls back to WikiConfig.traversalDirection, then 'both'. */
224
+ direction?: 'inbound' | 'outbound' | 'both';
225
+ /**
226
+ * Allowed edge types. `undefined` = no filter (all types).
227
+ * `[]` (explicit empty array) = match nothing — distinct from `undefined`.
228
+ */
229
+ edgeTypes?: string[];
230
+ /** Total node cap (anchor + neighbors). Default 20 via WikiConfig.maxTraversalNodes. */
231
+ maxTraversalNodes?: number;
232
+ /** Minimum confidence tier for *discovered* nodes. Does not gate the anchor. Default 'tentative'. */
233
+ minTraversalConfidence?: 'certain' | 'inferred' | 'tentative';
234
+ /** source_type values to dead-end on for *discovered* nodes. Does not gate the anchor. Default []. */
235
+ excludeSourceTypes?: Array<WikiFact['source_type']>;
236
+ }
237
+ interface GraphNeighborhood {
238
+ /** Anchor node first, then discovered neighbors ordered by depth ASC, then updated_at DESC. */
239
+ nodes: WikiFact[];
240
+ /** Only edges where both endpoints are present in `nodes`. */
241
+ edges: WikiEdge[];
242
+ }
162
243
  interface WikiCheckpoint {
163
244
  entity_id: string;
164
245
  heal_checkpoint: number;
@@ -170,6 +251,10 @@ interface ExtractedFact {
170
251
  tags: string[];
171
252
  confidence: 'certain' | 'inferred' | 'tentative';
172
253
  }
254
+ interface ExtractedFactWithOntology extends ExtractedFact {
255
+ okf_type?: string;
256
+ edges?: ExtractedFactEdge[];
257
+ }
173
258
  interface ExtractedTask {
174
259
  description: string;
175
260
  priority: number;
@@ -627,6 +712,15 @@ declare class MetadataRepository extends BaseRepository {
627
712
  getTableDdl(tableName: string, tx?: SQLiteAdapter): Promise<string | null>;
628
713
  vacuum(): Promise<void>;
629
714
  getDistinctEntityIds(tx?: SQLiteAdapter): Promise<string[]>;
715
+ getManifest(entityId: string, tx?: SQLiteAdapter): Promise<{
716
+ mode: OntologyMode;
717
+ manifest: OntologyManifest;
718
+ } | null>;
719
+ setManifest(entityId: string, data: {
720
+ mode: OntologyMode;
721
+ manifest: OntologyManifest;
722
+ }, tx: SQLiteAdapter): Promise<void>;
723
+ mergeManifestUpdates(entityId: string, updates: OntologyUpdates, tx: SQLiteAdapter): Promise<OntologyManifest>;
630
724
  }
631
725
 
632
726
  interface ScoredRow {
@@ -778,15 +872,76 @@ declare class EmbeddingService {
778
872
  notifyEmbeddingPersistedOrThrow(entityId: string, factId: string, vector: Float32Array | null): Promise<void>;
779
873
  }
780
874
 
875
+ interface NeighborhoodQueryOptions {
876
+ maxDepth: number;
877
+ direction: 'inbound' | 'outbound' | 'both';
878
+ edgeTypes?: string[];
879
+ minConfidence: 'certain' | 'inferred' | 'tentative';
880
+ excludeSourceTypes: string[];
881
+ maxNodes: number;
882
+ }
883
+ declare class EdgeRepository extends BaseRepository {
884
+ /**
885
+ * Insert an edge, silently skipping on primary-key or uniqueness conflicts.
886
+ * Throws when the insert was skipped due to an id collision with a different edge tuple.
887
+ */
888
+ addIgnoreDuplicate(edge: WikiEdge, tx?: SQLiteAdapter): Promise<void>;
889
+ getByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<WikiEdge[]>;
890
+ /** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
891
+ bulkDeleteByEntityId(entityId: string, tx: SQLiteAdapter): Promise<void>;
892
+ /**
893
+ * Multi-hop traversal from `sourceId` via SQLite `WITH RECURSIVE`. All filtering,
894
+ * dead-ending, cycle-guarding, capping, and ordering happens in this one query.
895
+ * The anchor is validated (exists, right entity, not soft-deleted) but never gated
896
+ * by confidence/source_type — only nodes discovered beyond it are.
897
+ */
898
+ getNeighborhood(entityId: string, sourceId: string, opts: NeighborhoodQueryOptions, tx?: SQLiteAdapter): Promise<{
899
+ nodeIds: string[];
900
+ edges: WikiEdge[];
901
+ }>;
902
+ }
903
+
904
+ type TitleIndexEntry = {
905
+ id: string;
906
+ okf_type: string | null;
907
+ };
908
+ /**
909
+ * Coordinates ontology mode resolution, manifest caching, LLM output validation, and edge persistence.
910
+ * Cache is per WikiMemory instance (single-process); not shared across instances.
911
+ */
912
+ declare class OntologyService {
913
+ private metadataRepo;
914
+ private edgeRepo;
915
+ private ontologyConfig?;
916
+ private cache;
917
+ constructor(metadataRepo: MetadataRepository, edgeRepo: EdgeRepository, ontologyConfig?: OntologyConfig | undefined);
918
+ resolveMode(storedMode?: OntologyMode): OntologyMode;
919
+ invalidateCache(entityId: string): void;
920
+ getEffectiveState(entityId: string, tx?: SQLiteAdapter): Promise<{
921
+ mode: OntologyMode;
922
+ manifest: OntologyManifest;
923
+ }>;
924
+ buildPromptContext(entityId: string): Promise<OntologyPromptContext | null>;
925
+ mergeEmergentUpdates(entityId: string, updates: OntologyUpdates, tx: SQLiteAdapter): Promise<OntologyManifest>;
926
+ validateAndNormalizeFact(fact: ExtractedFactWithOntology, manifest: OntologyManifest): {
927
+ okf_type: string | null;
928
+ edges: ExtractedFactEdge[];
929
+ };
930
+ resolveAndPersistEdges(entityId: string, sourceId: string, sourceType: string | null, edges: ExtractedFactEdge[], manifest: OntologyManifest, titleIndex: Map<string, TitleIndexEntry>, tx: SQLiteAdapter, now: number): Promise<void>;
931
+ }
932
+
781
933
  declare class PromptService {
782
934
  private globalOverrides?;
783
935
  constructor(globalOverrides?: PromptOverrides | undefined);
784
936
  private hydrate;
785
- buildIngestPrompt(documentChunk: string, runtimeOverride?: string): {
937
+ private hasOntologyPlaceholders;
938
+ private buildSystemPrompt;
939
+ private appendOntology;
940
+ buildIngestPrompt(documentChunk: string, runtimeOverride?: string, ontologyContext?: OntologyPromptContext | null): {
786
941
  systemPrompt: string;
787
942
  userPrompt: string;
788
943
  };
789
- buildLibrarianPrompt(events: unknown[], currentFacts: unknown[], runtimeOverride?: string): {
944
+ buildLibrarianPrompt(events: unknown[], currentFacts: unknown[], runtimeOverride?: string, ontologyContext?: OntologyPromptContext | null): {
790
945
  systemPrompt: string;
791
946
  userPrompt: string;
792
947
  };
@@ -804,8 +959,9 @@ declare class IngestionService {
804
959
  private searchService;
805
960
  private jobManager;
806
961
  private embeddingService;
962
+ private ontologyService?;
807
963
  private promptService;
808
- constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService);
964
+ constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
809
965
  ingestDocument(entityId: string, params: {
810
966
  sourceRef: string;
811
967
  sourceHash: string;
@@ -924,8 +1080,9 @@ declare class MaintenanceService {
924
1080
  private searchService;
925
1081
  private jobManager;
926
1082
  private embeddingService;
1083
+ private ontologyService?;
927
1084
  private promptService;
928
- constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService);
1085
+ constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
929
1086
  runPrune(entityId: string, options?: {
930
1087
  retainSoftDeletedFor?: number | null;
931
1088
  retainEventsFor?: number | null;
@@ -969,17 +1126,6 @@ declare class MaintenanceService {
969
1126
  private _sanitizeRankerError;
970
1127
  }
971
1128
 
972
- declare class EdgeRepository extends BaseRepository {
973
- /**
974
- * Insert an edge, silently skipping on primary-key or uniqueness conflicts.
975
- * Throws when the insert was skipped due to an id collision with a different edge tuple.
976
- */
977
- addIgnoreDuplicate(edge: WikiEdge, tx?: SQLiteAdapter): Promise<void>;
978
- getByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<WikiEdge[]>;
979
- /** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
980
- bulkDeleteByEntityId(entityId: string, tx: SQLiteAdapter): Promise<void>;
981
- }
982
-
983
1129
  declare class ImportExportService {
984
1130
  private db;
985
1131
  private entryRepo;
@@ -1056,6 +1202,18 @@ declare class WriteService {
1056
1202
  private runLibrarianThenMaybeHeal;
1057
1203
  }
1058
1204
 
1205
+ /**
1206
+ * Pure orchestrator — no SQL. Merges WikiConfig defaults with per-call options,
1207
+ * delegates the recursive walk to EdgeRepository, then hydrates node IDs into facts.
1208
+ */
1209
+ declare class GraphTraversalService {
1210
+ private edgeRepo;
1211
+ private entryRepo;
1212
+ private config;
1213
+ constructor(edgeRepo: EdgeRepository, entryRepo: EntryRepository, config: WikiConfig);
1214
+ traverseGraph(entityId: string, options: GraphTraversalOptions): Promise<GraphNeighborhood>;
1215
+ }
1216
+
1059
1217
  /** Typed escape hatch for tests — not part of the supported consumer API. */
1060
1218
  interface WikiMemoryTestAccess {
1061
1219
  embeddingService: EmbeddingService;
@@ -1066,6 +1224,7 @@ interface WikiMemoryTestAccess {
1066
1224
  searchService: SearchService;
1067
1225
  writeService: WriteService;
1068
1226
  promptService: PromptService;
1227
+ graphTraversalService: GraphTraversalService;
1069
1228
  entryRepo: EntryRepository;
1070
1229
  metadataRepo: MetadataRepository;
1071
1230
  jobManager: JobManager;
@@ -1090,6 +1249,8 @@ declare class WikiMemory {
1090
1249
  private retrievalService;
1091
1250
  private writeService;
1092
1251
  private promptService;
1252
+ private ontologyService;
1253
+ private graphTraversalService;
1093
1254
  constructor(db: SQLiteAdapter, options: WikiOptions);
1094
1255
  /**
1095
1256
  * Explicit escape hatch for test suites: typed access to composed services for mocks/spies.
@@ -1108,6 +1269,7 @@ declare class WikiMemory {
1108
1269
  events: number;
1109
1270
  }>;
1110
1271
  read(entityId: string | string[], query: string, options?: ReadOptions): Promise<MemoryBundle>;
1272
+ traverseGraph(entityId: string, options: GraphTraversalOptions): Promise<GraphNeighborhood>;
1111
1273
  getMemoryBundle(entityId: string): Promise<MemoryBundle>;
1112
1274
  write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
1113
1275
  /**
@@ -1180,6 +1342,22 @@ declare class WikiMemory {
1180
1342
  * Call after successfully committing events to the external system.
1181
1343
  */
1182
1344
  markOutboxEventsProcessed(eventIds: string[]): Promise<void>;
1345
+ /**
1346
+ * Returns the effective ontology mode and manifest for an entity.
1347
+ * Resolution order: persisted DB row → `WikiConfig.ontology.seedManifests[entityId]` → `null`.
1348
+ */
1349
+ getOntologyManifest(entityId: string): Promise<{
1350
+ mode: OntologyMode;
1351
+ manifest: OntologyManifest;
1352
+ } | null>;
1353
+ /**
1354
+ * Seeds or replaces an entity's ontology manifest and optional mode override.
1355
+ * Validates manifest invariants (unique type slugs, edge endpoints reference node types).
1356
+ * Invalidates the in-memory ontology cache for this entity.
1357
+ */
1358
+ setOntologyManifest(entityId: string, manifest: OntologyManifest, options?: {
1359
+ mode?: OntologyMode;
1360
+ }): Promise<void>;
1183
1361
  }
1184
1362
 
1185
- 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 WikiEdge as o, type WikiEvent as p, type WikiFact as q, type WikiMemoryTestAccess as r, type WikiOutboxEvent as s, type WikiTask as t, EmbeddingService as u, IngestionService as v, MaintenanceService as w, RetrievalService as x, SearchService as y, WriteService as z };
1363
+ export { type WikiMemoryTestAccess as A, type WikiOutboxEvent as B, type WikiTask as C, EmbeddingService as D, type EntityStatus as E, type FormatContextOptions as F, type GraphNeighborhood as G, HOOK_TIMEOUT_MARKER as H, ImportExportService as I, IngestionService as J, JobManager as K, type LLMProvider as L, type MemoryBundle as M, MaintenanceService as N, type OntologyConfig as O, type PromptOverrides as P, RetrievalService as Q, type ReadOptions as R, type SQLiteAdapter as S, SearchService as T, WriteService as U, type VectorRanker as V, type WikiOptions as W, type MemoryDump as a, type FormattedMemoryDump as b, WikiMemory as c, type ExtractedFact as d, type ExtractedFactEdge as e, type ExtractedFactWithOntology as f, type ExtractedTask as g, type GraphTraversalOptions as h, type OntologyEdgeType as i, type OntologyManifest as j, type OntologyMode as k, type OntologyNodeType as l, type OntologyPromptContext as m, type OntologyUpdates as n, PromptService as o, PrunePartialFailureError as p, type VectorRankerFallback as q, type VectorRankerRankArgs as r, type VectorRankerSemanticResult as s, WikiBusyError as t, type WikiBusyOperation as u, type WikiCheckpoint as v, type WikiConfig as w, type WikiEdge as x, type WikiEvent as y, type WikiFact as z };
@@ -1,2 +1,2 @@
1
- export { u as EmbeddingService, I as ImportExportService, v as IngestionService, J as JobManager, J as JobManagerType, w as MaintenanceService, x as RetrievalService, y as SearchService, y as SearchServiceType, r as WikiMemoryTestAccess, z as WriteService } from './testing-NH1_Aigh.mjs';
1
+ export { D as EmbeddingService, I as ImportExportService, J as IngestionService, K as JobManager, K as JobManagerType, N as MaintenanceService, Q as RetrievalService, T as SearchService, T as SearchServiceType, A as WikiMemoryTestAccess, U as WriteService } from './testing-D02cdI9A.mjs';
2
2
  import 'minisearch';
package/dist/testing.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { u as EmbeddingService, I as ImportExportService, v as IngestionService, J as JobManager, J as JobManagerType, w as MaintenanceService, x as RetrievalService, y as SearchService, y as SearchServiceType, r as WikiMemoryTestAccess, z as WriteService } from './testing-NH1_Aigh.js';
1
+ export { D as EmbeddingService, I as ImportExportService, J as IngestionService, K as JobManager, K as JobManagerType, N as MaintenanceService, Q as RetrievalService, T as SearchService, T as SearchServiceType, A as WikiMemoryTestAccess, U as WriteService } from './testing-D02cdI9A.js';
2
2
  import 'minisearch';