@equationalapplications/core-llm-wiki 4.14.1 → 4.15.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/{chunk-24ANTHZB.mjs → chunk-J4GBC6CP.mjs} +28 -10
- package/dist/chunk-J4GBC6CP.mjs.map +1 -0
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +357 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +334 -18
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-DW1qufP0.d.mts → testing-NH1_Aigh.d.mts} +32 -2
- package/dist/{testing-DW1qufP0.d.ts → testing-NH1_Aigh.d.ts} +32 -2
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +26 -8
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-24ANTHZB.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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 ExtractedTask, H as HOOK_TIMEOUT_MARKER, L as LLMProvider, P as PromptOverrides, f as PromptService, g as PrunePartialFailureError, V as VectorRanker, h as VectorRankerFallback, i as VectorRankerRankArgs, j as VectorRankerSemanticResult, k as WikiBusyError, l as WikiBusyOperation, m as WikiCheckpoint, n as WikiConfig, o as
|
|
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-NH1_Aigh.mjs';
|
|
2
|
+
export { E as EntityStatus, d as ExtractedFact, e as ExtractedTask, H as HOOK_TIMEOUT_MARKER, L as LLMProvider, P as PromptOverrides, f as PromptService, g as PrunePartialFailureError, V as VectorRanker, h as VectorRankerFallback, i as VectorRankerRankArgs, j as VectorRankerSemanticResult, k as WikiBusyError, l as WikiBusyOperation, m as WikiCheckpoint, n as WikiConfig, o as WikiEdge, p as WikiEvent, q as WikiFact, r as WikiMemoryTestAccess, s as WikiOutboxEvent, t as WikiTask } from './testing-NH1_Aigh.mjs';
|
|
3
3
|
import { OkfFile } from '@equationalapplications/core-okf';
|
|
4
4
|
import 'minisearch';
|
|
5
5
|
|
|
@@ -11,6 +11,12 @@ declare function formatOkfBundle(dump: MemoryDump): {
|
|
|
11
11
|
files: OkfFile[];
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
interface OkfImportOptions {
|
|
15
|
+
typeMapping?: Record<string, 'fact' | 'task' | 'ignore'>;
|
|
16
|
+
defaultSchema?: 'fact' | 'task' | 'ignore';
|
|
17
|
+
}
|
|
18
|
+
declare function parseOkfBundle(entityId: string, files: OkfFile[], options?: OkfImportOptions): MemoryDump;
|
|
19
|
+
|
|
14
20
|
declare function parseEmbedding(blob: Uint8Array | null | undefined, text: string | null | undefined): Float32Array | null;
|
|
15
21
|
|
|
16
22
|
interface LibrarianOptions {
|
|
@@ -37,4 +43,4 @@ declare function mapLibrarianOptionsToReadOptions(options: LibrarianOptions): Pi
|
|
|
37
43
|
|
|
38
44
|
declare function createWiki(db: SQLiteAdapter, options: WikiOptions): WikiMemory;
|
|
39
45
|
|
|
40
|
-
export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, FormatContextOptions, FormattedMemoryDump, type LibrarianOptions, type LibrarianPromptVariables, MemoryBundle, MemoryDump, ReadOptions, SQLiteAdapter, WikiMemory, WikiOptions, createWiki, formatContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, validateLibrarianPromptTemplate };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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 ExtractedTask, H as HOOK_TIMEOUT_MARKER, L as LLMProvider, P as PromptOverrides, f as PromptService, g as PrunePartialFailureError, V as VectorRanker, h as VectorRankerFallback, i as VectorRankerRankArgs, j as VectorRankerSemanticResult, k as WikiBusyError, l as WikiBusyOperation, m as WikiCheckpoint, n as WikiConfig, o as
|
|
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-NH1_Aigh.js';
|
|
2
|
+
export { E as EntityStatus, d as ExtractedFact, e as ExtractedTask, H as HOOK_TIMEOUT_MARKER, L as LLMProvider, P as PromptOverrides, f as PromptService, g as PrunePartialFailureError, V as VectorRanker, h as VectorRankerFallback, i as VectorRankerRankArgs, j as VectorRankerSemanticResult, k as WikiBusyError, l as WikiBusyOperation, m as WikiCheckpoint, n as WikiConfig, o as WikiEdge, p as WikiEvent, q as WikiFact, r as WikiMemoryTestAccess, s as WikiOutboxEvent, t as WikiTask } from './testing-NH1_Aigh.js';
|
|
3
3
|
import { OkfFile } from '@equationalapplications/core-okf';
|
|
4
4
|
import 'minisearch';
|
|
5
5
|
|
|
@@ -11,6 +11,12 @@ declare function formatOkfBundle(dump: MemoryDump): {
|
|
|
11
11
|
files: OkfFile[];
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
interface OkfImportOptions {
|
|
15
|
+
typeMapping?: Record<string, 'fact' | 'task' | 'ignore'>;
|
|
16
|
+
defaultSchema?: 'fact' | 'task' | 'ignore';
|
|
17
|
+
}
|
|
18
|
+
declare function parseOkfBundle(entityId: string, files: OkfFile[], options?: OkfImportOptions): MemoryDump;
|
|
19
|
+
|
|
14
20
|
declare function parseEmbedding(blob: Uint8Array | null | undefined, text: string | null | undefined): Float32Array | null;
|
|
15
21
|
|
|
16
22
|
interface LibrarianOptions {
|
|
@@ -37,4 +43,4 @@ declare function mapLibrarianOptionsToReadOptions(options: LibrarianOptions): Pi
|
|
|
37
43
|
|
|
38
44
|
declare function createWiki(db: SQLiteAdapter, options: WikiOptions): WikiMemory;
|
|
39
45
|
|
|
40
|
-
export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, FormatContextOptions, FormattedMemoryDump, type LibrarianOptions, type LibrarianPromptVariables, MemoryBundle, MemoryDump, ReadOptions, SQLiteAdapter, WikiMemory, WikiOptions, createWiki, formatContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseEmbedding, validateLibrarianPromptTemplate };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,8 @@ async function setupDatabase(db, prefix) {
|
|
|
34
34
|
access_count INTEGER NOT NULL DEFAULT 0,
|
|
35
35
|
deleted_at INTEGER,
|
|
36
36
|
embedding TEXT,
|
|
37
|
-
embedding_blob BLOB
|
|
37
|
+
embedding_blob BLOB,
|
|
38
|
+
okf_type TEXT
|
|
38
39
|
);
|
|
39
40
|
|
|
40
41
|
CREATE INDEX IF NOT EXISTS ${prefix}entries_entity_idx ON ${prefix}entries(entity_id);
|
|
@@ -51,11 +52,24 @@ async function setupDatabase(db, prefix) {
|
|
|
51
52
|
created_at INTEGER NOT NULL,
|
|
52
53
|
updated_at INTEGER NOT NULL,
|
|
53
54
|
resolved_at INTEGER,
|
|
54
|
-
deleted_at INTEGER
|
|
55
|
+
deleted_at INTEGER,
|
|
56
|
+
okf_type TEXT
|
|
55
57
|
);
|
|
56
58
|
|
|
57
59
|
CREATE INDEX IF NOT EXISTS ${prefix}tasks_entity_idx ON ${prefix}tasks(entity_id, status);
|
|
58
60
|
|
|
61
|
+
CREATE TABLE IF NOT EXISTS ${prefix}edges (
|
|
62
|
+
id TEXT PRIMARY KEY,
|
|
63
|
+
entity_id TEXT NOT NULL,
|
|
64
|
+
source_id TEXT NOT NULL,
|
|
65
|
+
target_id TEXT NOT NULL,
|
|
66
|
+
edge_type TEXT NOT NULL,
|
|
67
|
+
created_at INTEGER NOT NULL,
|
|
68
|
+
UNIQUE(entity_id, source_id, target_id, edge_type)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
CREATE INDEX IF NOT EXISTS ${prefix}edges_entity_idx ON ${prefix}edges(entity_id);
|
|
72
|
+
|
|
59
73
|
CREATE TABLE IF NOT EXISTS ${prefix}events (
|
|
60
74
|
id TEXT PRIMARY KEY,
|
|
61
75
|
entity_id TEXT NOT NULL,
|
|
@@ -156,6 +170,32 @@ var MIGRATIONS = [
|
|
|
156
170
|
ON ${prefix}outbox (entity_id, created_at);
|
|
157
171
|
`);
|
|
158
172
|
}
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
version: 5,
|
|
176
|
+
description: "Add okf_type to entries/tasks for OKF type fidelity; create edges table for OKF graph import",
|
|
177
|
+
run: async (db, prefix) => {
|
|
178
|
+
for (const table of ["entries", "tasks"]) {
|
|
179
|
+
const cols = await db.getAllAsync(
|
|
180
|
+
`PRAGMA table_info(${prefix}${table})`
|
|
181
|
+
);
|
|
182
|
+
if (!cols.some((c) => c.name === "okf_type")) {
|
|
183
|
+
await db.execAsync(`ALTER TABLE ${prefix}${table} ADD COLUMN okf_type TEXT`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
await db.execAsync(`
|
|
187
|
+
CREATE TABLE IF NOT EXISTS ${prefix}edges (
|
|
188
|
+
id TEXT PRIMARY KEY,
|
|
189
|
+
entity_id TEXT NOT NULL,
|
|
190
|
+
source_id TEXT NOT NULL,
|
|
191
|
+
target_id TEXT NOT NULL,
|
|
192
|
+
edge_type TEXT NOT NULL,
|
|
193
|
+
created_at INTEGER NOT NULL,
|
|
194
|
+
UNIQUE(entity_id, source_id, target_id, edge_type)
|
|
195
|
+
);
|
|
196
|
+
CREATE INDEX IF NOT EXISTS ${prefix}edges_entity_idx ON ${prefix}edges (entity_id);
|
|
197
|
+
`);
|
|
198
|
+
}
|
|
159
199
|
}
|
|
160
200
|
];
|
|
161
201
|
for (let i = 1; i < MIGRATIONS.length; i++) {
|
|
@@ -207,7 +247,8 @@ function mapRowToFact(row) {
|
|
|
207
247
|
updated_at: Number(row.updated_at),
|
|
208
248
|
last_accessed_at: row.last_accessed_at === null || row.last_accessed_at === void 0 ? null : Number(row.last_accessed_at),
|
|
209
249
|
deleted_at: row.deleted_at != null ? Number(row.deleted_at) : null,
|
|
210
|
-
access_count: Number(row.access_count ?? 0)
|
|
250
|
+
access_count: Number(row.access_count ?? 0),
|
|
251
|
+
okf_type: row.okf_type ?? null
|
|
211
252
|
};
|
|
212
253
|
}
|
|
213
254
|
function normalizeEmbeddingBlobValue(blob) {
|
|
@@ -380,8 +421,8 @@ var EntryRepository = class extends BaseRepository {
|
|
|
380
421
|
`INSERT INTO ${this.prefix}entries (
|
|
381
422
|
id, entity_id, title, body, tags, confidence, source_type,
|
|
382
423
|
source_hash, source_ref, created_at, updated_at, last_accessed_at, access_count,
|
|
383
|
-
deleted_at, embedding_blob, embedding
|
|
384
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
424
|
+
deleted_at, embedding_blob, embedding, okf_type
|
|
425
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
385
426
|
ON CONFLICT(id) DO UPDATE SET
|
|
386
427
|
entity_id = excluded.entity_id,
|
|
387
428
|
title = excluded.title,
|
|
@@ -397,7 +438,8 @@ var EntryRepository = class extends BaseRepository {
|
|
|
397
438
|
access_count = excluded.access_count,
|
|
398
439
|
deleted_at = excluded.deleted_at,
|
|
399
440
|
embedding_blob = excluded.embedding_blob,
|
|
400
|
-
embedding = NULL
|
|
441
|
+
embedding = NULL,
|
|
442
|
+
okf_type = excluded.okf_type`,
|
|
401
443
|
[
|
|
402
444
|
fact.id,
|
|
403
445
|
fact.entity_id,
|
|
@@ -414,7 +456,8 @@ var EntryRepository = class extends BaseRepository {
|
|
|
414
456
|
fact.access_count,
|
|
415
457
|
fact.deleted_at ?? null,
|
|
416
458
|
embeddingBlob ?? null,
|
|
417
|
-
null
|
|
459
|
+
null,
|
|
460
|
+
fact.okf_type ?? null
|
|
418
461
|
]
|
|
419
462
|
);
|
|
420
463
|
return result;
|
|
@@ -994,7 +1037,8 @@ function mapRowToTask(row) {
|
|
|
994
1037
|
created_at: Number(row.created_at),
|
|
995
1038
|
updated_at: Number(row.updated_at),
|
|
996
1039
|
resolved_at: row.resolved_at != null ? Number(row.resolved_at) : null,
|
|
997
|
-
deleted_at: row.deleted_at != null ? Number(row.deleted_at) : null
|
|
1040
|
+
deleted_at: row.deleted_at != null ? Number(row.deleted_at) : null,
|
|
1041
|
+
okf_type: row.okf_type ?? null
|
|
998
1042
|
};
|
|
999
1043
|
}
|
|
1000
1044
|
var TaskRepository = class extends BaseRepository {
|
|
@@ -1096,8 +1140,8 @@ var TaskRepository = class extends BaseRepository {
|
|
|
1096
1140
|
await executor.runAsync(
|
|
1097
1141
|
`INSERT INTO ${this.prefix}tasks (
|
|
1098
1142
|
id, entity_id, description, status, priority,
|
|
1099
|
-
created_at, updated_at, resolved_at, deleted_at
|
|
1100
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1143
|
+
created_at, updated_at, resolved_at, deleted_at, okf_type
|
|
1144
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1101
1145
|
ON CONFLICT(id) DO UPDATE SET
|
|
1102
1146
|
entity_id = excluded.entity_id,
|
|
1103
1147
|
description = excluded.description,
|
|
@@ -1105,7 +1149,8 @@ var TaskRepository = class extends BaseRepository {
|
|
|
1105
1149
|
priority = excluded.priority,
|
|
1106
1150
|
updated_at = excluded.updated_at,
|
|
1107
1151
|
resolved_at = excluded.resolved_at,
|
|
1108
|
-
deleted_at = excluded.deleted_at
|
|
1152
|
+
deleted_at = excluded.deleted_at,
|
|
1153
|
+
okf_type = excluded.okf_type`,
|
|
1109
1154
|
[
|
|
1110
1155
|
task.id,
|
|
1111
1156
|
task.entity_id,
|
|
@@ -1115,7 +1160,8 @@ var TaskRepository = class extends BaseRepository {
|
|
|
1115
1160
|
task.created_at,
|
|
1116
1161
|
now,
|
|
1117
1162
|
task.resolved_at ?? null,
|
|
1118
|
-
task.deleted_at ?? null
|
|
1163
|
+
task.deleted_at ?? null,
|
|
1164
|
+
task.okf_type ?? null
|
|
1119
1165
|
]
|
|
1120
1166
|
);
|
|
1121
1167
|
}
|
|
@@ -1337,6 +1383,53 @@ var EventRepository = class extends BaseRepository {
|
|
|
1337
1383
|
}
|
|
1338
1384
|
};
|
|
1339
1385
|
|
|
1386
|
+
// src/repositories/EdgeRepository.ts
|
|
1387
|
+
var EdgeRepository = class extends BaseRepository {
|
|
1388
|
+
/**
|
|
1389
|
+
* Insert an edge, silently skipping on primary-key or uniqueness conflicts.
|
|
1390
|
+
* Throws when the insert was skipped due to an id collision with a different edge tuple.
|
|
1391
|
+
*/
|
|
1392
|
+
async addIgnoreDuplicate(edge, tx) {
|
|
1393
|
+
const executor = this.getExecutor(tx);
|
|
1394
|
+
const result = await executor.runAsync(
|
|
1395
|
+
`INSERT OR IGNORE INTO ${this.prefix}edges (id, entity_id, source_id, target_id, edge_type, created_at)
|
|
1396
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
1397
|
+
[edge.id, edge.entity_id, edge.source_id, edge.target_id, edge.edge_type, edge.created_at]
|
|
1398
|
+
);
|
|
1399
|
+
if (result.changes > 0) return;
|
|
1400
|
+
const existing = await executor.getFirstAsync(
|
|
1401
|
+
`SELECT entity_id, source_id, target_id, edge_type FROM ${this.prefix}edges WHERE id = ?`,
|
|
1402
|
+
[edge.id]
|
|
1403
|
+
);
|
|
1404
|
+
if (!existing) return;
|
|
1405
|
+
if (String(existing.entity_id) !== edge.entity_id || String(existing.source_id) !== edge.source_id || String(existing.target_id) !== edge.target_id || String(existing.edge_type) !== edge.edge_type) {
|
|
1406
|
+
throw new Error(
|
|
1407
|
+
`Edge id collision: ${JSON.stringify(edge.id)} already exists with a different (entity_id, source_id, target_id, edge_type) tuple`
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
async getByEntityId(entityId, tx) {
|
|
1412
|
+
const executor = this.getExecutor(tx);
|
|
1413
|
+
const rows = await executor.getAllAsync(
|
|
1414
|
+
`SELECT * FROM ${this.prefix}edges WHERE entity_id = ? ORDER BY created_at ASC`,
|
|
1415
|
+
[entityId]
|
|
1416
|
+
);
|
|
1417
|
+
return rows.map((row) => ({
|
|
1418
|
+
id: String(row.id),
|
|
1419
|
+
entity_id: String(row.entity_id),
|
|
1420
|
+
source_id: String(row.source_id),
|
|
1421
|
+
target_id: String(row.target_id),
|
|
1422
|
+
edge_type: String(row.edge_type),
|
|
1423
|
+
created_at: Number(row.created_at)
|
|
1424
|
+
}));
|
|
1425
|
+
}
|
|
1426
|
+
/** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
|
|
1427
|
+
async bulkDeleteByEntityId(entityId, tx) {
|
|
1428
|
+
const executor = this.getExecutor(tx);
|
|
1429
|
+
await executor.runAsync(`DELETE FROM ${this.prefix}edges WHERE entity_id = ?`, [entityId]);
|
|
1430
|
+
}
|
|
1431
|
+
};
|
|
1432
|
+
|
|
1340
1433
|
// src/repositories/MetadataRepository.ts
|
|
1341
1434
|
var MetadataRepository = class extends BaseRepository {
|
|
1342
1435
|
// CHECKPOINTS TABLE METHODS
|
|
@@ -2842,11 +2935,12 @@ var MAX_EMBEDDING_BLOB_BYTES = 32 * 1024;
|
|
|
2842
2935
|
var IMPORT_TITLE_MAX = 500;
|
|
2843
2936
|
var IMPORT_BODY_MAX = 8e3;
|
|
2844
2937
|
var ImportExportService = class {
|
|
2845
|
-
constructor(db, entryRepo, taskRepo, eventRepo, metadataRepo, searchService, jobManager, embeddingService) {
|
|
2938
|
+
constructor(db, entryRepo, taskRepo, eventRepo, edgeRepo, metadataRepo, searchService, jobManager, embeddingService) {
|
|
2846
2939
|
this.db = db;
|
|
2847
2940
|
this.entryRepo = entryRepo;
|
|
2848
2941
|
this.taskRepo = taskRepo;
|
|
2849
2942
|
this.eventRepo = eventRepo;
|
|
2943
|
+
this.edgeRepo = edgeRepo;
|
|
2850
2944
|
this.metadataRepo = metadataRepo;
|
|
2851
2945
|
this.searchService = searchService;
|
|
2852
2946
|
this.jobManager = jobManager;
|
|
@@ -2891,10 +2985,11 @@ var ImportExportService = class {
|
|
|
2891
2985
|
}
|
|
2892
2986
|
}
|
|
2893
2987
|
async getFullBundle(entityId, opts) {
|
|
2894
|
-
const [factsRaw, tasks, events] = await Promise.all([
|
|
2988
|
+
const [factsRaw, tasks, events, edges] = await Promise.all([
|
|
2895
2989
|
opts?.includeBlobs ? this.entryRepo.findAllByEntityIdWithBlobs(entityId) : this.entryRepo.findAllByEntityId(entityId),
|
|
2896
2990
|
this.taskRepo.findAllByEntityId(entityId),
|
|
2897
|
-
this.eventRepo.getByEntityId(entityId, opts?.maxEvents)
|
|
2991
|
+
this.eventRepo.getByEntityId(entityId, opts?.maxEvents),
|
|
2992
|
+
this.edgeRepo.getByEntityId(entityId)
|
|
2898
2993
|
]);
|
|
2899
2994
|
const facts = factsRaw.map((f) => {
|
|
2900
2995
|
const {
|
|
@@ -2913,7 +3008,7 @@ var ImportExportService = class {
|
|
|
2913
3008
|
tags: typeof factBase.tags === "string" ? JSON.parse(factBase.tags) : factBase.tags
|
|
2914
3009
|
};
|
|
2915
3010
|
});
|
|
2916
|
-
return { facts, tasks, events };
|
|
3011
|
+
return { facts, tasks, events, edges };
|
|
2917
3012
|
}
|
|
2918
3013
|
/** Single-entity import transaction + post-processing; package-internal hook for tests. */
|
|
2919
3014
|
async doImportEntity(entityId, bundle, merge) {
|
|
@@ -2935,6 +3030,7 @@ var ImportExportService = class {
|
|
|
2935
3030
|
softDeletedFactIds.push(...deletedLiveFactIds);
|
|
2936
3031
|
await this.entryRepo.bulkSoftDeleteByEntityId(entityId, tx);
|
|
2937
3032
|
await this.taskRepo.bulkSoftDeleteByEntityId(entityId, tx);
|
|
3033
|
+
await this.edgeRepo.bulkDeleteByEntityId(entityId, tx);
|
|
2938
3034
|
await this.metadataRepo.deleteCheckpoint(entityId, tx);
|
|
2939
3035
|
}
|
|
2940
3036
|
const factIds = bundle.facts.map((fact) => fact.id);
|
|
@@ -3032,7 +3128,8 @@ var ImportExportService = class {
|
|
|
3032
3128
|
last_accessed_at: fact.last_accessed_at,
|
|
3033
3129
|
access_count: fact.access_count,
|
|
3034
3130
|
deleted_at: fact.deleted_at,
|
|
3035
|
-
embedding_blob: blobData ?? void 0
|
|
3131
|
+
embedding_blob: blobData ?? void 0,
|
|
3132
|
+
okf_type: fact.okf_type ?? null
|
|
3036
3133
|
};
|
|
3037
3134
|
await this.entryRepo.upsertForImport(factObj, tx);
|
|
3038
3135
|
if (blobData != null) {
|
|
@@ -3081,7 +3178,8 @@ var ImportExportService = class {
|
|
|
3081
3178
|
created_at: task.created_at,
|
|
3082
3179
|
updated_at: safeUpdatedAt,
|
|
3083
3180
|
resolved_at: task.resolved_at,
|
|
3084
|
-
deleted_at: task.deleted_at
|
|
3181
|
+
deleted_at: task.deleted_at,
|
|
3182
|
+
okf_type: task.okf_type ?? null
|
|
3085
3183
|
},
|
|
3086
3184
|
tx,
|
|
3087
3185
|
safeUpdatedAt
|
|
@@ -3105,6 +3203,19 @@ var ImportExportService = class {
|
|
|
3105
3203
|
tx
|
|
3106
3204
|
);
|
|
3107
3205
|
}
|
|
3206
|
+
for (const edge of bundle.edges ?? []) {
|
|
3207
|
+
await this.edgeRepo.addIgnoreDuplicate(
|
|
3208
|
+
{
|
|
3209
|
+
id: edge.id,
|
|
3210
|
+
entity_id: entityId,
|
|
3211
|
+
source_id: edge.source_id,
|
|
3212
|
+
target_id: edge.target_id,
|
|
3213
|
+
edge_type: edge.edge_type,
|
|
3214
|
+
created_at: edge.created_at
|
|
3215
|
+
},
|
|
3216
|
+
tx
|
|
3217
|
+
);
|
|
3218
|
+
}
|
|
3108
3219
|
});
|
|
3109
3220
|
await this.searchService.sync(entityId);
|
|
3110
3221
|
for (const fact of bundle.facts) {
|
|
@@ -3421,7 +3532,7 @@ var RetrievalService = class {
|
|
|
3421
3532
|
const sanitizedTierWeights = shouldExposeReadMetadata(entityId) ? sanitizeTierWeights(entityIds, options?.tierWeights) : void 0;
|
|
3422
3533
|
const exposeMetadata = shouldExposeReadMetadata(entityId);
|
|
3423
3534
|
if (entityIds.length === 0) {
|
|
3424
|
-
const empty = { facts: [], tasks: [], events: [] };
|
|
3535
|
+
const empty = { facts: [], tasks: [], events: [], edges: [] };
|
|
3425
3536
|
if (exposeMetadata) {
|
|
3426
3537
|
empty.metadata = { query, entityIds: [] };
|
|
3427
3538
|
if (sanitizedTierWeights && Object.keys(sanitizedTierWeights).length > 0) empty.metadata.tierWeights = sanitizedTierWeights;
|
|
@@ -3811,7 +3922,7 @@ var RetrievalService = class {
|
|
|
3811
3922
|
if (exposeMetadata && trimmedQuery && scoreByFactId) {
|
|
3812
3923
|
factScores = Object.fromEntries(facts.map((fact) => [fact.id, scoreByFactId.get(fact.id) ?? 0]));
|
|
3813
3924
|
}
|
|
3814
|
-
const bundle = { facts, tasks, events: events.reverse() };
|
|
3925
|
+
const bundle = { facts, tasks, events: events.reverse(), edges: [] };
|
|
3815
3926
|
if (exposeMetadata) {
|
|
3816
3927
|
bundle.metadata = { query, entityIds };
|
|
3817
3928
|
if (sanitizedTierWeights && Object.keys(sanitizedTierWeights).length > 0) bundle.metadata.tierWeights = sanitizedTierWeights;
|
|
@@ -4029,6 +4140,7 @@ var WikiMemory = class {
|
|
|
4029
4140
|
this.entryRepo = new EntryRepository(db, this.prefix, this.outboxRepo);
|
|
4030
4141
|
this.taskRepo = new TaskRepository(db, this.prefix, this.outboxRepo);
|
|
4031
4142
|
this.eventRepo = new EventRepository(db, this.prefix);
|
|
4143
|
+
this.edgeRepo = new EdgeRepository(db, this.prefix);
|
|
4032
4144
|
this.metadataRepo = new MetadataRepository(db, this.prefix);
|
|
4033
4145
|
this.embeddingService = new EmbeddingService(this.db, this.options, this.entryRepo, this.metadataRepo);
|
|
4034
4146
|
this.searchService = new SearchService(this.entryRepo);
|
|
@@ -4062,6 +4174,7 @@ var WikiMemory = class {
|
|
|
4062
4174
|
this.entryRepo,
|
|
4063
4175
|
this.taskRepo,
|
|
4064
4176
|
this.eventRepo,
|
|
4177
|
+
this.edgeRepo,
|
|
4065
4178
|
this.metadataRepo,
|
|
4066
4179
|
this.searchService,
|
|
4067
4180
|
this.jobManager,
|
|
@@ -4522,7 +4635,7 @@ function formatMemoryDump(dump) {
|
|
|
4522
4635
|
}
|
|
4523
4636
|
function factFrontmatter(f) {
|
|
4524
4637
|
return {
|
|
4525
|
-
type: "fact",
|
|
4638
|
+
type: f.okf_type ?? "fact",
|
|
4526
4639
|
title: f.title,
|
|
4527
4640
|
tags: f.tags,
|
|
4528
4641
|
timestamp: new Date(f.updated_at).toISOString(),
|
|
@@ -4540,7 +4653,7 @@ function factFrontmatter(f) {
|
|
|
4540
4653
|
}
|
|
4541
4654
|
function taskFrontmatter(t) {
|
|
4542
4655
|
return {
|
|
4543
|
-
type: "task",
|
|
4656
|
+
type: t.okf_type ?? "task",
|
|
4544
4657
|
title: t.description,
|
|
4545
4658
|
timestamp: new Date(t.updated_at).toISOString(),
|
|
4546
4659
|
id: t.id,
|
|
@@ -4615,6 +4728,227 @@ function formatOkfBundle(dump) {
|
|
|
4615
4728
|
});
|
|
4616
4729
|
return { files };
|
|
4617
4730
|
}
|
|
4731
|
+
var CONFIDENCE_VALUES = /* @__PURE__ */ new Set(["certain", "inferred", "tentative"]);
|
|
4732
|
+
var SOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
4733
|
+
"user_stated",
|
|
4734
|
+
"librarian_inferred",
|
|
4735
|
+
"user_confirmed",
|
|
4736
|
+
"immutable_document"
|
|
4737
|
+
]);
|
|
4738
|
+
var TASK_STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress", "done", "abandoned"]);
|
|
4739
|
+
var EVENT_TYPES = /* @__PURE__ */ new Set(["observation", "decision", "action", "outcome"]);
|
|
4740
|
+
function basenameMd(filePath) {
|
|
4741
|
+
const name = filePath.slice(filePath.lastIndexOf("/") + 1);
|
|
4742
|
+
return name.endsWith(".md") ? name.slice(0, -3) : name;
|
|
4743
|
+
}
|
|
4744
|
+
function isConceptFile(filePath) {
|
|
4745
|
+
if (!filePath.endsWith(".md")) return false;
|
|
4746
|
+
if (filePath.endsWith("/index.md") || filePath === "index.md") return false;
|
|
4747
|
+
if (filePath.endsWith("/log.md") || filePath === "log.md") return false;
|
|
4748
|
+
return true;
|
|
4749
|
+
}
|
|
4750
|
+
function isStructuralPath(filePath) {
|
|
4751
|
+
return filePath.endsWith("/index.md") || filePath === "index.md" || filePath.endsWith("/log.md") || filePath === "log.md";
|
|
4752
|
+
}
|
|
4753
|
+
function posixDirname(filePath) {
|
|
4754
|
+
const idx = filePath.lastIndexOf("/");
|
|
4755
|
+
return idx === -1 ? "" : filePath.slice(0, idx);
|
|
4756
|
+
}
|
|
4757
|
+
function resolveRelativePath(fromFile, linkPath) {
|
|
4758
|
+
const baseDir = posixDirname(fromFile);
|
|
4759
|
+
const segments = [...baseDir ? baseDir.split("/") : [], ...linkPath.split("/")];
|
|
4760
|
+
const resolved = [];
|
|
4761
|
+
for (const seg of segments) {
|
|
4762
|
+
if (seg === "" || seg === ".") continue;
|
|
4763
|
+
if (seg === "..") {
|
|
4764
|
+
resolved.pop();
|
|
4765
|
+
continue;
|
|
4766
|
+
}
|
|
4767
|
+
resolved.push(seg);
|
|
4768
|
+
}
|
|
4769
|
+
return resolved.join("/");
|
|
4770
|
+
}
|
|
4771
|
+
function addPathAliases(map, filePath, resolvedId) {
|
|
4772
|
+
map.set(filePath, resolvedId);
|
|
4773
|
+
const withoutDot = filePath.replace(/^\.\//, "");
|
|
4774
|
+
if (withoutDot !== filePath) map.set(withoutDot, resolvedId);
|
|
4775
|
+
const entityRelative = filePath.replace(/^entities\/[^/]+\//, "");
|
|
4776
|
+
if (entityRelative !== filePath) {
|
|
4777
|
+
map.set(entityRelative, resolvedId);
|
|
4778
|
+
map.set(`./${entityRelative}`, resolvedId);
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
function lookupResolvedId(map, path) {
|
|
4782
|
+
const normalized = path.replace(/^\.\//, "");
|
|
4783
|
+
return map.get(path) ?? map.get(normalized) ?? map.get(`./${normalized}`);
|
|
4784
|
+
}
|
|
4785
|
+
function stripLinkSuffix(linkPath) {
|
|
4786
|
+
const hashIdx = linkPath.indexOf("#");
|
|
4787
|
+
const queryIdx = linkPath.indexOf("?");
|
|
4788
|
+
if (hashIdx === -1 && queryIdx === -1) return linkPath;
|
|
4789
|
+
const cut = hashIdx === -1 ? queryIdx : queryIdx === -1 ? hashIdx : Math.min(hashIdx, queryIdx);
|
|
4790
|
+
return linkPath.slice(0, cut);
|
|
4791
|
+
}
|
|
4792
|
+
function resolveRoute(filePath, frontmatterType, options) {
|
|
4793
|
+
if (options?.typeMapping && Object.prototype.hasOwnProperty.call(options.typeMapping, frontmatterType)) {
|
|
4794
|
+
return options.typeMapping[frontmatterType];
|
|
4795
|
+
}
|
|
4796
|
+
if (filePath.includes("/facts/")) return "fact";
|
|
4797
|
+
if (filePath.includes("/tasks/")) return "task";
|
|
4798
|
+
return options?.defaultSchema ?? "fact";
|
|
4799
|
+
}
|
|
4800
|
+
function parseFrontmatterTimestamp(value, fallback) {
|
|
4801
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4802
|
+
if (typeof value === "string") {
|
|
4803
|
+
const parsed = Date.parse(value);
|
|
4804
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
4805
|
+
}
|
|
4806
|
+
return fallback;
|
|
4807
|
+
}
|
|
4808
|
+
function unescapeLogSummary(summary) {
|
|
4809
|
+
return summary.replace(/\\\]/g, "]").replace(/\\\[/g, "[").replace(/\\\\/g, "\\");
|
|
4810
|
+
}
|
|
4811
|
+
var LOG_LINE_PATTERN = /^\(([^)]+)\)\s*(?:\[((?:\\.|[^\]])*)\]\(([^)]+)\)|(.+))$/;
|
|
4812
|
+
function parseLogEntryText(text) {
|
|
4813
|
+
const match = LOG_LINE_PATTERN.exec(text.trim());
|
|
4814
|
+
if (!match) return null;
|
|
4815
|
+
const [, rawType, linkedSummary, linkPath, plainSummary] = match;
|
|
4816
|
+
const event_type = EVENT_TYPES.has(rawType) ? rawType : "observation";
|
|
4817
|
+
if (linkPath) {
|
|
4818
|
+
return { event_type, summary: unescapeLogSummary(linkedSummary), linkPath };
|
|
4819
|
+
}
|
|
4820
|
+
return { event_type, summary: (plainSummary ?? "").trim() };
|
|
4821
|
+
}
|
|
4822
|
+
function frontmatterToFact(entityId, id, frontmatter, body, now) {
|
|
4823
|
+
const created_at = parseFrontmatterTimestamp(frontmatter.created_at, now);
|
|
4824
|
+
const updated_at = parseFrontmatterTimestamp(
|
|
4825
|
+
frontmatter.timestamp,
|
|
4826
|
+
parseFrontmatterTimestamp(frontmatter.updated_at, now)
|
|
4827
|
+
);
|
|
4828
|
+
return {
|
|
4829
|
+
id,
|
|
4830
|
+
entity_id: entityId,
|
|
4831
|
+
title: typeof frontmatter.title === "string" ? frontmatter.title : "",
|
|
4832
|
+
body,
|
|
4833
|
+
tags: Array.isArray(frontmatter.tags) ? frontmatter.tags.filter((t) => typeof t === "string") : [],
|
|
4834
|
+
confidence: CONFIDENCE_VALUES.has(String(frontmatter.confidence)) ? frontmatter.confidence : "tentative",
|
|
4835
|
+
source_type: SOURCE_TYPES.has(String(frontmatter.source_type)) ? frontmatter.source_type : "user_stated",
|
|
4836
|
+
source_hash: typeof frontmatter.source_hash === "string" ? frontmatter.source_hash : null,
|
|
4837
|
+
source_ref: typeof frontmatter.resource === "string" ? frontmatter.resource : null,
|
|
4838
|
+
created_at,
|
|
4839
|
+
updated_at,
|
|
4840
|
+
last_accessed_at: frontmatter.last_accessed_at != null ? parseFrontmatterTimestamp(frontmatter.last_accessed_at, now) : null,
|
|
4841
|
+
access_count: typeof frontmatter.access_count === "number" ? frontmatter.access_count : 0,
|
|
4842
|
+
deleted_at: frontmatter.deleted_at != null ? parseFrontmatterTimestamp(frontmatter.deleted_at, 0) : null,
|
|
4843
|
+
okf_type: frontmatter.type
|
|
4844
|
+
};
|
|
4845
|
+
}
|
|
4846
|
+
function frontmatterToTask(entityId, id, frontmatter, now) {
|
|
4847
|
+
const created_at = parseFrontmatterTimestamp(frontmatter.created_at, now);
|
|
4848
|
+
const updated_at = parseFrontmatterTimestamp(
|
|
4849
|
+
frontmatter.timestamp,
|
|
4850
|
+
parseFrontmatterTimestamp(frontmatter.updated_at, now)
|
|
4851
|
+
);
|
|
4852
|
+
return {
|
|
4853
|
+
id,
|
|
4854
|
+
entity_id: entityId,
|
|
4855
|
+
description: typeof frontmatter.title === "string" ? frontmatter.title : "",
|
|
4856
|
+
status: TASK_STATUSES.has(String(frontmatter.status)) ? frontmatter.status : "pending",
|
|
4857
|
+
priority: typeof frontmatter.priority === "number" ? frontmatter.priority : 0,
|
|
4858
|
+
created_at,
|
|
4859
|
+
updated_at,
|
|
4860
|
+
resolved_at: frontmatter.resolved_at != null ? parseFrontmatterTimestamp(frontmatter.resolved_at, now) : null,
|
|
4861
|
+
deleted_at: frontmatter.deleted_at != null ? parseFrontmatterTimestamp(frontmatter.deleted_at, 0) : null,
|
|
4862
|
+
okf_type: frontmatter.type
|
|
4863
|
+
};
|
|
4864
|
+
}
|
|
4865
|
+
function findLogMdPath(files) {
|
|
4866
|
+
return files.find((f) => f.path.endsWith("/log.md") || f.path === "log.md")?.path;
|
|
4867
|
+
}
|
|
4868
|
+
function parseOkfBundle(entityId, files, options) {
|
|
4869
|
+
const now = Date.now();
|
|
4870
|
+
const pathToResolvedId = /* @__PURE__ */ new Map();
|
|
4871
|
+
for (const file of files) {
|
|
4872
|
+
if (!isConceptFile(file.path)) continue;
|
|
4873
|
+
const { frontmatter } = coreOkf.parseConcept(file.content);
|
|
4874
|
+
const route = resolveRoute(file.path, frontmatter.type ?? "", options);
|
|
4875
|
+
if (route === "ignore") continue;
|
|
4876
|
+
const resolvedId = typeof frontmatter.id === "string" && frontmatter.id ? frontmatter.id : basenameMd(file.path);
|
|
4877
|
+
addPathAliases(pathToResolvedId, file.path, resolvedId);
|
|
4878
|
+
}
|
|
4879
|
+
const facts = [];
|
|
4880
|
+
const tasks = [];
|
|
4881
|
+
const edges = [];
|
|
4882
|
+
let logContent = null;
|
|
4883
|
+
const logMdPath = findLogMdPath(files);
|
|
4884
|
+
for (const file of files) {
|
|
4885
|
+
if (file.path.endsWith("/log.md") || file.path === "log.md") {
|
|
4886
|
+
logContent = file.content;
|
|
4887
|
+
continue;
|
|
4888
|
+
}
|
|
4889
|
+
if (!isConceptFile(file.path)) continue;
|
|
4890
|
+
const { frontmatter, body } = coreOkf.parseConcept(file.content);
|
|
4891
|
+
const route = resolveRoute(file.path, frontmatter.type ?? "", options);
|
|
4892
|
+
if (route === "ignore") continue;
|
|
4893
|
+
const resolvedId = typeof frontmatter.id === "string" && frontmatter.id ? frontmatter.id : basenameMd(file.path);
|
|
4894
|
+
if (route === "fact") {
|
|
4895
|
+
facts.push(frontmatterToFact(entityId, resolvedId, frontmatter, body, now));
|
|
4896
|
+
} else {
|
|
4897
|
+
tasks.push(frontmatterToTask(entityId, resolvedId, frontmatter, now));
|
|
4898
|
+
}
|
|
4899
|
+
const seenEdges = /* @__PURE__ */ new Set();
|
|
4900
|
+
for (const link of coreOkf.extractMarkdownLinks(body)) {
|
|
4901
|
+
const strippedPath = stripLinkSuffix(link.path);
|
|
4902
|
+
const directTargetId = lookupResolvedId(pathToResolvedId, strippedPath);
|
|
4903
|
+
const resolvedTargetPath = resolveRelativePath(file.path, strippedPath);
|
|
4904
|
+
if (isStructuralPath(strippedPath) || isStructuralPath(resolvedTargetPath)) continue;
|
|
4905
|
+
const targetId = directTargetId ?? lookupResolvedId(pathToResolvedId, resolvedTargetPath);
|
|
4906
|
+
if (!targetId) continue;
|
|
4907
|
+
const edgeKey = `${resolvedId}\0${targetId}\0${link.text}`;
|
|
4908
|
+
if (seenEdges.has(edgeKey)) continue;
|
|
4909
|
+
seenEdges.add(edgeKey);
|
|
4910
|
+
edges.push({
|
|
4911
|
+
id: generateId(),
|
|
4912
|
+
entity_id: entityId,
|
|
4913
|
+
source_id: resolvedId,
|
|
4914
|
+
target_id: targetId,
|
|
4915
|
+
edge_type: link.text,
|
|
4916
|
+
created_at: now
|
|
4917
|
+
});
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
const events = [];
|
|
4921
|
+
if (logContent != null) {
|
|
4922
|
+
const logPath = logMdPath ?? `entities/${entityId}/log.md`;
|
|
4923
|
+
for (const entry of coreOkf.parseLogMd(logContent)) {
|
|
4924
|
+
const parsed = parseLogEntryText(entry.text);
|
|
4925
|
+
if (!parsed) continue;
|
|
4926
|
+
let related_entry_id = null;
|
|
4927
|
+
if (parsed.linkPath) {
|
|
4928
|
+
const targetPath = resolveRelativePath(logPath, stripLinkSuffix(parsed.linkPath));
|
|
4929
|
+
if (!isStructuralPath(targetPath) && targetPath.includes("/facts/")) {
|
|
4930
|
+
related_entry_id = lookupResolvedId(pathToResolvedId, targetPath) ?? null;
|
|
4931
|
+
}
|
|
4932
|
+
}
|
|
4933
|
+
const created_at = (/* @__PURE__ */ new Date(`${entry.date}T00:00:00.000Z`)).getTime();
|
|
4934
|
+
if (!Number.isFinite(created_at)) continue;
|
|
4935
|
+
events.push({
|
|
4936
|
+
id: generateId("evt_"),
|
|
4937
|
+
entity_id: entityId,
|
|
4938
|
+
event_type: parsed.event_type,
|
|
4939
|
+
summary: parsed.summary,
|
|
4940
|
+
related_entry_id,
|
|
4941
|
+
created_at
|
|
4942
|
+
});
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
return {
|
|
4946
|
+
generatedAt: now,
|
|
4947
|
+
entities: {
|
|
4948
|
+
[entityId]: { facts, tasks, events, edges }
|
|
4949
|
+
}
|
|
4950
|
+
};
|
|
4951
|
+
}
|
|
4618
4952
|
|
|
4619
4953
|
// src/librarianPrompt.ts
|
|
4620
4954
|
var DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT = `You are a careful memory synthesis assistant.
|
|
@@ -4673,6 +5007,7 @@ exports.formatOkfBundle = formatOkfBundle;
|
|
|
4673
5007
|
exports.hydrateLibrarianPrompt = hydrateLibrarianPrompt;
|
|
4674
5008
|
exports.mapLibrarianOptionsToReadOptions = mapLibrarianOptionsToReadOptions;
|
|
4675
5009
|
exports.parseEmbedding = parseEmbedding;
|
|
5010
|
+
exports.parseOkfBundle = parseOkfBundle;
|
|
4676
5011
|
exports.validateLibrarianPromptTemplate = validateLibrarianPromptTemplate;
|
|
4677
5012
|
//# sourceMappingURL=index.js.map
|
|
4678
5013
|
//# sourceMappingURL=index.js.map
|