@equationalapplications/core-llm-wiki 4.16.0 → 4.17.1
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 +20 -0
- package/dist/{chunk-2BGLPRT3.mjs → chunk-AV2ZNKEA.mjs} +27 -18
- package/dist/chunk-AV2ZNKEA.mjs.map +1 -0
- package/dist/index.d.mts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +188 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +179 -11
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-BMsplvLy.d.mts → testing-D02cdI9A.d.mts} +66 -1
- package/dist/{testing-BMsplvLy.d.ts → testing-D02cdI9A.d.ts} +66 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -3
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-2BGLPRT3.mjs.map +0 -1
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-
|
|
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,
|
|
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): {
|
|
@@ -19,6 +26,16 @@ declare function parseOkfBundle(entityId: string, files: OkfFile[], options?: Ok
|
|
|
19
26
|
|
|
20
27
|
declare function parseEmbedding(blob: Uint8Array | null | undefined, text: string | null | undefined): Float32Array | null;
|
|
21
28
|
|
|
29
|
+
type GetRandomValues = (bytes: Uint8Array) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Inject a platform-specific `getRandomValues` implementation.
|
|
32
|
+
* Call this once at module load time from the platform adapter
|
|
33
|
+
* (e.g. expo-crypto's getRandomValues) when the global `crypto` API is
|
|
34
|
+
* absent — Hermes / React Native being the primary case.
|
|
35
|
+
* Pass `null` to clear a previously injected source.
|
|
36
|
+
*/
|
|
37
|
+
declare function configureRandomSource(fn: GetRandomValues | null): void;
|
|
38
|
+
|
|
22
39
|
interface LibrarianOptions {
|
|
23
40
|
/** If provided, replaces the default Librarian system instructions. */
|
|
24
41
|
systemPrompt?: string;
|
|
@@ -43,4 +60,4 @@ declare function mapLibrarianOptionsToReadOptions(options: LibrarianOptions): Pi
|
|
|
43
60
|
|
|
44
61
|
declare function createWiki(db: SQLiteAdapter, options: WikiOptions): WikiMemory;
|
|
45
62
|
|
|
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 };
|
|
63
|
+
export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, FormatContextOptions, FormattedMemoryDump, GraphNeighborhood, type LibrarianOptions, type LibrarianPromptVariables, MemoryBundle, MemoryDump, type OkfImportOptions, ReadOptions, SQLiteAdapter, WikiMemory, WikiOptions, configureRandomSource, 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-
|
|
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,
|
|
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): {
|
|
@@ -19,6 +26,16 @@ declare function parseOkfBundle(entityId: string, files: OkfFile[], options?: Ok
|
|
|
19
26
|
|
|
20
27
|
declare function parseEmbedding(blob: Uint8Array | null | undefined, text: string | null | undefined): Float32Array | null;
|
|
21
28
|
|
|
29
|
+
type GetRandomValues = (bytes: Uint8Array) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Inject a platform-specific `getRandomValues` implementation.
|
|
32
|
+
* Call this once at module load time from the platform adapter
|
|
33
|
+
* (e.g. expo-crypto's getRandomValues) when the global `crypto` API is
|
|
34
|
+
* absent — Hermes / React Native being the primary case.
|
|
35
|
+
* Pass `null` to clear a previously injected source.
|
|
36
|
+
*/
|
|
37
|
+
declare function configureRandomSource(fn: GetRandomValues | null): void;
|
|
38
|
+
|
|
22
39
|
interface LibrarianOptions {
|
|
23
40
|
/** If provided, replaces the default Librarian system instructions. */
|
|
24
41
|
systemPrompt?: string;
|
|
@@ -43,4 +60,4 @@ declare function mapLibrarianOptionsToReadOptions(options: LibrarianOptions): Pi
|
|
|
43
60
|
|
|
44
61
|
declare function createWiki(db: SQLiteAdapter, options: WikiOptions): WikiMemory;
|
|
45
62
|
|
|
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 };
|
|
63
|
+
export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, FormatContextOptions, FormattedMemoryDump, GraphNeighborhood, type LibrarianOptions, type LibrarianPromptVariables, MemoryBundle, MemoryDump, type OkfImportOptions, ReadOptions, SQLiteAdapter, WikiMemory, WikiOptions, configureRandomSource, createWiki, formatContext, formatGraphContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, parseOkfBundle, validateLibrarianPromptTemplate };
|
package/dist/index.js
CHANGED
|
@@ -983,6 +983,10 @@ var EntryRepository = class extends BaseRepository {
|
|
|
983
983
|
};
|
|
984
984
|
|
|
985
985
|
// src/utils/ids.ts
|
|
986
|
+
var _injectedGetRandomValues = null;
|
|
987
|
+
function configureRandomSource(fn) {
|
|
988
|
+
_injectedGetRandomValues = fn;
|
|
989
|
+
}
|
|
986
990
|
function generateId(prefix = "") {
|
|
987
991
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
988
992
|
return prefix + crypto.randomUUID().replace(/-/g, "").substring(0, 24);
|
|
@@ -992,8 +996,13 @@ function generateId(prefix = "") {
|
|
|
992
996
|
crypto.getRandomValues(bytes);
|
|
993
997
|
return prefix + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("").substring(0, 24);
|
|
994
998
|
}
|
|
999
|
+
if (_injectedGetRandomValues) {
|
|
1000
|
+
const bytes = new Uint8Array(16);
|
|
1001
|
+
_injectedGetRandomValues(bytes);
|
|
1002
|
+
return prefix + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("").substring(0, 24);
|
|
1003
|
+
}
|
|
995
1004
|
throw new Error(
|
|
996
|
-
"generateId: no cryptographically secure random source available (crypto.randomUUID and crypto.getRandomValues are both missing)."
|
|
1005
|
+
"generateId: no cryptographically secure random source available (crypto.randomUUID and crypto.getRandomValues are both missing, and no configureRandomSource() injection was provided)."
|
|
997
1006
|
);
|
|
998
1007
|
}
|
|
999
1008
|
|
|
@@ -1407,6 +1416,11 @@ var EventRepository = class extends BaseRepository {
|
|
|
1407
1416
|
};
|
|
1408
1417
|
|
|
1409
1418
|
// src/repositories/EdgeRepository.ts
|
|
1419
|
+
var CONFIDENCE_RANK = {
|
|
1420
|
+
tentative: 0,
|
|
1421
|
+
inferred: 1,
|
|
1422
|
+
certain: 2
|
|
1423
|
+
};
|
|
1410
1424
|
var EdgeRepository = class extends BaseRepository {
|
|
1411
1425
|
/**
|
|
1412
1426
|
* Insert an edge, silently skipping on primary-key or uniqueness conflicts.
|
|
@@ -1437,21 +1451,111 @@ var EdgeRepository = class extends BaseRepository {
|
|
|
1437
1451
|
`SELECT * FROM ${this.prefix}edges WHERE entity_id = ? ORDER BY created_at ASC`,
|
|
1438
1452
|
[entityId]
|
|
1439
1453
|
);
|
|
1440
|
-
return rows.map(
|
|
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
|
-
}));
|
|
1454
|
+
return rows.map(mapRowToEdge);
|
|
1448
1455
|
}
|
|
1449
1456
|
/** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
|
|
1450
1457
|
async bulkDeleteByEntityId(entityId, tx) {
|
|
1451
1458
|
const executor = this.getExecutor(tx);
|
|
1452
1459
|
await executor.runAsync(`DELETE FROM ${this.prefix}edges WHERE entity_id = ?`, [entityId]);
|
|
1453
1460
|
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Multi-hop traversal from `sourceId` via SQLite `WITH RECURSIVE`. All filtering,
|
|
1463
|
+
* dead-ending, cycle-guarding, capping, and ordering happens in this one query.
|
|
1464
|
+
* The anchor is validated (exists, right entity, not soft-deleted) but never gated
|
|
1465
|
+
* by confidence/source_type — only nodes discovered beyond it are.
|
|
1466
|
+
*/
|
|
1467
|
+
async getNeighborhood(entityId, sourceId, opts, tx) {
|
|
1468
|
+
const executor = this.getExecutor(tx);
|
|
1469
|
+
if (opts.edgeTypes && opts.edgeTypes.length === 0) {
|
|
1470
|
+
const anchor = await executor.getFirstAsync(
|
|
1471
|
+
`SELECT id FROM ${this.prefix}entries WHERE id = ? AND entity_id = ? AND deleted_at IS NULL`,
|
|
1472
|
+
[sourceId, entityId]
|
|
1473
|
+
);
|
|
1474
|
+
return { nodeIds: anchor ? [anchor.id] : [], edges: [] };
|
|
1475
|
+
}
|
|
1476
|
+
const edgeTypesClause = opts.edgeTypes ? `e.edge_type IN (${opts.edgeTypes.map(() => "?").join(",")})` : "1=1";
|
|
1477
|
+
const excludeSourceTypesPlaceholders = opts.excludeSourceTypes.map(() => "?").join(",");
|
|
1478
|
+
const minConfidenceRank = CONFIDENCE_RANK[opts.minConfidence];
|
|
1479
|
+
const sql = `
|
|
1480
|
+
WITH RECURSIVE walk(node_id, depth, visited) AS (
|
|
1481
|
+
SELECT id, 0, ',' || id || ','
|
|
1482
|
+
FROM ${this.prefix}entries
|
|
1483
|
+
WHERE id = ? AND entity_id = ? AND deleted_at IS NULL
|
|
1484
|
+
|
|
1485
|
+
UNION
|
|
1486
|
+
|
|
1487
|
+
SELECT
|
|
1488
|
+
CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END,
|
|
1489
|
+
w.depth + 1,
|
|
1490
|
+
w.visited || (CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END) || ','
|
|
1491
|
+
FROM walk w
|
|
1492
|
+
JOIN ${this.prefix}edges e
|
|
1493
|
+
ON e.entity_id = ?
|
|
1494
|
+
AND (
|
|
1495
|
+
(? != 'inbound' AND e.source_id = w.node_id) OR
|
|
1496
|
+
(? != 'outbound' AND e.target_id = w.node_id)
|
|
1497
|
+
)
|
|
1498
|
+
AND (${edgeTypesClause})
|
|
1499
|
+
JOIN ${this.prefix}entries n
|
|
1500
|
+
ON n.id = (CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END)
|
|
1501
|
+
AND n.entity_id = ?
|
|
1502
|
+
AND n.deleted_at IS NULL
|
|
1503
|
+
AND (
|
|
1504
|
+
CASE n.confidence
|
|
1505
|
+
WHEN 'tentative' THEN 0
|
|
1506
|
+
WHEN 'inferred' THEN 1
|
|
1507
|
+
WHEN 'certain' THEN 2
|
|
1508
|
+
ELSE -1
|
|
1509
|
+
END
|
|
1510
|
+
) >= ?
|
|
1511
|
+
AND n.source_type NOT IN (${excludeSourceTypesPlaceholders})
|
|
1512
|
+
WHERE w.depth < ?
|
|
1513
|
+
AND instr(w.visited, ',' || (CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END) || ',') = 0
|
|
1514
|
+
)
|
|
1515
|
+
SELECT node_id, MIN(depth) AS depth
|
|
1516
|
+
FROM walk
|
|
1517
|
+
GROUP BY node_id
|
|
1518
|
+
ORDER BY depth ASC, (SELECT updated_at FROM ${this.prefix}entries WHERE id = node_id) DESC
|
|
1519
|
+
LIMIT ?
|
|
1520
|
+
`;
|
|
1521
|
+
const params = [
|
|
1522
|
+
sourceId,
|
|
1523
|
+
entityId,
|
|
1524
|
+
entityId,
|
|
1525
|
+
opts.direction,
|
|
1526
|
+
opts.direction,
|
|
1527
|
+
...opts.edgeTypes ?? [],
|
|
1528
|
+
entityId,
|
|
1529
|
+
minConfidenceRank,
|
|
1530
|
+
...opts.excludeSourceTypes,
|
|
1531
|
+
opts.maxDepth,
|
|
1532
|
+
opts.maxNodes
|
|
1533
|
+
];
|
|
1534
|
+
const rows = await executor.getAllAsync(sql, params);
|
|
1535
|
+
const nodeIds = rows.map((r) => r.node_id);
|
|
1536
|
+
if (nodeIds.length === 0) return { nodeIds: [], edges: [] };
|
|
1537
|
+
const valueRows = nodeIds.map(() => "(?)").join(", ");
|
|
1538
|
+
const edgeRows = await executor.getAllAsync(
|
|
1539
|
+
`WITH neighborhood(node_id) AS (VALUES ${valueRows})
|
|
1540
|
+
SELECT e.* FROM ${this.prefix}edges e
|
|
1541
|
+
JOIN neighborhood ns ON e.source_id = ns.node_id
|
|
1542
|
+
JOIN neighborhood nt ON e.target_id = nt.node_id
|
|
1543
|
+
WHERE e.entity_id = ?`,
|
|
1544
|
+
[...nodeIds, entityId]
|
|
1545
|
+
);
|
|
1546
|
+
return { nodeIds, edges: edgeRows.map(mapRowToEdge) };
|
|
1547
|
+
}
|
|
1454
1548
|
};
|
|
1549
|
+
function mapRowToEdge(row) {
|
|
1550
|
+
return {
|
|
1551
|
+
id: String(row.id),
|
|
1552
|
+
entity_id: String(row.entity_id),
|
|
1553
|
+
source_id: String(row.source_id),
|
|
1554
|
+
target_id: String(row.target_id),
|
|
1555
|
+
edge_type: String(row.edge_type),
|
|
1556
|
+
created_at: Number(row.created_at)
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1455
1559
|
|
|
1456
1560
|
// src/utils/ontology.ts
|
|
1457
1561
|
function emptyManifest() {
|
|
@@ -4481,6 +4585,38 @@ var OntologyService = class {
|
|
|
4481
4585
|
}
|
|
4482
4586
|
};
|
|
4483
4587
|
|
|
4588
|
+
// src/services/GraphTraversalService.ts
|
|
4589
|
+
var GraphTraversalService = class {
|
|
4590
|
+
constructor(edgeRepo, entryRepo, config) {
|
|
4591
|
+
this.edgeRepo = edgeRepo;
|
|
4592
|
+
this.entryRepo = entryRepo;
|
|
4593
|
+
this.config = config;
|
|
4594
|
+
}
|
|
4595
|
+
async traverseGraph(entityId, options) {
|
|
4596
|
+
const fallbackMaxNodes = 20;
|
|
4597
|
+
const rawConfigDefault = this.config.maxTraversalNodes ?? fallbackMaxNodes;
|
|
4598
|
+
const defaultMaxNodes = Number.isFinite(rawConfigDefault) && rawConfigDefault >= 1 ? Math.floor(rawConfigDefault) : fallbackMaxNodes;
|
|
4599
|
+
const rawMaxNodes = options.maxTraversalNodes ?? defaultMaxNodes;
|
|
4600
|
+
const maxNodes = Number.isFinite(rawMaxNodes) && rawMaxNodes >= 1 ? Math.floor(rawMaxNodes) : defaultMaxNodes;
|
|
4601
|
+
const opts = {
|
|
4602
|
+
maxDepth: Math.max(1, Math.min(options.maxDepth ?? 1, 3)),
|
|
4603
|
+
direction: options.direction ?? this.config.traversalDirection ?? "both",
|
|
4604
|
+
edgeTypes: options.edgeTypes,
|
|
4605
|
+
minConfidence: options.minTraversalConfidence ?? this.config.minTraversalConfidence ?? "tentative",
|
|
4606
|
+
excludeSourceTypes: options.excludeSourceTypes ?? this.config.excludeSourceTypes ?? [],
|
|
4607
|
+
maxNodes
|
|
4608
|
+
};
|
|
4609
|
+
const { nodeIds, edges } = await this.edgeRepo.getNeighborhood(entityId, options.sourceId, opts);
|
|
4610
|
+
if (nodeIds.length === 0) return { nodes: [], edges: [] };
|
|
4611
|
+
const nodes = await this.entryRepo.findByIds(nodeIds, [entityId]);
|
|
4612
|
+
const hydratedIds = new Set(nodes.map((node) => node.id));
|
|
4613
|
+
const filteredEdges = edges.filter(
|
|
4614
|
+
(edge) => hydratedIds.has(edge.source_id) && hydratedIds.has(edge.target_id)
|
|
4615
|
+
);
|
|
4616
|
+
return { nodes, edges: filteredEdges };
|
|
4617
|
+
}
|
|
4618
|
+
};
|
|
4619
|
+
|
|
4484
4620
|
// src/WikiMemory.ts
|
|
4485
4621
|
var TABLE_PREFIX_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,30}_$/;
|
|
4486
4622
|
var _testAccessNonTestEnvWarned;
|
|
@@ -4564,6 +4700,11 @@ var WikiMemory = class {
|
|
|
4564
4700
|
this.jobManager,
|
|
4565
4701
|
this.maintenanceService
|
|
4566
4702
|
);
|
|
4703
|
+
this.graphTraversalService = new GraphTraversalService(
|
|
4704
|
+
this.edgeRepo,
|
|
4705
|
+
this.entryRepo,
|
|
4706
|
+
this.options.config ?? {}
|
|
4707
|
+
);
|
|
4567
4708
|
}
|
|
4568
4709
|
/**
|
|
4569
4710
|
* Explicit escape hatch for test suites: typed access to composed services for mocks/spies.
|
|
@@ -4584,6 +4725,7 @@ var WikiMemory = class {
|
|
|
4584
4725
|
searchService: this.searchService,
|
|
4585
4726
|
writeService: this.writeService,
|
|
4586
4727
|
promptService: this.promptService,
|
|
4728
|
+
graphTraversalService: this.graphTraversalService,
|
|
4587
4729
|
entryRepo: this.entryRepo,
|
|
4588
4730
|
metadataRepo: this.metadataRepo,
|
|
4589
4731
|
jobManager: this.jobManager
|
|
@@ -4654,6 +4796,9 @@ var WikiMemory = class {
|
|
|
4654
4796
|
async read(entityId, query, options) {
|
|
4655
4797
|
return this.retrievalService.read(entityId, query, options);
|
|
4656
4798
|
}
|
|
4799
|
+
async traverseGraph(entityId, options) {
|
|
4800
|
+
return this.graphTraversalService.traverseGraph(entityId, options);
|
|
4801
|
+
}
|
|
4657
4802
|
async getMemoryBundle(entityId) {
|
|
4658
4803
|
return this.importExportService.getFullBundle(entityId, { maxEvents: 10 });
|
|
4659
4804
|
}
|
|
@@ -4881,6 +5026,38 @@ function formatContext(bundle, options) {
|
|
|
4881
5026
|
return lines.join("\n");
|
|
4882
5027
|
}
|
|
4883
5028
|
|
|
5029
|
+
// src/utils/formatGraphContext.ts
|
|
5030
|
+
function formatGraphContext(neighborhood) {
|
|
5031
|
+
const { nodes, edges } = neighborhood;
|
|
5032
|
+
if (nodes.length === 0) return "";
|
|
5033
|
+
const nodeById = new Map(nodes.map((n) => [n.id, n]));
|
|
5034
|
+
const nodeIndex = new Map(nodes.map((n, i) => [n.id, i]));
|
|
5035
|
+
const lines = [];
|
|
5036
|
+
for (const node of nodes) {
|
|
5037
|
+
lines.push(`[${node.okf_type ?? "fact"}] ${node.title} (ID: ${node.id})`);
|
|
5038
|
+
const outbound = edgesByDirection(edges, node.id, "source_id", nodeById, nodeIndex);
|
|
5039
|
+
const inbound = edgesByDirection(edges, node.id, "target_id", nodeById, nodeIndex);
|
|
5040
|
+
for (const { edge, other } of outbound) {
|
|
5041
|
+
lines.push(` -[${edge.edge_type}]-> [${other.okf_type ?? "fact"}] ${other.title}`);
|
|
5042
|
+
}
|
|
5043
|
+
for (const { edge, other } of inbound) {
|
|
5044
|
+
lines.push(` <-[${edge.edge_type}]- [${other.okf_type ?? "fact"}] ${other.title}`);
|
|
5045
|
+
}
|
|
5046
|
+
}
|
|
5047
|
+
return lines.join("\n");
|
|
5048
|
+
}
|
|
5049
|
+
function edgesByDirection(edges, nodeId, endpoint, nodeById, nodeIndex) {
|
|
5050
|
+
const otherEndpoint = endpoint === "source_id" ? "target_id" : "source_id";
|
|
5051
|
+
return edges.filter((e) => e[endpoint] === nodeId).filter((e) => {
|
|
5052
|
+
const otherId = e[otherEndpoint];
|
|
5053
|
+
const selfIdx = nodeIndex.get(nodeId);
|
|
5054
|
+
const otherIdx = nodeIndex.get(otherId);
|
|
5055
|
+
return otherIdx !== void 0 && selfIdx < otherIdx;
|
|
5056
|
+
}).map((edge) => ({ edge, other: nodeById.get(edge[otherEndpoint]) })).sort(
|
|
5057
|
+
(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)
|
|
5058
|
+
);
|
|
5059
|
+
}
|
|
5060
|
+
|
|
4884
5061
|
// src/utils/sanitizeForFilename.ts
|
|
4885
5062
|
function shortHash(value) {
|
|
4886
5063
|
let h1 = 5381;
|
|
@@ -5395,8 +5572,10 @@ exports.PromptService = PromptService;
|
|
|
5395
5572
|
exports.PrunePartialFailureError = PrunePartialFailureError;
|
|
5396
5573
|
exports.WikiBusyError = WikiBusyError;
|
|
5397
5574
|
exports.WikiMemory = WikiMemory;
|
|
5575
|
+
exports.configureRandomSource = configureRandomSource;
|
|
5398
5576
|
exports.createWiki = createWiki;
|
|
5399
5577
|
exports.formatContext = formatContext;
|
|
5578
|
+
exports.formatGraphContext = formatGraphContext;
|
|
5400
5579
|
exports.formatMemoryDump = formatMemoryDump;
|
|
5401
5580
|
exports.formatOkfBundle = formatOkfBundle;
|
|
5402
5581
|
exports.hydrateLibrarianPrompt = hydrateLibrarianPrompt;
|