@equationalapplications/core-llm-wiki 7.3.0 → 7.4.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 +25 -0
- package/dist/{chunk-IAYO63DQ.mjs → chunk-G5OR2VWD.mjs} +28 -11
- package/dist/chunk-G5OR2VWD.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +113 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +89 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-ht1qOvcD.d.mts → testing-Dmh1kfkd.d.mts} +74 -2
- package/dist/{testing-ht1qOvcD.d.ts → testing-Dmh1kfkd.d.ts} +74 -2
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +17 -8
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-IAYO63DQ.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -285,6 +285,31 @@ True cosine-range pure semantic ranking (including negative cosine values) is us
|
|
|
285
285
|
**Pre-filtering optimization:**
|
|
286
286
|
When `preFilterLimit: 50` is set with 1000 facts, cosine similarity is computed only for the top 50 MiniSearch keyword matches, reducing O(N) scoring to O(50).
|
|
287
287
|
|
|
288
|
+
## Draft Review
|
|
289
|
+
|
|
290
|
+
Facts can carry `lifecycle_status: 'draft'`, for example when a host marks model output as unreviewed. Drafts stay visible by default. To keep them out of results:
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
await wiki.read('user-1', 'deploy process', { excludeDrafts: true });
|
|
294
|
+
await wiki.traverseGraph('user-1', { sourceId, excludeDrafts: true });
|
|
295
|
+
// or engine-wide:
|
|
296
|
+
createWiki(db, { llmProvider, config: { excludeDrafts: true } });
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
- On every `read()` path, drafts are removed **before** `maxResults`, `tierFloors`, and pre-filter cuts, so they never take slots from reviewed facts.
|
|
300
|
+
- In traversal, drafts are dead ends. The starting fact is always returned.
|
|
301
|
+
- Status is read from SQLite on every call. A promotion is visible immediately, with no re-indexing.
|
|
302
|
+
|
|
303
|
+
Review API:
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
const { facts, nextCursor } = await wiki.listDrafts('user-1', { limit: 50 });
|
|
307
|
+
await wiki.promoteDraft(facts[0].id, 'user-1', { by: 'human:alice' }); // → stable, trustTier 'human-reviewed'
|
|
308
|
+
// Reject with setLifecycleStatus(id, entityId, 'deprecated') or forget().
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`promoteDraft` throws `WikiDraftNotFound` when no live draft with that id exists for the entity. The error is contextless by design. Promotion does not change `updated_at`, so a promoted fact keeps its recency position.
|
|
312
|
+
|
|
288
313
|
## Pluggable Vector Retrieval
|
|
289
314
|
|
|
290
315
|
When your entity corpus grows, in-process cosine similarity scoring becomes a bottleneck. The optional **`VectorRanker`** interface lets you delegate semantic ranking to [**sqlite-vec**](https://github.com/asg017/sqlite-vec), [**sqlite-vss**](https://github.com/asg017/sqlite-vss), or an external vector database while `WikiMemory` handles embedding validation, hybrid scoring, and tier-2 row hydration.
|
|
@@ -168,6 +168,14 @@ var WikiInvalidReadOptions = class _WikiInvalidReadOptions extends Error {
|
|
|
168
168
|
Object.setPrototypeOf(this, _WikiInvalidReadOptions.prototype);
|
|
169
169
|
}
|
|
170
170
|
};
|
|
171
|
+
var WikiDraftNotFound = class _WikiDraftNotFound extends Error {
|
|
172
|
+
constructor() {
|
|
173
|
+
super("No draft fact with that id exists for this entity.");
|
|
174
|
+
this.code = "WIKI_DRAFT_NOT_FOUND";
|
|
175
|
+
this.name = "WikiDraftNotFound";
|
|
176
|
+
Object.setPrototypeOf(this, _WikiDraftNotFound.prototype);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
171
179
|
|
|
172
180
|
// src/utils/ids.ts
|
|
173
181
|
var _injectedGetRandomValues = null;
|
|
@@ -4552,6 +4560,7 @@ function selectWithFloors(sortedRows, floors, maxResults) {
|
|
|
4552
4560
|
}
|
|
4553
4561
|
|
|
4554
4562
|
// src/services/RetrievalService.ts
|
|
4563
|
+
var EMPTY_ID_SET = /* @__PURE__ */ new Set();
|
|
4555
4564
|
var RetrievalService = class {
|
|
4556
4565
|
constructor(options, entryRepo, taskRepo, eventRepo, metadataRepo, searchService) {
|
|
4557
4566
|
this.options = options;
|
|
@@ -4584,6 +4593,7 @@ var RetrievalService = class {
|
|
|
4584
4593
|
}
|
|
4585
4594
|
const rawMaxResults = options?.maxResults ?? config?.maxResults ?? config?.maxFtsResults ?? 10;
|
|
4586
4595
|
const maxResults = Number.isFinite(rawMaxResults) ? Math.max(0, Math.trunc(rawMaxResults)) : 10;
|
|
4596
|
+
const excludeDrafts = (options?.excludeDrafts ?? config?.excludeDrafts ?? false) === true;
|
|
4587
4597
|
const trimmedQuery = query.trim();
|
|
4588
4598
|
const sanitizedTierFloors = trimmedQuery && exposeMetadata ? validateTierFloors(
|
|
4589
4599
|
entityIds,
|
|
@@ -4603,6 +4613,9 @@ var RetrievalService = class {
|
|
|
4603
4613
|
if (maxResults === 0) ; else if (trimmedQuery) {
|
|
4604
4614
|
let usedEmbed = false;
|
|
4605
4615
|
const scoredEntityIds = this._filterScoredEntities(entityIds, sanitizedTierWeights, options?.includeZeroWeightEntities);
|
|
4616
|
+
const draftIds = excludeDrafts && scoredEntityIds.length > 0 ? await this.entryRepo.findDraftIdsByEntityIds(scoredEntityIds) : EMPTY_ID_SET;
|
|
4617
|
+
const draftPad = draftIds.size;
|
|
4618
|
+
const padLimit = (n) => n >= Number.MAX_SAFE_INTEGER ? n : n + draftPad;
|
|
4606
4619
|
if (scoredEntityIds.length === 0) {
|
|
4607
4620
|
usedEmbed = true;
|
|
4608
4621
|
} else if (!skipEmbed && embedFn) {
|
|
@@ -4636,7 +4649,7 @@ var RetrievalService = class {
|
|
|
4636
4649
|
let miniSearchScores;
|
|
4637
4650
|
if (effectivePreFilterLimit !== void 0) {
|
|
4638
4651
|
populateCache = false;
|
|
4639
|
-
const preResults = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, Number.MAX_SAFE_INTEGER);
|
|
4652
|
+
const preResults = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, Number.MAX_SAFE_INTEGER).filter((r) => !draftIds.has(r.id));
|
|
4640
4653
|
if (preResults.length === 0) {
|
|
4641
4654
|
candidateRows = null;
|
|
4642
4655
|
} else {
|
|
@@ -4658,9 +4671,9 @@ var RetrievalService = class {
|
|
|
4658
4671
|
}
|
|
4659
4672
|
} else {
|
|
4660
4673
|
if (useRanker) {
|
|
4661
|
-
candidateRows = await this.entryRepo.findMetadataByEntityIds(scoredEntityIds);
|
|
4674
|
+
candidateRows = this._withoutDrafts(await this.entryRepo.findMetadataByEntityIds(scoredEntityIds), draftIds);
|
|
4662
4675
|
} else {
|
|
4663
|
-
candidateRows = await this.entryRepo.findWithEmbeddingsByEntityIds(scoredEntityIds);
|
|
4676
|
+
candidateRows = this._withoutDrafts(await this.entryRepo.findWithEmbeddingsByEntityIds(scoredEntityIds), draftIds);
|
|
4664
4677
|
}
|
|
4665
4678
|
if (weight !== void 0 && weight < 1) {
|
|
4666
4679
|
miniSearchScores = this.searchService.getMiniSearchScores(trimmedQuery, scoredEntityIds);
|
|
@@ -4690,7 +4703,7 @@ var RetrievalService = class {
|
|
|
4690
4703
|
candidateRows: rowsForEntity,
|
|
4691
4704
|
weight,
|
|
4692
4705
|
miniSearchScores,
|
|
4693
|
-
limit: Math.max(maxResults * 2, maxResults + 50)
|
|
4706
|
+
limit: padLimit(Math.max(maxResults * 2, maxResults + 50))
|
|
4694
4707
|
});
|
|
4695
4708
|
return ranked.map((row) => ({ ...row, entity_id: scopedEntityId }));
|
|
4696
4709
|
})
|
|
@@ -4904,7 +4917,7 @@ var RetrievalService = class {
|
|
|
4904
4917
|
});
|
|
4905
4918
|
} else if (policy === "keyword") {
|
|
4906
4919
|
const hasActiveFloorsKeywordFallback = sanitizedTierFloors !== void 0 && Object.values(sanitizedTierFloors).some((f) => f > 0);
|
|
4907
|
-
const keywordOversampledLimit = hasActiveFloorsKeywordFallback ? Number.MAX_SAFE_INTEGER : Math.max(maxResults * 2, maxResults + 50);
|
|
4920
|
+
const keywordOversampledLimit = hasActiveFloorsKeywordFallback ? Number.MAX_SAFE_INTEGER : padLimit(Math.max(maxResults * 2, maxResults + 50));
|
|
4908
4921
|
const preFilteredIds = effectivePreFilterLimit !== void 0 ? new Set(candidateRows.map((r) => r.id)) : void 0;
|
|
4909
4922
|
const keywordResults = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, keywordOversampledLimit);
|
|
4910
4923
|
const topResults = preFilteredIds === void 0 ? keywordResults : keywordResults.filter((r) => preFilteredIds.has(r.id));
|
|
@@ -4945,6 +4958,7 @@ var RetrievalService = class {
|
|
|
4945
4958
|
// read() re-sorts after applying tier weights
|
|
4946
4959
|
});
|
|
4947
4960
|
}
|
|
4961
|
+
if (draftPad > 0) scored = scored.filter((s) => !draftIds.has(s.id));
|
|
4948
4962
|
if (scored.length > 0) {
|
|
4949
4963
|
scored = scored.map((row) => ({
|
|
4950
4964
|
...row,
|
|
@@ -5007,8 +5021,8 @@ var RetrievalService = class {
|
|
|
5007
5021
|
}
|
|
5008
5022
|
if (!usedEmbed && scoredEntityIds.length > 0) {
|
|
5009
5023
|
const hasActiveFloors = sanitizedTierFloors !== void 0 && Object.values(sanitizedTierFloors).some((f) => f > 0);
|
|
5010
|
-
const fallbackOversampledLimit = hasActiveFloors ? Number.MAX_SAFE_INTEGER : Math.max(maxResults * 2, maxResults + 50);
|
|
5011
|
-
const results = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, fallbackOversampledLimit);
|
|
5024
|
+
const fallbackOversampledLimit = hasActiveFloors ? Number.MAX_SAFE_INTEGER : padLimit(Math.max(maxResults * 2, maxResults + 50));
|
|
5025
|
+
const results = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, fallbackOversampledLimit).filter((r) => !draftIds.has(r.id));
|
|
5012
5026
|
const candidates = results.map((r) => ({
|
|
5013
5027
|
id: r.id,
|
|
5014
5028
|
entity_id: r.entity_id,
|
|
@@ -5032,7 +5046,7 @@ var RetrievalService = class {
|
|
|
5032
5046
|
await this.entryRepo.trackAccess(ids, now);
|
|
5033
5047
|
}
|
|
5034
5048
|
} else {
|
|
5035
|
-
facts = await this.entryRepo.findRecentByEntityIds(entityIds, maxResults);
|
|
5049
|
+
facts = excludeDrafts ? await this.entryRepo.findRecentByEntityIds(entityIds, maxResults, void 0, { excludeDrafts: true }) : await this.entryRepo.findRecentByEntityIds(entityIds, maxResults);
|
|
5036
5050
|
}
|
|
5037
5051
|
const eventsLimit = Math.min(10 * entityIds.length, 100);
|
|
5038
5052
|
const [tasks, events] = await Promise.all([
|
|
@@ -5068,6 +5082,9 @@ var RetrievalService = class {
|
|
|
5068
5082
|
_tieBreakSort(items) {
|
|
5069
5083
|
items.sort((a, b) => this._compareScoredRows(a, b));
|
|
5070
5084
|
}
|
|
5085
|
+
_withoutDrafts(rows, draftIds) {
|
|
5086
|
+
return draftIds.size === 0 ? rows : rows.filter((row) => !draftIds.has(row.id));
|
|
5087
|
+
}
|
|
5071
5088
|
/**
|
|
5072
5089
|
* Comparator for score + deterministic tie-break fields.
|
|
5073
5090
|
* Negative return means "a ranks ahead of b" for descending score order.
|
|
@@ -5274,6 +5291,6 @@ var WriteService = class {
|
|
|
5274
5291
|
}
|
|
5275
5292
|
};
|
|
5276
5293
|
|
|
5277
|
-
export { BaseRepository, DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, DEFAULT_MAX_EMBED_CHARS, DiagnosticBuffer, EMBED_CHARS_CEILING, EmbeddingService, HEAL_ANCHORS_PER_CANDIDATE, HEAL_BATCH_SIZE, HEAL_MAX_FACT_BODY_CHARS_L3, HEAL_MAX_TASKS, HEAL_RECHECK_MS, 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, WikiDuplicateHashError, WikiGraphNodeOwnershipConflict, WikiIngestEmptyError, WikiInvalidReadOptions, WikiParseError, WikiSourceRefHashCollision, WikiStrictOntologyViolation, WikiTransactionError, WriteService, __privateAdd, __privateGet, __privateSet, chunkText, configureRandomSource, emptyManifest, entitySummaryMetaKey, extractSqliteCode, generateId, normalizeSourceHash, normalizeSourceRef, normalizeTitleKey, parseEmbedding, resolveEdgeDefinitions, resolveNodeType, safeSlice, typeSatisfies, validateInlineEdges, validateManifest };
|
|
5278
|
-
//# sourceMappingURL=chunk-
|
|
5279
|
-
//# sourceMappingURL=chunk-
|
|
5294
|
+
export { BaseRepository, DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, DEFAULT_MAX_EMBED_CHARS, DiagnosticBuffer, EMBED_CHARS_CEILING, EmbeddingService, HEAL_ANCHORS_PER_CANDIDATE, HEAL_BATCH_SIZE, HEAL_MAX_FACT_BODY_CHARS_L3, HEAL_MAX_TASKS, HEAL_RECHECK_MS, 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, WikiDraftNotFound, WikiDuplicateHashError, WikiGraphNodeOwnershipConflict, WikiIngestEmptyError, WikiInvalidReadOptions, WikiParseError, WikiSourceRefHashCollision, WikiStrictOntologyViolation, WikiTransactionError, WriteService, __privateAdd, __privateGet, __privateSet, chunkText, configureRandomSource, emptyManifest, entitySummaryMetaKey, extractSqliteCode, generateId, normalizeSourceHash, normalizeSourceRef, normalizeTitleKey, parseEmbedding, resolveEdgeDefinitions, resolveNodeType, safeSlice, typeSatisfies, validateInlineEdges, validateManifest };
|
|
5295
|
+
//# sourceMappingURL=chunk-G5OR2VWD.mjs.map
|
|
5296
|
+
//# sourceMappingURL=chunk-G5OR2VWD.mjs.map
|