@melandlabs/memory-store 0.3.0 → 1.0.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.
@@ -1,3 +1,38 @@
1
+ import * as _melandlabs_memory_consolidation from '@melandlabs/memory-consolidation';
2
+ import * as _melandlabs_contracts_peer from '@melandlabs/contracts/peer';
3
+ import { Peer } from '@melandlabs/contracts/peer';
4
+ import { FactType } from '@melandlabs/contracts';
5
+
6
+ /**
7
+ * Reranker adapter contract.
8
+ *
9
+ * A `Reranker` is an optional plug-in applied to the unified-search output
10
+ * after per-source merge but before the final `slice(0, limit)`. It lets a
11
+ * host swap in a cross-encoder, a learned ranker, or any other deterministic
12
+ * ordering without changing the retrieval pipeline.
13
+ *
14
+ * Implementations MUST be deterministic for the same `(query, candidates)`
15
+ * pair — non-deterministic orderings would defeat the existing
16
+ * `rrfScore`/`similarity` tie-break tests.
17
+ */
18
+ interface RerankerCandidate {
19
+ id: string;
20
+ content: string;
21
+ metadata?: Record<string, unknown>;
22
+ }
23
+ interface RerankerInput {
24
+ query: string;
25
+ candidates: RerankerCandidate[];
26
+ topK?: number;
27
+ }
28
+ interface RerankerScore {
29
+ id: string;
30
+ score: number;
31
+ }
32
+ interface Reranker {
33
+ rerank(input: RerankerInput): Promise<RerankerScore[]>;
34
+ }
35
+
1
36
  /**
2
37
  * Pure helpers used by the unified memory search pipeline.
3
38
  *
@@ -5,6 +40,7 @@
5
40
  * and the HTTP daemon without pulling in any of the heavier
6
41
  * storage/search implementations.
7
42
  */
43
+
8
44
  type UnifiedMemorySearchSource = "memory" | "insights" | "knowledge";
9
45
  type UnifiedMemoryReasoningStrategy = "none" | "rewrite" | "iterative";
