@melandlabs/memory-store 1.1.8 → 1.2.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.
@@ -2,6 +2,8 @@ import * as _melandlabs_memory_consolidation from '@melandlabs/memory-consolidat
2
2
  import * as _melandlabs_contracts_peer from '@melandlabs/contracts/peer';
3
3
  import { Peer } from '@melandlabs/contracts/peer';
4
4
  import { FactType } from '@melandlabs/contracts';
5
+ import { DerivedFact } from '@melandlabs/contracts/derived-fact';
6
+ import { EntityEdge } from '@melandlabs/contracts/entity-edge';
5
7
 
6
8
  /**
7
9
  * Reranker adapter contract.
@@ -42,6 +44,49 @@ interface Reranker {
42
44
  */
43
45
 
44
46
  type UnifiedMemorySearchSource = "memory" | "insights" | "knowledge";
47
+ /**
48
+ * A retrieval channel that contributed to a hit's final score.
49
+ *
50
+ * - `semantic` — dense embedding lookup (`searchRawMessagesAnn` or
51
+ * the SQLite manager's semantic-search fallback).
52
+ * - `lexical` — BM25 / FTS5 keyword match
53
+ * (`searchRawMessagesLexical` or the SQLite manager's lexical
54
+ * fallback).
55
+ * - `entity` — entity-link match supplied by the host's
56
+ * `entitySearch` dep.
57
+ */
58
+ type HitChannel = "semantic" | "lexical" | "entity";
59
+ /**
60
+ * Per-hit score breakdown. Always emitted by `search()` (default merge
61
+ * strategy) so callers can threshold / re-rank without losing the
62
+ * individual channel contributions. The RRF fusion additionally
63
+ * populates `signals.rrf` and continues to mirror the fused score
64
+ * onto `metadata.rrfScore` (legacy field).
65
+ *
66
+ * Each numeric field is the raw per-channel score for the *first*
67
+ * (highest-ranked) appearance of the same `(type, id)` key in the
68
+ * channel's list. Channels that did not contribute are `undefined`.
69
+ */
70
+ interface HitSignals {
71
+ /** Channels the hit actually appeared in. */
72
+ channels: HitChannel[];
73
+ /** Semantic sub-query similarity in [0..1] (undefined when absent). */
74
+ semantic?: number;
75
+ /** Lexical sub-query BM25 score (undefined when absent). */
76
+ lexical?: number;
77
+ /** Entity sub-query match score (undefined when absent). */
78
+ entity?: number;
79
+ /** RRF-fused score (only when mergeStrategy === "rrf"). */
80
+ rrf?: number;
81
+ }
82
+ /**
83
+ * Derive simple lexical keywords from a query string. Splits on any
84
+ * non-letter/non-digit Unicode boundary, lowercases, drops tokens
85
+ * shorter than 2 chars, and caps the list at 16. Used by the unified
86
+ * search lexical sub-query and by the `derive` primitive's candidate
87
+ * fetch fallback.
88
+ */
89
+ declare function deriveLexicalKeywords(query: string): string[];
45
90
  type UnifiedMemoryReasoningStrategy = "none" | "rewrite" | "iterative";
