@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
package/dist/facade.d.ts
CHANGED
|
@@ -3,10 +3,11 @@ import { ConflictPipeline, ConflictPipelineOptions } from "./conflict/types.js";
|
|
|
3
3
|
import "./conflict/index.js";
|
|
4
4
|
import { ContextualRetrievalMode } from "./internal/contextualize.js";
|
|
5
5
|
import { EpisodicMemory } from "./tiers/episodic-memory.js";
|
|
6
|
+
import { SalienceWeights } from "./consolidator/decay.js";
|
|
6
7
|
import { EntityResolutionConfig } from "./graph/entity-resolver.js";
|
|
7
8
|
import { ReRanker } from "./search/types.js";
|
|
8
9
|
import { SemanticMemory } from "./tiers/semantic-memory.js";
|
|
9
|
-
import {
|
|
10
|
+
import { BlockDefinition, WorkingMemory } from "./tiers/working-memory.js";
|
|
10
11
|
import { ConsolidatorCeilings, ConsolidatorPhase, ConsolidatorTier, ConsolidatorTriggerSpec, OnBudgetExceed, PhaseListener } from "./consolidator/types.js";
|
|
11
12
|
import { Consolidator } from "./consolidator/runtime.js";
|
|
12
13
|
import "./consolidator/index.js";
|
|
@@ -16,7 +17,6 @@ import { InsightMemory } from "./tiers/insight-memory.js";
|
|
|
16
17
|
import { ProceduralMemory } from "./tiers/procedural-memory.js";
|
|
17
18
|
import { SessionMemory } from "./tiers/session-memory.js";
|
|
18
19
|
import { SharedMemory } from "./tiers/shared-memory.js";
|
|
19
|
-
import { BlockDefinition, WorkingMemory } from "./tiers/working-memory.js";
|
|
20
20
|
import { ScopeResolver } from "./tools/types.js";
|
|
21
21
|
import "./tools/index.js";
|
|
22
22
|
import { EmbedderProvider, MemoryMetadata, Provider, SessionScope, Tool, Tracer } from "@graphorin/core";
|
|
@@ -33,9 +33,9 @@ interface CreateMemoryOptions {
|
|
|
33
33
|
readonly store: MemoryStoreAdapter;
|
|
34
34
|
/** Embedder registry. The default sqlite store exposes one as `sqlite.embeddings`. */
|
|
35
35
|
readonly embeddings: EmbeddingMetaRegistryLike;
|
|
36
|
-
/** Embedder provider (default: none
|
|
36
|
+
/** Embedder provider (default: none - vector search is disabled). */
|
|
37
37
|
readonly embedder?: EmbedderProvider;
|
|
38
|
-
/** Pre-declared working blocks (idempotent
|
|
38
|
+
/** Pre-declared working blocks (idempotent - re-defining is a no-op). */
|
|
39
39
|
readonly workingBlocks?: ReadonlyArray<BlockDefinition>;
|
|
40
40
|
/**
|
|
41
41
|
* Tracer used for every `memory.*` span. Defaults to the no-op
|
|
@@ -52,7 +52,7 @@ interface CreateMemoryOptions {
|
|
|
52
52
|
* structured fields) to the text that is embedded + FTS-indexed, so a
|
|
53
53
|
* terse fact stays findable; the canonical `text` is preserved. `'off'`
|
|
54
54
|
* indexes the bare text. The `'llm'` enrichment is **not** available on
|
|
55
|
-
* the hot path
|
|
55
|
+
* the hot path - it is a consolidator-only opt-in configured via
|
|
56
56
|
* `consolidator: { contextualRetrieval: 'llm' }`.
|
|
57
57
|
*/
|
|
58
58
|
readonly contextualRetrieval?: 'off' | 'late-chunk';
|
|
@@ -60,7 +60,7 @@ interface CreateMemoryOptions {
|
|
|
60
60
|
* Query transformation for retrieval (P2-3, opt-in). When supplied,
|
|
61
61
|
* `SemanticMemory.search(..., { multiQuery })` fans the query into
|
|
62
62
|
* reworded variants (multi-query / RAG-Fusion) and `{ hyde }` adds a
|
|
63
|
-
* hypothetical-answer embedding
|
|
63
|
+
* hypothetical-answer embedding - both via one cheap LLM call on the
|
|
64
64
|
* given provider, fused through the existing RRF reranker. Omitted (the
|
|
65
65
|
* default) ⇒ search stays **offline + single-shot** and the
|
|
66
66
|
* `multiQuery` / `hyde` search options become silent no-ops. Reserve it
|
|
@@ -101,7 +101,7 @@ interface CreateMemoryOptions {
|
|
|
101
101
|
* when memory is insufficient. Omitted (the default) ⇒ `searchIterative`
|
|
102
102
|
* stays a single difficulty-gated pass with **no provider call**, and
|
|
103
103
|
* `deep_recall` is **not** registered (the tool surface stays at the
|
|
104
|
-
* canonical eleven). Reserve it for hard multi-hop / temporal recall
|
|
104
|
+
* canonical eleven). Reserve it for hard multi-hop / temporal recall -
|
|
105
105
|
* it adds provider latency per pass.
|
|
106
106
|
*/
|
|
107
107
|
readonly iterativeRetrieval?: {
|
|
@@ -118,7 +118,7 @@ interface CreateMemoryOptions {
|
|
|
118
118
|
* trajectory and stores it **quarantined** + `provenance: 'induction'`.
|
|
119
119
|
* Omitted (the default) ⇒ `induce(...)` throws
|
|
120
120
|
* {@link ProcedureInductionNotConfiguredError} and the procedural tier
|
|
121
|
-
* stays pure offline CRUD
|
|
121
|
+
* stays pure offline CRUD - no provider call.
|
|
122
122
|
*/
|
|
123
123
|
readonly procedureInduction?: {
|
|
124
124
|
/** Provider used to abstract trajectory values into a procedure. */
|
|
@@ -128,7 +128,7 @@ interface CreateMemoryOptions {
|
|
|
128
128
|
};
|
|
129
129
|
/**
|
|
130
130
|
* Promotion-by-demonstrated-success for quarantined induced
|
|
131
|
-
* procedures (MCON-2 part 4). Fully offline
|
|
131
|
+
* procedures (MCON-2 part 4). Fully offline - orthogonal to
|
|
132
132
|
* `procedureInduction` (no provider needed). When configured,
|
|
133
133
|
* `procedural.recordOutcome(scope, id, true)` increments the rule's
|
|
134
134
|
* persistent success counter and promotes it into `activate()` once
|
|
@@ -140,9 +140,19 @@ interface CreateMemoryOptions {
|
|
|
140
140
|
/** Successful demonstrated reuses required before promotion (≥ 1). */
|
|
141
141
|
readonly afterSuccesses: number;
|
|
142
142
|
};
|
|
143
|
+
/**
|
|
144
|
+
* Register the gated `runbook_search` tool (D3) so the model can look
|
|
145
|
+
* up validated procedures by task description (content recall over
|
|
146
|
+
* procedural memory, returning whole runbooks). Fully offline - the
|
|
147
|
+
* default `@graphorin/store-sqlite` adapter serves it from the rules
|
|
148
|
+
* FTS index (migration 028); adapters without the index degrade to an
|
|
149
|
+
* in-memory lexical scan. Default `false` - the tool surface stays at
|
|
150
|
+
* the canonical eleven.
|
|
151
|
+
*/
|
|
152
|
+
readonly runbookSearch?: boolean;
|
|
143
153
|
/**
|
|
144
154
|
* Resolver that produces the live {@link SessionScope} for each
|
|
145
|
-
* memory-tool invocation. Defaults to a closure that throws
|
|
155
|
+
* memory-tool invocation. Defaults to a closure that throws - the
|
|
146
156
|
* agent runtime overrides it in Phase 12.
|
|
147
157
|
*/
|
|
148
158
|
readonly resolveScope?: ScopeResolver;
|
|
@@ -150,8 +160,8 @@ interface CreateMemoryOptions {
|
|
|
150
160
|
* Consolidator configuration. When omitted, empty, or
|
|
151
161
|
* `enabled: false`, the facade installs the Phase 10a no-op
|
|
152
162
|
* placeholder so consumers can still type their interactions without
|
|
153
|
-
* paying the runtime cost. ANY other setting
|
|
154
|
-
* knobs like `decayCapacity` or `contextualRetrieval`
|
|
163
|
+
* paying the runtime cost. ANY other setting - including offline
|
|
164
|
+
* knobs like `decayCapacity` or `contextualRetrieval` - implicitly
|
|
155
165
|
* enables the production runtime (MST-4); `enabled: false` together
|
|
156
166
|
* with other settings warns once and keeps the placeholder.
|
|
157
167
|
*/
|
|
@@ -162,6 +172,14 @@ interface CreateMemoryOptions {
|
|
|
162
172
|
readonly phases?: ReadonlyArray<ConsolidatorPhase>;
|
|
163
173
|
readonly ceilings?: Partial<ConsolidatorCeilings>;
|
|
164
174
|
readonly onExceed?: OnBudgetExceed;
|
|
175
|
+
/**
|
|
176
|
+
* USD pricer for phase LLM usage (memory-consolidation-02) - wire
|
|
177
|
+
* to `@graphorin/pricing` so `maxCostPerDay` can actually trip.
|
|
178
|
+
*/
|
|
179
|
+
readonly priceUsage?: (usage: {
|
|
180
|
+
promptTokens: number;
|
|
181
|
+
completionTokens: number;
|
|
182
|
+
}) => number;
|
|
165
183
|
/** Provider routed to the standard phase when set (MCON-7); falls back to `provider`. */
|
|
166
184
|
readonly cheapProvider?: Provider | null;
|
|
167
185
|
/** Provider routed to the deep + reflection passes when set (MCON-7). */
|
|
@@ -200,11 +218,22 @@ interface CreateMemoryOptions {
|
|
|
200
218
|
* and `'off'` defer to the write-path mode. Per-tier default.
|
|
201
219
|
*/
|
|
202
220
|
readonly contextualRetrieval?: ContextualRetrievalMode;
|
|
221
|
+
/**
|
|
222
|
+
* Maintain the learned-context digest block (D3): after each deep
|
|
223
|
+
* phase, one budgeted LLM call rewrites the reserved
|
|
224
|
+
* `learned_context` working block (previous digest + recent
|
|
225
|
+
* episodes / active insights / procedures), so the assembled system
|
|
226
|
+
* prompt carries a compact standing summary. Default `false` at
|
|
227
|
+
* every tier (Wave-D trial).
|
|
228
|
+
*/
|
|
229
|
+
readonly learnedContext?: boolean;
|
|
230
|
+
/** Character bound for the learned-context digest (D3). Default `1200`. */
|
|
231
|
+
readonly learnedContextMaxChars?: number;
|
|
203
232
|
readonly defaultScope?: SessionScope;
|
|
204
233
|
readonly provider?: Provider | null;
|
|
205
|
-
/** Override the wall clock
|
|
234
|
+
/** Override the wall clock - used by tests. */
|
|
206
235
|
readonly now?: () => number;
|
|
207
|
-
/** Stable id seed
|
|
236
|
+
/** Stable id seed - used by tests. */
|
|
208
237
|
readonly randomId?: () => string;
|
|
209
238
|
/** Subscribe to phase-finished events. */
|
|
210
239
|
readonly onPhaseFinished?: PhaseListener;
|
|
@@ -271,7 +300,7 @@ interface Memory {
|
|
|
271
300
|
* @stable
|
|
272
301
|
*/
|
|
273
302
|
declare function createMemory(options: CreateMemoryOptions): Memory;
|
|
274
|
-
/** @internal
|
|
303
|
+
/** @internal - test seam for the one-time disabled-config warning. */
|
|
275
304
|
declare function _resetConsolidatorConfigWarningForTesting(): void;
|
|
276
305
|
//#endregion
|
|
277
306
|
export { CreateMemoryOptions, Memory, _resetConsolidatorConfigWarningForTesting, createMemory };
|
package/dist/facade.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"facade.d.ts","names":[],"sources":["../src/facade.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAuEA;;;;;AAQ2B,UARV,mBAAA,CAQU;EAMP;EAEE,SAAA,KAAA,EAdJ,kBAcI;EAyBC;EAiBJ,SAAA,UAAA,EAtDI,yBAsDJ;EAIK;EAgBD,SAAA,QAAA,CAAA,EAxED,gBAwEC;EAgBA;
|
|
1
|
+
{"version":3,"file":"facade.d.ts","names":[],"sources":["../src/facade.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAuEA;;;;;AAQ2B,UARV,mBAAA,CAQU;EAMP;EAEE,SAAA,KAAA,EAdJ,kBAcI;EAyBC;EAiBJ,SAAA,UAAA,EAtDI,yBAsDJ;EAIK;EAgBD,SAAA,QAAA,CAAA,EAxED,gBAwEC;EAgBA;EAiCG,SAAA,aAAA,CAAA,EAvHC,aAuHD,CAvHe,eAuHf,CAAA;EAYY;;;;;EAGN,SAAA,MAAA,CAAA,EAhIZ,MAgIY;EAAR;EACA,SAAA,QAAA,CAAA,EA/HF,QA+HE;EAOK;;;;;;;;;;EAwEiB,SAAA,mBAAA,CAAA,EAAA,KAAA,GAAA,YAAA;EAQ7B;;;;;;;;;;;EAgBY,SAAA,cAAA,CAAA,EAAA;IAEH;IAEL,SAAA,QAAA,EAjNE,QAiNF;IASJ;IAAwB,SAAA,WAAA,CAAA,EAAA,MAAA;IAAyB;IAAR,SAAA,SAAA,CAAA,EAAA,MAAA;EAExC,CAAA;EAAuB;;;AASzC;AAwXA;;;;;;;mBA5kBmB;;;;wBAIK;;;;;;;;;;;;;;;;uBAgBD;;;;;;;;;;;;;;;;uBAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAiCG;;;;;;;;;;;;wBAYF,cAAc;oBAClB;sBACE,cAAc;wBACZ,QAAQ;wBACR;;;;;;;;;;6BAOK;;4BAED;;;4BAGA;;;;;;;+BAOG;;;;;;;;;;;;;;;;;;;;;;;;mCAwBI;;;;;;;;;;;;4BAYP;wBACJ;;;;;;+BAMO;;;;;;;;8BAQD;;;;;;;;;2BASH;;;;;;;UAQV,MAAA;oBACG;oBACA;qBACC;qBACA;uBACE;mBACJ;;;;;;qBAME;kBACH,cAAc;yBACP;;6BAEI;;0BAEH;;qBAEL;;;;;;;;;iBASJ,wBAAwB,iBAAiB,QAAQ;;kBAEhD,eAAe,QAAQ;;;;;;;;iBASzB,YAAA,UAAsB,sBAAsB;;iBAwX5C,yCAAA,CAAA"}
|
package/dist/facade.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createConflictPipeline } from "./conflict/pipeline.js";
|
|
2
2
|
import "./conflict/index.js";
|
|
3
3
|
import { createProviderWorkflowInducer } from "./consolidator/phases/induce.js";
|
|
4
|
+
import { WorkingMemory } from "./tiers/working-memory.js";
|
|
4
5
|
import { createConsolidator } from "./consolidator/runtime.js";
|
|
5
6
|
import { createConsolidatorPlaceholder } from "./consolidator/index.js";
|
|
6
7
|
import { enLocalePack } from "./context-engine/locale-packs/en.js";
|
|
@@ -21,7 +22,6 @@ import { ProceduralMemory } from "./tiers/procedural-memory.js";
|
|
|
21
22
|
import { SemanticMemory } from "./tiers/semantic-memory.js";
|
|
22
23
|
import { SessionMemory } from "./tiers/session-memory.js";
|
|
23
24
|
import { SharedMemory } from "./tiers/shared-memory.js";
|
|
24
|
-
import { WorkingMemory } from "./tiers/working-memory.js";
|
|
25
25
|
import { buildMemoryTools } from "./tools/index.js";
|
|
26
26
|
import { NOOP_TRACER } from "@graphorin/core";
|
|
27
27
|
|
|
@@ -36,7 +36,7 @@ function createMemory(options) {
|
|
|
36
36
|
const tracer = options.tracer ?? NOOP_TRACER;
|
|
37
37
|
const reranker = options.reranker ?? new RRFReranker();
|
|
38
38
|
const resolveScope = options.resolveScope ?? (() => {
|
|
39
|
-
throw new TypeError("[graphorin/memory] memory tool invoked without a scope resolver. Pass `resolveScope` to createMemory({...})
|
|
39
|
+
throw new TypeError("[graphorin/memory] memory tool invoked without a scope resolver. Pass `resolveScope` to createMemory({...}) - the agent runtime supplies one in Phase 12.");
|
|
40
40
|
});
|
|
41
41
|
let activeEmbedderId = null;
|
|
42
42
|
if (options.embedder !== void 0) activeEmbedderId = bindEmbedder(options.embedder, options.embeddings);
|
|
@@ -86,7 +86,8 @@ function createMemory(options) {
|
|
|
86
86
|
...queryTransformer !== null ? { queryTransformer } : {},
|
|
87
87
|
...entityResolver !== null ? { entityResolver } : {},
|
|
88
88
|
...grader !== null ? { grader } : {},
|
|
89
|
-
...options.iterativeRetrieval?.maxIterations !== void 0 ? { iterativeMaxIterations: options.iterativeRetrieval.maxIterations } : {}
|
|
89
|
+
...options.iterativeRetrieval?.maxIterations !== void 0 ? { iterativeMaxIterations: options.iterativeRetrieval.maxIterations } : {},
|
|
90
|
+
...options.consolidator?.salienceWeights !== void 0 ? { trustWeights: options.consolidator.salienceWeights } : {}
|
|
90
91
|
});
|
|
91
92
|
let consolidatorForSpend = null;
|
|
92
93
|
const inducer = options.procedureInduction !== void 0 ? createProviderWorkflowInducer(options.procedureInduction.provider, {
|
|
@@ -117,9 +118,12 @@ function createMemory(options) {
|
|
|
117
118
|
procedural,
|
|
118
119
|
shared,
|
|
119
120
|
resolveScope
|
|
120
|
-
}, {
|
|
121
|
+
}, {
|
|
122
|
+
includeDeepRecall: grader !== null,
|
|
123
|
+
includeRunbookSearch: options.runbookSearch === true
|
|
124
|
+
});
|
|
121
125
|
const consolidatorOpts = options.consolidator;
|
|
122
|
-
const consolidator = buildConsolidator(consolidatorOpts, options.store, semantic, episodic, tracer);
|
|
126
|
+
const consolidator = buildConsolidator(consolidatorOpts, options.store, semantic, episodic, working, tracer);
|
|
123
127
|
consolidatorForSpend = consolidator;
|
|
124
128
|
const contextEngineConfig = options.contextEngine ?? {};
|
|
125
129
|
const contextEngine = createContextEngine(contextEngineConfig);
|
|
@@ -196,7 +200,7 @@ function renderWorkingBlocksXml(blocks) {
|
|
|
196
200
|
function escapeXml(value) {
|
|
197
201
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
198
202
|
}
|
|
199
|
-
function buildConsolidator(opts, store, semantic, episodic, tracer) {
|
|
203
|
+
function buildConsolidator(opts, store, semantic, episodic, working, tracer) {
|
|
200
204
|
if (opts === void 0) return createConsolidatorPlaceholder();
|
|
201
205
|
if (!shouldEnableConsolidator(opts)) return createConsolidatorPlaceholder({
|
|
202
206
|
...opts.triggers !== void 0 ? { triggers: opts.triggers } : {},
|
|
@@ -206,6 +210,7 @@ function buildConsolidator(opts, store, semantic, episodic, tracer) {
|
|
|
206
210
|
store,
|
|
207
211
|
semantic,
|
|
208
212
|
episodic,
|
|
213
|
+
working,
|
|
209
214
|
tracer,
|
|
210
215
|
...opts.provider !== void 0 ? { provider: opts.provider } : {},
|
|
211
216
|
...opts.now !== void 0 ? { now: opts.now } : {},
|
|
@@ -215,6 +220,7 @@ function buildConsolidator(opts, store, semantic, episodic, tracer) {
|
|
|
215
220
|
...opts.phases !== void 0 ? { phases: opts.phases } : {},
|
|
216
221
|
...opts.ceilings !== void 0 ? { ceilings: opts.ceilings } : {},
|
|
217
222
|
...opts.onExceed !== void 0 ? { onExceed: opts.onExceed } : {},
|
|
223
|
+
...opts.priceUsage !== void 0 ? { priceUsage: opts.priceUsage } : {},
|
|
218
224
|
...opts.cheapProvider !== void 0 ? { cheapProvider: opts.cheapProvider } : {},
|
|
219
225
|
...opts.deepProvider !== void 0 ? { deepProvider: opts.deepProvider } : {},
|
|
220
226
|
...opts.cheapModel !== void 0 ? { cheapModel: opts.cheapModel } : {},
|
|
@@ -237,13 +243,15 @@ function buildConsolidator(opts, store, semantic, episodic, tracer) {
|
|
|
237
243
|
...opts.importanceThreshold !== void 0 ? { importanceThreshold: opts.importanceThreshold } : {},
|
|
238
244
|
...opts.reflectionMaxQuestions !== void 0 ? { reflectionMaxQuestions: opts.reflectionMaxQuestions } : {},
|
|
239
245
|
...opts.contextualRetrieval !== void 0 ? { contextualRetrieval: opts.contextualRetrieval } : {},
|
|
246
|
+
...opts.learnedContext !== void 0 ? { learnedContext: opts.learnedContext } : {},
|
|
247
|
+
...opts.learnedContextMaxChars !== void 0 ? { learnedContextMaxChars: opts.learnedContextMaxChars } : {},
|
|
240
248
|
...opts.defaultScope !== void 0 ? { defaultScope: opts.defaultScope } : {}
|
|
241
249
|
});
|
|
242
250
|
if (opts.onPhaseFinished !== void 0) consolidator.onPhaseFinished(opts.onPhaseFinished);
|
|
243
251
|
return consolidator;
|
|
244
252
|
}
|
|
245
253
|
let consolidatorConfigIgnoredWarned = false;
|
|
246
|
-
/** @internal
|
|
254
|
+
/** @internal - test seam for the one-time disabled-config warning. */
|
|
247
255
|
function _resetConsolidatorConfigWarningForTesting() {
|
|
248
256
|
consolidatorConfigIgnoredWarned = false;
|
|
249
257
|
}
|
|
@@ -252,7 +260,7 @@ function shouldEnableConsolidator(opts) {
|
|
|
252
260
|
if (opts.enabled === false) {
|
|
253
261
|
if (keys.length > 0 && !consolidatorConfigIgnoredWarned) {
|
|
254
262
|
consolidatorConfigIgnoredWarned = true;
|
|
255
|
-
process.stderr.write(`[graphorin/memory] consolidator config (${keys.join(", ")}) was supplied together with enabled: false
|
|
263
|
+
process.stderr.write(`[graphorin/memory] consolidator config (${keys.join(", ")}) was supplied together with enabled: false - the settings are ignored until the consolidator is enabled.\n`);
|
|
256
264
|
}
|
|
257
265
|
return false;
|
|
258
266
|
}
|
package/dist/facade.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"facade.js","names":["reranker: ReRanker","resolveScope: ScopeResolver","activeEmbedderId: string | null","consolidatorForSpend: Consolidator | null","consolidator: Consolidator","contextEngine: ContextEngine","out: { -readonly [K in keyof MemoryContextBlocks]: MemoryContextBlocks[K] }","blocksKept: ReadonlyArray<(typeof blocks)[number]>","rulesKept: ReadonlyArray<(typeof rules)[number]>","filterContext: Parameters<typeof partitionBySensitivity>[1]","partitionBySensitivity"],"sources":["../src/facade.ts"],"sourcesContent":["/**\n * `createMemory()` — the facade that wires every tier sub-module (the\n * seven-tier system) + the eleven (+1 gated) memory tools + the search\n * reranker + the context engine\n * stubs + the consolidator placeholder.\n *\n * @packageDocumentation\n */\n\nimport type {\n EmbedderProvider,\n MemoryMetadata,\n Provider,\n SessionScope,\n Tool,\n Tracer,\n} from '@graphorin/core';\nimport { NOOP_TRACER } from '@graphorin/core';\nimport {\n type ConflictPipeline,\n type ConflictPipelineOptions,\n createConflictPipeline,\n} from './conflict/index.js';\nimport {\n type Consolidator,\n type ConsolidatorCeilings,\n type ConsolidatorPhase,\n type ConsolidatorTier,\n type ConsolidatorTriggerSpec,\n createConsolidator,\n createConsolidatorPlaceholder,\n createProviderWorkflowInducer,\n type OnBudgetExceed,\n type PhaseListener,\n type SalienceWeights,\n} from './consolidator/index.js';\nimport { createContextEngine } from './context-engine/engine.js';\nimport type {\n CompileOptions,\n CompileScope,\n ContextEngine,\n ContextEngineConfig,\n MemoryContextBlocks,\n} from './context-engine/index.js';\nimport { enLocalePack } from './context-engine/locale-packs/index.js';\nimport { resolveLocalePack } from './context-engine/locale-packs/resolver.js';\nimport { gatherMemoryMetadata, renderMetadataBlock } from './context-engine/metadata.js';\nimport { partition as partitionBySensitivity } from './context-engine/privacy-filter.js';\nimport { composeLayer1 } from './context-engine/templates/composer.js';\nimport { type EntityResolutionConfig, EntityResolver } from './graph/entity-resolver.js';\nimport type { ContextualRetrievalMode } from './internal/contextualize.js';\nimport { bindEmbedder } from './internal/embedder-binding.js';\nimport type { EmbeddingMetaRegistryLike, MemoryStoreAdapter } from './internal/storage-adapter.js';\nimport { createProviderRetrievalGrader } from './search/iterative.js';\nimport { createProviderQueryTransformer } from './search/query-transform.js';\nimport { RRFReranker } from './search/rrf.js';\nimport type { ReRanker } from './search/types.js';\nimport { EpisodicMemory } from './tiers/episodic-memory.js';\nimport { InsightMemory } from './tiers/insight-memory.js';\nimport { ProceduralMemory } from './tiers/procedural-memory.js';\nimport { SemanticMemory } from './tiers/semantic-memory.js';\nimport { SessionMemory } from './tiers/session-memory.js';\nimport { SharedMemory } from './tiers/shared-memory.js';\nimport { type BlockDefinition, WorkingMemory } from './tiers/working-memory.js';\nimport { buildMemoryTools, type ScopeResolver } from './tools/index.js';\n\n/**\n * Options accepted by {@link createMemory}.\n *\n * @stable\n */\nexport interface CreateMemoryOptions {\n /** Storage adapter (default: `@graphorin/store-sqlite`'s `MemoryStore`). */\n readonly store: MemoryStoreAdapter;\n /** Embedder registry. The default sqlite store exposes one as `sqlite.embeddings`. */\n readonly embeddings: EmbeddingMetaRegistryLike;\n /** Embedder provider (default: none — vector search is disabled). */\n readonly embedder?: EmbedderProvider;\n /** Pre-declared working blocks (idempotent — re-defining is a no-op). */\n readonly workingBlocks?: ReadonlyArray<BlockDefinition>;\n /**\n * Tracer used for every `memory.*` span. Defaults to the no-op\n * tracer from `@graphorin/core` so unit tests do not need to wire\n * the observability stack.\n */\n readonly tracer?: Tracer;\n /** Override the reranker used by `SemanticMemory.search`. */\n readonly reranker?: ReRanker;\n /**\n * Contextual-retrieval mode for the write path (P1-3). `'late-chunk'`\n * (default) prepends a deterministic, offline situating context\n * (entities / timeframe / topics, derived from the fact's own\n * structured fields) to the text that is embedded + FTS-indexed, so a\n * terse fact stays findable; the canonical `text` is preserved. `'off'`\n * indexes the bare text. The `'llm'` enrichment is **not** available on\n * the hot path — it is a consolidator-only opt-in configured via\n * `consolidator: { contextualRetrieval: 'llm' }`.\n */\n readonly contextualRetrieval?: 'off' | 'late-chunk';\n /**\n * Query transformation for retrieval (P2-3, opt-in). When supplied,\n * `SemanticMemory.search(..., { multiQuery })` fans the query into\n * reworded variants (multi-query / RAG-Fusion) and `{ hyde }` adds a\n * hypothetical-answer embedding — both via one cheap LLM call on the\n * given provider, fused through the existing RRF reranker. Omitted (the\n * default) ⇒ search stays **offline + single-shot** and the\n * `multiQuery` / `hyde` search options become silent no-ops. Reserve it\n * for retrieval-heavy recall, not every search (it adds provider\n * latency).\n */\n readonly queryTransform?: {\n /** Cheap provider used to rewrite the query / write the HyDE passage. */\n readonly provider: Provider;\n /** Hard ceiling on reworded variants requested per call. Default 5. */\n readonly maxVariants?: number;\n /** Output-token ceiling per transform call. Default 256. */\n readonly maxTokens?: number;\n };\n /**\n * Relation-graph entity resolution (P2-1). When `entityResolution` is\n * `true` **and** the storage adapter exposes a `graph` surface (the\n * default `@graphorin/store-sqlite` does), `remember(...)` resolves a\n * fact's subject / object to canonical entities and links them, so\n * `search(..., { expandHops: 1 })` can traverse relationships. Omitted\n * (the default) ⇒ facts still carry s/p/o but form no entity links and\n * the write path stays offline + unchanged. Dedup is lexical +\n * embedding (offline, via the configured embedder); LLM adjudication of\n * ambiguous merges is a further opt-in that needs `provider`.\n */\n readonly graph?: EntityResolutionConfig & {\n /** Enable entity resolution + linking on write. Default `false`. */\n readonly entityResolution?: boolean;\n /** Provider for opt-in LLM adjudication of ambiguous merges. */\n readonly provider?: Provider;\n };\n /**\n * Agentic / iterative retrieval (P2-4, opt-in). When supplied,\n * `SemanticMemory.searchIterative(...)` and the gated `deep_recall`\n * tool can grade a retrieved set on the given provider and, for queries\n * judged hard, reformulate + retrieve again (widening to one-hop graph\n * expansion) up to `maxIterations`, abstaining instead of confabulating\n * when memory is insufficient. Omitted (the default) ⇒ `searchIterative`\n * stays a single difficulty-gated pass with **no provider call**, and\n * `deep_recall` is **not** registered (the tool surface stays at the\n * canonical eleven). Reserve it for hard multi-hop / temporal recall —\n * it adds provider latency per pass.\n */\n readonly iterativeRetrieval?: {\n /** Cheap provider used to grade retrieved memories + reformulate. */\n readonly provider: Provider;\n /** Default total-pass cap (clamped to `[1, 5]`). Default 3. */\n readonly maxIterations?: number;\n /** Output-token ceiling per grade call. Default 256. */\n readonly maxTokens?: number;\n };\n /**\n * Opt-in workflow induction (P2-2). When set, `ProceduralMemory.induce(...)`\n * distils a reusable, value-abstracted procedure from a successful agent\n * trajectory and stores it **quarantined** + `provenance: 'induction'`.\n * Omitted (the default) ⇒ `induce(...)` throws\n * {@link ProcedureInductionNotConfiguredError} and the procedural tier\n * stays pure offline CRUD — no provider call.\n */\n readonly procedureInduction?: {\n /** Provider used to abstract trajectory values into a procedure. */\n readonly provider: Provider;\n /** Output-token ceiling per induction call. Default 512. */\n readonly maxTokens?: number;\n };\n /**\n * Promotion-by-demonstrated-success for quarantined induced\n * procedures (MCON-2 part 4). Fully offline — orthogonal to\n * `procedureInduction` (no provider needed). When configured,\n * `procedural.recordOutcome(scope, id, true)` increments the rule's\n * persistent success counter and promotes it into `activate()` once\n * `afterSuccesses` verified reuses accumulate; the injection gate\n * still refuses flagged texts. Omitted ⇒ outcomes are counted but\n * nothing auto-promotes.\n */\n readonly procedurePromotion?: {\n /** Successful demonstrated reuses required before promotion (≥ 1). */\n readonly afterSuccesses: number;\n };\n /**\n * Resolver that produces the live {@link SessionScope} for each\n * memory-tool invocation. Defaults to a closure that throws — the\n * agent runtime overrides it in Phase 12.\n */\n readonly resolveScope?: ScopeResolver;\n /**\n * Consolidator configuration. When omitted, empty, or\n * `enabled: false`, the facade installs the Phase 10a no-op\n * placeholder so consumers can still type their interactions without\n * paying the runtime cost. ANY other setting — including offline\n * knobs like `decayCapacity` or `contextualRetrieval` — implicitly\n * enables the production runtime (MST-4); `enabled: false` together\n * with other settings warns once and keeps the placeholder.\n */\n readonly consolidator?: {\n readonly enabled?: boolean;\n readonly triggers?: ReadonlyArray<ConsolidatorTriggerSpec>;\n readonly tier?: ConsolidatorTier;\n readonly phases?: ReadonlyArray<ConsolidatorPhase>;\n readonly ceilings?: Partial<ConsolidatorCeilings>;\n readonly onExceed?: OnBudgetExceed;\n /** Provider routed to the standard phase when set (MCON-7); falls back to `provider`. */\n readonly cheapProvider?: Provider | null;\n /** Provider routed to the deep + reflection passes when set (MCON-7). */\n readonly deepProvider?: Provider | null;\n readonly cheapModel?: string | null;\n readonly deepModel?: string | null;\n readonly noiseFilters?: ReadonlyArray<'default' | 'minimal' | 'none'>;\n readonly lockWaitMs?: number;\n readonly decayTauDays?: number;\n readonly decayArchiveThreshold?: number;\n /** Capacity-bounded eviction target for the light phase (X-1). Default unbounded. */\n readonly decayCapacity?: number | null;\n /** Weights for the multi-signal salience score (X-1). */\n readonly salienceWeights?: SalienceWeights;\n readonly maxStandardBatchSize?: number;\n readonly maxDeepConflictsPerRun?: number;\n readonly dlqMaxRetries?: number;\n readonly dlqBaseBackoffMs?: number;\n readonly dlqMaxBackoffMs?: number;\n /** Auto-form quarantined episodes from processed slices (P1-2). Per-tier default. */\n readonly formEpisodes?: boolean;\n /** Score episode importance via the consolidator LLM (P1-2). Per-tier default. */\n readonly importanceScoring?: boolean;\n /** Opt in to auto-promotion of injection-clean extraction facts (MCON-2). Default off. */\n readonly autoPromoteExtraction?: boolean;\n /** Run the deep-phase reflection pass synthesizing cited insights (P1-1). Per-tier default. */\n readonly reflection?: boolean;\n /** Accumulated-importance threshold at which reflection fires (P1-1). */\n readonly importanceThreshold?: number;\n /** Upper bound on salient questions reflection asks per pass (P1-1). */\n readonly reflectionMaxQuestions?: number;\n /**\n * Contextual retrieval for standard-phase fact writes (P1-3).\n * `'llm'` opts into one budgeted cheap-model call per write to author\n * a situating prefix (consolidator-only); `'late-chunk'` (default)\n * and `'off'` defer to the write-path mode. Per-tier default.\n */\n readonly contextualRetrieval?: ContextualRetrievalMode;\n readonly defaultScope?: SessionScope;\n readonly provider?: Provider | null;\n /** Override the wall clock — used by tests. */\n readonly now?: () => number;\n /** Stable id seed — used by tests. */\n readonly randomId?: () => string;\n /** Subscribe to phase-finished events. */\n readonly onPhaseFinished?: PhaseListener;\n };\n /**\n * Conflict pipeline configuration (Phase 10b). Default: enabled,\n * English locale pack, thresholds `0.95 / 0.85 / 0.4`. Pass\n * `{ mode: 'off' }` to bypass the pipeline entirely (logs a one-shot\n * WARN per process per the spec).\n */\n readonly conflictPipeline?: ConflictPipelineOptions;\n /**\n * Context engine configuration (Phase 10d). The engine assembles\n * the layered six-layer system prompt; `memory.compile(scope)`\n * delegates to it for the working blocks + rules + metadata\n * fragments. When omitted, a default engine is created (English\n * locale; `'full'` base mode; no auto-recall; conservative\n * `'public-tls'` provider trust).\n */\n readonly contextEngine?: ContextEngineConfig;\n}\n\n/**\n * The facade returned by {@link createMemory}.\n *\n * @stable\n */\nexport interface Memory {\n readonly working: WorkingMemory;\n readonly session: SessionMemory;\n readonly episodic: EpisodicMemory;\n readonly semantic: SemanticMemory;\n readonly procedural: ProceduralMemory;\n readonly shared: SharedMemory;\n /**\n * Read surface over reflection insights (P1-1). A no-op (returns\n * empty) when the storage adapter does not expose the optional\n * insight surface.\n */\n readonly insights: InsightMemory;\n readonly tools: ReadonlyArray<Tool>;\n readonly consolidator: Consolidator;\n /** The configured conflict pipeline. Surfaced for tests + CLI tooling. */\n readonly conflictPipeline: ConflictPipeline;\n /** The configured context engine (Phase 10d). */\n readonly contextEngine: ContextEngine;\n /** The active embedder, when configured. `null` otherwise. */\n readonly embedder: EmbedderProvider | null;\n /** The canonical id of the active embedder, when configured. */\n embedderId(): string | null;\n /**\n * Compile a system-prompt block bundle. The bundle carries the\n * static fragments per memory tier; the agent runtime consumes\n * the {@link ContextEngine} surface (`memory.contextEngine`)\n * directly for the full six-layer assembly.\n */\n compile(scope: CompileScope, options?: CompileOptions): Promise<MemoryContextBlocks>;\n /** Counter snapshot consumed by Phase 10d's metadata layer. */\n metadata(scope: SessionScope): Promise<MemoryMetadata>;\n}\n\n/**\n * Wire every memory subsystem in one call. Returns the typed\n * `Memory` facade ready to be passed into `createAgent({...})`.\n *\n * @stable\n */\nexport function createMemory(options: CreateMemoryOptions): Memory {\n const tracer = options.tracer ?? NOOP_TRACER;\n const reranker: ReRanker = options.reranker ?? new RRFReranker();\n const resolveScope: ScopeResolver =\n options.resolveScope ??\n (() => {\n throw new TypeError(\n '[graphorin/memory] memory tool invoked without a scope resolver. ' +\n 'Pass `resolveScope` to createMemory({...}) — the agent runtime supplies one in Phase 12.',\n );\n });\n\n let activeEmbedderId: string | null = null;\n if (options.embedder !== undefined) {\n activeEmbedderId = bindEmbedder(options.embedder, options.embeddings);\n }\n const embedder = options.embedder ?? null;\n const embedderIdProvider = (): string | null => activeEmbedderId;\n\n const working = new WorkingMemory({ store: options.store, tracer });\n for (const block of options.workingBlocks ?? []) {\n working.define(block);\n }\n const session = new SessionMemory({ store: options.store, tracer });\n const episodic = new EpisodicMemory({\n store: options.store,\n tracer,\n embedder,\n embedderIdProvider,\n });\n const conflictPipeline = createConflictPipeline(options.conflictPipeline ?? {});\n // P2-3: build the (opt-in) query transformer from the supplied provider.\n // Absent ⇒ `null` ⇒ search stays offline + single-shot.\n const queryTransformer =\n options.queryTransform !== undefined\n ? createProviderQueryTransformer(options.queryTransform.provider, {\n ...(options.queryTransform.maxVariants !== undefined\n ? { maxVariants: options.queryTransform.maxVariants }\n : {}),\n ...(options.queryTransform.maxTokens !== undefined\n ? { maxTokens: options.queryTransform.maxTokens }\n : {}),\n })\n : null;\n // P2-1: build the (opt-in) entity resolver. Requires `graph.entityResolution`\n // *and* a graph-capable adapter; absent ⇒ `null` ⇒ writes carry s/p/o but\n // form no entity links and the write path stays offline + unchanged.\n const graphStore = options.store.graph;\n const entityResolver =\n options.graph?.entityResolution === true && graphStore !== undefined\n ? new EntityResolver({\n store: graphStore,\n embedder,\n embedderId: embedderIdProvider,\n ...(options.graph.provider !== undefined ? { provider: options.graph.provider } : {}),\n config: {\n ...(options.graph.mergeThreshold !== undefined\n ? { mergeThreshold: options.graph.mergeThreshold }\n : {}),\n ...(options.graph.adjudicateThreshold !== undefined\n ? { adjudicateThreshold: options.graph.adjudicateThreshold }\n : {}),\n ...(options.graph.llmAdjudication !== undefined\n ? { llmAdjudication: options.graph.llmAdjudication }\n : {}),\n },\n })\n : null;\n // P2-4: build the (opt-in) retrieval grader. Absent ⇒ `null` ⇒\n // `searchIterative` runs a single difficulty-gated pass (no provider\n // call) and the `deep_recall` tool is not registered.\n const grader =\n options.iterativeRetrieval !== undefined\n ? createProviderRetrievalGrader(options.iterativeRetrieval.provider, {\n ...(options.iterativeRetrieval.maxTokens !== undefined\n ? { maxTokens: options.iterativeRetrieval.maxTokens }\n : {}),\n })\n : null;\n const semantic = new SemanticMemory({\n store: options.store,\n tracer,\n embedder,\n embedderIdProvider,\n reranker,\n conflictPipeline,\n ...(options.contextualRetrieval !== undefined\n ? { contextualRetrieval: options.contextualRetrieval }\n : {}),\n ...(queryTransformer !== null ? { queryTransformer } : {}),\n ...(entityResolver !== null ? { entityResolver } : {}),\n ...(grader !== null ? { grader } : {}),\n ...(options.iterativeRetrieval?.maxIterations !== undefined\n ? { iterativeMaxIterations: options.iterativeRetrieval.maxIterations }\n : {}),\n });\n // P2-2: build the (opt-in) workflow inducer. Absent ⇒ `null` ⇒\n // `ProceduralMemory.induce(...)` throws and the tier stays offline CRUD.\n // MCON-15: induction spend is recorded into the consolidator budget —\n // the consolidator is constructed AFTER the inducer, so the callback\n // routes through a slot filled below (placeholder ⇒ no-op).\n let consolidatorForSpend: Consolidator | null = null;\n const inducer =\n options.procedureInduction !== undefined\n ? createProviderWorkflowInducer(options.procedureInduction.provider, {\n ...(options.procedureInduction.maxTokens !== undefined\n ? { maxTokens: options.procedureInduction.maxTokens }\n : {}),\n onUsage: (usage) => {\n consolidatorForSpend?.recordExternalSpend(usage.promptTokens + usage.completionTokens);\n },\n })\n : null;\n const procedural = new ProceduralMemory({\n store: options.store,\n tracer,\n ...(inducer !== null ? { inducer } : {}),\n // MCON-2 part 4: opt-in promotion-by-demonstrated-success.\n ...(options.procedurePromotion?.afterSuccesses !== undefined\n ? { promoteAfterSuccesses: options.procedurePromotion.afterSuccesses }\n : {}),\n });\n const shared = new SharedMemory({ store: options.store, tracer });\n const insights = new InsightMemory({ store: options.store, tracer });\n\n const tools = buildMemoryTools(\n {\n working,\n session,\n episodic,\n semantic,\n procedural,\n shared,\n resolveScope,\n },\n // P2-4: the gated `deep_recall` tool is registered only when a grader\n // is configured — the offline default stays at exactly eleven tools.\n { includeDeepRecall: grader !== null },\n );\n\n const consolidatorOpts = options.consolidator;\n const consolidator: Consolidator = buildConsolidator(\n consolidatorOpts,\n options.store,\n semantic,\n episodic,\n tracer,\n );\n consolidatorForSpend = consolidator;\n const contextEngineConfig = options.contextEngine ?? {};\n const contextEngine: ContextEngine = createContextEngine(contextEngineConfig);\n const resolved = contextEngine.config();\n const localePack =\n contextEngineConfig.locale === undefined\n ? enLocalePack\n : typeof contextEngineConfig.locale === 'string'\n ? contextEngineConfig.locale === enLocalePack.id\n ? enLocalePack\n : resolveLocalePack({ id: contextEngineConfig.locale })\n : resolveLocalePack(contextEngineConfig.locale);\n\n // The facade's `compile(...)` is the static-fragment surface\n // consumed by callers that do not know the active provider yet\n // (the agent runtime calls `memory.contextEngine.assemble(...)`\n // with full provider context when `autoAssembleContext` is\n // enabled). The privacy filter only fires\n // when the caller explicitly passes `providerAcceptsSensitivity`\n // OR the operator opted into the engine's `privacy` block.\n const privacyOptedIn =\n contextEngineConfig.privacy !== undefined &&\n (contextEngineConfig.privacy.providerAcceptsSensitivity !== undefined ||\n contextEngineConfig.privacy.cloudUploadConsent !== undefined ||\n contextEngineConfig.privacy.providerTrust !== undefined);\n\n async function compile(\n scope: CompileScope,\n compileOptions: CompileOptions = {},\n ): Promise<MemoryContextBlocks> {\n const out: { -readonly [K in keyof MemoryContextBlocks]: MemoryContextBlocks[K] } = {};\n const blocks = await options.store.working.list(scope);\n // Quarantined (e.g. P2-2-induced) procedures are provisional and must not\n // reach the system prompt — `activate()` already excludes them, and\n // compile() (public `@stable`) must agree or a compile()-based prompt\n // builder ingests unvalidated induction procedures (MST-3).\n const rules = (await options.store.procedural.list(scope)).filter(\n (rule) => rule.status !== 'quarantined',\n );\n const shouldFilter = privacyOptedIn || compileOptions.providerAcceptsSensitivity !== undefined;\n let blocksKept: ReadonlyArray<(typeof blocks)[number]> = blocks;\n let rulesKept: ReadonlyArray<(typeof rules)[number]> = rules;\n if (shouldFilter) {\n const filterContext: Parameters<typeof partitionBySensitivity>[1] = {\n providerTrust: resolved.providerTrust,\n cloudUploadConsent: resolved.cloudUploadConsent,\n defaultSensitivity: resolved.defaultSensitivity,\n };\n if (compileOptions.providerAcceptsSensitivity !== undefined) {\n (\n filterContext as {\n providerAcceptsSensitivity?: ReadonlyArray<'public' | 'internal' | 'secret'>;\n }\n ).providerAcceptsSensitivity = compileOptions.providerAcceptsSensitivity;\n }\n blocksKept = partitionBySensitivity(blocks, filterContext).kept;\n rulesKept = partitionBySensitivity(rules, filterContext).kept;\n }\n const blocksXml = renderWorkingBlocksXml(blocksKept);\n if (blocksXml.length > 0) {\n out.workingBlocks = blocksXml;\n }\n if (rulesKept.length > 0) {\n const lines = ['<memory_rules>'];\n for (const rule of rulesKept) {\n lines.push(` <rule priority=\"${rule.priority}\">${escapeXml(rule.text)}</rule>`);\n }\n lines.push('</memory_rules>');\n out.rules = lines.join('\\n');\n }\n if (compileOptions.includeMetadata !== false) {\n const meta = await metadata(scope);\n out.metadata = renderMetadataBlock(meta);\n }\n out.base = composeLayer1(localePack, resolved.memoryBaseMode);\n return Object.freeze(out);\n }\n\n async function metadata(scope: SessionScope): Promise<MemoryMetadata> {\n return gatherMemoryMetadata(scope, {\n store: options.store,\n consolidator,\n embedderId: embedderIdProvider,\n localeId: resolved.localeId,\n });\n }\n\n return Object.freeze({\n working,\n session,\n episodic,\n semantic,\n procedural,\n shared,\n insights,\n tools,\n consolidator,\n conflictPipeline,\n contextEngine,\n embedder,\n embedderId: embedderIdProvider,\n compile,\n metadata,\n });\n}\n\nfunction renderWorkingBlocksXml(\n blocks: ReadonlyArray<{\n readonly label: string;\n readonly value: string;\n readonly description?: string;\n }>,\n): string {\n if (blocks.length === 0) return '';\n const lines = ['<memory_blocks>'];\n for (const block of blocks) {\n const description =\n block.description !== undefined ? ` description=\"${escapeXml(block.description)}\"` : '';\n lines.push(` <block label=\"${escapeXml(block.label)}\"${description}>`);\n lines.push(` ${escapeXml(block.value)}`);\n lines.push(' </block>');\n }\n lines.push('</memory_blocks>');\n return lines.join('\\n');\n}\n\nfunction escapeXml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nfunction buildConsolidator(\n opts: CreateMemoryOptions['consolidator'],\n store: CreateMemoryOptions['store'],\n semantic: SemanticMemory,\n episodic: EpisodicMemory,\n tracer: Tracer,\n): Consolidator {\n if (opts === undefined) {\n return createConsolidatorPlaceholder();\n }\n const enabled = shouldEnableConsolidator(opts);\n if (!enabled) {\n return createConsolidatorPlaceholder({\n ...(opts.triggers !== undefined ? { triggers: opts.triggers } : {}),\n ...(opts.tier !== undefined ? { tier: opts.tier } : {}),\n });\n }\n const consolidator = createConsolidator({\n store,\n semantic,\n episodic,\n tracer,\n ...(opts.provider !== undefined ? { provider: opts.provider } : {}),\n ...(opts.now !== undefined ? { now: opts.now } : {}),\n ...(opts.randomId !== undefined ? { randomId: opts.randomId } : {}),\n ...(opts.triggers !== undefined ? { triggers: opts.triggers } : {}),\n ...(opts.tier !== undefined ? { tier: opts.tier } : {}),\n ...(opts.phases !== undefined ? { phases: opts.phases } : {}),\n ...(opts.ceilings !== undefined ? { ceilings: opts.ceilings } : {}),\n ...(opts.onExceed !== undefined ? { onExceed: opts.onExceed } : {}),\n ...(opts.cheapProvider !== undefined ? { cheapProvider: opts.cheapProvider } : {}),\n ...(opts.deepProvider !== undefined ? { deepProvider: opts.deepProvider } : {}),\n ...(opts.cheapModel !== undefined ? { cheapModel: opts.cheapModel } : {}),\n ...(opts.deepModel !== undefined ? { deepModel: opts.deepModel } : {}),\n ...(opts.noiseFilters !== undefined ? { noiseFilters: opts.noiseFilters } : {}),\n ...(opts.lockWaitMs !== undefined ? { lockWaitMs: opts.lockWaitMs } : {}),\n ...(opts.decayTauDays !== undefined ? { decayTauDays: opts.decayTauDays } : {}),\n ...(opts.decayArchiveThreshold !== undefined\n ? { decayArchiveThreshold: opts.decayArchiveThreshold }\n : {}),\n ...(opts.decayCapacity !== undefined ? { decayCapacity: opts.decayCapacity } : {}),\n ...(opts.salienceWeights !== undefined ? { salienceWeights: opts.salienceWeights } : {}),\n ...(opts.maxStandardBatchSize !== undefined\n ? { maxStandardBatchSize: opts.maxStandardBatchSize }\n : {}),\n ...(opts.maxDeepConflictsPerRun !== undefined\n ? { maxDeepConflictsPerRun: opts.maxDeepConflictsPerRun }\n : {}),\n ...(opts.dlqMaxRetries !== undefined ? { dlqMaxRetries: opts.dlqMaxRetries } : {}),\n ...(opts.dlqBaseBackoffMs !== undefined ? { dlqBaseBackoffMs: opts.dlqBaseBackoffMs } : {}),\n ...(opts.dlqMaxBackoffMs !== undefined ? { dlqMaxBackoffMs: opts.dlqMaxBackoffMs } : {}),\n ...(opts.formEpisodes !== undefined ? { formEpisodes: opts.formEpisodes } : {}),\n ...(opts.importanceScoring !== undefined ? { importanceScoring: opts.importanceScoring } : {}),\n ...(opts.autoPromoteExtraction !== undefined\n ? { autoPromoteExtraction: opts.autoPromoteExtraction }\n : {}),\n ...(opts.reflection !== undefined ? { reflection: opts.reflection } : {}),\n ...(opts.importanceThreshold !== undefined\n ? { importanceThreshold: opts.importanceThreshold }\n : {}),\n ...(opts.reflectionMaxQuestions !== undefined\n ? { reflectionMaxQuestions: opts.reflectionMaxQuestions }\n : {}),\n ...(opts.contextualRetrieval !== undefined\n ? { contextualRetrieval: opts.contextualRetrieval }\n : {}),\n ...(opts.defaultScope !== undefined ? { defaultScope: opts.defaultScope } : {}),\n });\n if (opts.onPhaseFinished !== undefined) {\n consolidator.onPhaseFinished(opts.onPhaseFinished);\n }\n return consolidator;\n}\n\nlet consolidatorConfigIgnoredWarned = false;\n\n/** @internal — test seam for the one-time disabled-config warning. */\nexport function _resetConsolidatorConfigWarningForTesting(): void {\n consolidatorConfigIgnoredWarned = false;\n}\n\nfunction shouldEnableConsolidator(opts: NonNullable<CreateMemoryOptions['consolidator']>): boolean {\n // MST-4: ANY non-empty consolidator config implicitly enables — the old\n // allow-list silently ignored offline knobs (`decayCapacity`,\n // `formEpisodes`, `reflection`, `contextualRetrieval`, …): the caller\n // got a no-op placeholder while believing the feature was on.\n const keys = Object.keys(opts).filter(\n (k) => k !== 'enabled' && (opts as Record<string, unknown>)[k] !== undefined,\n );\n if (opts.enabled === false) {\n if (keys.length > 0 && !consolidatorConfigIgnoredWarned) {\n consolidatorConfigIgnoredWarned = true;\n process.stderr.write(\n `[graphorin/memory] consolidator config (${keys.join(', ')}) was supplied together with enabled: false — the settings are ignored until the consolidator is enabled.\\n`,\n );\n }\n return false;\n }\n if (opts.enabled === true) return true;\n return keys.length > 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"facade.js","names":["reranker: ReRanker","resolveScope: ScopeResolver","activeEmbedderId: string | null","consolidatorForSpend: Consolidator | null","consolidator: Consolidator","contextEngine: ContextEngine","out: { -readonly [K in keyof MemoryContextBlocks]: MemoryContextBlocks[K] }","blocksKept: ReadonlyArray<(typeof blocks)[number]>","rulesKept: ReadonlyArray<(typeof rules)[number]>","filterContext: Parameters<typeof partitionBySensitivity>[1]","partitionBySensitivity"],"sources":["../src/facade.ts"],"sourcesContent":["/**\n * `createMemory()` - the facade that wires every tier sub-module (the\n * seven-tier system) + the eleven (+1 gated) memory tools + the search\n * reranker + the context engine\n * stubs + the consolidator placeholder.\n *\n * @packageDocumentation\n */\n\nimport type {\n EmbedderProvider,\n MemoryMetadata,\n Provider,\n SessionScope,\n Tool,\n Tracer,\n} from '@graphorin/core';\nimport { NOOP_TRACER } from '@graphorin/core';\nimport {\n type ConflictPipeline,\n type ConflictPipelineOptions,\n createConflictPipeline,\n} from './conflict/index.js';\nimport {\n type Consolidator,\n type ConsolidatorCeilings,\n type ConsolidatorPhase,\n type ConsolidatorTier,\n type ConsolidatorTriggerSpec,\n createConsolidator,\n createConsolidatorPlaceholder,\n createProviderWorkflowInducer,\n type OnBudgetExceed,\n type PhaseListener,\n type SalienceWeights,\n} from './consolidator/index.js';\nimport { createContextEngine } from './context-engine/engine.js';\nimport type {\n CompileOptions,\n CompileScope,\n ContextEngine,\n ContextEngineConfig,\n MemoryContextBlocks,\n} from './context-engine/index.js';\nimport { enLocalePack } from './context-engine/locale-packs/index.js';\nimport { resolveLocalePack } from './context-engine/locale-packs/resolver.js';\nimport { gatherMemoryMetadata, renderMetadataBlock } from './context-engine/metadata.js';\nimport { partition as partitionBySensitivity } from './context-engine/privacy-filter.js';\nimport { composeLayer1 } from './context-engine/templates/composer.js';\nimport { type EntityResolutionConfig, EntityResolver } from './graph/entity-resolver.js';\nimport type { ContextualRetrievalMode } from './internal/contextualize.js';\nimport { bindEmbedder } from './internal/embedder-binding.js';\nimport type { EmbeddingMetaRegistryLike, MemoryStoreAdapter } from './internal/storage-adapter.js';\nimport { createProviderRetrievalGrader } from './search/iterative.js';\nimport { createProviderQueryTransformer } from './search/query-transform.js';\nimport { RRFReranker } from './search/rrf.js';\nimport type { ReRanker } from './search/types.js';\nimport { EpisodicMemory } from './tiers/episodic-memory.js';\nimport { InsightMemory } from './tiers/insight-memory.js';\nimport { ProceduralMemory } from './tiers/procedural-memory.js';\nimport { SemanticMemory } from './tiers/semantic-memory.js';\nimport { SessionMemory } from './tiers/session-memory.js';\nimport { SharedMemory } from './tiers/shared-memory.js';\nimport { type BlockDefinition, WorkingMemory } from './tiers/working-memory.js';\nimport { buildMemoryTools, type ScopeResolver } from './tools/index.js';\n\n/**\n * Options accepted by {@link createMemory}.\n *\n * @stable\n */\nexport interface CreateMemoryOptions {\n /** Storage adapter (default: `@graphorin/store-sqlite`'s `MemoryStore`). */\n readonly store: MemoryStoreAdapter;\n /** Embedder registry. The default sqlite store exposes one as `sqlite.embeddings`. */\n readonly embeddings: EmbeddingMetaRegistryLike;\n /** Embedder provider (default: none - vector search is disabled). */\n readonly embedder?: EmbedderProvider;\n /** Pre-declared working blocks (idempotent - re-defining is a no-op). */\n readonly workingBlocks?: ReadonlyArray<BlockDefinition>;\n /**\n * Tracer used for every `memory.*` span. Defaults to the no-op\n * tracer from `@graphorin/core` so unit tests do not need to wire\n * the observability stack.\n */\n readonly tracer?: Tracer;\n /** Override the reranker used by `SemanticMemory.search`. */\n readonly reranker?: ReRanker;\n /**\n * Contextual-retrieval mode for the write path (P1-3). `'late-chunk'`\n * (default) prepends a deterministic, offline situating context\n * (entities / timeframe / topics, derived from the fact's own\n * structured fields) to the text that is embedded + FTS-indexed, so a\n * terse fact stays findable; the canonical `text` is preserved. `'off'`\n * indexes the bare text. The `'llm'` enrichment is **not** available on\n * the hot path - it is a consolidator-only opt-in configured via\n * `consolidator: { contextualRetrieval: 'llm' }`.\n */\n readonly contextualRetrieval?: 'off' | 'late-chunk';\n /**\n * Query transformation for retrieval (P2-3, opt-in). When supplied,\n * `SemanticMemory.search(..., { multiQuery })` fans the query into\n * reworded variants (multi-query / RAG-Fusion) and `{ hyde }` adds a\n * hypothetical-answer embedding - both via one cheap LLM call on the\n * given provider, fused through the existing RRF reranker. Omitted (the\n * default) ⇒ search stays **offline + single-shot** and the\n * `multiQuery` / `hyde` search options become silent no-ops. Reserve it\n * for retrieval-heavy recall, not every search (it adds provider\n * latency).\n */\n readonly queryTransform?: {\n /** Cheap provider used to rewrite the query / write the HyDE passage. */\n readonly provider: Provider;\n /** Hard ceiling on reworded variants requested per call. Default 5. */\n readonly maxVariants?: number;\n /** Output-token ceiling per transform call. Default 256. */\n readonly maxTokens?: number;\n };\n /**\n * Relation-graph entity resolution (P2-1). When `entityResolution` is\n * `true` **and** the storage adapter exposes a `graph` surface (the\n * default `@graphorin/store-sqlite` does), `remember(...)` resolves a\n * fact's subject / object to canonical entities and links them, so\n * `search(..., { expandHops: 1 })` can traverse relationships. Omitted\n * (the default) ⇒ facts still carry s/p/o but form no entity links and\n * the write path stays offline + unchanged. Dedup is lexical +\n * embedding (offline, via the configured embedder); LLM adjudication of\n * ambiguous merges is a further opt-in that needs `provider`.\n */\n readonly graph?: EntityResolutionConfig & {\n /** Enable entity resolution + linking on write. Default `false`. */\n readonly entityResolution?: boolean;\n /** Provider for opt-in LLM adjudication of ambiguous merges. */\n readonly provider?: Provider;\n };\n /**\n * Agentic / iterative retrieval (P2-4, opt-in). When supplied,\n * `SemanticMemory.searchIterative(...)` and the gated `deep_recall`\n * tool can grade a retrieved set on the given provider and, for queries\n * judged hard, reformulate + retrieve again (widening to one-hop graph\n * expansion) up to `maxIterations`, abstaining instead of confabulating\n * when memory is insufficient. Omitted (the default) ⇒ `searchIterative`\n * stays a single difficulty-gated pass with **no provider call**, and\n * `deep_recall` is **not** registered (the tool surface stays at the\n * canonical eleven). Reserve it for hard multi-hop / temporal recall -\n * it adds provider latency per pass.\n */\n readonly iterativeRetrieval?: {\n /** Cheap provider used to grade retrieved memories + reformulate. */\n readonly provider: Provider;\n /** Default total-pass cap (clamped to `[1, 5]`). Default 3. */\n readonly maxIterations?: number;\n /** Output-token ceiling per grade call. Default 256. */\n readonly maxTokens?: number;\n };\n /**\n * Opt-in workflow induction (P2-2). When set, `ProceduralMemory.induce(...)`\n * distils a reusable, value-abstracted procedure from a successful agent\n * trajectory and stores it **quarantined** + `provenance: 'induction'`.\n * Omitted (the default) ⇒ `induce(...)` throws\n * {@link ProcedureInductionNotConfiguredError} and the procedural tier\n * stays pure offline CRUD - no provider call.\n */\n readonly procedureInduction?: {\n /** Provider used to abstract trajectory values into a procedure. */\n readonly provider: Provider;\n /** Output-token ceiling per induction call. Default 512. */\n readonly maxTokens?: number;\n };\n /**\n * Promotion-by-demonstrated-success for quarantined induced\n * procedures (MCON-2 part 4). Fully offline - orthogonal to\n * `procedureInduction` (no provider needed). When configured,\n * `procedural.recordOutcome(scope, id, true)` increments the rule's\n * persistent success counter and promotes it into `activate()` once\n * `afterSuccesses` verified reuses accumulate; the injection gate\n * still refuses flagged texts. Omitted ⇒ outcomes are counted but\n * nothing auto-promotes.\n */\n readonly procedurePromotion?: {\n /** Successful demonstrated reuses required before promotion (≥ 1). */\n readonly afterSuccesses: number;\n };\n /**\n * Register the gated `runbook_search` tool (D3) so the model can look\n * up validated procedures by task description (content recall over\n * procedural memory, returning whole runbooks). Fully offline - the\n * default `@graphorin/store-sqlite` adapter serves it from the rules\n * FTS index (migration 028); adapters without the index degrade to an\n * in-memory lexical scan. Default `false` - the tool surface stays at\n * the canonical eleven.\n */\n readonly runbookSearch?: boolean;\n /**\n * Resolver that produces the live {@link SessionScope} for each\n * memory-tool invocation. Defaults to a closure that throws - the\n * agent runtime overrides it in Phase 12.\n */\n readonly resolveScope?: ScopeResolver;\n /**\n * Consolidator configuration. When omitted, empty, or\n * `enabled: false`, the facade installs the Phase 10a no-op\n * placeholder so consumers can still type their interactions without\n * paying the runtime cost. ANY other setting - including offline\n * knobs like `decayCapacity` or `contextualRetrieval` - implicitly\n * enables the production runtime (MST-4); `enabled: false` together\n * with other settings warns once and keeps the placeholder.\n */\n readonly consolidator?: {\n readonly enabled?: boolean;\n readonly triggers?: ReadonlyArray<ConsolidatorTriggerSpec>;\n readonly tier?: ConsolidatorTier;\n readonly phases?: ReadonlyArray<ConsolidatorPhase>;\n readonly ceilings?: Partial<ConsolidatorCeilings>;\n readonly onExceed?: OnBudgetExceed;\n /**\n * USD pricer for phase LLM usage (memory-consolidation-02) - wire\n * to `@graphorin/pricing` so `maxCostPerDay` can actually trip.\n */\n readonly priceUsage?: (usage: { promptTokens: number; completionTokens: number }) => number;\n /** Provider routed to the standard phase when set (MCON-7); falls back to `provider`. */\n readonly cheapProvider?: Provider | null;\n /** Provider routed to the deep + reflection passes when set (MCON-7). */\n readonly deepProvider?: Provider | null;\n readonly cheapModel?: string | null;\n readonly deepModel?: string | null;\n readonly noiseFilters?: ReadonlyArray<'default' | 'minimal' | 'none'>;\n readonly lockWaitMs?: number;\n readonly decayTauDays?: number;\n readonly decayArchiveThreshold?: number;\n /** Capacity-bounded eviction target for the light phase (X-1). Default unbounded. */\n readonly decayCapacity?: number | null;\n /** Weights for the multi-signal salience score (X-1). */\n readonly salienceWeights?: SalienceWeights;\n readonly maxStandardBatchSize?: number;\n readonly maxDeepConflictsPerRun?: number;\n readonly dlqMaxRetries?: number;\n readonly dlqBaseBackoffMs?: number;\n readonly dlqMaxBackoffMs?: number;\n /** Auto-form quarantined episodes from processed slices (P1-2). Per-tier default. */\n readonly formEpisodes?: boolean;\n /** Score episode importance via the consolidator LLM (P1-2). Per-tier default. */\n readonly importanceScoring?: boolean;\n /** Opt in to auto-promotion of injection-clean extraction facts (MCON-2). Default off. */\n readonly autoPromoteExtraction?: boolean;\n /** Run the deep-phase reflection pass synthesizing cited insights (P1-1). Per-tier default. */\n readonly reflection?: boolean;\n /** Accumulated-importance threshold at which reflection fires (P1-1). */\n readonly importanceThreshold?: number;\n /** Upper bound on salient questions reflection asks per pass (P1-1). */\n readonly reflectionMaxQuestions?: number;\n /**\n * Contextual retrieval for standard-phase fact writes (P1-3).\n * `'llm'` opts into one budgeted cheap-model call per write to author\n * a situating prefix (consolidator-only); `'late-chunk'` (default)\n * and `'off'` defer to the write-path mode. Per-tier default.\n */\n readonly contextualRetrieval?: ContextualRetrievalMode;\n /**\n * Maintain the learned-context digest block (D3): after each deep\n * phase, one budgeted LLM call rewrites the reserved\n * `learned_context` working block (previous digest + recent\n * episodes / active insights / procedures), so the assembled system\n * prompt carries a compact standing summary. Default `false` at\n * every tier (Wave-D trial).\n */\n readonly learnedContext?: boolean;\n /** Character bound for the learned-context digest (D3). Default `1200`. */\n readonly learnedContextMaxChars?: number;\n readonly defaultScope?: SessionScope;\n readonly provider?: Provider | null;\n /** Override the wall clock - used by tests. */\n readonly now?: () => number;\n /** Stable id seed - used by tests. */\n readonly randomId?: () => string;\n /** Subscribe to phase-finished events. */\n readonly onPhaseFinished?: PhaseListener;\n };\n /**\n * Conflict pipeline configuration (Phase 10b). Default: enabled,\n * English locale pack, thresholds `0.95 / 0.85 / 0.4`. Pass\n * `{ mode: 'off' }` to bypass the pipeline entirely (logs a one-shot\n * WARN per process per the spec).\n */\n readonly conflictPipeline?: ConflictPipelineOptions;\n /**\n * Context engine configuration (Phase 10d). The engine assembles\n * the layered six-layer system prompt; `memory.compile(scope)`\n * delegates to it for the working blocks + rules + metadata\n * fragments. When omitted, a default engine is created (English\n * locale; `'full'` base mode; no auto-recall; conservative\n * `'public-tls'` provider trust).\n */\n readonly contextEngine?: ContextEngineConfig;\n}\n\n/**\n * The facade returned by {@link createMemory}.\n *\n * @stable\n */\nexport interface Memory {\n readonly working: WorkingMemory;\n readonly session: SessionMemory;\n readonly episodic: EpisodicMemory;\n readonly semantic: SemanticMemory;\n readonly procedural: ProceduralMemory;\n readonly shared: SharedMemory;\n /**\n * Read surface over reflection insights (P1-1). A no-op (returns\n * empty) when the storage adapter does not expose the optional\n * insight surface.\n */\n readonly insights: InsightMemory;\n readonly tools: ReadonlyArray<Tool>;\n readonly consolidator: Consolidator;\n /** The configured conflict pipeline. Surfaced for tests + CLI tooling. */\n readonly conflictPipeline: ConflictPipeline;\n /** The configured context engine (Phase 10d). */\n readonly contextEngine: ContextEngine;\n /** The active embedder, when configured. `null` otherwise. */\n readonly embedder: EmbedderProvider | null;\n /** The canonical id of the active embedder, when configured. */\n embedderId(): string | null;\n /**\n * Compile a system-prompt block bundle. The bundle carries the\n * static fragments per memory tier; the agent runtime consumes\n * the {@link ContextEngine} surface (`memory.contextEngine`)\n * directly for the full six-layer assembly.\n */\n compile(scope: CompileScope, options?: CompileOptions): Promise<MemoryContextBlocks>;\n /** Counter snapshot consumed by Phase 10d's metadata layer. */\n metadata(scope: SessionScope): Promise<MemoryMetadata>;\n}\n\n/**\n * Wire every memory subsystem in one call. Returns the typed\n * `Memory` facade ready to be passed into `createAgent({...})`.\n *\n * @stable\n */\nexport function createMemory(options: CreateMemoryOptions): Memory {\n const tracer = options.tracer ?? NOOP_TRACER;\n const reranker: ReRanker = options.reranker ?? new RRFReranker();\n const resolveScope: ScopeResolver =\n options.resolveScope ??\n (() => {\n throw new TypeError(\n '[graphorin/memory] memory tool invoked without a scope resolver. ' +\n 'Pass `resolveScope` to createMemory({...}) - the agent runtime supplies one in Phase 12.',\n );\n });\n\n let activeEmbedderId: string | null = null;\n if (options.embedder !== undefined) {\n activeEmbedderId = bindEmbedder(options.embedder, options.embeddings);\n }\n const embedder = options.embedder ?? null;\n const embedderIdProvider = (): string | null => activeEmbedderId;\n\n const working = new WorkingMemory({ store: options.store, tracer });\n for (const block of options.workingBlocks ?? []) {\n working.define(block);\n }\n const session = new SessionMemory({ store: options.store, tracer });\n const episodic = new EpisodicMemory({\n store: options.store,\n tracer,\n embedder,\n embedderIdProvider,\n });\n const conflictPipeline = createConflictPipeline(options.conflictPipeline ?? {});\n // P2-3: build the (opt-in) query transformer from the supplied provider.\n // Absent ⇒ `null` ⇒ search stays offline + single-shot.\n const queryTransformer =\n options.queryTransform !== undefined\n ? createProviderQueryTransformer(options.queryTransform.provider, {\n ...(options.queryTransform.maxVariants !== undefined\n ? { maxVariants: options.queryTransform.maxVariants }\n : {}),\n ...(options.queryTransform.maxTokens !== undefined\n ? { maxTokens: options.queryTransform.maxTokens }\n : {}),\n })\n : null;\n // P2-1: build the (opt-in) entity resolver. Requires `graph.entityResolution`\n // *and* a graph-capable adapter; absent ⇒ `null` ⇒ writes carry s/p/o but\n // form no entity links and the write path stays offline + unchanged.\n const graphStore = options.store.graph;\n const entityResolver =\n options.graph?.entityResolution === true && graphStore !== undefined\n ? new EntityResolver({\n store: graphStore,\n embedder,\n embedderId: embedderIdProvider,\n ...(options.graph.provider !== undefined ? { provider: options.graph.provider } : {}),\n config: {\n ...(options.graph.mergeThreshold !== undefined\n ? { mergeThreshold: options.graph.mergeThreshold }\n : {}),\n ...(options.graph.adjudicateThreshold !== undefined\n ? { adjudicateThreshold: options.graph.adjudicateThreshold }\n : {}),\n ...(options.graph.llmAdjudication !== undefined\n ? { llmAdjudication: options.graph.llmAdjudication }\n : {}),\n },\n })\n : null;\n // P2-4: build the (opt-in) retrieval grader. Absent ⇒ `null` ⇒\n // `searchIterative` runs a single difficulty-gated pass (no provider\n // call) and the `deep_recall` tool is not registered.\n const grader =\n options.iterativeRetrieval !== undefined\n ? createProviderRetrievalGrader(options.iterativeRetrieval.provider, {\n ...(options.iterativeRetrieval.maxTokens !== undefined\n ? { maxTokens: options.iterativeRetrieval.maxTokens }\n : {}),\n })\n : null;\n const semantic = new SemanticMemory({\n store: options.store,\n tracer,\n embedder,\n embedderIdProvider,\n reranker,\n conflictPipeline,\n ...(options.contextualRetrieval !== undefined\n ? { contextualRetrieval: options.contextualRetrieval }\n : {}),\n ...(queryTransformer !== null ? { queryTransformer } : {}),\n ...(entityResolver !== null ? { entityResolver } : {}),\n ...(grader !== null ? { grader } : {}),\n ...(options.iterativeRetrieval?.maxIterations !== undefined\n ? { iterativeMaxIterations: options.iterativeRetrieval.maxIterations }\n : {}),\n // C5: the same weights drive eviction salience and rank-time trust.\n ...(options.consolidator?.salienceWeights !== undefined\n ? { trustWeights: options.consolidator.salienceWeights }\n : {}),\n });\n // P2-2: build the (opt-in) workflow inducer. Absent ⇒ `null` ⇒\n // `ProceduralMemory.induce(...)` throws and the tier stays offline CRUD.\n // MCON-15: induction spend is recorded into the consolidator budget -\n // the consolidator is constructed AFTER the inducer, so the callback\n // routes through a slot filled below (placeholder ⇒ no-op).\n let consolidatorForSpend: Consolidator | null = null;\n const inducer =\n options.procedureInduction !== undefined\n ? createProviderWorkflowInducer(options.procedureInduction.provider, {\n ...(options.procedureInduction.maxTokens !== undefined\n ? { maxTokens: options.procedureInduction.maxTokens }\n : {}),\n onUsage: (usage) => {\n consolidatorForSpend?.recordExternalSpend(usage.promptTokens + usage.completionTokens);\n },\n })\n : null;\n const procedural = new ProceduralMemory({\n store: options.store,\n tracer,\n ...(inducer !== null ? { inducer } : {}),\n // MCON-2 part 4: opt-in promotion-by-demonstrated-success.\n ...(options.procedurePromotion?.afterSuccesses !== undefined\n ? { promoteAfterSuccesses: options.procedurePromotion.afterSuccesses }\n : {}),\n });\n const shared = new SharedMemory({ store: options.store, tracer });\n const insights = new InsightMemory({ store: options.store, tracer });\n\n const tools = buildMemoryTools(\n {\n working,\n session,\n episodic,\n semantic,\n procedural,\n shared,\n resolveScope,\n },\n // P2-4: the gated `deep_recall` tool is registered only when a grader\n // is configured - the offline default stays at exactly eleven tools.\n // D3: `runbook_search` is a second gated appendix, opt-in via\n // `runbookSearch: true`.\n {\n includeDeepRecall: grader !== null,\n includeRunbookSearch: options.runbookSearch === true,\n },\n );\n\n const consolidatorOpts = options.consolidator;\n const consolidator: Consolidator = buildConsolidator(\n consolidatorOpts,\n options.store,\n semantic,\n episodic,\n working,\n tracer,\n );\n consolidatorForSpend = consolidator;\n const contextEngineConfig = options.contextEngine ?? {};\n const contextEngine: ContextEngine = createContextEngine(contextEngineConfig);\n const resolved = contextEngine.config();\n const localePack =\n contextEngineConfig.locale === undefined\n ? enLocalePack\n : typeof contextEngineConfig.locale === 'string'\n ? contextEngineConfig.locale === enLocalePack.id\n ? enLocalePack\n : resolveLocalePack({ id: contextEngineConfig.locale })\n : resolveLocalePack(contextEngineConfig.locale);\n\n // The facade's `compile(...)` is the static-fragment surface\n // consumed by callers that do not know the active provider yet\n // (the agent runtime calls `memory.contextEngine.assemble(...)`\n // with full provider context when `autoAssembleContext` is\n // enabled). The privacy filter only fires\n // when the caller explicitly passes `providerAcceptsSensitivity`\n // OR the operator opted into the engine's `privacy` block.\n const privacyOptedIn =\n contextEngineConfig.privacy !== undefined &&\n (contextEngineConfig.privacy.providerAcceptsSensitivity !== undefined ||\n contextEngineConfig.privacy.cloudUploadConsent !== undefined ||\n contextEngineConfig.privacy.providerTrust !== undefined);\n\n async function compile(\n scope: CompileScope,\n compileOptions: CompileOptions = {},\n ): Promise<MemoryContextBlocks> {\n const out: { -readonly [K in keyof MemoryContextBlocks]: MemoryContextBlocks[K] } = {};\n const blocks = await options.store.working.list(scope);\n // Quarantined (e.g. P2-2-induced) procedures are provisional and must not\n // reach the system prompt - `activate()` already excludes them, and\n // compile() (public `@stable`) must agree or a compile()-based prompt\n // builder ingests unvalidated induction procedures (MST-3).\n const rules = (await options.store.procedural.list(scope)).filter(\n (rule) => rule.status !== 'quarantined',\n );\n const shouldFilter = privacyOptedIn || compileOptions.providerAcceptsSensitivity !== undefined;\n let blocksKept: ReadonlyArray<(typeof blocks)[number]> = blocks;\n let rulesKept: ReadonlyArray<(typeof rules)[number]> = rules;\n if (shouldFilter) {\n const filterContext: Parameters<typeof partitionBySensitivity>[1] = {\n providerTrust: resolved.providerTrust,\n cloudUploadConsent: resolved.cloudUploadConsent,\n defaultSensitivity: resolved.defaultSensitivity,\n };\n if (compileOptions.providerAcceptsSensitivity !== undefined) {\n (\n filterContext as {\n providerAcceptsSensitivity?: ReadonlyArray<'public' | 'internal' | 'secret'>;\n }\n ).providerAcceptsSensitivity = compileOptions.providerAcceptsSensitivity;\n }\n blocksKept = partitionBySensitivity(blocks, filterContext).kept;\n rulesKept = partitionBySensitivity(rules, filterContext).kept;\n }\n const blocksXml = renderWorkingBlocksXml(blocksKept);\n if (blocksXml.length > 0) {\n out.workingBlocks = blocksXml;\n }\n if (rulesKept.length > 0) {\n const lines = ['<memory_rules>'];\n for (const rule of rulesKept) {\n lines.push(` <rule priority=\"${rule.priority}\">${escapeXml(rule.text)}</rule>`);\n }\n lines.push('</memory_rules>');\n out.rules = lines.join('\\n');\n }\n if (compileOptions.includeMetadata !== false) {\n const meta = await metadata(scope);\n out.metadata = renderMetadataBlock(meta);\n }\n out.base = composeLayer1(localePack, resolved.memoryBaseMode);\n return Object.freeze(out);\n }\n\n async function metadata(scope: SessionScope): Promise<MemoryMetadata> {\n return gatherMemoryMetadata(scope, {\n store: options.store,\n consolidator,\n embedderId: embedderIdProvider,\n localeId: resolved.localeId,\n });\n }\n\n return Object.freeze({\n working,\n session,\n episodic,\n semantic,\n procedural,\n shared,\n insights,\n tools,\n consolidator,\n conflictPipeline,\n contextEngine,\n embedder,\n embedderId: embedderIdProvider,\n compile,\n metadata,\n });\n}\n\nfunction renderWorkingBlocksXml(\n blocks: ReadonlyArray<{\n readonly label: string;\n readonly value: string;\n readonly description?: string;\n }>,\n): string {\n if (blocks.length === 0) return '';\n const lines = ['<memory_blocks>'];\n for (const block of blocks) {\n const description =\n block.description !== undefined ? ` description=\"${escapeXml(block.description)}\"` : '';\n lines.push(` <block label=\"${escapeXml(block.label)}\"${description}>`);\n lines.push(` ${escapeXml(block.value)}`);\n lines.push(' </block>');\n }\n lines.push('</memory_blocks>');\n return lines.join('\\n');\n}\n\nfunction escapeXml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nfunction buildConsolidator(\n opts: CreateMemoryOptions['consolidator'],\n store: CreateMemoryOptions['store'],\n semantic: SemanticMemory,\n episodic: EpisodicMemory,\n working: WorkingMemory,\n tracer: Tracer,\n): Consolidator {\n if (opts === undefined) {\n return createConsolidatorPlaceholder();\n }\n const enabled = shouldEnableConsolidator(opts);\n if (!enabled) {\n return createConsolidatorPlaceholder({\n ...(opts.triggers !== undefined ? { triggers: opts.triggers } : {}),\n ...(opts.tier !== undefined ? { tier: opts.tier } : {}),\n });\n }\n const consolidator = createConsolidator({\n store,\n semantic,\n episodic,\n working,\n tracer,\n ...(opts.provider !== undefined ? { provider: opts.provider } : {}),\n ...(opts.now !== undefined ? { now: opts.now } : {}),\n ...(opts.randomId !== undefined ? { randomId: opts.randomId } : {}),\n ...(opts.triggers !== undefined ? { triggers: opts.triggers } : {}),\n ...(opts.tier !== undefined ? { tier: opts.tier } : {}),\n ...(opts.phases !== undefined ? { phases: opts.phases } : {}),\n ...(opts.ceilings !== undefined ? { ceilings: opts.ceilings } : {}),\n ...(opts.onExceed !== undefined ? { onExceed: opts.onExceed } : {}),\n ...(opts.priceUsage !== undefined ? { priceUsage: opts.priceUsage } : {}),\n ...(opts.cheapProvider !== undefined ? { cheapProvider: opts.cheapProvider } : {}),\n ...(opts.deepProvider !== undefined ? { deepProvider: opts.deepProvider } : {}),\n ...(opts.cheapModel !== undefined ? { cheapModel: opts.cheapModel } : {}),\n ...(opts.deepModel !== undefined ? { deepModel: opts.deepModel } : {}),\n ...(opts.noiseFilters !== undefined ? { noiseFilters: opts.noiseFilters } : {}),\n ...(opts.lockWaitMs !== undefined ? { lockWaitMs: opts.lockWaitMs } : {}),\n ...(opts.decayTauDays !== undefined ? { decayTauDays: opts.decayTauDays } : {}),\n ...(opts.decayArchiveThreshold !== undefined\n ? { decayArchiveThreshold: opts.decayArchiveThreshold }\n : {}),\n ...(opts.decayCapacity !== undefined ? { decayCapacity: opts.decayCapacity } : {}),\n ...(opts.salienceWeights !== undefined ? { salienceWeights: opts.salienceWeights } : {}),\n ...(opts.maxStandardBatchSize !== undefined\n ? { maxStandardBatchSize: opts.maxStandardBatchSize }\n : {}),\n ...(opts.maxDeepConflictsPerRun !== undefined\n ? { maxDeepConflictsPerRun: opts.maxDeepConflictsPerRun }\n : {}),\n ...(opts.dlqMaxRetries !== undefined ? { dlqMaxRetries: opts.dlqMaxRetries } : {}),\n ...(opts.dlqBaseBackoffMs !== undefined ? { dlqBaseBackoffMs: opts.dlqBaseBackoffMs } : {}),\n ...(opts.dlqMaxBackoffMs !== undefined ? { dlqMaxBackoffMs: opts.dlqMaxBackoffMs } : {}),\n ...(opts.formEpisodes !== undefined ? { formEpisodes: opts.formEpisodes } : {}),\n ...(opts.importanceScoring !== undefined ? { importanceScoring: opts.importanceScoring } : {}),\n ...(opts.autoPromoteExtraction !== undefined\n ? { autoPromoteExtraction: opts.autoPromoteExtraction }\n : {}),\n ...(opts.reflection !== undefined ? { reflection: opts.reflection } : {}),\n ...(opts.importanceThreshold !== undefined\n ? { importanceThreshold: opts.importanceThreshold }\n : {}),\n ...(opts.reflectionMaxQuestions !== undefined\n ? { reflectionMaxQuestions: opts.reflectionMaxQuestions }\n : {}),\n ...(opts.contextualRetrieval !== undefined\n ? { contextualRetrieval: opts.contextualRetrieval }\n : {}),\n ...(opts.learnedContext !== undefined ? { learnedContext: opts.learnedContext } : {}),\n ...(opts.learnedContextMaxChars !== undefined\n ? { learnedContextMaxChars: opts.learnedContextMaxChars }\n : {}),\n ...(opts.defaultScope !== undefined ? { defaultScope: opts.defaultScope } : {}),\n });\n if (opts.onPhaseFinished !== undefined) {\n consolidator.onPhaseFinished(opts.onPhaseFinished);\n }\n return consolidator;\n}\n\nlet consolidatorConfigIgnoredWarned = false;\n\n/** @internal - test seam for the one-time disabled-config warning. */\nexport function _resetConsolidatorConfigWarningForTesting(): void {\n consolidatorConfigIgnoredWarned = false;\n}\n\nfunction shouldEnableConsolidator(opts: NonNullable<CreateMemoryOptions['consolidator']>): boolean {\n // MST-4: ANY non-empty consolidator config implicitly enables - the old\n // allow-list silently ignored offline knobs (`decayCapacity`,\n // `formEpisodes`, `reflection`, `contextualRetrieval`, …): the caller\n // got a no-op placeholder while believing the feature was on.\n const keys = Object.keys(opts).filter(\n (k) => k !== 'enabled' && (opts as Record<string, unknown>)[k] !== undefined,\n );\n if (opts.enabled === false) {\n if (keys.length > 0 && !consolidatorConfigIgnoredWarned) {\n consolidatorConfigIgnoredWarned = true;\n process.stderr.write(\n `[graphorin/memory] consolidator config (${keys.join(', ')}) was supplied together with enabled: false - the settings are ignored until the consolidator is enabled.\\n`,\n );\n }\n return false;\n }\n if (opts.enabled === true) return true;\n return keys.length > 0;\n}\n"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { EmbedderProvider, Fact, Provider, ProviderRequest, SessionScope } from
|
|
|
5
5
|
|
|
6
6
|
/** Cosine `≥` this auto-reuses an existing entity (embedding match). */
|
|
7
7
|
declare const DEFAULT_MERGE_THRESHOLD = 0.92;
|
|
8
|
-
/** Cosine in `[this, merge)` is *ambiguous*
|
|
8
|
+
/** Cosine in `[this, merge)` is *ambiguous* - adjudicate or mint new. */
|
|
9
9
|
declare const DEFAULT_ADJUDICATE_THRESHOLD = 0.82;
|
|
10
10
|
/**
|
|
11
11
|
* Outcome of the pure resolution policy. `match` reuses an existing
|
|
@@ -34,7 +34,7 @@ interface ResolutionCandidate {
|
|
|
34
34
|
/**
|
|
35
35
|
* MST-11: the embedder that produced `vector`. When both this and the
|
|
36
36
|
* query's `vectorEmbedderId` are known and differ, the candidate is skipped
|
|
37
|
-
* for embedding comparison
|
|
37
|
+
* for embedding comparison - vectors from different models live in different
|
|
38
38
|
* spaces, so their cosine is meaningless. Absent on either side ⇒ compared
|
|
39
39
|
* (byte-identical to the prior behaviour).
|
|
40
40
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/graph/entity-resolver.ts
|
|
2
2
|
/** Cosine `≥` this auto-reuses an existing entity (embedding match). */
|
|
3
3
|
const DEFAULT_MERGE_THRESHOLD = .92;
|
|
4
|
-
/** Cosine in `[this, merge)` is *ambiguous*
|
|
4
|
+
/** Cosine in `[this, merge)` is *ambiguous* - adjudicate or mint new. */
|
|
5
5
|
const DEFAULT_ADJUDICATE_THRESHOLD = .82;
|
|
6
6
|
/**
|
|
7
7
|
* Fold an entity surface form into a canonical lexical key: Unicode
|
|
@@ -76,7 +76,7 @@ function resolveEntityDecision(input) {
|
|
|
76
76
|
};
|
|
77
77
|
return { kind: "new" };
|
|
78
78
|
}
|
|
79
|
-
const ADJUDICATION_SYSTEM_PROMPT = "You decide whether two short names refer to the SAME real-world entity (person, place, org, thing). Reply with a single word: \"yes\" or \"no\". Be conservative
|
|
79
|
+
const ADJUDICATION_SYSTEM_PROMPT = "You decide whether two short names refer to the SAME real-world entity (person, place, org, thing). Reply with a single word: \"yes\" or \"no\". Be conservative - answer \"no\" unless they are clearly the same entity.";
|
|
80
80
|
/** Build the (pure) adjudication request. Exposed for testing. */
|
|
81
81
|
function buildAdjudicationRequest(nameA, nameB, options = {}) {
|
|
82
82
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-resolver.js","names":["bestId: string | null","#store","#embedder","#embedderId","#provider","#mergeThreshold","#adjudicateThreshold","#llmAdjudication","#embed","#create","#adjudicate"],"sources":["../../src/graph/entity-resolver.ts"],"sourcesContent":["/**\n * Entity resolution for the lightweight in-SQLite relation graph (P2-1).\n *\n * Raw `subject` / `object` strings on facts fragment (\"Anna\", \"Anna S.\",\n * \"my sister\" become unrelated rows), which kills multi-hop recall. This\n * module folds them into **canonical entities** so the one-hop CTE can\n * traverse relationships. Resolution is layered, cheapest first:\n *\n * 1. **lexical** — exact match on the folded {@link normalizeEntityName}.\n * 2. **embedding** — cosine over candidate name vectors; `≥ mergeThreshold`\n * reuses the match.\n * 3. **adjudication** — a middle similarity band (`[adjudicate, merge)`)\n * is *ambiguous*; an opt-in LLM call (provider + `llmAdjudication`)\n * decides. **Offline / by default the ambiguous band mints a new\n * entity** — the resolver never auto-merges on weak evidence, because\n * a wrong merge fuses two distinct people (the stated P2-1 risk).\n *\n * The pure policy ({@link resolveEntityDecision}) is provider-agnostic and\n * does no I/O; {@link EntityResolver} wires it to an injected store +\n * embedder + optional provider. With no embedder it degrades to\n * lexical-only — still useful, and still fully offline.\n *\n * @packageDocumentation\n */\n\nimport type {\n EmbedderProvider,\n Fact,\n Provider,\n ProviderRequest,\n SessionScope,\n} from '@graphorin/core';\nimport type { EntityWithEmbedding, GraphMemoryStoreExt } from '../internal/storage-adapter.js';\n\n/** Cosine `≥` this auto-reuses an existing entity (embedding match). */\nexport const DEFAULT_MERGE_THRESHOLD = 0.92;\n/** Cosine in `[this, merge)` is *ambiguous* — adjudicate or mint new. */\nexport const DEFAULT_ADJUDICATE_THRESHOLD = 0.82;\n\n/**\n * Outcome of the pure resolution policy. `match` reuses an existing\n * entity; `ambiguous` flags a middle-similarity candidate for the caller\n * to adjudicate (or conservatively reject); `new` mints a fresh entity.\n *\n * @stable\n */\nexport type EntityResolveDecision =\n | {\n readonly kind: 'match';\n readonly entityId: string;\n readonly similarity: number;\n readonly via: 'lexical' | 'embedding';\n }\n | { readonly kind: 'ambiguous'; readonly entityId: string; readonly similarity: number }\n | { readonly kind: 'new' };\n\n/** Minimal candidate shape the pure policy compares against. */\nexport interface ResolutionCandidate {\n readonly id: string;\n readonly normalizedName: string;\n readonly vector: Float32Array | null;\n /**\n * MST-11: the embedder that produced `vector`. When both this and the\n * query's `vectorEmbedderId` are known and differ, the candidate is skipped\n * for embedding comparison — vectors from different models live in different\n * spaces, so their cosine is meaningless. Absent on either side ⇒ compared\n * (byte-identical to the prior behaviour).\n */\n readonly embedderId?: string | null;\n}\n\n/** Inputs to {@link resolveEntityDecision} (all provided by the caller). */\nexport interface ResolveDecisionInput {\n readonly normalizedName: string;\n readonly vector?: Float32Array | null;\n /** MST-11: the embedder that produced `vector` (gates cross-embedder cosine). */\n readonly vectorEmbedderId?: string | null;\n readonly candidates: ReadonlyArray<ResolutionCandidate>;\n readonly mergeThreshold: number;\n readonly adjudicateThreshold: number;\n}\n\n/**\n * Fold an entity surface form into a canonical lexical key: Unicode\n * NFKC, lowercased, internal whitespace collapsed, surrounding\n * punctuation stripped. `\" Anna S. \"` → `\"anna s\"`. Returns `''` for a\n * name with no letters/digits (the resolver treats that as \"no entity\").\n *\n * @stable\n */\nexport function normalizeEntityName(name: string): string {\n return name\n .normalize('NFKC')\n .toLowerCase()\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/^[^\\p{L}\\p{N}]+|[^\\p{L}\\p{N}]+$/gu, '');\n}\n\n/**\n * Cosine similarity of two embeddings in `[-1, 1]`. Compares over the\n * shorter length and returns `0` when either vector is empty / zero-norm.\n *\n * @stable\n */\nexport function cosineSimilarity(a: Float32Array, b: Float32Array): number {\n const len = Math.min(a.length, b.length);\n let dot = 0;\n let na = 0;\n let nb = 0;\n for (let i = 0; i < len; i++) {\n const ai = a[i] ?? 0;\n const bi = b[i] ?? 0;\n dot += ai * bi;\n na += ai * ai;\n nb += bi * bi;\n }\n if (na === 0 || nb === 0) return 0;\n return dot / Math.sqrt(na * nb);\n}\n\n/**\n * Pure resolution policy: lexical exact match → embedding cosine →\n * ambiguous band → new. No I/O; deterministic. The caller decides what\n * to do with `ambiguous` (LLM adjudicate, or conservatively mint new).\n *\n * @stable\n */\nexport function resolveEntityDecision(input: ResolveDecisionInput): EntityResolveDecision {\n // 1. Exact lexical match is the cheapest + strongest signal.\n for (const c of input.candidates) {\n if (c.normalizedName === input.normalizedName) {\n return { kind: 'match', entityId: c.id, similarity: 1, via: 'lexical' };\n }\n }\n // 2. Embedding similarity (only when both sides have a vector).\n const v = input.vector;\n if (v === undefined || v === null || v.length === 0) return { kind: 'new' };\n let bestId: string | null = null;\n let bestSim = Number.NEGATIVE_INFINITY;\n for (const c of input.candidates) {\n if (c.vector === null || c.vector.length === 0) continue;\n // MST-11: never compare vectors across embedders — different models live\n // in different vector spaces, so their cosine is meaningless. Skip only\n // when both embedder ids are known and differ.\n if (\n input.vectorEmbedderId != null &&\n c.embedderId != null &&\n c.embedderId !== input.vectorEmbedderId\n ) {\n continue;\n }\n const sim = cosineSimilarity(v, c.vector);\n if (sim > bestSim) {\n bestSim = sim;\n bestId = c.id;\n }\n }\n if (bestId === null) return { kind: 'new' };\n if (bestSim >= input.mergeThreshold) {\n return { kind: 'match', entityId: bestId, similarity: bestSim, via: 'embedding' };\n }\n if (bestSim >= input.adjudicateThreshold) {\n return { kind: 'ambiguous', entityId: bestId, similarity: bestSim };\n }\n return { kind: 'new' };\n}\n\n/** Tunable thresholds + LLM-adjudication switch for {@link EntityResolver}. */\nexport interface EntityResolutionConfig {\n /** Cosine `≥` this auto-reuses a match. Default {@link DEFAULT_MERGE_THRESHOLD}. */\n readonly mergeThreshold?: number;\n /** Cosine in `[this, merge)` is ambiguous. Default {@link DEFAULT_ADJUDICATE_THRESHOLD}. */\n readonly adjudicateThreshold?: number;\n /**\n * Resolve the ambiguous band with one provider call. Requires a\n * `provider`. Default `false` ⇒ ambiguous mints a new entity (no\n * network call; never auto-merges on weak evidence).\n */\n readonly llmAdjudication?: boolean;\n}\n\n/** Construction deps for {@link EntityResolver}. */\nexport interface EntityResolverDeps {\n readonly store: GraphMemoryStoreExt;\n readonly embedder?: EmbedderProvider | null;\n readonly embedderId?: () => string | null;\n readonly provider?: Provider | null;\n readonly config?: EntityResolutionConfig;\n}\n\nconst ADJUDICATION_SYSTEM_PROMPT =\n 'You decide whether two short names refer to the SAME real-world entity ' +\n '(person, place, org, thing). Reply with a single word: \"yes\" or \"no\". ' +\n 'Be conservative — answer \"no\" unless they are clearly the same entity.';\n\n/** Build the (pure) adjudication request. Exposed for testing. */\nexport function buildAdjudicationRequest(\n nameA: string,\n nameB: string,\n options: { readonly signal?: AbortSignal } = {},\n): ProviderRequest {\n return {\n messages: [{ role: 'user', content: `Name A: ${nameA}\\nName B: ${nameB}\\nSame entity?` }],\n systemMessage: ADJUDICATION_SYSTEM_PROMPT,\n temperature: 0,\n maxTokens: 4,\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n };\n}\n\n/** Parse a yes/no adjudication reply. Conservative: only a clear yes is `true`. */\nexport function parseAdjudication(text: string): boolean {\n return /^\\s*(yes|true|same)\\b/i.test(text);\n}\n\n/**\n * Resolves a fact's subject / object strings to canonical entity ids and\n * links them, applying {@link resolveEntityDecision} backed by an\n * injected store + embedder (+ optional provider for adjudication).\n * Constructed only when entity resolution is opted in\n * (`createMemory({ graph: { entityResolution: true } })`); otherwise the\n * write path skips it and behaviour is unchanged + offline.\n *\n * @stable\n */\nexport class EntityResolver {\n readonly #store: GraphMemoryStoreExt;\n readonly #embedder: EmbedderProvider | null;\n readonly #embedderId: () => string | null;\n readonly #provider: Provider | null;\n readonly #mergeThreshold: number;\n readonly #adjudicateThreshold: number;\n readonly #llmAdjudication: boolean;\n\n constructor(deps: EntityResolverDeps) {\n this.#store = deps.store;\n this.#embedder = deps.embedder ?? null;\n this.#embedderId = deps.embedderId ?? (() => null);\n this.#provider = deps.provider ?? null;\n this.#mergeThreshold = deps.config?.mergeThreshold ?? DEFAULT_MERGE_THRESHOLD;\n this.#adjudicateThreshold = deps.config?.adjudicateThreshold ?? DEFAULT_ADJUDICATE_THRESHOLD;\n this.#llmAdjudication = deps.config?.llmAdjudication ?? false;\n }\n\n /**\n * Resolve a single name to a canonical entity id (find-or-create),\n * deduping via lexical + embedding similarity. Returns `null` for a\n * name that normalizes to empty (no entity).\n */\n async resolve(\n scope: SessionScope,\n rawName: string,\n opts: { readonly signal?: AbortSignal } = {},\n ): Promise<string | null> {\n const normalizedName = normalizeEntityName(rawName);\n if (normalizedName.length === 0) return null;\n // 1. Exact lexical match — the cheapest, strongest signal. Resolve it via\n // an uncapped indexed lookup so an alias of an arbitrarily-old entity\n // dedups without scanning (and deserializing) the bounded candidate\n // window, and short-circuits before any embedding call (CS-11). Stores\n // that don't implement it fall through to the capped lexical scan below.\n const exact = await this.#store.findEntityByNormalizedName?.(scope, normalizedName);\n if (exact != null) return exact.id;\n const vector = await this.#embed(rawName, opts.signal);\n // 2. Without a query vector, embedding dedup is impossible — skip the\n // BLOB-deserializing candidate scan entirely and mint a new entity.\n if (vector === null || vector.length === 0) {\n return this.#create(scope, rawName, normalizedName, vector);\n }\n const candidates = await this.#store.listEntities(scope);\n const decision = resolveEntityDecision({\n normalizedName,\n vector,\n vectorEmbedderId: this.#embedderId(),\n candidates,\n mergeThreshold: this.#mergeThreshold,\n adjudicateThreshold: this.#adjudicateThreshold,\n });\n if (decision.kind === 'match') return decision.entityId;\n if (decision.kind === 'ambiguous') {\n if (this.#llmAdjudication && this.#provider !== null) {\n const same = await this.#adjudicate(rawName, decision.entityId, candidates, opts.signal);\n if (same) return decision.entityId;\n }\n // Conservative default: weak evidence ⇒ a distinct new entity.\n }\n return this.#create(scope, rawName, normalizedName, vector);\n }\n\n /**\n * Resolve + link a fact's subject and object (the predicate is a\n * relation label, never an entity). Idempotent on re-link.\n */\n async linkFact(\n scope: SessionScope,\n fact: Fact,\n opts: { readonly signal?: AbortSignal } = {},\n ): Promise<void> {\n if (fact.subject !== undefined) {\n const id = await this.resolve(scope, fact.subject, opts);\n if (id !== null) await this.#store.linkFactEntity(fact.id, id, 'subject');\n }\n if (fact.object !== undefined) {\n const id = await this.resolve(scope, fact.object, opts);\n if (id !== null) await this.#store.linkFactEntity(fact.id, id, 'object');\n }\n }\n\n async #embed(name: string, signal?: AbortSignal): Promise<Float32Array | null> {\n const embedder = this.#embedder;\n if (embedder === null || this.#embedderId() === null) return null;\n void signal;\n try {\n const [vector] = await embedder.embed([name]);\n return vector ?? null;\n } catch {\n return null;\n }\n }\n\n async #create(\n scope: SessionScope,\n name: string,\n normalizedName: string,\n vector: Float32Array | null,\n ): Promise<string> {\n const embedderId = this.#embedderId();\n return this.#store.upsertEntity(scope, {\n name,\n normalizedName,\n ...(vector !== null ? { vector } : {}),\n ...(vector !== null && embedderId !== null ? { embedderId } : {}),\n });\n }\n\n async #adjudicate(\n name: string,\n candidateId: string,\n candidates: ReadonlyArray<EntityWithEmbedding>,\n signal?: AbortSignal,\n ): Promise<boolean> {\n const provider = this.#provider;\n if (provider === null) return false;\n const candidate = candidates.find((c) => c.id === candidateId);\n if (candidate === undefined) return false;\n try {\n const request = buildAdjudicationRequest(name, candidate.name, {\n ...(signal !== undefined ? { signal } : {}),\n });\n const response = await provider.generate(request);\n return parseAdjudication(response.text ?? '');\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entity-resolver.js","names":["bestId: string | null","#store","#embedder","#embedderId","#provider","#mergeThreshold","#adjudicateThreshold","#llmAdjudication","#embed","#create","#adjudicate"],"sources":["../../src/graph/entity-resolver.ts"],"sourcesContent":["/**\n * Entity resolution for the lightweight in-SQLite relation graph (P2-1).\n *\n * Raw `subject` / `object` strings on facts fragment (\"Anna\", \"Anna S.\",\n * \"my sister\" become unrelated rows), which kills multi-hop recall. This\n * module folds them into **canonical entities** so the one-hop CTE can\n * traverse relationships. Resolution is layered, cheapest first:\n *\n * 1. **lexical** - exact match on the folded {@link normalizeEntityName}.\n * 2. **embedding** - cosine over candidate name vectors; `≥ mergeThreshold`\n * reuses the match.\n * 3. **adjudication** - a middle similarity band (`[adjudicate, merge)`)\n * is *ambiguous*; an opt-in LLM call (provider + `llmAdjudication`)\n * decides. **Offline / by default the ambiguous band mints a new\n * entity** - the resolver never auto-merges on weak evidence, because\n * a wrong merge fuses two distinct people (the stated P2-1 risk).\n *\n * The pure policy ({@link resolveEntityDecision}) is provider-agnostic and\n * does no I/O; {@link EntityResolver} wires it to an injected store +\n * embedder + optional provider. With no embedder it degrades to\n * lexical-only - still useful, and still fully offline.\n *\n * @packageDocumentation\n */\n\nimport type {\n EmbedderProvider,\n Fact,\n Provider,\n ProviderRequest,\n SessionScope,\n} from '@graphorin/core';\nimport type { EntityWithEmbedding, GraphMemoryStoreExt } from '../internal/storage-adapter.js';\n\n/** Cosine `≥` this auto-reuses an existing entity (embedding match). */\nexport const DEFAULT_MERGE_THRESHOLD = 0.92;\n/** Cosine in `[this, merge)` is *ambiguous* - adjudicate or mint new. */\nexport const DEFAULT_ADJUDICATE_THRESHOLD = 0.82;\n\n/**\n * Outcome of the pure resolution policy. `match` reuses an existing\n * entity; `ambiguous` flags a middle-similarity candidate for the caller\n * to adjudicate (or conservatively reject); `new` mints a fresh entity.\n *\n * @stable\n */\nexport type EntityResolveDecision =\n | {\n readonly kind: 'match';\n readonly entityId: string;\n readonly similarity: number;\n readonly via: 'lexical' | 'embedding';\n }\n | { readonly kind: 'ambiguous'; readonly entityId: string; readonly similarity: number }\n | { readonly kind: 'new' };\n\n/** Minimal candidate shape the pure policy compares against. */\nexport interface ResolutionCandidate {\n readonly id: string;\n readonly normalizedName: string;\n readonly vector: Float32Array | null;\n /**\n * MST-11: the embedder that produced `vector`. When both this and the\n * query's `vectorEmbedderId` are known and differ, the candidate is skipped\n * for embedding comparison - vectors from different models live in different\n * spaces, so their cosine is meaningless. Absent on either side ⇒ compared\n * (byte-identical to the prior behaviour).\n */\n readonly embedderId?: string | null;\n}\n\n/** Inputs to {@link resolveEntityDecision} (all provided by the caller). */\nexport interface ResolveDecisionInput {\n readonly normalizedName: string;\n readonly vector?: Float32Array | null;\n /** MST-11: the embedder that produced `vector` (gates cross-embedder cosine). */\n readonly vectorEmbedderId?: string | null;\n readonly candidates: ReadonlyArray<ResolutionCandidate>;\n readonly mergeThreshold: number;\n readonly adjudicateThreshold: number;\n}\n\n/**\n * Fold an entity surface form into a canonical lexical key: Unicode\n * NFKC, lowercased, internal whitespace collapsed, surrounding\n * punctuation stripped. `\" Anna S. \"` → `\"anna s\"`. Returns `''` for a\n * name with no letters/digits (the resolver treats that as \"no entity\").\n *\n * @stable\n */\nexport function normalizeEntityName(name: string): string {\n return name\n .normalize('NFKC')\n .toLowerCase()\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/^[^\\p{L}\\p{N}]+|[^\\p{L}\\p{N}]+$/gu, '');\n}\n\n/**\n * Cosine similarity of two embeddings in `[-1, 1]`. Compares over the\n * shorter length and returns `0` when either vector is empty / zero-norm.\n *\n * @stable\n */\nexport function cosineSimilarity(a: Float32Array, b: Float32Array): number {\n const len = Math.min(a.length, b.length);\n let dot = 0;\n let na = 0;\n let nb = 0;\n for (let i = 0; i < len; i++) {\n const ai = a[i] ?? 0;\n const bi = b[i] ?? 0;\n dot += ai * bi;\n na += ai * ai;\n nb += bi * bi;\n }\n if (na === 0 || nb === 0) return 0;\n return dot / Math.sqrt(na * nb);\n}\n\n/**\n * Pure resolution policy: lexical exact match → embedding cosine →\n * ambiguous band → new. No I/O; deterministic. The caller decides what\n * to do with `ambiguous` (LLM adjudicate, or conservatively mint new).\n *\n * @stable\n */\nexport function resolveEntityDecision(input: ResolveDecisionInput): EntityResolveDecision {\n // 1. Exact lexical match is the cheapest + strongest signal.\n for (const c of input.candidates) {\n if (c.normalizedName === input.normalizedName) {\n return { kind: 'match', entityId: c.id, similarity: 1, via: 'lexical' };\n }\n }\n // 2. Embedding similarity (only when both sides have a vector).\n const v = input.vector;\n if (v === undefined || v === null || v.length === 0) return { kind: 'new' };\n let bestId: string | null = null;\n let bestSim = Number.NEGATIVE_INFINITY;\n for (const c of input.candidates) {\n if (c.vector === null || c.vector.length === 0) continue;\n // MST-11: never compare vectors across embedders - different models live\n // in different vector spaces, so their cosine is meaningless. Skip only\n // when both embedder ids are known and differ.\n if (\n input.vectorEmbedderId != null &&\n c.embedderId != null &&\n c.embedderId !== input.vectorEmbedderId\n ) {\n continue;\n }\n const sim = cosineSimilarity(v, c.vector);\n if (sim > bestSim) {\n bestSim = sim;\n bestId = c.id;\n }\n }\n if (bestId === null) return { kind: 'new' };\n if (bestSim >= input.mergeThreshold) {\n return { kind: 'match', entityId: bestId, similarity: bestSim, via: 'embedding' };\n }\n if (bestSim >= input.adjudicateThreshold) {\n return { kind: 'ambiguous', entityId: bestId, similarity: bestSim };\n }\n return { kind: 'new' };\n}\n\n/** Tunable thresholds + LLM-adjudication switch for {@link EntityResolver}. */\nexport interface EntityResolutionConfig {\n /** Cosine `≥` this auto-reuses a match. Default {@link DEFAULT_MERGE_THRESHOLD}. */\n readonly mergeThreshold?: number;\n /** Cosine in `[this, merge)` is ambiguous. Default {@link DEFAULT_ADJUDICATE_THRESHOLD}. */\n readonly adjudicateThreshold?: number;\n /**\n * Resolve the ambiguous band with one provider call. Requires a\n * `provider`. Default `false` ⇒ ambiguous mints a new entity (no\n * network call; never auto-merges on weak evidence).\n */\n readonly llmAdjudication?: boolean;\n}\n\n/** Construction deps for {@link EntityResolver}. */\nexport interface EntityResolverDeps {\n readonly store: GraphMemoryStoreExt;\n readonly embedder?: EmbedderProvider | null;\n readonly embedderId?: () => string | null;\n readonly provider?: Provider | null;\n readonly config?: EntityResolutionConfig;\n}\n\nconst ADJUDICATION_SYSTEM_PROMPT =\n 'You decide whether two short names refer to the SAME real-world entity ' +\n '(person, place, org, thing). Reply with a single word: \"yes\" or \"no\". ' +\n 'Be conservative - answer \"no\" unless they are clearly the same entity.';\n\n/** Build the (pure) adjudication request. Exposed for testing. */\nexport function buildAdjudicationRequest(\n nameA: string,\n nameB: string,\n options: { readonly signal?: AbortSignal } = {},\n): ProviderRequest {\n return {\n messages: [{ role: 'user', content: `Name A: ${nameA}\\nName B: ${nameB}\\nSame entity?` }],\n systemMessage: ADJUDICATION_SYSTEM_PROMPT,\n temperature: 0,\n maxTokens: 4,\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n };\n}\n\n/** Parse a yes/no adjudication reply. Conservative: only a clear yes is `true`. */\nexport function parseAdjudication(text: string): boolean {\n return /^\\s*(yes|true|same)\\b/i.test(text);\n}\n\n/**\n * Resolves a fact's subject / object strings to canonical entity ids and\n * links them, applying {@link resolveEntityDecision} backed by an\n * injected store + embedder (+ optional provider for adjudication).\n * Constructed only when entity resolution is opted in\n * (`createMemory({ graph: { entityResolution: true } })`); otherwise the\n * write path skips it and behaviour is unchanged + offline.\n *\n * @stable\n */\nexport class EntityResolver {\n readonly #store: GraphMemoryStoreExt;\n readonly #embedder: EmbedderProvider | null;\n readonly #embedderId: () => string | null;\n readonly #provider: Provider | null;\n readonly #mergeThreshold: number;\n readonly #adjudicateThreshold: number;\n readonly #llmAdjudication: boolean;\n\n constructor(deps: EntityResolverDeps) {\n this.#store = deps.store;\n this.#embedder = deps.embedder ?? null;\n this.#embedderId = deps.embedderId ?? (() => null);\n this.#provider = deps.provider ?? null;\n this.#mergeThreshold = deps.config?.mergeThreshold ?? DEFAULT_MERGE_THRESHOLD;\n this.#adjudicateThreshold = deps.config?.adjudicateThreshold ?? DEFAULT_ADJUDICATE_THRESHOLD;\n this.#llmAdjudication = deps.config?.llmAdjudication ?? false;\n }\n\n /**\n * Resolve a single name to a canonical entity id (find-or-create),\n * deduping via lexical + embedding similarity. Returns `null` for a\n * name that normalizes to empty (no entity).\n */\n async resolve(\n scope: SessionScope,\n rawName: string,\n opts: { readonly signal?: AbortSignal } = {},\n ): Promise<string | null> {\n const normalizedName = normalizeEntityName(rawName);\n if (normalizedName.length === 0) return null;\n // 1. Exact lexical match - the cheapest, strongest signal. Resolve it via\n // an uncapped indexed lookup so an alias of an arbitrarily-old entity\n // dedups without scanning (and deserializing) the bounded candidate\n // window, and short-circuits before any embedding call (CS-11). Stores\n // that don't implement it fall through to the capped lexical scan below.\n const exact = await this.#store.findEntityByNormalizedName?.(scope, normalizedName);\n if (exact != null) return exact.id;\n const vector = await this.#embed(rawName, opts.signal);\n // 2. Without a query vector, embedding dedup is impossible - skip the\n // BLOB-deserializing candidate scan entirely and mint a new entity.\n if (vector === null || vector.length === 0) {\n return this.#create(scope, rawName, normalizedName, vector);\n }\n const candidates = await this.#store.listEntities(scope);\n const decision = resolveEntityDecision({\n normalizedName,\n vector,\n vectorEmbedderId: this.#embedderId(),\n candidates,\n mergeThreshold: this.#mergeThreshold,\n adjudicateThreshold: this.#adjudicateThreshold,\n });\n if (decision.kind === 'match') return decision.entityId;\n if (decision.kind === 'ambiguous') {\n if (this.#llmAdjudication && this.#provider !== null) {\n const same = await this.#adjudicate(rawName, decision.entityId, candidates, opts.signal);\n if (same) return decision.entityId;\n }\n // Conservative default: weak evidence ⇒ a distinct new entity.\n }\n return this.#create(scope, rawName, normalizedName, vector);\n }\n\n /**\n * Resolve + link a fact's subject and object (the predicate is a\n * relation label, never an entity). Idempotent on re-link.\n */\n async linkFact(\n scope: SessionScope,\n fact: Fact,\n opts: { readonly signal?: AbortSignal } = {},\n ): Promise<void> {\n if (fact.subject !== undefined) {\n const id = await this.resolve(scope, fact.subject, opts);\n if (id !== null) await this.#store.linkFactEntity(fact.id, id, 'subject');\n }\n if (fact.object !== undefined) {\n const id = await this.resolve(scope, fact.object, opts);\n if (id !== null) await this.#store.linkFactEntity(fact.id, id, 'object');\n }\n }\n\n async #embed(name: string, signal?: AbortSignal): Promise<Float32Array | null> {\n const embedder = this.#embedder;\n if (embedder === null || this.#embedderId() === null) return null;\n void signal;\n try {\n const [vector] = await embedder.embed([name]);\n return vector ?? null;\n } catch {\n return null;\n }\n }\n\n async #create(\n scope: SessionScope,\n name: string,\n normalizedName: string,\n vector: Float32Array | null,\n ): Promise<string> {\n const embedderId = this.#embedderId();\n return this.#store.upsertEntity(scope, {\n name,\n normalizedName,\n ...(vector !== null ? { vector } : {}),\n ...(vector !== null && embedderId !== null ? { embedderId } : {}),\n });\n }\n\n async #adjudicate(\n name: string,\n candidateId: string,\n candidates: ReadonlyArray<EntityWithEmbedding>,\n signal?: AbortSignal,\n ): Promise<boolean> {\n const provider = this.#provider;\n if (provider === null) return false;\n const candidate = candidates.find((c) => c.id === candidateId);\n if (candidate === undefined) return false;\n try {\n const request = buildAdjudicationRequest(name, candidate.name, {\n ...(signal !== undefined ? { signal } : {}),\n });\n const response = await provider.generate(request);\n return parseAdjudication(response.text ?? '');\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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"}
|