@graphorin/memory 0.5.0 → 0.6.1
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/CHANGELOG.md +102 -1
- package/README.md +54 -37
- package/dist/conflict/index.d.ts +3 -1
- package/dist/conflict/index.js +1 -1
- package/dist/conflict/locale-packs/en.d.ts +13 -0
- package/dist/conflict/locale-packs/en.d.ts.map +1 -0
- package/dist/conflict/locale-packs/en.js +1 -1
- package/dist/conflict/locale-packs/en.js.map +1 -1
- package/dist/conflict/pipeline.d.ts +2 -2
- package/dist/conflict/pipeline.js +3 -3
- package/dist/conflict/pipeline.js.map +1 -1
- package/dist/conflict/stages/helpers.js +1 -1
- package/dist/conflict/stages/helpers.js.map +1 -1
- package/dist/conflict/stages/stage1-exact-dedup.js.map +1 -1
- package/dist/conflict/stages/stage2-embedding-three-zone.js.map +1 -1
- package/dist/conflict/stages/stage3-heuristic-regex.js +1 -1
- package/dist/conflict/stages/stage3-heuristic-regex.js.map +1 -1
- package/dist/conflict/stages/stage4-subject-predicate.js.map +1 -1
- package/dist/conflict/stages/stage5-defer-to-deep.js.map +1 -1
- package/dist/conflict/types.d.ts +7 -7
- package/dist/conflict/types.js +1 -1
- package/dist/conflict/types.js.map +1 -1
- package/dist/consolidator/budget.js +16 -3
- package/dist/consolidator/budget.js.map +1 -1
- package/dist/consolidator/decay.d.ts +13 -2
- package/dist/consolidator/decay.js +17 -5
- package/dist/consolidator/decay.js.map +1 -1
- package/dist/consolidator/dlq.js +1 -1
- package/dist/consolidator/dlq.js.map +1 -1
- package/dist/consolidator/errors.js +2 -2
- package/dist/consolidator/errors.js.map +1 -1
- package/dist/consolidator/index.js +8 -6
- package/dist/consolidator/index.js.map +1 -1
- package/dist/consolidator/lock.js +1 -1
- package/dist/consolidator/lock.js.map +1 -1
- package/dist/consolidator/noise-filter.js.map +1 -1
- package/dist/consolidator/phases/deep.js +6 -2
- package/dist/consolidator/phases/deep.js.map +1 -1
- package/dist/consolidator/phases/induce.d.ts +10 -10
- package/dist/consolidator/phases/induce.js +6 -6
- package/dist/consolidator/phases/induce.js.map +1 -1
- package/dist/consolidator/phases/learned-context.js +129 -0
- package/dist/consolidator/phases/learned-context.js.map +1 -0
- package/dist/consolidator/phases/light.js +2 -1
- package/dist/consolidator/phases/light.js.map +1 -1
- package/dist/consolidator/phases/reflect.js +5 -4
- package/dist/consolidator/phases/reflect.js.map +1 -1
- package/dist/consolidator/phases/standard.js +37 -8
- package/dist/consolidator/phases/standard.js.map +1 -1
- package/dist/consolidator/reconcile.js +1 -1
- package/dist/consolidator/reconcile.js.map +1 -1
- package/dist/consolidator/runtime.d.ts +4 -4
- package/dist/consolidator/runtime.d.ts.map +1 -1
- package/dist/consolidator/runtime.js +73 -16
- package/dist/consolidator/runtime.js.map +1 -1
- package/dist/consolidator/scheduler.d.ts +5 -5
- package/dist/consolidator/scheduler.js +1 -1
- package/dist/consolidator/scheduler.js.map +1 -1
- package/dist/consolidator/triggers.js +7 -7
- package/dist/consolidator/triggers.js.map +1 -1
- package/dist/consolidator/types.d.ts +68 -20
- package/dist/consolidator/types.d.ts.map +1 -1
- package/dist/consolidator/types.js +16 -6
- package/dist/consolidator/types.js.map +1 -1
- package/dist/context-engine/annotations.d.ts +9 -9
- package/dist/context-engine/annotations.js +3 -3
- package/dist/context-engine/annotations.js.map +1 -1
- package/dist/context-engine/auto-recall.js.map +1 -1
- package/dist/context-engine/compaction/clear-tool-results.d.ts +18 -3
- package/dist/context-engine/compaction/clear-tool-results.d.ts.map +1 -1
- package/dist/context-engine/compaction/clear-tool-results.js +26 -5
- package/dist/context-engine/compaction/clear-tool-results.js.map +1 -1
- package/dist/context-engine/compaction/compactor.js +19 -6
- package/dist/context-engine/compaction/compactor.js.map +1 -1
- package/dist/context-engine/compaction/hooks/reanchor-persona-block.js +4 -0
- package/dist/context-engine/compaction/hooks/reanchor-persona-block.js.map +1 -1
- package/dist/context-engine/compaction/hooks/reanchor-pinned-facts.js +1 -0
- package/dist/context-engine/compaction/hooks/reanchor-pinned-facts.js.map +1 -1
- package/dist/context-engine/compaction/hooks/reanchor-project-rules.js +2 -1
- package/dist/context-engine/compaction/hooks/reanchor-project-rules.js.map +1 -1
- package/dist/context-engine/compaction/hooks/reanchor-recent-results.d.ts +28 -0
- package/dist/context-engine/compaction/hooks/reanchor-recent-results.d.ts.map +1 -0
- package/dist/context-engine/compaction/hooks/reanchor-recent-results.js +71 -0
- package/dist/context-engine/compaction/hooks/reanchor-recent-results.js.map +1 -0
- package/dist/context-engine/compaction/hooks/types.d.ts +15 -3
- package/dist/context-engine/compaction/hooks/types.d.ts.map +1 -1
- package/dist/context-engine/compaction/index.d.ts +1 -0
- package/dist/context-engine/compaction/index.js +2 -1
- package/dist/context-engine/compaction/templates/summary-9-section.d.ts +10 -3
- package/dist/context-engine/compaction/templates/summary-9-section.d.ts.map +1 -1
- package/dist/context-engine/compaction/templates/summary-9-section.js +42 -5
- package/dist/context-engine/compaction/templates/summary-9-section.js.map +1 -1
- package/dist/context-engine/compaction/thresholds.js.map +1 -1
- package/dist/context-engine/compaction/types.d.ts +47 -7
- package/dist/context-engine/compaction/types.d.ts.map +1 -1
- package/dist/context-engine/engine.d.ts +23 -4
- package/dist/context-engine/engine.d.ts.map +1 -1
- package/dist/context-engine/engine.js +69 -15
- package/dist/context-engine/engine.js.map +1 -1
- package/dist/context-engine/index.d.ts +1 -0
- package/dist/context-engine/index.d.ts.map +1 -1
- package/dist/context-engine/index.js +2 -1
- package/dist/context-engine/locale-packs/en.js +14 -13
- package/dist/context-engine/locale-packs/en.js.map +1 -1
- package/dist/context-engine/locale-packs/types.d.ts +10 -10
- package/dist/context-engine/locale-packs/types.d.ts.map +1 -1
- package/dist/context-engine/locale-packs/types.js.map +1 -1
- package/dist/context-engine/metadata.d.ts +1 -1
- package/dist/context-engine/metadata.js +2 -2
- package/dist/context-engine/metadata.js.map +1 -1
- package/dist/context-engine/preambles/inbound-en.d.ts +1 -1
- package/dist/context-engine/preambles/inbound-en.js +1 -1
- package/dist/context-engine/preambles/inbound-en.js.map +1 -1
- package/dist/context-engine/privacy-filter.d.ts +2 -2
- package/dist/context-engine/privacy-filter.js +1 -1
- package/dist/context-engine/privacy-filter.js.map +1 -1
- package/dist/context-engine/templates/base-en.d.ts +1 -1
- package/dist/context-engine/templates/base-en.js +1 -1
- package/dist/context-engine/templates/base-en.js.map +1 -1
- package/dist/context-engine/templates/composer.d.ts +1 -1
- package/dist/context-engine/templates/composer.js.map +1 -1
- package/dist/context-engine/token-budget.d.ts +1 -1
- package/dist/context-engine/token-budget.js +1 -1
- package/dist/context-engine/token-budget.js.map +1 -1
- package/dist/context-engine/token-counter.d.ts +16 -7
- package/dist/context-engine/token-counter.d.ts.map +1 -1
- package/dist/context-engine/token-counter.js +31 -9
- package/dist/context-engine/token-counter.js.map +1 -1
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.js +4 -4
- package/dist/errors/index.js.map +1 -1
- package/dist/facade.d.ts +44 -15
- package/dist/facade.d.ts.map +1 -1
- package/dist/facade.js +16 -8
- package/dist/facade.js.map +1 -1
- package/dist/graph/entity-resolver.d.ts +2 -2
- package/dist/graph/entity-resolver.js +2 -2
- package/dist/graph/entity-resolver.js.map +1 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/internal/contextualize.js +2 -2
- package/dist/internal/contextualize.js.map +1 -1
- package/dist/internal/embedder-binding.js +1 -1
- package/dist/internal/embedder-binding.js.map +1 -1
- package/dist/internal/id.js +1 -1
- package/dist/internal/id.js.map +1 -1
- package/dist/internal/injection-heuristics.js +25 -2
- package/dist/internal/injection-heuristics.js.map +1 -1
- package/dist/internal/spans.js +1 -1
- package/dist/internal/spans.js.map +1 -1
- package/dist/internal/storage-adapter.d.ts +71 -22
- package/dist/internal/storage-adapter.d.ts.map +1 -1
- package/dist/migration/embedder-migration.d.ts +7 -7
- package/dist/migration/embedder-migration.js.map +1 -1
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/search/explain.d.ts +7 -4
- package/dist/search/explain.d.ts.map +1 -1
- package/dist/search/explain.js +1 -1
- package/dist/search/explain.js.map +1 -1
- package/dist/search/fit-weights.d.ts +48 -0
- package/dist/search/fit-weights.d.ts.map +1 -0
- package/dist/search/fit-weights.js +70 -0
- package/dist/search/fit-weights.js.map +1 -0
- package/dist/search/graph-ppr.d.ts +36 -0
- package/dist/search/graph-ppr.d.ts.map +1 -0
- package/dist/search/graph-ppr.js +38 -0
- package/dist/search/graph-ppr.js.map +1 -0
- package/dist/search/index.d.ts +4 -1
- package/dist/search/index.js +4 -1
- package/dist/search/iterative.d.ts +15 -8
- package/dist/search/iterative.d.ts.map +1 -1
- package/dist/search/iterative.js +10 -9
- package/dist/search/iterative.js.map +1 -1
- package/dist/search/query-transform.d.ts +6 -6
- package/dist/search/query-transform.js +6 -6
- package/dist/search/query-transform.js.map +1 -1
- package/dist/search/rrf.d.ts +4 -4
- package/dist/search/rrf.js +4 -4
- package/dist/search/rrf.js.map +1 -1
- package/dist/search/trust.d.ts +30 -0
- package/dist/search/trust.d.ts.map +1 -0
- package/dist/search/trust.js +50 -0
- package/dist/search/trust.js.map +1 -0
- package/dist/search/types.d.ts +1 -1
- package/dist/tiers/episodic-memory.d.ts +6 -4
- package/dist/tiers/episodic-memory.d.ts.map +1 -1
- package/dist/tiers/episodic-memory.js +3 -2
- package/dist/tiers/episodic-memory.js.map +1 -1
- package/dist/tiers/index.d.ts +1 -1
- package/dist/tiers/index.js +1 -1
- package/dist/tiers/insight-memory.d.ts +4 -4
- package/dist/tiers/insight-memory.js +3 -3
- package/dist/tiers/insight-memory.js.map +1 -1
- package/dist/tiers/procedural-memory.d.ts +29 -7
- package/dist/tiers/procedural-memory.d.ts.map +1 -1
- package/dist/tiers/procedural-memory.js +66 -6
- package/dist/tiers/procedural-memory.js.map +1 -1
- package/dist/tiers/semantic-memory.d.ts +111 -30
- package/dist/tiers/semantic-memory.d.ts.map +1 -1
- package/dist/tiers/semantic-memory.js +120 -27
- package/dist/tiers/semantic-memory.js.map +1 -1
- package/dist/tiers/session-memory.d.ts +7 -7
- package/dist/tiers/session-memory.js +7 -7
- package/dist/tiers/session-memory.js.map +1 -1
- package/dist/tiers/shared-memory.d.ts +1 -1
- package/dist/tiers/shared-memory.js +1 -1
- package/dist/tiers/shared-memory.js.map +1 -1
- package/dist/tiers/working-memory.d.ts +3 -3
- package/dist/tiers/working-memory.js +2 -2
- package/dist/tiers/working-memory.js.map +1 -1
- package/dist/tools/block-tools.d.ts +3 -3
- package/dist/tools/block-tools.js +3 -3
- package/dist/tools/block-tools.js.map +1 -1
- package/dist/tools/fact-tools.d.ts +48 -31
- package/dist/tools/fact-tools.d.ts.map +1 -1
- package/dist/tools/fact-tools.js +30 -18
- package/dist/tools/fact-tools.js.map +1 -1
- package/dist/tools/index.d.ts +9 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/recall-tools.d.ts +40 -20
- package/dist/tools/recall-tools.d.ts.map +1 -1
- package/dist/tools/recall-tools.js +29 -10
- package/dist/tools/recall-tools.js.map +1 -1
- package/dist/tools/runbook-tools.d.ts +76 -0
- package/dist/tools/runbook-tools.d.ts.map +1 -0
- package/dist/tools/runbook-tools.js +53 -0
- package/dist/tools/runbook-tools.js.map +1 -0
- package/dist/tools/taint.js +33 -0
- package/dist/tools/taint.js.map +1 -0
- package/dist/tools/types.d.ts +1 -1
- package/package.json +8 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityRole, Episode as Episode$1, EpisodicMemoryStore, Fact as Fact$1, GraphEntity, Insight as Insight$1, MemoryHit, MemoryStatus, MemoryStore, Message as Message$1, ProceduralMemoryStore, SemanticMemoryStore, SessionMemoryStore, SessionScope as SessionScope$1 } from "@graphorin/core";
|
|
1
|
+
import { EntityRole, Episode as Episode$1, EpisodicMemoryStore, Fact as Fact$1, GraphEntity, Insight as Insight$1, MemoryHit, MemoryOwner, MemoryStatus, MemoryStore, Message as Message$1, ProceduralMemoryStore, Rule, SemanticMemoryStore, SessionMemoryStore, SessionScope as SessionScope$1 } from "@graphorin/core";
|
|
2
2
|
|
|
3
3
|
//#region src/internal/storage-adapter.d.ts
|
|
4
4
|
|
|
@@ -37,11 +37,11 @@ interface EpisodicMemoryStoreExt extends EpisodicMemoryStore {
|
|
|
37
37
|
searchVector?(scope: SessionScope$1, embedding: Float32Array, embedderId: string, topK: number, /** Point-in-time filter (`started_at <= asOf`, ISO-8601). P0-2. */
|
|
38
38
|
asOf?: string, /** Include quarantined episodes (validation/inspector path). P1-4. */
|
|
39
39
|
includeQuarantined?: boolean): Promise<ReadonlyArray<MemoryHit<Episode$1>>>;
|
|
40
|
-
/** Mark an episode archived. Soft-archive
|
|
40
|
+
/** Mark an episode archived. Soft-archive - the row stays for replay. */
|
|
41
41
|
archive?(id: string, reason?: string): Promise<void>;
|
|
42
42
|
/**
|
|
43
43
|
* Most-recent episodes by end time (newest first), with no FTS / vector
|
|
44
|
-
* query
|
|
44
|
+
* query - recency, not relevance (MCON-1). Powers `EpisodicMemory.recent()`
|
|
45
45
|
* and the deep-phase reflection gate. The default `@graphorin/store-sqlite`
|
|
46
46
|
* adapter implements it.
|
|
47
47
|
*/
|
|
@@ -49,13 +49,13 @@ interface EpisodicMemoryStoreExt extends EpisodicMemoryStore {
|
|
|
49
49
|
includeQuarantined?: boolean;
|
|
50
50
|
}): Promise<ReadonlyArray<Episode$1>>;
|
|
51
51
|
/**
|
|
52
|
-
* Set an episode's retrieval-trust `status` (MCON-2)
|
|
52
|
+
* Set an episode's retrieval-trust `status` (MCON-2) - promote a quarantined
|
|
53
53
|
* (auto-formed) episode into default recall or re-quarantine an active one,
|
|
54
54
|
* with a `memory_history` audit row. Powers {@link EpisodicMemory.validate}.
|
|
55
55
|
*/
|
|
56
56
|
setStatus?(id: string, status: MemoryStatus, reason?: string): Promise<void>;
|
|
57
57
|
/**
|
|
58
|
-
* Count the recall-eligible episodes for the scope (CE-5)
|
|
58
|
+
* Count the recall-eligible episodes for the scope (CE-5) - a `COUNT(*)`,
|
|
59
59
|
* never materialising rows. Powers honest `metadata()` counts.
|
|
60
60
|
*/
|
|
61
61
|
count?(scope: SessionScope$1): Promise<number>;
|
|
@@ -79,20 +79,30 @@ interface SemanticMemoryStoreExt extends SemanticMemoryStore {
|
|
|
79
79
|
* Include quarantined facts in the KNN result (validation /
|
|
80
80
|
* inspector path). Default reads exclude them. P1-4.
|
|
81
81
|
*/
|
|
82
|
-
includeQuarantined?: boolean
|
|
82
|
+
includeQuarantined?: boolean,
|
|
83
|
+
/**
|
|
84
|
+
* Include superseded / validity-expired facts. Default reads
|
|
85
|
+
* evaluate validity at NOW (memory-retrieval-01).
|
|
86
|
+
*/
|
|
87
|
+
includeSuperseded?: boolean,
|
|
88
|
+
/**
|
|
89
|
+
* Retrieval-time principal filter (D3). Rows with no stored owner
|
|
90
|
+
* are treated as `'user'`. Absent ⇒ no owner filter.
|
|
91
|
+
*/
|
|
92
|
+
owner?: MemoryOwner | ReadonlyArray<MemoryOwner>): Promise<ReadonlyArray<MemoryHit<Fact$1>>>;
|
|
83
93
|
/** Lookup a single fact by id (returns `null` when absent or soft-deleted). */
|
|
84
94
|
get?(id: string): Promise<Fact$1 | null>;
|
|
85
95
|
/**
|
|
86
96
|
* Set a fact's retrieval-trust `status` and write a `memory_history`
|
|
87
97
|
* audit row (P1-4). Promotes a quarantined fact to `active` (the
|
|
88
98
|
* validation path) or re-quarantines an active one. Never touches
|
|
89
|
-
* content / embedding / tombstone
|
|
99
|
+
* content / embedding / tombstone - quarantine is a retrieval gate.
|
|
90
100
|
* Powers {@link SemanticMemory.validate}; the default
|
|
91
101
|
* `@graphorin/store-sqlite` adapter implements it.
|
|
92
102
|
*/
|
|
93
103
|
setStatus?(factId: string, status: MemoryStatus, reason?: string): Promise<void>;
|
|
94
104
|
/**
|
|
95
|
-
* Count the recall-eligible facts for the scope (CE-5)
|
|
105
|
+
* Count the recall-eligible facts for the scope (CE-5) - a `COUNT(*)` with
|
|
96
106
|
* the default recall filters (live, non-archived, non-quarantined), never
|
|
97
107
|
* materialising rows. Powers honest `metadata()` counts.
|
|
98
108
|
*/
|
|
@@ -152,7 +162,7 @@ interface SessionMemoryStoreExt extends SessionMemoryStore {
|
|
|
152
162
|
*/
|
|
153
163
|
listMessagesSince?(scope: SessionScope$1, lastMessageId: string | null, limit: number): Promise<ReadonlyArray<SessionMessageRecord>>;
|
|
154
164
|
/**
|
|
155
|
-
* Count the live messages in the scoped session (CE-5)
|
|
165
|
+
* Count the live messages in the scoped session (CE-5) - a `COUNT(*)`, never
|
|
156
166
|
* materialising rows; `0` for a user-only scope. Powers honest `metadata()`
|
|
157
167
|
* counts instead of `list(...)`-materialising up to 1000 rows.
|
|
158
168
|
*/
|
|
@@ -226,7 +236,7 @@ interface ConflictAuditInputLike {
|
|
|
226
236
|
readonly detectedBy?: string;
|
|
227
237
|
}
|
|
228
238
|
/**
|
|
229
|
-
* Pending-queue payload
|
|
239
|
+
* Pending-queue payload - Stage 5 (defer-to-deep) hands the row over
|
|
230
240
|
* to the deep-phase LLM judge (Phase 10c).
|
|
231
241
|
*
|
|
232
242
|
* @stable
|
|
@@ -281,7 +291,7 @@ interface ConflictMemoryStoreExt {
|
|
|
281
291
|
* Stamp `attemptedAt` on a pending row whose judge call failed
|
|
282
292
|
* (MCON-9). The deep phase closes the row as `'judge-unparseable'`
|
|
283
293
|
* on the NEXT failure, so a poisoned row is billed at most twice.
|
|
284
|
-
* Optional
|
|
294
|
+
* Optional - without it the deep phase falls back to skip-and-retry.
|
|
285
295
|
*/
|
|
286
296
|
markAttempted?(id: number, attemptedAt?: number): Promise<void>;
|
|
287
297
|
}
|
|
@@ -399,7 +409,7 @@ interface DlqBatchRow {
|
|
|
399
409
|
* for Phase 10c. Mirrors the `consolidator_state`,
|
|
400
410
|
* `consolidator_runs`, and `consolidator_failed_batches` tables
|
|
401
411
|
* shipped in Phase 05's migration 009. Adapters that do not
|
|
402
|
-
* implement the surface degrade gracefully
|
|
412
|
+
* implement the surface degrade gracefully - the consolidator runs
|
|
403
413
|
* in stateless mode (no DLQ, no cursor persistence) and emits a
|
|
404
414
|
* one-shot WARN.
|
|
405
415
|
*
|
|
@@ -437,7 +447,7 @@ interface ConsolidatorMemoryStoreExt {
|
|
|
437
447
|
* oldest backlog drains first.
|
|
438
448
|
*/
|
|
439
449
|
claimReadyBatches(scope: SessionScope$1, now: number, limit?: number): Promise<ReadonlyArray<DlqBatchRow>>;
|
|
440
|
-
/** Mark the row succeeded
|
|
450
|
+
/** Mark the row succeeded - removes it from the DLQ. */
|
|
441
451
|
markBatchSucceeded(id: string): Promise<void>;
|
|
442
452
|
/**
|
|
443
453
|
* Schedule the next retry attempt. The caller computes
|
|
@@ -462,7 +472,7 @@ interface ConsolidatorMemoryStoreExt {
|
|
|
462
472
|
* 10c's light phase reads the strength + last-accessed columns and
|
|
463
473
|
* archives facts whose retention curve falls below the configured
|
|
464
474
|
* threshold. Adapters that do not maintain decay columns may omit
|
|
465
|
-
* the surface entirely
|
|
475
|
+
* the surface entirely - the light phase skips the archive step
|
|
466
476
|
* with an INFO log.
|
|
467
477
|
*
|
|
468
478
|
* @stable
|
|
@@ -473,7 +483,7 @@ interface DecayMemoryStoreExt {
|
|
|
473
483
|
* caller can apply Ebbinghaus retention without scanning the
|
|
474
484
|
* whole table. `limit` defaults to `1000`.
|
|
475
485
|
*
|
|
476
|
-
* Archived rows are EXCLUDED by default (MCON-6)
|
|
486
|
+
* Archived rows are EXCLUDED by default (MCON-6) - they never receive
|
|
477
487
|
* access bumps, so they would pin the LRU head and saturate the decay
|
|
478
488
|
* window, structurally stopping threshold-archiving and capacity
|
|
479
489
|
* eviction for live facts. Inspection paths pass
|
|
@@ -497,6 +507,12 @@ interface DecayMemoryStoreExt {
|
|
|
497
507
|
readonly status: string;
|
|
498
508
|
/** Trust-provenance tag (P1-4); `null` for first-party rows. */
|
|
499
509
|
readonly provenance: string | null;
|
|
510
|
+
/**
|
|
511
|
+
* Monotonic retrieval-access counter (D3, migration 027). Feeds
|
|
512
|
+
* the opt-in `accessReinforcement` salience weight. Optional -
|
|
513
|
+
* adapters without the column omit it (treated as `0`).
|
|
514
|
+
*/
|
|
515
|
+
readonly accessCount?: number;
|
|
500
516
|
}>>;
|
|
501
517
|
/**
|
|
502
518
|
* Soft-archive a fact (sets `archived = 1`). The audit row in
|
|
@@ -506,13 +522,13 @@ interface DecayMemoryStoreExt {
|
|
|
506
522
|
/**
|
|
507
523
|
* Record a retrieval access for the given facts (MRET-7): stamp
|
|
508
524
|
* `lastAccessedAt` and reinforce `strength` (implementation-capped).
|
|
509
|
-
* Optional
|
|
525
|
+
* Optional - adapters without decay columns may omit it; callers
|
|
510
526
|
* MUST treat failures as non-fatal (the read path never breaks on a
|
|
511
527
|
* bookkeeping write).
|
|
512
528
|
*/
|
|
513
529
|
markAccessed?(ids: ReadonlyArray<string>, accessedAt?: number): Promise<void>;
|
|
514
530
|
/**
|
|
515
|
-
* Narrow decay-column read for exactly the given fact ids (MRET-8)
|
|
531
|
+
* Narrow decay-column read for exactly the given fact ids (MRET-8) -
|
|
516
532
|
* powers per-search decay re-ranking without the old O(scope)
|
|
517
533
|
* 1000-row window read. Optional; absent ⇒ the tier falls back to
|
|
518
534
|
* `listForDecay`.
|
|
@@ -541,7 +557,7 @@ interface InsightSearchStoreOptions {
|
|
|
541
557
|
* (P1-1). The consolidator's reflection pass inserts quarantined,
|
|
542
558
|
* cited insights here; the thin `InsightMemory` read surface lists /
|
|
543
559
|
* searches them; the ExpeL salience loop bumps + prunes them. Search is
|
|
544
|
-
* FTS-only by design
|
|
560
|
+
* FTS-only by design - insights are a soft, rank-capped inspector
|
|
545
561
|
* surface, not primary recall.
|
|
546
562
|
*
|
|
547
563
|
* Adapters that opt out leave the property undefined; reflection then
|
|
@@ -561,7 +577,7 @@ interface InsightMemoryStoreExt {
|
|
|
561
577
|
/** Lookup a single insight by id (`null` when absent / pruned). */
|
|
562
578
|
get?(id: string): Promise<Insight$1 | null>;
|
|
563
579
|
/**
|
|
564
|
-
* Set an insight's retrieval-trust `status` (MCON-2)
|
|
580
|
+
* Set an insight's retrieval-trust `status` (MCON-2) - promote a quarantined
|
|
565
581
|
* (reflection) insight or re-quarantine an active one, with a
|
|
566
582
|
* `memory_history` audit row. Powers {@link InsightMemory.validate}.
|
|
567
583
|
*/
|
|
@@ -573,7 +589,7 @@ interface InsightMemoryStoreExt {
|
|
|
573
589
|
bumpSalience(id: string, delta: number, reason?: string): Promise<void>;
|
|
574
590
|
/**
|
|
575
591
|
* Soft-delete every salience-0 insight for the scope (the ExpeL
|
|
576
|
-
* forgetting step). Returns the number pruned. Tombstone only
|
|
592
|
+
* forgetting step). Returns the number pruned. Tombstone only -
|
|
577
593
|
* pruned insights stay auditable.
|
|
578
594
|
*/
|
|
579
595
|
prune(scope: SessionScope$1): Promise<number>;
|
|
@@ -586,16 +602,28 @@ interface InsightMemoryStoreExt {
|
|
|
586
602
|
*/
|
|
587
603
|
interface ProceduralMemoryStoreExt extends ProceduralMemoryStore {
|
|
588
604
|
/**
|
|
589
|
-
* Set a rule's retrieval-trust `status`
|
|
605
|
+
* Set a rule's retrieval-trust `status` - promote a quarantined (induced)
|
|
590
606
|
* procedure into `activate()` or re-quarantine an active one, with a
|
|
591
607
|
* `memory_history` audit row. Powers {@link ProceduralMemory.validate}.
|
|
592
608
|
*/
|
|
593
609
|
setStatus?(id: string, status: MemoryStatus, reason?: string): Promise<void>;
|
|
610
|
+
/**
|
|
611
|
+
* Lexical runbook search over rule text (D3, migration 028) - content
|
|
612
|
+
* recall for "find the procedure for this task", as opposed to
|
|
613
|
+
* predicate activation. Quarantined (unvalidated induced) procedures
|
|
614
|
+
* are excluded unless the inspector opts in. Optional - adapters
|
|
615
|
+
* without the index omit it and {@link ProceduralMemory.search} falls
|
|
616
|
+
* back to an in-memory lexical scan over `list(...)`.
|
|
617
|
+
*/
|
|
618
|
+
search?(scope: SessionScope$1, query: string, opts?: {
|
|
619
|
+
readonly topK?: number;
|
|
620
|
+
readonly includeQuarantined?: boolean;
|
|
621
|
+
}): Promise<ReadonlyArray<MemoryHit<Rule>>>;
|
|
594
622
|
/**
|
|
595
623
|
* Record one demonstrated successful reuse of a rule and return the
|
|
596
624
|
* new counter value (MCON-2 part 4). Powers
|
|
597
625
|
* promotion-by-demonstrated-success via
|
|
598
|
-
* {@link ProceduralMemory.recordOutcome}. Optional
|
|
626
|
+
* {@link ProceduralMemory.recordOutcome}. Optional - adapters without
|
|
599
627
|
* the counter simply never auto-promote.
|
|
600
628
|
*/
|
|
601
629
|
recordSuccess?(id: string): Promise<number>;
|
|
@@ -639,6 +667,11 @@ interface ExpandHopsStoreOptions {
|
|
|
639
667
|
readonly includeQuarantined?: boolean;
|
|
640
668
|
/** Point-in-time filter, ISO-8601 (same semantics as fact search). */
|
|
641
669
|
readonly asOf?: string;
|
|
670
|
+
/**
|
|
671
|
+
* Include superseded / validity-expired neighbours. Default reads
|
|
672
|
+
* evaluate validity at NOW (memory-retrieval-01).
|
|
673
|
+
*/
|
|
674
|
+
readonly includeSuperseded?: boolean;
|
|
642
675
|
}
|
|
643
676
|
/**
|
|
644
677
|
* Optional storage extension for the lightweight in-SQLite relation
|
|
@@ -686,6 +719,22 @@ interface GraphMemoryStoreExt {
|
|
|
686
719
|
}): Promise<ReadonlyArray<EntityMergeRecord>>;
|
|
687
720
|
/** Expand seed facts to neighbours sharing a canonical entity (one-hop CTE). */
|
|
688
721
|
expandOneHop(scope: SessionScope$1, seedFactIds: ReadonlyArray<string>, opts?: ExpandHopsStoreOptions): Promise<ReadonlyArray<Fact$1>>;
|
|
722
|
+
/**
|
|
723
|
+
* PPR-lite graded expansion (D5): like {@link expandOneHop} but returns
|
|
724
|
+
* each neighbour with its minimum hop `depth` from the seeds, so the
|
|
725
|
+
* tier can weight it by damped spreading activation. Optional - stores
|
|
726
|
+
* without it fall back to flat one-hop expansion.
|
|
727
|
+
*/
|
|
728
|
+
expandActivation?(scope: SessionScope$1, seedFactIds: ReadonlyArray<string>, opts?: ExpandHopsStoreOptions): Promise<ReadonlyArray<{
|
|
729
|
+
readonly fact: Fact$1;
|
|
730
|
+
readonly depth: number;
|
|
731
|
+
}>>;
|
|
732
|
+
/**
|
|
733
|
+
* Exact entity-match retriever (D5): facts linked to the canonical
|
|
734
|
+
* entity for `normalizedName`. Optional. Powers a precise
|
|
735
|
+
* "facts about <entity>" candidate leg.
|
|
736
|
+
*/
|
|
737
|
+
factsForEntityName?(scope: SessionScope$1, normalizedName: string, opts?: ExpandHopsStoreOptions): Promise<ReadonlyArray<Fact$1>>;
|
|
689
738
|
}
|
|
690
739
|
/**
|
|
691
740
|
* Composite shape every `@graphorin/memory` consumer must supply at
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-adapter.d.ts","names":[],"sources":["../../src/internal/storage-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"storage-adapter.d.ts","names":[],"sources":["../../src/internal/storage-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;AAkCA;AAqBA;;;;;;;AAW2B,UAhCV,oBAAA,CAgCU;EAAd,SAAA,SAAA,CAAA,EAAA;IAAR,SAAA,UAAA,EAAA,MAAA;IAEoC,SAAA,MAAA,EA/BpB,YA+BoB;EAQ9B,CAAA;EAGgB;;;;;;EAWI,SAAA,SAAA,CAAA,EAAA,MAAA;;;AAU/B;;;;;;AA0BY,UAvEK,sBAAA,SAA+B,mBAuEpC,CAAA;EAA4B,gBAAA,EAAA,OAAA,EAtEX,SAsEW,EAAA,OAAA,EAtEO,oBAsEP,CAAA,EAtE8B,OAsE9B,CAAA,IAAA,CAAA;EAAd,YAAA,EAAA,KAAA,EApEf,cAoEe,EAAA,SAAA,EAnEX,YAmEW,EAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EACW;EAAV,IAAA,CAAA,EAAA,MAAA,EAAd;EAAR,kBAAA,CAAA,EAAA,OAAA,CAAA,EA7DA,OA6DA,CA7DQ,aA6DR,CA7DsB,SA6DtB,CA7DgC,SA6DhC,CAAA,CAAA,CAAA;EAEuB;EAAR,OAAA,EAAA,EAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA7DqB,OA6DrB,CAAA,IAAA,CAAA;EASiB;;;;;;EAsBoC,UAAA,EAAA,KAAA,EApF9D,cAoF8D,EAAA,KAAA,EAAA,MAAA,EAAA,OAAtB,CAAsB,EAAA;IAAd,kBAAA,CAAA,EAAA,OAAA;EAAR,CAAA,CAAA,EAjF9C,OAiF8C,CAjFtC,aAiFsC,CAjFxB,SAiFwB,CAAA,CAAA;EA5DH;;AAuEhD;AAeA;;EAGe,SAAA,EAAA,EAAA,EAAA,MAAA,EAAA,MAAA,EAxGkB,YAwGlB,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAxGkD,OAwGlD,CAAA,IAAA,CAAA;EAGY;;;;EAMgB,KAAA,EAAA,KAAA,EA5G3B,cA4G2B,CAAA,EA5GZ,OA4GY,CAAA,MAAA,CAAA;;;;;;;;;AA2B1B,UA7HA,sBAAA,SAA+B,mBA2IhC,CAAA;EAUJ,qBAAkB,EAAA,IAAA,EApJC,MAoJD,EAAA,OAAA,EApJgB,oBAoJhB,CAAA,EApJuC,OAoJvC,CAAA,IAAA,CAAA;EAelB,YAAA,EAAA,KAAA,EAjKD,cAiKsB,EAAA,SAAA,EAhKlB,YAgKkB,EAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA;EAehB;;;;EAKmB,IAAA,CAAA,EAAA,MAAA;EAanB;;;;EAOwB,kBAAA,CAAA,EAAA,OAAA;EAQxB;AAuBjB;;;EAKwB,iBAAA,CAAA,EAAA,OAAA;EAA2B;;;;EACC,KAAA,CAAA,EAvNxC,WAuNwC,GAvN1B,aAuN0B,CAvNZ,WAuNY,CAAA,CAAA,EAtN/C,OAsN+C,CAtNvC,aAsNuC,CAtNzB,SAsNyB,CAtNf,MAsNe,CAAA,CAAA,CAAA;EACf;EAAwB,GAAA,EAAA,EAAA,EAAA,MAAA,CAAA,EArNzC,OAqNyC,CArNjC,MAqNiC,GAAA,IAAA,CAAA;EAOT;;AAapD;AA0BA;AAiBA;AASA;AAoBA;AAmBA;EAyBiB,SAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAA0B,EApVN,YAoVM,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EApV0B,OAoV1B,CAAA,IAAA,CAAA;EACzB;;;;;EACyD,KAAA,EAAA,KAAA,EAhV3D,cAgV2D,CAAA,EAhV5C,OAgV4C,CAAA,MAAA,CAAA;EAAR;;;;;EAW3C,KAAA,EAAA,EAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EArVe,OAqVf,CAAA,IAAA,CAAA;EAAuB;;;;;;;;;EA6BpB,SAAA,EAAA,KAAA,EAxWP,cAwWO,EAAA,MAAA,EAAA,MAAA,CAAA,EAxWwB,OAwWxB,CAxWgC,aAwWhC,CAxW8C,MAwW9C,CAAA,CAAA;;;;;;;;;;AAmBsC,UAhXhD,oBAAA,CAgXgD;EAahD,SAAA,EAAA,EAAA,MAAA;EAgBN,SAAA,QAAA,EAAA,MAAA;EAIP,SAAA,SAAA,EAAA,MAAA;EADC,SAAA,UAAA,EAAA,MAAA,GAAA,IAAA;EA0BuC,SAAA,OAAA,EAraxB,SAqawB;;;;;;;AA0B5C;AAOA;AAqBiB,UAjdA,qBAAA,SAA8B,kBAidT,CAAA;EAEpB,YAAA,EAAA,KAAA,EAjdP,cAidO,EAAA,SAAA,EAhdH,YAgdG,EAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,CAAA,EA7cb,OA6ca,CA7cL,aA6cK,CA7cS,SA6cT,CAAA,CAAA;EAAU;;;;;EAE4B,iBAAA,EAAA,KAAA,EAzc5B,cAyc4B,CAAA,EAzcb,OAyca,CAAA,MAAA,GAAA,IAAA,CAAA;EAG7C;;;;;;EAKiB,iBAAA,EAAA,KAAA,EAzcjB,cAyciB,EAAA,aAAA,EAAA,MAAA,GAAA,IAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EAtcvB,OAscuB,CAtcf,aAsce,CAtcD,oBAscC,CAAA,CAAA;EAAR;;;;;EAiBU,KAAA,EAAA,KAAA,EAjdd,cAidc,CAAA,EAjdC,OAidD,CAAA,MAAA,CAAA;;AAS9B;;;;;;;AAmBK,UAneY,yBAAA,CAmeZ;EAQyB,gBAAA,CAAA,KAAA,EAAA;IA3BoB,SAAA,EAAA,EAAA,MAAA;IAAqB,SAAA,YAAA,EAAA,MAAA;IA+BtD,SAAA,KAAA,EAAiB,MAAA;IAejB,SAAA,GAAA,EAAA,MAAoB;IAMpB,SAAA,cAAiB,CAAA,EAAA,QAAA,GAAA,KAAA,GAAA,WAAA;IAWjB,SAAA,UAAA,EAAsB,MAAA;IA8BtB,SAAA,KAAA,CAAA,EAAA,MAAmB,GAAA,IAAA;EAEd,CAAA,CAAA,EAAA;IAAqB,SAAA,EAAA,EAAA,MAAA;EAAoB,CAAA;EAEN,GAAA,CAAA,EAAA,EAAA,MAAA,CAAA,EAAA,OAAA,GAAA,IAAA;EAAa,WAAA,CAAA,EAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAG3D,MAAA,CAAA,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAEgB,OAAA,EAAA,EAziBd,aAyiBc,CAAA;IAAd,SAAA,EAAA,EAAA,MAAA;IAAR,SAAA,SAAA,EAAA,MAAA,GAAA,IAAA;EASM,CAAA,CAAA;EAEE,UAAA,EAAA,EAnjBG,aAmjBH,CAAA;IAAR,SAAA,EAAA,EAAA,MAAA;IAEc,SAAA,SAAA,EAAA,MAAA,GAAA,IAAA;EAAmC,CAAA,CAAA;;;;;;;;;AAgB3B,KA3jBf,kBAAA,GA2jBe,aAAA,GAAA,sBAAA,GAAA,iBAAA,GAAA,mBAAA,GAAA,eAAA;;;;;;;;;AAchB,KA1jBC,qBAAA,GA0jBD,OAAA,GAAA,OAAA,GAAA,WAAA,GAAA,SAAA,GAAA,mBAAA;;;;;;;;;AAaE,UAxjBI,sBAAA,CAwjBJ;EAAR,SAAA,KAAA,EAvjBa,cAujBb;EAAO,SAAA,WAAA,EAAA,MAAA;EAeK,SAAA,UAAA,CAAA,EACf,MAAA;EAAa,SAAA,QAAA,EApkBM,qBAokBN;EACK,SAAA,KAAA,EApkBF,kBAokBE;EACC,SAAA,aAAA,CAAA,EAAA,MAAA;EACA,SAAA,UAAA,CAAA,EAAA,MAAA;EAAiC,SAAA,MAAA,CAAA,EAAA,MAAA;EAAR,SAAA,UAAA,CAAA,EAAA,MAAA;;;;;;;;UAzjB7B,wBAAA;kBACC;;;kBAGA;;;4BAGU;;;;;;;UAQX,sBAAA;;;;;;;;;;;;2BAYU;;;;;;;;;;UAWV,sBAAA;wBACO,yBAAyB;;;;wBAIzB,2BAA2B;;;qBAC9B,iCAA+B,QAAQ,cAAc;qCACrC,wBAAwB;;;;;;;oDAOT;;;;;;;;;;;;UAanC,oBAAA;kBACC;;;;;;;;;;;;;;;;;;;;;;;;UAyBD,sBAAA;;;;;;;;;;;;;;;;UAiBA,oBAAA;;kBAEC;;;;;;UAOD,qBAAA;;;;;;;;;;;;;;;;;;;UAoBA,aAAA;;;kBAGC;uBACK;;;;;;;;;;;;;;UAeN,WAAA;;;kBAGC;uBACK;;;;;;;;;;;;;;;;;;;;UAqBN,0BAAA;kBACC,iBAAe,QAAQ;qBACpB,uBAAqB,yBAAyB,QAAQ;;;;;;;;qBAQtD,+DAA6D;qBAC7D,gCAA8B;wBAE3B,uBAAuB;0BACrB,wBAAwB;wBAEvC,iCAEN,QACD;;;;;;;;;;;4BAawB,gBAAgB;;;;;;2BAOjC,8CAGN,QAAQ,cAAc;;kCAEO;;;;;;wEAMsC;;;;;;;;;;6EAUK;2BAClD,iCAA+B,QAAQ,cAAc;;;;;;;;;;;;UAa/D,mBAAA;;;;;;;;;;;;;;;sBAgBN;;MAGN,QACD;;;;;;;;;;;;;;;;;;;;;;;;4CAyBwC;;;;;;;;qBAQvB,6CAA6C;;;;;;;yBAOzC,wBAAwB,QAC7C;;;;;;;;UAUa,kBAAA;;;;;;UAOA,yBAAA;;;;;;;;;;;;;;;;;;;;UAqBA,qBAAA;;kBAEC,YAAU;;cAEd,uBAAqB,qBAAqB,QAAQ,cAAc;;gBAGnE,sCAEA,4BACN,QAAQ,cAAc,UAAU;;oBAEjB,QAAQ;;;;;;iCAMK,gCAAgC;;;;;4DAKL;;;;;;eAM7C,iBAAe;;;;;;;;UASb,wBAAA,SAAiC;;;;;;iCAMjB,gCAAgC;;;;;;;;;iBAUtD;;;MAGN,QAAQ,cAAc,UAAU;;;;;;;;8BAQP;;;UAIb,iBAAA;;;;;;oBAMG;;;;;;;;UASH,mBAAA,SAA4B;mBAC1B;;;;UAKF,iBAAA;;;;;;;;;;UAWA,sBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA8BA,mBAAA;;sBAEK,uBAAqB,oBAAoB;;yDAEN,aAAa;;sBAG3D;;;MAEN,QAAQ,cAAc;;;;;;;;qCAShB,yCAEN,QAAQ;;mBAEM,6BAA2B,QAAQ;;0BAE5B,6BAA2B;;uBAG1C,kEAIN;;uBAEkB,8CAA4C;;oBAGxD;;MAEN,QAAQ,cAAc;;sBAGhB,6BACM,8BACN,yBACN,QAAQ,cAAc;;;;;;;2BAQhB,6BACM,8BACN,yBACN,QAAQ;mBAA+B;;;;;;;;6BAOjC,+CAEA,yBACN,QAAQ,cAAc;;;;;;;;;;;;;;UAeV,kBAAA,SACP,KAAK;oBACK;qBACC;qBACA,yBAAyB,QAAQ;uBAC/B;;;;;;;;uBAQA;;;;;;;;0BAQG;;;;;;;;sBAQJ;;;;;;;;mBAQH"}
|
|
@@ -6,12 +6,12 @@ import { EmbedderProvider } from "@graphorin/core";
|
|
|
6
6
|
/**
|
|
7
7
|
* Coexistence policy for embedder swaps.
|
|
8
8
|
*
|
|
9
|
-
* - `'lock-on-first'` (default)
|
|
9
|
+
* - `'lock-on-first'` (default) - refuses to register a second active
|
|
10
10
|
* embedder; surfaces an actionable error pointing at the planned
|
|
11
11
|
* migration runner.
|
|
12
|
-
* - `'multi-active'`
|
|
12
|
+
* - `'multi-active'` - keeps both embedders alive (read union, write
|
|
13
13
|
* to active); used while a long migration is in flight.
|
|
14
|
-
* - `'auto-migrate'`
|
|
14
|
+
* - `'auto-migrate'` - re-embeds existing rows in resumable batches
|
|
15
15
|
* until the source embedder has zero rows, then retires it.
|
|
16
16
|
*
|
|
17
17
|
* @stable
|
|
@@ -23,7 +23,7 @@ type EmbedderMigrationStrategy = 'lock-on-first' | 'multi-active' | 'auto-migrat
|
|
|
23
23
|
* @stable
|
|
24
24
|
*/
|
|
25
25
|
interface MigrationProgress {
|
|
26
|
-
/** `'fact'`, `'episode'`, or `'message'`
|
|
26
|
+
/** `'fact'`, `'episode'`, or `'message'` - which entity is being migrated. */
|
|
27
27
|
readonly kind: 'fact' | 'episode' | 'message';
|
|
28
28
|
/** Number of records processed so far. */
|
|
29
29
|
readonly processed: number;
|
|
@@ -35,7 +35,7 @@ interface MigrationProgress {
|
|
|
35
35
|
readonly target: string;
|
|
36
36
|
/**
|
|
37
37
|
* Identifier for this migration run. MST-12: this is an in-memory id for
|
|
38
|
-
* the current run
|
|
38
|
+
* the current run - there is no persisted `migration_state` cursor today, so
|
|
39
39
|
* a migration does not resume across processes.
|
|
40
40
|
*/
|
|
41
41
|
readonly migrationId: string;
|
|
@@ -66,12 +66,12 @@ interface MigrateEmbedderOptions {
|
|
|
66
66
|
readonly maxRecordsPerKind?: number;
|
|
67
67
|
/**
|
|
68
68
|
* Hook that returns the next batch of rows to re-embed for a given kind.
|
|
69
|
-
* MST-12: this is **caller-supplied**
|
|
69
|
+
* MST-12: this is **caller-supplied** - there is no store-side helper that
|
|
70
70
|
* auto-wires it today, and `auto-migrate` throws without it. Pass a paging
|
|
71
71
|
* function over your source rows to drive the migration.
|
|
72
72
|
*/
|
|
73
73
|
readonly nextBatch?: NextBatchHook;
|
|
74
|
-
/** Optional abort signal
|
|
74
|
+
/** Optional abort signal - aborting yields one final progress event. */
|
|
75
75
|
readonly signal?: AbortSignal;
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedder-migration.js","names":["cursor: string | null"],"sources":["../../src/migration/embedder-migration.ts"],"sourcesContent":["import type { EmbedderProvider } from '@graphorin/core';\nimport {\n EmbedderMigrationAbortedError,\n EmbedderMigrationLockedError,\n EmbedderMigrationStateError,\n} from '../errors/index.js';\nimport { bindEmbedder } from '../internal/embedder-binding.js';\nimport type { EmbeddingMetaRegistryLike } from '../internal/storage-adapter.js';\n\n/**\n * Coexistence policy for embedder swaps.\n *\n * - `'lock-on-first'` (default)
|
|
1
|
+
{"version":3,"file":"embedder-migration.js","names":["cursor: string | null"],"sources":["../../src/migration/embedder-migration.ts"],"sourcesContent":["import type { EmbedderProvider } from '@graphorin/core';\nimport {\n EmbedderMigrationAbortedError,\n EmbedderMigrationLockedError,\n EmbedderMigrationStateError,\n} from '../errors/index.js';\nimport { bindEmbedder } from '../internal/embedder-binding.js';\nimport type { EmbeddingMetaRegistryLike } from '../internal/storage-adapter.js';\n\n/**\n * Coexistence policy for embedder swaps.\n *\n * - `'lock-on-first'` (default) - refuses to register a second active\n * embedder; surfaces an actionable error pointing at the planned\n * migration runner.\n * - `'multi-active'` - keeps both embedders alive (read union, write\n * to active); used while a long migration is in flight.\n * - `'auto-migrate'` - re-embeds existing rows in resumable batches\n * until the source embedder has zero rows, then retires it.\n *\n * @stable\n */\nexport type EmbedderMigrationStrategy = 'lock-on-first' | 'multi-active' | 'auto-migrate';\n\n/**\n * Per-iteration progress snapshot yielded by {@link migrateEmbedder}.\n *\n * @stable\n */\nexport interface MigrationProgress {\n /** `'fact'`, `'episode'`, or `'message'` - which entity is being migrated. */\n readonly kind: 'fact' | 'episode' | 'message';\n /** Number of records processed so far. */\n readonly processed: number;\n /** Total records expected for this entity (when known). */\n readonly total: number;\n /** Identifier of the source embedder (`'<adapter>:<model>@<dim>'`). */\n readonly source: string;\n /** Identifier of the target embedder. */\n readonly target: string;\n /**\n * Identifier for this migration run. MST-12: this is an in-memory id for\n * the current run - there is no persisted `migration_state` cursor today, so\n * a migration does not resume across processes.\n */\n readonly migrationId: string;\n /** Phase discriminator. */\n readonly phase: 'planning' | 'running' | 'paused' | 'committed' | 'aborted';\n}\n\n/**\n * Options accepted by {@link migrateEmbedder}.\n *\n * @stable\n */\nexport interface MigrateEmbedderOptions {\n /** Source embedder (currently active). */\n readonly source: EmbedderProvider;\n /** Target embedder (becomes active when migration commits). */\n readonly target: EmbedderProvider;\n /** Storage layer's embedder registry. */\n readonly embeddings: EmbeddingMetaRegistryLike;\n /** Strategy applied per `embedding_meta` row. Default `'lock-on-first'`. */\n readonly strategy?: EmbedderMigrationStrategy;\n /**\n * Threshold for `auto-migrate`. The runner streams source rows in\n * batches of `batchSize` (default `512`) and yields progress after\n * each batch.\n */\n readonly batchSize?: number;\n /** Optional cap on the number of rows to migrate per kind. */\n readonly maxRecordsPerKind?: number;\n /**\n * Hook that returns the next batch of rows to re-embed for a given kind.\n * MST-12: this is **caller-supplied** - there is no store-side helper that\n * auto-wires it today, and `auto-migrate` throws without it. Pass a paging\n * function over your source rows to drive the migration.\n */\n readonly nextBatch?: NextBatchHook;\n /** Optional abort signal - aborting yields one final progress event. */\n readonly signal?: AbortSignal;\n}\n\n/**\n * Per-batch loader. Returns up to `batchSize` rows for the supplied\n * `kind` whose `embedder_id` is the source embedder. Returning an\n * empty array signals end-of-stream.\n *\n * @stable\n */\nexport type NextBatchHook = (args: {\n readonly kind: 'fact' | 'episode' | 'message';\n readonly source: string;\n readonly target: string;\n readonly batchSize: number;\n readonly cursor: string | null;\n}) => Promise<{ readonly rows: ReadonlyArray<MigrationRow>; readonly nextCursor: string | null }>;\n\n/**\n * Single row exposed to the migration runner. The runner re-embeds\n * `text` with the target embedder; the storage adapter is responsible\n * for committing the new vector + updating `embedder_id`.\n *\n * @stable\n */\nexport interface MigrationRow {\n readonly id: string;\n readonly text: string;\n readonly write: (vector: Float32Array) => Promise<void>;\n}\n\n/**\n * Stream embedder migrations as `AsyncIterable<MigrationProgress>`.\n *\n * The function is the universal entry point for every migration\n * strategy:\n *\n * - `'lock-on-first'`: surfaces the locked error eagerly so the\n * operator can act before any work happens.\n * - `'multi-active'`: registers the target alongside the source and\n * yields a single `'committed'` progress event.\n * - `'auto-migrate'`: streams batches until the source is fully\n * drained, then retires the source row.\n *\n * @stable\n */\nexport async function* migrateEmbedder(\n options: MigrateEmbedderOptions,\n): AsyncGenerator<MigrationProgress, void, unknown> {\n const { source, target, embeddings } = options;\n const strategy = options.strategy ?? 'lock-on-first';\n const sourceId = source.id();\n const targetId = target.id();\n const migrationId = `migration_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`;\n\n if (sourceId === targetId) {\n throw new EmbedderMigrationStateError(\n `source and target embedders must differ; both resolved to '${sourceId}'.`,\n );\n }\n\n const sourceMeta = embeddings.get(sourceId);\n if (sourceMeta === null) {\n throw new EmbedderMigrationStateError(\n `source embedder '${sourceId}' is not registered. Run createMemory({ embedder: source }) first.`,\n );\n }\n\n if (strategy === 'lock-on-first') {\n throw new EmbedderMigrationLockedError(sourceId, targetId);\n }\n\n bindEmbedder(target, embeddings);\n\n if (strategy === 'multi-active') {\n yield {\n kind: 'fact',\n processed: 0,\n total: 0,\n source: sourceId,\n target: targetId,\n migrationId,\n phase: 'committed',\n };\n return;\n }\n\n // strategy === 'auto-migrate'\n if (options.nextBatch === undefined) {\n throw new EmbedderMigrationStateError(\n \"'auto-migrate' requires a `nextBatch` hook supplied by the storage adapter.\",\n );\n }\n\n const batchSize = options.batchSize ?? 512;\n const cap = options.maxRecordsPerKind ?? Number.POSITIVE_INFINITY;\n\n for (const kind of ['fact', 'episode', 'message'] as const) {\n let cursor: string | null = null;\n let processed = 0;\n while (processed < cap) {\n if (options.signal?.aborted === true) {\n yield {\n kind,\n processed,\n total: processed,\n source: sourceId,\n target: targetId,\n migrationId,\n phase: 'aborted',\n };\n throw new EmbedderMigrationAbortedError(migrationId);\n }\n const batch = await options.nextBatch({\n kind,\n source: sourceId,\n target: targetId,\n batchSize,\n cursor,\n });\n if (batch.rows.length === 0) break;\n const texts = batch.rows.map((r) => r.text);\n const vectors = await target.embed(texts, {\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n });\n for (let i = 0; i < batch.rows.length; i++) {\n const row = batch.rows[i];\n const vector = vectors[i];\n if (row === undefined || vector === undefined) continue;\n await row.write(vector);\n }\n processed += batch.rows.length;\n cursor = batch.nextCursor;\n yield {\n kind,\n processed,\n total: processed,\n source: sourceId,\n target: targetId,\n migrationId,\n phase: 'running',\n };\n if (cursor === null) break;\n }\n }\n\n embeddings.retire(sourceId);\n yield {\n kind: 'fact',\n processed: 0,\n total: 0,\n source: sourceId,\n target: targetId,\n migrationId,\n phase: 'committed',\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA8HA,gBAAuB,gBACrB,SACkD;CAClD,MAAM,EAAE,QAAQ,QAAQ,eAAe;CACvC,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,WAAW,OAAO,IAAI;CAC5B,MAAM,WAAW,OAAO,IAAI;CAC5B,MAAM,cAAc,aAAa,KAAK,KAAK,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE;AAElG,KAAI,aAAa,SACf,OAAM,IAAI,4BACR,8DAA8D,SAAS,IACxE;AAIH,KADmB,WAAW,IAAI,SAAS,KACxB,KACjB,OAAM,IAAI,4BACR,oBAAoB,SAAS,oEAC9B;AAGH,KAAI,aAAa,gBACf,OAAM,IAAI,6BAA6B,UAAU,SAAS;AAG5D,cAAa,QAAQ,WAAW;AAEhC,KAAI,aAAa,gBAAgB;AAC/B,QAAM;GACJ,MAAM;GACN,WAAW;GACX,OAAO;GACP,QAAQ;GACR,QAAQ;GACR;GACA,OAAO;GACR;AACD;;AAIF,KAAI,QAAQ,cAAc,OACxB,OAAM,IAAI,4BACR,8EACD;CAGH,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,MAAM,QAAQ,qBAAqB,OAAO;AAEhD,MAAK,MAAM,QAAQ;EAAC;EAAQ;EAAW;EAAU,EAAW;EAC1D,IAAIA,SAAwB;EAC5B,IAAI,YAAY;AAChB,SAAO,YAAY,KAAK;AACtB,OAAI,QAAQ,QAAQ,YAAY,MAAM;AACpC,UAAM;KACJ;KACA;KACA,OAAO;KACP,QAAQ;KACR,QAAQ;KACR;KACA,OAAO;KACR;AACD,UAAM,IAAI,8BAA8B,YAAY;;GAEtD,MAAM,QAAQ,MAAM,QAAQ,UAAU;IACpC;IACA,QAAQ;IACR,QAAQ;IACR;IACA;IACD,CAAC;AACF,OAAI,MAAM,KAAK,WAAW,EAAG;GAC7B,MAAM,QAAQ,MAAM,KAAK,KAAK,MAAM,EAAE,KAAK;GAC3C,MAAM,UAAU,MAAM,OAAO,MAAM,OAAO,EACxC,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE,EACnE,CAAC;AACF,QAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KAAK,QAAQ,KAAK;IAC1C,MAAM,MAAM,MAAM,KAAK;IACvB,MAAM,SAAS,QAAQ;AACvB,QAAI,QAAQ,UAAa,WAAW,OAAW;AAC/C,UAAM,IAAI,MAAM,OAAO;;AAEzB,gBAAa,MAAM,KAAK;AACxB,YAAS,MAAM;AACf,SAAM;IACJ;IACA;IACA,OAAO;IACP,QAAQ;IACR,QAAQ;IACR;IACA,OAAO;IACR;AACD,OAAI,WAAW,KAAM;;;AAIzB,YAAW,OAAO,SAAS;AAC3B,OAAM;EACJ,MAAM;EACN,WAAW;EACX,OAAO;EACP,QAAQ;EACR,QAAQ;EACR;EACA,OAAO;EACR"}
|
package/dist/package.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@graphorin/memory\",\n \"version\": \"0.6.1\",\n \"description\": \"Six-tier memory system for the Graphorin framework: createMemory() facade with working / session / episodic / semantic / procedural / shared sub-modules, eleven memory tools wired into @graphorin/tools, hybrid vector + FTS5 search composed through Reciprocal Rank Fusion (k=60 default) with a pluggable reranker hook, a multi-stage conflict resolution pipeline (exact dedup → embedding three-zone → heuristic regex → subject/predicate → defer-to-deep) with an English locale pack default + plug-in locales, an embedder migration runner with three coexistence policies (lock-on-first / multi-active / auto-migrate), per-record embedder_id enforcement, multi-agent attribution, append-only writes with soft-delete + supersede semantics, default-on bi-temporal storage, provenance + quarantine safety gate for synthesized memory, AISpan emission for every operation, and tier-aware memory-modification guard wiring.\",\n \"license\": \"MIT\",\n \"author\": \"Oleksiy Stepurenko\",\n \"homepage\": \"https://github.com/o-stepper/graphorin/tree/main/packages/memory\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/o-stepper/graphorin.git\",\n \"directory\": \"packages/memory\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/o-stepper/graphorin/issues\"\n },\n \"keywords\": [\n \"graphorin\",\n \"ai\",\n \"agents\",\n \"framework\",\n \"memory\",\n \"long-term-memory\",\n \"working-memory\",\n \"session-memory\",\n \"episodic-memory\",\n \"semantic-memory\",\n \"procedural-memory\",\n \"shared-memory\",\n \"rrf\",\n \"hybrid-search\",\n \"rerank\",\n \"conflict-resolution\",\n \"embedder-migration\",\n \"bi-temporal\",\n \"multi-agent\"\n ],\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=22.0.0\"\n },\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./facade\": {\n \"types\": \"./dist/facade.d.ts\",\n \"import\": \"./dist/facade.js\"\n },\n \"./tiers\": {\n \"types\": \"./dist/tiers/index.d.ts\",\n \"import\": \"./dist/tiers/index.js\"\n },\n \"./tools\": {\n \"types\": \"./dist/tools/index.d.ts\",\n \"import\": \"./dist/tools/index.js\"\n },\n \"./search\": {\n \"types\": \"./dist/search/index.d.ts\",\n \"import\": \"./dist/search/index.js\"\n },\n \"./conflict\": {\n \"types\": \"./dist/conflict/index.d.ts\",\n \"import\": \"./dist/conflict/index.js\"\n },\n \"./migration\": {\n \"types\": \"./dist/migration/index.d.ts\",\n \"import\": \"./dist/migration/index.js\"\n },\n \"./errors\": {\n \"types\": \"./dist/errors/index.d.ts\",\n \"import\": \"./dist/errors/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsdown\",\n \"typecheck\": \"tsc --noEmit && tsc -p tsconfig.tests.json\",\n \"test\": \"vitest run\",\n \"lint\": \"biome check .\",\n \"clean\": \"rimraf dist .turbo *.tsbuildinfo\"\n },\n \"dependencies\": {\n \"@graphorin/core\": \"workspace:*\",\n \"@graphorin/observability\": \"workspace:*\",\n \"@graphorin/security\": \"workspace:*\",\n \"@graphorin/tools\": \"workspace:*\"\n },\n \"peerDependencies\": {\n \"zod\": \"^3.23.0 || ^4.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"zod\": {\n \"optional\": false\n }\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"provenance\": true\n },\n \"devDependencies\": {\n \"@graphorin/store-sqlite\": \"workspace:*\",\n \"@graphorin/embedder-transformersjs\": \"workspace:*\",\n \"@graphorin/triggers\": \"workspace:*\",\n \"@types/better-sqlite3\": \"^7.6.13\",\n \"better-sqlite3\": \"^12.9.0\",\n \"fast-check\": \"^3.23.0\",\n \"zod\": \"^3.25.0\"\n }\n}\n"],"mappings":";cAEa"}
|
package/dist/search/explain.d.ts
CHANGED
|
@@ -22,8 +22,11 @@ interface RecalledMemoryExplanation {
|
|
|
22
22
|
/**
|
|
23
23
|
* Raw per-signal scores contributing to `score`, exactly as the
|
|
24
24
|
* pipeline recorded them on the hit: FTS (`bm25`), vector similarity
|
|
25
|
-
* (`vector`), the fused reciprocal-rank terms (`rrf`
|
|
26
|
-
* `rrf
|
|
25
|
+
* (`vector`), the fused reciprocal-rank terms (`rrf` plus one
|
|
26
|
+
* `rrf.<label>` entry per fused list keyed by the retriever kind,
|
|
27
|
+
* e.g. `rrf.fts` / `rrf.vector`, with `rrf.list_N` as the fallback
|
|
28
|
+
* when a list carries no label), and the decay multiplier (`decay`)
|
|
29
|
+
* when decay ran.
|
|
27
30
|
*/
|
|
28
31
|
readonly signals: Readonly<Record<string, number>>;
|
|
29
32
|
}
|
|
@@ -31,7 +34,7 @@ interface RecalledMemoryExplanation {
|
|
|
31
34
|
* Structured "why was this recalled?" explanation for one
|
|
32
35
|
* {@link SemanticMemory.search} call: the query, the reranker that
|
|
33
36
|
* fused the candidate lists, and the per-memory signal breakdown in
|
|
34
|
-
* final-rank order. Pure data
|
|
37
|
+
* final-rank order. Pure data - safe to attach to a span, log, or
|
|
35
38
|
* render. X-3.
|
|
36
39
|
*
|
|
37
40
|
* @stable
|
|
@@ -61,7 +64,7 @@ declare function explainRecall<TRecord extends MemoryRecord>(hits: ReadonlyArray
|
|
|
61
64
|
readonly rerankerId: string;
|
|
62
65
|
}): RecallExplanation;
|
|
63
66
|
/**
|
|
64
|
-
* Render a {@link RecallExplanation} as a compact ASCII block
|
|
67
|
+
* Render a {@link RecallExplanation} as a compact ASCII block - a
|
|
65
68
|
* header line plus one line per recalled memory with its signal
|
|
66
69
|
* breakdown. Pure (returns a string, no I/O); used by operator tooling
|
|
67
70
|
* and trace inspectors.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain.d.ts","names":[],"sources":["../../src/search/explain.ts"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"explain.d.ts","names":[],"sources":["../../src/search/explain.ts"],"sourcesContent":[],"mappings":";;;;AA2GA;;;;;;;;UAjFiB,yBAAA;;;;iBAIA;;;;;;;;;;;;;;oBAcG,SAAS;;;;;;;;;;;UAYZ,iBAAA;;;;;;;;oBAQG,cAAc;;;;;;;;;;;;iBAalB,8BAA8B,oBACtC,cAAc,UAAU;;;IAE7B;;;;;;;;;iBA2Ba,uBAAA,cAAqC"}
|
package/dist/search/explain.js
CHANGED
|
@@ -25,7 +25,7 @@ function explainRecall(hits, opts) {
|
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Render a {@link RecallExplanation} as a compact ASCII block
|
|
28
|
+
* Render a {@link RecallExplanation} as a compact ASCII block - a
|
|
29
29
|
* header line plus one line per recalled memory with its signal
|
|
30
30
|
* breakdown. Pure (returns a string, no I/O); used by operator tooling
|
|
31
31
|
* and trace inspectors.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain.js","names":[],"sources":["../../src/search/explain.ts"],"sourcesContent":["/**\n * Recall explainability for `@graphorin/memory`
|
|
1
|
+
{"version":3,"file":"explain.js","names":[],"sources":["../../src/search/explain.ts"],"sourcesContent":["/**\n * Recall explainability for `@graphorin/memory` - \"why was this\n * recalled?\" (X-3). Turns the per-signal scores the hybrid pipeline\n * already records on each {@link MemoryHit} (FTS `bm25`, vector\n * similarity, the fused reciprocal-rank term, the decay multiplier,\n * future graph-hop terms) into a structured, renderable explanation.\n *\n * Pure data: the builder re-uses whatever {@link MemoryHit.signals} the\n * pipeline left behind rather than re-deriving them, so the explanation\n * always matches the ranking that actually happened. The renderer\n * returns a string and performs no I/O, so the explanation can be\n * attached to a span, logged, or surfaced by operator tooling.\n *\n * @packageDocumentation\n */\n\nimport type { MemoryHit, MemoryKind, MemoryRecord } from '@graphorin/core';\n\n/**\n * Per-memory contribution breakdown for one recalled record: the\n * decomposed signals the hybrid pipeline summed into the final score,\n * plus the record's final rank. Surfaces *why* a single memory was\n * recalled and how it ranked relative to its siblings.\n *\n * @stable\n */\nexport interface RecalledMemoryExplanation {\n /** Record id (fact / episode / insight / …). */\n readonly id: string;\n /** Memory kind of the recalled record. */\n readonly kind: MemoryKind;\n /** 1-based position in the final fused + decayed ranking. */\n readonly rank: number;\n /** Final score after fusion and (optional) decay. */\n readonly score: number;\n /**\n * Raw per-signal scores contributing to `score`, exactly as the\n * pipeline recorded them on the hit: FTS (`bm25`), vector similarity\n * (`vector`), the fused reciprocal-rank terms (`rrf` plus one\n * `rrf.<label>` entry per fused list keyed by the retriever kind,\n * e.g. `rrf.fts` / `rrf.vector`, with `rrf.list_N` as the fallback\n * when a list carries no label), and the decay multiplier (`decay`)\n * when decay ran.\n */\n readonly signals: Readonly<Record<string, number>>;\n}\n\n/**\n * Structured \"why was this recalled?\" explanation for one\n * {@link SemanticMemory.search} call: the query, the reranker that\n * fused the candidate lists, and the per-memory signal breakdown in\n * final-rank order. Pure data - safe to attach to a span, log, or\n * render. X-3.\n *\n * @stable\n */\nexport interface RecallExplanation {\n /** The query the recall ran for. */\n readonly query: string;\n /** Stable id of the reranker that fused the candidate lists. */\n readonly rerankerId: string;\n /** Number of recalled memories explained. */\n readonly count: number;\n /** Per-memory breakdown, in final-rank order (rank 1 first). */\n readonly results: ReadonlyArray<RecalledMemoryExplanation>;\n}\n\n/**\n * Build a {@link RecallExplanation} from a ranked hit list. Pure and\n * deterministic: it surfaces whatever per-signal scores the hybrid\n * pipeline left on each {@link MemoryHit.signals} (FTS, vector, RRF,\n * decay, future graph-hop terms) without re-deriving them, so the\n * explanation always matches what actually drove the ranking. Hits are\n * assumed to be in final-rank order (as returned by `search`).\n *\n * @stable\n */\nexport function explainRecall<TRecord extends MemoryRecord>(\n hits: ReadonlyArray<MemoryHit<TRecord>>,\n opts: { readonly query: string; readonly rerankerId: string },\n): RecallExplanation {\n const results = hits.map(\n (hit, idx): RecalledMemoryExplanation =>\n Object.freeze({\n id: hit.record.id,\n kind: hit.record.kind,\n rank: idx + 1,\n score: hit.score,\n signals: Object.freeze({ ...(hit.signals ?? {}) }),\n }),\n );\n return Object.freeze({\n query: opts.query,\n rerankerId: opts.rerankerId,\n count: results.length,\n results: Object.freeze(results),\n });\n}\n\n/**\n * Render a {@link RecallExplanation} as a compact ASCII block - a\n * header line plus one line per recalled memory with its signal\n * breakdown. Pure (returns a string, no I/O); used by operator tooling\n * and trace inspectors.\n *\n * @stable\n */\nexport function formatRecallExplanation(explanation: RecallExplanation): string {\n const header = `recall ${JSON.stringify(explanation.query)} via ${explanation.rerankerId} -> ${explanation.count} result(s)`;\n if (explanation.results.length === 0) return header;\n const lines = explanation.results.map((r) => {\n const signals = Object.entries(r.signals)\n .map(([key, value]) => `${key}=${formatScore(value)}`)\n .join(' ');\n const suffix = signals === '' ? '' : ` (${signals})`;\n return ` #${r.rank} ${r.id} [${r.kind}] score=${formatScore(r.score)}${suffix}`;\n });\n return [header, ...lines].join('\\n');\n}\n\nfunction formatScore(value: number): string {\n return Number.isFinite(value) ? value.toFixed(4) : String(value);\n}\n"],"mappings":";;;;;;;;;;;AA6EA,SAAgB,cACd,MACA,MACmB;CACnB,MAAM,UAAU,KAAK,KAClB,KAAK,QACJ,OAAO,OAAO;EACZ,IAAI,IAAI,OAAO;EACf,MAAM,IAAI,OAAO;EACjB,MAAM,MAAM;EACZ,OAAO,IAAI;EACX,SAAS,OAAO,OAAO,EAAE,GAAI,IAAI,WAAW,EAAE,EAAG,CAAC;EACnD,CAAC,CACL;AACD,QAAO,OAAO,OAAO;EACnB,OAAO,KAAK;EACZ,YAAY,KAAK;EACjB,OAAO,QAAQ;EACf,SAAS,OAAO,OAAO,QAAQ;EAChC,CAAC;;;;;;;;;;AAWJ,SAAgB,wBAAwB,aAAwC;CAC9E,MAAM,SAAS,UAAU,KAAK,UAAU,YAAY,MAAM,CAAC,OAAO,YAAY,WAAW,MAAM,YAAY,MAAM;AACjH,KAAI,YAAY,QAAQ,WAAW,EAAG,QAAO;AAQ7C,QAAO,CAAC,QAAQ,GAPF,YAAY,QAAQ,KAAK,MAAM;EAC3C,MAAM,UAAU,OAAO,QAAQ,EAAE,QAAQ,CACtC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,YAAY,MAAM,GAAG,CACrD,KAAK,IAAI;EACZ,MAAM,SAAS,YAAY,KAAK,KAAK,KAAK,QAAQ;AAClD,SAAO,MAAM,EAAE,KAAK,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,UAAU,YAAY,EAAE,MAAM,GAAG;GACxE,CACuB,CAAC,KAAK,KAAK;;AAGtC,SAAS,YAAY,OAAuB;AAC1C,QAAO,OAAO,SAAS,MAAM,GAAG,MAAM,QAAQ,EAAE,GAAG,OAAO,MAAM"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { MemoryHit, MemoryRecord } from "@graphorin/core";
|
|
2
|
+
|
|
3
|
+
//#region src/search/fit-weights.d.ts
|
|
4
|
+
|
|
5
|
+
/** One labelled query: per-kind candidate lists + the relevant ids. */
|
|
6
|
+
interface FitFusionCase<TRecord extends MemoryRecord = MemoryRecord> {
|
|
7
|
+
/** FTS candidate list, best-first (as the store returns it). */
|
|
8
|
+
readonly fts: ReadonlyArray<MemoryHit<TRecord>>;
|
|
9
|
+
/** Vector candidate list, best-first. */
|
|
10
|
+
readonly vector: ReadonlyArray<MemoryHit<TRecord>>;
|
|
11
|
+
/** Ids judged relevant for this query (binary gain). */
|
|
12
|
+
readonly relevantIds: ReadonlyArray<string>;
|
|
13
|
+
}
|
|
14
|
+
/** Options for {@link fitFusionWeights}. */
|
|
15
|
+
interface FitFusionOptions {
|
|
16
|
+
/** Candidate weight values per axis. Default `[0.25, 0.5, 1, 2, 4]`. */
|
|
17
|
+
readonly grid?: ReadonlyArray<number>;
|
|
18
|
+
/** nDCG cutoff. Default `10`. */
|
|
19
|
+
readonly k?: number;
|
|
20
|
+
/** RRF constant forwarded to the fuse. Default `60`. */
|
|
21
|
+
readonly rrfK?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Result of a fit: the winning weights + its score and the RRF baseline. */
|
|
24
|
+
interface FitFusionResult {
|
|
25
|
+
readonly weights: {
|
|
26
|
+
readonly fts: number;
|
|
27
|
+
readonly vector: number;
|
|
28
|
+
};
|
|
29
|
+
/** Mean nDCG@k of the winning weights across the cases. */
|
|
30
|
+
readonly score: number;
|
|
31
|
+
/** Mean nDCG@k of unit weights (plain RRF) - compare before adopting. */
|
|
32
|
+
readonly baseline: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Binary-gain nDCG@k over a ranked id list.
|
|
36
|
+
*
|
|
37
|
+
* @stable
|
|
38
|
+
*/
|
|
39
|
+
declare function ndcgAtK(rankedIds: ReadonlyArray<string>, relevant: ReadonlySet<string>, k: number): number;
|
|
40
|
+
/**
|
|
41
|
+
* Grid-search fusion weights against labelled cases (C5).
|
|
42
|
+
*
|
|
43
|
+
* @stable
|
|
44
|
+
*/
|
|
45
|
+
declare function fitFusionWeights<TRecord extends MemoryRecord = MemoryRecord>(cases: ReadonlyArray<FitFusionCase<TRecord>>, options?: FitFusionOptions): FitFusionResult;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { FitFusionCase, FitFusionOptions, FitFusionResult, fitFusionWeights, ndcgAtK };
|
|
48
|
+
//# sourceMappingURL=fit-weights.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fit-weights.d.ts","names":[],"sources":["../../src/search/fit-weights.ts"],"sourcesContent":[],"mappings":";;;;AA4EA;AAAiD,UAvDhC,aAuDgC,CAAA,gBAvDF,YAuDE,GAvDa,YAuDb,CAAA,CAAA;EAAe;EAC3B,SAAA,GAAA,EAtDrB,aAsDqB,CAtDP,SAsDO,CAtDG,OAsDH,CAAA,CAAA;EAAd;EAAd,SAAA,MAAA,EApDU,aAoDV,CApDwB,SAoDxB,CApDkC,OAoDlC,CAAA,CAAA;EACE;EACR,SAAA,WAAA,EApDqB,aAoDrB,CAAA,MAAA,CAAA;;;UAhDc,gBAAA;;kBAEC;;;;;;;UAQD,eAAA;;;;;;;;;;;;;;;iBAaD,OAAA,YACH,iCACD;;;;;;iBAoBI,iCAAiC,eAAe,qBACvD,cAAc,cAAc,qBAC1B,mBACR"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { fuseWeighted } from "./rrf.js";
|
|
2
|
+
|
|
3
|
+
//#region src/search/fit-weights.ts
|
|
4
|
+
/**
|
|
5
|
+
* Binary-gain nDCG@k over a ranked id list.
|
|
6
|
+
*
|
|
7
|
+
* @stable
|
|
8
|
+
*/
|
|
9
|
+
function ndcgAtK(rankedIds, relevant, k) {
|
|
10
|
+
const cutoff = Math.min(k, rankedIds.length);
|
|
11
|
+
let dcg = 0;
|
|
12
|
+
for (let i = 0; i < cutoff; i++) {
|
|
13
|
+
const id = rankedIds[i];
|
|
14
|
+
if (id !== void 0 && relevant.has(id)) dcg += 1 / Math.log2(i + 2);
|
|
15
|
+
}
|
|
16
|
+
const idealHits = Math.min(relevant.size, k);
|
|
17
|
+
let idcg = 0;
|
|
18
|
+
for (let i = 0; i < idealHits; i++) idcg += 1 / Math.log2(i + 2);
|
|
19
|
+
return idcg === 0 ? 0 : dcg / idcg;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Grid-search fusion weights against labelled cases (C5).
|
|
23
|
+
*
|
|
24
|
+
* @stable
|
|
25
|
+
*/
|
|
26
|
+
function fitFusionWeights(cases, options = {}) {
|
|
27
|
+
if (cases.length === 0) throw new TypeError("[graphorin/memory] fitFusionWeights: at least one labelled case required");
|
|
28
|
+
const grid = options.grid ?? [
|
|
29
|
+
.25,
|
|
30
|
+
.5,
|
|
31
|
+
1,
|
|
32
|
+
2,
|
|
33
|
+
4
|
|
34
|
+
];
|
|
35
|
+
const k = options.k ?? 10;
|
|
36
|
+
const rrfK = options.rrfK ?? 60;
|
|
37
|
+
const meanNdcg = (wFts, wVector) => {
|
|
38
|
+
let total = 0;
|
|
39
|
+
for (const c of cases) {
|
|
40
|
+
const rankedIds = fuseWeighted([c.fts, c.vector], [wFts, wVector], rrfK).map((h) => h.record.id);
|
|
41
|
+
total += ndcgAtK(rankedIds, new Set(c.relevantIds), k);
|
|
42
|
+
}
|
|
43
|
+
return total / cases.length;
|
|
44
|
+
};
|
|
45
|
+
const baseline = meanNdcg(1, 1);
|
|
46
|
+
let best = {
|
|
47
|
+
weights: {
|
|
48
|
+
fts: 1,
|
|
49
|
+
vector: 1
|
|
50
|
+
},
|
|
51
|
+
score: baseline,
|
|
52
|
+
baseline
|
|
53
|
+
};
|
|
54
|
+
for (const wFts of grid) for (const wVector of grid) {
|
|
55
|
+
const score = meanNdcg(wFts, wVector);
|
|
56
|
+
if (score > best.score + 1e-12) best = {
|
|
57
|
+
weights: {
|
|
58
|
+
fts: wFts,
|
|
59
|
+
vector: wVector
|
|
60
|
+
},
|
|
61
|
+
score,
|
|
62
|
+
baseline
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return best;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//#endregion
|
|
69
|
+
export { fitFusionWeights, ndcgAtK };
|
|
70
|
+
//# sourceMappingURL=fit-weights.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fit-weights.js","names":["best: FitFusionResult"],"sources":["../../src/search/fit-weights.ts"],"sourcesContent":["/**\n * C5: offline fusion-weight fitting. Tuned convex/weighted fusion beats\n * RRF with a handful of labelled queries (Bruch et al., TOIS 2023) - this\n * module turns that into a small, pure routine: grid-search\n * {@link FusionWeights} over labelled cases and return the setting that\n * maximizes mean nDCG@k, together with the plain-RRF baseline so the\n * caller can see whether tuning actually paid.\n *\n * Pure and I/O-free: the caller supplies per-kind candidate lists (run\n * your FTS and vector retrievers once per query, offline) plus the ids\n * judged relevant. Feed the winning weights to\n * `search(..., { fusion: { strategy: 'weighted', weights } })` or a\n * process-default `WeightedRRFReranker`.\n *\n * @packageDocumentation\n */\n\nimport type { MemoryHit, MemoryRecord } from '@graphorin/core';\nimport { fuseWeighted } from './rrf.js';\n\n/** One labelled query: per-kind candidate lists + the relevant ids. */\nexport interface FitFusionCase<TRecord extends MemoryRecord = MemoryRecord> {\n /** FTS candidate list, best-first (as the store returns it). */\n readonly fts: ReadonlyArray<MemoryHit<TRecord>>;\n /** Vector candidate list, best-first. */\n readonly vector: ReadonlyArray<MemoryHit<TRecord>>;\n /** Ids judged relevant for this query (binary gain). */\n readonly relevantIds: ReadonlyArray<string>;\n}\n\n/** Options for {@link fitFusionWeights}. */\nexport interface FitFusionOptions {\n /** Candidate weight values per axis. Default `[0.25, 0.5, 1, 2, 4]`. */\n readonly grid?: ReadonlyArray<number>;\n /** nDCG cutoff. Default `10`. */\n readonly k?: number;\n /** RRF constant forwarded to the fuse. Default `60`. */\n readonly rrfK?: number;\n}\n\n/** Result of a fit: the winning weights + its score and the RRF baseline. */\nexport interface FitFusionResult {\n readonly weights: { readonly fts: number; readonly vector: number };\n /** Mean nDCG@k of the winning weights across the cases. */\n readonly score: number;\n /** Mean nDCG@k of unit weights (plain RRF) - compare before adopting. */\n readonly baseline: number;\n}\n\n/**\n * Binary-gain nDCG@k over a ranked id list.\n *\n * @stable\n */\nexport function ndcgAtK(\n rankedIds: ReadonlyArray<string>,\n relevant: ReadonlySet<string>,\n k: number,\n): number {\n const cutoff = Math.min(k, rankedIds.length);\n let dcg = 0;\n for (let i = 0; i < cutoff; i++) {\n const id = rankedIds[i];\n if (id !== undefined && relevant.has(id)) dcg += 1 / Math.log2(i + 2);\n }\n const idealHits = Math.min(relevant.size, k);\n let idcg = 0;\n for (let i = 0; i < idealHits; i++) idcg += 1 / Math.log2(i + 2);\n return idcg === 0 ? 0 : dcg / idcg;\n}\n\n/**\n * Grid-search fusion weights against labelled cases (C5).\n *\n * @stable\n */\nexport function fitFusionWeights<TRecord extends MemoryRecord = MemoryRecord>(\n cases: ReadonlyArray<FitFusionCase<TRecord>>,\n options: FitFusionOptions = {},\n): FitFusionResult {\n if (cases.length === 0) {\n throw new TypeError('[graphorin/memory] fitFusionWeights: at least one labelled case required');\n }\n const grid = options.grid ?? [0.25, 0.5, 1, 2, 4];\n const k = options.k ?? 10;\n const rrfK = options.rrfK ?? 60;\n\n const meanNdcg = (wFts: number, wVector: number): number => {\n let total = 0;\n for (const c of cases) {\n const fused = fuseWeighted([c.fts, c.vector], [wFts, wVector], rrfK);\n const rankedIds = fused.map((h) => h.record.id);\n total += ndcgAtK(rankedIds, new Set(c.relevantIds), k);\n }\n return total / cases.length;\n };\n\n const baseline = meanNdcg(1, 1);\n let best: FitFusionResult = { weights: { fts: 1, vector: 1 }, score: baseline, baseline };\n for (const wFts of grid) {\n for (const wVector of grid) {\n const score = meanNdcg(wFts, wVector);\n if (score > best.score + 1e-12) {\n best = { weights: { fts: wFts, vector: wVector }, score, baseline };\n }\n }\n }\n return best;\n}\n"],"mappings":";;;;;;;;AAsDA,SAAgB,QACd,WACA,UACA,GACQ;CACR,MAAM,SAAS,KAAK,IAAI,GAAG,UAAU,OAAO;CAC5C,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;EAC/B,MAAM,KAAK,UAAU;AACrB,MAAI,OAAO,UAAa,SAAS,IAAI,GAAG,CAAE,QAAO,IAAI,KAAK,KAAK,IAAI,EAAE;;CAEvE,MAAM,YAAY,KAAK,IAAI,SAAS,MAAM,EAAE;CAC5C,IAAI,OAAO;AACX,MAAK,IAAI,IAAI,GAAG,IAAI,WAAW,IAAK,SAAQ,IAAI,KAAK,KAAK,IAAI,EAAE;AAChE,QAAO,SAAS,IAAI,IAAI,MAAM;;;;;;;AAQhC,SAAgB,iBACd,OACA,UAA4B,EAAE,EACb;AACjB,KAAI,MAAM,WAAW,EACnB,OAAM,IAAI,UAAU,2EAA2E;CAEjG,MAAM,OAAO,QAAQ,QAAQ;EAAC;EAAM;EAAK;EAAG;EAAG;EAAE;CACjD,MAAM,IAAI,QAAQ,KAAK;CACvB,MAAM,OAAO,QAAQ,QAAQ;CAE7B,MAAM,YAAY,MAAc,YAA4B;EAC1D,IAAI,QAAQ;AACZ,OAAK,MAAM,KAAK,OAAO;GAErB,MAAM,YADQ,aAAa,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,MAAM,QAAQ,EAAE,KAAK,CAC5C,KAAK,MAAM,EAAE,OAAO,GAAG;AAC/C,YAAS,QAAQ,WAAW,IAAI,IAAI,EAAE,YAAY,EAAE,EAAE;;AAExD,SAAO,QAAQ,MAAM;;CAGvB,MAAM,WAAW,SAAS,GAAG,EAAE;CAC/B,IAAIA,OAAwB;EAAE,SAAS;GAAE,KAAK;GAAG,QAAQ;GAAG;EAAE,OAAO;EAAU;EAAU;AACzF,MAAK,MAAM,QAAQ,KACjB,MAAK,MAAM,WAAW,MAAM;EAC1B,MAAM,QAAQ,SAAS,MAAM,QAAQ;AACrC,MAAI,QAAQ,KAAK,QAAQ,MACvB,QAAO;GAAE,SAAS;IAAE,KAAK;IAAM,QAAQ;IAAS;GAAE;GAAO;GAAU;;AAIzE,QAAO"}
|