46
91
  interface UnifiedMemorySearchWarning {
47
92
  source: UnifiedMemorySearchSource;
@@ -158,6 +203,12 @@ interface UnifiedMemorySearchResult {
158
203
  content: string;
159
204
  similarity: number;
160
205
  metadata: Record<string, unknown>;
206
+ /**
207
+ * Optional per-channel score breakdown. Always populated by the
208
+ * pipeline when at least one channel contributed a non-empty list;
209
+ * callers should treat absence as "no channel info available".
210
+ */
211
+ signals?: HitSignals;
161
212
  }
162
213
  interface UnifiedMemorySearchOutput {
163
214
  query: string;
@@ -280,6 +331,28 @@ declare function toMemoryResult(result: {
280
331
  similarity: number;
281
332
  metadata: Record<string, unknown>;
282
333
  }): UnifiedMemorySearchResult;
334
+ /**
335
+ * Build the `signals` breakdown for a single hit from the per-channel
336
+ * ranked lists it appeared in. Only the highest-ranked (i.e. first)
337
+ * appearance of `(type, id)` per channel contributes — duplicate hits
338
+ * later in the same list are ignored so the breakdown stays
339
+ * deterministic.
340
+ *
341
+ * Used by `mergeAcrossSources` to attach `signals` to every emitted
342
+ * `UnifiedMemorySearchResult`. Pure; no I/O.
343
+ */
344
+ declare function materializeSignals(lists: ReadonlyArray<{
345
+ name: string;
346
+ hits: UnifiedMemorySearchResult[];
347
+ }>, hit: UnifiedMemorySearchResult): HitSignals | undefined;
348
+ /**
349
+ * Map a `UnifiedMemoryRankedList.name` to a `HitChannel`. Unknown names
350
+ * (e.g. "insights", "knowledge", "summary") are not channels — they
351
+ * surface their similarity through the merge's `similarity` field and
352
+ * are simply skipped here so callers can still see which channel set
353
+ * the hit came from.
354
+ */
355
+ declare function listNameToChannel(name: string): HitChannel | undefined;
283
356
  declare function isRawMemorySemanticResult(result: unknown): result is {
284
357
  id: string;
285
358
  content: string;
@@ -616,6 +689,69 @@ interface UnifiedSearchDeps {
616
689
  /** Optional peer scope resolved from `UnifiedMemorySearchInput.peerFilter`. */
617
690
  peers?: ReadonlyArray<Peer>;
618
691
  }) => Promise<MemorySummaryHit[]>;
692
+ /**
693
+ * Optional entity sub-query provider. Hosts wire this in to opt
694
+ * into the `entity` channel of unified search: matches are
695
+ * projected back as `UnifiedMemorySearchResult`s and fused with
696
+ * semantic + lexical via RRF. Without it, the entity channel is
697
+ * skipped silently (with a `memory_entity_search_not_configured`
698
+ * warning when RRF was requested).
699
+ *
700
+ * The provider is intentionally narrow: it returns `(messageId,
701
+ * label, score)` tuples. The host is responsible for keeping its
702
+ * own entity store (graph nodes, separate SQLite table, etc.) —
703
+ * the SDK never persists entity edges itself.
704
+ */
705
+ entitySearch?: (input: {
706
+ userId: string;
707
+ keywords: string[];
708
+ limit: number;
709
+ botId?: string;
710
+ /** Optional peer scope resolved from `UnifiedMemorySearchInput.peerFilter`. */
711
+ peers?: ReadonlyArray<Peer>;
712
+ }) => Promise<Array<{
713
+ messageId: string;
714
+ label: string;
715
+ score: number;
716
+ }>>;
717
+ /**
718
+ * Optional entity extractor wired into the `distill` primitive. The
719
+ * extractor receives the raw message text and returns a batch of
720
+ * `EntityEdge`s the host may persist via the `persist` callback
721
+ * supplied on the `distill` input.
722
+ *
723
+ * When omitted, `distill` short-circuits with a
724
+ * `distill_extractor_not_configured` warning — matching the
725
+ * `memory_iterative_planner_not_configured` precedent.
726
+ */
727
+ entityExtractor?: (input: {
728
+ userId: string;
729
+ messageId: string;
730
+ content: string;
731
+ }) => Promise<EntityEdge[]>;
732
+ /**
733
+ * Optional deriver wired into the `derive` primitive. The deriver
734
+ * receives a window of candidate fact texts and returns a batch of
735
+ * `DerivedFact`s the host may persist via the `persist` callback
736
+ * supplied on the `derive` input.
737
+ *
738
+ * When omitted, `derive` short-circuits with a
739
+ * `derive_deriver_not_configured` warning — same precedent.
740
+ */
741
+ deriver?: (input: {
742
+ userId: string;
743
+ userScope: {
744
+ userId: string;
745
+ botIds?: string[];
746
+ dateFrom?: string;
747
+ dateTo?: string;
748
+ };
749
+ recentFactTexts: string[];
750
+ window?: {
751
+ from: number;
752
+ to: number;
753
+ };
754
+ }) => Promise<DerivedFact[]>;
619
755
  /**
620
756
  * Optional host-side check that validates whether a `peerFilter` peer is
621
757
  * actually reachable from this `userId`. Used by
@@ -680,4 +816,4 @@ interface MemoryStoreConfig {
680
816
  logger?: Pick<Console, "log" | "warn" | "error">;
681
817
  }
682
818
 
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 };
819
+ export { toMemoryResult as A, type IterativeRecallExecutor as B, type IterativeRecallPlanner as C, type IterativeRecallPlannerOptions as D, type EmbedQueryFn as E, type IterativeRecallResult as F, type IterativeRecallSearchRequest as G, type HitChannel as H, type IterativeRecallCandidate as I, type IterativeRecallSearchResult as J, type IterativeRecallStats as K, type MemoryStoreDb as L, type MemoryStoreConfig as M, type QueryRewriterInput as N, type QueryRewriterOptions as O, type UnifiedMemoryReasoningInfo as P, type QueryRewriter as Q, type UnifiedSearchInsightsResult as R, type SearchTier as S, type UnifiedSearchKnowledgeResult as T, type UnifiedSearchDeps as U, type UnifiedSearchReasoningDeps as V, type VectorBackend as W, createIdentityIterativePlanner as X, createIdentityRewriter as Y, createIterativeRecallPlanner as Z, createUserVoiceRewriter as _, 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 HitSignals as i, type SearchSource as j, type UnifiedMemoryMergeStrategy as k, type UnifiedMemoryRankedList as l, type UnifiedMemoryReasoningStrategy as m, type UnifiedMemorySearchSource as n, clampUnifiedMemorySearchLimit as o, clampUnifiedMemorySearchThreshold as p, deriveLexicalKeywords as q, isRawMemorySemanticResult as r, listNameToChannel as s, materializeSignals as t, mergeUnifiedMemorySearchResults as u, mergeUnifiedMemorySearchResultsRrf as v, normalizeUnifiedMemoryMergeStrategy as w, normalizeUnifiedMemoryReasoningStrategy as x, normalizeUnifiedMemorySearchSources as y, toKnowledgeResult as z };
package/dist/http.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { M as MemoryStoreConfig } from './config-CnbqSek5.js';
1
+ import { M as MemoryStoreConfig } from './config-DfvVZ--0.js';
2
2
  import '@melandlabs/memory-consolidation';
3
3
  import '@melandlabs/contracts/peer';
4
4
  import '@melandlabs/contracts';
5
+ import '@melandlabs/contracts/derived-fact';
6
+ import '@melandlabs/contracts/entity-edge';
5
7
 
6
8
  /**
7
9
  * @melandlabs/memory-store/http — HTTP server entry.
@@ -16,7 +18,14 @@ import '@melandlabs/contracts';
16
18
  * Endpoints (all POST, JSON in/out):
17
19
  * GET /health → { ok: true }
18
20
  * POST /v1/search → SearchOutput (set `synthesize: true` for
19
- * LLM synthesis)
21
+ * LLM synthesis). Each hit carries a
22
+ * `signals` field with per-channel scores.
23
+ * POST /v1/distill → DistillOutput (entity extraction from
24
+ * a single raw message; requires
25
+ * `unified.entityExtractor`)
26
+ * POST /v1/derive → DeriveOutput (fact derivation over a
27
+ * window of candidate texts; requires
28
+ * `unified.deriver`)
20
29
  * POST /v1/raw-messages → upsert raw messages (returns count)
21
30
  * GET /v1/raw-messages/:id → single raw message
22
31
  * POST /v1/consolidate:apply → ApplyConsolidateOutput (agentic write-back)