10
46
  interface UnifiedMemorySearchWarning {
@@ -81,12 +117,28 @@ interface UnifiedMemorySearchInput {
81
117
  * lists fed via the (internal) `rankedLists` option.
82
118
  */
83
119
  mergeStrategy?: UnifiedMemoryMergeStrategy;
120
+ /**
121
+ * Optional additive scope-narrowing filter expressed as structured
122
+ * peers. Coexists with `userId`/`botIds`. When supplied, the host's
123
+ * `UnifiedSearchDeps.peerScopeCheck` is consulted; peers that fall
124
+ * outside `userId` are dropped with a `peer_filter_outside_user_scope`
125
+ * warning rather than broadening the scope.
126
+ */
127
+ peerFilter?: ReadonlyArray<Peer>;
84
128
  /**
85
129
  * Optional reasoning strategy. `"rewrite"` rewrites the query before
86
130
  * embedding; `"iterative"` runs an LLM planner that searches, notes
87
131
  * evidence, and searches again. Defaults to `"none"`.
88
132
  */
89
133
  reasoningStrategy?: UnifiedMemoryReasoningStrategy;
134
+ /**
135
+ * Optional `FactType` read-side filter. When supplied, the memory
136
+ * source narrows candidates to rows whose `factType` is in this set.
137
+ * Only affects the `memory` source; `insights` and `knowledge` are
138
+ * not filtered by this. Empty array is treated as "no filter" so
139
+ * callers can pass `searchInput.factTypes ?? []` without surprises.
140
+ */
141
+ factTypes?: FactType[];
90
142
  }
91
143
  type UnifiedMemoryMergeStrategy = "similarity" | "rrf";
92
144
  /**
@@ -95,7 +147,9 @@ type UnifiedMemoryMergeStrategy = "similarity" | "rrf";
95
147
  * flattening them into a single similarity score first.
96
148
  */
97
149
  interface UnifiedMemoryRankedList {
98
- name: "memory-bm25" | "memory-semantic" | "insights" | "knowledge";
150
+ /** Label for the source list (e.g. a tier or channel). Free-form; the
151
+ * RRF fusion only reads `hits`, so `name` is purely diagnostic. */
152
+ name: string;
99
153
  hits: UnifiedMemorySearchResult[];
100
154
  }
101
155
  interface UnifiedMemorySearchResult {
@@ -118,6 +172,83 @@ interface UnifiedMemorySearchOutput {
118
172
  */
119
173
  reasoning?: UnifiedMemoryReasoningInfo;
120
174
  }
175
+ /**
176
+ * Cross-source retrieval surface for the unified search. Mirrors
177
+ * `UnifiedMemorySearchSource` but is exposed under a more discoverable
178
+ * name.
179
+ */
180
+ type SearchSource = UnifiedMemorySearchSource;
181
+ /**
182
+ * Per-tier evidence bucket consulted by `reflect`-style synthesis.
183
+ * Includes the `summary` tier that the read-only sources do not surface.
184
+ */
185
+ type SearchTier = "summary" | "raw" | "insight" | "knowledge";
186
+ interface SearchInput {
187
+ userId: string;
188
+ query: string;
189
+ /** Cross-source retrieval surface (defaults to all three sources). */
190
+ sources?: ReadonlyArray<SearchSource>;
191
+ /**
192
+ * Per-tier subset — when omitted, defaults to all four tiers.
193
+ * Forwarded to the gather step so the read pipeline can scope the
194
+ * evidence. Most callers pass nothing; `synthesize` callers can
195
+ * narrow to `["raw"]` or `["summary", "raw"]` for cheaper synthesis.
196
+ */
197
+ tiers?: ReadonlyArray<SearchTier>;
198
+ /**
199
+ * Opt-in LLM synthesis. When `true`, runs `reasoning.complete` after
200
+ * gathering evidence and returns `answer` in the output. When
201
+ * omitted / `false`, no LLM call is made (matches today's
202
+ * `searchUnifiedMemory`). The `responseSchema` form lets the LLM
203
+ * return JSON; the SDK extracts `{ answer: string }` from the
204
+ * payload and surfaces the rest via warnings.
205
+ */
206
+ synthesize?: boolean | {
207
+ responseSchema?: Record<string, unknown>;
208
+ };
209
+ limit?: number;
210
+ threshold?: number;
211
+ botIds?: string[];
212
+ documentIds?: string[];
213
+ dateFrom?: string;
214
+ dateTo?: string;
215
+ asOf?: string;
216
+ peerFilter?: ReadonlyArray<Peer>;
217
+ authToken?: string;
218
+ factTypes?: FactType[];
219
+ mergeStrategy?: UnifiedMemoryMergeStrategy;
220
+ reasoningStrategy?: UnifiedMemoryReasoningStrategy;
221
+ /**
222
+ * Backward-compat pass-through for callers that previously passed
223
+ * `responseSchema` at the top level. When set, it overrides
224
+ * `synthesize.responseSchema`.
225
+ */
226
+ responseSchema?: Record<string, unknown>;
227
+ /**
228
+ * Backward-compat pass-through for callers that previously passed
229
+ * `includeArchivedInsights` to the read-only search.
230
+ */
231
+ includeArchivedInsights?: boolean;
232
+ }
233
+ interface SearchEvidence {
234
+ id: string;
235
+ source: SearchSource | SearchTier;
236
+ snippet: string;
237
+ score: number;
238
+ timestamp?: number;
239
+ }
240
+ interface SearchOutput {
241
+ query: string;
242
+ sources: ReadonlyArray<SearchSource>;
243
+ results: UnifiedMemorySearchResult[];
244
+ /** Same hits as `results`, with the source labelled for synthesis callers. */
245
+ evidence: SearchEvidence[];
246
+ count: number;
247
+ warnings: UnifiedMemorySearchWarning[];
248
+ reasoning?: UnifiedMemoryReasoningInfo;
249
+ /** Only present when `synthesize` was truthy. */
250
+ answer?: string;
251
+ }
121
252
  declare function normalizeUnifiedMemorySearchSources(sources: unknown): UnifiedMemorySearchSource[];
122
253
  declare function clampUnifiedMemorySearchLimit(limit: unknown): number;
123
254
  declare function clampUnifiedMemorySearchThreshold(threshold: unknown): number;
@@ -372,6 +503,16 @@ interface UnifiedSearchInsightsResult {
372
503
  metadata: Record<string, unknown>;
373
504
  }
374
505
  interface UnifiedSearchReasoningDeps {
506
+ /**
507
+ * LLM single-turn synthesis callback. Wired into
508
+ * `search({ synthesize: true })` so a host that wants synthesis
509
+ * responses only has to drop in one callable. When omitted, the
510
+ * synthesis path returns the gathered evidence with a
511
+ * `synthesize_llm_not_configured` warning instead of throwing.
512
+ */
513
+ complete?: (prompt: string) => Promise<string>;
514
+ /** Default merge strategy used by `searchUnifiedMemory` when the caller does not specify one. @default "rrf" */
515
+ defaultMergeStrategy?: UnifiedMemoryMergeStrategy;
375
516
  /** Optional query rewriter. When present, "rewrite" strategy is available. */
376
517
  queryRewriter?: QueryRewriter;
377
518
  /** Optional iterative recall planner. When present, "iterative" strategy is available. */
@@ -379,6 +520,14 @@ interface UnifiedSearchReasoningDeps {
379
520
  /** Default reasoning strategy when callers do not specify one. @default "none" */
380
521
  defaultStrategy?: UnifiedMemoryReasoningStrategy;
381
522
  }
523
+ interface MemorySummaryHit {
524
+ summaryId: string;
525
+ summaryText: string;
526
+ summaryTier?: "L1" | "L2" | "L3";
527
+ keywords?: string[];
528
+ startTimestamp?: number;
529
+ endTimestamp?: number;
530
+ }
382
531
  interface UnifiedSearchDeps {
383
532
  /** Embed a query string using the active user's provider. */
384
533
  embedQuery?: EmbedQueryFn;
@@ -394,6 +543,10 @@ interface UnifiedSearchDeps {
394
543
  limit: number;
395
544
  threshold: number;
396
545
  botId?: string;
546
+ /** Optional peer scope resolved from `UnifiedMemorySearchInput.peerFilter`. */
547
+ peers?: ReadonlyArray<Peer>;
548
+ /** Optional `FactType` filter resolved from `UnifiedMemorySearchInput.factTypes`. */
549
+ factTypes?: FactType[];
397
550
  }) => Promise<Array<{
398
551
  id: string;
399
552
  content: string;
@@ -410,6 +563,8 @@ interface UnifiedSearchDeps {
410
563
  documentIds?: string[];
411
564
  };
412
565
  authToken?: string;
566
+ /** Optional peer scope resolved from `UnifiedMemorySearchInput.peerFilter`. */
567
+ peers?: ReadonlyArray<Peer>;
413
568
  }) => Promise<UnifiedSearchKnowledgeResult[]>;
414
569
  /** Semantic search over extracted insights. */
415
570
  searchInsights?: (input: {
@@ -420,6 +575,8 @@ interface UnifiedSearchDeps {
420
575
  botIds?: string[];
421
576
  includeArchived?: boolean;
422
577
  authToken?: string;
578
+ /** Optional peer scope resolved from `UnifiedMemorySearchInput.peerFilter`. */
579
+ peers?: ReadonlyArray<Peer>;
423
580
  }) => Promise<UnifiedSearchInsightsResult[]>;
424
581
  /**
425
582
  * Optional BM25 (lexical) sub-query for the memory source. Mirrors the
@@ -432,14 +589,58 @@ interface UnifiedSearchDeps {
432
589
  keywords: string[];
433
590
  limit: number;
434
591
  botId?: string;
592
+ /** Optional peer scope resolved from `UnifiedMemorySearchInput.peerFilter`. */
593
+ peers?: ReadonlyArray<Peer>;
594
+ /** Optional `FactType` filter resolved from `UnifiedMemorySearchInput.factTypes`. */
595
+ factTypes?: FactType[];
435
596
  }) => Promise<Array<{
436
597
  id: string;
437
598
  content: string;
438
599
  similarity: number;
439
600
  metadata: Record<string, unknown>;
440
601
  }>>;
602
+ /**
603
+ * Optional summary-tier search. When wired in, `reflect()` consults the
604
+ * summary tier alongside raw messages and emits a
605
+ * `reflect_summaries_unavailable` warning if the call fails.
606
+ */
607
+ searchSummaries?: (input: {
608
+ userId: string;
609
+ query: string;
610
+ keywords: string[];
611
+ limit: number;
612
+ threshold: number;
613
+ dateFrom?: string;
614
+ dateTo?: string;
615
+ authToken?: string;
616
+ /** Optional peer scope resolved from `UnifiedMemorySearchInput.peerFilter`. */
617
+ peers?: ReadonlyArray<Peer>;
618
+ }) => Promise<MemorySummaryHit[]>;
619
+ /**
620
+ * Optional host-side check that validates whether a `peerFilter` peer is
621
+ * actually reachable from this `userId`. Used by
622
+ * `resolveScopePeer` to drop out-of-scope peers with a warning
623
+ * rather than broadening the search. May be omitted for hosts that
624
+ * have no peer-permission model.
625
+ */
626
+ peerScopeCheck?: (input: {
627
+ userId: string;
628
+ peers: ReadonlyArray<_melandlabs_contracts_peer.Peer>;
629
+ }) => Promise<boolean> | boolean;
441
630
  /** Optional reasoning providers. */
442
631
  reasoning?: UnifiedSearchReasoningDeps;
632
+ /**
633
+ * Optional reranker applied after per-source merge and before the
634
+ * final limit. Defaults to an identity pass-through so the merge order
635
+ * is preserved.
636
+ */
637
+ reranker?: Reranker;
638
+ /**
639
+ * Optional logger. When set (e.g. via `MemoryStoreConfig.logger`),
640
+ * `reflect` / `consolidate` log through it instead of `console`.
641
+ * Falls back to `console` when omitted.
642
+ */
643
+ logger?: Pick<Console, "log" | "warn" | "error">;
443
644
  }
