@equationalapplications/core-llm-wiki 4.20.0 → 4.21.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 +34 -0
- package/dist/{chunk-HKB5FEJG.mjs → chunk-UYLYN5N4.mjs} +170 -9
- package/dist/chunk-UYLYN5N4.mjs.map +1 -0
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +287 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +118 -7
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-BVN_g414.d.mts → testing-i91HR1TG.d.mts} +100 -7
- package/dist/{testing-BVN_g414.d.ts → testing-i91HR1TG.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/README.md
CHANGED
|
@@ -541,6 +541,40 @@ In **Strict** and **Emergent** modes, librarian and ingest JSON may include type
|
|
|
541
541
|
|
|
542
542
|
See the design spec: [`docs/superpowers/specs/2026-06-23-per-entity-seeded-ontology-design.md`](https://github.com/equationalapplications/expo-llm-wiki/blob/main/docs/superpowers/specs/2026-06-23-per-entity-seeded-ontology-design.md).
|
|
543
543
|
|
|
544
|
+
### Ontology backfill
|
|
545
|
+
|
|
546
|
+
Facts that enter the store without passing through the librarian (synced-down
|
|
547
|
+
remote facts via `importDump`, or facts created before the ontology feature)
|
|
548
|
+
have `okf_type = NULL` and no edges, so `traverseGraph` cannot reach them.
|
|
549
|
+
`runOntologyBackfill` types them in place:
|
|
550
|
+
|
|
551
|
+
```ts
|
|
552
|
+
const result = await wiki.runOntologyBackfill(entityId);
|
|
553
|
+
// { scanned, typed, failedValidation, edgesAdded, remaining, deferred }
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
- **When to call it:** you own the trigger — the library provides the operation,
|
|
557
|
+
not a scheduler (same as `runLibrarian`/`runHeal`). A good default is after
|
|
558
|
+
each sync/import completes. `WikiBusyError` under concurrency is safe to
|
|
559
|
+
swallow; the next trigger retries.
|
|
560
|
+
- **Cost model:** one LLM call only when eligible untyped facts exist; otherwise
|
|
561
|
+
one SELECT. Each run scans at most 25 facts (override via
|
|
562
|
+
`options.batchSize`), oldest first, with the full serialized prompt
|
|
563
|
+
(system + user) capped at 40k chars. One exception: a single fact whose
|
|
564
|
+
prompt alone exceeds the cap is still sent by itself so it is never starved.
|
|
565
|
+
- **Convergence:** loop `while (result.remaining > 0)` to drain a backlog.
|
|
566
|
+
`remaining` counts only *eligible* untyped facts, so the loop terminates even
|
|
567
|
+
when unclassifiable facts exist; those are cooldown-stamped and retried after
|
|
568
|
+
7 days (`deferred` reports them). Because of that weekly retry, host
|
|
569
|
+
dashboards may see small recurring bumps in `scanned`/`failedValidation` as
|
|
570
|
+
the unclassifiable backlog is re-tested — expected, not a regression.
|
|
571
|
+
- **Strictly additive:** never creates, deletes, or rewrites facts, and never
|
|
572
|
+
overwrites an existing `okf_type` (guarded in SQL, not just convention).
|
|
573
|
+
`updated_at` is never touched, so sync merge resolution is unaffected.
|
|
574
|
+
- **Prompt customization:** per-call `options.promptOverride`, or global
|
|
575
|
+
`config.prompts.ontologyBackfillSystemPrompt` (template may use `{{facts}}`
|
|
576
|
+
and the ontology placeholders).
|
|
577
|
+
|
|
544
578
|
## OKF Import/Export
|
|
545
579
|
|
|
546
580
|
The core package integrates with `@equationalapplications/core-okf` to seamlessly adapt wiki data dumps to and from Open Knowledge Format (OKF) v0.1 bundles.
|
|
@@ -374,7 +374,8 @@ var JobManager = class {
|
|
|
374
374
|
heal: (id) => this._healKey(id),
|
|
375
375
|
reembed: (id) => this._reembedKey(id),
|
|
376
376
|
import: (id) => this._importKey(id),
|
|
377
|
-
forget: (id) => this._forgetKey(id)
|
|
377
|
+
forget: (id) => this._forgetKey(id),
|
|
378
|
+
ontologyBackfill: (id) => this._ontologyBackfillKey(id)
|
|
378
379
|
};
|
|
379
380
|
}
|
|
380
381
|
_pruneKey(entityId) {
|
|
@@ -401,6 +402,9 @@ var JobManager = class {
|
|
|
401
402
|
_healKey(entityId) {
|
|
402
403
|
return `${this.prefix}:${entityId}:heal`;
|
|
403
404
|
}
|
|
405
|
+
_ontologyBackfillKey(entityId) {
|
|
406
|
+
return `${this.prefix}:${entityId}:ontologyBackfill`;
|
|
407
|
+
}
|
|
404
408
|
_isReembedActive(entityId) {
|
|
405
409
|
return this.activeMaintenanceJobs.has(this._reembedKey(entityId)) || this.activeMaintenanceJobs.has(this._globalReembedKey());
|
|
406
410
|
}
|
|
@@ -451,14 +455,16 @@ var JobManager = class {
|
|
|
451
455
|
if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) blockingOperation = "prune";
|
|
452
456
|
else if (this.activeMaintenanceJobs.has(this._librarianKey(entityId))) blockingOperation = "librarian";
|
|
453
457
|
else if (this.activeMaintenanceJobs.has(this._healKey(entityId))) blockingOperation = "heal";
|
|
458
|
+
else if (this.activeMaintenanceJobs.has(this._ontologyBackfillKey(entityId))) blockingOperation = "ontologyBackfill";
|
|
454
459
|
else if (this._isReembedActive(entityId)) blockingOperation = "reembed";
|
|
455
460
|
else if (this._isIngestActiveFor(entityId)) blockingOperation = "ingest";
|
|
456
461
|
else if (this._isImportActiveFor(entityId)) blockingOperation = "import";
|
|
457
462
|
else if (this._isForgetActiveFor(entityId)) blockingOperation = "forget";
|
|
458
463
|
break;
|
|
459
464
|
case "librarian":
|
|
460
|
-
case "heal":
|
|
461
|
-
|
|
465
|
+
case "heal":
|
|
466
|
+
case "ontologyBackfill": {
|
|
467
|
+
const opKey = this.lockKeyFns[operation](entityId);
|
|
462
468
|
if (this.activeMaintenanceJobs.has(opKey)) blockingOperation = operation;
|
|
463
469
|
else if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) blockingOperation = "prune";
|
|
464
470
|
else if (this._isReembedActive(entityId)) blockingOperation = "reembed";
|
|
@@ -472,6 +478,7 @@ var JobManager = class {
|
|
|
472
478
|
else if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) blockingOperation = "prune";
|
|
473
479
|
else if (this.activeMaintenanceJobs.has(this._librarianKey(entityId))) blockingOperation = "librarian";
|
|
474
480
|
else if (this.activeMaintenanceJobs.has(this._healKey(entityId))) blockingOperation = "heal";
|
|
481
|
+
else if (this.activeMaintenanceJobs.has(this._ontologyBackfillKey(entityId))) blockingOperation = "ontologyBackfill";
|
|
475
482
|
else if (this._isIngestActiveFor(entityId)) blockingOperation = "ingest";
|
|
476
483
|
else if (this._isImportActiveFor(entityId)) blockingOperation = "import";
|
|
477
484
|
else if (this._isForgetActiveFor(entityId)) blockingOperation = "forget";
|
|
@@ -482,6 +489,7 @@ var JobManager = class {
|
|
|
482
489
|
else if (this._isAnyMaintenanceActiveWithSuffix(":prune")) blockingOperation = "prune";
|
|
483
490
|
else if (this._isAnyMaintenanceActiveWithSuffix(":librarian")) blockingOperation = "librarian";
|
|
484
491
|
else if (this._isAnyMaintenanceActiveWithSuffix(":heal")) blockingOperation = "heal";
|
|
492
|
+
else if (this._isAnyMaintenanceActiveWithSuffix(":ontologyBackfill")) blockingOperation = "ontologyBackfill";
|
|
485
493
|
else if (this.activeIngestJobs.size > 0) blockingOperation = "ingest";
|
|
486
494
|
else if (this._isAnyMaintenanceActiveWithSuffix(":import")) blockingOperation = "import";
|
|
487
495
|
else if (this._isAnyMaintenanceActiveWithSuffix(":forget")) blockingOperation = "forget";
|
|
@@ -492,6 +500,7 @@ var JobManager = class {
|
|
|
492
500
|
if (this.activeMaintenanceJobs.has(selfKey)) blockingOperation = operation;
|
|
493
501
|
else if (this.activeMaintenanceJobs.has(this._librarianKey(entityId))) blockingOperation = "librarian";
|
|
494
502
|
else if (this.activeMaintenanceJobs.has(this._healKey(entityId))) blockingOperation = "heal";
|
|
503
|
+
else if (this.activeMaintenanceJobs.has(this._ontologyBackfillKey(entityId))) blockingOperation = "ontologyBackfill";
|
|
495
504
|
else if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) blockingOperation = "prune";
|
|
496
505
|
else if (this._isReembedActive(entityId)) blockingOperation = "reembed";
|
|
497
506
|
else if (this._isIngestActiveFor(entityId)) blockingOperation = "ingest";
|
|
@@ -549,11 +558,11 @@ var JobManager = class {
|
|
|
549
558
|
if (operation !== "global_import" && this.activeMaintenanceJobs.has(this._globalImportKey())) return true;
|
|
550
559
|
switch (operation) {
|
|
551
560
|
case "librarian":
|
|
552
|
-
return this.activeMaintenanceJobs.has(this._librarianKey(entityId)) || this.activeMaintenanceJobs.has(this._pruneKey(entityId)) || this._isReembedActive(entityId) || this._isImportActiveFor(entityId) || this._isForgetActiveFor(entityId);
|
|
553
561
|
case "heal":
|
|
554
|
-
|
|
562
|
+
case "ontologyBackfill":
|
|
563
|
+
return this.activeMaintenanceJobs.has(this.lockKeyFns[operation](entityId)) || this.activeMaintenanceJobs.has(this._pruneKey(entityId)) || this._isReembedActive(entityId) || this._isImportActiveFor(entityId) || this._isForgetActiveFor(entityId);
|
|
555
564
|
case "prune":
|
|
556
|
-
return this.activeMaintenanceJobs.has(this._pruneKey(entityId)) || this.activeMaintenanceJobs.has(this._librarianKey(entityId)) || this.activeMaintenanceJobs.has(this._healKey(entityId)) || this._isReembedActive(entityId) || this._isIngestActiveFor(entityId) || this._isImportActiveFor(entityId) || this._isForgetActiveFor(entityId);
|
|
565
|
+
return this.activeMaintenanceJobs.has(this._pruneKey(entityId)) || this.activeMaintenanceJobs.has(this._librarianKey(entityId)) || this.activeMaintenanceJobs.has(this._healKey(entityId)) || this.activeMaintenanceJobs.has(this._ontologyBackfillKey(entityId)) || this._isReembedActive(entityId) || this._isIngestActiveFor(entityId) || this._isImportActiveFor(entityId) || this._isForgetActiveFor(entityId);
|
|
557
566
|
default:
|
|
558
567
|
return false;
|
|
559
568
|
}
|
|
@@ -578,6 +587,7 @@ var JobManager = class {
|
|
|
578
587
|
if (this.activeMaintenanceJobs.has(this._importKey(entityId))) throw new WikiBusyError("import", entityId);
|
|
579
588
|
if (this.activeMaintenanceJobs.has(this._librarianKey(entityId))) throw new WikiBusyError("librarian", entityId);
|
|
580
589
|
if (this.activeMaintenanceJobs.has(this._healKey(entityId))) throw new WikiBusyError("heal", entityId);
|
|
590
|
+
if (this.activeMaintenanceJobs.has(this._ontologyBackfillKey(entityId))) throw new WikiBusyError("ontologyBackfill", entityId);
|
|
581
591
|
if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) throw new WikiBusyError("prune", entityId);
|
|
582
592
|
if (this._isReembedActive(entityId)) throw new WikiBusyError("reembed", entityId);
|
|
583
593
|
if (this._isIngestActiveFor(entityId)) throw new WikiBusyError("ingest", entityId);
|
|
@@ -671,6 +681,15 @@ Return ONLY a valid JSON object matching this schema:
|
|
|
671
681
|
"facts": [{ "title": "string (max 80 chars)", "body": "string (max 800 chars)", "tags": ["string"], "confidence": "certain|inferred|tentative" }]
|
|
672
682
|
}
|
|
673
683
|
Extract verbatim factual content. Do not return markdown, just raw JSON.`;
|
|
684
|
+
var ONTOLOGY_BACKFILL_SYSTEM_PROMPT = `You are a knowledge classification agent. You will receive existing memory facts that currently have no ontology type. For each input fact { "id", "title", "body", "tags" }, assign the best matching okf_type from the ontology manifest and optionally propose edges to related facts by title.
|
|
685
|
+
Return ONLY a valid JSON object matching this schema:
|
|
686
|
+
{
|
|
687
|
+
"classifications": [
|
|
688
|
+
{ "id": "string (input fact id, copied verbatim)", "okf_type": "string (manifest node type slug)", "edges": [{ "edge_type": "string", "target_title": "string" }] }
|
|
689
|
+
]
|
|
690
|
+
}
|
|
691
|
+
If no manifest type fits a fact, omit that fact from "classifications" entirely \u2014 do not guess.
|
|
692
|
+
Do not return markdown, just raw JSON.`;
|
|
674
693
|
|
|
675
694
|
// src/services/PromptService.ts
|
|
676
695
|
var PromptService = class {
|
|
@@ -760,6 +779,22 @@ ${JSON.stringify(recentEvents, null, 2)}
|
|
|
760
779
|
The following document anchors are provided for contradiction detection only. Do not include them in \`downgraded\`, \`deleted\`, or \`newFacts\`.`
|
|
761
780
|
};
|
|
762
781
|
}
|
|
782
|
+
buildOntologyBackfillPrompt(facts, runtimeOverride, ontologyContext) {
|
|
783
|
+
const template = runtimeOverride ?? this.globalOverrides?.ontologyBackfillSystemPrompt ?? ONTOLOGY_BACKFILL_SYSTEM_PROMPT;
|
|
784
|
+
const hasFacts = /\{\{\s*facts\s*\}\}/.test(template);
|
|
785
|
+
if (hasFacts || this.hasOntologyPlaceholders(template)) {
|
|
786
|
+
return {
|
|
787
|
+
systemPrompt: this.buildSystemPrompt(template, { facts }, ontologyContext),
|
|
788
|
+
userPrompt: hasFacts ? "Please classify the facts." : `Facts:
|
|
789
|
+
${JSON.stringify(facts, null, 2)}`
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
return {
|
|
793
|
+
systemPrompt: this.appendOntology(template, ontologyContext),
|
|
794
|
+
userPrompt: `Facts:
|
|
795
|
+
${JSON.stringify(facts, null, 2)}`
|
|
796
|
+
};
|
|
797
|
+
}
|
|
763
798
|
};
|
|
764
799
|
|
|
765
800
|
// src/utils/pure.ts
|
|
@@ -1376,6 +1411,9 @@ var MetadataRepository = class extends BaseRepository {
|
|
|
1376
1411
|
// src/services/MaintenanceService.ts
|
|
1377
1412
|
var FUZZY_THRESHOLD = 0.5;
|
|
1378
1413
|
var MIN_TOKENS_TO_QUALIFY = 3;
|
|
1414
|
+
var ONTOLOGY_BACKFILL_BATCH_SIZE = 25;
|
|
1415
|
+
var ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS = 4e4;
|
|
1416
|
+
var ONTOLOGY_BACKFILL_RECHECK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
1379
1417
|
var MaintenanceService = class {
|
|
1380
1418
|
constructor(db, prefix, options, entryRepo, taskRepo, eventRepo, metadataRepo, searchService, jobManager, embeddingService, promptService, ontologyService) {
|
|
1381
1419
|
this.db = db;
|
|
@@ -1481,6 +1519,14 @@ var MaintenanceService = class {
|
|
|
1481
1519
|
this.jobManager.releaseLock("heal", entityId);
|
|
1482
1520
|
}
|
|
1483
1521
|
}
|
|
1522
|
+
async runOntologyBackfill(entityId, options) {
|
|
1523
|
+
this.jobManager.acquireLock("ontologyBackfill", entityId);
|
|
1524
|
+
try {
|
|
1525
|
+
return await this.doRunOntologyBackfill(entityId, options);
|
|
1526
|
+
} finally {
|
|
1527
|
+
this.jobManager.releaseLock("ontologyBackfill", entityId);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1484
1530
|
async runReembed(entityId, opts) {
|
|
1485
1531
|
const embedFn = this.options.llmProvider.embed;
|
|
1486
1532
|
if (!embedFn) return { embedded: 0, skipped: 0, failed: 0 };
|
|
@@ -1832,6 +1878,121 @@ var MaintenanceService = class {
|
|
|
1832
1878
|
}
|
|
1833
1879
|
this.searchService.evictCache(entityId);
|
|
1834
1880
|
}
|
|
1881
|
+
/** Core ontology backfill pass (locks handled by {@link runOntologyBackfill}). Package-internal orchestration hook. */
|
|
1882
|
+
async doRunOntologyBackfill(entityId, options) {
|
|
1883
|
+
const batchSize = options?.batchSize ?? ONTOLOGY_BACKFILL_BATCH_SIZE;
|
|
1884
|
+
if (!Number.isInteger(batchSize) || batchSize < 1) {
|
|
1885
|
+
throw new Error("Invalid batchSize: must be an integer >= 1");
|
|
1886
|
+
}
|
|
1887
|
+
const now = Date.now();
|
|
1888
|
+
const recheckCutoff = now - ONTOLOGY_BACKFILL_RECHECK_MS;
|
|
1889
|
+
const zeroed = { scanned: 0, typed: 0, failedValidation: 0, edgesAdded: 0 };
|
|
1890
|
+
const ontologyService = this.ontologyService;
|
|
1891
|
+
if (!ontologyService) {
|
|
1892
|
+
return { ...zeroed, remaining: 0, deferred: 0 };
|
|
1893
|
+
}
|
|
1894
|
+
const { mode } = await ontologyService.getEffectiveState(entityId);
|
|
1895
|
+
if (mode === "off") {
|
|
1896
|
+
const counts2 = await this.entryRepo.countUntypedByEntityId(entityId, recheckCutoff);
|
|
1897
|
+
return { ...zeroed, remaining: 0, deferred: counts2.deferred };
|
|
1898
|
+
}
|
|
1899
|
+
const candidates = await this.entryRepo.findUntypedByEntityId(entityId, batchSize, recheckCutoff);
|
|
1900
|
+
if (candidates.length === 0) {
|
|
1901
|
+
const counts2 = await this.entryRepo.countUntypedByEntityId(entityId, recheckCutoff);
|
|
1902
|
+
return { ...zeroed, remaining: counts2.eligible, deferred: counts2.deferred };
|
|
1903
|
+
}
|
|
1904
|
+
const ontologyContext = await ontologyService.buildPromptContext(entityId);
|
|
1905
|
+
const toPromptShape = (f) => ({ id: f.id, title: f.title, body: f.body, tags: f.tags });
|
|
1906
|
+
const buildPrompt = (facts) => this.promptService.buildOntologyBackfillPrompt(
|
|
1907
|
+
facts.map(toPromptShape),
|
|
1908
|
+
options?.promptOverride,
|
|
1909
|
+
ontologyContext
|
|
1910
|
+
);
|
|
1911
|
+
const batch = [candidates[0]];
|
|
1912
|
+
let built = buildPrompt(batch);
|
|
1913
|
+
for (let i = 1; i < candidates.length; i++) {
|
|
1914
|
+
const next = buildPrompt([...batch, candidates[i]]);
|
|
1915
|
+
if (next.systemPrompt.length + next.userPrompt.length > ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS) break;
|
|
1916
|
+
batch.push(candidates[i]);
|
|
1917
|
+
built = next;
|
|
1918
|
+
}
|
|
1919
|
+
const { systemPrompt, userPrompt } = built;
|
|
1920
|
+
const responseText = await this.options.llmProvider.generateText({ systemPrompt, userPrompt });
|
|
1921
|
+
const parsed = parseJsonResponse(responseText);
|
|
1922
|
+
const classifications = Array.isArray(parsed.classifications) ? parsed.classifications : [];
|
|
1923
|
+
let typed = 0;
|
|
1924
|
+
let failedValidation = 0;
|
|
1925
|
+
let edgesAdded = 0;
|
|
1926
|
+
let abortedOntologyOff = false;
|
|
1927
|
+
await this.db.withTransactionAsync(async (tx) => {
|
|
1928
|
+
let { mode: txMode, manifest } = await ontologyService.getEffectiveState(entityId, tx);
|
|
1929
|
+
if (txMode === "off") {
|
|
1930
|
+
abortedOntologyOff = true;
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1933
|
+
if (txMode === "emergent" && parsed.ontology_updates) {
|
|
1934
|
+
manifest = await ontologyService.mergeEmergentUpdates(entityId, parsed.ontology_updates, tx);
|
|
1935
|
+
}
|
|
1936
|
+
const titleRows = await this.entryRepo.findTitleIndexByEntityId(entityId, tx);
|
|
1937
|
+
const titleIndex = /* @__PURE__ */ new Map();
|
|
1938
|
+
for (const row of titleRows) {
|
|
1939
|
+
titleIndex.set(normalizeTitleKey(row.title), { id: row.id, okf_type: row.okf_type });
|
|
1940
|
+
}
|
|
1941
|
+
const batchById = new Map(batch.map((f) => [f.id, f]));
|
|
1942
|
+
const applied = /* @__PURE__ */ new Set();
|
|
1943
|
+
const pendingEdges = [];
|
|
1944
|
+
for (const classification of classifications) {
|
|
1945
|
+
const fact = typeof classification.id === "string" ? batchById.get(classification.id) : void 0;
|
|
1946
|
+
if (!fact || applied.has(fact.id)) {
|
|
1947
|
+
failedValidation++;
|
|
1948
|
+
continue;
|
|
1949
|
+
}
|
|
1950
|
+
applied.add(fact.id);
|
|
1951
|
+
const normalized = ontologyService.validateAndNormalizeFact(
|
|
1952
|
+
{
|
|
1953
|
+
title: fact.title,
|
|
1954
|
+
body: fact.body,
|
|
1955
|
+
tags: fact.tags,
|
|
1956
|
+
confidence: fact.confidence,
|
|
1957
|
+
okf_type: classification.okf_type,
|
|
1958
|
+
edges: classification.edges
|
|
1959
|
+
},
|
|
1960
|
+
manifest
|
|
1961
|
+
);
|
|
1962
|
+
if (!normalized.okf_type) {
|
|
1963
|
+
failedValidation++;
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
const result = await this.entryRepo.updateOkfType(fact.id, entityId, normalized.okf_type, tx);
|
|
1967
|
+
if (result.changes === 0) continue;
|
|
1968
|
+
typed++;
|
|
1969
|
+
titleIndex.set(normalizeTitleKey(fact.title), { id: fact.id, okf_type: normalized.okf_type });
|
|
1970
|
+
if (normalized.edges.length > 0) {
|
|
1971
|
+
pendingEdges.push({ sourceId: fact.id, sourceType: normalized.okf_type, edges: normalized.edges });
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
for (const item of pendingEdges) {
|
|
1975
|
+
edgesAdded += await ontologyService.resolveAndPersistEdges(
|
|
1976
|
+
entityId,
|
|
1977
|
+
item.sourceId,
|
|
1978
|
+
item.sourceType,
|
|
1979
|
+
item.edges,
|
|
1980
|
+
manifest,
|
|
1981
|
+
titleIndex,
|
|
1982
|
+
tx,
|
|
1983
|
+
now
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
await this.entryRepo.markOntologyChecked(batch.map((f) => f.id), entityId, now, tx);
|
|
1987
|
+
});
|
|
1988
|
+
if (abortedOntologyOff) {
|
|
1989
|
+
const counts2 = await this.entryRepo.countUntypedByEntityId(entityId, recheckCutoff);
|
|
1990
|
+
return { ...zeroed, remaining: 0, deferred: counts2.deferred };
|
|
1991
|
+
}
|
|
1992
|
+
this.searchService.evictCache(entityId);
|
|
1993
|
+
const counts = await this.entryRepo.countUntypedByEntityId(entityId, recheckCutoff);
|
|
1994
|
+
return { scanned: batch.length, typed, failedValidation, edgesAdded, remaining: counts.eligible, deferred: counts.deferred };
|
|
1995
|
+
}
|
|
1835
1996
|
_validatePruneDuration(value, name) {
|
|
1836
1997
|
if (value !== null && value !== void 0 && (typeof value !== "number" || !isFinite(value) || value < 0)) {
|
|
1837
1998
|
throw new Error(`Invalid ${name}: must be a non-negative finite number or null`);
|
|
@@ -3045,6 +3206,6 @@ var WriteService = class {
|
|
|
3045
3206
|
}
|
|
3046
3207
|
};
|
|
3047
3208
|
|
|
3048
|
-
export { BaseRepository, EmbeddingService, HOOK_TIMEOUT_MARKER, ImportExportService, IngestionService, JobManager, MaintenanceService, MetadataRepository, PromptService, PrunePartialFailureError, RetrievalService, SearchService, WikiBusyError, WikiTransactionError, WriteService, __privateAdd, __privateGet, __privateSet, configureRandomSource, emptyManifest, entitySummaryMetaKey, extractSqliteCode, generateId, normalizeSourceHash, normalizeSourceRef, normalizeTitleKey, parseEmbedding, resolveEdgeDefinition, resolveNodeType, validateInlineEdges };
|
|
3049
|
-
//# sourceMappingURL=chunk-
|
|
3050
|
-
//# sourceMappingURL=chunk-
|
|
3209
|
+
export { BaseRepository, EmbeddingService, HOOK_TIMEOUT_MARKER, ImportExportService, IngestionService, JobManager, MaintenanceService, MetadataRepository, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, RetrievalService, SearchService, WikiBusyError, WikiTransactionError, WriteService, __privateAdd, __privateGet, __privateSet, configureRandomSource, emptyManifest, entitySummaryMetaKey, extractSqliteCode, generateId, normalizeSourceHash, normalizeSourceRef, normalizeTitleKey, parseEmbedding, resolveEdgeDefinition, resolveNodeType, validateInlineEdges };
|
|
3210
|
+
//# sourceMappingURL=chunk-UYLYN5N4.mjs.map
|
|
3211
|
+
//# sourceMappingURL=chunk-UYLYN5N4.mjs.map
|