mem-os-python 1.6.27__py3-none-any.whl
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.
- mem_os_python-1.6.27.dist-info/METADATA +1032 -0
- mem_os_python-1.6.27.dist-info/RECORD +253 -0
- mem_os_python-1.6.27.dist-info/WHEEL +4 -0
- mem_os_python-1.6.27.dist-info/entry_points.txt +2 -0
- mem_os_python-1.6.27.dist-info/licenses/LICENSE +21 -0
- memos/__init__.py +16 -0
- memos/_js/adapters/anthropic.d.ts +279 -0
- memos/_js/adapters/anthropic.d.ts.map +1 -0
- memos/_js/adapters/anthropic.js +348 -0
- memos/_js/adapters/anthropic.js.map +1 -0
- memos/_js/adapters/base.d.ts +10 -0
- memos/_js/adapters/base.d.ts.map +1 -0
- memos/_js/adapters/base.js +2 -0
- memos/_js/adapters/base.js.map +1 -0
- memos/_js/adapters/openai.d.ts +264 -0
- memos/_js/adapters/openai.d.ts.map +1 -0
- memos/_js/adapters/openai.js +342 -0
- memos/_js/adapters/openai.js.map +1 -0
- memos/_js/apps/explorer.d.ts +244 -0
- memos/_js/apps/explorer.d.ts.map +1 -0
- memos/_js/apps/explorer.js +738 -0
- memos/_js/apps/explorer.js.map +1 -0
- memos/_js/citations.d.ts +65 -0
- memos/_js/citations.d.ts.map +1 -0
- memos/_js/citations.js +143 -0
- memos/_js/citations.js.map +1 -0
- memos/_js/cli-browse.d.ts +3 -0
- memos/_js/cli-browse.d.ts.map +1 -0
- memos/_js/cli-browse.js +129 -0
- memos/_js/cli-browse.js.map +1 -0
- memos/_js/cli-completion.d.ts +31 -0
- memos/_js/cli-completion.d.ts.map +1 -0
- memos/_js/cli-completion.js +340 -0
- memos/_js/cli-completion.js.map +1 -0
- memos/_js/cli-help.d.ts +18 -0
- memos/_js/cli-help.d.ts.map +1 -0
- memos/_js/cli-help.js +357 -0
- memos/_js/cli-help.js.map +1 -0
- memos/_js/cli.d.ts +28 -0
- memos/_js/cli.d.ts.map +1 -0
- memos/_js/cli.js +2880 -0
- memos/_js/cli.js.map +1 -0
- memos/_js/compression.d.ts +25 -0
- memos/_js/compression.d.ts.map +1 -0
- memos/_js/compression.js +319 -0
- memos/_js/compression.js.map +1 -0
- memos/_js/confidence-machine.d.ts +99 -0
- memos/_js/confidence-machine.d.ts.map +1 -0
- memos/_js/confidence-machine.js +222 -0
- memos/_js/confidence-machine.js.map +1 -0
- memos/_js/context-pack.d.ts +506 -0
- memos/_js/context-pack.d.ts.map +1 -0
- memos/_js/context-pack.js +1435 -0
- memos/_js/context-pack.js.map +1 -0
- memos/_js/contradictions.d.ts +160 -0
- memos/_js/contradictions.d.ts.map +1 -0
- memos/_js/contradictions.js +255 -0
- memos/_js/contradictions.js.map +1 -0
- memos/_js/dashboard.d.ts +30 -0
- memos/_js/dashboard.d.ts.map +1 -0
- memos/_js/dashboard.js +302 -0
- memos/_js/dashboard.js.map +1 -0
- memos/_js/ebbinghaus.d.ts +29 -0
- memos/_js/ebbinghaus.d.ts.map +1 -0
- memos/_js/ebbinghaus.js +32 -0
- memos/_js/ebbinghaus.js.map +1 -0
- memos/_js/embedding-queue.d.ts +190 -0
- memos/_js/embedding-queue.d.ts.map +1 -0
- memos/_js/embedding-queue.js +316 -0
- memos/_js/embedding-queue.js.map +1 -0
- memos/_js/embeddings.d.ts +187 -0
- memos/_js/embeddings.d.ts.map +1 -0
- memos/_js/embeddings.js +633 -0
- memos/_js/embeddings.js.map +1 -0
- memos/_js/entity-extraction.d.ts +54 -0
- memos/_js/entity-extraction.d.ts.map +1 -0
- memos/_js/entity-extraction.js +325 -0
- memos/_js/entity-extraction.js.map +1 -0
- memos/_js/entity-index.d.ts +93 -0
- memos/_js/entity-index.d.ts.map +1 -0
- memos/_js/entity-index.js +165 -0
- memos/_js/entity-index.js.map +1 -0
- memos/_js/event-memory.d.ts +147 -0
- memos/_js/event-memory.d.ts.map +1 -0
- memos/_js/event-memory.js +290 -0
- memos/_js/event-memory.js.map +1 -0
- memos/_js/external-import.d.ts +98 -0
- memos/_js/external-import.d.ts.map +1 -0
- memos/_js/external-import.js +669 -0
- memos/_js/external-import.js.map +1 -0
- memos/_js/fidelity.d.ts +367 -0
- memos/_js/fidelity.d.ts.map +1 -0
- memos/_js/fidelity.js +911 -0
- memos/_js/fidelity.js.map +1 -0
- memos/_js/graph-expansion.d.ts +119 -0
- memos/_js/graph-expansion.d.ts.map +1 -0
- memos/_js/graph-expansion.js +213 -0
- memos/_js/graph-expansion.js.map +1 -0
- memos/_js/graph-mermaid.d.ts +13 -0
- memos/_js/graph-mermaid.d.ts.map +1 -0
- memos/_js/graph-mermaid.js +32 -0
- memos/_js/graph-mermaid.js.map +1 -0
- memos/_js/graph.d.ts +170 -0
- memos/_js/graph.d.ts.map +1 -0
- memos/_js/graph.js +482 -0
- memos/_js/graph.js.map +1 -0
- memos/_js/harness.d.ts +63 -0
- memos/_js/harness.d.ts.map +1 -0
- memos/_js/harness.js +93 -0
- memos/_js/harness.js.map +1 -0
- memos/_js/importance.d.ts +118 -0
- memos/_js/importance.d.ts.map +1 -0
- memos/_js/importance.js +144 -0
- memos/_js/importance.js.map +1 -0
- memos/_js/index.d.ts +51 -0
- memos/_js/index.d.ts.map +1 -0
- memos/_js/index.js +53 -0
- memos/_js/index.js.map +1 -0
- memos/_js/mcp.d.ts +58 -0
- memos/_js/mcp.d.ts.map +1 -0
- memos/_js/mcp.js +1853 -0
- memos/_js/mcp.js.map +1 -0
- memos/_js/memory.d.ts +1762 -0
- memos/_js/memory.d.ts.map +1 -0
- memos/_js/memory.js +6283 -0
- memos/_js/memory.js.map +1 -0
- memos/_js/procedural.d.ts +74 -0
- memos/_js/procedural.d.ts.map +1 -0
- memos/_js/procedural.js +125 -0
- memos/_js/procedural.js.map +1 -0
- memos/_js/project-config.d.ts +68 -0
- memos/_js/project-config.d.ts.map +1 -0
- memos/_js/project-config.js +59 -0
- memos/_js/project-config.js.map +1 -0
- memos/_js/proof-of-forgetting.d.ts +57 -0
- memos/_js/proof-of-forgetting.d.ts.map +1 -0
- memos/_js/proof-of-forgetting.js +80 -0
- memos/_js/proof-of-forgetting.js.map +1 -0
- memos/_js/provenance.d.ts +122 -0
- memos/_js/provenance.d.ts.map +1 -0
- memos/_js/provenance.js +182 -0
- memos/_js/provenance.js.map +1 -0
- memos/_js/quarantine-commands.d.ts +23 -0
- memos/_js/quarantine-commands.d.ts.map +1 -0
- memos/_js/quarantine-commands.js +42 -0
- memos/_js/quarantine-commands.js.map +1 -0
- memos/_js/quarantine.d.ts +120 -0
- memos/_js/quarantine.d.ts.map +1 -0
- memos/_js/quarantine.js +873 -0
- memos/_js/quarantine.js.map +1 -0
- memos/_js/redact.d.ts +12 -0
- memos/_js/redact.d.ts.map +1 -0
- memos/_js/redact.js +26 -0
- memos/_js/redact.js.map +1 -0
- memos/_js/repl.d.ts +57 -0
- memos/_js/repl.d.ts.map +1 -0
- memos/_js/repl.js +295 -0
- memos/_js/repl.js.map +1 -0
- memos/_js/rerank-local.d.ts +61 -0
- memos/_js/rerank-local.d.ts.map +1 -0
- memos/_js/rerank-local.js +210 -0
- memos/_js/rerank-local.js.map +1 -0
- memos/_js/retain-filter.d.ts +98 -0
- memos/_js/retain-filter.d.ts.map +1 -0
- memos/_js/retain-filter.js +232 -0
- memos/_js/retain-filter.js.map +1 -0
- memos/_js/retrieval.d.ts +265 -0
- memos/_js/retrieval.d.ts.map +1 -0
- memos/_js/retrieval.js +1018 -0
- memos/_js/retrieval.js.map +1 -0
- memos/_js/revert.d.ts +77 -0
- memos/_js/revert.d.ts.map +1 -0
- memos/_js/revert.js +252 -0
- memos/_js/revert.js.map +1 -0
- memos/_js/scope.d.ts +30 -0
- memos/_js/scope.d.ts.map +1 -0
- memos/_js/scope.js +71 -0
- memos/_js/scope.js.map +1 -0
- memos/_js/semantic-screen.d.ts +152 -0
- memos/_js/semantic-screen.d.ts.map +1 -0
- memos/_js/semantic-screen.js +290 -0
- memos/_js/semantic-screen.js.map +1 -0
- memos/_js/session-hooks.d.ts +127 -0
- memos/_js/session-hooks.d.ts.map +1 -0
- memos/_js/session-hooks.js +482 -0
- memos/_js/session-hooks.js.map +1 -0
- memos/_js/storage/sqlite.d.ts +427 -0
- memos/_js/storage/sqlite.d.ts.map +1 -0
- memos/_js/storage/sqlite.js +2428 -0
- memos/_js/storage/sqlite.js.map +1 -0
- memos/_js/sync.d.ts +213 -0
- memos/_js/sync.d.ts.map +1 -0
- memos/_js/sync.js +389 -0
- memos/_js/sync.js.map +1 -0
- memos/_js/tamper-log.d.ts +98 -0
- memos/_js/tamper-log.d.ts.map +1 -0
- memos/_js/tamper-log.js +327 -0
- memos/_js/tamper-log.js.map +1 -0
- memos/_js/temporal.d.ts +92 -0
- memos/_js/temporal.d.ts.map +1 -0
- memos/_js/temporal.js +536 -0
- memos/_js/temporal.js.map +1 -0
- memos/_js/time-travel.d.ts +38 -0
- memos/_js/time-travel.d.ts.map +1 -0
- memos/_js/time-travel.js +46 -0
- memos/_js/time-travel.js.map +1 -0
- memos/_js/timestamp-format.d.ts +18 -0
- memos/_js/timestamp-format.d.ts.map +1 -0
- memos/_js/timestamp-format.js +52 -0
- memos/_js/timestamp-format.js.map +1 -0
- memos/_js/triple-extraction.d.ts +31 -0
- memos/_js/triple-extraction.d.ts.map +1 -0
- memos/_js/triple-extraction.js +116 -0
- memos/_js/triple-extraction.js.map +1 -0
- memos/_js/types.d.ts +2474 -0
- memos/_js/types.d.ts.map +1 -0
- memos/_js/types.js +20 -0
- memos/_js/types.js.map +1 -0
- memos/_js/updater.d.ts +95 -0
- memos/_js/updater.d.ts.map +1 -0
- memos/_js/updater.js +268 -0
- memos/_js/updater.js.map +1 -0
- memos/_js/version.d.ts +17 -0
- memos/_js/version.d.ts.map +1 -0
- memos/_js/version.js +34 -0
- memos/_js/version.js.map +1 -0
- memos/_js/vision/clip-query-cache.d.ts +58 -0
- memos/_js/vision/clip-query-cache.d.ts.map +1 -0
- memos/_js/vision/clip-query-cache.js +79 -0
- memos/_js/vision/clip-query-cache.js.map +1 -0
- memos/_js/vision/clip.d.ts +113 -0
- memos/_js/vision/clip.d.ts.map +1 -0
- memos/_js/vision/clip.js +224 -0
- memos/_js/vision/clip.js.map +1 -0
- memos/_js/vision/fake-clip.d.ts +55 -0
- memos/_js/vision/fake-clip.d.ts.map +1 -0
- memos/_js/vision/fake-clip.js +122 -0
- memos/_js/vision/fake-clip.js.map +1 -0
- memos/_js/vision/index.d.ts +15 -0
- memos/_js/vision/index.d.ts.map +1 -0
- memos/_js/vision/index.js +13 -0
- memos/_js/vision/index.js.map +1 -0
- memos/_js/vision/store.d.ts +137 -0
- memos/_js/vision/store.d.ts.map +1 -0
- memos/_js/vision/store.js +383 -0
- memos/_js/vision/store.js.map +1 -0
- memos/adapters/__init__.py +0 -0
- memos/adapters/crewai.py +385 -0
- memos/adapters/langchain.py +301 -0
- memos/adapters/ollama.py +396 -0
- memos/server/__init__.py +0 -0
- memos/server/main.py +547 -0
- memos/server/routes.py +360 -0
memos/_js/memory.d.ts
ADDED
|
@@ -0,0 +1,1762 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MemoryManager — the public API surface of MemOS.
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates graph operations, persistence, auto-linking, and
|
|
5
|
+
* extractive summarisation. This is the class that application
|
|
6
|
+
* code interacts with.
|
|
7
|
+
*
|
|
8
|
+
* @module @memos/memory
|
|
9
|
+
*/
|
|
10
|
+
import { type DetectedExportSource, type ExternalImportSource } from "./external-import.js";
|
|
11
|
+
import { type CitationResolution } from "./citations.js";
|
|
12
|
+
import type { ContextPack } from "./context-pack.js";
|
|
13
|
+
import type { DeletionCertificate } from "./proof-of-forgetting.js";
|
|
14
|
+
import type { CompactOptions, CompactResult, FidelityLevel, FidelityRecallOptions, FidelityRecallResult } from "./fidelity.js";
|
|
15
|
+
import type { TamperVerifyResult } from "./tamper-log.js";
|
|
16
|
+
import type { TamperLogEntry } from "./types.js";
|
|
17
|
+
import type { RelevanceGateResult, MemoryNode, MemoryEdge, MemoryPool, MemoryScope, MemoryHistory, HistoryOptions, CreateMemoryInput, UpdateMemoryInput, ScoredMemory, SearchFilter, SemanticSearchOptions, GraphSnapshot, MemOSConfig, MemOSEvent, MemOSEventListener, ExportOptions, ExportResult, ImportOptions, ImportResult, ContextPackCompressionOptions, ContextPackWireFormat, EmbeddingRuntimeInfo, MemoryType, MemorySource, EmbeddingNodeStatusInfo, EmbeddingQueueStatus, DedupeOptions, DedupeResult, DecayForgettingOptions, DecayForgetResult, ArchiveOptions, ArchiveResult, ConsolidateOptions, ConsolidateResult, SummarizeClusterOptions, RevertOptions, RevertResult, RevertTargetResolution, RevertScopeInput, SummarizeClusterResult, ConversationMessage, ExtractFactsOptions, ExtractFactsResult, DiagnosticsResult, LessonOutcome, ProceduralLesson, ProvenanceTier, HarnessCount, HarnessMergeOptions, HarnessMergeResult } from "./types.js";
|
|
18
|
+
import type { QuarantineVerdict } from "./quarantine.js";
|
|
19
|
+
import type { AddImageMemoryOptions, AddImageMemoryResult, ImageInput, ImageSearchResult, ListImagesOptions, SearchImagesOptions } from "./types.js";
|
|
20
|
+
/**
|
|
21
|
+
* Thrown by `store({ filterRetain: true })` when the Hermes-style retain
|
|
22
|
+
* pre-filter decides the content is too low-signal to store (v1.6.26).
|
|
23
|
+
* Catch this to silently skip noise instead of treating it as an error.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* try {
|
|
27
|
+
* await memos.store("ok got it", { filterRetain: true });
|
|
28
|
+
* } catch (e) {
|
|
29
|
+
* if (e instanceof MemorySkippedError) return; // expected — low signal
|
|
30
|
+
* throw e;
|
|
31
|
+
* }
|
|
32
|
+
*/
|
|
33
|
+
export declare class MemorySkippedError extends Error {
|
|
34
|
+
readonly score: number;
|
|
35
|
+
constructor(reason: string, score: number);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Core MemOS instance. This is the primary entry point for all
|
|
39
|
+
* memory operations.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { MemOS } from "@mem-os/sdk";
|
|
44
|
+
*
|
|
45
|
+
* const memos = new MemOS({ dbPath: "./my-app.db" });
|
|
46
|
+
* await memos.init();
|
|
47
|
+
*
|
|
48
|
+
* const { node } = await memos.store("User prefers dark mode", { type: "preference" });
|
|
49
|
+
* const results = await memos.search("dark mode");
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare class MemOS {
|
|
53
|
+
private graph;
|
|
54
|
+
private storage;
|
|
55
|
+
/** In-memory snapshots for time-travel (experimental). */
|
|
56
|
+
private snapshots;
|
|
57
|
+
private config;
|
|
58
|
+
private experimental;
|
|
59
|
+
private embeddingProvider;
|
|
60
|
+
/**
|
|
61
|
+
* In-process LRU cache of query embedding vectors, keyed by
|
|
62
|
+
* `${provider.id}:${provider.model}:${query}`.
|
|
63
|
+
*
|
|
64
|
+
* Round 4 (perf): the semantic leg embeds the query on every search,
|
|
65
|
+
* and `multiStreamSearch` fans out to three pool streams — previously
|
|
66
|
+
* three identical ONNX inferences per search. Embedding is a pure
|
|
67
|
+
* function of (provider, model, query), so caching the vector is
|
|
68
|
+
* provably recall-neutral: a cache hit returns the byte-identical
|
|
69
|
+
* vector the provider would have produced. Bounded (LRU eviction) so
|
|
70
|
+
* long-lived processes cannot grow it without limit.
|
|
71
|
+
*/
|
|
72
|
+
private queryEmbeddingCache;
|
|
73
|
+
private static readonly QUERY_EMBEDDING_CACHE_MAX;
|
|
74
|
+
/**
|
|
75
|
+
* Tier-2 semantic screen for the provenance-trust write gate (intent
|
|
76
|
+
* level, fastembed embeddings — no LLM). Lazily constructed: the
|
|
77
|
+
* anchor embeddings are computed on first use and cached for the
|
|
78
|
+
* process lifetime.
|
|
79
|
+
*/
|
|
80
|
+
private semanticScreen;
|
|
81
|
+
private listeners;
|
|
82
|
+
private initialised;
|
|
83
|
+
private sweepTimer;
|
|
84
|
+
/** Background embedding queue. Null when no provider is configured. */
|
|
85
|
+
private embeddingQueue;
|
|
86
|
+
/**
|
|
87
|
+
* Per-node embedding status cache. Populated as the queue emits status
|
|
88
|
+
* callbacks and as nodes are reaped into the persisted embedding.
|
|
89
|
+
*/
|
|
90
|
+
private nodeEmbeddingStatus;
|
|
91
|
+
/**
|
|
92
|
+
* LRU cache for recent search results. Prevents re-running hybrid
|
|
93
|
+
* search (which embeds the query + scans the embedding table) when
|
|
94
|
+
* the same query is issued repeatedly within a short window.
|
|
95
|
+
* Key: `${query}::${namespace}::${limit}`. Value: { results, expiry }.
|
|
96
|
+
*/
|
|
97
|
+
private searchCache;
|
|
98
|
+
private searchCacheMaxEntries;
|
|
99
|
+
private searchCacheTtlMs;
|
|
100
|
+
/**
|
|
101
|
+
* Vision (image memory) runtime state. All three fields stay inert
|
|
102
|
+
* until `vision.enabled` is set, so a bare `new MemOS()` pays nothing
|
|
103
|
+
* and behaves exactly as it did before image memory existed.
|
|
104
|
+
*
|
|
105
|
+
* - `blobRoot` is derived once from the db path so every image write
|
|
106
|
+
* resolves the same directory.
|
|
107
|
+
* - `clipProvider` is the Track B encoder (explicit from config, or
|
|
108
|
+
* the lazily-loaded default). Null when Track B is off.
|
|
109
|
+
* - `clipQueryCache` memoizes CLIP query encodings; it is deliberately
|
|
110
|
+
* separate from `queryEmbeddingCache` so a CLIP vector can never be
|
|
111
|
+
* served to a text-semantic query.
|
|
112
|
+
*/
|
|
113
|
+
private imageBlobRoot;
|
|
114
|
+
private clipProvider;
|
|
115
|
+
private clipQueryCache;
|
|
116
|
+
/** In-flight image embeds, drained by `flushEmbeddings`. */
|
|
117
|
+
private pendingImageEmbeds;
|
|
118
|
+
/**
|
|
119
|
+
* Idempotency guard for the ranking-modulation chain (effective
|
|
120
|
+
* importance + triple boost + Ebbinghaus reinforcement).
|
|
121
|
+
*
|
|
122
|
+
* `applyRankingModulators` is additive, so running it twice would
|
|
123
|
+
* double-count. It now lives inside `hybridSearch` (so `contextPack`,
|
|
124
|
+
* `multiStreamSearch`, and the store-time evidence pass rank like
|
|
125
|
+
* `search`), while `postSortResults` — the historical owner — is still
|
|
126
|
+
* reached by `search()` on both the hybrid and the keyword-only path.
|
|
127
|
+
* `postSortResults` therefore skips the chain when it recognizes the
|
|
128
|
+
* very objects `applyRankingModulators` produced: `hybridSearch` hands
|
|
129
|
+
* back that same array, so `results[0]` is still the marked entry.
|
|
130
|
+
*/
|
|
131
|
+
private readonly rankingModulated;
|
|
132
|
+
/** Warn only once when the rerank endpoint fails (graceful degradation). */
|
|
133
|
+
private rerankFailureWarned;
|
|
134
|
+
/**
|
|
135
|
+
* Last timestamp handed out by `store()`. Fast successive stores can land
|
|
136
|
+
* in the same millisecond, which would make createdAt ties ambiguous for
|
|
137
|
+
* temporal ordering, version timelines, and recency tie-breaks — so
|
|
138
|
+
* store timestamps are kept strictly monotonic per instance.
|
|
139
|
+
*/
|
|
140
|
+
private lastStoreTime;
|
|
141
|
+
/**
|
|
142
|
+
* Node ids written by `store()` whose embeddings have not been scanned
|
|
143
|
+
* for contradiction candidates yet. The write-time scan runs when the
|
|
144
|
+
* embedding is persisted (see `onEmbeddingPersisted`) — the gate keeps
|
|
145
|
+
* the scan off the startup backfill path and off re-embeddings from
|
|
146
|
+
* `update()`, so detection stays a bounded per-write cost.
|
|
147
|
+
*/
|
|
148
|
+
private contradictionScanPending;
|
|
149
|
+
/**
|
|
150
|
+
* Append one entry to the tamper-evident mutation log (see
|
|
151
|
+
* `src/tamper-log.ts`). Fail-open: logging never blocks the mutation
|
|
152
|
+
* — a logging failure is swallowed so the write path always wins.
|
|
153
|
+
*/
|
|
154
|
+
private logMutation;
|
|
155
|
+
/**
|
|
156
|
+
* `storage.updateNode` plus tamper-log bookkeeping. Use for every
|
|
157
|
+
* node mutation that goes through `updateNode` so the log stays
|
|
158
|
+
* complete — a mutation invisible to the log is indistinguishable
|
|
159
|
+
* from tampering at verify time.
|
|
160
|
+
*/
|
|
161
|
+
private updateNodeLogged;
|
|
162
|
+
/**
|
|
163
|
+
* Lifetime token-savings telemetry for context packs (in-process —
|
|
164
|
+
* resets when the MemOS instance is recreated). `packTokens` counts
|
|
165
|
+
* what was actually injected; `naiveBaselineTokens` counts what
|
|
166
|
+
* dumping the same candidates as raw JSON nodes would have cost.
|
|
167
|
+
*/
|
|
168
|
+
private usage;
|
|
169
|
+
/**
|
|
170
|
+
* Create a new MemOS instance.
|
|
171
|
+
*
|
|
172
|
+
* @param config — Configuration options. All fields are optional.
|
|
173
|
+
*/
|
|
174
|
+
constructor(config?: MemOSConfig);
|
|
175
|
+
/**
|
|
176
|
+
* Initialise the storage backend and hydrate the in-memory graph.
|
|
177
|
+
* Must be called before any other method.
|
|
178
|
+
*/
|
|
179
|
+
init(): Promise<void>;
|
|
180
|
+
/**
|
|
181
|
+
* Store a new memory.
|
|
182
|
+
*
|
|
183
|
+
* Automatically generates a summary (if not provided) and attempts
|
|
184
|
+
* to link the new node to existing nodes based on text similarity.
|
|
185
|
+
*
|
|
186
|
+
* @param content — Text content to remember.
|
|
187
|
+
* @param opts — Optional metadata, type, summary, importance, ttl, tags.
|
|
188
|
+
* @returns The created node and any auto-created edges.
|
|
189
|
+
*/
|
|
190
|
+
store(content: string, opts?: Omit<CreateMemoryInput, "content">): Promise<{
|
|
191
|
+
node: MemoryNode;
|
|
192
|
+
links: MemoryEdge[];
|
|
193
|
+
}>;
|
|
194
|
+
/**
|
|
195
|
+
* Import a record with its original identity (ID and timestamps).
|
|
196
|
+
*
|
|
197
|
+
* Used by encrypted sync restore (`src/sync.ts`). Unlike `store()`,
|
|
198
|
+
* this bypasses the write pipeline — no retain filter, no quarantine
|
|
199
|
+
* screen, no event-update resolution, no auto-linking — because the
|
|
200
|
+
* record already went through all of that on the exporting machine.
|
|
201
|
+
* The node is still queued for (re-)embedding under the local
|
|
202
|
+
* provider and registered for the contradiction scan.
|
|
203
|
+
*/
|
|
204
|
+
importRecord(record: {
|
|
205
|
+
id: string;
|
|
206
|
+
content: string;
|
|
207
|
+
summary?: string;
|
|
208
|
+
type: MemoryType;
|
|
209
|
+
tags?: string[];
|
|
210
|
+
importance?: number;
|
|
211
|
+
createdAt: number;
|
|
212
|
+
updatedAt: number;
|
|
213
|
+
namespace?: string;
|
|
214
|
+
metadata?: Record<string, unknown>;
|
|
215
|
+
source?: MemorySource;
|
|
216
|
+
provenance?: ProvenanceTier;
|
|
217
|
+
pool?: MemoryPool;
|
|
218
|
+
expiresAt?: number | null;
|
|
219
|
+
validFrom?: number | null;
|
|
220
|
+
validTo?: number | null;
|
|
221
|
+
harness?: string;
|
|
222
|
+
}): Promise<MemoryNode>;
|
|
223
|
+
/**
|
|
224
|
+
* Inner write path. `skipEventUpdate` is true only for the event-update
|
|
225
|
+
* machinery below (prevents the replacement write from re-triggering
|
|
226
|
+
* update detection on its own text — infinite recursion otherwise).
|
|
227
|
+
*/
|
|
228
|
+
private storeInner;
|
|
229
|
+
/**
|
|
230
|
+
* Resolve a natural-language event update/cancel against the store.
|
|
231
|
+
*
|
|
232
|
+
* Cross-harness rule: the target is resolved from the CURRENT rows in
|
|
233
|
+
* the shared DB file (same deterministic rules in every harness), so
|
|
234
|
+
* model B can update an event stored by model A with no shared
|
|
235
|
+
* conversation state.
|
|
236
|
+
*
|
|
237
|
+
* Deterministic tiebreaks:
|
|
238
|
+
* - kind named ("that meeting") → newest open event whose kind matches
|
|
239
|
+
* `metadata.event.kind`, or whose label contains the kind;
|
|
240
|
+
* createdAt desc, id asc.
|
|
241
|
+
* - kind unnamed ("it got moved") → the single open event if exactly
|
|
242
|
+
* one exists; zero or ambiguous → null (fail safe, never guess).
|
|
243
|
+
*
|
|
244
|
+
* @returns The resolved replacement write, or null when nothing
|
|
245
|
+
* resolves (the caller falls through to a normal write).
|
|
246
|
+
*/
|
|
247
|
+
private applyEventUpdate;
|
|
248
|
+
/**
|
|
249
|
+
* Find the currently-open scheduled event an update/cancel refers to.
|
|
250
|
+
* See `applyEventUpdate` for the deterministic tiebreak rules.
|
|
251
|
+
*/
|
|
252
|
+
private resolveOpenEventTarget;
|
|
253
|
+
/**
|
|
254
|
+
* Retrieve a single memory by ID.
|
|
255
|
+
*
|
|
256
|
+
* @param id — Memory node ID.
|
|
257
|
+
* @returns The node, or `null` if not found.
|
|
258
|
+
*/
|
|
259
|
+
retrieve(id: string): Promise<MemoryNode | null>;
|
|
260
|
+
/**
|
|
261
|
+
* Store an image as a durable memory.
|
|
262
|
+
*
|
|
263
|
+
* An image memory is an ORDINARY memory node plus two side artifacts:
|
|
264
|
+
* a caption stored as the node's `content` (so every existing text
|
|
265
|
+
* retrieval path finds it), and the image bytes in a content-addressed
|
|
266
|
+
* blob store next to the database. The node shape does not change and
|
|
267
|
+
* no new `MemoryType` member is introduced — `metadata.image` is the
|
|
268
|
+
* discriminator, exactly like `metadata.context`.
|
|
269
|
+
*
|
|
270
|
+
* Because it routes through `storeInner`, the write goes through the
|
|
271
|
+
* same pipeline as every text memory: retain triage, quarantine
|
|
272
|
+
* screening, provenance resolution, auto-linking, contradiction scan,
|
|
273
|
+
* tamper log. That is the difference between ~250 lines and ~800.
|
|
274
|
+
*
|
|
275
|
+
* Two embedding tracks, independent of each other:
|
|
276
|
+
* - **Track A (always on):** the caption is embedded by the normal
|
|
277
|
+
* TEXT provider, so the image is found by keyword and text-semantic
|
|
278
|
+
* search on every install. Zero extra model downloads.
|
|
279
|
+
* - **Track B (opt-in via `vision.clip.enabled`):** the image itself
|
|
280
|
+
* is encoded by CLIP into a separate vector space, so a query can
|
|
281
|
+
* match the PIXELS when its wording differs from the caption's.
|
|
282
|
+
* Degrades to Track A when the transformers package is missing —
|
|
283
|
+
* it never throws and never substitutes a text vector.
|
|
284
|
+
*
|
|
285
|
+
* @param input — A filesystem path, raw bytes, `{ data, mime }`
|
|
286
|
+
* (base64), `{ url }`, or a `data:` URL.
|
|
287
|
+
* @param opts — Caption, kind, tags, and the usual store options.
|
|
288
|
+
* @returns The created node, its image attachment, and the CLIP status.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```ts
|
|
292
|
+
* const { node, image } = await memos.addImageMemory("./diagram.png", {
|
|
293
|
+
* caption: "gateway → auth → orders → postgres, retry loop on orders",
|
|
294
|
+
* kind: "diagram",
|
|
295
|
+
* tags: ["arch"],
|
|
296
|
+
* });
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
addImageMemory(input: ImageInput, opts?: AddImageMemoryOptions): Promise<AddImageMemoryResult>;
|
|
300
|
+
/**
|
|
301
|
+
* Resolve an image reference (or node id) to its bytes.
|
|
302
|
+
*
|
|
303
|
+
* Takes the REF, not the node id, so a host model that only saw
|
|
304
|
+
* `[img:…]` in a context pack can resolve it without any other
|
|
305
|
+
* context. Also accepts a node id for convenience.
|
|
306
|
+
*
|
|
307
|
+
* @returns The blob bytes and MIME type, or null when missing.
|
|
308
|
+
*/
|
|
309
|
+
imageMemory(refOrId: string): Promise<{
|
|
310
|
+
buffer: Buffer;
|
|
311
|
+
mime: string;
|
|
312
|
+
ref: string;
|
|
313
|
+
} | null>;
|
|
314
|
+
/**
|
|
315
|
+
* Search image memories by text query.
|
|
316
|
+
*
|
|
317
|
+
* Runs the caption leg (keyword + text-semantic — the same legs every
|
|
318
|
+
* other memory uses) and, when Track B is enabled, the CLIP leg, then
|
|
319
|
+
* fuses them. The CLIP leg is what makes a query match the PIXELS
|
|
320
|
+
* when its wording shares nothing with the caption.
|
|
321
|
+
*
|
|
322
|
+
* Only nodes carrying `metadata.image` are returned.
|
|
323
|
+
*/
|
|
324
|
+
searchImages(query: string, opts?: SearchImagesOptions): Promise<ImageSearchResult[]>;
|
|
325
|
+
/**
|
|
326
|
+
* All image memories in a namespace, newest first.
|
|
327
|
+
*
|
|
328
|
+
* Requires vision to be enabled, so an operator who has not turned
|
|
329
|
+
* the feature on gets told how rather than an empty list that looks
|
|
330
|
+
* like "no images stored".
|
|
331
|
+
*/
|
|
332
|
+
listImages(opts?: ListImagesOptions): Promise<ImageSearchResult[]>;
|
|
333
|
+
/**
|
|
334
|
+
* Delete an image memory: the node, its blob, and its CLIP vector.
|
|
335
|
+
* The embedding row cascades with the node (ON DELETE CASCADE).
|
|
336
|
+
*/
|
|
337
|
+
deleteImageMemory(nodeId: string): Promise<boolean>;
|
|
338
|
+
/**
|
|
339
|
+
* Delete blobs no live node references any more.
|
|
340
|
+
*
|
|
341
|
+
* Explicit rather than scheduled: eviction paths (`forgetByDecay`,
|
|
342
|
+
* `archive`) delete nodes, so their blobs become unreachable garbage
|
|
343
|
+
* that only an explicit sweep removes.
|
|
344
|
+
*/
|
|
345
|
+
purgeOrphanImages(): Promise<number>;
|
|
346
|
+
/**
|
|
347
|
+
* The CLIP retrieval leg for a hybrid search, or [] when it cannot
|
|
348
|
+
* contribute.
|
|
349
|
+
*
|
|
350
|
+
* Returns an empty list — with zero storage reads — whenever any of
|
|
351
|
+
* these holds:
|
|
352
|
+
* - the query is empty (a structured-only filter search),
|
|
353
|
+
* - `vision.clip.enabled` is false (the default),
|
|
354
|
+
* - the provider cannot encode text (`embedImageText` missing), or
|
|
355
|
+
* - the storage adapter has no `querySimilarImages`.
|
|
356
|
+
*
|
|
357
|
+
* That is what makes the leg free for a text-only install: not one
|
|
358
|
+
* extra query, not one changed byte. When it IS active, the query is
|
|
359
|
+
* encoded through the dedicated CLIP LRU (never `embedQueryCached`,
|
|
360
|
+
* whose keys belong to the text provider) and scanned against
|
|
361
|
+
* `image_embeddings` with the caller's own filter mirrored — so an
|
|
362
|
+
* image in another namespace can never leak into this scope.
|
|
363
|
+
*
|
|
364
|
+
* A CLIP failure degrades to [] rather than propagating: Track B is a
|
|
365
|
+
* recall upgrade, and losing it must never break a text search.
|
|
366
|
+
*/
|
|
367
|
+
private fetchImageLeg;
|
|
368
|
+
/** Resolve (and memoize) the blob-store root for this instance. */
|
|
369
|
+
private resolveImageBlobRoot;
|
|
370
|
+
/**
|
|
371
|
+
* Resolve the Track B image encoder.
|
|
372
|
+
*
|
|
373
|
+
* Order: an explicitly injected provider, then the lazily-constructed
|
|
374
|
+
* default. Null whenever Track B is off — which is the common case, so
|
|
375
|
+
* the default `ClipEmbeddingProvider` is never even allocated.
|
|
376
|
+
*/
|
|
377
|
+
private resolveClipProvider;
|
|
378
|
+
private resolveClipQueryCache;
|
|
379
|
+
/**
|
|
380
|
+
* The image payload carried by a node, or null when it is not an
|
|
381
|
+
* image memory. `metadata.image` — not `type`, not a new MemoryType
|
|
382
|
+
* member — is the discriminator, so MemoryType exhaustiveness stays
|
|
383
|
+
* intact everywhere (sync allowlist, fidelity labels, adapters, MCP
|
|
384
|
+
* schema).
|
|
385
|
+
*/
|
|
386
|
+
private imageAttachmentOf;
|
|
387
|
+
/** The CLIP bookkeeping recorded in `metadata.clip`. */
|
|
388
|
+
private clipMetaOf;
|
|
389
|
+
private clipStatusOf;
|
|
390
|
+
/**
|
|
391
|
+
* Schedule the CLIP embed for a freshly written image node.
|
|
392
|
+
*
|
|
393
|
+
* Deliberately NOT routed through `EmbeddingQueue`: that queue's
|
|
394
|
+
* batch-and-persist contract writes to the TEXT `embeddings` table,
|
|
395
|
+
* and CLIP vectors belong in `image_embeddings`. This is a small
|
|
396
|
+
* in-flight set drained by `flushEmbeddings`, with retry-free
|
|
397
|
+
* fail-soft semantics — a CLIP failure records
|
|
398
|
+
* `metadata.clip.status = "failed"` and leaves Track A intact.
|
|
399
|
+
*/
|
|
400
|
+
private scheduleImageEmbedding;
|
|
401
|
+
/** Persist `metadata.clip` on the node. */
|
|
402
|
+
private recordClipStatus;
|
|
403
|
+
/** Find an image node with the same content digest in one namespace. */
|
|
404
|
+
private findImageNodeByDigest;
|
|
405
|
+
/** Find an image node by its blob ref. */
|
|
406
|
+
private findImageNodeByRef;
|
|
407
|
+
/** Count image nodes sharing one digest (blob refcount). */
|
|
408
|
+
private countImageNodesByDigest;
|
|
409
|
+
/** Every ref referenced by a live image node. */
|
|
410
|
+
private collectLiveImageRefs;
|
|
411
|
+
/**
|
|
412
|
+
* Fuse the caption leg and the CLIP leg by reciprocal rank.
|
|
413
|
+
*
|
|
414
|
+
* RRF rather than score blending: the two legs live in different
|
|
415
|
+
* vector spaces, so their raw scores are not comparable — only their
|
|
416
|
+
* RANKS are. An image found by both legs outranks one found by
|
|
417
|
+
* either alone, which is exactly the intended behaviour.
|
|
418
|
+
*/
|
|
419
|
+
private fuseImageLegs;
|
|
420
|
+
/**
|
|
421
|
+
* Search memories by text query and/or structured filters.
|
|
422
|
+
*
|
|
423
|
+
* @param queryOrFilter — A plain text query string, or a full SearchFilter object.
|
|
424
|
+
* @returns Array of scored memories, ordered by relevance.
|
|
425
|
+
*/
|
|
426
|
+
search(queryOrFilter: string | SearchFilter): Promise<ScoredMemory[]>;
|
|
427
|
+
/**
|
|
428
|
+
* Whether a text query should take the hybrid (multi-leg) path.
|
|
429
|
+
*
|
|
430
|
+
* Historically this was just "is a text embedding provider
|
|
431
|
+
* configured". The CLIP image leg is a second, INDEPENDENT reason to
|
|
432
|
+
* fuse: an install with `embeddings.enabled: false` but
|
|
433
|
+
* `vision.clip.enabled: true` still has a vector leg to run, and
|
|
434
|
+
* gating on the text provider alone would leave Track B silently
|
|
435
|
+
* dead on exactly the installs that opted into it.
|
|
436
|
+
*
|
|
437
|
+
* Cheap: the check is a boolean on resolved config, not a probe.
|
|
438
|
+
*/
|
|
439
|
+
private canRunHybrid;
|
|
440
|
+
/**
|
|
441
|
+
* Fidelity-aware recall: retrieve memories at the CHEAPEST fidelity
|
|
442
|
+
* level that satisfies the query, escalating L0→L1→L2→L3 within the
|
|
443
|
+
* same call when the result set looks insufficient.
|
|
444
|
+
*
|
|
445
|
+
* This is an ADDITIVE API — `search()` / `semanticSearch()` are
|
|
446
|
+
* untouched. Scoring is a local IDF-weighted term-coverage pass over
|
|
447
|
+
* the level corpus (zero LLM, zero embeddings); each result carries
|
|
448
|
+
* the full node plus the level it was served at.
|
|
449
|
+
*
|
|
450
|
+
* Default behavior is L3-equivalent (verbatim text, no routing, no
|
|
451
|
+
* escalation): existing consumers see the same output shape as a
|
|
452
|
+
* plain search. Pass `fidelity: "adaptive"` (or a fixed lower level)
|
|
453
|
+
* to opt into token savings.
|
|
454
|
+
*
|
|
455
|
+
* Two guards keep an adaptive call answerable:
|
|
456
|
+
* - the escalation FLOOR (default L1) — an L0 tag/entity listing
|
|
457
|
+
* is a retrieval affordance, not an answer, so it is never the
|
|
458
|
+
* terminal level unless the caller explicitly asked for L0;
|
|
459
|
+
* - the DECISIVE-TOKEN check — when the query carries a number,
|
|
460
|
+
* unit or negation that the served text lacks, escalation
|
|
461
|
+
* continues regardless of the IDF coverage score.
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```ts
|
|
465
|
+
* // Adaptive never serves tag soup: a factoid starts at L1 and
|
|
466
|
+
* // escalates to L3 when the decisive token is still missing.
|
|
467
|
+
* const hits = await memos.recall("postgres pool size", {
|
|
468
|
+
* fidelity: "adaptive",
|
|
469
|
+
* maxFidelity: "L2",
|
|
470
|
+
* });
|
|
471
|
+
* for (const h of hits) console.log(h.level, h.text);
|
|
472
|
+
* ```
|
|
473
|
+
*/
|
|
474
|
+
recall(query: string, opts?: FidelityRecallOptions): Promise<FidelityRecallResult[]>;
|
|
475
|
+
/**
|
|
476
|
+
* Scope the recall candidate set. Mirrors the `SearchFilter` fields
|
|
477
|
+
* that make sense for an in-memory scan (namespace / type / tags /
|
|
478
|
+
* pool); full-text and vector legs live in `search()`. The harness
|
|
479
|
+
* scope comes from the explicit argument first, then
|
|
480
|
+
* `filter.harness` — `"all"` (or unset) keeps every harness.
|
|
481
|
+
*/
|
|
482
|
+
private applyRecallFilter;
|
|
483
|
+
/**
|
|
484
|
+
* Eager fidelity backfill: generate missing L1/L2 levels for stored
|
|
485
|
+
* memories and persist them into the reserved `metadata.fidelity`
|
|
486
|
+
* slot. Idempotent — memories that already carry cached levels are
|
|
487
|
+
* skipped. Reads (`recall`, `contextPack`) also generate lazily, so
|
|
488
|
+
* this command is an optimization, not a requirement.
|
|
489
|
+
*
|
|
490
|
+
* `memos compact --stats` reports per-level token averages without
|
|
491
|
+
* writing anything.
|
|
492
|
+
*/
|
|
493
|
+
compact(opts?: CompactOptions): Promise<CompactResult>;
|
|
494
|
+
/**
|
|
495
|
+
* Search and return results in TOON (Token-Optimized Object Notation)
|
|
496
|
+
* format — a compact pipe-delimited string that cuts token count.
|
|
497
|
+
*
|
|
498
|
+
* Format:
|
|
499
|
+
* # memos.search.v1
|
|
500
|
+
* # toon:pipe-delimited
|
|
501
|
+
* # fields: id|score|trust|source|updatedAt|tags|content
|
|
502
|
+
* mem_abc|0.950|local|user_input|2026-06-18T12:00:00.000Z|preference;ui|User likes dark mode
|
|
503
|
+
*
|
|
504
|
+
* @param opts — If a string, searches with that query. If an object,
|
|
505
|
+
* accepts `{ query, format: "toon" | "toon-compact", ...searchOptions }`.
|
|
506
|
+
* Default format is "toon-compact" for maximum token savings.
|
|
507
|
+
* @returns A TOON-formatted string.
|
|
508
|
+
*/
|
|
509
|
+
searchToon(opts: string | (SearchFilter & {
|
|
510
|
+
format?: "toon" | "toon-compact";
|
|
511
|
+
})): Promise<string>;
|
|
512
|
+
/**
|
|
513
|
+
* Compose a scope filter into storage-facing namespace constraints.
|
|
514
|
+
* Explicit `namespace` always wins over `scope`; scope matches
|
|
515
|
+
* hierarchically (prefix) unless `scopeMatch: "exact"`.
|
|
516
|
+
*/
|
|
517
|
+
private resolveScopeFilter;
|
|
518
|
+
/**
|
|
519
|
+
* Apply post-query sorting that the storage layer can't do natively
|
|
520
|
+
* (e.g. trustScore when the query went through FTS which always
|
|
521
|
+
* sorts by rank).
|
|
522
|
+
*
|
|
523
|
+
* The ranking-modulation chain (triple boost, effective importance,
|
|
524
|
+
* Ebbinghaus reinforcement) is owned by `hybridSearch` these days —
|
|
525
|
+
* see {@link applyRankingModulators} — so this method only runs it for
|
|
526
|
+
* the keyword-only path, where `hybridSearch` is never reached. On the
|
|
527
|
+
* hybrid path the incoming array is already modulated and is passed
|
|
528
|
+
* through untouched (the `rankingModulated` WeakSet tells the two
|
|
529
|
+
* apart).
|
|
530
|
+
*/
|
|
531
|
+
private postSortResults;
|
|
532
|
+
/**
|
|
533
|
+
* The shared ranking-modulation chain: everything that re-ranks a
|
|
534
|
+
* fused result set AFTER relevance. Runs inside `hybridSearch`'s
|
|
535
|
+
* post-fusion stages so every caller of the hybrid pipeline —
|
|
536
|
+
* `search()`, `contextPack()`, `multiStreamSearch()`, the store-time
|
|
537
|
+
* evidence pass — ranks identically instead of `search()` alone.
|
|
538
|
+
*
|
|
539
|
+
* Three independent, individually-gated stages:
|
|
540
|
+
*
|
|
541
|
+
* 1. TRIPLE BOOST (`experimental.tripleExtraction`) — ×1.15 when a
|
|
542
|
+
* memory's stored triples match the query's triples.
|
|
543
|
+
* 2. EFFECTIVE IMPORTANCE (`config.importance`, opt-in) — a bounded
|
|
544
|
+
* multiplicative factor from `computeEffectiveImportance()`, so
|
|
545
|
+
* recency decay and access reinforcement modulate ranking the same
|
|
546
|
+
* way they already modulate eviction and archival.
|
|
547
|
+
* 3. EBBINGHAUS REINFORCEMENT (`experimental.ebbinghaus`) — a small
|
|
548
|
+
* additive forgetting-curve term, plus the access-counter bump.
|
|
549
|
+
*
|
|
550
|
+
* Every stage is off unless its own config says otherwise, and stage 2
|
|
551
|
+
* additionally requires the `importance` block to be non-empty — so an
|
|
552
|
+
* unconfigured instance passes its exact input array through.
|
|
553
|
+
*/
|
|
554
|
+
private applyRankingModulators;
|
|
555
|
+
/**
|
|
556
|
+
* Resolve the effective-importance config for ranking / eviction /
|
|
557
|
+
* archival, or `null` when the user left it unconfigured.
|
|
558
|
+
*
|
|
559
|
+
* The constructor normalises `config.importance` to `{}`, so "unset"
|
|
560
|
+
* and "explicitly empty" are indistinguishable there — and BOTH must
|
|
561
|
+
* keep the historical behaviour (raw `node.importance`) exactly, since
|
|
562
|
+
* this is a published SDK. An object carrying at least one defined
|
|
563
|
+
* field is therefore the opt-in signal.
|
|
564
|
+
*
|
|
565
|
+
* @returns The configured tuning block, or `null` for "use raw importance".
|
|
566
|
+
*/
|
|
567
|
+
private resolveImportanceRanking;
|
|
568
|
+
/**
|
|
569
|
+
* Bump accessCount and lastAccessed for retrieved nodes (Ebbinghaus
|
|
570
|
+
* reinforcement). Fire-and-forget; failures are ignored.
|
|
571
|
+
*
|
|
572
|
+
* MUST go through the storage adapter's `recordAccess` — never
|
|
573
|
+
* `updateNode`. `updateNode` stamps `updatedAt = Date.now()` and
|
|
574
|
+
* ignores the `accessCount`/`lastAccessed` fields in its UPDATE
|
|
575
|
+
* statement, so routing read telemetry through it did both of these:
|
|
576
|
+
*
|
|
577
|
+
* 1. Every search rewrote `updated_at` on up to 10 nodes without a
|
|
578
|
+
* tamper-log entry, so `verifyTamperLog` reported the whole store
|
|
579
|
+
* as "edited without logging" (false tamper alarm on a plain read).
|
|
580
|
+
* It also made recalled memories look freshly written to recency
|
|
581
|
+
* ordering, sync last-write-wins, and the embedding-freshness
|
|
582
|
+
* check (`info.updatedAt >= node.updatedAt` → needless re-embed).
|
|
583
|
+
* 2. The `accessCount`/`lastAccessed` it passed were silently dropped —
|
|
584
|
+
* both fields are absent from `updateNode`'s UPDATE statement — so
|
|
585
|
+
* every search paid a full row rewrite (plus tag/entity index
|
|
586
|
+
* resync) to persist none of its own telemetry.
|
|
587
|
+
*
|
|
588
|
+
* Adapters without `recordAccess` skip reinforcement (fail-open).
|
|
589
|
+
*/
|
|
590
|
+
private bumpAccessCounters;
|
|
591
|
+
/**
|
|
592
|
+
* Boost results whose stored triples match the query's triples.
|
|
593
|
+
* Matching triples get a 15% score boost.
|
|
594
|
+
*/
|
|
595
|
+
private applyTripleBoost;
|
|
596
|
+
/**
|
|
597
|
+
* Permanently forget a memory and all its connected edges.
|
|
598
|
+
*
|
|
599
|
+
* @param id — Memory node ID to forget.
|
|
600
|
+
* @returns `true` if the memory existed and was deleted.
|
|
601
|
+
*/
|
|
602
|
+
forget(id: string): Promise<boolean>;
|
|
603
|
+
/**
|
|
604
|
+
* Generate a summary of all stored memories.
|
|
605
|
+
*
|
|
606
|
+
* Concatenates all node summaries and produces an extractive
|
|
607
|
+
* summary of the combined text.
|
|
608
|
+
*
|
|
609
|
+
* @returns A summary string.
|
|
610
|
+
*/
|
|
611
|
+
summarize(): Promise<string>;
|
|
612
|
+
/**
|
|
613
|
+
* Manually create a link (edge) between two memories.
|
|
614
|
+
*
|
|
615
|
+
* @param sourceId — Source node ID.
|
|
616
|
+
* @param targetId — Target node ID.
|
|
617
|
+
* @param relation — Semantic relation type.
|
|
618
|
+
* @param weight — Edge weight [0, 1].
|
|
619
|
+
* @returns The created edge.
|
|
620
|
+
*/
|
|
621
|
+
link(sourceId: string, targetId: string, relation?: MemoryEdge["relation"], weight?: number): Promise<MemoryEdge>;
|
|
622
|
+
/**
|
|
623
|
+
* Set a time-to-live on a memory node.
|
|
624
|
+
*
|
|
625
|
+
* @param id — Memory node ID.
|
|
626
|
+
* @param seconds — TTL in seconds from now.
|
|
627
|
+
*/
|
|
628
|
+
setTTL(id: string, seconds: number): Promise<void>;
|
|
629
|
+
/**
|
|
630
|
+
* Clear the TTL on a memory node (make it persist indefinitely).
|
|
631
|
+
*
|
|
632
|
+
* @param id — Memory node ID.
|
|
633
|
+
*/
|
|
634
|
+
clearTTL(id: string): Promise<void>;
|
|
635
|
+
/**
|
|
636
|
+
* Add tags to a memory node.
|
|
637
|
+
*
|
|
638
|
+
* @param id — Memory node ID.
|
|
639
|
+
* @param tags — Tags to add.
|
|
640
|
+
*/
|
|
641
|
+
tag(id: string, tags: string[]): Promise<void>;
|
|
642
|
+
/**
|
|
643
|
+
* Remove tags from a memory node.
|
|
644
|
+
*
|
|
645
|
+
* @param id — Memory node ID.
|
|
646
|
+
* @param tags — Tags to remove.
|
|
647
|
+
*/
|
|
648
|
+
untag(id: string, tags: string[]): Promise<void>;
|
|
649
|
+
/**
|
|
650
|
+
* List all memories with a specific tag.
|
|
651
|
+
*
|
|
652
|
+
* @param tag — Tag to filter by.
|
|
653
|
+
* @returns Array of memory nodes with the tag.
|
|
654
|
+
*/
|
|
655
|
+
listByTag(tag: string): Promise<MemoryNode[]>;
|
|
656
|
+
/**
|
|
657
|
+
* Export memories in the specified format.
|
|
658
|
+
*/
|
|
659
|
+
export(opts?: ExportOptions): Promise<ExportResult>;
|
|
660
|
+
/**
|
|
661
|
+
* Import memories from a JSON file or directory of Markdown/Obsidian files.
|
|
662
|
+
*
|
|
663
|
+
* @param opts — Import options (source path, format).
|
|
664
|
+
* @returns Import result with counts.
|
|
665
|
+
*/
|
|
666
|
+
/**
|
|
667
|
+
* Import memories from a third-party export: ChatGPT
|
|
668
|
+
* (`conversations.json`), Claude (export directory or file), or Slack
|
|
669
|
+
* (export directory). The parser sniffs each entry, maps messages to
|
|
670
|
+
* timestamped memories, dedupes by content hash, and every item is
|
|
671
|
+
* stored with `source: "external_data"` (lower trust by default) plus
|
|
672
|
+
* provenance tags (`imported`, `<source>`), so imported memories are
|
|
673
|
+
* rankable but never outrank first-party facts.
|
|
674
|
+
*
|
|
675
|
+
* With `synthesize: true`, a post-import pass extracts structured
|
|
676
|
+
* decisions / preferences / milestones from the imported text using
|
|
677
|
+
* rule-based heuristics (no LLM) and stores them as tagged memories.
|
|
678
|
+
*/
|
|
679
|
+
importExternal(opts: {
|
|
680
|
+
/** Path to the export JSON file. Mutually exclusive with `data`. */
|
|
681
|
+
file?: string;
|
|
682
|
+
/** Pre-loaded export payload (JSON string or decoded value). */
|
|
683
|
+
data?: unknown;
|
|
684
|
+
/**
|
|
685
|
+
* Path to an export directory. Required for `slack`; for
|
|
686
|
+
* `chatgpt`/`claude` scans every `*.json`/`*.jsonl` file in the
|
|
687
|
+
* directory. Mutually exclusive with `file`/`data`.
|
|
688
|
+
*/
|
|
689
|
+
dir?: string;
|
|
690
|
+
/** Parser hint. Default `"auto"` sniffs the shape. */
|
|
691
|
+
source?: ExternalImportSource;
|
|
692
|
+
namespace?: string;
|
|
693
|
+
dryRun?: boolean;
|
|
694
|
+
/** Safety cap on imported items. Default 500. */
|
|
695
|
+
maxItems?: number;
|
|
696
|
+
/** Extra tags applied to every imported memory. */
|
|
697
|
+
tags?: string[];
|
|
698
|
+
/**
|
|
699
|
+
* Post-import synthesis pass: rule-based extraction of decisions,
|
|
700
|
+
* preferences, and milestones into structured memories. Default
|
|
701
|
+
* false.
|
|
702
|
+
*/
|
|
703
|
+
synthesize?: boolean;
|
|
704
|
+
}): Promise<{
|
|
705
|
+
detected: DetectedExportSource;
|
|
706
|
+
total: number;
|
|
707
|
+
imported: number;
|
|
708
|
+
skipped: number;
|
|
709
|
+
dryRun: boolean;
|
|
710
|
+
durationMs: number;
|
|
711
|
+
sampleIds: string[];
|
|
712
|
+
synthesized: {
|
|
713
|
+
decisions: number;
|
|
714
|
+
preferences: number;
|
|
715
|
+
milestones: number;
|
|
716
|
+
};
|
|
717
|
+
}>;
|
|
718
|
+
private lessonStorage;
|
|
719
|
+
/**
|
|
720
|
+
* Capture a procedural lesson — behavioral guidance for future tasks,
|
|
721
|
+
* not a fact. Starts at the neutral prior score (0.5); outcome
|
|
722
|
+
* feedback via `recordLessonOutcome` moves it from there.
|
|
723
|
+
*/
|
|
724
|
+
memorizeProcedural(lesson: string, opts?: {
|
|
725
|
+
context?: string;
|
|
726
|
+
tags?: string[];
|
|
727
|
+
namespace?: string;
|
|
728
|
+
scope?: MemoryScope;
|
|
729
|
+
initialScore?: number;
|
|
730
|
+
}): Promise<ProceduralLesson>;
|
|
731
|
+
/**
|
|
732
|
+
* Record an outcome for a lesson. Successes reinforce
|
|
733
|
+
* (`score += (1 - score) * 0.2`), failures demote
|
|
734
|
+
* (`score -= score * 0.3`) — pure local math, fully transparent.
|
|
735
|
+
* Also bumps `useCount` and refreshes timestamps (which resets the
|
|
736
|
+
* read-time decay clock).
|
|
737
|
+
*/
|
|
738
|
+
recordLessonOutcome(id: string, outcome: LessonOutcome): Promise<ProceduralLesson>;
|
|
739
|
+
/**
|
|
740
|
+
* Retrieve the top-k procedural lessons for a query, ranked by a
|
|
741
|
+
* blend of decayed score (60%) and query-token relevance (40%).
|
|
742
|
+
* Lessons with no query overlap are skipped unless the query is
|
|
743
|
+
* empty (empty query = top lessons by score).
|
|
744
|
+
*/
|
|
745
|
+
recallProcedural(query: string, k?: number, opts?: {
|
|
746
|
+
namespace?: string;
|
|
747
|
+
scope?: MemoryScope;
|
|
748
|
+
}): Promise<ProceduralLesson[]>;
|
|
749
|
+
/** List procedural lessons, highest score first. */
|
|
750
|
+
listProceduralLessons(opts?: {
|
|
751
|
+
namespace?: string;
|
|
752
|
+
scope?: MemoryScope;
|
|
753
|
+
}): Promise<ProceduralLesson[]>;
|
|
754
|
+
/**
|
|
755
|
+
* Trace a citation token (e.g. `[mem:a3f9]`, `a3f9`, or a full id)
|
|
756
|
+
* back to its source memory. Returns the full memory on an exact
|
|
757
|
+
* prefix match, `not_found` when nothing matches, and `ambiguous`
|
|
758
|
+
* with the candidate list when the token matches several memories
|
|
759
|
+
* (use a longer token to disambiguate).
|
|
760
|
+
*/
|
|
761
|
+
resolveCitation(token: string): Promise<CitationResolution>;
|
|
762
|
+
/**
|
|
763
|
+
* Render a citation resolution exactly as `memos cite` prints it.
|
|
764
|
+
* Shared with the CLI so tests assert on the real output bytes.
|
|
765
|
+
*/
|
|
766
|
+
formatCitation(resolution: CitationResolution, asJson?: boolean): string;
|
|
767
|
+
/**
|
|
768
|
+
* Screen text with the write-gate classifier without storing
|
|
769
|
+
* anything. Useful for pre-flight checks and for testing the
|
|
770
|
+
* classifier's verdict on a given input. Tier 1 only (synchronous
|
|
771
|
+
* regex screen) — the async semantic tier needs an initialized
|
|
772
|
+
* instance and runs on the real write path.
|
|
773
|
+
*/
|
|
774
|
+
screenContent(content: string): QuarantineVerdict;
|
|
775
|
+
/**
|
|
776
|
+
* Lazily-constructed tier-2 semantic screen, or null when embeddings
|
|
777
|
+
* are disabled (no provider to embed with).
|
|
778
|
+
*/
|
|
779
|
+
private getSemanticScreen;
|
|
780
|
+
/**
|
|
781
|
+
* Tier-2 semantic screen for the provenance-trust write gate:
|
|
782
|
+
* intent-level detection via cosine similarity to canonical
|
|
783
|
+
* attack-shape anchors (fastembed, no LLM — see
|
|
784
|
+
* `src/semantic-screen.ts`).
|
|
785
|
+
*
|
|
786
|
+
* Runs only when tier 1 left the write in the gray zone (score in
|
|
787
|
+
* [1.0, 2.0)) or the write is low-trust tiered — ordinary writes
|
|
788
|
+
* never pay the embedding cost, and the zero-LLM cheap screen stays
|
|
789
|
+
* the first and only mandatory tier.
|
|
790
|
+
*
|
|
791
|
+
* Escalation rules (both quarantine, never hard-block — flagged
|
|
792
|
+
* content is still stored, just excluded from recall pending review):
|
|
793
|
+
* - gray-zone: tier-1 score + `semanticEscalationPoints(sim)` >= 2.0 —
|
|
794
|
+
* the semantic tier escalates partial regex evidence, it cannot
|
|
795
|
+
* quarantine a clean-looking write on its own;
|
|
796
|
+
* - low-trust tiers: sim >= SEMANTIC_HIGH_SIM_BAR quarantines on
|
|
797
|
+
* intent alone (tool output is data, never instructions).
|
|
798
|
+
*
|
|
799
|
+
* Returns null when the tier doesn't run (out of scope, embeddings
|
|
800
|
+
* off) or is unavailable (hash fallback, transient embed error) —
|
|
801
|
+
* callers keep the tier-1 verdict. Fail-open for writes: a semantic
|
|
802
|
+
* outage never blocks or silently quarantines a write.
|
|
803
|
+
*/
|
|
804
|
+
private maybeSemanticScreen;
|
|
805
|
+
/**
|
|
806
|
+
* Retrieval-time anomaly scoring (topic-conditioned): memories whose
|
|
807
|
+
* write-time attack-shape similarity (`metadata.semanticAttackSim`,
|
|
808
|
+
* stamped by {@link maybeSemanticScreen}) is at/above
|
|
809
|
+
* RETRIEVAL_ANOMALY_THRESHOLD are down-weighted — unless the query
|
|
810
|
+
* itself is attack-shaped (similarity at/above QUERY_ATTACK_SIM_CAP),
|
|
811
|
+
* in which case attack-shaped memories are expected (security
|
|
812
|
+
* discussion, red-team review) and the flag stays off.
|
|
813
|
+
*
|
|
814
|
+
* Cheap by construction: the query is embedded only when at least one
|
|
815
|
+
* stamped suspect is in the result set; stored memories reuse their
|
|
816
|
+
* write-time measurement.
|
|
817
|
+
*/
|
|
818
|
+
private applyRetrievalAnomalyScoring;
|
|
819
|
+
/**
|
|
820
|
+
* List quarantined memories — the review queue — most recently
|
|
821
|
+
* flagged first. Quarantined memories are excluded from recall by
|
|
822
|
+
* default; this is the explicit review path.
|
|
823
|
+
*/
|
|
824
|
+
listQuarantined(opts?: {
|
|
825
|
+
limit?: number;
|
|
826
|
+
namespace?: string;
|
|
827
|
+
}): Promise<MemoryNode[]>;
|
|
828
|
+
/**
|
|
829
|
+
* Release a memory from quarantine: it becomes recallable again, but
|
|
830
|
+
* stays flagged as low-trust for agent consumption — the
|
|
831
|
+
* `releasedFromQuarantine` metadata marker keeps
|
|
832
|
+
* `untrusted_source: true` on in MCP responses so a host agent
|
|
833
|
+
* confirms it instead of silently injecting it as context.
|
|
834
|
+
* Idempotent: releasing a non-quarantined memory is a no-op.
|
|
835
|
+
* Add-only: `quarantinedAt`/`quarantineReason` are preserved as the
|
|
836
|
+
* audit trail of the original flagging.
|
|
837
|
+
*/
|
|
838
|
+
releaseFromQuarantine(id: string): Promise<MemoryNode>;
|
|
839
|
+
/**
|
|
840
|
+
* Set a memory's provenance tier. This is the only path to the
|
|
841
|
+
* `user-verified` tier — explicit user confirmation, never assigned
|
|
842
|
+
* automatically at write time.
|
|
843
|
+
*/
|
|
844
|
+
setProvenance(id: string, tier: ProvenanceTier): Promise<MemoryNode>;
|
|
845
|
+
/**
|
|
846
|
+
* Per-harness memory counts — "which harnesses wrote what lives in
|
|
847
|
+
* this database". Powers `memos harness list`. Memories written
|
|
848
|
+
* before harness attribution existed (or by clients that never set
|
|
849
|
+
* the tag) read as `"unknown"`.
|
|
850
|
+
*/
|
|
851
|
+
getHarnessCounts(): Promise<HarnessCount[]>;
|
|
852
|
+
/**
|
|
853
|
+
* Merge another harness's database file into this one — "one memory,
|
|
854
|
+
* every harness."
|
|
855
|
+
*
|
|
856
|
+
* The merge is a faithful row-level import, not a re-write: every
|
|
857
|
+
* source node keeps its id (remapped only on collision), timestamps,
|
|
858
|
+
* bitemporal validity interval (`validFrom`/`validTo`), provenance
|
|
859
|
+
* tier, trust score, tags, quarantine state, and harness tag. Edges
|
|
860
|
+
* follow their endpoints through the id remap.
|
|
861
|
+
*
|
|
862
|
+
* Cross-harness duplicates and contradictions are NOT resolved here:
|
|
863
|
+
* imported nodes go through the exact same post-write path as
|
|
864
|
+
* `store()` — re-embedded by the local provider and registered for
|
|
865
|
+
* the existing write-time contradiction scan — so the established
|
|
866
|
+
* contradiction detection + read-time resolution machinery converges
|
|
867
|
+
* them exactly as if they had been written locally. No second
|
|
868
|
+
* resolution system exists, by design.
|
|
869
|
+
*
|
|
870
|
+
* Deterministic: nodes import in (createdAt, id) order; collisions
|
|
871
|
+
* get fresh UUIDs recorded in the result's id map.
|
|
872
|
+
*
|
|
873
|
+
* @param fromPath — Path to the source `.db` file.
|
|
874
|
+
* @param opts — `{ dryRun }` reports the plan without writing.
|
|
875
|
+
*/
|
|
876
|
+
mergeHarnessDb(fromPath: string, opts?: HarnessMergeOptions): Promise<HarnessMergeResult>;
|
|
877
|
+
importMemories(opts: ImportOptions): Promise<ImportResult>;
|
|
878
|
+
private importJson;
|
|
879
|
+
private parseMarkdownFile;
|
|
880
|
+
/**
|
|
881
|
+
* Semantic-only retrieval. Uses persisted embedding vectors when configured,
|
|
882
|
+
* with the older graph text-similarity path kept as a no-provider fallback.
|
|
883
|
+
*
|
|
884
|
+
* Two call styles (both supported):
|
|
885
|
+
* semanticSearch(query, 10, 0.2, { namespace: "demo" }) // positional
|
|
886
|
+
* semanticSearch(query, { limit: 10, threshold: 0.2, namespace: "demo" })
|
|
887
|
+
*
|
|
888
|
+
* @param query — Text query to search for.
|
|
889
|
+
* @param limitOrOpts — Result limit, or an options object with `limit`,
|
|
890
|
+
* `threshold`, and any `SearchFilter` field.
|
|
891
|
+
* @param threshold — Minimum similarity score in [0, 1] (positional style).
|
|
892
|
+
* @param filter — Extra search filters (positional style).
|
|
893
|
+
* @param internal — Internal plumbing (not part of the public contract):
|
|
894
|
+
* `queryVector` skips the query embedding when the caller already
|
|
895
|
+
* computed it (see `multiStreamSearch` embed-once threading).
|
|
896
|
+
*/
|
|
897
|
+
semanticSearch(query: string, limitOrOpts?: number | SemanticSearchOptions, threshold?: number, filter?: SearchFilter, internal?: {
|
|
898
|
+
queryVector?: number[];
|
|
899
|
+
}): Promise<ScoredMemory[]>;
|
|
900
|
+
/**
|
|
901
|
+
* Generate a DOT-format graph visualization string.
|
|
902
|
+
*/
|
|
903
|
+
graphViz(): Promise<string>;
|
|
904
|
+
/**
|
|
905
|
+
* List all namespaces.
|
|
906
|
+
*/
|
|
907
|
+
listNamespaces(): Promise<string[]>;
|
|
908
|
+
/**
|
|
909
|
+
* Get the count of memories in a namespace.
|
|
910
|
+
*/
|
|
911
|
+
namespaceCount(ns: string): Promise<number>;
|
|
912
|
+
/**
|
|
913
|
+
* Scoped-space inventory: every namespace with its live memory count,
|
|
914
|
+
* ordered by count descending. Free-form scopes (convention:
|
|
915
|
+
* `project:<name>`, `harness:<name>`) appear here alongside typed
|
|
916
|
+
* `user:/agent:/run:` scopes and the shared `default` namespace.
|
|
917
|
+
* Powers `memos scope list`.
|
|
918
|
+
*/
|
|
919
|
+
listNamespaceCounts(): Promise<Array<{
|
|
920
|
+
namespace: string;
|
|
921
|
+
count: number;
|
|
922
|
+
}>>;
|
|
923
|
+
/**
|
|
924
|
+
* Get context for a node by walking the graph to a given depth.
|
|
925
|
+
* Returns the node's content plus contents of neighbours up to `depth` hops.
|
|
926
|
+
*/
|
|
927
|
+
injectContext(id: string, depth?: number, maxChars?: number): Promise<string>;
|
|
928
|
+
/**
|
|
929
|
+
* Update an existing memory node.
|
|
930
|
+
*/
|
|
931
|
+
update(id: string, input: UpdateMemoryInput): Promise<MemoryNode | null>;
|
|
932
|
+
/**
|
|
933
|
+
* Get the full graph snapshot (nodes + edges).
|
|
934
|
+
*/
|
|
935
|
+
getGraph(): Promise<GraphSnapshot>;
|
|
936
|
+
/**
|
|
937
|
+
* Get the graph as of a bitemporal timestamp (unix ms) — time-travel
|
|
938
|
+
* over add-only history. Backs the MCP Apps explorer's as-of scrubber.
|
|
939
|
+
* Reads from storage (the in-memory graph only reflects live state);
|
|
940
|
+
* adapters without `getGraphAtTime` fall back to filtering the live
|
|
941
|
+
* snapshot with the same as-of predicates.
|
|
942
|
+
*/
|
|
943
|
+
getGraphAtTime(atTime: number): Promise<GraphSnapshot>;
|
|
944
|
+
/**
|
|
945
|
+
* Get direct neighbours of a memory node.
|
|
946
|
+
*/
|
|
947
|
+
getNeighbours(nodeId: string): Promise<MemoryNode[]>;
|
|
948
|
+
/**
|
|
949
|
+
* Get all edges connected to a memory node.
|
|
950
|
+
*/
|
|
951
|
+
getEdges(nodeId: string): Promise<MemoryEdge[]>;
|
|
952
|
+
/**
|
|
953
|
+
* Find clusters of related memories.
|
|
954
|
+
*/
|
|
955
|
+
clusters(minSize?: number): Promise<string[][]>;
|
|
956
|
+
/**
|
|
957
|
+
* Return the total number of stored memories.
|
|
958
|
+
*/
|
|
959
|
+
get count(): number;
|
|
960
|
+
/**
|
|
961
|
+
* Remove all memories and edges.
|
|
962
|
+
*/
|
|
963
|
+
clear(): Promise<void>;
|
|
964
|
+
/**
|
|
965
|
+
* Shut down MemOS and release resources.
|
|
966
|
+
*/
|
|
967
|
+
close(): Promise<void>;
|
|
968
|
+
/**
|
|
969
|
+
* Build an AI Trio v1 context pack for a query.
|
|
970
|
+
*
|
|
971
|
+
* This is the canonical read-only envelope consumed by LLM Guardian
|
|
972
|
+
* and any other AI Trio member. Items are sorted by descending
|
|
973
|
+
* relevance and trimmed to fit `tokenBudget`. The score is
|
|
974
|
+
* reproducible for the same query, provider, model, and database.
|
|
975
|
+
*
|
|
976
|
+
* @example
|
|
977
|
+
* ```ts
|
|
978
|
+
* const pack = await memos.contextPack({
|
|
979
|
+
* query: "release blockers",
|
|
980
|
+
* namespace: "default",
|
|
981
|
+
* tokenBudget: 1200,
|
|
982
|
+
* });
|
|
983
|
+
* ```
|
|
984
|
+
*/
|
|
985
|
+
contextPack(opts: {
|
|
986
|
+
query: string;
|
|
987
|
+
namespace?: string;
|
|
988
|
+
/** Typed multi-scope filter (hierarchical by default). */
|
|
989
|
+
scope?: MemoryScope;
|
|
990
|
+
/** How `scope` matches stored namespaces. Default `"hierarchical"`. */
|
|
991
|
+
scopeMatch?: "exact" | "hierarchical";
|
|
992
|
+
tokenBudget: number;
|
|
993
|
+
limit?: number;
|
|
994
|
+
trust?: string;
|
|
995
|
+
source?: string;
|
|
996
|
+
includeSummary?: boolean;
|
|
997
|
+
/**
|
|
998
|
+
* Fidelity level for pack item contents: a fixed level or
|
|
999
|
+
* `"adaptive"` (the query-adaptive router picks the starting level
|
|
1000
|
+
* per query). Default `undefined` = L3 verbatim — current behavior
|
|
1001
|
+
* preserved exactly. Lower levels cut tokens per item; the chosen
|
|
1002
|
+
* level is recorded per item (`item.fidelity`) and in the pack
|
|
1003
|
+
* metadata (`pack.fidelity`).
|
|
1004
|
+
*/
|
|
1005
|
+
fidelity?: FidelityLevel | "adaptive";
|
|
1006
|
+
/** Output format: "json" (default), "toon", or "toon-compact" */
|
|
1007
|
+
format?: "json" | "toon" | "toon-compact";
|
|
1008
|
+
/**
|
|
1009
|
+
* Opt-in semantic dedup: drop pack items whose stored embedding is a
|
|
1010
|
+
* near-duplicate (cosine >= 0.90) of an already-selected item's.
|
|
1011
|
+
* Catches paraphrased memories that lexical dedup misses. Costs one
|
|
1012
|
+
* pass over stored embedding rows (filtered to the candidate set);
|
|
1013
|
+
* off by default.
|
|
1014
|
+
*/
|
|
1015
|
+
semanticDedup?: boolean;
|
|
1016
|
+
/**
|
|
1017
|
+
* Multi-stream retrieval (LongMemEval-V2 design lesson): run the query
|
|
1018
|
+
* separately against each granularity pool (`event`, `note`,
|
|
1019
|
+
* `procedure`) and fuse the ranked lists. Beats a single fused query
|
|
1020
|
+
* once distilled notes or procedures exist, and degrades to the
|
|
1021
|
+
* plain single-stream path when only `event` content is present.
|
|
1022
|
+
* Default true.
|
|
1023
|
+
*/
|
|
1024
|
+
multiStream?: boolean;
|
|
1025
|
+
/**
|
|
1026
|
+
* Bounded graph expansion for this pack: 1-hop neighbours of the top
|
|
1027
|
+
* seeds join the candidate set (via `derived_from` / relation edges),
|
|
1028
|
+
* so consolidated summaries carry their sources. Default true;
|
|
1029
|
+
* `experimental.graphExpansion` settings take precedence when set.
|
|
1030
|
+
*/
|
|
1031
|
+
graphExpansion?: boolean;
|
|
1032
|
+
/**
|
|
1033
|
+
* Memory-grounded citations (opt-in, default off): every pack item
|
|
1034
|
+
* carries a `[mem:xxxx]` token (unique within the pack) rendered
|
|
1035
|
+
* ahead of its content in TOON output, resolvable via
|
|
1036
|
+
* `resolveCitation` / `memos cite`.
|
|
1037
|
+
*/
|
|
1038
|
+
citations?: boolean;
|
|
1039
|
+
/**
|
|
1040
|
+
* Inject top procedural lessons as an "operating instructions"
|
|
1041
|
+
* section (additive; default off). `true` injects the top 3 lessons
|
|
1042
|
+
* for the query; a number sets k. Uses the pack's namespace.
|
|
1043
|
+
*/
|
|
1044
|
+
lessons?: boolean | number;
|
|
1045
|
+
/**
|
|
1046
|
+
* Wire format the pack will be serialized to. When set, the token
|
|
1047
|
+
* budget is enforced against what each item actually costs on the
|
|
1048
|
+
* wire for that format — TOON row scaffolding (`id|score|trust|src|
|
|
1049
|
+
* epochDelta|tags|content`, base64url ids, citations) or the JSON
|
|
1050
|
+
* serializer's field names and quotes — instead of a flat
|
|
1051
|
+
* `content + summary + 4` estimate. Without it the item selection is
|
|
1052
|
+
* exactly what it has always been.
|
|
1053
|
+
*/
|
|
1054
|
+
wireFormat?: ContextPackWireFormat;
|
|
1055
|
+
/**
|
|
1056
|
+
* Hard ceiling on the token count of the SERIALIZED output. When the
|
|
1057
|
+
* rendered string exceeds it, the lowest-ranked rows are dropped
|
|
1058
|
+
* until it fits. Only meaningful together with a TOON `format`;
|
|
1059
|
+
* ignored for "json" (an object has no length to trim). Omitted by
|
|
1060
|
+
* default, which leaves the rendered bytes untouched.
|
|
1061
|
+
*/
|
|
1062
|
+
maxWireTokens?: number;
|
|
1063
|
+
/**
|
|
1064
|
+
* Compression for items that don't fit the budget: an oversized item
|
|
1065
|
+
* is re-rendered through `compressText` and admitted if the
|
|
1066
|
+
* compressed form fits. Defaults to
|
|
1067
|
+
* `experimental.packCompression`; off unless that config enables it,
|
|
1068
|
+
* so default pack contents stay byte-identical.
|
|
1069
|
+
*/
|
|
1070
|
+
compression?: ContextPackCompressionOptions;
|
|
1071
|
+
/**
|
|
1072
|
+
* Attach image references to pack items that are image memories.
|
|
1073
|
+
* Default `true` when any candidate item is an image memory (the
|
|
1074
|
+
* attachment is a reference, never bytes, so there is no token cost
|
|
1075
|
+
* to justify an off-by-default); pass `false` to omit them. Bytes
|
|
1076
|
+
* are resolved separately via `memos.imageMemory(ref)`.
|
|
1077
|
+
*/
|
|
1078
|
+
images?: boolean;
|
|
1079
|
+
}): Promise<ContextPack | string>;
|
|
1080
|
+
/**
|
|
1081
|
+
* Fetch procedural lessons for pack injection. Returns `{}` when the
|
|
1082
|
+
* caller didn't ask for lessons or the storage adapter has no lesson
|
|
1083
|
+
* support — packs stay additive and never fail on lessons.
|
|
1084
|
+
*/
|
|
1085
|
+
private packLessons;
|
|
1086
|
+
/**
|
|
1087
|
+
* Lifetime token-savings counters for context packs. `savedPct` is the
|
|
1088
|
+
* percentage of the naive baseline (raw node JSON for the same
|
|
1089
|
+
* candidates) that TOON packing + budget trimming eliminated.
|
|
1090
|
+
*/
|
|
1091
|
+
usageStats(): {
|
|
1092
|
+
packsBuilt: number;
|
|
1093
|
+
packTokens: number;
|
|
1094
|
+
naiveBaselineTokens: number;
|
|
1095
|
+
savedTokens: number;
|
|
1096
|
+
savedPct: number;
|
|
1097
|
+
};
|
|
1098
|
+
private trackPackUsage;
|
|
1099
|
+
/**
|
|
1100
|
+
* Whether any memory exists in the given pools. Cheap probe used by
|
|
1101
|
+
* `contextPack` to skip multi-stream retrieval on event-only stores.
|
|
1102
|
+
*/
|
|
1103
|
+
private hasPoolContent;
|
|
1104
|
+
/**
|
|
1105
|
+
* Multi-stream retrieval: run the query separately against each
|
|
1106
|
+
* granularity pool and fuse the ranked lists by keeping each node's best
|
|
1107
|
+
* stream score. Candidates found by multiple streams are the strongest
|
|
1108
|
+
* evidence — exactly the behavior that beats single-query retrieval on
|
|
1109
|
+
* the LongMemEval-V2 ablations.
|
|
1110
|
+
*/
|
|
1111
|
+
private multiStreamSearch;
|
|
1112
|
+
/**
|
|
1113
|
+
* Merge near-duplicate memories. Two memories with cosine
|
|
1114
|
+
* similarity over their embeddings above `threshold` collapse into
|
|
1115
|
+
* one: the survivor is the one with the highest importance (ties
|
|
1116
|
+
* broken by recency), and the merged-in nodes have their access
|
|
1117
|
+
* count and tag union folded in.
|
|
1118
|
+
*/
|
|
1119
|
+
dedupe(opts?: DedupeOptions): Promise<DedupeResult>;
|
|
1120
|
+
/**
|
|
1121
|
+
* Move stale + low-importance memories to the `archived` namespace.
|
|
1122
|
+
* They are NOT deleted — they remain in the DB and can be restored
|
|
1123
|
+
* with `memos.update(id, { namespace: "default" })`.
|
|
1124
|
+
*/
|
|
1125
|
+
archive(opts?: ArchiveOptions): Promise<ArchiveResult>;
|
|
1126
|
+
/**
|
|
1127
|
+
* Cluster memories by embedding similarity and produce an extractive
|
|
1128
|
+
* summary for each cluster above `minClusterSize`. The summary is
|
|
1129
|
+
* stored as a regular node with `derived_from` edges to each
|
|
1130
|
+
* source.
|
|
1131
|
+
*/
|
|
1132
|
+
summarizeCluster(opts?: SummarizeClusterOptions): Promise<SummarizeClusterResult>;
|
|
1133
|
+
/**
|
|
1134
|
+
* Verify the tamper-evident mutation log.
|
|
1135
|
+
*
|
|
1136
|
+
* Checks the hash chain (sequence continuity, prev-hash linkage,
|
|
1137
|
+
* entry-hash recomputation) and cross-checks every node's current
|
|
1138
|
+
* content against its latest log entry. Pass `expectTip` with a
|
|
1139
|
+
* checkpoint hash from `memos log checkpoint` to also prove the
|
|
1140
|
+
* chain wasn't rewritten since the checkpoint.
|
|
1141
|
+
*
|
|
1142
|
+
* See `src/tamper-log.ts` for the honest threat model: without an
|
|
1143
|
+
* externally anchored checkpoint, a full-chain rewrite by someone
|
|
1144
|
+
* with raw DB write access is undetectable.
|
|
1145
|
+
*/
|
|
1146
|
+
verifyTamperLog(opts?: {
|
|
1147
|
+
expectTip?: string;
|
|
1148
|
+
}): Promise<TamperVerifyResult>;
|
|
1149
|
+
/**
|
|
1150
|
+
* Read the tamper-evident mutation log in sequence order (newest
|
|
1151
|
+
* last). Returns an empty array when the storage adapter doesn't
|
|
1152
|
+
* implement the log. Entries contain hashes only — no memory
|
|
1153
|
+
* content — so they are safe to display or export.
|
|
1154
|
+
*/
|
|
1155
|
+
readTamperLog(): Promise<TamperLogEntry[]>;
|
|
1156
|
+
/**
|
|
1157
|
+
* Export a cryptographic deletion certificate for a forgotten memory.
|
|
1158
|
+
*
|
|
1159
|
+
* Finds the "forget" entry in the tamper log for the given node ID and
|
|
1160
|
+
* returns a verifiable certificate proving what was deleted and when.
|
|
1161
|
+
* Use `verifyDeletionCertificate()` to check it.
|
|
1162
|
+
*
|
|
1163
|
+
* @param nodeId - The deleted node's ID.
|
|
1164
|
+
* @returns The deletion certificate, or null if no forget entry exists.
|
|
1165
|
+
*/
|
|
1166
|
+
proveForget(nodeId: string): Promise<DeletionCertificate | null>;
|
|
1167
|
+
/**
|
|
1168
|
+
* Reconstruct the memory state as it existed at a given timestamp.
|
|
1169
|
+
*
|
|
1170
|
+
* Time-travel: answers "what did the agent believe on date X?" by
|
|
1171
|
+
* replaying snapshots. Nodes deleted before the target are excluded.
|
|
1172
|
+
*
|
|
1173
|
+
* Note: snapshots are captured from now onward (in-memory). Historical
|
|
1174
|
+
* state before this feature was enabled is not available.
|
|
1175
|
+
*
|
|
1176
|
+
* @param targetTs - Unix ms timestamp to reconstruct.
|
|
1177
|
+
* @returns Nodes as they existed at targetTs.
|
|
1178
|
+
*/
|
|
1179
|
+
replayAt(targetTs: number): Promise<MemoryNode[]>;
|
|
1180
|
+
/**
|
|
1181
|
+
* Version timeline for one memory — the audit view behind "auditable by
|
|
1182
|
+
* design". Returns the memory, the older versions it replaced
|
|
1183
|
+
* (`supersedes`), the newer versions that replaced it (`supersededBy`),
|
|
1184
|
+
* consolidated notes derived from it, and every graph edge touching it.
|
|
1185
|
+
*
|
|
1186
|
+
* Related versions are inferred by content similarity (cosine over
|
|
1187
|
+
* stored embeddings where available, text similarity otherwise) combined
|
|
1188
|
+
* with creation order — superseded versions are the historical ones
|
|
1189
|
+
* (`validTo` set), so nothing here is guesswork about intent.
|
|
1190
|
+
*/
|
|
1191
|
+
history(id: string, opts?: HistoryOptions): Promise<MemoryHistory>;
|
|
1192
|
+
/**
|
|
1193
|
+
* Run dedupe + archive (+ optional cluster summary) in one pass.
|
|
1194
|
+
* This is the canonical entry point for "memory maintenance".
|
|
1195
|
+
*/
|
|
1196
|
+
consolidate(opts?: ConsolidateOptions): Promise<ConsolidateResult>;
|
|
1197
|
+
/**
|
|
1198
|
+
* Decay-based algorithmic forgetting. Computes a retention score per
|
|
1199
|
+
* memory — importance, trust, access reinforcement, and an exponential
|
|
1200
|
+
* recency term — and SUPERSEDES memories whose score falls below
|
|
1201
|
+
* `minScore`: `validTo = now`, so they become historical and drop out
|
|
1202
|
+
* of default search while remaining queryable via `searchTemporal`.
|
|
1203
|
+
* Nothing is ever deleted.
|
|
1204
|
+
*
|
|
1205
|
+
* Weights: importance 0.35 · trust 0.15 · access 0.15 · recency 0.35.
|
|
1206
|
+
* With the default half-life (60 days) a month-old, never-accessed,
|
|
1207
|
+
* agent-inferred low-importance memory crosses the default threshold
|
|
1208
|
+
* (~0.2) at roughly four months of age; frequently-reinforced or
|
|
1209
|
+
* user-stated memories effectively never do.
|
|
1210
|
+
*/
|
|
1211
|
+
forgetByDecay(opts?: DecayForgettingOptions): Promise<DecayForgetResult>;
|
|
1212
|
+
/**
|
|
1213
|
+
* Internal: fetch every node's embedding for the given namespace.
|
|
1214
|
+
* Returns an empty array if the storage adapter doesn't expose
|
|
1215
|
+
* `getAllEmbeddings` (e.g. an in-memory custom adapter).
|
|
1216
|
+
*/
|
|
1217
|
+
private collectEmbeddings;
|
|
1218
|
+
/** Clear the search result cache. Called on any mutation. */
|
|
1219
|
+
private invalidateSearchCache;
|
|
1220
|
+
/**
|
|
1221
|
+
* Wait for all pending embedding jobs to complete.
|
|
1222
|
+
*
|
|
1223
|
+
* Resolves once both the queue and any in-flight persist callbacks have
|
|
1224
|
+
* drained. Safe to call when no embedding provider is configured — it
|
|
1225
|
+
* resolves immediately.
|
|
1226
|
+
*/
|
|
1227
|
+
flushEmbeddings(): Promise<void>;
|
|
1228
|
+
/**
|
|
1229
|
+
* Embed a query through the configured provider with an in-process LRU
|
|
1230
|
+
* cache. Returns `null` when no embedding provider is configured.
|
|
1231
|
+
*
|
|
1232
|
+
* The cache is recall-neutral by construction: the provider's embed
|
|
1233
|
+
* is deterministic in (provider id, model, query), so a hit returns
|
|
1234
|
+
* the exact vector a fresh inference would produce. This collapses the
|
|
1235
|
+
* repeated identical inferences an agent loop performs — most
|
|
1236
|
+
* importantly the 3× fan-out inside `multiStreamSearch`, which now
|
|
1237
|
+
* embeds once and threads the vector through all three pool streams.
|
|
1238
|
+
*/
|
|
1239
|
+
private embedQueryCached;
|
|
1240
|
+
/**
|
|
1241
|
+
* Re-embed every node with the CURRENTLY configured provider, replacing
|
|
1242
|
+
* stale vectors in place. Required after switching embedding models:
|
|
1243
|
+
* vectors from different models are not comparable (semantic search
|
|
1244
|
+
* filters by stored model), and the embedding table has no automatic
|
|
1245
|
+
* migration.
|
|
1246
|
+
*
|
|
1247
|
+
* @param opts.purgeStale — When true, first delete all embedding rows
|
|
1248
|
+
* stored by any OTHER model (frees space; without it, old-model rows
|
|
1249
|
+
* stay on disk until overwritten node-by-node).
|
|
1250
|
+
* @returns Summary counters. `failed` counts nodes whose embedding
|
|
1251
|
+
* could not be recomputed (their status is marked `failed`).
|
|
1252
|
+
*/
|
|
1253
|
+
reindexEmbeddings(opts?: {
|
|
1254
|
+
purgeStale?: boolean;
|
|
1255
|
+
}): Promise<{
|
|
1256
|
+
reembedded: number;
|
|
1257
|
+
purged: number;
|
|
1258
|
+
failed: number;
|
|
1259
|
+
model: string;
|
|
1260
|
+
}>;
|
|
1261
|
+
/**
|
|
1262
|
+
* Per-node embedding status, plus the queue's running/pending counters.
|
|
1263
|
+
*
|
|
1264
|
+
* @param nodeId — Optional filter; when provided, returns only that node.
|
|
1265
|
+
* @returns Aggregate status when called with no args, or a single info
|
|
1266
|
+
* object for the requested node.
|
|
1267
|
+
*/
|
|
1268
|
+
embeddingStatus(): EmbeddingQueueStatus;
|
|
1269
|
+
embeddingStatus(nodeId: string): EmbeddingNodeStatusInfo | null;
|
|
1270
|
+
/**
|
|
1271
|
+
* Set the temporal validity window on a memory node.
|
|
1272
|
+
*
|
|
1273
|
+
* When `validTo` is set to a past timestamp, the memory becomes
|
|
1274
|
+
* "historical" — it is excluded from default search results but
|
|
1275
|
+
* remains queryable via `searchTemporal(query, atTime)`.
|
|
1276
|
+
*
|
|
1277
|
+
* @param id — Memory node ID.
|
|
1278
|
+
* @param validFrom — Validity start (Unix ms), or null to clear.
|
|
1279
|
+
* @param validTo — Validity end (Unix ms), or null to clear.
|
|
1280
|
+
* @returns The updated node, or null if not found.
|
|
1281
|
+
*/
|
|
1282
|
+
setValidity(id: string, validFrom: number | null, validTo: number | null,
|
|
1283
|
+
/** Optional confidence to stamp alongside the validity change. */
|
|
1284
|
+
confidence?: number,
|
|
1285
|
+
/** Optional evidence count to stamp alongside the validity change. */
|
|
1286
|
+
evidenceCount?: number): Promise<MemoryNode | null>;
|
|
1287
|
+
/**
|
|
1288
|
+
* Search for memories that were valid at a specific point in time.
|
|
1289
|
+
*
|
|
1290
|
+
* This is the temporal knowledge graph query: "What did we know
|
|
1291
|
+
* at time T?" A memory is included if:
|
|
1292
|
+
* (validFrom is null OR validFrom <= atTime) AND
|
|
1293
|
+
* (validTo is null OR validTo >= atTime)
|
|
1294
|
+
*
|
|
1295
|
+
* @param query — Text search query.
|
|
1296
|
+
* @param atTime — The point in time to query (Unix ms).
|
|
1297
|
+
* @param opts — Additional search filters (limit, tags, namespace, etc.).
|
|
1298
|
+
* @returns Scored memories valid at `atTime`.
|
|
1299
|
+
*/
|
|
1300
|
+
searchTemporal(query: string, atTime: number, opts?: Omit<SearchFilter, "query" | "validAt">): Promise<ScoredMemory[]>;
|
|
1301
|
+
/**
|
|
1302
|
+
* Supersede a memory — mark it as historical by setting `validTo`
|
|
1303
|
+
* to now, and optionally link the replacement memory with a
|
|
1304
|
+
* `temporal_precedes` edge.
|
|
1305
|
+
*
|
|
1306
|
+
* @param id — The memory to supersede.
|
|
1307
|
+
* @param replacementId — Optional ID of the new memory that replaces it.
|
|
1308
|
+
* @param confidence — Optional confidence to stamp on the retracted
|
|
1309
|
+
* node. Supersession is a contradiction: when the evidence state
|
|
1310
|
+
* machine has already computed the crushed score, pass it here so
|
|
1311
|
+
* the old version stops outranking its replacement. Omit to leave
|
|
1312
|
+
* confidence untouched (pure temporal supersession).
|
|
1313
|
+
* @returns The superseded (updated) node, or null if not found.
|
|
1314
|
+
*/
|
|
1315
|
+
supersede(id: string, replacementId?: string, confidence?: number, evidenceCount?: number): Promise<MemoryNode | null>;
|
|
1316
|
+
/**
|
|
1317
|
+
* Find the predecessor of a memory in its version ledger — the older
|
|
1318
|
+
* version the target superseded. Signals, in priority order:
|
|
1319
|
+
*
|
|
1320
|
+
* 1. `temporal_precedes` edges where the target is the newer endpoint
|
|
1321
|
+
* (written by supersede(id, replacementId));
|
|
1322
|
+
* 2. `resolved` contradiction pairs involving the target (written by the
|
|
1323
|
+
* evidence state machine's contradict path). Pair ids are stored in
|
|
1324
|
+
* canonical sorted order, so direction is recovered from validity —
|
|
1325
|
+
* the historical (validTo-stamped) endpoint is the predecessor.
|
|
1326
|
+
*
|
|
1327
|
+
* The most recently created candidate wins. Returns null when the
|
|
1328
|
+
* memory has no supersession history.
|
|
1329
|
+
*/
|
|
1330
|
+
findRevertPredecessor(targetId: string): Promise<MemoryNode | null>;
|
|
1331
|
+
/**
|
|
1332
|
+
* The most recent currently-valid, non-audit memory in a namespace —
|
|
1333
|
+
* what "revert that" / "revert the last thing" resolves to. Revert
|
|
1334
|
+
* audit events are excluded so a revert can never target its own
|
|
1335
|
+
* record.
|
|
1336
|
+
*/
|
|
1337
|
+
private mostRecentRevertible;
|
|
1338
|
+
/**
|
|
1339
|
+
* Resolve a named entity to the best-matching memory. Disambiguation
|
|
1340
|
+
* rule: when several valid memories match, the most recently created
|
|
1341
|
+
* one wins and the rest are returned as `alternatives` for confirmation
|
|
1342
|
+
* (CLI --dry-run, MCP dry_run) instead of being guessed over.
|
|
1343
|
+
*/
|
|
1344
|
+
private resolveRevertEntity;
|
|
1345
|
+
/**
|
|
1346
|
+
* Resolve a revert scope to a concrete target memory.
|
|
1347
|
+
*
|
|
1348
|
+
* - `{ kind: "id" }` — the memory with that ID.
|
|
1349
|
+
* - `{ kind: "last" }` — the most recent currently-valid, non-audit
|
|
1350
|
+
* memory in the namespace (durable across processes).
|
|
1351
|
+
* - `{ kind: "entity" }` — named-entity search, most-recent-wins.
|
|
1352
|
+
* - `{ kind: "text" }` — natural language run through the local intent
|
|
1353
|
+
* detector (`detectRevertIntent`); "last"-scope phrasing resolves as
|
|
1354
|
+
* "last", named phrasing as an entity. Throws when no revert intent
|
|
1355
|
+
* is detected.
|
|
1356
|
+
*/
|
|
1357
|
+
resolveRevertTarget(scope: RevertScopeInput | string, namespace?: string): Promise<RevertTargetResolution>;
|
|
1358
|
+
/**
|
|
1359
|
+
* Revert a memory to its previous version — the command-driven belief
|
|
1360
|
+
* revision primitive. The user/agent says "revert that" / "go back" /
|
|
1361
|
+
* "that last thing was wrong"; MemOS closes the target's validity
|
|
1362
|
+
* interval NOW and reactivates the predecessor, so the next recall
|
|
1363
|
+
* returns the pre-correction belief with full provenance.
|
|
1364
|
+
*
|
|
1365
|
+
* Add-only: the reverted-away version stays in history (validTo
|
|
1366
|
+
* stamped, the row is never deleted), and the revert itself is recorded
|
|
1367
|
+
* as an audit event node (tags `audit`/`revert`, metadata.audit =
|
|
1368
|
+
* "revert") capturing who/when/why. Edge validity intervals closed by
|
|
1369
|
+
* the earlier supersession are NOT reopened — edges stay add-only; the
|
|
1370
|
+
* node-level belief is what recall returns.
|
|
1371
|
+
*
|
|
1372
|
+
* @param scope — where the target comes from (or a raw string, run
|
|
1373
|
+
* through the intent detector).
|
|
1374
|
+
* @param opts — actor / reason (recorded on the audit event), dryRun,
|
|
1375
|
+
* namespace. Defaults are unchanged everywhere else.
|
|
1376
|
+
* @throws When no target resolves, the target is already historical, or
|
|
1377
|
+
* it has no supersession history to restore.
|
|
1378
|
+
*/
|
|
1379
|
+
revert(scope: RevertScopeInput | string, opts?: RevertOptions): Promise<RevertResult>;
|
|
1380
|
+
/**
|
|
1381
|
+
* Get the trust score of a memory.
|
|
1382
|
+
*
|
|
1383
|
+
* @param id — Memory node ID.
|
|
1384
|
+
* @returns The trust score [0, 1], or null if the node doesn't exist.
|
|
1385
|
+
*/
|
|
1386
|
+
trust(id: string): Promise<number | null>;
|
|
1387
|
+
/**
|
|
1388
|
+
* Set the trust score of a memory.
|
|
1389
|
+
*
|
|
1390
|
+
* Trust scores influence retrieval ranking: higher-trust memories
|
|
1391
|
+
* rank above lower-trust ones for the same relevance score.
|
|
1392
|
+
*
|
|
1393
|
+
* @param id — Memory node ID.
|
|
1394
|
+
* @param score — Trust score in [0, 1].
|
|
1395
|
+
* @returns The updated node, or null if not found.
|
|
1396
|
+
*/
|
|
1397
|
+
setTrust(id: string, score: number): Promise<MemoryNode | null>;
|
|
1398
|
+
/**
|
|
1399
|
+
* Adjust the trust score of a memory by a delta, clamped to [0, 1].
|
|
1400
|
+
*
|
|
1401
|
+
* @param id — Memory node ID.
|
|
1402
|
+
* @param delta — Amount to add (positive) or subtract (negative).
|
|
1403
|
+
* @returns The updated node, or null if not found.
|
|
1404
|
+
*/
|
|
1405
|
+
adjustTrust(id: string, delta: number): Promise<MemoryNode | null>;
|
|
1406
|
+
/**
|
|
1407
|
+
* Extract candidate facts from a conversation.
|
|
1408
|
+
*
|
|
1409
|
+
* Uses a rule-based extractor that identifies user statements,
|
|
1410
|
+
* preferences, and entities from conversation messages. Each
|
|
1411
|
+
* candidate fact is scored by confidence and optionally stored.
|
|
1412
|
+
*
|
|
1413
|
+
* This is a local-first alternative to LLM-based extraction — no
|
|
1414
|
+
* API calls required. For higher-quality extraction, callers can
|
|
1415
|
+
* use an LLM to pre-process the conversation and pass the results
|
|
1416
|
+
* as plain text messages.
|
|
1417
|
+
*
|
|
1418
|
+
* @param messages — The conversation to extract facts from.
|
|
1419
|
+
* @param opts — Extraction options.
|
|
1420
|
+
* @returns Extracted facts and (if autoStore) stored node IDs.
|
|
1421
|
+
*/
|
|
1422
|
+
extractFacts(messages: ConversationMessage[], opts?: ExtractFactsOptions): Promise<ExtractFactsResult>;
|
|
1423
|
+
/**
|
|
1424
|
+
* Rule-based fact extractor. Scans conversation messages for
|
|
1425
|
+
* patterns that indicate facts, preferences, and entities.
|
|
1426
|
+
*
|
|
1427
|
+
* Heuristics:
|
|
1428
|
+
* - "I like/prefer/use/work at" → preference
|
|
1429
|
+
* - "My name is/I am/I'm" → entity (about the user)
|
|
1430
|
+
* - "I need/want/should" → context
|
|
1431
|
+
* - Declarative statements from the user → fact
|
|
1432
|
+
*/
|
|
1433
|
+
private runFactExtractor;
|
|
1434
|
+
/**
|
|
1435
|
+
* Return a detailed diagnostics snapshot of the memory store.
|
|
1436
|
+
*
|
|
1437
|
+
* Includes counts by source, type, and namespace; temporal and
|
|
1438
|
+
* trust statistics; embedding coverage; storage capabilities; and
|
|
1439
|
+
* database file size.
|
|
1440
|
+
*
|
|
1441
|
+
* @returns A diagnostics report.
|
|
1442
|
+
*/
|
|
1443
|
+
/**
|
|
1444
|
+
* Runtime metadata about the active embedding provider: what was
|
|
1445
|
+
* requested vs. what actually resolved, and whether the FastEmbed
|
|
1446
|
+
* local-hash fallback is active. Returns null when embeddings are
|
|
1447
|
+
* disabled (`embeddings: { enabled: false }`).
|
|
1448
|
+
*/
|
|
1449
|
+
getEmbeddingRuntimeInfo(): EmbeddingRuntimeInfo | null;
|
|
1450
|
+
diagnostics(): Promise<DiagnosticsResult>;
|
|
1451
|
+
/**
|
|
1452
|
+
* Register an event listener.
|
|
1453
|
+
*/
|
|
1454
|
+
on(event: MemOSEvent, listener: MemOSEventListener): void;
|
|
1455
|
+
/**
|
|
1456
|
+
* Remove an event listener.
|
|
1457
|
+
*/
|
|
1458
|
+
off(event: MemOSEvent, listener: MemOSEventListener): void;
|
|
1459
|
+
private emit;
|
|
1460
|
+
private assertInit;
|
|
1461
|
+
/**
|
|
1462
|
+
* Evict the least-important memory when `maxMemories` is exceeded.
|
|
1463
|
+
*
|
|
1464
|
+
* The selection is a single SQL statement — we do not load the full
|
|
1465
|
+
* table into memory the way the old in-JS sort did. Falls back to
|
|
1466
|
+
* the in-memory path if the storage adapter doesn't implement
|
|
1467
|
+
* `evictLeastImportant`.
|
|
1468
|
+
*/
|
|
1469
|
+
private evict;
|
|
1470
|
+
/**
|
|
1471
|
+
* Evidence state machine hook for `store()` (opt-in via
|
|
1472
|
+
* `{ evidenceLearning: true }`). Compares the incoming content against
|
|
1473
|
+
* the most similar existing memory in the namespace and applies the
|
|
1474
|
+
* outcome:
|
|
1475
|
+
*
|
|
1476
|
+
* - `{ action: "reinforced", node }`: an existing memory was
|
|
1477
|
+
* confirmed — its confidence and evidence count were bumped and
|
|
1478
|
+
* the caller should NOT write a duplicate node. The returned node
|
|
1479
|
+
* is the freshly-updated version.
|
|
1480
|
+
* - `{ action: "superseded" }`: an existing memory was contradicted —
|
|
1481
|
+
* it has been marked historical (validTo = now) and the caller
|
|
1482
|
+
* SHOULD write the new version.
|
|
1483
|
+
* - `{ action: "new" }`: no decisive match; the caller writes a
|
|
1484
|
+
* fresh node.
|
|
1485
|
+
*
|
|
1486
|
+
* Candidate selection reuses the search index (top-8 by hybrid rank);
|
|
1487
|
+
* classification uses content-to-content pair similarity via
|
|
1488
|
+
* {@link classifyEvidence}, with a shared-subject guard so a negation
|
|
1489
|
+
* can only supersede a memory that is actually about the same thing.
|
|
1490
|
+
*/
|
|
1491
|
+
private applyStoreEvidence;
|
|
1492
|
+
/** Cosine similarity over embeddings with a bag-of-words fallback. */
|
|
1493
|
+
private pairSimilarity;
|
|
1494
|
+
/**
|
|
1495
|
+
* The text that gets embedded for a node. `embeddings.embedText`
|
|
1496
|
+
* selects raw content vs. the historical summary+content blend (the
|
|
1497
|
+
* extractive summary roughly doubles input tokens for short facts).
|
|
1498
|
+
* Write-time context (`metadata.context`, from `store({ context })` or
|
|
1499
|
+
* the `enrichMemory` hook) is prepended so the vector carries
|
|
1500
|
+
* situational meaning — contextual retrieval, without re-embedding
|
|
1501
|
+
* queries. Only nodes stored with a context line are affected; changing
|
|
1502
|
+
* enrichment later requires `reindexEmbeddings()`.
|
|
1503
|
+
*/
|
|
1504
|
+
private embeddedTextFor;
|
|
1505
|
+
private persistEmbedding;
|
|
1506
|
+
/**
|
|
1507
|
+
* Runs after an embedding vector is persisted for a node — all three
|
|
1508
|
+
* persist paths (background queue, synchronous queue fallback, inline
|
|
1509
|
+
* fallback) funnel through here.
|
|
1510
|
+
*
|
|
1511
|
+
* Beyond persisting, this is the write-time contradiction-detection
|
|
1512
|
+
* hook: when the node was freshly written by `store()` (the pending
|
|
1513
|
+
* gate), a bounded semantic-neighbor scan flags contradiction
|
|
1514
|
+
* candidates and persists them. The scan runs in the embedding
|
|
1515
|
+
* background context — never on the synchronous `store()` path — so
|
|
1516
|
+
* write-path overhead stays bounded. Best-effort: detection failures
|
|
1517
|
+
* must never break embedding persistence.
|
|
1518
|
+
*/
|
|
1519
|
+
private onEmbeddingPersisted;
|
|
1520
|
+
/**
|
|
1521
|
+
* Write-time contradiction candidate detection.
|
|
1522
|
+
*
|
|
1523
|
+
* Scans a BOUNDED set of semantic neighbors (top
|
|
1524
|
+
* {@link CONTRADICTION_SCAN_LIMIT} above
|
|
1525
|
+
* {@link CONTRADICTION_SIM_MIN}, same namespace, same embedding
|
|
1526
|
+
* model — one indexed query, never a full table scan), flags pairs
|
|
1527
|
+
* in the contradiction band via `findContradictionCandidates`, and
|
|
1528
|
+
* persists them as `unresolved` pairs. Confirmed `contradicted`
|
|
1529
|
+
* outcomes from the evidence state machine are recorded separately
|
|
1530
|
+
* by `store()` with status `resolved` (see the provenance block
|
|
1531
|
+
* there).
|
|
1532
|
+
*/
|
|
1533
|
+
private detectContradictionsForNode;
|
|
1534
|
+
/**
|
|
1535
|
+
* Enqueue a node for background embedding. Returns immediately.
|
|
1536
|
+
*
|
|
1537
|
+
* If `embeddingQueue.synchronous` is true, falls back to awaiting the
|
|
1538
|
+
* inline persist call (useful for tests that need read-after-write
|
|
1539
|
+
* semantics).
|
|
1540
|
+
*/
|
|
1541
|
+
private scheduleEmbedding;
|
|
1542
|
+
private recordEmbeddingStatus;
|
|
1543
|
+
private backfillEmbeddings;
|
|
1544
|
+
/**
|
|
1545
|
+
* Read-time contradiction resolution (accuracy item 4).
|
|
1546
|
+
*
|
|
1547
|
+
* Fetches recorded contradiction pairs for the ids in the fused
|
|
1548
|
+
* result set (one bounded IN-query) and applies
|
|
1549
|
+
* {@link resolveContradictionsAtRead}: when both members of a pair
|
|
1550
|
+
* are present, the older one is score-demoted so the newer version
|
|
1551
|
+
* wins. Best-effort and storage-agnostic — any failure or a storage
|
|
1552
|
+
* without the contradictions table returns the input untouched.
|
|
1553
|
+
*/
|
|
1554
|
+
private applyContradictionResolution;
|
|
1555
|
+
/**
|
|
1556
|
+
* ── item2: entity leg ── candidate generation from the entity→memories
|
|
1557
|
+
* inverted index (`src/entity-index.ts`). Returns ranked `ScoredMemory`s
|
|
1558
|
+
* (score = number of matched query entities, rank = match count desc /
|
|
1559
|
+
* node id tiebreak) for fusion as the third RRF leg in `fuseResults`.
|
|
1560
|
+
*
|
|
1561
|
+
* Applies the same namespace / type / pool / tag / temporal scoping as
|
|
1562
|
+
* the keyword and semantic legs, so the entity leg can never leak
|
|
1563
|
+
* out-of-scope memories into results. Degrades to `[]` when the query
|
|
1564
|
+
* has no entities or the storage has no entity index (custom adapters).
|
|
1565
|
+
*/
|
|
1566
|
+
private fetchEntityLeg;
|
|
1567
|
+
private hybridSearch;
|
|
1568
|
+
/**
|
|
1569
|
+
* Search and report the relevance gate's verdict alongside the results.
|
|
1570
|
+
*
|
|
1571
|
+
* Backward-compatible sibling of {@link search}: `search()` keeps
|
|
1572
|
+
* returning a bare `ScoredMemory[]`, and every result still carries the
|
|
1573
|
+
* same `relevanceGate` metadata this method exposes as a first-class
|
|
1574
|
+
* member. Unlike `search()` this method bypasses the result cache, so
|
|
1575
|
+
* the reported verdict always describes the call you just made.
|
|
1576
|
+
*
|
|
1577
|
+
* @example
|
|
1578
|
+
* ```ts
|
|
1579
|
+
* const memos = new MemOS({
|
|
1580
|
+
* retrieval: { relevanceGate: { enabled: true, abstainSimilarity: 0.3 } },
|
|
1581
|
+
* });
|
|
1582
|
+
* const { results, gate } = await memos.searchWithGate("anything");
|
|
1583
|
+
* if (gate.abstained) {
|
|
1584
|
+
* // The store has nothing about this query — answer from world
|
|
1585
|
+
* // knowledge instead of inventing a memory recall.
|
|
1586
|
+
* }
|
|
1587
|
+
* ```
|
|
1588
|
+
*/
|
|
1589
|
+
searchWithGate(queryOrFilter: string | SearchFilter): Promise<{
|
|
1590
|
+
results: ScoredMemory[];
|
|
1591
|
+
gate: RelevanceGateResult;
|
|
1592
|
+
}>;
|
|
1593
|
+
/**
|
|
1594
|
+
* Resolve the relevance-gate config, or `null` when the gate is off.
|
|
1595
|
+
*
|
|
1596
|
+
* Off means byte-identical output: the stage is skipped entirely and
|
|
1597
|
+
* the pipeline returns exactly what fusion + expansion + rerank
|
|
1598
|
+
* produced. `enabled` defaults to false because this is a published
|
|
1599
|
+
* SDK and an enabled gate changes how many memories a search returns
|
|
1600
|
+
* for the same query. `MEMOS_RELEVANCE_GATE=1` turns it on without a
|
|
1601
|
+
* config change (experiments and A/B runs).
|
|
1602
|
+
*/
|
|
1603
|
+
private resolveRelevanceGate;
|
|
1604
|
+
/**
|
|
1605
|
+
* Apply the relevance gate to a finished, best-first result list.
|
|
1606
|
+
*
|
|
1607
|
+
* `applyRelevanceGate` (src/retrieval.ts) is pure and already covers
|
|
1608
|
+
* abstention and tail trimming; this wrapper adds the two things the
|
|
1609
|
+
* SDK needs around it:
|
|
1610
|
+
*
|
|
1611
|
+
* - a `minResults` floor, so a caller that needs N items is never left
|
|
1612
|
+
* with fewer by an aggressive ratio;
|
|
1613
|
+
* - reporting — the outcome is written to `opts.gateOut` (when the
|
|
1614
|
+
* caller wants it, e.g. `searchWithGate`) and stamped onto every
|
|
1615
|
+
* surviving result as `ScoredMemory.relevanceGate`.
|
|
1616
|
+
*
|
|
1617
|
+
* Only runs when the gate is configured; otherwise the input array is
|
|
1618
|
+
* returned untouched.
|
|
1619
|
+
*/
|
|
1620
|
+
private applyRelevanceGateStage;
|
|
1621
|
+
/**
|
|
1622
|
+
* Two-stage reranking (`experimental.rerank`, off by default). The first
|
|
1623
|
+
* stage — hybrid retrieval — exists to RECALL candidates; a cross-encoder
|
|
1624
|
+
* then re-scores the top `candidates` fused results against the query and
|
|
1625
|
+
* the final ranking is reordered by that score. Cross-encoders read query
|
|
1626
|
+
* and document together, so they are far more precise than bi-encoder
|
|
1627
|
+
* similarity — at O(candidates) cost per query, which is why it only
|
|
1628
|
+
* ever runs on the narrow head of the pool.
|
|
1629
|
+
*
|
|
1630
|
+
* Two providers: `"endpoint"` (an HTTP `/rerank` server, e.g.
|
|
1631
|
+
* bge-reranker-v2-m3 served by llama-server) and `"local"` (in-process
|
|
1632
|
+
* cross-encoder via `src/rerank-local.ts`, no server needed).
|
|
1633
|
+
*
|
|
1634
|
+
* On reranker failure the fused order is kept unchanged (graceful
|
|
1635
|
+
* degradation) — a downed reranker degrades quality, not availability.
|
|
1636
|
+
*/
|
|
1637
|
+
private applyRerank;
|
|
1638
|
+
/**
|
|
1639
|
+
* Graph-expansion recall leg. Takes the top `maxSeeds` fused results,
|
|
1640
|
+
* follows their graph edges in both directions, and injects unseen
|
|
1641
|
+
* neighbours at `seedScore × scoreFactor` (halved for each subsequent
|
|
1642
|
+
* neighbour of the same seed). Lifts multi-evidence / multi-hop
|
|
1643
|
+
* queries where related facts are connected by edges but neither
|
|
1644
|
+
* retrieval leg surfaces them.
|
|
1645
|
+
*
|
|
1646
|
+
* An EXPLICIT `config` (passed by `contextPack`, which resolves its
|
|
1647
|
+
* own `graphExpansion` opt-out) is authoritative — it is used as-is.
|
|
1648
|
+
* When `config` is omitted the leg resolves its own default:
|
|
1649
|
+
* `experimental.graphExpansion` when present, otherwise ON, and OFF
|
|
1650
|
+
* when `fusion.graphExpansion` is configured (that flag is the
|
|
1651
|
+
* PPR-leg knob — see `applyPprGraphExpansion` — and when a caller
|
|
1652
|
+
* tunes it the PPR walk owns graph expansion, so this older
|
|
1653
|
+
* injection leg stays out of the way rather than double-injecting
|
|
1654
|
+
* nodes the PPR walk should be reporting on).
|
|
1655
|
+
*
|
|
1656
|
+
* `SearchFilter.graphExpansion` is an opt-OUT here (`false` suppresses
|
|
1657
|
+
* injection for one query, which is how the pack path turns expansion
|
|
1658
|
+
* off); `true` is the PPR leg's business and must not turn injection
|
|
1659
|
+
* on when it is otherwise off.
|
|
1660
|
+
*/
|
|
1661
|
+
private applyGraphExpansion;
|
|
1662
|
+
/**
|
|
1663
|
+
* PPR-lite graph expansion (single-step, HippoRAG-style). Runs after
|
|
1664
|
+
* fusion (and after the experimental neighbour-injection leg): the top
|
|
1665
|
+
* `graphExpansionSeeds` fused results seed a personalized PageRank walk
|
|
1666
|
+
* (damping 0.5, `graphExpansionHops` hops) over graph edges plus
|
|
1667
|
+
* shared-entity links, and the final score blends as
|
|
1668
|
+
* `(1 - graphExpansionAlpha) * fused + graphExpansionAlpha * pprNorm`
|
|
1669
|
+
* with PPR scores normalized to [0,1]. Graph neighbours of seeds that
|
|
1670
|
+
* neither retrieval leg surfaced can enter the results this way.
|
|
1671
|
+
*
|
|
1672
|
+
* Controlled by `config.fusion`: `graphExpansion` (default true),
|
|
1673
|
+
* `graphExpansionAlpha` (default 0.2), `graphExpansionHops` (default 2),
|
|
1674
|
+
* `graphExpansionSeeds` (default 10). `filter.graphExpansion === false`
|
|
1675
|
+
* disables it for a single query. With expansion disabled (or
|
|
1676
|
+
* alpha <= 0) the fused list is returned untouched — byte-identical to
|
|
1677
|
+
* the pre-expansion pipeline.
|
|
1678
|
+
*
|
|
1679
|
+
* Cost: one bounded BFS + power iteration over the seed neighbourhood
|
|
1680
|
+
* (no LLM, no embedding calls) plus at most `DEFAULT_PPR_MAX_INJECTED`
|
|
1681
|
+
* `peekNode` reads for newly injected neighbours.
|
|
1682
|
+
*/
|
|
1683
|
+
private applyPprGraphExpansion;
|
|
1684
|
+
/**
|
|
1685
|
+
* In-memory mirror of the SQLite `queryNodes` structured-filter
|
|
1686
|
+
* semantics, applied to PPR-injected neighbours. The SQL legs filter
|
|
1687
|
+
* type, pool, tags, metadata, importance/trust bounds, and temporal
|
|
1688
|
+
* windows at scan time; graph traversal bypasses all of that, so an
|
|
1689
|
+
* injected node must satisfy the same constraints or the expansion
|
|
1690
|
+
* would leak across filter boundaries (e.g. a procedure-only search
|
|
1691
|
+
* surfacing an event-pool neighbour).
|
|
1692
|
+
*
|
|
1693
|
+
* Namespace scoping is enforced separately by the seed-namespace
|
|
1694
|
+
* guard (stricter: the injected node must share a seed's namespace,
|
|
1695
|
+
* and seeds already passed the query's namespace/scope filter). The
|
|
1696
|
+
* query text itself is intentionally not re-applied — injected nodes
|
|
1697
|
+
* are recall wins the keyword/semantic legs missed.
|
|
1698
|
+
*/
|
|
1699
|
+
private pprInjectedNodePassesFilter;
|
|
1700
|
+
/**
|
|
1701
|
+
* Neighbour lookup for the PPR walk, over two link types:
|
|
1702
|
+
*
|
|
1703
|
+
* (a) Graph edges — from the in-memory `GraphEngine` adjacency (both
|
|
1704
|
+
* endpoints, i.e. undirected traversal). Cheapest source: no
|
|
1705
|
+
* storage I/O, O(1) per node.
|
|
1706
|
+
* (b) Shared-entity links — nodes in the fused candidate set sharing a
|
|
1707
|
+
* tag or `metadata.entities` entry (exact match, lowercased),
|
|
1708
|
+
* built in-memory over the candidate set. There is no
|
|
1709
|
+
* entity→memories inverted table on this branch, so this is the
|
|
1710
|
+
* zero-I/O analogue; nodes discovered via edges at hop 2+ do not
|
|
1711
|
+
* contribute entity links (their tags are never fetched, keeping
|
|
1712
|
+
* the hot path bounded) but remain reachable/expandable via edges.
|
|
1713
|
+
*
|
|
1714
|
+
* The returned list is sorted for deterministic iteration; fan-out
|
|
1715
|
+
* capping happens inside {@link personalizedPageRank}.
|
|
1716
|
+
*/
|
|
1717
|
+
private buildPprNeighbors;
|
|
1718
|
+
/**
|
|
1719
|
+
* Near-duplicate suppression (opt-in via `filter.semanticDedup`). A
|
|
1720
|
+
* result whose stored embedding is a near-verbatim duplicate (cosine >=
|
|
1721
|
+
* `experimental.searchDedupThreshold`, default 0.95) of an
|
|
1722
|
+
* already-selected result is dropped and the next candidate takes its
|
|
1723
|
+
* slot — multi-evidence questions otherwise lose top-K slots to
|
|
1724
|
+
* restated facts. Similarity comes from the storage vector cache, so
|
|
1725
|
+
* the pass costs a few dot products, not a new embedding call.
|
|
1726
|
+
*/
|
|
1727
|
+
private applySearchDedup;
|
|
1728
|
+
/**
|
|
1729
|
+
* Session-sibling expansion. Memories recorded from the same
|
|
1730
|
+
* conversation (`metadata.sessionId` / `metadata.instanceId`) are
|
|
1731
|
+
* pulled in behind their seed at a decaying fraction of the seed
|
|
1732
|
+
* score. Multi-hop answers typically span many turns of one session,
|
|
1733
|
+
* so recovering the neighbours of a single relevant turn raises
|
|
1734
|
+
* all-evidence recall without another embedding pass.
|
|
1735
|
+
*
|
|
1736
|
+
* ON by default (`experimental.sessionExpansion`, default true):
|
|
1737
|
+
* injected siblings sit BEHIND every organically-retrieved result at a
|
|
1738
|
+
* decaying `seed.score * scoreFactor^k`, so the head ordering never
|
|
1739
|
+
* moves and only the empty tail is filled — the injected node is only
|
|
1740
|
+
* ever ranked above nodes that scored below it. An explicit
|
|
1741
|
+
* `filter.sessionExpansion === false` disables it per query.
|
|
1742
|
+
*/
|
|
1743
|
+
private applySessionExpansion;
|
|
1744
|
+
/**
|
|
1745
|
+
* Start the background TTL sweep timer.
|
|
1746
|
+
*/
|
|
1747
|
+
private startSweep;
|
|
1748
|
+
/**
|
|
1749
|
+
* Stop the background TTL sweep timer.
|
|
1750
|
+
*/
|
|
1751
|
+
private stopSweep;
|
|
1752
|
+
/**
|
|
1753
|
+
* Convert a memory node to markdown with YAML frontmatter.
|
|
1754
|
+
*/
|
|
1755
|
+
private nodeToMarkdown;
|
|
1756
|
+
private escapeDot;
|
|
1757
|
+
private escapeRegex;
|
|
1758
|
+
}
|
|
1759
|
+
export type { MemoryNode, MemoryEdge, SearchFilter, ScoredMemory, GraphSnapshot, MemOSConfig, ExportOptions, ExportResult, ExperimentalConfig, } from "./types.js";
|
|
1760
|
+
export { GraphEngine, textSimilarity } from "./graph.js";
|
|
1761
|
+
export { SQLiteStorage } from "./storage/sqlite.js";
|
|
1762
|
+
//# sourceMappingURL=memory.d.ts.map
|