444
645
  interface MemoryStoreConfig {
445
646
  /**
@@ -463,8 +664,20 @@ interface MemoryStoreConfig {
463
664
  vector?: MemoryStoreVectorConfig;
464
665
  /** Optional cross-source search providers. */
465
666
  unified?: UnifiedSearchDeps;
667
+ /**
668
+ * Optional write-back graph store. When set, `createMemoryStore` wires
669
+ * it into `store.graphStore` and forwards it to `consolidate`. Hosts
670
+ * that prefer post-construction wiring can use `attachMemoryGraphStore`.
671
+ */
672
+ graphStore?: _melandlabs_memory_consolidation.MemoryGraphStoreWithOperationHistory;
673
+ /**
674
+ * Optional storage adapter carrying `deprecateRecords`. Forwarded into
675
+ * `consolidate` for callers that want deprecation writes without
676
+ * attaching a full graph store.
677
+ */
678
+ storage?: _melandlabs_memory_consolidation.MemoryStorageAdapterLike;
466
679
  /** Optional logger. Defaults to console. */
467
680
  logger?: Pick<Console, "log" | "warn" | "error">;
468
681
  }
469
682
 
470
- export { isRawMemorySemanticResult as A, mergeUnifiedMemorySearchResults as B, normalizeUnifiedMemoryReasoningStrategy as C, normalizeUnifiedMemorySearchSources as D, type EmbedQueryFn as E, toKnowledgeResult as F, toMemoryResult as G, type UnifiedSearchDeps as H, type IterativeRecallCandidate as I, type UnifiedMemoryMergeStrategy as J, type UnifiedMemoryRankedList as K, mergeUnifiedMemorySearchResultsRrf as L, type MemoryStoreConfig as M, normalizeUnifiedMemoryMergeStrategy as N, type QueryRewriter as Q, type UnifiedMemoryReasoningInfo as U, type VectorBackend as V, type IterativeRecallExecutor as a, type IterativeRecallPlanner as b, type IterativeRecallPlannerOptions as c, type IterativeRecallResult as d, type IterativeRecallSearchRequest as e, type IterativeRecallSearchResult as f, type IterativeRecallStats as g, type MemoryStoreDb as h, type MemoryStoreEnv as i, type QueryRewriterInput as j, type QueryRewriterOptions as k, type UnifiedMemoryReasoningStrategy as l, type UnifiedMemorySearchInput as m, type UnifiedMemorySearchOutput as n, type UnifiedMemorySearchResult as o, type UnifiedMemorySearchSource as p, type UnifiedMemorySearchWarning as q, type UnifiedSearchInsightsResult as r, type UnifiedSearchKnowledgeResult as s, type UnifiedSearchReasoningDeps as t, clampUnifiedMemorySearchLimit as u, clampUnifiedMemorySearchThreshold as v, createIdentityIterativePlanner as w, createIdentityRewriter as x, createIterativeRecallPlanner as y, createUserVoiceRewriter as z };
683
+ export { type IterativeRecallResult as A, type IterativeRecallSearchRequest as B, type IterativeRecallSearchResult as C, type IterativeRecallStats as D, type EmbedQueryFn as E, type MemoryStoreDb as F, type QueryRewriterInput as G, type QueryRewriterOptions as H, type IterativeRecallCandidate as I, type UnifiedMemoryReasoningInfo as J, type UnifiedSearchInsightsResult as K, type UnifiedSearchKnowledgeResult as L, type MemoryStoreConfig as M, type UnifiedSearchReasoningDeps as N, createIdentityIterativePlanner as O, createIdentityRewriter as P, type QueryRewriter as Q, createIterativeRecallPlanner as R, type SearchTier as S, createUserVoiceRewriter as T, type UnifiedSearchDeps as U, type VectorBackend as V, type MemoryStoreEnv as a, type UnifiedMemorySearchWarning as b, type SearchEvidence as c, type SearchInput as d, type SearchOutput as e, type UnifiedMemorySearchInput as f, type UnifiedMemorySearchOutput as g, type UnifiedMemorySearchResult as h, type SearchSource as i, type UnifiedMemoryMergeStrategy as j, type UnifiedMemoryRankedList as k, type UnifiedMemoryReasoningStrategy as l, type UnifiedMemorySearchSource as m, clampUnifiedMemorySearchLimit as n, clampUnifiedMemorySearchThreshold as o, isRawMemorySemanticResult as p, mergeUnifiedMemorySearchResults as q, mergeUnifiedMemorySearchResultsRrf as r, normalizeUnifiedMemoryMergeStrategy as s, normalizeUnifiedMemoryReasoningStrategy as t, normalizeUnifiedMemorySearchSources as u, toKnowledgeResult as v, toMemoryResult as w, type IterativeRecallExecutor as x, type IterativeRecallPlanner as y, type IterativeRecallPlannerOptions as z };
@@ -1,4 +1,5 @@
1
1
  import { MemoryRecord } from '@melandlabs/ai/memory';
