@equationalapplications/core-llm-wiki 4.16.0 → 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.
package/dist/index.d.mts CHANGED
@@ -1,10 +1,17 @@
1
- import { M as MemoryBundle, F as FormatContextOptions, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-BMsplvLy.mjs';
2
- export { E as EntityStatus, d as ExtractedFact, e as ExtractedFactEdge, f as ExtractedFactWithOntology, g as ExtractedTask, H as HOOK_TIMEOUT_MARKER, L as LLMProvider, O as OntologyConfig, h as OntologyEdgeType, i as OntologyManifest, j as OntologyMode, k as OntologyNodeType, l as OntologyPromptContext, m as OntologyUpdates, P as PromptOverrides, n as PromptService, o as PrunePartialFailureError, V as VectorRanker, p as VectorRankerFallback, q as VectorRankerRankArgs, r as VectorRankerSemanticResult, s as WikiBusyError, t as WikiBusyOperation, u as WikiCheckpoint, v as WikiConfig, w as WikiEdge, x as WikiEvent, y as WikiFact, z as WikiMemoryTestAccess, A as WikiOutboxEvent, B as WikiTask } from './testing-BMsplvLy.mjs';
1
+ import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-D02cdI9A.mjs';
2
+ export { E as EntityStatus, d as ExtractedFact, e as ExtractedFactEdge, f as ExtractedFactWithOntology, g as ExtractedTask, h as GraphTraversalOptions, H as HOOK_TIMEOUT_MARKER, L as LLMProvider, O as OntologyConfig, i as OntologyEdgeType, j as OntologyManifest, k as OntologyMode, l as OntologyNodeType, m as OntologyPromptContext, n as OntologyUpdates, P as PromptOverrides, o as PromptService, p as PrunePartialFailureError, V as VectorRanker, q as VectorRankerFallback, r as VectorRankerRankArgs, s as VectorRankerSemanticResult, t as WikiBusyError, u as WikiBusyOperation, v as WikiCheckpoint, w as WikiConfig, x as WikiEdge, y as WikiEvent, z as WikiFact, A as WikiMemoryTestAccess, B as WikiOutboxEvent, C as WikiTask } from './testing-D02cdI9A.mjs';
3
3
  import { OkfFile } from '@equationalapplications/core-okf';
4
4
  import 'minisearch';
5
5
 
6
6
  declare function formatContext(bundle: MemoryBundle, options?: FormatContextOptions): string;
7
7
 
8
+ /**
9
+ * Pure presenter — dense text serialization of a GraphNeighborhood for LLM prompt
10
+ * injection. Deterministic: same input always produces byte-identical output
11
+ * (matters for prompt caching).
12
+ */
13
+ declare function formatGraphContext(neighborhood: GraphNeighborhood): string;
14
+
8
15
  declare function formatMemoryDump(dump: MemoryDump): FormattedMemoryDump;
9
16
 
10
17
  declare function formatOkfBundle(dump: MemoryDump): {
@@ -43,4 +50,4 @@ declare function mapLibrarianOptionsToReadOptions(options: LibrarianOptions): Pi
43
50
 
44
51
  declare function createWiki(db: SQLiteAdapter, options: WikiOptions): WikiMemory;
45
52
 
46
- export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, FormatContextOptions, FormattedMemoryDump, type LibrarianOptions, type LibrarianPromptVariables, MemoryBundle, MemoryDump, type OkfImportOptions, ReadOptions, SQLiteAdapter, WikiMemory, WikiOptions, createWiki, formatContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, parseOkfBundle, validateLibrarianPromptTemplate };
53
+ export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, FormatContextOptions, FormattedMemoryDump, GraphNeighborhood, type LibrarianOptions, type LibrarianPromptVariables, MemoryBundle, MemoryDump, type OkfImportOptions, ReadOptions, SQLiteAdapter, WikiMemory, WikiOptions, createWiki, formatContext, formatGraphContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, parseOkfBundle, validateLibrarianPromptTemplate };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,17 @@
1
- import { M as MemoryBundle, F as FormatContextOptions, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-BMsplvLy.js';
2
- export { E as EntityStatus, d as ExtractedFact, e as ExtractedFactEdge, f as ExtractedFactWithOntology, g as ExtractedTask, H as HOOK_TIMEOUT_MARKER, L as LLMProvider, O as OntologyConfig, h as OntologyEdgeType, i as OntologyManifest, j as OntologyMode, k as OntologyNodeType, l as OntologyPromptContext, m as OntologyUpdates, P as PromptOverrides, n as PromptService, o as PrunePartialFailureError, V as VectorRanker, p as VectorRankerFallback, q as VectorRankerRankArgs, r as VectorRankerSemanticResult, s as WikiBusyError, t as WikiBusyOperation, u as WikiCheckpoint, v as WikiConfig, w as WikiEdge, x as WikiEvent, y as WikiFact, z as WikiMemoryTestAccess, A as WikiOutboxEvent, B as WikiTask } from './testing-BMsplvLy.js';
1
+ import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-D02cdI9A.js';
2
+ export { E as EntityStatus, d as ExtractedFact, e as ExtractedFactEdge, f as ExtractedFactWithOntology, g as ExtractedTask, h as GraphTraversalOptions, H as HOOK_TIMEOUT_MARKER, L as LLMProvider, O as OntologyConfig, i as OntologyEdgeType, j as OntologyManifest, k as OntologyMode, l as OntologyNodeType, m as OntologyPromptContext, n as OntologyUpdates, P as PromptOverrides, o as PromptService, p as PrunePartialFailureError, V as VectorRanker, q as VectorRankerFallback, r as VectorRankerRankArgs, s as VectorRankerSemanticResult, t as WikiBusyError, u as WikiBusyOperation, v as WikiCheckpoint, w as WikiConfig, x as WikiEdge, y as WikiEvent, z as WikiFact, A as WikiMemoryTestAccess, B as WikiOutboxEvent, C as WikiTask } from './testing-D02cdI9A.js';
3
3
  import { OkfFile } from '@equationalapplications/core-okf';
4
4
  import 'minisearch';
5
5
 
6
6
  declare function formatContext(bundle: MemoryBundle, options?: FormatContextOptions): string;
7
7
 
8
+ /**
9
+ * Pure presenter — dense text serialization of a GraphNeighborhood for LLM prompt
10
+ * injection. Deterministic: same input always produces byte-identical output
11
+ * (matters for prompt caching).
12
+ */
13
+ declare function formatGraphContext(neighborhood: GraphNeighborhood): string;
14
+
8
15
  declare function formatMemoryDump(dump: MemoryDump): FormattedMemoryDump;
9
16
 
10
17
  declare function formatOkfBundle(dump: MemoryDump): {
@@ -43,4 +50,4 @@ declare function mapLibrarianOptionsToReadOptions(options: LibrarianOptions): Pi
43
50
 
44
51
  declare function createWiki(db: SQLiteAdapter, options: WikiOptions): WikiMemory;
45
52
 
46
- export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, FormatContextOptions, FormattedMemoryDump, type LibrarianOptions, type LibrarianPromptVariables, MemoryBundle, MemoryDump, type OkfImportOptions, ReadOptions, SQLiteAdapter, WikiMemory, WikiOptions, createWiki, formatContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, parseOkfBundle, validateLibrarianPromptTemplate };
53
+ export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, FormatContextOptions, FormattedMemoryDump, GraphNeighborhood, type LibrarianOptions, type LibrarianPromptVariables, MemoryBundle, MemoryDump, type OkfImportOptions, ReadOptions, SQLiteAdapter, WikiMemory, WikiOptions, createWiki, formatContext, formatGraphContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, parseOkfBundle, validateLibrarianPromptTemplate };
package/dist/index.js CHANGED
@@ -1407,6 +1407,11 @@ var EventRepository = class extends BaseRepository {
1407
1407
  };
