@graphorin/memory 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +83 -0
- package/README.md +24 -7
- package/dist/conflict/index.js +0 -1
- package/dist/conflict/pipeline.js +0 -1
- package/dist/conflict/pipeline.js.map +1 -1
- package/dist/conflict/stages/stage3-heuristic-regex.js +0 -1
- package/dist/conflict/stages/stage3-heuristic-regex.js.map +1 -1
- package/dist/conflict/types.d.ts +1 -1
- package/dist/conflict/types.js.map +1 -1
- package/dist/consolidator/index.js +2 -0
- package/dist/consolidator/index.js.map +1 -1
- package/dist/consolidator/lock.js +7 -1
- package/dist/consolidator/lock.js.map +1 -1
- package/dist/consolidator/phases/deep.js +19 -12
- package/dist/consolidator/phases/deep.js.map +1 -1
- package/dist/consolidator/phases/induce.d.ts.map +1 -1
- package/dist/consolidator/phases/induce.js +2 -3
- package/dist/consolidator/phases/induce.js.map +1 -1
- package/dist/consolidator/phases/reflect.js +35 -8
- package/dist/consolidator/phases/reflect.js.map +1 -1
- package/dist/consolidator/phases/standard.js +199 -28
- package/dist/consolidator/phases/standard.js.map +1 -1
- package/dist/consolidator/reconcile.js +16 -15
- package/dist/consolidator/reconcile.js.map +1 -1
- package/dist/consolidator/runtime.d.ts.map +1 -1
- package/dist/consolidator/runtime.js +129 -47
- package/dist/consolidator/runtime.js.map +1 -1
- package/dist/consolidator/scheduler.d.ts +17 -3
- package/dist/consolidator/scheduler.d.ts.map +1 -1
- package/dist/consolidator/scheduler.js.map +1 -1
- package/dist/consolidator/types.d.ts +30 -1
- package/dist/consolidator/types.d.ts.map +1 -1
- package/dist/consolidator/types.js +10 -0
- package/dist/consolidator/types.js.map +1 -1
- package/dist/context-engine/compaction/clear-tool-results.d.ts +1 -1
- package/dist/context-engine/compaction/clear-tool-results.js +1 -1
- package/dist/context-engine/compaction/clear-tool-results.js.map +1 -1
- package/dist/context-engine/compaction/compactor.d.ts +1 -0
- package/dist/context-engine/compaction/compactor.d.ts.map +1 -1
- package/dist/context-engine/compaction/compactor.js +32 -8
- package/dist/context-engine/compaction/compactor.js.map +1 -1
- package/dist/context-engine/compaction/hooks/types.d.ts +1 -1
- package/dist/context-engine/compaction/index.d.ts +1 -0
- package/dist/context-engine/compaction/templates/marker.d.ts +33 -0
- package/dist/context-engine/compaction/templates/marker.d.ts.map +1 -0
- package/dist/context-engine/compaction/templates/marker.js +34 -0
- package/dist/context-engine/compaction/templates/marker.js.map +1 -0
- package/dist/context-engine/compaction/templates/summary-9-section.d.ts +1 -1
- package/dist/context-engine/compaction/templates/summary-9-section.d.ts.map +1 -1
- package/dist/context-engine/compaction/templates/summary-9-section.js +4 -3
- package/dist/context-engine/compaction/templates/summary-9-section.js.map +1 -1
- package/dist/context-engine/engine.d.ts +7 -176
- package/dist/context-engine/engine.d.ts.map +1 -1
- package/dist/context-engine/engine.js +0 -2
- package/dist/context-engine/engine.js.map +1 -1
- package/dist/context-engine/index.d.ts +8 -49
- package/dist/context-engine/io-types.d.ts +144 -0
- package/dist/context-engine/io-types.d.ts.map +1 -0
- package/dist/context-engine/locale-packs/types.d.ts +1 -1
- package/dist/context-engine/locale-packs/types.js.map +1 -1
- package/dist/context-engine/privacy-filter.d.ts +1 -2
- package/dist/context-engine/privacy-filter.d.ts.map +1 -1
- package/dist/context-engine/privacy-filter.js +1 -2
- package/dist/context-engine/privacy-filter.js.map +1 -1
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.js +2 -2
- package/dist/errors/index.js.map +1 -1
- package/dist/facade.d.ts +43 -52
- package/dist/facade.d.ts.map +1 -1
- package/dist/facade.js +5 -3
- package/dist/facade.js.map +1 -1
- package/dist/graph/entity-resolver.js +1 -1
- package/dist/graph/entity-resolver.js.map +1 -1
- package/dist/index.d.ts +17 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -7
- package/dist/index.js.map +1 -1
- package/dist/internal/envelope.js +57 -0
- package/dist/internal/envelope.js.map +1 -0
- package/dist/internal/injection-heuristics.js +0 -0
- package/dist/internal/injection-heuristics.js.map +1 -1
- package/dist/internal/llm-json.js +40 -0
- package/dist/internal/llm-json.js.map +1 -0
- package/dist/internal/storage-adapter.d.ts +23 -10
- package/dist/internal/storage-adapter.d.ts.map +1 -1
- package/dist/memory-interface.d.ts +131 -0
- package/dist/memory-interface.d.ts.map +1 -0
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/search/iterative.d.ts.map +1 -1
- package/dist/search/iterative.js +2 -3
- package/dist/search/iterative.js.map +1 -1
- package/dist/search/query-transform.d.ts.map +1 -1
- package/dist/search/query-transform.js +2 -3
- package/dist/search/query-transform.js.map +1 -1
- package/dist/tiers/episodic-memory.js +3 -3
- package/dist/tiers/episodic-memory.js.map +1 -1
- package/dist/tiers/index.d.ts +2 -2
- package/dist/tiers/insight-memory.js +1 -1
- package/dist/tiers/insight-memory.js.map +1 -1
- package/dist/tiers/procedural-memory.d.ts +1 -1
- package/dist/tiers/procedural-memory.js +2 -2
- package/dist/tiers/procedural-memory.js.map +1 -1
- package/dist/tiers/semantic-memory.d.ts +58 -4
- package/dist/tiers/semantic-memory.d.ts.map +1 -1
- package/dist/tiers/semantic-memory.js +103 -20
- package/dist/tiers/semantic-memory.js.map +1 -1
- package/dist/tools/block-tools.d.ts +19 -57
- package/dist/tools/block-tools.d.ts.map +1 -1
- package/dist/tools/block-tools.js.map +1 -1
- package/dist/tools/fact-tools.d.ts +53 -214
- package/dist/tools/fact-tools.d.ts.map +1 -1
- package/dist/tools/fact-tools.js +3 -2
- package/dist/tools/fact-tools.js.map +1 -1
- package/dist/tools/recall-tools.d.ts +34 -175
- package/dist/tools/recall-tools.d.ts.map +1 -1
- package/dist/tools/recall-tools.js +5 -4
- package/dist/tools/recall-tools.js.map +1 -1
- package/dist/tools/runbook-tools.d.ts +15 -58
- package/dist/tools/runbook-tools.d.ts.map +1 -1
- package/dist/tools/runbook-tools.js.map +1 -1
- package/dist/tools/types.d.ts +1 -1
- package/package.json +18 -17
- package/src/conflict/index.ts +29 -0
- package/src/conflict/locale-packs/en.ts +142 -0
- package/src/conflict/locale-packs/index.ts +17 -0
- package/src/conflict/locale-packs/types.ts +138 -0
- package/src/conflict/pipeline.ts +371 -0
- package/src/conflict/stages/helpers.ts +65 -0
- package/src/conflict/stages/stage1-exact-dedup.ts +40 -0
- package/src/conflict/stages/stage2-embedding-three-zone.ts +54 -0
- package/src/conflict/stages/stage3-heuristic-regex.ts +51 -0
- package/src/conflict/stages/stage4-subject-predicate.ts +46 -0
- package/src/conflict/stages/stage5-defer-to-deep.ts +34 -0
- package/src/conflict/types.ts +263 -0
- package/src/consolidator/budget.ts +312 -0
- package/src/consolidator/decay.ts +246 -0
- package/src/consolidator/dlq.ts +61 -0
- package/src/consolidator/errors.ts +87 -0
- package/src/consolidator/idempotency.ts +27 -0
- package/src/consolidator/index.ts +269 -0
- package/src/consolidator/lock.ts +141 -0
- package/src/consolidator/noise-filter.ts +235 -0
- package/src/consolidator/phases/deep.ts +308 -0
- package/src/consolidator/phases/induce.ts +423 -0
- package/src/consolidator/phases/learned-context.ts +233 -0
- package/src/consolidator/phases/light.ts +166 -0
- package/src/consolidator/phases/reflect.ts +504 -0
- package/src/consolidator/phases/standard.ts +1002 -0
- package/src/consolidator/reconcile.ts +273 -0
- package/src/consolidator/runtime.ts +1049 -0
- package/src/consolidator/scheduler.ts +182 -0
- package/src/consolidator/triggers.ts +134 -0
- package/src/consolidator/types.ts +622 -0
- package/src/context-engine/annotations.ts +161 -0
- package/src/context-engine/auto-recall.ts +92 -0
- package/src/context-engine/compaction/clear-tool-results.ts +232 -0
- package/src/context-engine/compaction/compactor.ts +403 -0
- package/src/context-engine/compaction/hooks/reanchor-persona-block.ts +55 -0
- package/src/context-engine/compaction/hooks/reanchor-pinned-facts.ts +66 -0
- package/src/context-engine/compaction/hooks/reanchor-project-rules.ts +57 -0
- package/src/context-engine/compaction/hooks/reanchor-recent-results.ts +116 -0
- package/src/context-engine/compaction/hooks/types.ts +68 -0
- package/src/context-engine/compaction/index.ts +60 -0
- package/src/context-engine/compaction/templates/marker.ts +33 -0
- package/src/context-engine/compaction/templates/summary-9-section.ts +223 -0
- package/src/context-engine/compaction/thresholds.ts +107 -0
- package/src/context-engine/compaction/types.ts +255 -0
- package/src/context-engine/engine.ts +970 -0
- package/src/context-engine/index.ts +118 -0
- package/src/context-engine/io-types.ts +162 -0
- package/src/context-engine/locale-packs/en.ts +107 -0
- package/src/context-engine/locale-packs/index.ts +19 -0
- package/src/context-engine/locale-packs/resolver.ts +197 -0
- package/src/context-engine/locale-packs/types.ts +177 -0
- package/src/context-engine/metadata.ts +114 -0
- package/src/context-engine/preambles/inbound-en.ts +19 -0
- package/src/context-engine/privacy-filter.ts +190 -0
- package/src/context-engine/templates/base-en.ts +19 -0
- package/src/context-engine/templates/composer.ts +91 -0
- package/src/context-engine/token-budget.ts +319 -0
- package/src/context-engine/token-counter.ts +157 -0
- package/src/errors/index.ts +273 -0
- package/src/facade.ts +750 -0
- package/src/graph/entity-resolver.ts +364 -0
- package/src/graph/index.ts +24 -0
- package/src/index.ts +259 -0
- package/src/internal/contextualize.ts +173 -0
- package/src/internal/embedder-binding.ts +53 -0
- package/src/internal/envelope.ts +70 -0
- package/src/internal/id.ts +23 -0
- package/src/internal/injection-heuristics.ts +0 -0
- package/src/internal/llm-json.ts +38 -0
- package/src/internal/spans.ts +35 -0
- package/src/internal/storage-adapter.ts +963 -0
- package/src/memory-interface.ts +158 -0
- package/src/migration/embedder-migration.ts +237 -0
- package/src/migration/index.ts +13 -0
- package/src/search/explain.ts +123 -0
- package/src/search/fit-weights.ts +109 -0
- package/src/search/graph-ppr.ts +38 -0
- package/src/search/index.ts +55 -0
- package/src/search/iterative.ts +658 -0
- package/src/search/query-transform.ts +285 -0
- package/src/search/rrf.ts +225 -0
- package/src/search/trust.ts +55 -0
- package/src/search/types.ts +50 -0
- package/src/tiers/episodic-memory.ts +463 -0
- package/src/tiers/index.ts +50 -0
- package/src/tiers/insight-memory.ts +208 -0
- package/src/tiers/procedural-memory.ts +482 -0
- package/src/tiers/semantic-memory.ts +1729 -0
- package/src/tiers/session-memory.ts +271 -0
- package/src/tiers/shared-memory.ts +62 -0
- package/src/tiers/working-memory.ts +368 -0
- package/src/tools/block-tools.ts +172 -0
- package/src/tools/fact-tools.ts +473 -0
- package/src/tools/index.ts +109 -0
- package/src/tools/recall-tools.ts +303 -0
- package/src/tools/runbook-tools.ts +107 -0
- package/src/tools/taint.ts +39 -0
- package/src/tools/types.ts +37 -0
- package/dist/conflict/locale-packs/index.js +0 -4
- package/dist/context-engine/compaction/index.js +0 -10
- package/dist/context-engine/index.d.ts.map +0 -1
- package/dist/context-engine/index.js +0 -25
- package/dist/context-engine/locale-packs/index.js +0 -4
package/src/facade.ts
ADDED
|
@@ -0,0 +1,750 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createMemory()` - the facade that wires every tier sub-module (the
|
|
3
|
+
* seven-tier system) + the eleven (+1 gated) memory tools + the search
|
|
4
|
+
* reranker + the context engine
|
|
5
|
+
* stubs + the consolidator placeholder.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
EmbedderProvider,
|
|
12
|
+
MemoryMetadata,
|
|
13
|
+
Provider,
|
|
14
|
+
SessionScope,
|
|
15
|
+
Tracer,
|
|
16
|
+
} from '@graphorin/core';
|
|
17
|
+
import { NOOP_TRACER } from '@graphorin/core';
|
|
18
|
+
import { type ConflictPipelineOptions, createConflictPipeline } from './conflict/index.js';
|
|
19
|
+
import {
|
|
20
|
+
type Consolidator,
|
|
21
|
+
type ConsolidatorCeilings,
|
|
22
|
+
type ConsolidatorPhase,
|
|
23
|
+
type ConsolidatorTier,
|
|
24
|
+
type ConsolidatorTriggerSpec,
|
|
25
|
+
createConsolidator,
|
|
26
|
+
createConsolidatorPlaceholder,
|
|
27
|
+
createProviderWorkflowInducer,
|
|
28
|
+
type OnBudgetExceed,
|
|
29
|
+
type PhaseListener,
|
|
30
|
+
type SalienceWeights,
|
|
31
|
+
} from './consolidator/index.js';
|
|
32
|
+
import { createContextEngine } from './context-engine/engine.js';
|
|
33
|
+
import type {
|
|
34
|
+
CompileOptions,
|
|
35
|
+
CompileScope,
|
|
36
|
+
ContextEngine,
|
|
37
|
+
ContextEngineConfig,
|
|
38
|
+
MemoryContextBlocks,
|
|
39
|
+
} from './context-engine/index.js';
|
|
40
|
+
import { enLocalePack } from './context-engine/locale-packs/index.js';
|
|
41
|
+
import { resolveLocalePack } from './context-engine/locale-packs/resolver.js';
|
|
42
|
+
import { gatherMemoryMetadata, renderMetadataBlock } from './context-engine/metadata.js';
|
|
43
|
+
import { partition as partitionBySensitivity } from './context-engine/privacy-filter.js';
|
|
44
|
+
import { composeLayer1 } from './context-engine/templates/composer.js';
|
|
45
|
+
import { type EntityResolutionConfig, EntityResolver } from './graph/entity-resolver.js';
|
|
46
|
+
import type { ContextualRetrievalMode } from './internal/contextualize.js';
|
|
47
|
+
import { bindEmbedder } from './internal/embedder-binding.js';
|
|
48
|
+
import type { EmbeddingMetaRegistryLike, MemoryStoreAdapter } from './internal/storage-adapter.js';
|
|
49
|
+
import type { Memory } from './memory-interface.js';
|
|
50
|
+
import { createProviderRetrievalGrader } from './search/iterative.js';
|
|
51
|
+
import { createProviderQueryTransformer } from './search/query-transform.js';
|
|
52
|
+
import { RRFReranker } from './search/rrf.js';
|
|
53
|
+
import type { ReRanker } from './search/types.js';
|
|
54
|
+
import { EpisodicMemory } from './tiers/episodic-memory.js';
|
|
55
|
+
import { InsightMemory } from './tiers/insight-memory.js';
|
|
56
|
+
import { ProceduralMemory } from './tiers/procedural-memory.js';
|
|
57
|
+
import { SemanticMemory, type SemanticSearchDefaults } from './tiers/semantic-memory.js';
|
|
58
|
+
import { SessionMemory } from './tiers/session-memory.js';
|
|
59
|
+
import { SharedMemory } from './tiers/shared-memory.js';
|
|
60
|
+
import { type BlockDefinition, WorkingMemory } from './tiers/working-memory.js';
|
|
61
|
+
import { buildMemoryTools, type ScopeResolver } from './tools/index.js';
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Options accepted by {@link createMemory}.
|
|
65
|
+
*
|
|
66
|
+
* @stable
|
|
67
|
+
*/
|
|
68
|
+
export interface CreateMemoryOptions {
|
|
69
|
+
/** Storage adapter (default: `@graphorin/store-sqlite`'s `MemoryStore`). */
|
|
70
|
+
readonly store: MemoryStoreAdapter;
|
|
71
|
+
/** Embedder registry. The default sqlite store exposes one as `sqlite.embeddings`. */
|
|
72
|
+
readonly embeddings: EmbeddingMetaRegistryLike;
|
|
73
|
+
/** Embedder provider (default: none - vector search is disabled). */
|
|
74
|
+
readonly embedder?: EmbedderProvider;
|
|
75
|
+
/** Pre-declared working blocks (idempotent - re-defining is a no-op). */
|
|
76
|
+
readonly workingBlocks?: ReadonlyArray<BlockDefinition>;
|
|
77
|
+
/**
|
|
78
|
+
* Tracer used for every `memory.*` span. Defaults to the no-op
|
|
79
|
+
* tracer from `@graphorin/core` so unit tests do not need to wire
|
|
80
|
+
* the observability stack.
|
|
81
|
+
*/
|
|
82
|
+
readonly tracer?: Tracer;
|
|
83
|
+
/** Override the reranker used by `SemanticMemory.search`. */
|
|
84
|
+
readonly reranker?: ReRanker;
|
|
85
|
+
/**
|
|
86
|
+
* Construction-time retrieval defaults (W-086) merged under every
|
|
87
|
+
* `SemanticMemory.search(...)` call, per-call options winning
|
|
88
|
+
* key-by-key. This is how the advanced retrieval stack (multi-query
|
|
89
|
+
* fan-out, HyDE, graph expansion, entity matching, weighted fusion,
|
|
90
|
+
* decay ranking) reaches the model-facing surfaces - `fact_search`,
|
|
91
|
+
* auto-recall and `deep_recall` all funnel through `search()` and
|
|
92
|
+
* inherit these without custom tools. Deliberately excludes the
|
|
93
|
+
* trust-sensitive predicates (`includeQuarantined`,
|
|
94
|
+
* `includeSuperseded`, `trustWeighting`, `owner`) so configuration
|
|
95
|
+
* cannot silently weaken trust gates. The fan-out switches only take
|
|
96
|
+
* effect when their backing dependency is configured (`queryTransform`
|
|
97
|
+
* for `multiQuery`/`hyde`, `graph` for `expandHops`/`entityMatch`) -
|
|
98
|
+
* and they add provider latency and cost to EVERY recall, including
|
|
99
|
+
* auto-recall, so opt in deliberately.
|
|
100
|
+
*/
|
|
101
|
+
readonly searchDefaults?: SemanticSearchDefaults;
|
|
102
|
+
/**
|
|
103
|
+
* Contextual-retrieval mode for the write path (P1-3). `'late-chunk'`
|
|
104
|
+
* (default) prepends a deterministic, offline situating context
|
|
105
|
+
* (entities / timeframe / topics, derived from the fact's own
|
|
106
|
+
* structured fields) to the text that is embedded + FTS-indexed, so a
|
|
107
|
+
* terse fact stays findable; the canonical `text` is preserved. `'off'`
|
|
108
|
+
* indexes the bare text. The `'llm'` enrichment is **not** available on
|
|
109
|
+
* the hot path - it is a consolidator-only opt-in configured via
|
|
110
|
+
* `consolidator: { contextualRetrieval: 'llm' }`.
|
|
111
|
+
*/
|
|
112
|
+
readonly contextualRetrieval?: 'off' | 'late-chunk';
|
|
113
|
+
/**
|
|
114
|
+
* Query transformation for retrieval (P2-3, opt-in). When supplied,
|
|
115
|
+
* `SemanticMemory.search(..., { multiQuery })` fans the query into
|
|
116
|
+
* reworded variants (multi-query / RAG-Fusion) and `{ hyde }` adds a
|
|
117
|
+
* hypothetical-answer embedding - both via one cheap LLM call on the
|
|
118
|
+
* given provider, fused through the existing RRF reranker. Omitted (the
|
|
119
|
+
* default) ⇒ search stays **offline + single-shot** and the
|
|
120
|
+
* `multiQuery` / `hyde` search options become silent no-ops. Reserve it
|
|
121
|
+
* for retrieval-heavy recall, not every search (it adds provider
|
|
122
|
+
* latency).
|
|
123
|
+
*/
|
|
124
|
+
readonly queryTransform?: {
|
|
125
|
+
/** Cheap provider used to rewrite the query / write the HyDE passage. */
|
|
126
|
+
readonly provider: Provider;
|
|
127
|
+
/** Hard ceiling on reworded variants requested per call. Default 5. */
|
|
128
|
+
readonly maxVariants?: number;
|
|
129
|
+
/** Output-token ceiling per transform call. Default 256. */
|
|
130
|
+
readonly maxTokens?: number;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Relation-graph entity resolution (P2-1). When `entityResolution` is
|
|
134
|
+
* `true` **and** the storage adapter exposes a `graph` surface (the
|
|
135
|
+
* default `@graphorin/store-sqlite` does), `remember(...)` resolves a
|
|
136
|
+
* fact's subject / object to canonical entities and links them, so
|
|
137
|
+
* `search(..., { expandHops: 1 })` can traverse relationships. Omitted
|
|
138
|
+
* (the default) ⇒ facts still carry s/p/o but form no entity links and
|
|
139
|
+
* the write path stays offline + unchanged. Dedup is lexical +
|
|
140
|
+
* embedding (offline, via the configured embedder); LLM adjudication of
|
|
141
|
+
* ambiguous merges is a further opt-in that needs `provider`.
|
|
142
|
+
*/
|
|
143
|
+
readonly graph?: EntityResolutionConfig & {
|
|
144
|
+
/** Enable entity resolution + linking on write. Default `false`. */
|
|
145
|
+
readonly entityResolution?: boolean;
|
|
146
|
+
/** Provider for opt-in LLM adjudication of ambiguous merges. */
|
|
147
|
+
readonly provider?: Provider;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Agentic / iterative retrieval (P2-4, opt-in). When supplied,
|
|
151
|
+
* `SemanticMemory.searchIterative(...)` and the gated `deep_recall`
|
|
152
|
+
* tool can grade a retrieved set on the given provider and, for queries
|
|
153
|
+
* judged hard, reformulate + retrieve again (widening to one-hop graph
|
|
154
|
+
* expansion) up to `maxIterations`, abstaining instead of confabulating
|
|
155
|
+
* when memory is insufficient. Omitted (the default) ⇒ `searchIterative`
|
|
156
|
+
* stays a single difficulty-gated pass with **no provider call**, and
|
|
157
|
+
* `deep_recall` is **not** registered (the tool surface stays at the
|
|
158
|
+
* canonical eleven). Reserve it for hard multi-hop / temporal recall -
|
|
159
|
+
* it adds provider latency per pass.
|
|
160
|
+
*/
|
|
161
|
+
readonly iterativeRetrieval?: {
|
|
162
|
+
/** Cheap provider used to grade retrieved memories + reformulate. */
|
|
163
|
+
readonly provider: Provider;
|
|
164
|
+
/** Default total-pass cap (clamped to `[1, 5]`). Default 3. */
|
|
165
|
+
readonly maxIterations?: number;
|
|
166
|
+
/** Output-token ceiling per grade call. Default 256. */
|
|
167
|
+
readonly maxTokens?: number;
|
|
168
|
+
/**
|
|
169
|
+
* Default difficulty-gate threshold in `[0, 1]` (W-088). The gate's
|
|
170
|
+
* signal lexicon is **English-only**: on non-English deployments the
|
|
171
|
+
* auto-gate never fires, so either lower this threshold or rely on
|
|
172
|
+
* `forceHard` (`deep_recall` already forces the loop). Omitted ⇒ the
|
|
173
|
+
* built-in `0.5`; per-call `difficultyThreshold` overrides it.
|
|
174
|
+
*/
|
|
175
|
+
readonly difficultyThreshold?: number;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Opt-in workflow induction (P2-2). When set, `ProceduralMemory.induce(...)`
|
|
179
|
+
* distils a reusable, value-abstracted procedure from a successful agent
|
|
180
|
+
* trajectory and stores it **quarantined** + `provenance: 'induction'`.
|
|
181
|
+
* Omitted (the default) ⇒ `induce(...)` throws
|
|
182
|
+
* `ProcedureInductionNotConfiguredError` and the procedural tier
|
|
183
|
+
* stays pure offline CRUD - no provider call.
|
|
184
|
+
*/
|
|
185
|
+
readonly procedureInduction?: {
|
|
186
|
+
/** Provider used to abstract trajectory values into a procedure. */
|
|
187
|
+
readonly provider: Provider;
|
|
188
|
+
/** Output-token ceiling per induction call. Default 512. */
|
|
189
|
+
readonly maxTokens?: number;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Promotion-by-demonstrated-success for quarantined induced
|
|
193
|
+
* procedures (MCON-2 part 4). Fully offline - orthogonal to
|
|
194
|
+
* `procedureInduction` (no provider needed). When configured,
|
|
195
|
+
* `procedural.recordOutcome(scope, id, true)` increments the rule's
|
|
196
|
+
* persistent success counter and promotes it into `activate()` once
|
|
197
|
+
* `afterSuccesses` verified reuses accumulate; the injection gate
|
|
198
|
+
* still refuses flagged texts. Omitted ⇒ outcomes are counted but
|
|
199
|
+
* nothing auto-promotes.
|
|
200
|
+
*/
|
|
201
|
+
readonly procedurePromotion?: {
|
|
202
|
+
/** Successful demonstrated reuses required before promotion (≥ 1). */
|
|
203
|
+
readonly afterSuccesses: number;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Register the gated `runbook_search` tool (D3) so the model can look
|
|
207
|
+
* up validated procedures by task description (content recall over
|
|
208
|
+
* procedural memory, returning whole runbooks). Fully offline - the
|
|
209
|
+
* default `@graphorin/store-sqlite` adapter serves it from the rules
|
|
210
|
+
* FTS index (migration 028); adapters without the index degrade to an
|
|
211
|
+
* in-memory lexical scan. Default `false` - the tool surface stays at
|
|
212
|
+
* the canonical eleven.
|
|
213
|
+
*/
|
|
214
|
+
readonly runbookSearch?: boolean;
|
|
215
|
+
/**
|
|
216
|
+
* Resolver that produces the live {@link SessionScope} for each
|
|
217
|
+
* memory-tool invocation. Defaults to a closure that throws - the
|
|
218
|
+
* agent runtime overrides it in Phase 12.
|
|
219
|
+
*/
|
|
220
|
+
readonly resolveScope?: ScopeResolver;
|
|
221
|
+
/**
|
|
222
|
+
* Consolidator configuration. When omitted, empty, or
|
|
223
|
+
* `enabled: false`, the facade installs the Phase 10a no-op
|
|
224
|
+
* placeholder so consumers can still type their interactions without
|
|
225
|
+
* paying the runtime cost. ANY other setting - including offline
|
|
226
|
+
* knobs like `decayCapacity` or `contextualRetrieval` - implicitly
|
|
227
|
+
* enables the production runtime (MST-4); `enabled: false` together
|
|
228
|
+
* with other settings warns once and keeps the placeholder.
|
|
229
|
+
*/
|
|
230
|
+
readonly consolidator?: {
|
|
231
|
+
readonly enabled?: boolean;
|
|
232
|
+
readonly triggers?: ReadonlyArray<ConsolidatorTriggerSpec>;
|
|
233
|
+
readonly tier?: ConsolidatorTier;
|
|
234
|
+
readonly phases?: ReadonlyArray<ConsolidatorPhase>;
|
|
235
|
+
readonly ceilings?: Partial<ConsolidatorCeilings>;
|
|
236
|
+
readonly onExceed?: OnBudgetExceed;
|
|
237
|
+
/**
|
|
238
|
+
* USD pricer for phase LLM usage (memory-consolidation-02) - wire
|
|
239
|
+
* to `@graphorin/pricing` so `maxCostPerDay` can actually trip.
|
|
240
|
+
*/
|
|
241
|
+
readonly priceUsage?: (usage: { promptTokens: number; completionTokens: number }) => number;
|
|
242
|
+
/** Provider routed to the standard phase when set (MCON-7); falls back to `provider`. */
|
|
243
|
+
readonly cheapProvider?: Provider | null;
|
|
244
|
+
/** Provider routed to the deep + reflection passes when set (MCON-7). */
|
|
245
|
+
readonly deepProvider?: Provider | null;
|
|
246
|
+
readonly cheapModel?: string | null;
|
|
247
|
+
readonly deepModel?: string | null;
|
|
248
|
+
readonly noiseFilters?: ReadonlyArray<'default' | 'minimal' | 'none'>;
|
|
249
|
+
readonly lockWaitMs?: number;
|
|
250
|
+
readonly decayTauDays?: number;
|
|
251
|
+
readonly decayArchiveThreshold?: number;
|
|
252
|
+
/** Capacity-bounded eviction target for the light phase (X-1). Default unbounded. */
|
|
253
|
+
readonly decayCapacity?: number | null;
|
|
254
|
+
/** Weights for the multi-signal salience score (X-1). */
|
|
255
|
+
readonly salienceWeights?: SalienceWeights;
|
|
256
|
+
readonly maxStandardBatchSize?: number;
|
|
257
|
+
/**
|
|
258
|
+
* Input transcript budget for one standard-phase slice, in
|
|
259
|
+
* characters (W-081). Over-budget batches are half-split before the
|
|
260
|
+
* provider call; a lone over-budget message is tail-truncated.
|
|
261
|
+
* Per-tier default (60k chars ~ 15k tokens; 120k on `full`).
|
|
262
|
+
*/
|
|
263
|
+
readonly maxTranscriptChars?: number;
|
|
264
|
+
readonly maxDeepConflictsPerRun?: number;
|
|
265
|
+
readonly dlqMaxRetries?: number;
|
|
266
|
+
readonly dlqBaseBackoffMs?: number;
|
|
267
|
+
readonly dlqMaxBackoffMs?: number;
|
|
268
|
+
/** Auto-form quarantined episodes from processed slices (P1-2). Per-tier default. */
|
|
269
|
+
readonly formEpisodes?: boolean;
|
|
270
|
+
/** Score episode importance via the consolidator LLM (P1-2). Per-tier default. */
|
|
271
|
+
readonly importanceScoring?: boolean;
|
|
272
|
+
/** Opt in to auto-promotion of injection-clean extraction facts (MCON-2). Default off. */
|
|
273
|
+
readonly autoPromoteExtraction?: boolean;
|
|
274
|
+
/** Run the deep-phase reflection pass synthesizing cited insights (P1-1). Per-tier default. */
|
|
275
|
+
readonly reflection?: boolean;
|
|
276
|
+
/** Accumulated-importance threshold at which reflection fires (P1-1). */
|
|
277
|
+
readonly importanceThreshold?: number;
|
|
278
|
+
/** Upper bound on salient questions reflection asks per pass (P1-1). */
|
|
279
|
+
readonly reflectionMaxQuestions?: number;
|
|
280
|
+
/** Override the quarantined-insight queue cap (W-082). Default 100. */
|
|
281
|
+
readonly reflectionMaxQuarantinedInsights?: number;
|
|
282
|
+
/**
|
|
283
|
+
* Contextual retrieval for standard-phase fact writes (P1-3).
|
|
284
|
+
* `'llm'` opts into one budgeted cheap-model call per write to author
|
|
285
|
+
* a situating prefix (consolidator-only); `'late-chunk'` (default)
|
|
286
|
+
* and `'off'` defer to the write-path mode. Per-tier default.
|
|
287
|
+
*/
|
|
288
|
+
readonly contextualRetrieval?: ContextualRetrievalMode;
|
|
289
|
+
/**
|
|
290
|
+
* Maintain the learned-context digest block (D3): after each deep
|
|
291
|
+
* phase, one budgeted LLM call rewrites the reserved
|
|
292
|
+
* `learned_context` working block (previous digest + recent
|
|
293
|
+
* episodes / active insights / procedures), so the assembled system
|
|
294
|
+
* prompt carries a compact standing summary. Default `false` at
|
|
295
|
+
* every tier (Wave-D trial).
|
|
296
|
+
*/
|
|
297
|
+
readonly learnedContext?: boolean;
|
|
298
|
+
/** Character bound for the learned-context digest (D3). Default `1200`. */
|
|
299
|
+
readonly learnedContextMaxChars?: number;
|
|
300
|
+
readonly defaultScope?: SessionScope;
|
|
301
|
+
readonly provider?: Provider | null;
|
|
302
|
+
/** Override the wall clock - used by tests. */
|
|
303
|
+
readonly now?: () => number;
|
|
304
|
+
/** Stable id seed - used by tests. */
|
|
305
|
+
readonly randomId?: () => string;
|
|
306
|
+
/** Subscribe to phase-finished events. */
|
|
307
|
+
readonly onPhaseFinished?: PhaseListener;
|
|
308
|
+
};
|
|
309
|
+
/**
|
|
310
|
+
* Conflict pipeline configuration (Phase 10b). Default: enabled,
|
|
311
|
+
* English locale pack, thresholds `0.95 / 0.85 / 0.4`. Pass
|
|
312
|
+
* `{ mode: 'off' }` to bypass the pipeline entirely (logs a one-shot
|
|
313
|
+
* WARN per process per the spec).
|
|
314
|
+
*/
|
|
315
|
+
readonly conflictPipeline?: ConflictPipelineOptions;
|
|
316
|
+
/**
|
|
317
|
+
* Context engine configuration (Phase 10d). The engine assembles
|
|
318
|
+
* the layered six-layer system prompt; `memory.compile(scope)`
|
|
319
|
+
* delegates to it for the working blocks + rules + metadata
|
|
320
|
+
* fragments. When omitted, a default engine is created (English
|
|
321
|
+
* locale; `'full'` base mode; no auto-recall; conservative
|
|
322
|
+
* `'public-tls'` provider trust).
|
|
323
|
+
*/
|
|
324
|
+
readonly contextEngine?: ContextEngineConfig;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// The `Memory` interface is co-located with `ContextEngine` in
|
|
328
|
+
// memory-interface.ts (issue #22 - the pair is mutually recursive and
|
|
329
|
+
// keeping it here put a type-only cycle into the module graph).
|
|
330
|
+
// Re-exported so `import type { Memory } from './facade.js'` and the
|
|
331
|
+
// public barrel keep working unchanged.
|
|
332
|
+
export type { Memory } from './memory-interface.js';
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Wire every memory subsystem in one call. Returns the typed
|
|
336
|
+
* `Memory` facade ready to be passed into `createAgent({...})`.
|
|
337
|
+
*
|
|
338
|
+
* @stable
|
|
339
|
+
*/
|
|
340
|
+
export function createMemory(options: CreateMemoryOptions): Memory {
|
|
341
|
+
const tracer = options.tracer ?? NOOP_TRACER;
|
|
342
|
+
const reranker: ReRanker = options.reranker ?? new RRFReranker();
|
|
343
|
+
const resolveScope: ScopeResolver =
|
|
344
|
+
options.resolveScope ??
|
|
345
|
+
(() => {
|
|
346
|
+
throw new TypeError(
|
|
347
|
+
'[graphorin/memory] memory tool invoked without a scope resolver. ' +
|
|
348
|
+
'Pass `resolveScope` to createMemory({...}) - the agent runtime supplies one in Phase 12.',
|
|
349
|
+
);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
let activeEmbedderId: string | null = null;
|
|
353
|
+
if (options.embedder !== undefined) {
|
|
354
|
+
activeEmbedderId = bindEmbedder(options.embedder, options.embeddings);
|
|
355
|
+
}
|
|
356
|
+
const embedder = options.embedder ?? null;
|
|
357
|
+
const embedderIdProvider = (): string | null => activeEmbedderId;
|
|
358
|
+
|
|
359
|
+
const working = new WorkingMemory({ store: options.store, tracer });
|
|
360
|
+
for (const block of options.workingBlocks ?? []) {
|
|
361
|
+
working.define(block);
|
|
362
|
+
}
|
|
363
|
+
const session = new SessionMemory({ store: options.store, tracer });
|
|
364
|
+
const episodic = new EpisodicMemory({
|
|
365
|
+
store: options.store,
|
|
366
|
+
tracer,
|
|
367
|
+
embedder,
|
|
368
|
+
embedderIdProvider,
|
|
369
|
+
});
|
|
370
|
+
const conflictPipeline = createConflictPipeline(options.conflictPipeline ?? {});
|
|
371
|
+
// P2-3: build the (opt-in) query transformer from the supplied provider.
|
|
372
|
+
// Absent ⇒ `null` ⇒ search stays offline + single-shot.
|
|
373
|
+
const queryTransformer =
|
|
374
|
+
options.queryTransform !== undefined
|
|
375
|
+
? createProviderQueryTransformer(options.queryTransform.provider, {
|
|
376
|
+
...(options.queryTransform.maxVariants !== undefined
|
|
377
|
+
? { maxVariants: options.queryTransform.maxVariants }
|
|
378
|
+
: {}),
|
|
379
|
+
...(options.queryTransform.maxTokens !== undefined
|
|
380
|
+
? { maxTokens: options.queryTransform.maxTokens }
|
|
381
|
+
: {}),
|
|
382
|
+
})
|
|
383
|
+
: null;
|
|
384
|
+
// P2-1: build the (opt-in) entity resolver. Requires `graph.entityResolution`
|
|
385
|
+
// *and* a graph-capable adapter; absent ⇒ `null` ⇒ writes carry s/p/o but
|
|
386
|
+
// form no entity links and the write path stays offline + unchanged.
|
|
387
|
+
const graphStore = options.store.graph;
|
|
388
|
+
const entityResolver =
|
|
389
|
+
options.graph?.entityResolution === true && graphStore !== undefined
|
|
390
|
+
? new EntityResolver({
|
|
391
|
+
store: graphStore,
|
|
392
|
+
embedder,
|
|
393
|
+
embedderId: embedderIdProvider,
|
|
394
|
+
...(options.graph.provider !== undefined ? { provider: options.graph.provider } : {}),
|
|
395
|
+
config: {
|
|
396
|
+
...(options.graph.mergeThreshold !== undefined
|
|
397
|
+
? { mergeThreshold: options.graph.mergeThreshold }
|
|
398
|
+
: {}),
|
|
399
|
+
...(options.graph.adjudicateThreshold !== undefined
|
|
400
|
+
? { adjudicateThreshold: options.graph.adjudicateThreshold }
|
|
401
|
+
: {}),
|
|
402
|
+
...(options.graph.llmAdjudication !== undefined
|
|
403
|
+
? { llmAdjudication: options.graph.llmAdjudication }
|
|
404
|
+
: {}),
|
|
405
|
+
},
|
|
406
|
+
})
|
|
407
|
+
: null;
|
|
408
|
+
// P2-4: build the (opt-in) retrieval grader. Absent ⇒ `null` ⇒
|
|
409
|
+
// `searchIterative` runs a single difficulty-gated pass (no provider
|
|
410
|
+
// call) and the `deep_recall` tool is not registered.
|
|
411
|
+
const grader =
|
|
412
|
+
options.iterativeRetrieval !== undefined
|
|
413
|
+
? createProviderRetrievalGrader(options.iterativeRetrieval.provider, {
|
|
414
|
+
...(options.iterativeRetrieval.maxTokens !== undefined
|
|
415
|
+
? { maxTokens: options.iterativeRetrieval.maxTokens }
|
|
416
|
+
: {}),
|
|
417
|
+
})
|
|
418
|
+
: null;
|
|
419
|
+
const semantic = new SemanticMemory({
|
|
420
|
+
store: options.store,
|
|
421
|
+
tracer,
|
|
422
|
+
embedder,
|
|
423
|
+
embedderIdProvider,
|
|
424
|
+
reranker,
|
|
425
|
+
conflictPipeline,
|
|
426
|
+
...(options.contextualRetrieval !== undefined
|
|
427
|
+
? { contextualRetrieval: options.contextualRetrieval }
|
|
428
|
+
: {}),
|
|
429
|
+
...(queryTransformer !== null ? { queryTransformer } : {}),
|
|
430
|
+
...(entityResolver !== null ? { entityResolver } : {}),
|
|
431
|
+
...(grader !== null ? { grader } : {}),
|
|
432
|
+
...(options.iterativeRetrieval?.maxIterations !== undefined
|
|
433
|
+
? { iterativeMaxIterations: options.iterativeRetrieval.maxIterations }
|
|
434
|
+
: {}),
|
|
435
|
+
...(options.iterativeRetrieval?.difficultyThreshold !== undefined
|
|
436
|
+
? { iterativeDifficultyThreshold: options.iterativeRetrieval.difficultyThreshold }
|
|
437
|
+
: {}),
|
|
438
|
+
// C5: the same weights drive eviction salience and rank-time trust.
|
|
439
|
+
...(options.consolidator?.salienceWeights !== undefined
|
|
440
|
+
? { trustWeights: options.consolidator.salienceWeights }
|
|
441
|
+
: {}),
|
|
442
|
+
// W-086: construction-time retrieval defaults for every search().
|
|
443
|
+
...(options.searchDefaults !== undefined ? { searchDefaults: options.searchDefaults } : {}),
|
|
444
|
+
});
|
|
445
|
+
// P2-2: build the (opt-in) workflow inducer. Absent ⇒ `null` ⇒
|
|
446
|
+
// `ProceduralMemory.induce(...)` throws and the tier stays offline CRUD.
|
|
447
|
+
// MCON-15: induction spend is recorded into the consolidator budget -
|
|
448
|
+
// the consolidator is constructed AFTER the inducer, so the callback
|
|
449
|
+
// routes through a slot filled below (placeholder ⇒ no-op).
|
|
450
|
+
let consolidatorForSpend: Consolidator | null = null;
|
|
451
|
+
const inducer =
|
|
452
|
+
options.procedureInduction !== undefined
|
|
453
|
+
? createProviderWorkflowInducer(options.procedureInduction.provider, {
|
|
454
|
+
...(options.procedureInduction.maxTokens !== undefined
|
|
455
|
+
? { maxTokens: options.procedureInduction.maxTokens }
|
|
456
|
+
: {}),
|
|
457
|
+
onUsage: (usage) => {
|
|
458
|
+
consolidatorForSpend?.recordExternalSpend(usage.promptTokens + usage.completionTokens);
|
|
459
|
+
},
|
|
460
|
+
})
|
|
461
|
+
: null;
|
|
462
|
+
const procedural = new ProceduralMemory({
|
|
463
|
+
store: options.store,
|
|
464
|
+
tracer,
|
|
465
|
+
...(inducer !== null ? { inducer } : {}),
|
|
466
|
+
// MCON-2 part 4: opt-in promotion-by-demonstrated-success.
|
|
467
|
+
...(options.procedurePromotion?.afterSuccesses !== undefined
|
|
468
|
+
? { promoteAfterSuccesses: options.procedurePromotion.afterSuccesses }
|
|
469
|
+
: {}),
|
|
470
|
+
});
|
|
471
|
+
const shared = new SharedMemory({ store: options.store, tracer });
|
|
472
|
+
const insights = new InsightMemory({ store: options.store, tracer });
|
|
473
|
+
|
|
474
|
+
const tools = buildMemoryTools(
|
|
475
|
+
{
|
|
476
|
+
working,
|
|
477
|
+
session,
|
|
478
|
+
episodic,
|
|
479
|
+
semantic,
|
|
480
|
+
procedural,
|
|
481
|
+
shared,
|
|
482
|
+
resolveScope,
|
|
483
|
+
},
|
|
484
|
+
// P2-4: the gated `deep_recall` tool is registered only when a grader
|
|
485
|
+
// is configured - the offline default stays at exactly eleven tools.
|
|
486
|
+
// D3: `runbook_search` is a second gated appendix, opt-in via
|
|
487
|
+
// `runbookSearch: true`.
|
|
488
|
+
{
|
|
489
|
+
includeDeepRecall: grader !== null,
|
|
490
|
+
includeRunbookSearch: options.runbookSearch === true,
|
|
491
|
+
},
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
const consolidatorOpts = options.consolidator;
|
|
495
|
+
const consolidator: Consolidator = buildConsolidator(
|
|
496
|
+
consolidatorOpts,
|
|
497
|
+
options.store,
|
|
498
|
+
semantic,
|
|
499
|
+
episodic,
|
|
500
|
+
working,
|
|
501
|
+
tracer,
|
|
502
|
+
);
|
|
503
|
+
consolidatorForSpend = consolidator;
|
|
504
|
+
const contextEngineConfig = options.contextEngine ?? {};
|
|
505
|
+
const contextEngine: ContextEngine = createContextEngine(contextEngineConfig);
|
|
506
|
+
const resolved = contextEngine.config();
|
|
507
|
+
const localePack =
|
|
508
|
+
contextEngineConfig.locale === undefined
|
|
509
|
+
? enLocalePack
|
|
510
|
+
: typeof contextEngineConfig.locale === 'string'
|
|
511
|
+
? contextEngineConfig.locale === enLocalePack.id
|
|
512
|
+
? enLocalePack
|
|
513
|
+
: resolveLocalePack({ id: contextEngineConfig.locale })
|
|
514
|
+
: resolveLocalePack(contextEngineConfig.locale);
|
|
515
|
+
|
|
516
|
+
// The facade's `compile(...)` is the static-fragment surface
|
|
517
|
+
// consumed by callers that do not know the active provider yet
|
|
518
|
+
// (the agent runtime calls `memory.contextEngine.assemble(...)`
|
|
519
|
+
// with full provider context when `autoAssembleContext` is
|
|
520
|
+
// enabled). The privacy filter only fires
|
|
521
|
+
// when the caller explicitly passes `providerAcceptsSensitivity`
|
|
522
|
+
// OR the operator opted into the engine's `privacy` block.
|
|
523
|
+
const privacyOptedIn =
|
|
524
|
+
contextEngineConfig.privacy !== undefined &&
|
|
525
|
+
(contextEngineConfig.privacy.providerAcceptsSensitivity !== undefined ||
|
|
526
|
+
contextEngineConfig.privacy.cloudUploadConsent !== undefined ||
|
|
527
|
+
contextEngineConfig.privacy.providerTrust !== undefined);
|
|
528
|
+
|
|
529
|
+
async function compile(
|
|
530
|
+
scope: CompileScope,
|
|
531
|
+
compileOptions: CompileOptions = {},
|
|
532
|
+
): Promise<MemoryContextBlocks> {
|
|
533
|
+
const out: { -readonly [K in keyof MemoryContextBlocks]: MemoryContextBlocks[K] } = {};
|
|
534
|
+
const blocks = await options.store.working.list(scope);
|
|
535
|
+
// Quarantined (e.g. P2-2-induced) procedures are provisional and must not
|
|
536
|
+
// reach the system prompt - `activate()` already excludes them, and
|
|
537
|
+
// compile() (public `@stable`) must agree or a compile()-based prompt
|
|
538
|
+
// builder ingests unvalidated induction procedures (MST-3).
|
|
539
|
+
const rules = (await options.store.procedural.list(scope)).filter(
|
|
540
|
+
(rule) => rule.status !== 'quarantined',
|
|
541
|
+
);
|
|
542
|
+
const shouldFilter = privacyOptedIn || compileOptions.providerAcceptsSensitivity !== undefined;
|
|
543
|
+
let blocksKept: ReadonlyArray<(typeof blocks)[number]> = blocks;
|
|
544
|
+
let rulesKept: ReadonlyArray<(typeof rules)[number]> = rules;
|
|
545
|
+
if (shouldFilter) {
|
|
546
|
+
const filterContext: Parameters<typeof partitionBySensitivity>[1] = {
|
|
547
|
+
providerTrust: resolved.providerTrust,
|
|
548
|
+
cloudUploadConsent: resolved.cloudUploadConsent,
|
|
549
|
+
defaultSensitivity: resolved.defaultSensitivity,
|
|
550
|
+
};
|
|
551
|
+
if (compileOptions.providerAcceptsSensitivity !== undefined) {
|
|
552
|
+
(
|
|
553
|
+
filterContext as {
|
|
554
|
+
providerAcceptsSensitivity?: ReadonlyArray<'public' | 'internal' | 'secret'>;
|
|
555
|
+
}
|
|
556
|
+
).providerAcceptsSensitivity = compileOptions.providerAcceptsSensitivity;
|
|
557
|
+
}
|
|
558
|
+
blocksKept = partitionBySensitivity(blocks, filterContext).kept;
|
|
559
|
+
rulesKept = partitionBySensitivity(rules, filterContext).kept;
|
|
560
|
+
}
|
|
561
|
+
const blocksXml = renderWorkingBlocksXml(blocksKept);
|
|
562
|
+
if (blocksXml.length > 0) {
|
|
563
|
+
out.workingBlocks = blocksXml;
|
|
564
|
+
}
|
|
565
|
+
if (rulesKept.length > 0) {
|
|
566
|
+
const lines = ['<memory_rules>'];
|
|
567
|
+
for (const rule of rulesKept) {
|
|
568
|
+
lines.push(` <rule priority="${rule.priority}">${escapeXml(rule.text)}</rule>`);
|
|
569
|
+
}
|
|
570
|
+
lines.push('</memory_rules>');
|
|
571
|
+
out.rules = lines.join('\n');
|
|
572
|
+
}
|
|
573
|
+
if (compileOptions.includeMetadata !== false) {
|
|
574
|
+
const meta = await metadata(scope);
|
|
575
|
+
out.metadata = renderMetadataBlock(meta);
|
|
576
|
+
}
|
|
577
|
+
out.base = composeLayer1(localePack, resolved.memoryBaseMode);
|
|
578
|
+
return Object.freeze(out);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async function metadata(scope: SessionScope): Promise<MemoryMetadata> {
|
|
582
|
+
return gatherMemoryMetadata(scope, {
|
|
583
|
+
store: options.store,
|
|
584
|
+
consolidator,
|
|
585
|
+
embedderId: embedderIdProvider,
|
|
586
|
+
localeId: resolved.localeId,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return Object.freeze({
|
|
591
|
+
working,
|
|
592
|
+
session,
|
|
593
|
+
episodic,
|
|
594
|
+
semantic,
|
|
595
|
+
procedural,
|
|
596
|
+
shared,
|
|
597
|
+
insights,
|
|
598
|
+
tools,
|
|
599
|
+
consolidator,
|
|
600
|
+
conflictPipeline,
|
|
601
|
+
contextEngine,
|
|
602
|
+
embedder,
|
|
603
|
+
embedderId: embedderIdProvider,
|
|
604
|
+
compile,
|
|
605
|
+
metadata,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function renderWorkingBlocksXml(
|
|
610
|
+
blocks: ReadonlyArray<{
|
|
611
|
+
readonly label: string;
|
|
612
|
+
readonly value: string;
|
|
613
|
+
readonly description?: string;
|
|
614
|
+
}>,
|
|
615
|
+
): string {
|
|
616
|
+
if (blocks.length === 0) return '';
|
|
617
|
+
const lines = ['<memory_blocks>'];
|
|
618
|
+
for (const block of blocks) {
|
|
619
|
+
const description =
|
|
620
|
+
block.description !== undefined ? ` description="${escapeXml(block.description)}"` : '';
|
|
621
|
+
lines.push(` <block label="${escapeXml(block.label)}"${description}>`);
|
|
622
|
+
lines.push(` ${escapeXml(block.value)}`);
|
|
623
|
+
lines.push(' </block>');
|
|
624
|
+
}
|
|
625
|
+
lines.push('</memory_blocks>');
|
|
626
|
+
return lines.join('\n');
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function escapeXml(value: string): string {
|
|
630
|
+
return value
|
|
631
|
+
.replace(/&/g, '&')
|
|
632
|
+
.replace(/</g, '<')
|
|
633
|
+
.replace(/>/g, '>')
|
|
634
|
+
.replace(/"/g, '"');
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function buildConsolidator(
|
|
638
|
+
opts: CreateMemoryOptions['consolidator'],
|
|
639
|
+
store: CreateMemoryOptions['store'],
|
|
640
|
+
semantic: SemanticMemory,
|
|
641
|
+
episodic: EpisodicMemory,
|
|
642
|
+
working: WorkingMemory,
|
|
643
|
+
tracer: Tracer,
|
|
644
|
+
): Consolidator {
|
|
645
|
+
if (opts === undefined) {
|
|
646
|
+
return createConsolidatorPlaceholder();
|
|
647
|
+
}
|
|
648
|
+
const enabled = shouldEnableConsolidator(opts);
|
|
649
|
+
if (!enabled) {
|
|
650
|
+
return createConsolidatorPlaceholder({
|
|
651
|
+
...(opts.triggers !== undefined ? { triggers: opts.triggers } : {}),
|
|
652
|
+
...(opts.tier !== undefined ? { tier: opts.tier } : {}),
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
const consolidator = createConsolidator({
|
|
656
|
+
store,
|
|
657
|
+
semantic,
|
|
658
|
+
episodic,
|
|
659
|
+
working,
|
|
660
|
+
tracer,
|
|
661
|
+
...(opts.provider !== undefined ? { provider: opts.provider } : {}),
|
|
662
|
+
...(opts.now !== undefined ? { now: opts.now } : {}),
|
|
663
|
+
...(opts.randomId !== undefined ? { randomId: opts.randomId } : {}),
|
|
664
|
+
...(opts.triggers !== undefined ? { triggers: opts.triggers } : {}),
|
|
665
|
+
...(opts.tier !== undefined ? { tier: opts.tier } : {}),
|
|
666
|
+
...(opts.phases !== undefined ? { phases: opts.phases } : {}),
|
|
667
|
+
...(opts.ceilings !== undefined ? { ceilings: opts.ceilings } : {}),
|
|
668
|
+
...(opts.onExceed !== undefined ? { onExceed: opts.onExceed } : {}),
|
|
669
|
+
...(opts.priceUsage !== undefined ? { priceUsage: opts.priceUsage } : {}),
|
|
670
|
+
...(opts.cheapProvider !== undefined ? { cheapProvider: opts.cheapProvider } : {}),
|
|
671
|
+
...(opts.deepProvider !== undefined ? { deepProvider: opts.deepProvider } : {}),
|
|
672
|
+
...(opts.cheapModel !== undefined ? { cheapModel: opts.cheapModel } : {}),
|
|
673
|
+
...(opts.deepModel !== undefined ? { deepModel: opts.deepModel } : {}),
|
|
674
|
+
...(opts.noiseFilters !== undefined ? { noiseFilters: opts.noiseFilters } : {}),
|
|
675
|
+
...(opts.lockWaitMs !== undefined ? { lockWaitMs: opts.lockWaitMs } : {}),
|
|
676
|
+
...(opts.decayTauDays !== undefined ? { decayTauDays: opts.decayTauDays } : {}),
|
|
677
|
+
...(opts.decayArchiveThreshold !== undefined
|
|
678
|
+
? { decayArchiveThreshold: opts.decayArchiveThreshold }
|
|
679
|
+
: {}),
|
|
680
|
+
...(opts.decayCapacity !== undefined ? { decayCapacity: opts.decayCapacity } : {}),
|
|
681
|
+
...(opts.salienceWeights !== undefined ? { salienceWeights: opts.salienceWeights } : {}),
|
|
682
|
+
...(opts.maxStandardBatchSize !== undefined
|
|
683
|
+
? { maxStandardBatchSize: opts.maxStandardBatchSize }
|
|
684
|
+
: {}),
|
|
685
|
+
...(opts.maxTranscriptChars !== undefined
|
|
686
|
+
? { maxTranscriptChars: opts.maxTranscriptChars }
|
|
687
|
+
: {}),
|
|
688
|
+
...(opts.maxDeepConflictsPerRun !== undefined
|
|
689
|
+
? { maxDeepConflictsPerRun: opts.maxDeepConflictsPerRun }
|
|
690
|
+
: {}),
|
|
691
|
+
...(opts.dlqMaxRetries !== undefined ? { dlqMaxRetries: opts.dlqMaxRetries } : {}),
|
|
692
|
+
...(opts.dlqBaseBackoffMs !== undefined ? { dlqBaseBackoffMs: opts.dlqBaseBackoffMs } : {}),
|
|
693
|
+
...(opts.dlqMaxBackoffMs !== undefined ? { dlqMaxBackoffMs: opts.dlqMaxBackoffMs } : {}),
|
|
694
|
+
...(opts.formEpisodes !== undefined ? { formEpisodes: opts.formEpisodes } : {}),
|
|
695
|
+
...(opts.importanceScoring !== undefined ? { importanceScoring: opts.importanceScoring } : {}),
|
|
696
|
+
...(opts.autoPromoteExtraction !== undefined
|
|
697
|
+
? { autoPromoteExtraction: opts.autoPromoteExtraction }
|
|
698
|
+
: {}),
|
|
699
|
+
...(opts.reflection !== undefined ? { reflection: opts.reflection } : {}),
|
|
700
|
+
...(opts.importanceThreshold !== undefined
|
|
701
|
+
? { importanceThreshold: opts.importanceThreshold }
|
|
702
|
+
: {}),
|
|
703
|
+
...(opts.reflectionMaxQuestions !== undefined
|
|
704
|
+
? { reflectionMaxQuestions: opts.reflectionMaxQuestions }
|
|
705
|
+
: {}),
|
|
706
|
+
...(opts.reflectionMaxQuarantinedInsights !== undefined
|
|
707
|
+
? { reflectionMaxQuarantinedInsights: opts.reflectionMaxQuarantinedInsights }
|
|
708
|
+
: {}),
|
|
709
|
+
...(opts.contextualRetrieval !== undefined
|
|
710
|
+
? { contextualRetrieval: opts.contextualRetrieval }
|
|
711
|
+
: {}),
|
|
712
|
+
...(opts.learnedContext !== undefined ? { learnedContext: opts.learnedContext } : {}),
|
|
713
|
+
...(opts.learnedContextMaxChars !== undefined
|
|
714
|
+
? { learnedContextMaxChars: opts.learnedContextMaxChars }
|
|
715
|
+
: {}),
|
|
716
|
+
...(opts.defaultScope !== undefined ? { defaultScope: opts.defaultScope } : {}),
|
|
717
|
+
});
|
|
718
|
+
if (opts.onPhaseFinished !== undefined) {
|
|
719
|
+
consolidator.onPhaseFinished(opts.onPhaseFinished);
|
|
720
|
+
}
|
|
721
|
+
return consolidator;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
let consolidatorConfigIgnoredWarned = false;
|
|
725
|
+
|
|
726
|
+
/** @internal - test seam for the one-time disabled-config warning. */
|
|
727
|
+
export function _resetConsolidatorConfigWarningForTesting(): void {
|
|
728
|
+
consolidatorConfigIgnoredWarned = false;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function shouldEnableConsolidator(opts: NonNullable<CreateMemoryOptions['consolidator']>): boolean {
|
|
732
|
+
// MST-4: ANY non-empty consolidator config implicitly enables - the old
|
|
733
|
+
// allow-list silently ignored offline knobs (`decayCapacity`,
|
|
734
|
+
// `formEpisodes`, `reflection`, `contextualRetrieval`, …): the caller
|
|
735
|
+
// got a no-op placeholder while believing the feature was on.
|
|
736
|
+
const keys = Object.keys(opts).filter(
|
|
737
|
+
(k) => k !== 'enabled' && (opts as Record<string, unknown>)[k] !== undefined,
|
|
738
|
+
);
|
|
739
|
+
if (opts.enabled === false) {
|
|
740
|
+
if (keys.length > 0 && !consolidatorConfigIgnoredWarned) {
|
|
741
|
+
consolidatorConfigIgnoredWarned = true;
|
|
742
|
+
process.stderr.write(
|
|
743
|
+
`[graphorin/memory] consolidator config (${keys.join(', ')}) was supplied together with enabled: false - the settings are ignored until the consolidator is enabled.\n`,
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
if (opts.enabled === true) return true;
|
|
749
|
+
return keys.length > 0;
|
|
750
|
+
}
|