@equationalapplications/core-llm-wiki 4.5.0 → 4.6.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 +27 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,9 @@ Pure TypeScript business logic for LLM Wiki Memory.
|
|
|
9
9
|
- **Platform-agnostic** — Zero runtime dependencies; works with any SQLite driver via the `SQLiteAdapter` interface
|
|
10
10
|
- **Semantic search** — Vector embeddings via your LLM's `embed` function, ranked by cosine similarity
|
|
11
11
|
- **Keyword fallback** — MiniSearch in-memory index for offline/degraded scenarios when embeddings unavailable
|
|
12
|
-
- **Retrieval tuning** — Per-call overrides for `maxResults`, `preFilterLimit`, and `
|
|
12
|
+
- **Retrieval tuning** — Per-call overrides for `maxResults`, `preFilterLimit`, `hybridWeight`, `tierWeights`, and `includeZeroWeightEntities`
|
|
13
|
+
- **Multi-entity reads** — Search across multiple `entity_id` namespaces in one pass with per-entity score multipliers (`tierWeights`); optional `factScores` and `metadata` for explainability
|
|
14
|
+
- **Immutable vs mutable facts** — Use `WikiFact.source_type` to distinguish document-sourced facts (`immutable_document`) from derived or user-provided facts (`librarian_inferred`, `user_stated`, `user_confirmed`). Immutable document facts are not rewritten by `runLibrarian()` or `runHeal()` and can only be removed by `forget()` or re-ingesting.
|
|
13
15
|
- **Full-featured memory** — Facts, tasks, events, maintenance jobs (librarian, heal, reembed, prune)
|
|
14
16
|
- **Type-safe** — Built with TypeScript, full type exports
|
|
15
17
|
|
|
@@ -121,6 +123,19 @@ const memory = await wikiMemory.read('user-123', 'my preferences', {
|
|
|
121
123
|
preFilterLimit: 20,
|
|
122
124
|
hybridWeight: 0.5,
|
|
123
125
|
});
|
|
126
|
+
|
|
127
|
+
// Multi-entity with tier weights
|
|
128
|
+
const multiMemory = await wikiMemory.read(['tier_wisdom', 'tier_fact', 'tier_working'], 'my preferences', {
|
|
129
|
+
maxResults: 8,
|
|
130
|
+
tierWeights: {
|
|
131
|
+
tier_wisdom: 2, // high-confidence curated notes boosted 2×
|
|
132
|
+
tier_fact: 1, // neutral baseline
|
|
133
|
+
tier_working: 0.25, // recent but unvetted context downranked
|
|
134
|
+
},
|
|
135
|
+
// includeZeroWeightEntities: true — include 0-weight entities as bottom-ranked filler
|
|
136
|
+
});
|
|
137
|
+
// multiMemory.factScores — optional Record<factId, weightedScore> for returned facts; may be absent/undefined
|
|
138
|
+
// multiMemory.metadata — optional { query, entityIds, tierWeights }; may be absent/undefined
|
|
124
139
|
```
|
|
125
140
|
|
|
126
141
|
**Hybrid scoring blends:**
|
|
@@ -130,6 +145,15 @@ const memory = await wikiMemory.read('user-123', 'my preferences', {
|
|
|
130
145
|
|
|
131
146
|
True cosine-range pure semantic ranking (including negative cosine values) is used when `hybridWeight` is left `undefined`.
|
|
132
147
|
|
|
148
|
+
**Tier weights:**
|
|
149
|
+
- `tierWeights` applies a per-entity multiplier after semantic/keyword scoring: `finalScore = retrievalScore × weight`
|
|
150
|
+
- Missing weights default to `1.0`. Negative weights clamp to `0`. Non-finite weights default to `1.0`.
|
|
151
|
+
- `tierWeights[entity] = 0` skips that entity's scored retrieval branch (no compute cost).
|
|
152
|
+
- `includeZeroWeightEntities: true` includes zero-weight entities as bottom-ranked filler instead of skipping them.
|
|
153
|
+
- `factScores` is present for array-shaped `entityId` calls only when the query is non-empty and at least one fact is scored; empty-query ("recent facts") reads leave it absent even when `entityId` is an array. Plain string calls never expose it. `metadata` is present for all array-shaped calls regardless of query.
|
|
154
|
+
- `maxResults` applies globally across all requested entities.
|
|
155
|
+
- Tasks are capped at `min(20 × entityCount, 200)`; events at `min(10 × entityCount, 100)` for multi-entity reads.
|
|
156
|
+
|
|
133
157
|
**Pre-filtering optimization:**
|
|
134
158
|
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).
|
|
135
159
|
|
|
@@ -418,7 +442,7 @@ console.log(memory.factScores);
|
|
|
418
442
|
|
|
419
443
|
### Librarian prompt override contract
|
|
420
444
|
|
|
421
|
-
Core
|
|
445
|
+
Core exports prompt utilities for weighted retrieval-based synthesis. Use `mapLibrarianOptionsToReadOptions()` to map `entityWeights` to `tierWeights`, then hydrate a prompt with `query`, `context`, and `tasks`.
|
|
422
446
|
|
|
423
447
|
```ts
|
|
424
448
|
import {
|
|
@@ -553,7 +577,7 @@ const adapter: SQLiteAdapter = {
|
|
|
553
577
|
|
|
554
578
|
```mermaid
|
|
555
579
|
flowchart TD
|
|
556
|
-
A["read(entityId, query)"] --> B{hybridWeight = 0?}
|
|
580
|
+
A["read(entityId | entityId[], query, options?)"] --> B{hybridWeight = 0?}
|
|
557
581
|
B -->|Yes| C["MiniSearch only<br/>(skip embed)"]
|
|
558
582
|
B -->|No| D{embed available?}
|
|
559
583
|
D -->|No| C
|
package/dist/index.js
CHANGED
|
@@ -1009,7 +1009,7 @@ After running the migration SQL, restart your application.`
|
|
|
1009
1009
|
async read(entityId, query, options) {
|
|
1010
1010
|
const config = this.options.config;
|
|
1011
1011
|
const entityIds = normalizeEntityIds(entityId);
|
|
1012
|
-
const sanitizedTierWeights = sanitizeTierWeights(entityIds, options?.tierWeights);
|
|
1012
|
+
const sanitizedTierWeights = shouldExposeReadMetadata(entityId) ? sanitizeTierWeights(entityIds, options?.tierWeights) : void 0;
|
|
1013
1013
|
const exposeMetadata = shouldExposeReadMetadata(entityId);
|
|
1014
1014
|
if (entityIds.length === 0) {
|
|
1015
1015
|
const empty = { facts: [], tasks: [], events: [] };
|
|
@@ -1064,7 +1064,7 @@ After running the migration SQL, restart your application.`
|
|
|
1064
1064
|
);
|
|
1065
1065
|
}
|
|
1066
1066
|
}
|
|
1067
|
-
const mismatchScope = this._entityInClause(
|
|
1067
|
+
const mismatchScope = this._entityInClause(scoredEntityIds);
|
|
1068
1068
|
const mismatchedCount = await this.db.getFirstAsync(
|
|
1069
1069
|
`SELECT COUNT(*) AS cnt FROM ${this.prefix}entries
|
|
1070
1070
|
WHERE ${mismatchScope.clause} AND deleted_at IS NULL
|