@equationalapplications/core-llm-wiki 4.20.0 → 4.22.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/README.md +35 -0
- package/dist/{chunk-HKB5FEJG.mjs → chunk-LCAU6NYC.mjs} +270 -94
- package/dist/chunk-LCAU6NYC.mjs.map +1 -0
- package/dist/index.d.mts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +328 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +126 -11
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-BVN_g414.d.mts → testing-Bk8J6QLX.d.mts} +100 -7
- package/dist/{testing-BVN_g414.d.ts → testing-Bk8J6QLX.d.ts} +100 -7
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +167 -6
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-HKB5FEJG.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { __privateAdd, MetadataRepository, EmbeddingService, SearchService, JobManager, PromptService, IngestionService, MaintenanceService, ImportExportService, RetrievalService, WriteService, __privateGet, __privateSet, normalizeSourceRef, normalizeSourceHash, entitySummaryMetaKey, generateId, BaseRepository, emptyManifest, resolveNodeType, validateInlineEdges,
|
|
2
|
-
export { HOOK_TIMEOUT_MARKER, PromptService, PrunePartialFailureError, WikiBusyError, WikiTransactionError, configureRandomSource, parseEmbedding } from './chunk-
|
|
1
|
+
import { __privateAdd, MetadataRepository, EmbeddingService, SearchService, JobManager, PromptService, IngestionService, MaintenanceService, ImportExportService, RetrievalService, WriteService, __privateGet, __privateSet, normalizeSourceRef, normalizeSourceHash, entitySummaryMetaKey, generateId, BaseRepository, emptyManifest, resolveNodeType, validateInlineEdges, resolveEdgeDefinitions, normalizeTitleKey, WikiTransactionError, extractSqliteCode } from './chunk-LCAU6NYC.mjs';
|
|
2
|
+
export { HOOK_TIMEOUT_MARKER, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, WikiBusyError, WikiTransactionError, configureRandomSource, parseEmbedding, validateManifest } from './chunk-LCAU6NYC.mjs';
|
|
3
3
|
import { appendRelatedSection, buildConceptDocument, buildLogMd, buildEntityIndexMd, buildRootIndexMd, isAllowedOkfPath, parseRootIndexMd, parseEntityIndexMd, parseConcept, splitRelatedSection, extractMarkdownLinks, parseLogMd, parseEventIdComment, appendEventIdComment } from '@equationalapplications/core-okf';
|
|
4
4
|
|
|
5
5
|
// src/db/schema.ts
|
|
@@ -22,7 +22,8 @@ async function setupDatabase(db, prefix) {
|
|
|
22
22
|
deleted_at INTEGER,
|
|
23
23
|
embedding TEXT,
|
|
24
24
|
embedding_blob BLOB,
|
|
25
|
-
okf_type TEXT
|
|
25
|
+
okf_type TEXT,
|
|
26
|
+
ontology_checked_at INTEGER
|
|
26
27
|
);
|
|
27
28
|
|
|
28
29
|
CREATE INDEX IF NOT EXISTS ${prefix}entries_entity_idx ON ${prefix}entries(entity_id);
|
|
@@ -248,6 +249,20 @@ var MIGRATIONS = [
|
|
|
248
249
|
);
|
|
249
250
|
`);
|
|
250
251
|
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
version: 7,
|
|
255
|
+
description: "Add ontology_checked_at to entries for ontology backfill recheck cooldown",
|
|
256
|
+
run: async (db, prefix) => {
|
|
257
|
+
const cols = await db.getAllAsync(
|
|
258
|
+
`PRAGMA table_info(${prefix}entries)`
|
|
259
|
+
);
|
|
260
|
+
if (!cols.some((c) => c.name === "ontology_checked_at")) {
|
|
261
|
+
await db.execAsync(
|
|
262
|
+
`ALTER TABLE ${prefix}entries ADD COLUMN ontology_checked_at INTEGER`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
251
266
|
}
|
|
252
267
|
];
|
|
253
268
|
for (let i = 1; i < MIGRATIONS.length; i++) {
|
|
@@ -996,6 +1011,79 @@ var EntryRepository = class extends BaseRepository {
|
|
|
996
1011
|
);
|
|
997
1012
|
return rows.map(mapRowToFact);
|
|
998
1013
|
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Live untyped facts eligible for ontology backfill, oldest first.
|
|
1016
|
+
* Skips facts checked within the recheck cooldown (ontology_checked_at > recheckCutoff).
|
|
1017
|
+
*/
|
|
1018
|
+
async findUntypedByEntityId(entityId, limit, recheckCutoff, tx) {
|
|
1019
|
+
const executor = this.getExecutor(tx);
|
|
1020
|
+
const rows = await executor.getAllAsync(
|
|
1021
|
+
`SELECT * FROM ${this.prefix}entries
|
|
1022
|
+
WHERE entity_id = ? AND okf_type IS NULL AND deleted_at IS NULL
|
|
1023
|
+
AND (ontology_checked_at IS NULL OR ontology_checked_at <= ?)
|
|
1024
|
+
ORDER BY updated_at ASC LIMIT ?`,
|
|
1025
|
+
[entityId, recheckCutoff, limit]
|
|
1026
|
+
);
|
|
1027
|
+
return rows.map(mapRowToFact);
|
|
1028
|
+
}
|
|
1029
|
+
/** Counts live untyped facts: eligible (past cooldown) vs deferred (in cooldown). */
|
|
1030
|
+
async countUntypedByEntityId(entityId, recheckCutoff, tx) {
|
|
1031
|
+
const executor = this.getExecutor(tx);
|
|
1032
|
+
const row = await executor.getFirstAsync(
|
|
1033
|
+
`SELECT
|
|
1034
|
+
SUM(CASE WHEN ontology_checked_at IS NULL OR ontology_checked_at <= ? THEN 1 ELSE 0 END) AS eligible,
|
|
1035
|
+
SUM(CASE WHEN ontology_checked_at IS NOT NULL AND ontology_checked_at > ? THEN 1 ELSE 0 END) AS deferred
|
|
1036
|
+
FROM ${this.prefix}entries
|
|
1037
|
+
WHERE entity_id = ? AND okf_type IS NULL AND deleted_at IS NULL`,
|
|
1038
|
+
[recheckCutoff, recheckCutoff, entityId]
|
|
1039
|
+
);
|
|
1040
|
+
return { eligible: Number(row?.eligible ?? 0), deferred: Number(row?.deferred ?? 0) };
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Sets okf_type only when currently NULL — additive by construction: a
|
|
1044
|
+
* concurrently-typed fact is never overwritten. Returns changes for the caller
|
|
1045
|
+
* to distinguish applied vs skipped.
|
|
1046
|
+
*/
|
|
1047
|
+
async updateOkfType(id, entityId, okfType, tx) {
|
|
1048
|
+
const result = await tx.runAsync(
|
|
1049
|
+
`UPDATE ${this.prefix}entries SET okf_type = ?
|
|
1050
|
+
WHERE id = ? AND entity_id = ? AND okf_type IS NULL AND deleted_at IS NULL`,
|
|
1051
|
+
[okfType, id, entityId]
|
|
1052
|
+
);
|
|
1053
|
+
return { changes: result.changes };
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Stamps the backfill recheck cooldown. NEVER touches updated_at — import
|
|
1057
|
+
* merge resolution is last-write-wins on updated_at and a bump here would
|
|
1058
|
+
* make an unchanged local fact beat a genuinely newer remote edit.
|
|
1059
|
+
*/
|
|
1060
|
+
async markOntologyChecked(ids, entityId, now, tx) {
|
|
1061
|
+
if (ids.length === 0) return;
|
|
1062
|
+
for (let i = 0; i < ids.length; i += this.chunkSize) {
|
|
1063
|
+
const chunk = ids.slice(i, i + this.chunkSize);
|
|
1064
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
1065
|
+
await tx.runAsync(
|
|
1066
|
+
`UPDATE ${this.prefix}entries SET ontology_checked_at = ?
|
|
1067
|
+
WHERE id IN (${placeholders}) AND entity_id = ? AND deleted_at IS NULL`,
|
|
1068
|
+
[now, ...chunk, entityId]
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Lightweight full-breadth title index (id, title, okf_type) over all live
|
|
1074
|
+
* typed facts. Used by ontology backfill edge resolution — a recent-N window
|
|
1075
|
+
* would miss an old fact's contemporaries. Untyped rows are excluded: they
|
|
1076
|
+
* can never pass the edge target-type check, and batch facts typed during
|
|
1077
|
+
* the run are re-added to the in-memory index by the caller.
|
|
1078
|
+
*/
|
|
1079
|
+
async findTitleIndexByEntityId(entityId, tx) {
|
|
1080
|
+
const executor = this.getExecutor(tx);
|
|
1081
|
+
const rows = await executor.getAllAsync(
|
|
1082
|
+
`SELECT id, title, okf_type FROM ${this.prefix}entries WHERE entity_id = ? AND deleted_at IS NULL AND okf_type IS NOT NULL`,
|
|
1083
|
+
[entityId]
|
|
1084
|
+
);
|
|
1085
|
+
return rows.map((r) => ({ id: r.id, title: r.title, okf_type: r.okf_type ?? null }));
|
|
1086
|
+
}
|
|
999
1087
|
};
|
|
1000
1088
|
|
|
1001
1089
|
// src/repositories/OutboxRepository.ts
|
|
@@ -1416,6 +1504,7 @@ var CONFIDENCE_RANK = {
|
|
|
1416
1504
|
var EdgeRepository = class extends BaseRepository {
|
|
1417
1505
|
/**
|
|
1418
1506
|
* Insert an edge, silently skipping on primary-key or uniqueness conflicts.
|
|
1507
|
+
* Returns true when a row was inserted, false when skipped as a duplicate.
|
|
1419
1508
|
* Throws when the insert was skipped due to an id collision with a different edge tuple.
|
|
1420
1509
|
*/
|
|
1421
1510
|
async addIgnoreDuplicate(edge, tx) {
|
|
@@ -1425,17 +1514,18 @@ var EdgeRepository = class extends BaseRepository {
|
|
|
1425
1514
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
1426
1515
|
[edge.id, edge.entity_id, edge.source_id, edge.target_id, edge.edge_type, edge.created_at]
|
|
1427
1516
|
);
|
|
1428
|
-
if (result.changes > 0) return;
|
|
1517
|
+
if (result.changes > 0) return true;
|
|
1429
1518
|
const existing = await executor.getFirstAsync(
|
|
1430
1519
|
`SELECT entity_id, source_id, target_id, edge_type FROM ${this.prefix}edges WHERE id = ?`,
|
|
1431
1520
|
[edge.id]
|
|
1432
1521
|
);
|
|
1433
|
-
if (!existing) return;
|
|
1522
|
+
if (!existing) return false;
|
|
1434
1523
|
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) {
|
|
1435
1524
|
throw new Error(
|
|
1436
1525
|
`Edge id collision: ${JSON.stringify(edge.id)} already exists with a different (entity_id, source_id, target_id, edge_type) tuple`
|
|
1437
1526
|
);
|
|
1438
1527
|
}
|
|
1528
|
+
return false;
|
|
1439
1529
|
}
|
|
1440
1530
|
async getByEntityId(entityId, tx) {
|
|
1441
1531
|
const executor = this.getExecutor(tx);
|
|
@@ -1553,7 +1643,8 @@ function mapRowToEdge(row) {
|
|
|
1553
1643
|
var FACT_ONTOLOGY_FIELDS = `
|
|
1554
1644
|
Each fact may optionally include:
|
|
1555
1645
|
- "okf_type": string \u2014 must be one of the node_types in the manifest
|
|
1556
|
-
- "edges": [{ "edge_type": string, "target_title": string }] \u2014 target_title must match another fact's title in this response or existing memory
|
|
1646
|
+
- "edges": [{ "edge_type": string, "target_title": string }] \u2014 target_title must match another fact's title in this response or existing memory
|
|
1647
|
+
- An edge_type may appear in the manifest multiple times with different source_type/target_type; use the row whose types match your fact and target.`;
|
|
1557
1648
|
var EMERGENT_EXTRA = `
|
|
1558
1649
|
You may also return "ontology_updates" to propose new types:
|
|
1559
1650
|
"ontology_updates": {
|
|
@@ -1635,14 +1726,18 @@ var OntologyService = class {
|
|
|
1635
1726
|
return { okf_type: canonical, edges };
|
|
1636
1727
|
}
|
|
1637
1728
|
async resolveAndPersistEdges(entityId, sourceId, sourceType, edges, manifest, titleIndex, tx, now) {
|
|
1638
|
-
if (!sourceType || edges.length === 0) return;
|
|
1729
|
+
if (!sourceType || edges.length === 0) return 0;
|
|
1730
|
+
let persisted = 0;
|
|
1639
1731
|
for (const edge of edges) {
|
|
1640
|
-
const
|
|
1641
|
-
if (
|
|
1732
|
+
const candidates = resolveEdgeDefinitions(edge.edge_type, manifest).filter((d) => d.source_type.toLowerCase() === sourceType.toLowerCase());
|
|
1733
|
+
if (candidates.length === 0) continue;
|
|
1642
1734
|
const targetKey = normalizeTitleKey(edge.target_title);
|
|
1643
1735
|
const target = titleIndex.get(targetKey);
|
|
1644
1736
|
if (!target) continue;
|
|
1645
|
-
|
|
1737
|
+
const def = candidates.find(
|
|
1738
|
+
(d) => d.target_type.toLowerCase() === (target.okf_type ?? "").toLowerCase()
|
|
1739
|
+
);
|
|
1740
|
+
if (!def) continue;
|
|
1646
1741
|
const wikiEdge = {
|
|
1647
1742
|
id: generateId(),
|
|
1648
1743
|
entity_id: entityId,
|
|
@@ -1651,8 +1746,10 @@ var OntologyService = class {
|
|
|
1651
1746
|
edge_type: def.type,
|
|
1652
1747
|
created_at: now
|
|
1653
1748
|
};
|
|
1654
|
-
await this.edgeRepo.addIgnoreDuplicate(wikiEdge, tx);
|
|
1749
|
+
const inserted = await this.edgeRepo.addIgnoreDuplicate(wikiEdge, tx);
|
|
1750
|
+
if (inserted) persisted++;
|
|
1655
1751
|
}
|
|
1752
|
+
return persisted;
|
|
1656
1753
|
}
|
|
1657
1754
|
};
|
|
1658
1755
|
|
|
@@ -1892,6 +1989,24 @@ var WikiMemory = class {
|
|
|
1892
1989
|
async runHeal(entityId, options) {
|
|
1893
1990
|
return this.maintenanceService.runHeal(entityId, options);
|
|
1894
1991
|
}
|
|
1992
|
+
/**
|
|
1993
|
+
* Types already-persisted untyped facts (okf_type IS NULL) in place via one
|
|
1994
|
+
* librarian-style LLM call. Strictly additive: never creates, deletes, or
|
|
1995
|
+
* rewrites facts; never overwrites an existing okf_type. Free when there is
|
|
1996
|
+
* nothing to do (ontology off, or zero eligible untyped facts).
|
|
1997
|
+
*
|
|
1998
|
+
* Hosts own the trigger cadence (e.g. after each sync); loop `while
|
|
1999
|
+
* result.remaining > 0` for convergence. Throws WikiBusyError when another
|
|
2000
|
+
* backfill (or conflicting maintenance op) is running for the entity.
|
|
2001
|
+
*
|
|
2002
|
+
* @param options.promptOverride - Applies only to this call. For persistent
|
|
2003
|
+
* customization set `options.config.prompts.ontologyBackfillSystemPrompt`.
|
|
2004
|
+
* @param options.batchSize - Facts per run (default 25) for providers with
|
|
2005
|
+
* tighter context limits.
|
|
2006
|
+
*/
|
|
2007
|
+
async runOntologyBackfill(entityId, options) {
|
|
2008
|
+
return this.maintenanceService.runOntologyBackfill(entityId, options);
|
|
2009
|
+
}
|
|
1895
2010
|
async runReembed(entityId, opts) {
|
|
1896
2011
|
return this.maintenanceService.runReembed(entityId, opts);
|
|
1897
2012
|
}
|