1408
1408
 
1409
1409
  // src/repositories/EdgeRepository.ts
1410
+ var CONFIDENCE_RANK = {
1411
+ tentative: 0,
1412
+ inferred: 1,
1413
+ certain: 2
1414
+ };
1410
1415
  var EdgeRepository = class extends BaseRepository {
1411
1416
  /**
1412
1417
  * Insert an edge, silently skipping on primary-key or uniqueness conflicts.
@@ -1437,21 +1442,111 @@ var EdgeRepository = class extends BaseRepository {
1437
1442
  `SELECT * FROM ${this.prefix}edges WHERE entity_id = ? ORDER BY created_at ASC`,
1438
1443
  [entityId]
1439
1444
  );
1440
- return rows.map((row) => ({
1441
- id: String(row.id),
1442
- entity_id: String(row.entity_id),
1443
- source_id: String(row.source_id),
1444
- target_id: String(row.target_id),
1445
- edge_type: String(row.edge_type),
1446
- created_at: Number(row.created_at)
1447
- }));
1445
+ return rows.map(mapRowToEdge);
1448
1446
  }
1449
1447
  /** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
1450
1448
  async bulkDeleteByEntityId(entityId, tx) {
1451
1449
  const executor = this.getExecutor(tx);
1452
1450
  await executor.runAsync(`DELETE FROM ${this.prefix}edges WHERE entity_id = ?`, [entityId]);
1453
1451
  }
1452
+ /**
1453
+ * Multi-hop traversal from `sourceId` via SQLite `WITH RECURSIVE`. All filtering,
1454
+ * dead-ending, cycle-guarding, capping, and ordering happens in this one query.
1455
+ * The anchor is validated (exists, right entity, not soft-deleted) but never gated
1456
+ * by confidence/source_type — only nodes discovered beyond it are.
1457
+ */
1458
+ async getNeighborhood(entityId, sourceId, opts, tx) {
1459
+ const executor = this.getExecutor(tx);
1460
+ if (opts.edgeTypes && opts.edgeTypes.length === 0) {
1461
+ const anchor = await executor.getFirstAsync(
1462
+ `SELECT id FROM ${this.prefix}entries WHERE id = ? AND entity_id = ? AND deleted_at IS NULL`,
1463
+ [sourceId, entityId]
1464
+ );
1465
+ return { nodeIds: anchor ? [anchor.id] : [], edges: [] };
1466
+ }
1467
+ const edgeTypesClause = opts.edgeTypes ? `e.edge_type IN (${opts.edgeTypes.map(() => "?").join(",")})` : "1=1";
1468
+ const excludeSourceTypesPlaceholders = opts.excludeSourceTypes.map(() => "?").join(",");
1469
+ const minConfidenceRank = CONFIDENCE_RANK[opts.minConfidence];
1470
+ const sql = `
1471
+ WITH RECURSIVE walk(node_id, depth, visited) AS (
1472
+ SELECT id, 0, ',' || id || ','
1473
+ FROM ${this.prefix}entries
1474
+ WHERE id = ? AND entity_id = ? AND deleted_at IS NULL
1475
+
1476
+ UNION
1477
+
1478
+ SELECT
1479
+ CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END,
1480
+ w.depth + 1,
1481
+ w.visited || (CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END) || ','
1482
+ FROM walk w
1483
+ JOIN ${this.prefix}edges e
1484
+ ON e.entity_id = ?
1485
+ AND (
1486
+ (? != 'inbound' AND e.source_id = w.node_id) OR
1487
+ (? != 'outbound' AND e.target_id = w.node_id)
1488
+ )
1489
+ AND (${edgeTypesClause})
1490
+ JOIN ${this.prefix}entries n
1491
+ ON n.id = (CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END)
1492
+ AND n.entity_id = ?
1493
+ AND n.deleted_at IS NULL
1494
+ AND (
1495
+ CASE n.confidence
1496
+ WHEN 'tentative' THEN 0
1497
+ WHEN 'inferred' THEN 1
1498
+ WHEN 'certain' THEN 2
1499
+ ELSE -1
1500
+ END
1501
+ ) >= ?
1502
+ AND n.source_type NOT IN (${excludeSourceTypesPlaceholders})
1503
+ WHERE w.depth < ?
1504
+ AND instr(w.visited, ',' || (CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END) || ',') = 0
1505
+ )
1506
+ SELECT node_id, MIN(depth) AS depth
1507
+ FROM walk
1508
+ GROUP BY node_id
1509
+ ORDER BY depth ASC, (SELECT updated_at FROM ${this.prefix}entries WHERE id = node_id) DESC
1510
+ LIMIT ?
1511
+ `;
1512
+ const params = [
1513
+ sourceId,
1514
+ entityId,
1515
+ entityId,
1516
+ opts.direction,
1517
+ opts.direction,
1518
+ ...opts.edgeTypes ?? [],
1519
+ entityId,
1520
+ minConfidenceRank,
1521
+ ...opts.excludeSourceTypes,
1522
+ opts.maxDepth,
1523
+ opts.maxNodes
1524
+ ];
1525
+ const rows = await executor.getAllAsync(sql, params);
1526
+ const nodeIds = rows.map((r) => r.node_id);
1527
+ if (nodeIds.length === 0) return { nodeIds: [], edges: [] };
1528
+ const valueRows = nodeIds.map(() => "(?)").join(", ");
1529
+ const edgeRows = await executor.getAllAsync(
1530
+ `WITH neighborhood(node_id) AS (VALUES ${valueRows})
1531
+ SELECT e.* FROM ${this.prefix}edges e
1532
+ JOIN neighborhood ns ON e.source_id = ns.node_id
1533
+ JOIN neighborhood nt ON e.target_id = nt.node_id
1534
+ WHERE e.entity_id = ?`,
1535
+ [...nodeIds, entityId]
1536
+ );
1537
+ return { nodeIds, edges: edgeRows.map(mapRowToEdge) };
1538
+ }
1454
1539
  };
