@equationalapplications/core-llm-wiki 5.2.1 → 5.3.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-6HNIOKT4.mjs → chunk-KIJINNYU.mjs} +213 -41
- package/dist/chunk-KIJINNYU.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +370 -50
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +162 -16
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-CAk9oFvw.d.mts → testing-zf3Jp_RL.d.mts} +228 -24
- package/dist/{testing-CAk9oFvw.d.ts → testing-zf3Jp_RL.d.ts} +228 -24
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +170 -31
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-6HNIOKT4.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, resolveEdgeDefinitions, normalizeTitleKey, WikiTransactionError, extractSqliteCode } from './chunk-
|
|
2
|
-
export { DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, HEAL_BATCH_SIZE, HEAL_RECHECK_MS, HOOK_TIMEOUT_MARKER, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, WikiBusyError, WikiDuplicateHashError, WikiTransactionError, chunkText, configureRandomSource, parseEmbedding, safeSlice, validateManifest } from './chunk-
|
|
1
|
+
import { __privateAdd, MetadataRepository, EmbeddingService, SearchService, JobManager, PromptService, IngestionService, MaintenanceService, ImportExportService, RetrievalService, WriteService, __privateGet, __privateSet, normalizeSourceRef, normalizeSourceHash, entitySummaryMetaKey, WikiSourceRefHashCollision, generateId, BaseRepository, emptyManifest, resolveNodeType, WikiStrictOntologyViolation, validateInlineEdges, resolveEdgeDefinitions, normalizeTitleKey, WikiTransactionError, extractSqliteCode } from './chunk-KIJINNYU.mjs';
|
|
2
|
+
export { DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, HEAL_BATCH_SIZE, HEAL_RECHECK_MS, HOOK_TIMEOUT_MARKER, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, WikiBusyError, WikiDuplicateHashError, WikiSourceRefHashCollision, WikiStrictOntologyViolation, WikiTransactionError, chunkText, configureRandomSource, parseEmbedding, safeSlice, validateManifest } from './chunk-KIJINNYU.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
|
|
@@ -736,12 +736,22 @@ var EntryRepository = class extends BaseRepository {
|
|
|
736
736
|
/**
|
|
737
737
|
* Fetch recent non-deleted entries for an entity (limited), ordered by updated_at DESC.
|
|
738
738
|
* Used by MaintenanceService.doRunLibrarian().
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
739
|
+
*
|
|
740
|
+
* When `excludeSourceRef` is supplied, the WHERE clause filters out that
|
|
741
|
+
* sourceRef BEFORE applying LIMIT. The caller in IngestionService is
|
|
742
|
+
* `findRecentByEntityId(entityId, 500, tx)` — it discards same-sourceRef
|
|
743
|
+
* rows after the read to build a cross-sourceRef title index. If those
|
|
744
|
+
* rows are filtered out in SQL, the limit applies to usable rows only
|
|
745
|
+
* and a re-ingest where the caller's sourceRef owns most recent facts
|
|
746
|
+
* still leaves cross-sourceRef entries in the index.
|
|
747
|
+
*/
|
|
748
|
+
async findRecentByEntityId(entityId, limit, tx, excludeSourceRef) {
|
|
749
|
+
const executor = this.getExecutor(tx);
|
|
750
|
+
const excludeClause = excludeSourceRef ? ` AND (source_ref IS NULL OR source_ref != ?)` : "";
|
|
751
|
+
const args = excludeSourceRef ? [entityId, excludeSourceRef, limit] : [entityId, limit];
|
|
742
752
|
const rows = await executor.getAllAsync(
|
|
743
|
-
`SELECT * FROM ${this.prefix}entries WHERE entity_id = ? AND deleted_at IS NULL ORDER BY updated_at DESC LIMIT ?`,
|
|
744
|
-
|
|
753
|
+
`SELECT * FROM ${this.prefix}entries WHERE entity_id = ? AND deleted_at IS NULL${excludeClause} ORDER BY updated_at DESC LIMIT ?`,
|
|
754
|
+
args
|
|
745
755
|
);
|
|
746
756
|
return rows.map(mapRowToFact);
|
|
747
757
|
}
|
|
@@ -1932,6 +1942,34 @@ var EdgeRepository = class extends BaseRepository {
|
|
|
1932
1942
|
const executor = this.getExecutor(tx);
|
|
1933
1943
|
await executor.runAsync(`DELETE FROM ${this.prefix}edges WHERE entity_id = ?`, [entityId]);
|
|
1934
1944
|
}
|
|
1945
|
+
/**
|
|
1946
|
+
* Hard-delete every edge whose `source_id` is in `sourceFactIds`, scoped to
|
|
1947
|
+
* `entityId`. Returns the number of rows deleted. Edges have no soft-delete
|
|
1948
|
+
* concept; this method is named `softDeleteBySourceFactIds` for symmetry with
|
|
1949
|
+
* `EntryRepository.softDeleteBySource` (which IS a soft delete), but its
|
|
1950
|
+
* semantics are immediate presence/absence removal. Use ONLY inside an open
|
|
1951
|
+
* transaction — the method requires `tx` and performs no autocommit.
|
|
1952
|
+
*
|
|
1953
|
+
* Used by `IngestionService.upsertGraphCore` to retire the prior parse's
|
|
1954
|
+
* edges whose source facts are being superseded by `softDeleteBySource`.
|
|
1955
|
+
*/
|
|
1956
|
+
async softDeleteBySourceFactIds(entityId, sourceFactIds, tx) {
|
|
1957
|
+
if (sourceFactIds.length === 0) return 0;
|
|
1958
|
+
const executor = this.getExecutor(tx);
|
|
1959
|
+
const chunkSize = 500;
|
|
1960
|
+
let totalChanges = 0;
|
|
1961
|
+
for (let i = 0; i < sourceFactIds.length; i += chunkSize) {
|
|
1962
|
+
const chunk = sourceFactIds.slice(i, i + chunkSize);
|
|
1963
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
1964
|
+
const result = await executor.runAsync(
|
|
1965
|
+
`DELETE FROM ${this.prefix}edges
|
|
1966
|
+
WHERE entity_id = ? AND source_id IN (${placeholders})`,
|
|
1967
|
+
[entityId, ...chunk]
|
|
1968
|
+
);
|
|
1969
|
+
totalChanges += result.changes;
|
|
1970
|
+
}
|
|
1971
|
+
return totalChanges;
|
|
1972
|
+
}
|
|
1935
1973
|
/**
|
|
1936
1974
|
* Multi-hop traversal from `sourceId` via SQLite `WITH RECURSIVE`. All filtering,
|
|
1937
1975
|
* dead-ending, cycle-guarding, capping, and ordering happens in this one query.
|
|
@@ -2110,16 +2148,27 @@ var OntologyService = class {
|
|
|
2110
2148
|
this.invalidateCache(entityId);
|
|
2111
2149
|
return merged;
|
|
2112
2150
|
}
|
|
2113
|
-
validateAndNormalizeFact(fact, manifest) {
|
|
2151
|
+
validateAndNormalizeFact(fact, manifest, opts) {
|
|
2114
2152
|
const rawType = typeof fact.okf_type === "string" ? fact.okf_type : "";
|
|
2153
|
+
const strict = opts?.strict === true;
|
|
2115
2154
|
const canonical = resolveNodeType(rawType, manifest);
|
|
2116
|
-
if (!canonical)
|
|
2117
|
-
|
|
2155
|
+
if (!canonical) {
|
|
2156
|
+
if (strict) throw new WikiStrictOntologyViolation(opts?.entityId ?? "", "node", rawType);
|
|
2157
|
+
return { okf_type: null, edges: [] };
|
|
2158
|
+
}
|
|
2159
|
+
const edges = validateInlineEdges(canonical, null, fact.edges ?? [], manifest, opts);
|
|
2118
2160
|
return { okf_type: canonical, edges };
|
|
2119
2161
|
}
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2162
|
+
/**
|
|
2163
|
+
* Pure resolver: given a source type, LLM-supplied edges, the manifest,
|
|
2164
|
+
* and a title index, return a list of concrete `WikiEdge` objects ready
|
|
2165
|
+
* for persistence. Performs no DB writes. Used by callers that batch edge
|
|
2166
|
+
* writes inside their own transaction (e.g. `IngestionService.ingestDocument`
|
|
2167
|
+
* when delegating to `upsertGraphCore`).
|
|
2168
|
+
*/
|
|
2169
|
+
resolveEdges(entityId, sourceId, sourceType, edges, manifest, titleIndex, now) {
|
|
2170
|
+
if (!sourceType || edges.length === 0) return [];
|
|
2171
|
+
const out = [];
|
|
2123
2172
|
for (const edge of edges) {
|
|
2124
2173
|
const candidates = resolveEdgeDefinitions(edge.edge_type, manifest).filter((d) => d.source_type.toLowerCase() === sourceType.toLowerCase());
|
|
2125
2174
|
if (candidates.length === 0) continue;
|
|
@@ -2130,15 +2179,29 @@ var OntologyService = class {
|
|
|
2130
2179
|
(d) => d.target_type.toLowerCase() === (target.okf_type ?? "").toLowerCase()
|
|
2131
2180
|
);
|
|
2132
2181
|
if (!def) continue;
|
|
2133
|
-
|
|
2182
|
+
out.push({
|
|
2134
2183
|
id: generateId(),
|
|
2135
2184
|
entity_id: entityId,
|
|
2136
2185
|
source_id: sourceId,
|
|
2137
2186
|
target_id: target.id,
|
|
2138
2187
|
edge_type: def.type,
|
|
2139
2188
|
created_at: now
|
|
2140
|
-
};
|
|
2141
|
-
|
|
2189
|
+
});
|
|
2190
|
+
}
|
|
2191
|
+
return out;
|
|
2192
|
+
}
|
|
2193
|
+
/**
|
|
2194
|
+
* Backwards-compatible wrapper: resolves edges via {@link resolveEdges},
|
|
2195
|
+
* then persists each via `edgeRepo.addIgnoreDuplicate` in the supplied
|
|
2196
|
+
* transaction. Returns the number of edges persisted. Used by paths that
|
|
2197
|
+
* want self-contained edge persistence (e.g. MaintenanceService heal /
|
|
2198
|
+
* backfill callers that do not have a separate edge-write step).
|
|
2199
|
+
*/
|
|
2200
|
+
async resolveAndPersistEdges(entityId, sourceId, sourceType, edges, manifest, titleIndex, tx, now) {
|
|
2201
|
+
const resolved = this.resolveEdges(entityId, sourceId, sourceType, edges, manifest, titleIndex, now);
|
|
2202
|
+
let persisted = 0;
|
|
2203
|
+
for (const edge of resolved) {
|
|
2204
|
+
const inserted = await this.edgeRepo.addIgnoreDuplicate(edge, tx);
|
|
2142
2205
|
if (inserted) persisted++;
|
|
2143
2206
|
}
|
|
2144
2207
|
return persisted;
|
|
@@ -2214,6 +2277,8 @@ var WikiMemory = class {
|
|
|
2214
2277
|
this.options,
|
|
2215
2278
|
this.entryRepo,
|
|
2216
2279
|
this.sourceRefIndexRepo,
|
|
2280
|
+
this.metadataRepo,
|
|
2281
|
+
this.edgeRepo,
|
|
2217
2282
|
this.searchService,
|
|
2218
2283
|
this.jobManager,
|
|
2219
2284
|
this.embeddingService,
|
|
@@ -2406,6 +2471,36 @@ var WikiMemory = class {
|
|
|
2406
2471
|
const canonical = await this.sourceRefIndexRepo.findActiveByEntityAndHash(entityId, sourceHash);
|
|
2407
2472
|
return canonical === null ? [] : [canonical];
|
|
2408
2473
|
}
|
|
2474
|
+
/**
|
|
2475
|
+
* Returns the set of `entity_id` values with at least one row in this
|
|
2476
|
+
* database, INCLUDING entities whose only remaining rows are soft-deleted
|
|
2477
|
+
* — sorted ascending `entity_id COLLATE BINARY`. Empty array when the
|
|
2478
|
+
* database has no entities.
|
|
2479
|
+
*
|
|
2480
|
+
* The deliberate inclusion of soft-deleted-only entities closes the
|
|
2481
|
+
* decommissioned-scope leak: a scoped namespace whose documents have all
|
|
2482
|
+
* been forgotten or superseded must still appear so host maintenance
|
|
2483
|
+
* sweeps (`runLibrarian`, `runHeal`, `runOntologyBackfill`, `runPrune`)
|
|
2484
|
+
* can visit it and reap the soft-deleted rows.
|
|
2485
|
+
*
|
|
2486
|
+
* Read-only. Never acquires a lock. Never opens a transaction. Propagates
|
|
2487
|
+
* underlying read errors.
|
|
2488
|
+
*
|
|
2489
|
+
* @param options.prefix - Optional string filter applied as
|
|
2490
|
+
* `id.startsWith(prefix)`. O(n) over distinct ids because the
|
|
2491
|
+
* `(entity_id, source_ref)` index is not seekable on `entity_id`-only
|
|
2492
|
+
* prefix. Empty-string prefix matches every id.
|
|
2493
|
+
*
|
|
2494
|
+
* Note: this widens the coverage of `exportDump` (which delegates to
|
|
2495
|
+
* `MetadataRepository.getDistinctEntityIds`); exported dumps now include
|
|
2496
|
+
* orphaned entities. This is a deliberate widening for backup/migration
|
|
2497
|
+
* coverage, not a breaking change to `exportDump`'s return shape.
|
|
2498
|
+
*/
|
|
2499
|
+
async listEntityIds(options) {
|
|
2500
|
+
const ids = await this.metadataRepo.getDistinctEntityIds();
|
|
2501
|
+
if (options?.prefix === void 0) return ids;
|
|
2502
|
+
return ids.filter((id) => id.startsWith(options.prefix));
|
|
2503
|
+
}
|
|
2409
2504
|
async runPrune(entityId, options) {
|
|
2410
2505
|
return this.maintenanceService.runPrune(entityId, options);
|
|
2411
2506
|
}
|
|
@@ -2502,6 +2597,57 @@ var WikiMemory = class {
|
|
|
2502
2597
|
async ingestDocument(entityId, params, opts) {
|
|
2503
2598
|
return this.ingestionService.ingestDocument(entityId, params, opts);
|
|
2504
2599
|
}
|
|
2600
|
+
/**
|
|
2601
|
+
* Deterministic write path into the graph. Accepts caller-supplied
|
|
2602
|
+
* `(nodes, edges)` and writes them under `(sourceRef, sourceHash)`
|
|
2603
|
+
* semantics identical to `ingestDocument`, minus the LLM extraction step.
|
|
2604
|
+
*
|
|
2605
|
+
* MUST be called from inside an open `db.withTransactionAsync` callback —
|
|
2606
|
+
* the third argument is the caller's `tx`. The method does not open a
|
|
2607
|
+
* nested transaction, does not acquire any lock, and does not perform
|
|
2608
|
+
* post-commit work (search sync, embedding, cache eviction). Hosts that
|
|
2609
|
+
* want embeddings synced should drive the existing maintenance sweep
|
|
2610
|
+
* (`runLibrarian` / `runHeal` / `runOntologyBackfill` / `runPrune`,
|
|
2611
|
+
* scoped via `listEntityIds`).
|
|
2612
|
+
*
|
|
2613
|
+
* Contract (full pre-flight validation lives inside
|
|
2614
|
+
* `IngestionService.upsertGraphCore`, which this method delegates to):
|
|
2615
|
+
* - C2: no-op when `(entityId, sourceHash)` is already mapped to
|
|
2616
|
+
* `params.sourceRef`; throws `WikiSourceRefHashCollision` if mapped to
|
|
2617
|
+
* a different `sourceRef`.
|
|
2618
|
+
* - C3: edges with dangling `targetId` are stored verbatim (no FK, no
|
|
2619
|
+
* resolution).
|
|
2620
|
+
* - C4: under persisted ontology mode `'strict'`, an out-of-manifest node
|
|
2621
|
+
* or edge `type` throws `WikiStrictOntologyViolation` (pre-flight,
|
|
2622
|
+
* all-or-nothing — NONE written on failure).
|
|
2623
|
+
*
|
|
2624
|
+
* @returns Counts: nodesWritten (validated nodes persisted), edgesWritten
|
|
2625
|
+
* (manifest-valid edges persisted), superseded (prior facts soft-deleted
|
|
2626
|
+
* plus prior source-ref edges hard-deleted).
|
|
2627
|
+
*/
|
|
2628
|
+
async upsertGraph(entityId, params, adapter) {
|
|
2629
|
+
const sourceRef = normalizeSourceRef(params.sourceRef);
|
|
2630
|
+
if (!sourceRef) throw new Error("Invalid sourceRef");
|
|
2631
|
+
const sourceHash = normalizeSourceHash(params.sourceHash);
|
|
2632
|
+
if (!sourceHash) throw new Error("Invalid sourceHash (must be 64-char hex string)");
|
|
2633
|
+
const canonical = await this.sourceRefIndexRepo.findActiveByEntityAndHash(entityId, sourceHash, adapter);
|
|
2634
|
+
if (canonical !== null && canonical === sourceRef) {
|
|
2635
|
+
return { nodesWritten: 0, edgesWritten: 0, superseded: 0 };
|
|
2636
|
+
}
|
|
2637
|
+
if (canonical !== null && canonical !== sourceRef) {
|
|
2638
|
+
throw new WikiSourceRefHashCollision({
|
|
2639
|
+
entityId,
|
|
2640
|
+
sourceHash,
|
|
2641
|
+
existingSourceRef: canonical,
|
|
2642
|
+
attemptedSourceRef: sourceRef
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2645
|
+
return this.ingestionService.upsertGraphCore(
|
|
2646
|
+
entityId,
|
|
2647
|
+
{ sourceRef, sourceHash, nodes: params.nodes, edges: params.edges },
|
|
2648
|
+
adapter
|
|
2649
|
+
);
|
|
2650
|
+
}
|
|
2505
2651
|
/**
|
|
2506
2652
|
* Returns up to `limit` unprocessed outbox events, oldest first.
|
|
2507
2653
|
* Works regardless of enableOutbox value — allows draining after disabling.
|