2
+ export { StoreVsaFactInput, StoreVsaFactOutput, VsaFact, VsaFactStorage, VsaFactSummary, VsaForgetInput, VsaForgetOutput, VsaListInput, VsaRecallInput, VsaRecallOutput, VsaRecallScore, VsaVocabularyEntry, vsaAssertSameDim, vsaNormalizeVector } from '@melandlabs/contracts';
2
3
 
3
4
  /**
4
5
  * Memory-store contracts — types and constants that were originally re-exported
package/dist/contracts.js CHANGED
@@ -1,3 +1,5 @@
1
+ export { vsaAssertSameDim, vsaNormalizeVector } from '@melandlabs/contracts';
2
+
1
3
  // src/contracts.ts
2
4
  var CHAT_MEMORY_EVIDENCE_ID_PREFIX = "opencontext-chat:";
3
5
  function normalizeTimestampToMs(value) {
package/dist/http.d.ts CHANGED
@@ -1,4 +1,7 @@
1
- import { M as MemoryStoreConfig } from './config-2Q092MUz.js';
1
+ import { M as MemoryStoreConfig } from './config-CnbqSek5.js';
2
+ import '@melandlabs/memory-consolidation';
3
+ import '@melandlabs/contracts/peer';
4
+ import '@melandlabs/contracts';
2
5
 
3
6
  /**
4
7
  * @melandlabs/memory-store/http — HTTP server entry.
@@ -11,10 +14,16 @@ import { M as MemoryStoreConfig } from './config-2Q092MUz.js';
11
14
  * });
12
15
  *
13
16
  * Endpoints (all POST, JSON in/out):
14
- * GET /health → { ok: true }
15
- * POST /v1/search → UnifiedMemorySearchOutput
16
- * POST /v1/raw-messages → upsert raw messages (returns count)
17
- * GET /v1/raw-messages/:id → single raw message
17
+ * GET /health → { ok: true }
18
+ * POST /v1/search → SearchOutput (set `synthesize: true` for
19
+ * LLM synthesis)
20
+ * POST /v1/raw-messages → upsert raw messages (returns count)
21
+ * GET /v1/raw-messages/:id → single raw message
22
+ * POST /v1/consolidate:apply → ApplyConsolidateOutput (agentic write-back)
23
+ * POST /v1/vsa/store → StoreVsaFactOutput
24
+ * POST /v1/vsa/recall → VsaRecallOutput
25
+ * POST /v1/vsa/list → VsaFactSummary[]
26
+ * POST /v1/vsa/forget → VsaForgetOutput
18
27
  *
19
28
  * `POST /v1/raw-messages` supports two body keys beyond `userId` /
20
29
  * `messages[]`:
@@ -29,6 +38,13 @@ import { M as MemoryStoreConfig } from './config-2Q092MUz.js';
29
38
  * and the messages persist without an embedding (so ANN search
30
39
  * won't return them).
31
40
  *
41
+ * `POST /v1/consolidate:apply` runs the same evidence pipeline as
42
+ * `POST /v1/search` with `synthesize: true`, then builds a
43
+ * memory-consolidation plan, optionally asks the LLM to veto unsafe
44
+ * entries, and persists via the attached graph store (when the host
45
+ * wired one into `options.graphStore`) + soft-deprecates superseded
46
+ * records via the storage adapter.
47
+ *
32
48
  * The HTTP server speaks only to the raw-message + vector layers; it does
33
49
  * not expose RAG/insights cross-source search (callers wire those up
34
50
  * server-side or use the MCP server with a fully-wired store).