1540
+ function mapRowToEdge(row) {
1541
+ return {
1542
+ id: String(row.id),
1543
+ entity_id: String(row.entity_id),
1544
+ source_id: String(row.source_id),
1545
+ target_id: String(row.target_id),
1546
+ edge_type: String(row.edge_type),
1547
+ created_at: Number(row.created_at)
1548
+ };
1549
+ }
1455
1550
 
1456
1551
  // src/utils/ontology.ts
1457
1552
  function emptyManifest() {
@@ -4481,6 +4576,38 @@ var OntologyService = class {
4481
4576
  }
4482
4577
  };
4483
4578
 
4579
+ // src/services/GraphTraversalService.ts
4580
+ var GraphTraversalService = class {
4581
+ constructor(edgeRepo, entryRepo, config) {
4582
+ this.edgeRepo = edgeRepo;
4583
+ this.entryRepo = entryRepo;
4584
+ this.config = config;
4585
+ }
4586
+ async traverseGraph(entityId, options) {
4587
+ const fallbackMaxNodes = 20;
4588
+ const rawConfigDefault = this.config.maxTraversalNodes ?? fallbackMaxNodes;
4589
+ const defaultMaxNodes = Number.isFinite(rawConfigDefault) && rawConfigDefault >= 1 ? Math.floor(rawConfigDefault) : fallbackMaxNodes;
4590
+ const rawMaxNodes = options.maxTraversalNodes ?? defaultMaxNodes;
4591
+ const maxNodes = Number.isFinite(rawMaxNodes) && rawMaxNodes >= 1 ? Math.floor(rawMaxNodes) : defaultMaxNodes;
4592
+ const opts = {
4593
+ maxDepth: Math.max(1, Math.min(options.maxDepth ?? 1, 3)),
4594
+ direction: options.direction ?? this.config.traversalDirection ?? "both",
4595
+ edgeTypes: options.edgeTypes,
4596
+ minConfidence: options.minTraversalConfidence ?? this.config.minTraversalConfidence ?? "tentative",
4597
+ excludeSourceTypes: options.excludeSourceTypes ?? this.config.excludeSourceTypes ?? [],
4598
+ maxNodes
4599
+ };
4600
+ const { nodeIds, edges } = await this.edgeRepo.getNeighborhood(entityId, options.sourceId, opts);
4601
+ if (nodeIds.length === 0) return { nodes: [], edges: [] };
4602
+ const nodes = await this.entryRepo.findByIds(nodeIds, [entityId]);
4603
+ const hydratedIds = new Set(nodes.map((node) => node.id));
4604
+ const filteredEdges = edges.filter(
4605
+ (edge) => hydratedIds.has(edge.source_id) && hydratedIds.has(edge.target_id)
4606
+ );
4607
+ return { nodes, edges: filteredEdges };
4608
+ }
4609
+ };
4610
+
4484
4611
  // src/WikiMemory.ts
4485
4612
  var TABLE_PREFIX_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,30}_$/;
4486
4613
  var _testAccessNonTestEnvWarned;
@@ -4564,6 +4691,11 @@ var WikiMemory = class {
4564
4691
  this.jobManager,
4565
4692
  this.maintenanceService
4566
4693
  );
4694
+ this.graphTraversalService = new GraphTraversalService(
4695
+ this.edgeRepo,
4696
+ this.entryRepo,
4697
+ this.options.config ?? {}
4698
+ );
4567
4699
  }
4568
4700
  /**
4569
4701
  * Explicit escape hatch for test suites: typed access to composed services for mocks/spies.
@@ -4584,6 +4716,7 @@ var WikiMemory = class {
4584
4716
  searchService: this.searchService,
4585
4717
  writeService: this.writeService,
4586
4718
  promptService: this.promptService,
4719
+ graphTraversalService: this.graphTraversalService,
4587
4720
  entryRepo: this.entryRepo,
4588
4721
  metadataRepo: this.metadataRepo,
4589
4722
  jobManager: this.jobManager
@@ -4654,6 +4787,9 @@ var WikiMemory = class {
4654
4787
  async read(entityId, query, options) {
4655
4788
  return this.retrievalService.read(entityId, query, options);
4656
4789
  }
4790
+ async traverseGraph(entityId, options) {
4791
+ return this.graphTraversalService.traverseGraph(entityId, options);
4792
+ }
4657
4793
  async getMemoryBundle(entityId) {
4658
4794
  return this.importExportService.getFullBundle(entityId, { maxEvents: 10 });
4659
4795
  }
@@ -4881,6 +5017,38 @@ function formatContext(bundle, options) {
4881
5017
  return lines.join("\n");
4882
5018
  }
4883
5019
 
5020
+ // src/utils/formatGraphContext.ts
5021
+ function formatGraphContext(neighborhood) {
5022
+ const { nodes, edges } = neighborhood;
5023
+ if (nodes.length === 0) return "";
5024
+ const nodeById = new Map(nodes.map((n) => [n.id, n]));
5025
+ const nodeIndex = new Map(nodes.map((n, i) => [n.id, i]));
5026
+ const lines = [];
5027
+ for (const node of nodes) {
5028
+ lines.push(`[${node.okf_type ?? "fact"}] ${node.title} (ID: ${node.id})`);
5029
+ const outbound = edgesByDirection(edges, node.id, "source_id", nodeById, nodeIndex);
5030
+ const inbound = edgesByDirection(edges, node.id, "target_id", nodeById, nodeIndex);
5031
+ for (const { edge, other } of outbound) {
5032
+ lines.push(` -[${edge.edge_type}]-> [${other.okf_type ?? "fact"}] ${other.title}`);
5033
+ }
5034
+ for (const { edge, other } of inbound) {
5035
+ lines.push(` <-[${edge.edge_type}]- [${other.okf_type ?? "fact"}] ${other.title}`);
5036
+ }
5037
+ }
5038
+ return lines.join("\n");
5039
+ }
5040
+ function edgesByDirection(edges, nodeId, endpoint, nodeById, nodeIndex) {
5041
+ const otherEndpoint = endpoint === "source_id" ? "target_id" : "source_id";
5042
+ return edges.filter((e) => e[endpoint] === nodeId).filter((e) => {
5043
+ const otherId = e[otherEndpoint];
5044
+ const selfIdx = nodeIndex.get(nodeId);
5045
+ const otherIdx = nodeIndex.get(otherId);
5046
+ return otherIdx !== void 0 && selfIdx < otherIdx;
5047
+ }).map((edge) => ({ edge, other: nodeById.get(edge[otherEndpoint]) })).sort(
5048
+ (a, b) => a.edge.edge_type.localeCompare(b.edge.edge_type) || a.other.title.localeCompare(b.other.title) || a.other.id.localeCompare(b.other.id) || a.edge.id.localeCompare(b.edge.id)
5049
+ );
5050
+ }
5051
+
4884
5052
  // src/utils/sanitizeForFilename.ts
4885
5053
  function shortHash(value) {
4886
5054
  let h1 = 5381;
@@ -5397,6 +5565,7 @@ exports.WikiBusyError = WikiBusyError;
5397
5565
  exports.WikiMemory = WikiMemory;
5398
5566
  exports.createWiki = createWiki;
5399
5567
  exports.formatContext = formatContext;
5568
+ exports.formatGraphContext = formatGraphContext;
5400
5569
  exports.formatMemoryDump = formatMemoryDump;
5401
5570
  exports.formatOkfBundle = formatOkfBundle;
5402
5571
  exports.hydrateLibrarianPrompt = hydrateLibrarianPrompt;