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.
Files changed (253) hide show
  1. mem_os_python-1.6.27.dist-info/METADATA +1032 -0
  2. mem_os_python-1.6.27.dist-info/RECORD +253 -0
  3. mem_os_python-1.6.27.dist-info/WHEEL +4 -0
  4. mem_os_python-1.6.27.dist-info/entry_points.txt +2 -0
  5. mem_os_python-1.6.27.dist-info/licenses/LICENSE +21 -0
  6. memos/__init__.py +16 -0
  7. memos/_js/adapters/anthropic.d.ts +279 -0
  8. memos/_js/adapters/anthropic.d.ts.map +1 -0
  9. memos/_js/adapters/anthropic.js +348 -0
  10. memos/_js/adapters/anthropic.js.map +1 -0
  11. memos/_js/adapters/base.d.ts +10 -0
  12. memos/_js/adapters/base.d.ts.map +1 -0
  13. memos/_js/adapters/base.js +2 -0
  14. memos/_js/adapters/base.js.map +1 -0
  15. memos/_js/adapters/openai.d.ts +264 -0
  16. memos/_js/adapters/openai.d.ts.map +1 -0
  17. memos/_js/adapters/openai.js +342 -0
  18. memos/_js/adapters/openai.js.map +1 -0
  19. memos/_js/apps/explorer.d.ts +244 -0
  20. memos/_js/apps/explorer.d.ts.map +1 -0
  21. memos/_js/apps/explorer.js +738 -0
  22. memos/_js/apps/explorer.js.map +1 -0
  23. memos/_js/citations.d.ts +65 -0
  24. memos/_js/citations.d.ts.map +1 -0
  25. memos/_js/citations.js +143 -0
  26. memos/_js/citations.js.map +1 -0
  27. memos/_js/cli-browse.d.ts +3 -0
  28. memos/_js/cli-browse.d.ts.map +1 -0
  29. memos/_js/cli-browse.js +129 -0
  30. memos/_js/cli-browse.js.map +1 -0
  31. memos/_js/cli-completion.d.ts +31 -0
  32. memos/_js/cli-completion.d.ts.map +1 -0
  33. memos/_js/cli-completion.js +340 -0
  34. memos/_js/cli-completion.js.map +1 -0
  35. memos/_js/cli-help.d.ts +18 -0
  36. memos/_js/cli-help.d.ts.map +1 -0
  37. memos/_js/cli-help.js +357 -0
  38. memos/_js/cli-help.js.map +1 -0
  39. memos/_js/cli.d.ts +28 -0
  40. memos/_js/cli.d.ts.map +1 -0
  41. memos/_js/cli.js +2880 -0
  42. memos/_js/cli.js.map +1 -0
  43. memos/_js/compression.d.ts +25 -0
  44. memos/_js/compression.d.ts.map +1 -0
  45. memos/_js/compression.js +319 -0
  46. memos/_js/compression.js.map +1 -0
  47. memos/_js/confidence-machine.d.ts +99 -0
  48. memos/_js/confidence-machine.d.ts.map +1 -0
  49. memos/_js/confidence-machine.js +222 -0
  50. memos/_js/confidence-machine.js.map +1 -0
  51. memos/_js/context-pack.d.ts +506 -0
  52. memos/_js/context-pack.d.ts.map +1 -0
  53. memos/_js/context-pack.js +1435 -0
  54. memos/_js/context-pack.js.map +1 -0
  55. memos/_js/contradictions.d.ts +160 -0
  56. memos/_js/contradictions.d.ts.map +1 -0
  57. memos/_js/contradictions.js +255 -0
  58. memos/_js/contradictions.js.map +1 -0
  59. memos/_js/dashboard.d.ts +30 -0
  60. memos/_js/dashboard.d.ts.map +1 -0
  61. memos/_js/dashboard.js +302 -0
  62. memos/_js/dashboard.js.map +1 -0
  63. memos/_js/ebbinghaus.d.ts +29 -0
  64. memos/_js/ebbinghaus.d.ts.map +1 -0
  65. memos/_js/ebbinghaus.js +32 -0
  66. memos/_js/ebbinghaus.js.map +1 -0
  67. memos/_js/embedding-queue.d.ts +190 -0
  68. memos/_js/embedding-queue.d.ts.map +1 -0
  69. memos/_js/embedding-queue.js +316 -0
  70. memos/_js/embedding-queue.js.map +1 -0
  71. memos/_js/embeddings.d.ts +187 -0
  72. memos/_js/embeddings.d.ts.map +1 -0
  73. memos/_js/embeddings.js +633 -0
  74. memos/_js/embeddings.js.map +1 -0
  75. memos/_js/entity-extraction.d.ts +54 -0
  76. memos/_js/entity-extraction.d.ts.map +1 -0
  77. memos/_js/entity-extraction.js +325 -0
  78. memos/_js/entity-extraction.js.map +1 -0
  79. memos/_js/entity-index.d.ts +93 -0
  80. memos/_js/entity-index.d.ts.map +1 -0
  81. memos/_js/entity-index.js +165 -0
  82. memos/_js/entity-index.js.map +1 -0
  83. memos/_js/event-memory.d.ts +147 -0
  84. memos/_js/event-memory.d.ts.map +1 -0
  85. memos/_js/event-memory.js +290 -0
  86. memos/_js/event-memory.js.map +1 -0
  87. memos/_js/external-import.d.ts +98 -0
  88. memos/_js/external-import.d.ts.map +1 -0
  89. memos/_js/external-import.js +669 -0
  90. memos/_js/external-import.js.map +1 -0
  91. memos/_js/fidelity.d.ts +367 -0
  92. memos/_js/fidelity.d.ts.map +1 -0
  93. memos/_js/fidelity.js +911 -0
  94. memos/_js/fidelity.js.map +1 -0
  95. memos/_js/graph-expansion.d.ts +119 -0
  96. memos/_js/graph-expansion.d.ts.map +1 -0
  97. memos/_js/graph-expansion.js +213 -0
  98. memos/_js/graph-expansion.js.map +1 -0
  99. memos/_js/graph-mermaid.d.ts +13 -0
  100. memos/_js/graph-mermaid.d.ts.map +1 -0
  101. memos/_js/graph-mermaid.js +32 -0
  102. memos/_js/graph-mermaid.js.map +1 -0
  103. memos/_js/graph.d.ts +170 -0
  104. memos/_js/graph.d.ts.map +1 -0
  105. memos/_js/graph.js +482 -0
  106. memos/_js/graph.js.map +1 -0
  107. memos/_js/harness.d.ts +63 -0
  108. memos/_js/harness.d.ts.map +1 -0
  109. memos/_js/harness.js +93 -0
  110. memos/_js/harness.js.map +1 -0
  111. memos/_js/importance.d.ts +118 -0
  112. memos/_js/importance.d.ts.map +1 -0
  113. memos/_js/importance.js +144 -0
  114. memos/_js/importance.js.map +1 -0
  115. memos/_js/index.d.ts +51 -0
  116. memos/_js/index.d.ts.map +1 -0
  117. memos/_js/index.js +53 -0
  118. memos/_js/index.js.map +1 -0
  119. memos/_js/mcp.d.ts +58 -0
  120. memos/_js/mcp.d.ts.map +1 -0
  121. memos/_js/mcp.js +1853 -0
  122. memos/_js/mcp.js.map +1 -0
  123. memos/_js/memory.d.ts +1762 -0
  124. memos/_js/memory.d.ts.map +1 -0
  125. memos/_js/memory.js +6283 -0
  126. memos/_js/memory.js.map +1 -0
  127. memos/_js/procedural.d.ts +74 -0
  128. memos/_js/procedural.d.ts.map +1 -0
  129. memos/_js/procedural.js +125 -0
  130. memos/_js/procedural.js.map +1 -0
  131. memos/_js/project-config.d.ts +68 -0
  132. memos/_js/project-config.d.ts.map +1 -0
  133. memos/_js/project-config.js +59 -0
  134. memos/_js/project-config.js.map +1 -0
  135. memos/_js/proof-of-forgetting.d.ts +57 -0
  136. memos/_js/proof-of-forgetting.d.ts.map +1 -0
  137. memos/_js/proof-of-forgetting.js +80 -0
  138. memos/_js/proof-of-forgetting.js.map +1 -0
  139. memos/_js/provenance.d.ts +122 -0
  140. memos/_js/provenance.d.ts.map +1 -0
  141. memos/_js/provenance.js +182 -0
  142. memos/_js/provenance.js.map +1 -0
  143. memos/_js/quarantine-commands.d.ts +23 -0
  144. memos/_js/quarantine-commands.d.ts.map +1 -0
  145. memos/_js/quarantine-commands.js +42 -0
  146. memos/_js/quarantine-commands.js.map +1 -0
  147. memos/_js/quarantine.d.ts +120 -0
  148. memos/_js/quarantine.d.ts.map +1 -0
  149. memos/_js/quarantine.js +873 -0
  150. memos/_js/quarantine.js.map +1 -0
  151. memos/_js/redact.d.ts +12 -0
  152. memos/_js/redact.d.ts.map +1 -0
  153. memos/_js/redact.js +26 -0
  154. memos/_js/redact.js.map +1 -0
  155. memos/_js/repl.d.ts +57 -0
  156. memos/_js/repl.d.ts.map +1 -0
  157. memos/_js/repl.js +295 -0
  158. memos/_js/repl.js.map +1 -0
  159. memos/_js/rerank-local.d.ts +61 -0
  160. memos/_js/rerank-local.d.ts.map +1 -0
  161. memos/_js/rerank-local.js +210 -0
  162. memos/_js/rerank-local.js.map +1 -0
  163. memos/_js/retain-filter.d.ts +98 -0
  164. memos/_js/retain-filter.d.ts.map +1 -0
  165. memos/_js/retain-filter.js +232 -0
  166. memos/_js/retain-filter.js.map +1 -0
  167. memos/_js/retrieval.d.ts +265 -0
  168. memos/_js/retrieval.d.ts.map +1 -0
  169. memos/_js/retrieval.js +1018 -0
  170. memos/_js/retrieval.js.map +1 -0
  171. memos/_js/revert.d.ts +77 -0
  172. memos/_js/revert.d.ts.map +1 -0
  173. memos/_js/revert.js +252 -0
  174. memos/_js/revert.js.map +1 -0
  175. memos/_js/scope.d.ts +30 -0
  176. memos/_js/scope.d.ts.map +1 -0
  177. memos/_js/scope.js +71 -0
  178. memos/_js/scope.js.map +1 -0
  179. memos/_js/semantic-screen.d.ts +152 -0
  180. memos/_js/semantic-screen.d.ts.map +1 -0
  181. memos/_js/semantic-screen.js +290 -0
  182. memos/_js/semantic-screen.js.map +1 -0
  183. memos/_js/session-hooks.d.ts +127 -0
  184. memos/_js/session-hooks.d.ts.map +1 -0
  185. memos/_js/session-hooks.js +482 -0
  186. memos/_js/session-hooks.js.map +1 -0
  187. memos/_js/storage/sqlite.d.ts +427 -0
  188. memos/_js/storage/sqlite.d.ts.map +1 -0
  189. memos/_js/storage/sqlite.js +2428 -0
  190. memos/_js/storage/sqlite.js.map +1 -0
  191. memos/_js/sync.d.ts +213 -0
  192. memos/_js/sync.d.ts.map +1 -0
  193. memos/_js/sync.js +389 -0
  194. memos/_js/sync.js.map +1 -0
  195. memos/_js/tamper-log.d.ts +98 -0
  196. memos/_js/tamper-log.d.ts.map +1 -0
  197. memos/_js/tamper-log.js +327 -0
  198. memos/_js/tamper-log.js.map +1 -0
  199. memos/_js/temporal.d.ts +92 -0
  200. memos/_js/temporal.d.ts.map +1 -0
  201. memos/_js/temporal.js +536 -0
  202. memos/_js/temporal.js.map +1 -0
  203. memos/_js/time-travel.d.ts +38 -0
  204. memos/_js/time-travel.d.ts.map +1 -0
  205. memos/_js/time-travel.js +46 -0
  206. memos/_js/time-travel.js.map +1 -0
  207. memos/_js/timestamp-format.d.ts +18 -0
  208. memos/_js/timestamp-format.d.ts.map +1 -0
  209. memos/_js/timestamp-format.js +52 -0
  210. memos/_js/timestamp-format.js.map +1 -0
  211. memos/_js/triple-extraction.d.ts +31 -0
  212. memos/_js/triple-extraction.d.ts.map +1 -0
  213. memos/_js/triple-extraction.js +116 -0
  214. memos/_js/triple-extraction.js.map +1 -0
  215. memos/_js/types.d.ts +2474 -0
  216. memos/_js/types.d.ts.map +1 -0
  217. memos/_js/types.js +20 -0
  218. memos/_js/types.js.map +1 -0
  219. memos/_js/updater.d.ts +95 -0
  220. memos/_js/updater.d.ts.map +1 -0
  221. memos/_js/updater.js +268 -0
  222. memos/_js/updater.js.map +1 -0
  223. memos/_js/version.d.ts +17 -0
  224. memos/_js/version.d.ts.map +1 -0
  225. memos/_js/version.js +34 -0
  226. memos/_js/version.js.map +1 -0
  227. memos/_js/vision/clip-query-cache.d.ts +58 -0
  228. memos/_js/vision/clip-query-cache.d.ts.map +1 -0
  229. memos/_js/vision/clip-query-cache.js +79 -0
  230. memos/_js/vision/clip-query-cache.js.map +1 -0
  231. memos/_js/vision/clip.d.ts +113 -0
  232. memos/_js/vision/clip.d.ts.map +1 -0
  233. memos/_js/vision/clip.js +224 -0
  234. memos/_js/vision/clip.js.map +1 -0
  235. memos/_js/vision/fake-clip.d.ts +55 -0
  236. memos/_js/vision/fake-clip.d.ts.map +1 -0
  237. memos/_js/vision/fake-clip.js +122 -0
  238. memos/_js/vision/fake-clip.js.map +1 -0
  239. memos/_js/vision/index.d.ts +15 -0
  240. memos/_js/vision/index.d.ts.map +1 -0
  241. memos/_js/vision/index.js +13 -0
  242. memos/_js/vision/index.js.map +1 -0
  243. memos/_js/vision/store.d.ts +137 -0
  244. memos/_js/vision/store.d.ts.map +1 -0
  245. memos/_js/vision/store.js +383 -0
  246. memos/_js/vision/store.js.map +1 -0
  247. memos/adapters/__init__.py +0 -0
  248. memos/adapters/crewai.py +385 -0
  249. memos/adapters/langchain.py +301 -0
  250. memos/adapters/ollama.py +396 -0
  251. memos/server/__init__.py +0 -0
  252. memos/server/main.py +547 -0
  253. memos/server/routes.py +360 -0
memos/_js/types.d.ts ADDED
@@ -0,0 +1,2474 @@
1
+ /**
2
+ * MemOS — Universal memory layer for AI agents.
3
+ *
4
+ * Core type definitions. Every interface and type in the system
5
+ * is defined here to provide a single source of truth for the
6
+ * data model across modules.
7
+ *
8
+ * @module @memos/types
9
+ */
10
+ import type { CompressionLevel } from "./compression.js";
11
+ import type { ImportanceConfig } from "./importance.js";
12
+ /**
13
+ * Semantic category for a memory node.
14
+ *
15
+ * - `fact` — A discrete piece of information.
16
+ * - `preference` — A user or agent preference.
17
+ * - `context` — Conversational or situational context.
18
+ * - `relationship` — An observed relationship between entities.
19
+ * - `entity` — A named entity (person, place, thing).
20
+ * - `custom` — Application-defined type.
21
+ */
22
+ export type MemoryType = "fact" | "preference" | "context" | "relationship" | "entity" | "custom";
23
+ /**
24
+ * Provenance source for a memory node.
25
+ *
26
+ * - `user_input` — Stated directly by the user. Highest trust.
27
+ * - `agent_inferred` — Inferred by an agent from context.
28
+ * - `tool_output` — Returned by a tool call (treated as untrusted
29
+ * for agent consumption — see the provenance-trust layer).
30
+ * - `external_data` — Imported from an external source.
31
+ * - `system` — Generated by the system itself.
32
+ */
33
+ export type MemorySource = "user_input" | "agent_inferred" | "tool_output" | "external_data" | "system";
34
+ /**
35
+ * Default trust score for each provenance source.
36
+ */
37
+ export declare const DEFAULT_TRUST_SCORES: Record<MemorySource, number>;
38
+ /**
39
+ * Provenance tier — the trust channel a memory arrived through, assigned
40
+ * at write time and stored as a column. Ordered highest-trust first:
41
+ *
42
+ * - `user-verified` — explicitly confirmed by the user. Never assigned
43
+ * automatically — only via an explicit `provenance` option or
44
+ * `verify()`.
45
+ * - `user` — ordinary user statements (default for
46
+ * `source: "user_input"` writes).
47
+ * - `tool-output` — results returned by tools (`source: "tool_output"`).
48
+ * - `chat` — model-generated content (`source: "agent_inferred"`
49
+ * or `"system"`).
50
+ * - `imported` — bulk imports (`source: "external_data"`).
51
+ *
52
+ * See `src/provenance.ts` for the default rule, trust multipliers, and
53
+ * the read-time trust policy.
54
+ */
55
+ export type ProvenanceTier = "user-verified" | "user" | "tool-output" | "chat" | "imported";
56
+ /**
57
+ * A single unit of memory stored in the graph.
58
+ */
59
+ /**
60
+ * Which retrieval pool a memory belongs to — the multi-granularity
61
+ * structure from the LongMemEval-V2 design lessons:
62
+ * - `event` — raw statements as they were captured (the default; every
63
+ * legacy memory reads as `event`).
64
+ * - `note` — distilled summaries produced by consolidation
65
+ * (`summarizeCluster` writes here).
66
+ * - `procedure` — workflow/procedural knowledge ("how to" steps).
67
+ * - `visual` — image memories (the node is `type: "fact"` with
68
+ * `metadata.image` present); multi-stream packs search
69
+ * this as a dedicated stream.
70
+ * Pools are queryable via `SearchFilter.pool` and searched as separate
71
+ * streams by multi-stream context packs.
72
+ */
73
+ export type MemoryPool = "event" | "note" | "procedure" | "visual";
74
+ /**
75
+ * Typed multi-scope keys for isolating memories per user, agent, and run.
76
+ * Composed into the underlying namespace string in fixed order
77
+ * (`u:alice/a:coder/r:r1`) — see `src/scope.ts`. Hierarchical by default:
78
+ * querying `{ user: "alice" }` surfaces every memory Alice's agents and
79
+ * runs stored.
80
+ */
81
+ export interface MemoryScope {
82
+ /** Owner of the memories (e.g. end-user id). */
83
+ user?: string;
84
+ /** Which agent produced them. */
85
+ agent?: string;
86
+ /** Which session/run produced them. */
87
+ run?: string;
88
+ }
89
+ export interface MemoryNode {
90
+ /** Globally unique identifier (UUID v4). */
91
+ id: string;
92
+ /** Raw text content of the memory. */
93
+ content: string;
94
+ /** Extractive summary (auto-generated if not supplied). */
95
+ summary: string;
96
+ /** Semantic type of this memory. */
97
+ type: MemoryType;
98
+ /** Arbitrary metadata bag. Must be JSON-serialisable. */
99
+ metadata: Record<string, unknown>;
100
+ /**
101
+ * Base importance score in [0, 1]. Set at write time (default 0.5) or
102
+ * manually via `update`. Lifecycle decisions (eviction, archival)
103
+ * derive an *effective* importance from this base plus recency decay
104
+ * and access reinforcement — see `computeEffectiveImportance` in
105
+ * `src/importance.ts`.
106
+ */
107
+ importance: number;
108
+ /** Creation timestamp (Unix ms). */
109
+ createdAt: number;
110
+ /** Last-modified timestamp (Unix ms). */
111
+ updatedAt: number;
112
+ /** Number of times this node has been retrieved. */
113
+ accessCount: number;
114
+ /** Timestamp of last access (Unix ms). */
115
+ lastAccessed: number;
116
+ /** Custom tags for categorisation. */
117
+ tags: string[];
118
+ /** TTL expiration as Unix timestamp (seconds). null = no expiration. */
119
+ expiresAt: number | null;
120
+ /** Namespace for grouping memories (experimental). */
121
+ namespace: string;
122
+ /**
123
+ * Temporal validity start (Unix ms). When set, the memory is
124
+ * considered "active" from this point in time. null = always valid.
125
+ */
126
+ validFrom: number | null;
127
+ /**
128
+ * Temporal validity end (Unix ms). When set, the memory becomes
129
+ * "historical" (excluded from default search) after this time.
130
+ * null = no expiry. Superseded memories keep their validTo so the
131
+ * history is queryable via `searchTemporal`.
132
+ */
133
+ validTo: number | null;
134
+ /**
135
+ * Where this memory originated. Used for provenance and trust
136
+ * scoring.
137
+ * - `user_input` — Stated directly by the user. Highest trust.
138
+ * - `agent_inferred` — Inferred by an agent from context. Lower trust.
139
+ * - `external_data` — Imported from an external source (API, file, etc.).
140
+ * - `system` — Generated by the system itself.
141
+ */
142
+ source: MemorySource;
143
+ /**
144
+ * Provenance tier — the trust channel this memory arrived through
145
+ * (`user-verified` > `user` > `tool-output` > `chat` > `imported`).
146
+ * Assigned at write time from `CreateMemoryInput.provenance` or the
147
+ * source-derived default (see `resolveProvenance` in
148
+ * `src/provenance.ts`); backfilled as `"user"` for legacy rows.
149
+ */
150
+ provenance: ProvenanceTier;
151
+ /**
152
+ * Write-gate quarantine flag. When the local-heuristic classifier
153
+ * (`screenWrite` in `src/quarantine.ts`) flags instruction-like
154
+ * content, the memory is still stored (add-only) but quarantined:
155
+ * excluded from recall by default until reviewed via
156
+ * `memos quarantine list|release`.
157
+ */
158
+ quarantined: boolean;
159
+ /** Unix ms when the memory was quarantined. null when never. */
160
+ quarantinedAt: number | null;
161
+ /** `;`-joined quarantine signal codes. null when never quarantined. */
162
+ quarantineReason: string | null;
163
+ /**
164
+ * Retrieval pool this memory belongs to (multi-granularity retrieval).
165
+ * Optional for backward compatibility with custom storage adapters;
166
+ * treated as `"event"` when absent.
167
+ */
168
+ pool?: MemoryPool;
169
+ /**
170
+ * Harness that wrote this memory (`"claude-code"`, `"cline"`,
171
+ * `"codex"`, `"gemini-cli"`, `"openclaw"`, or `"unknown"`). Stamped
172
+ * at write time by `store()` via `detectHarness()`; optional for
173
+ * backward compatibility with node literals and custom storage
174
+ * adapters — reads as `"unknown"` when absent. Legacy rows are
175
+ * backfilled as `"unknown"` by the schema migration.
176
+ */
177
+ harness?: string;
178
+ /**
179
+ * Trust score in [0, 1]. Influences retrieval ranking. Starts at
180
+ * 1.0 for `user_input`, 0.7 for `agent_inferred`, 0.5 for
181
+ * `external_data`, 0.3 for `system`. Can be manually adjusted via
182
+ * `memos.setTrust()`.
183
+ */
184
+ trustScore: number;
185
+ /**
186
+ * Dynamic confidence score in [0, 1]. Reflects how sure the system
187
+ * is that this memory is still true, given new observations.
188
+ * - Reinforced when new observations agree (confidence goes up)
189
+ * - Revised when new observations partially conflict (confidence goes down)
190
+ * - Superseded when new facts clearly replace old ones (marked historical)
191
+ * Stored in metadata as `confidence` and `evidenceCount`.
192
+ */
193
+ confidence?: number;
194
+ /** Number of evidence events (reinforces + revisions) that touched this memory. */
195
+ evidenceCount?: number;
196
+ }
197
+ /**
198
+ * Partial input accepted when creating a new memory.
199
+ * Only `content` is required; everything else has defaults.
200
+ */
201
+ export interface CreateMemoryInput {
202
+ content: string;
203
+ type?: MemoryType;
204
+ metadata?: Record<string, unknown>;
205
+ summary?: string;
206
+ importance?: number;
207
+ /** TTL in seconds from now. */
208
+ ttl?: number;
209
+ /** Custom tags. */
210
+ tags?: string[];
211
+ /** Namespace (experimental). */
212
+ namespace?: string;
213
+ /**
214
+ * Typed multi-scope isolation. Composed into the namespace string
215
+ * (fixed order user → agent → run); takes precedence over `namespace`
216
+ * when both are supplied.
217
+ */
218
+ scope?: MemoryScope;
219
+ /** Temporal validity start (Unix ms). null = always valid. */
220
+ validFrom?: number | null;
221
+ /** Temporal validity end (Unix ms). null = no expiry. */
222
+ validTo?: number | null;
223
+ /** Provenance source. Default: `user_input`. */
224
+ source?: MemorySource;
225
+ /**
226
+ * Provenance tier override (`user-verified` > `user` > `tool-output` >
227
+ * `chat` > `imported`). When omitted, the tier is derived from
228
+ * `source` via the default rule (see `resolveProvenance` in
229
+ * `src/provenance.ts`): `user_input` → `user`, `tool_output` →
230
+ * `tool-output`, `agent_inferred`/`system` → `chat`, `external_data` →
231
+ * `imported`. `user-verified` is never assigned automatically.
232
+ */
233
+ provenance?: ProvenanceTier;
234
+ /**
235
+ * Write-gate screening: when true (default), the local-heuristic
236
+ * classifier (`screenWrite`) runs on `content` and flags
237
+ * instruction-like payloads by storing them quarantined (excluded
238
+ * from recall until reviewed). Set to false to bypass screening for
239
+ * trusted bulk operations. No LLM is ever consulted on this path.
240
+ */
241
+ quarantineScreen?: boolean;
242
+ /**
243
+ * Retrieval pool for this memory. Default: `"event"`. Use `"procedure"`
244
+ * for workflow/how-to knowledge — multi-stream context packs search
245
+ * procedures with a dedicated query stream.
246
+ */
247
+ pool?: MemoryPool;
248
+ /**
249
+ * One line of write-time context describing the situation this memory
250
+ * was captured in (e.g. "stated while debugging the deploy pipeline").
251
+ * Stored in `metadata.context`, prepended to the embedded text, and
252
+ * included in context packs. When absent, the optional
253
+ * `MemOSConfig.enrichMemory` hook is consulted.
254
+ */
255
+ context?: string;
256
+ /** Trust score [0, 1]. Overrides the default for the chosen source. */
257
+ trustScore?: number;
258
+ /**
259
+ * Harness attribution override (e.g. `"claude-code"`, `"cline"`).
260
+ * When omitted, `store()` stamps the harness detected from the
261
+ * environment via `detectHarness()` (see `src/harness.ts`).
262
+ */
263
+ harness?: string;
264
+ /**
265
+ * Dynamic confidence score [0, 1] for the confidence state machine.
266
+ * Used to track how sure the system is that this memory is still true.
267
+ * If omitted, defaults to INITIAL_CONFIDENCE (0.5).
268
+ */
269
+ confidence?: number;
270
+ /**
271
+ * Evidence count for the confidence state machine.
272
+ * Number of reinforce/revise events this memory has accumulated.
273
+ * If omitted, defaults to 0 for manually stored items.
274
+ */
275
+ evidenceCount?: number;
276
+ /**
277
+ * When true, apply the Hermes-style retain pre-filter (v1.6.26) before
278
+ * writing: low-signal content (acknowledgements, chit-chat, near-empty
279
+ * text) is skipped so long-term memory isn't flooded with noise that would
280
+ * later bloat context-packs. Default: false (write always).
281
+ */
282
+ filterRetain?: boolean;
283
+ /**
284
+ * When true, run the evidence state machine before writing:
285
+ * content that confirms an existing memory reinforces it (confidence ↑)
286
+ * instead of writing a duplicate node, and content that contradicts it
287
+ * supersedes the old version. Default: false — store() appends a new
288
+ * node every time (use dedupe()/consolidate() for explicit merging).
289
+ */
290
+ evidenceLearning?: boolean;
291
+ /**
292
+ * Reference time (Unix ms) for this write. Overrides `Date.now()` as
293
+ * the write timestamp AND as the reference time for deterministic
294
+ * temporal parsing (event extraction / update resolution). Primarily
295
+ * a testing hook — omit in production so the wall clock is used.
296
+ */
297
+ now?: number;
298
+ }
299
+ /**
300
+ * Partial update for an existing memory node.
301
+ */
302
+ export interface UpdateMemoryInput {
303
+ content?: string;
304
+ summary?: string;
305
+ type?: MemoryType;
306
+ metadata?: Record<string, unknown>;
307
+ importance?: number;
308
+ tags?: string[];
309
+ namespace?: string;
310
+ /** Access count for Ebbinghaus reinforcement. */
311
+ accessCount?: number;
312
+ /** Last access time (Unix ms) for Ebbinghaus reinforcement. */
313
+ lastAccessed?: number;
314
+ /** Temporal validity start (Unix ms). */
315
+ validFrom?: number | null;
316
+ /** Temporal validity end (Unix ms). */
317
+ validTo?: number | null;
318
+ /** Provenance source. */
319
+ source?: MemorySource;
320
+ /** Provenance tier override (see `CreateMemoryInput.provenance`). */
321
+ provenance?: ProvenanceTier;
322
+ /**
323
+ * Quarantine flag. Set explicitly by `releaseFromQuarantine` (false)
324
+ * or administrative quarantine (true); the write gate sets it via
325
+ * `store()`, not via `update()`.
326
+ */
327
+ quarantined?: boolean;
328
+ /** Unix ms when the memory was quarantined. null clears it. */
329
+ quarantinedAt?: number | null;
330
+ /** `;`-joined quarantine signal codes. null clears it. */
331
+ quarantineReason?: string | null;
332
+ /** Trust score [0, 1]. */
333
+ trustScore?: number;
334
+ /** Dynamic confidence [0, 1] — updated by the evidence state machine. */
335
+ confidence?: number;
336
+ /** Evidence count — updated by the evidence state machine. */
337
+ evidenceCount?: number;
338
+ }
339
+ /**
340
+ * Semantic relation between two memory nodes.
341
+ *
342
+ * - `relates_to` — General association.
343
+ * - `contradicts` — The target contradicts the source.
344
+ * - `supports` — The target supports the source.
345
+ * - `derived_from` — The source was derived from the target.
346
+ * - `part_of` — The source is a part of the target.
347
+ * - `custom` — Application-defined relation.
348
+ */
349
+ export type EdgeRelation = "relates_to" | "contradicts" | "supports" | "derived_from" | "part_of" | "temporal_precedes" | "custom";
350
+ /**
351
+ * A directed, weighted edge connecting two memory nodes.
352
+ */
353
+ export interface MemoryEdge {
354
+ /** Globally unique identifier (UUID v4). */
355
+ id: string;
356
+ /** Source node ID. */
357
+ sourceId: string;
358
+ /** Target node ID. */
359
+ targetId: string;
360
+ /** Semantic relation label. */
361
+ relation: EdgeRelation;
362
+ /** Edge weight in [0, 1]. */
363
+ weight: number;
364
+ /** Arbitrary metadata bag. */
365
+ metadata: Record<string, unknown>;
366
+ /**
367
+ * Transaction/ingest time (Unix ms): when MemOS learned the fact.
368
+ * This is the bitemporal transaction-time axis — it is never renamed
369
+ * or repurposed; event-time validity lives in `validFrom`/`validTo`.
370
+ */
371
+ createdAt: number;
372
+ /**
373
+ * Event-time validity start (Unix ms): when the fact became true in the
374
+ * world. `null`/undefined = open-ended (still true, or unknown).
375
+ */
376
+ validFrom?: number | null;
377
+ /**
378
+ * Event-time validity end (Unix ms): when the fact ceased to be true.
379
+ * `null`/undefined = open-ended (still true). Supersession stamps this
380
+ * instead of deleting the row, preserving add-only history for as-of
381
+ * (time-travel) reads.
382
+ */
383
+ validTo?: number | null;
384
+ }
385
+ /**
386
+ * Input for creating a new edge.
387
+ */
388
+ export interface CreateEdgeInput {
389
+ sourceId: string;
390
+ targetId: string;
391
+ relation?: EdgeRelation;
392
+ weight?: number;
393
+ metadata?: Record<string, unknown>;
394
+ /**
395
+ * Event-time validity start (Unix ms): when the fact became true in the
396
+ * world. `null`/undefined = open-ended.
397
+ */
398
+ validFrom?: number | null;
399
+ /**
400
+ * Event-time validity end (Unix ms): when the fact ceased to be true.
401
+ * `null`/undefined = open-ended.
402
+ */
403
+ validTo?: number | null;
404
+ }
405
+ /**
406
+ * Filter criteria for searching memories.
407
+ */
408
+ export interface SearchFilter {
409
+ /** Full-text search query. */
410
+ query?: string;
411
+ /** Filter by memory type. */
412
+ type?: MemoryType;
413
+ /** Minimum importance threshold [0, 1]. */
414
+ minImportance?: number;
415
+ /** Maximum importance threshold [0, 1]. */
416
+ maxImportance?: number;
417
+ /** Metadata key-value filter. */
418
+ metadata?: Record<string, unknown>;
419
+ /** Limit the number of results. */
420
+ limit?: number;
421
+ /** Offset for pagination. */
422
+ offset?: number;
423
+ /** Sort field. */
424
+ sortBy?: "importance" | "createdAt" | "updatedAt" | "accessCount" | "relevance" | "trustScore";
425
+ /** Sort direction. */
426
+ sortOrder?: "asc" | "desc";
427
+ /** Filter by tags (AND logic — node must have ALL specified tags). */
428
+ tags?: string[];
429
+ /** Filter by namespace. */
430
+ namespace?: string;
431
+ /**
432
+ * Filter by an explicit list of namespaces (OR logic). Composes with
433
+ * `namespace` / `namespacePrefix` (OR'd together) when several are set.
434
+ * Useful for multi-scope reads, e.g. `["project:alpha", "project:beta"]`.
435
+ */
436
+ namespaces?: string[];
437
+ /**
438
+ * Scoped-space union (company-brain container semantics): when any
439
+ * namespace constraint is present (`namespace`, `namespaces`, or
440
+ * `namespacePrefix`), also include the shared `default` namespace in
441
+ * the result set. `MemOS.search` enables this by default for
442
+ * scope-filtered searches; pass `false` explicitly for the legacy
443
+ * exclusive behavior. Unscoped searches are unaffected.
444
+ */
445
+ includeSharedScope?: boolean;
446
+ /**
447
+ * Typed multi-scope filter. Composed into a namespace prefix; with the
448
+ * default `"hierarchical"` match, `{ user: "alice" }` surfaces every
449
+ * memory stored under Alice's agents and runs. Set
450
+ * `scopeMatch: "exact"` to require the identical namespace string.
451
+ */
452
+ scope?: MemoryScope;
453
+ /** How `scope` matches stored namespaces. Default `"hierarchical"`. */
454
+ scopeMatch?: "exact" | "hierarchical";
455
+ /** Internal: pre-composed LIKE prefix for namespace matching. */
456
+ namespacePrefix?: string;
457
+ /**
458
+ * Filter by retrieval pool. Pass a single pool or a list (OR logic).
459
+ * Memories written before pools existed read as `"event"`.
460
+ */
461
+ pool?: MemoryPool | MemoryPool[];
462
+ /**
463
+ * Filter by authoring harness. Pass a harness slug stamped at write
464
+ * time (`"claude-code"`, `"cline"`, …) or `"all"` (default) for the
465
+ * behavior-preserving cross-harness recall. `"unknown"` matches
466
+ * unattributed rows, including everything written before harness
467
+ * attribution existed.
468
+ */
469
+ harness?: string;
470
+ /** Filter by provenance source. */
471
+ source?: MemorySource;
472
+ /** Filter by provenance tier. */
473
+ provenance?: ProvenanceTier;
474
+ /** Minimum trust score [0, 1]. */
475
+ minTrustScore?: number;
476
+ /**
477
+ * Quarantine visibility. Quarantined memories are excluded from
478
+ * recall by default (`includeQuarantined` unset or false) — the
479
+ * write-gate guarantee. Pass `true` to include them (review flows);
480
+ * `quarantinedOnly: true` returns only quarantined rows (equivalent
481
+ * to `memos quarantine list`).
482
+ */
483
+ includeQuarantined?: boolean;
484
+ /** When true, return only quarantined memories (the review queue). */
485
+ quarantinedOnly?: boolean;
486
+ /**
487
+ * When true (default), exclude memories whose `validTo` is in the
488
+ * past (i.e. historical/superseded memories). Set to false to
489
+ * include historical memories.
490
+ */
491
+ includeHistorical?: boolean;
492
+ /**
493
+ * FTS term-join operator for the keyword leg.
494
+ *
495
+ * - `"AUTO"` (default): run the precision `AND` query first; when it
496
+ * matches nothing, relax to an `OR` query so partial-term matches
497
+ * still surface. Precise, and the historical default.
498
+ * - `"AND"`: every query term must appear (forced precision).
499
+ * - `"OR"`: any term may appear (forced recall — useful for
500
+ * multi-evidence retrieval where relevant facts rarely share every
501
+ * query term; noisier for single-fact queries).
502
+ */
503
+ ftsOperator?: "AUTO" | "AND" | "OR";
504
+ /**
505
+ * When true, expand the top base results with their "session siblings" —
506
+ * other memories sharing the same `sessionId` (or `instanceId`) metadata
507
+ * value. Multi-hop / multi-evidence answers typically live across many turns
508
+ * of one conversation, so once a single relevant turn is retrieved, pulling
509
+ * its conversation neighbours into the ranking materially raises All-Evidence
510
+ * Recall. Deterministic, model-free, and ON by default (override with
511
+ * `config.experimental.sessionExpansion`); injected siblings are ranked
512
+ * behind every organically-retrieved result, so head ordering never moves
513
+ * and only the empty tail is filled.
514
+ */
515
+ sessionExpansion?: boolean;
516
+ /** Timestamp filter (Unix ms): only return memories valid at this time. */
517
+ validAt?: number;
518
+ /**
519
+ * How many candidates each hybrid-search leg fetches before fusion.
520
+ * Overrides the default `max(limit * 4, 20)`. Higher values widen the
521
+ * recall pool (useful when a reranker or expansion stage narrows
522
+ * afterwards) at linear scan cost.
523
+ */
524
+ candidateDepth?: number;
525
+ /**
526
+ * Drop results whose stored embedding is a near-duplicate (cosine >=
527
+ * `experimental.searchDedupThreshold`, default 0.95) of an
528
+ * already-selected result. Near-duplicates waste top-K slots that
529
+ * distinct evidence needs — multi-evidence questions score one node per
530
+ * duplicate otherwise. Off by default.
531
+ */
532
+ semanticDedup?: boolean;
533
+ /**
534
+ * Per-query override for the PPR-lite graph expansion
535
+ * (`config.fusion.graphExpansion`). `true` forces expansion on for this
536
+ * query, `false` disables it (byte-identical to the pre-expansion
537
+ * pipeline); `undefined` falls back to the fusion-config default (off).
538
+ * `contextPack`
539
+ * forwards its own `graphExpansion: false` through this flag.
540
+ */
541
+ graphExpansion?: boolean;
542
+ }
543
+ /**
544
+ * Options for `MemOS.semanticSearch()`. Accepts every `SearchFilter` field
545
+ * (namespace, tags, type, limit, …) plus the semantic similarity cutoff.
546
+ */
547
+ export interface SemanticSearchOptions extends SearchFilter {
548
+ /** Minimum similarity score in [0, 1]. Default 0.1. */
549
+ threshold?: number;
550
+ }
551
+ /**
552
+ * AI Trio context pack — a token-budgeted, ranked, namespace-filtered
553
+ * slice of memory intended to be folded into an LLM prompt by Guardian.
554
+ *
555
+ * See `docs/ai-trio-contracts.md` for the full contract.
556
+ */
557
+ export interface ContextPackItem {
558
+ id: string;
559
+ content: string;
560
+ summary: string;
561
+ score: number;
562
+ scores?: {
563
+ keyword?: number;
564
+ semantic?: number;
565
+ hybrid?: number;
566
+ };
567
+ trust: string;
568
+ source: string;
569
+ /**
570
+ * Provenance tier of the item's channel (see `ProvenanceTier`).
571
+ * Present on packs built after the provenance-trust layer.
572
+ */
573
+ provenance?: string;
574
+ /**
575
+ * True when the item comes from a low-trust channel (`imported` /
576
+ * `tool-output` tier, or quarantined-then-released): confirm before
577
+ * acting on it.
578
+ */
579
+ untrustedSource?: boolean;
580
+ tags: string[];
581
+ updatedAt: string;
582
+ }
583
+ export interface ContextPack {
584
+ schema: "ai-trio.memos.context-pack.v1";
585
+ query: string;
586
+ namespace: string;
587
+ tokenBudget: number;
588
+ items: ContextPackItem[];
589
+ }
590
+ /**
591
+ * A memory node bundled with its relevance score after a search.
592
+ */
593
+ export interface ScoredMemory {
594
+ node: MemoryNode;
595
+ /** Relevance score returned by the search algorithm. */
596
+ score: number;
597
+ /**
598
+ * Provenance tier of the result's channel (see `ProvenanceTier`).
599
+ * Stamped by `decorateTrustFlags` for agent-facing result sets.
600
+ */
601
+ provenance?: ProvenanceTier;
602
+ /**
603
+ * Citable `[mem:hex]` token tracing the memory to its source episode
604
+ * (see `src/citations.ts`). Stamped by `decorateTrustFlags`.
605
+ */
606
+ citation?: string;
607
+ /**
608
+ * True when the memory comes from a low-trust channel (`imported` /
609
+ * `tool-output` tier, or quarantined-then-released): the host agent
610
+ * should confirm it instead of silently injecting it as context.
611
+ * Stamped by `decorateTrustFlags`.
612
+ */
613
+ untrustedSource?: boolean;
614
+ /** Optional score breakdown for hybrid retrieval. `graph` marks a
615
+ * node injected by the graph-expansion leg, `ppr` the normalized
616
+ * personalized-PageRank score from the PPR-lite expansion blend,
617
+ * `session` one pulled in
618
+ * by session-sibling expansion, `rerank` the cross-encoder score
619
+ * (squashed to [0,1]) from the two-stage reranking pass, `entity` the
620
+ * query-entity overlap (in [0,1]) that earned the entity-fusion boost,
621
+ * and `entityLeg` the matched-entity count from the entity-inverted-index
622
+ * RRF leg (recall signal, distinct from the `entity` scoring boost),
623
+ * and `provenance` the per-tier trust multiplier from the
624
+ * provenance-trust layer.
625
+ *
626
+ * `semantic` vs `semanticRaw`: `semantic` is the leg's MIN-MAX
627
+ * NORMALIZED contribution used for fusion — its top candidate is
628
+ * always exactly `1`, so it is a fusion weight and never an absolute
629
+ * similarity. `semanticRaw` carries the raw embedding cosine on the
630
+ * embedder's own scale, which is the only form that can be compared
631
+ * against an absolute floor such as the abstention threshold in
632
+ * `shouldAbstain`. Consumers fall back to `semantic` when
633
+ * `semanticRaw` is absent (hand-built results, custom fusion paths).
634
+ */
635
+ scores?: {
636
+ keyword?: number;
637
+ /** Normalized semantic-leg contribution (fusion weight, 0..1). */
638
+ semantic?: number;
639
+ /** Raw embedding cosine (absolute similarity, embedder scale). */
640
+ semanticRaw?: number;
641
+ hybrid?: number;
642
+ graph?: number;
643
+ ppr?: number;
644
+ session?: number;
645
+ rerank?: number;
646
+ entity?: number;
647
+ /**
648
+ * Present when read-time contradiction resolution demoted this
649
+ * result: the demotion factor applied (see
650
+ * CONTRADICTION_DEMOTION_FACTOR in src/contradictions.ts).
651
+ */
652
+ contradiction_demoted?: number;
653
+ entityLeg?: number;
654
+ /**
655
+ * Raw CLIP cosine from the image-memory leg (`image_embeddings`,
656
+ * scanned by `querySimilarImages`). Present only when Track B is
657
+ * enabled and the leg actually retrieved this candidate — an absent
658
+ * value means the image leg did not surface it, exactly like
659
+ * `entityLeg`.
660
+ */
661
+ imageLeg?: number;
662
+ /**
663
+ * Present when provenance-trust weighting ran: the per-tier trust
664
+ * multiplier applied (`1 - strength * (1 - tierTrust)` — see
665
+ * `provenanceMultiplier` in src/provenance.ts).
666
+ */
667
+ provenance?: number;
668
+ /**
669
+ * Present when retrieval-time anomaly scoring ran: the demotion
670
+ * factor applied because the memory's write-time attack-shape
671
+ * similarity was high while the query was not attack-shaped (see
672
+ * `applyRetrievalAnomalyScoring` in src/memory.ts).
673
+ */
674
+ retrievalAnomaly?: number;
675
+ };
676
+ /**
677
+ * Relevance-gate outcome (see `RelevanceGateConfig` /
678
+ * `applyRelevanceGate`). Present on every result only when the gate is
679
+ * enabled (`retrieval.relevanceGate.enabled`, or `MEMOS_RELEVANCE_GATE=1`)
680
+ * — an absent field means the gate never ran, so the list is exactly
681
+ * what the pre-gate pipeline produced.
682
+ *
683
+ * `abstained` is `false` on every kept result: abstention empties the
684
+ * result list rather than marking survivors.
685
+ */
686
+ relevanceGate?: RelevanceGateResult;
687
+ }
688
+ /**
689
+ * Lifecycle status of a recorded contradiction pair.
690
+ *
691
+ * - `unresolved`: detected at write time by the rule-based detector;
692
+ * both versions are kept (add-only). Read-time resolution demotes the
693
+ * older member. Sleep-time LLM adjudication (future) may resolve it.
694
+ * - `resolved`: a contradiction outcome was confirmed through the
695
+ * evidence state machine (e.g. an old memory superseded by a new
696
+ * version) — the pair is recorded for provenance.
697
+ */
698
+ export type ContradictionStatus = "unresolved" | "resolved";
699
+ /**
700
+ * A recorded contradiction pair: two memory nodes about the same
701
+ * subject that disagree. Node ids are stored in canonical (sorted)
702
+ * order so the UNIQUE(node_a, node_b) constraint dedups pairs
703
+ * regardless of insertion order.
704
+ */
705
+ export interface ContradictionRecord {
706
+ id: string;
707
+ nodeA: string;
708
+ nodeB: string;
709
+ detectedAt: number;
710
+ status: ContradictionStatus;
711
+ }
712
+ /** How to address the memory a revert applies to. */
713
+ export type RevertScopeInput = {
714
+ kind: "last";
715
+ } | {
716
+ kind: "id";
717
+ id: string;
718
+ } | {
719
+ kind: "entity";
720
+ entity: string;
721
+ } | {
722
+ kind: "text";
723
+ text: string;
724
+ };
725
+ /**
726
+ * Options for {@link MemOS.revert}.
727
+ */
728
+ export interface RevertOptions {
729
+ /** Who issued the revert (free text, e.g. "user", "agent:coder"). Default "user". */
730
+ actor?: string;
731
+ /** Why the revert was issued — recorded on the audit event. */
732
+ reason?: string;
733
+ /** If true, resolve and report the target without writing anything. Default false. */
734
+ dryRun?: boolean;
735
+ /** Namespace to resolve "last"/named scopes in. Default "default". */
736
+ namespace?: string;
737
+ }
738
+ /**
739
+ * The resolved target of a revert command, plus the other candidates
740
+ * that matched (empty when the scope was unambiguous). When several
741
+ * memories match a named target, the most recently created valid memory
742
+ * wins and the rest are reported here for confirmation.
743
+ */
744
+ export interface RevertTargetResolution {
745
+ /** The memory that would be (or was) reverted. */
746
+ target: MemoryNode;
747
+ /** The scope that produced this target. */
748
+ scope: RevertScopeInput;
749
+ /** Other memories that matched the scope (most recent first). */
750
+ alternatives: ScoredMemory[];
751
+ }
752
+ /**
753
+ * The outcome of {@link MemOS.revert}.
754
+ *
755
+ * Ledger mechanics: the target's validity interval is closed at `at`
756
+ * (add-only — the row stays in history), the predecessor's interval is
757
+ * reopened (`validTo = null`), and the revert itself is recorded as an
758
+ * audit event node (tags `audit`/`revert`, metadata.audit === "revert").
759
+ */
760
+ export interface RevertResult {
761
+ /** The reverted-away memory — now historical (validTo = at). */
762
+ target: MemoryNode;
763
+ /** The reactivated predecessor — the belief recall returns now. */
764
+ predecessor: MemoryNode;
765
+ /** ID of the audit event node, or null on dry-run. */
766
+ auditId: string | null;
767
+ /** Unix ms when the revert executed (0 on dry-run). */
768
+ at: number;
769
+ /** True when nothing was written. */
770
+ dryRun: boolean;
771
+ /** Other candidates that matched the scope. */
772
+ alternatives: ScoredMemory[];
773
+ }
774
+ /** Outcome feedback for a procedural lesson. */
775
+ export type LessonOutcome = "success" | "failure";
776
+ /**
777
+ * A procedural lesson: behavioral guidance ("check rate limits before
778
+ * batch calls") rather than a fact. Captured via `memorizeProcedural`,
779
+ * reinforced/demoted by `recordLessonOutcome`, and surfaced via
780
+ * `recallProcedural` / context-pack injection. Scoring is pure local
781
+ * math — see `src/procedural.ts`.
782
+ */
783
+ export interface ProceduralLesson {
784
+ id: string;
785
+ /** The lesson text — an instruction for future behavior. */
786
+ lesson: string;
787
+ /** When/where the lesson applies (free text). */
788
+ context: string;
789
+ tags: string[];
790
+ /** Stored score in [0.01, 0.99]; read-time decay is applied lazily. */
791
+ score: number;
792
+ successCount: number;
793
+ failureCount: number;
794
+ useCount: number;
795
+ namespace: string;
796
+ createdAt: number;
797
+ updatedAt: number;
798
+ lastUsedAt: number;
799
+ }
800
+ /** Input for creating a procedural lesson (id/timestamps assigned). */
801
+ export interface NewProceduralLesson {
802
+ lesson: string;
803
+ context?: string;
804
+ tags?: string[];
805
+ namespace?: string;
806
+ /** Override the neutral 0.5 prior. Clamped to [0.01, 0.99]. */
807
+ initialScore?: number;
808
+ }
809
+ export type EmbeddingVector = number[];
810
+ /**
811
+ * Runtime resolution metadata for an embedding provider instance.
812
+ *
813
+ * Benchmarks (and any caller who cares about reproducibility) use this to
814
+ * verify that the provider they REQUESTED is the provider that actually
815
+ * loaded — in particular to detect the FastEmbed local-hash fallback that
816
+ * activates when the transformers package is missing.
817
+ */
818
+ export interface EmbeddingRuntimeInfo {
819
+ /** Provider kind the caller asked for, e.g. "fastembed". */
820
+ requestedProvider: string;
821
+ /** Provider actually serving embeddings, e.g. "fastembed" or
822
+ * "local-hash-fallback". Equal to `requestedProvider` when no fallback. */
823
+ resolvedProvider: string;
824
+ /** Model the caller asked for. */
825
+ requestedModel: string;
826
+ /** Model actually producing vectors. */
827
+ resolvedModel: string;
828
+ /** Model revision/commit when the provider exposes one, else null. */
829
+ modelRevision: string | null;
830
+ /** Dimensions the caller declared. */
831
+ requestedDimensions: number;
832
+ /** Dimensions observed on the most recent embed call, or null before
833
+ * the first call. Differs from `requestedDimensions` only when the
834
+ * provider's real output shape disagrees with configuration. */
835
+ observedDimensions: number | null;
836
+ /** True when the requested backend did NOT load and a fallback is
837
+ * serving embeddings instead. Only meaningful after the first embed
838
+ * call (or an explicit probe) has run. */
839
+ fallbackActive: boolean;
840
+ /** Human-readable reason for the fallback, or null when none occurred. */
841
+ fallbackReason: string | null;
842
+ }
843
+ export interface EmbeddingProvider {
844
+ /** Stable provider identifier, e.g. "local-hash" or "ollama". */
845
+ id: string;
846
+ /** Human-readable embedding model name. */
847
+ model: string;
848
+ /** Expected vector dimensionality. */
849
+ dimensions: number;
850
+ /**
851
+ * Runtime resolution metadata (requested vs. resolved provider/model,
852
+ * fallback status). Optional so custom providers need not implement it;
853
+ * when absent, callers should assume the provider IS what it claims and
854
+ * there is no fallback. The built-in FastEmbed provider implements it to
855
+ * expose the local-hash fallback state.
856
+ */
857
+ getRuntimeInfo?(): EmbeddingRuntimeInfo;
858
+ /** Generate a normalized embedding vector for a text input. */
859
+ embed(text: string): Promise<EmbeddingVector>;
860
+ /**
861
+ * Optional batch embedding. If the provider can batch, override this to
862
+ * amortize network round-trips. Default implementation calls `embed` for
863
+ * each text in order. The returned vectors must be in the same order as
864
+ * the input `texts` array.
865
+ */
866
+ batchEmbed?(texts: string[]): Promise<EmbeddingVector[]>;
867
+ /**
868
+ * Embed a QUERY — a short natural-language retrieval question.
869
+ *
870
+ * Many modern retrieval models (e.g. the Liquid E / e5 families, and
871
+ * Cohere embed-v3) are trained for an asymmetric query/document setting:
872
+ * they expect an instruction or "query" prefix on the query side and plain
873
+ * text on the document side. Routing queries through a dedicated method lets
874
+ * providers apply that signal, which materially improves semantic recall for
875
+ * paraphrase questions.
876
+ *
877
+ * Optional for backward compatibility: when a provider does not implement it,
878
+ * `embedQuery`/`embedDocuments` default to the plain `embed` path so
879
+ * existing custom providers keep working unchanged.
880
+ */
881
+ embedQuery?(text: string): Promise<EmbeddingVector>;
882
+ /**
883
+ * Embed a batch of DOCUMENTS (the persisted memory contents) for indexing.
884
+ *
885
+ * Optional; defaults to `batchEmbed`, falling back to per-text `embed`.
886
+ * Providers that distinguish query from document mode should use the document
887
+ * input type here (e.g. Cohere `search_document`).
888
+ */
889
+ embedDocuments?(texts: string[]): Promise<EmbeddingVector[]>;
890
+ /**
891
+ * Optional image encoder. Text and CLIP vectors live in different
892
+ * vector spaces (and different tables), so this is an OPTIONAL extra
893
+ * capability, never the provider's primary contract — a text provider
894
+ * that also encodes images can satisfy both interfaces, and the
895
+ * image-embedding path must never be handed to the text embedding
896
+ * queue. See {@link EmbedImageProvider} for the dedicated contract.
897
+ */
898
+ embedImage?(image: Buffer | string): Promise<EmbeddingVector>;
899
+ }
900
+ export type EmbeddingProviderKind = "local-hash" | "ollama" | "openai-compatible" | "voyage" | "cohere" | "fastembed";
901
+ export interface EmbeddingConfig {
902
+ /** Enables embedding generation. Defaults to true when semantic search is enabled. */
903
+ enabled?: boolean;
904
+ /** Built-in provider kind, or a custom provider implementation. */
905
+ provider?: EmbeddingProviderKind | EmbeddingProvider;
906
+ /** Provider model name. */
907
+ model?: string;
908
+ /** Embedding vector dimensions. */
909
+ dimensions?: number;
910
+ /** Base URL for Ollama or OpenAI-compatible embedding endpoints. */
911
+ baseUrl?: string;
912
+ /** API key for OpenAI-compatible embedding endpoints. */
913
+ apiKey?: string;
914
+ /**
915
+ * Prefix prepended to QUERY text before embedding. Asymmetric retrieval
916
+ * models are trained with a query-side instruction and silently degrade
917
+ * without it — e.g. Liquid LFM2.5-Embedding and e5 models expect
918
+ * `"query: "`. Empty (default) sends queries as-is.
919
+ */
920
+ queryPrefix?: string;
921
+ /**
922
+ * Prefix prepended to DOCUMENT text (stored memory content) before
923
+ * embedding at index time. e.g. Liquid LFM2.5-Embedding and e5 models
924
+ * expect `"document: "`. Empty (default) sends documents as-is.
925
+ */
926
+ documentPrefix?: string;
927
+ /**
928
+ * Which node text to embed at store time: the raw `content`, or
929
+ * `summary + "\n" + content` (the historical default — for short facts
930
+ * the extractive summary roughly doubles the embedded tokens).
931
+ */
932
+ embedText?: "content" | "summary+content";
933
+ }
934
+ export interface EmbeddingRecordInfo {
935
+ model: string;
936
+ dimensions: number;
937
+ updatedAt: number;
938
+ }
939
+ /**
940
+ * Per-node embedding pipeline status. `pending` means the node has been
941
+ * stored but its embedding has not been computed yet. `ready` means the
942
+ * persisted vector is fresh for the current provider/model. `failed`
943
+ * means the most recent attempt gave up after retries.
944
+ */
945
+ export type EmbeddingNodeStatus = "pending" | "queued" | "running" | "ready" | "failed";
946
+ /** Lightweight status snapshot returned by `memos.embeddingStatus()`. */
947
+ export interface EmbeddingNodeStatusInfo {
948
+ nodeId: string;
949
+ status: EmbeddingNodeStatus;
950
+ attempts: number;
951
+ lastError: string | null;
952
+ updatedAt: number;
953
+ }
954
+ /** Aggregate status returned by `memos.embeddingStatus()` (no args). */
955
+ export interface EmbeddingQueueStatus {
956
+ pending: number;
957
+ running: number;
958
+ total: number;
959
+ nodes: EmbeddingNodeStatusInfo[];
960
+ }
961
+ /**
962
+ * Configuration for the background embedding queue. All fields are
963
+ * optional; sensible defaults are used when omitted.
964
+ */
965
+ export interface EmbeddingQueueConfig {
966
+ /** Max concurrent in-flight embed calls. Default 2. */
967
+ concurrency?: number;
968
+ /**
969
+ * Max pending jobs drained into a single `batchEmbed()` call when the
970
+ * provider supports batching (array-input HTTP endpoints). Default 1 =
971
+ * one `embed()` call per job. Groups that fail fall back to per-job
972
+ * retries.
973
+ */
974
+ batchSize?: number;
975
+ /** Max buffered jobs before `enqueue` throws. Default 10000. */
976
+ maxQueueSize?: number;
977
+ /** Max retry attempts per job before marking it failed. Default 3. */
978
+ maxRetries?: number;
979
+ /** Base backoff in ms; retries use exponential backoff. Default 250. */
980
+ retryBackoffMs?: number;
981
+ /**
982
+ * Coalescing delay in ms before a fully-idle queue picks up
983
+ * newly-enqueued work. Default 5. Lets rapid sequential `store()` calls
984
+ * form full `batchSize` groups instead of one single-job group each.
985
+ * Set to 0 for immediate microtask pickup.
986
+ */
987
+ batchLingerMs?: number;
988
+ /**
989
+ * If true, `store()` waits for the embedding to complete before
990
+ * returning. Default false — background mode. Tests and the CLI
991
+ * `memos flush-embeddings` command benefit from this being false.
992
+ */
993
+ synchronous?: boolean;
994
+ }
995
+ /**
996
+ * Full in-memory graph snapshot.
997
+ */
998
+ export interface GraphSnapshot {
999
+ nodes: MemoryNode[];
1000
+ edges: MemoryEdge[];
1001
+ }
1002
+ /**
1003
+ * Mutation recorded in the tamper-evident log.
1004
+ *
1005
+ * - `store` — new memory written via `MemOS.store()` (including event-update
1006
+ * replacements and revert audit entries).
1007
+ * - `import` — record imported with its original identity (`importRecord`,
1008
+ * e.g. encrypted sync restore).
1009
+ * - `update` — node mutated via `updateNode` (content, tags, metadata,
1010
+ * validity, provenance…), TTL changes, and `setValidity`.
1011
+ * - `forget` — node deleted via `MemOS.forget()`.
1012
+ */
1013
+ export type TamperOp = "store" | "import" | "update" | "forget";
1014
+ /**
1015
+ * One entry of the tamper-evident mutation log.
1016
+ *
1017
+ * Entries form a hash chain: `entryHash = sha256("memos-tamper-entry-v2"|
1018
+ * seq|ts|op|nodeId|nodeHash|prevHash)` where `prevHash` is the previous
1019
+ * entry's `entryHash` (or a fixed genesis constant for seq 1) and `seq`
1020
+ * is the entry's 1-based chain position, assigned atomically by the
1021
+ * storage adapter. `nodeHash` is `sha256` over a canonical serialization
1022
+ * of the node's full mutable state at mutation time (content, summary,
1023
+ * type, tags, importance, namespace, metadata, provenance, validity,
1024
+ * TTL, timestamps — everything except volatile read stats) — for
1025
+ * `forget` it is the hash of the deleted node's final state, so
1026
+ * deletions are provable too.
1027
+ */
1028
+ export interface TamperLogEntry {
1029
+ seq: number;
1030
+ ts: number;
1031
+ op: TamperOp;
1032
+ nodeId: string;
1033
+ nodeHash: string;
1034
+ prevHash: string;
1035
+ entryHash: string;
1036
+ }
1037
+ /**
1038
+ * A tamper-log entry as supplied by the caller. The storage adapter
1039
+ * assigns the chain position atomically: it determines `prevHash` from
1040
+ * the current tip, allocates `seq`, and computes `entryHash` — all in
1041
+ * one transaction — then returns the complete stored entry.
1042
+ */
1043
+ export type NewTamperLogEntry = Pick<TamperLogEntry, "ts" | "op" | "nodeId" | "nodeHash">;
1044
+ /**
1045
+ * Backend-agnostic storage contract.
1046
+ *
1047
+ * Any persistence backend (SQLite, Postgres, Redis, Qdrant …) must
1048
+ * implement this interface. The core engine only depends on this
1049
+ * contract, never on a concrete backend.
1050
+ */
1051
+ export interface StorageAdapter {
1052
+ /** Initialise tables / indices / connections. Called once at startup. */
1053
+ init(): Promise<void>;
1054
+ /** Persist a new memory node. Returns the created node. */
1055
+ saveNode(node: MemoryNode): Promise<MemoryNode>;
1056
+ /** Retrieve a node by ID. Returns `null` when not found.
1057
+ * Implementations should bump the access stats (access_count,
1058
+ * last_accessed) on read. For side-effect-free reads, use `peekNode`. */
1059
+ getNode(id: string): Promise<MemoryNode | null>;
1060
+ /**
1061
+ * Side-effect-free variant of `getNode`. Does not increment
1062
+ * `access_count` or update `last_accessed`. Use for internal lookups
1063
+ * where the read is not a user-initiated retrieval — e.g. tag
1064
+ * updates, TTL changes, eviction candidate selection.
1065
+ */
1066
+ peekNode?(id: string): Promise<MemoryNode | null>;
1067
+ /**
1068
+ * Delete the single least-important node, where "least important" is
1069
+ * defined as lowest `importance` then oldest `last_accessed`.
1070
+ * Returns the id of the deleted node, or null if the table is empty.
1071
+ * Implementations may fall back to in-memory selection if SQL is
1072
+ * not appropriate.
1073
+ */
1074
+ evictLeastImportant?(): Promise<string | null>;
1075
+ /** Partially update a node. Returns the updated node. */
1076
+ updateNode(id: string, input: UpdateMemoryInput): Promise<MemoryNode | null>;
1077
+ /** Delete a node and all connected edges. */
1078
+ deleteNode(id: string): Promise<boolean>;
1079
+ /**
1080
+ * Record one read access for a node: bumps `access_count` and
1081
+ * `last_accessed` ONLY. Must not touch `updatedAt` or any content —
1082
+ * a read is not a write, and mutating `updatedAt` on read would
1083
+ * corrupt recency ordering, sync conflict resolution, embedding
1084
+ * freshness, and the tamper-evident log's content cross-check.
1085
+ *
1086
+ * Optional: adapters that don't implement it skip read telemetry
1087
+ * (fail-open). Never route read telemetry through `updateNode` —
1088
+ * see `bumpAccessCounters` in `src/memory.ts`.
1089
+ */
1090
+ recordAccess?(id: string): void | Promise<void>;
1091
+ /**
1092
+ * Append one entry to the tamper-evident mutation log. The adapter
1093
+ * MUST assign the chain position atomically: determine `prevHash`
1094
+ * from the current tip, allocate `seq`, compute `entryHash`, and
1095
+ * insert — all in a single transaction — then return the complete
1096
+ * stored entry. Optional: adapters that don't implement the log
1097
+ * disable mutation logging (fail-open) and `verifyTamperLog`
1098
+ * reports the log as unsupported.
1099
+ */
1100
+ appendTamperEntry?(entry: NewTamperLogEntry): Promise<TamperLogEntry>;
1101
+ /** Read the full tamper-evident log in sequence order. */
1102
+ readTamperLog?(): Promise<TamperLogEntry[]>;
1103
+ /** Persist a new edge. Returns the created edge. */
1104
+ saveEdge(edge: MemoryEdge): Promise<MemoryEdge>;
1105
+ /**
1106
+ * Batch-insert multiple edges in a single transaction.
1107
+ * Falls back to individual saveEdge calls when not implemented.
1108
+ */
1109
+ saveEdgesBatch?(edges: MemoryEdge[]): Promise<MemoryEdge[]>;
1110
+ /** Retrieve an edge by ID. */
1111
+ getEdge(id: string): Promise<MemoryEdge | null>;
1112
+ /** Delete an edge by ID. */
1113
+ deleteEdge(id: string): Promise<boolean>;
1114
+ /**
1115
+ * Scoped-space inventory: every namespace with its live memory count.
1116
+ * Optional — adapters that cannot provide it fall back to a full scan.
1117
+ */
1118
+ listNamespaces?(): Promise<Array<{
1119
+ namespace: string;
1120
+ count: number;
1121
+ }>>;
1122
+ /**
1123
+ * Close (invalidate) the currently-valid edges incident to a node by
1124
+ * stamping `valid_to = validTo`. Rows are updated, never deleted, so
1125
+ * as-of reads at earlier timestamps still return them.
1126
+ * Returns the number of edges closed.
1127
+ */
1128
+ closeEdgesForNode?(nodeId: string, validTo: number): Promise<number>;
1129
+ /** Query nodes with filters. */
1130
+ queryNodes(filter: SearchFilter): Promise<ScoredMemory[]>;
1131
+ /**
1132
+ * Per-harness memory counts (`SELECT harness, COUNT(*) … GROUP BY
1133
+ * harness`). Optional — `MemOS.getHarnessCounts()` falls back to a
1134
+ * paged `queryNodes` scan when the adapter does not implement it.
1135
+ */
1136
+ getHarnessCounts?(): Promise<HarnessCount[]>;
1137
+ /** Persist an embedding vector for a node. */
1138
+ saveEmbedding?(nodeId: string, vector: EmbeddingVector, model: string): Promise<void>;
1139
+ /** Return stored embedding metadata for startup backfill decisions. */
1140
+ getEmbeddingInfo?(nodeId: string): Promise<EmbeddingRecordInfo | null>;
1141
+ /**
1142
+ * Return stored embedding metadata for every node in one round trip.
1143
+ * Optional bulk counterpart to `getEmbeddingInfo` — lets startup
1144
+ * backfill avoid one SELECT per node. Storages that don't implement it
1145
+ * fall back to per-node `getEmbeddingInfo` calls.
1146
+ */
1147
+ getAllEmbeddingInfos?(): Promise<Array<{
1148
+ nodeId: string;
1149
+ } & EmbeddingRecordInfo>>;
1150
+ /** Query nodes by vector similarity. */
1151
+ querySimilarEmbeddings?(vector: EmbeddingVector, filter: SearchFilter, limit: number, threshold?: number,
1152
+ /**
1153
+ * When provided, only rows stored by this exact model are compared.
1154
+ * Cosine similarity is meaningless across models, and two different
1155
+ * models can share a dimensionality — dimension equality alone does
1156
+ * not prevent silently mixing incompatible vectors.
1157
+ */
1158
+ model?: string): Promise<ScoredMemory[]>;
1159
+ /** Counts of stored embeddings grouped by model (reindex/audit support). */
1160
+ getEmbeddingModelCounts?(): Promise<Array<{
1161
+ model: string;
1162
+ count: number;
1163
+ }>>;
1164
+ /**
1165
+ * Bulk-fetch stored embedding vectors for the given node ids.
1166
+ * Used by write-time contradiction detection to avoid one SELECT per
1167
+ * neighbor. Returns only ids that have a stored vector.
1168
+ */
1169
+ getEmbeddingVectors?(nodeIds: string[]): Promise<Map<string, EmbeddingVector>>;
1170
+ /** Delete all embedding rows stored by the given model. Returns the count. */
1171
+ deleteEmbeddingsByModel?(model: string): Promise<number>;
1172
+ /**
1173
+ * Persist a CLIP image vector for a node, in the SEPARATE
1174
+ * `image_embeddings` space. Never mixed with text `embeddings`:
1175
+ * cosine similarity across the two spaces is meaningless.
1176
+ */
1177
+ saveImageEmbedding?(nodeId: string, vector: EmbeddingVector, model: string): Promise<void>;
1178
+ /** Every stored image vector (node id + vector + model), for reindex/audit. */
1179
+ getAllImageEmbeddings?(): Promise<Array<{
1180
+ nodeId: string;
1181
+ vector: EmbeddingVector;
1182
+ model: string;
1183
+ }>>;
1184
+ /**
1185
+ * Query image memories by CLIP vector similarity. Behaves exactly like
1186
+ * `querySimilarEmbeddings`, except it scans `image_embeddings` and
1187
+ * filters on model + dimensions — a 768-d text vector must never be
1188
+ * scored against a 512-d CLIP query.
1189
+ */
1190
+ querySimilarImages?(vector: EmbeddingVector, filter: SearchFilter, limit: number, threshold?: number,
1191
+ /** Only rows stored by this exact CLIP model are compared. */
1192
+ model?: string): Promise<ScoredMemory[]>;
1193
+ /**
1194
+ * Image-embedding model counts, for `memos diagnostics` / reindex
1195
+ * support. Grouped by model like `getEmbeddingModelCounts`.
1196
+ */
1197
+ getImageEmbeddingModelCounts?(): Promise<Array<{
1198
+ model: string;
1199
+ count: number;
1200
+ }>>;
1201
+ /**
1202
+ * Delete the image-embedding row for a node (used by the node-delete
1203
+ * path alongside the blob unlink). Returns true when a row was removed.
1204
+ */
1205
+ deleteImageEmbedding?(nodeId: string): Promise<boolean>;
1206
+ /** Query edges, optionally filtered by source/target. */
1207
+ queryEdges(filter?: {
1208
+ sourceId?: string;
1209
+ targetId?: string;
1210
+ relation?: EdgeRelation;
1211
+ /**
1212
+ * Bitemporal as-of read: when provided, only edges whose event-time
1213
+ * validity interval covers this Unix-ms timestamp are returned
1214
+ * (NULL bounds are open-ended). Default returns all edges.
1215
+ */
1216
+ validAt?: number;
1217
+ }): Promise<MemoryEdge[]>;
1218
+ /**
1219
+ * Record a contradiction pair between two memory nodes. Node ids are
1220
+ * canonicalized (sorted) by the implementation so the UNIQUE constraint
1221
+ * dedups reversed pairs. Insert is idempotent (no-op when the pair is
1222
+ * already recorded).
1223
+ */
1224
+ addContradiction?(nodeA: string, nodeB: string, status?: ContradictionStatus): Promise<ContradictionRecord>;
1225
+ /**
1226
+ * Return recorded contradiction pairs where node_a OR node_b is in
1227
+ * `nodeIds` — the bounded read-time lookup for
1228
+ * `resolveContradictionsAtRead`.
1229
+ */
1230
+ getContradictionPairsFor?(nodeIds: string[]): Promise<ContradictionRecord[]>;
1231
+ /** Transition a contradiction record between `unresolved`/`resolved`. */
1232
+ updateContradictionStatus?(id: string, status: ContradictionStatus): Promise<void>;
1233
+ /**
1234
+ * Procedural lessons (optional — only SQLiteStorage implements these
1235
+ * today). `updateProceduralLesson` applies a partial patch (score,
1236
+ * counts, timestamps) and returns the updated record, or null when
1237
+ * the id is unknown.
1238
+ */
1239
+ saveProceduralLesson?(lesson: NewProceduralLesson): Promise<ProceduralLesson>;
1240
+ getProceduralLesson?(id: string): Promise<ProceduralLesson | null>;
1241
+ updateProceduralLesson?(id: string, patch: Partial<ProceduralLesson>): Promise<ProceduralLesson | null>;
1242
+ listProceduralLessons?(namespace?: string): Promise<ProceduralLesson[]>;
1243
+ /**
1244
+ * Find memory nodes whose id (dashes ignored) starts with `prefix`
1245
+ * (hex, case-insensitive). Backs citation resolution; capped by the
1246
+ * implementation to a bounded candidate list.
1247
+ */
1248
+ findNodesByIdPrefix?(prefix: string): Promise<MemoryNode[]>;
1249
+ /** Return the full graph (nodes + edges). */
1250
+ getGraph(): Promise<GraphSnapshot>;
1251
+ /**
1252
+ * Return the graph as of a bitemporal timestamp (unix ms): nodes and
1253
+ * edges whose validity interval covers `atTime`. Optional so
1254
+ * third-party adapters are not forced to implement history; callers
1255
+ * should fall back to filtering `getGraph()` with the same predicates.
1256
+ */
1257
+ getGraphAtTime?(atTime: number): Promise<GraphSnapshot>;
1258
+ /**
1259
+ * Return every persisted embedding (node id + vector + model). Used
1260
+ * by memory consolidation. Implementations may return an empty
1261
+ * array when embeddings are not stored.
1262
+ */
1263
+ getAllEmbeddings?(): Promise<Array<{
1264
+ nodeId: string;
1265
+ vector: EmbeddingVector;
1266
+ model: string;
1267
+ }>>;
1268
+ /**
1269
+ * Update only the `namespace` of a node. Used by `archive` to
1270
+ * move a memory to the `archived` namespace.
1271
+ */
1272
+ setNodeNamespace?(id: string, namespace: string): Promise<void>;
1273
+ /** Set TTL on a node. */
1274
+ setTTL(id: string, seconds: number): Promise<void>;
1275
+ /** Clear TTL on a node. */
1276
+ clearTTL(id: string): Promise<void>;
1277
+ /** Delete expired nodes and return the count of deleted nodes. */
1278
+ sweepExpired(): Promise<number>;
1279
+ /** Get all nodes with a specific tag. */
1280
+ queryNodesByTag(tag: string): Promise<MemoryNode[]>;
1281
+ /**
1282
+ * ── item2: entity leg ── candidate generation for hybrid search: node
1283
+ * ids whose indexed entities intersect `entities`, ranked by number of
1284
+ * matched entities (desc), node id tiebreak. Backed by the
1285
+ * `entity_index` inverted table in the SQLite storage. Optional —
1286
+ * storages without an entity index omit this and the entity RRF leg
1287
+ * degrades to no candidates.
1288
+ */
1289
+ searchByEntities?(entities: string[], limit: number): Promise<Array<{
1290
+ nodeId: string;
1291
+ matches: number;
1292
+ }>>;
1293
+ /** Delete all nodes and edges (batch operation). */
1294
+ deleteAllNodes(): Promise<void>;
1295
+ /** Close connections and release resources. */
1296
+ close(): Promise<void>;
1297
+ }
1298
+ /**
1299
+ * Experimental feature flags.
1300
+ */
1301
+ /**
1302
+ * Wire format a context pack will be serialized to. Used by the
1303
+ * budget-accounting path to charge each item what it actually costs on
1304
+ * the wire (TOON row scaffolding / JSON field names, citations)
1305
+ * instead of the legacy flat `content + summary + 4` estimate.
1306
+ *
1307
+ * See `wireFormat` on the context-pack options in
1308
+ * `src/context-pack.ts`.
1309
+ */
1310
+ export type ContextPackWireFormat = "json" | "toon" | "toon-compact";
1311
+ /**
1312
+ * Compression knobs for the context-pack budget path — the switch that
1313
+ * finally uses `compressText` from `src/compression.ts`.
1314
+ *
1315
+ * Compression is attempted ONLY for an item that does not fit the
1316
+ * pack's `tokenBudget`: the compressor runs over the item's
1317
+ * already-debloated content (and summary) and the item is admitted when
1318
+ * the compressed form fits. An item that still does not fit after
1319
+ * compression is skipped exactly as it is today, so enabling
1320
+ * compression can only ever ADD items to a pack, never remove them.
1321
+ *
1322
+ * Default `enabled: false`, deliberately: `compressText` is a lossy
1323
+ * stopword filter ("the deploy pipeline" → "deploy pipeline"), so the
1324
+ * default build keeps every content byte identical to the
1325
+ * pre-compression pack. Opt in when you want the extra recall and
1326
+ * accept terser evidence text.
1327
+ */
1328
+ export interface ContextPackCompressionOptions {
1329
+ /**
1330
+ * Try `compressText` on items that would otherwise be dropped for
1331
+ * not fitting the token budget. Default false — when false the
1332
+ * compressor is never invoked and no content is altered.
1333
+ */
1334
+ enabled?: boolean;
1335
+ /**
1336
+ * Compression aggressiveness. `"light"` drops articles, copulas and
1337
+ * common prepositions; `"aggressive"` additionally drops filler
1338
+ * adverbs and most pronouns (roughly 40-60% of prose tokens — read
1339
+ * the output before trusting it). Default `"light"`.
1340
+ */
1341
+ level?: CompressionLevel;
1342
+ }
1343
+ export interface ExperimentalConfig {
1344
+ /**
1345
+ * @deprecated No longer required — `semanticSearch()` works without it.
1346
+ * Kept as a shorthand for enabling embeddings with the default provider
1347
+ * (equivalent to `embeddings: { enabled: true }`).
1348
+ */
1349
+ semanticSearch?: boolean;
1350
+ /**
1351
+ * Context-pack budget compression. When `enabled`, items that do not
1352
+ * fit `contextPack({ tokenBudget })` are first re-rendered through
1353
+ * `compressText` (`src/compression.ts`) and admitted if the compressed
1354
+ * form fits; only items that are still too big are skipped.
1355
+ *
1356
+ * Default off: compression is lossy, so the default pack contents stay
1357
+ * byte-identical to the pre-compression build. Read the rationale in
1358
+ * `ContextPackCompressionOptions`.
1359
+ */
1360
+ packCompression?: ContextPackCompressionOptions;
1361
+ /** Enable graph visualization export. */
1362
+ graphViz?: boolean;
1363
+ /** Enable namespace isolation. */
1364
+ namespaces?: boolean;
1365
+ /** Enable context injection from graph neighbours. */
1366
+ contextInjection?: boolean;
1367
+ /**
1368
+ * Extract semantic (subject, predicate, object) triples at write time
1369
+ * and store them in node metadata. Enables triple-aware retrieval
1370
+ * boosting. Experimental, default off.
1371
+ */
1372
+ tripleExtraction?: boolean;
1373
+ /**
1374
+ * Apply Ebbinghaus forgetting-curve reinforcement to retrieval scoring.
1375
+ * Memories decay exponentially by time-since-access divided by access
1376
+ * count; frequently-recalled memories stay strong. Experimental,
1377
+ * default off.
1378
+ */
1379
+ ebbinghaus?: boolean;
1380
+ /**
1381
+ * Run the evidence state machine on every `store()`: similar existing
1382
+ * memories are reinforced, revised, or superseded, and near-duplicates
1383
+ * (similarity >= 0.92) are folded into the existing node instead of
1384
+ * being written again. Default: true.
1385
+ */
1386
+ evidenceOnStore?: boolean;
1387
+ /**
1388
+ * After a node's embedding is persisted, auto-link it to its top
1389
+ * embedding-similarity neighbours (cosine >= 0.6, max 8 edges) in
1390
+ * addition to the bag-of-words links. Only active when an embedding
1391
+ * provider is configured. Default: true.
1392
+ */
1393
+ embeddingAutoLink?: boolean;
1394
+ /**
1395
+ * Apply a gentle recency boost to hybrid search ranking. Off by
1396
+ * default: enabling it makes scores time-dependent, which relaxes the
1397
+ * score-reproducibility guarantee in `docs/ai-trio-contracts.md`.
1398
+ * Default: false.
1399
+ */
1400
+ recencyBoost?: boolean;
1401
+ /**
1402
+ * Graph-expansion recall leg for hybrid search. After fusion, the top
1403
+ * `maxSeeds` results are expanded along their graph edges and unseen
1404
+ * neighbours are injected into the ranking at `seedScore * scoreFactor`
1405
+ * (capped at `maxAdded` extra nodes). Useful for multi-evidence /
1406
+ * multi-hop queries where related facts are connected by
1407
+ * `relates_to`/`supports` edges but neither retrieval leg surfaces them.
1408
+ * Off by default.
1409
+ */
1410
+ graphExpansion?: {
1411
+ enabled?: boolean;
1412
+ /** How many top fused results to expand along edges. Default 3. */
1413
+ maxSeeds?: number;
1414
+ /** Maximum neighbours injected per query. Default 5. */
1415
+ maxAdded?: number;
1416
+ /** Injected neighbour score = seed score × this factor. Default 0.85. */
1417
+ scoreFactor?: number;
1418
+ };
1419
+ /**
1420
+ * Two-stage reranking: after fusion, the top `candidates` results are
1421
+ * re-scored by a cross-encoder and the final ranking is reordered by
1422
+ * relevance score. The first stage (hybrid search) exists to recall;
1423
+ * the reranker decides what the caller actually sees. Two providers:
1424
+ *
1425
+ * - `"endpoint"` (default when `endpoint` is set): re-scores via an HTTP
1426
+ * `/rerank` server (e.g. llama-server with bge-reranker-v2-m3).
1427
+ * - `"local"`: in-process cross-encoder through `@huggingface/transformers`
1428
+ * (default model `Xenova/bge-reranker-base`, ~280 MB, downloaded on
1429
+ * first use). No server needed; needs one of the transformers packages
1430
+ * installed.
1431
+ *
1432
+ * On reranker failure the fused order is kept unchanged (graceful
1433
+ * degradation). Off by default.
1434
+ */
1435
+ /**
1436
+ * Cosine threshold for the opt-in `filter.semanticDedup` in hybrid
1437
+ * search. Default 0.95 — near-verbatim duplicates only.
1438
+ */
1439
+ searchDedupThreshold?: number;
1440
+ /**
1441
+ * Round 4: RM3-lite pseudo-relevance feedback for hybrid search.
1442
+ * For short queries (≤3 content terms) whose primary keyword leg is
1443
+ * thin (<5 hits), harvest up to 3 expansion terms from the top-5
1444
+ * semantic hits and re-probe FTS5 as a second keyword pass. Union
1445
+ * semantics: expansion can only ADD candidates, never demote or
1446
+ * remove primary-leg results (expansion-only hits are demoted below
1447
+ * every primary hit, since expansion bm25 scores are not comparable
1448
+ * to primary-query bm25 scores).
1449
+ *
1450
+ * Off by default: PRF is a recall booster with query-drift risk —
1451
+ * enable it only after measuring a win on your eval (deterministic
1452
+ * eval was neutral: 0.9792/0.9688 with and without). `MEMOS_PRF=1`
1453
+ * forces it on for experiments without a config change.
1454
+ * Default: false.
1455
+ */
1456
+ prfExpansion?: boolean;
1457
+ rerank?: {
1458
+ /**
1459
+ * Rerank provider: `"endpoint"` (HTTP `/rerank` server) or `"local"`
1460
+ * (in-process cross-encoder). Default: `"endpoint"` when `endpoint` is
1461
+ * set, `"local"` when `localModel` is set. `MEMOS_RERANK_LOCAL=1`
1462
+ * forces the local provider for experiments without a config change.
1463
+ */
1464
+ provider?: "endpoint" | "local";
1465
+ /** Base URL of the rerank server, e.g. "http://127.0.0.1:8081".
1466
+ * Receives `POST {endpoint}/rerank` with
1467
+ * `{ model, query, documents: string[] }`. Required for the
1468
+ * `"endpoint"` provider; ignored for `"local"`. */
1469
+ endpoint?: string;
1470
+ /** Bearer token for the rerank endpoint, when required. */
1471
+ apiKey?: string;
1472
+ /** Model name sent to the endpoint (many local servers ignore it). */
1473
+ model?: string;
1474
+ /**
1475
+ * Local cross-encoder model id for `provider: "local"`.
1476
+ * Default `"Xenova/bge-reranker-base"`. Overridable for
1477
+ * experiments with `MEMOS_RERANK_MODEL`.
1478
+ */
1479
+ localModel?: string;
1480
+ /**
1481
+ * Weight dtype for the local model (`from_pretrained` dtype, e.g.
1482
+ * `"q8"`, `"fp32"`). Default `"q8"` — much faster on CPU with
1483
+ * negligible ranking impact. Overridable with `MEMOS_RERANK_DTYPE`.
1484
+ */
1485
+ localDtype?: string;
1486
+ /** How many fused candidates to submit for reranking. Default 50.
1487
+ * Overridable for experiments with `MEMOS_RERANK_CANDIDATES`. */
1488
+ candidates?: number;
1489
+ /**
1490
+ * Truncate each reranked document to this many characters before
1491
+ * sending. Cross-encoder relevance signal lives in the first few
1492
+ * hundred tokens, and capping pair length keeps the request's token
1493
+ * count predictable — long-tail documents otherwise force many extra
1494
+ * GPU waves on the rerank server. Default 0 = send full documents.
1495
+ */
1496
+ maxDocChars?: number;
1497
+ /** Request timeout in ms. Default 5000. */
1498
+ timeoutMs?: number;
1499
+ };
1500
+ /**
1501
+ * Session-neighbour expansion for hybrid search. After fusion, the top
1502
+ * `maxSeeds` results are expanded along their same-conversation
1503
+ * neighbours and unseen siblings are injected into the ranking at a
1504
+ * decaying `seed.score * scoreFactor^k`. Multi-hop answers typically
1505
+ * span many turns of one session, so recovering the neighbours of a
1506
+ * single relevant turn raises all-evidence recall without another
1507
+ * embedding pass. Default: true (injected siblings sit behind every
1508
+ * organically-retrieved result, so head ordering never moves).
1509
+ */
1510
+ sessionExpansion?: boolean;
1511
+ }
1512
+ /**
1513
+ * Relevance-gate knobs for hybrid search (see `applyRelevanceGate` and
1514
+ * `shouldAbstain` in `src/retrieval.ts`).
1515
+ *
1516
+ * Two independent problems, one knob each:
1517
+ *
1518
+ * - ABSTENTION. When nothing in the store is genuinely about the query,
1519
+ * the honest answer is "no memories" — not "the ten least-bad rows".
1520
+ * A memory layer that always returns k results forces the caller to
1521
+ * invent an answer.
1522
+ * - TAIL TRIMMING. Precision@10 measured 0.099 on LoCoMo: about nine of
1523
+ * every ten injected items were noise. Dropping candidates that trail
1524
+ * the top score by a large factor costs little recall and sharply
1525
+ * improves a context pack's signal-to-noise ratio.
1526
+ *
1527
+ * Lives in `types.ts` (dependency-free) and is forwarded by
1528
+ * `MemOSConfig.retrieval.relevanceGate` into every hybrid search
1529
+ * (`search`, `contextPack`, `multiStreamSearch`, `recall`'s scoring
1530
+ * pipeline). Off unless `enabled` is true — see the field's default.
1531
+ */
1532
+ export interface RelevanceGateConfig {
1533
+ /**
1534
+ * Master switch for the whole gate (tail trimming AND abstention).
1535
+ *
1536
+ * Defaults to `false`. This is a published SDK: an enabled gate
1537
+ * changes how many memories `search()` returns for the same query
1538
+ * (results whose fused score trails the top hit by more than
1539
+ * `1 - ratio` are dropped), and silently shrinking a consumer's result
1540
+ * count on upgrade is not a behaviour change we can make for them.
1541
+ * Turning it on is deliberately one explicit field:
1542
+ *
1543
+ * ```ts
1544
+ * new MemOS({ retrieval: { relevanceGate: { enabled: true } } })
1545
+ * // or, for a one-off experiment with no config change:
1546
+ * // MEMOS_RELEVANCE_GATE=1
1547
+ * ```
1548
+ */
1549
+ enabled?: boolean;
1550
+ /**
1551
+ * Keep only candidates whose fused score is at least
1552
+ * `topScore * ratio`. `0` disables trimming while leaving abstention
1553
+ * (if configured) active.
1554
+ *
1555
+ * Default 0.15 (`DEFAULT_RELEVANCE_RATIO` in `src/retrieval.ts`) —
1556
+ * deliberately low: it exists to cut the long tail of "matched one
1557
+ * stopword" rows, not to make fine-grained relevance decisions.
1558
+ */
1559
+ ratio?: number;
1560
+ /**
1561
+ * Abstain (return nothing) when no candidate reaches this cosine
1562
+ * similarity on the semantic leg AND nothing matched the query
1563
+ * literally. `undefined` disables abstention entirely.
1564
+ *
1565
+ * Deliberately unset by default even when the gate is enabled: the
1566
+ * floor is embedder-dependent — a 256-d hash embedder and a 1024-d
1567
+ * transformer do not share a cosine scale. Calibrate against your
1568
+ * embedder before switching this on (0.3 is a reasonable starting
1569
+ * point for paraphrase-quality embedders — see
1570
+ * `DEFAULT_ABSTAIN_SIMILARITY`).
1571
+ */
1572
+ abstainSimilarity?: number;
1573
+ /**
1574
+ * Safety floor: never trim below this many results, whatever the ratio
1575
+ * says. Useful for callers that need at least N items to render a view.
1576
+ * `0` means no floor.
1577
+ */
1578
+ minResults?: number;
1579
+ }
1580
+ /**
1581
+ * Outcome of one relevance-gate pass. Additive metadata — never breaks
1582
+ * the `ScoredMemory[]` shape `search()` has always returned.
1583
+ *
1584
+ * Surface points:
1585
+ * - `ScoredMemory.relevanceGate` on every result of a gated search;
1586
+ * - the `{ results, gate }` member pair returned by
1587
+ * `MemOS.searchWithGate()`.
1588
+ */
1589
+ export interface RelevanceGateResult {
1590
+ /**
1591
+ * True when the gate decided nothing in the store is relevant to the
1592
+ * query. The result list is empty and the caller should answer from
1593
+ * its own knowledge rather than from memory.
1594
+ */
1595
+ abstained: boolean;
1596
+ /** True when at least one candidate was dropped by tail trimming. */
1597
+ trimmed: boolean;
1598
+ /** How many fused candidates the gate removed. */
1599
+ dropped: number;
1600
+ }
1601
+ /**
1602
+ * Tunable knobs for the hybrid-search Reciprocal Rank Fusion. Lives in
1603
+ * `types.ts` (dependency-free) and is re-exported by `src/retrieval.ts`,
1604
+ * where `fuseResults()` consumes it. `MemOSConfig.fusion` forwards these
1605
+ * to every hybrid search; unset fields fall back to `retrieval.ts`
1606
+ * defaults.
1607
+ */
1608
+ export interface FusionOptions {
1609
+ /** RRF constant K. Larger K flattens rank differences. Default 60. */
1610
+ rrfK?: number;
1611
+ /** Weight of the keyword (FTS5) leg. Default 0.8. */
1612
+ keywordWeight?: number;
1613
+ /** Weight of the semantic (embedding) leg. Default 0.2. */
1614
+ semanticWeight?: number;
1615
+ /**
1616
+ * Lower bound of the trust multiplier (applied as
1617
+ * `trustFloor + trustScore * (1 - trustFloor)`). Default 0.7.
1618
+ * Set to 1.0 to disable trust weighting.
1619
+ */
1620
+ trustFloor?: number;
1621
+ /**
1622
+ * Strength of the confidence/trust combined multiplier from the
1623
+ * evidence state machine. Default 0.35. Set to 0 to disable
1624
+ * confidence-aware ranking.
1625
+ */
1626
+ confidenceWeightStrength?: number;
1627
+ /**
1628
+ * Recency half-life in ms for the tie-break among near-equal scores.
1629
+ * Default 30 days. Set to 0 to disable recency tie-breaking.
1630
+ */
1631
+ recencyHalfLifeMs?: number;
1632
+ /**
1633
+ * Reference "now" for recency computations. Defaults to wall-clock;
1634
+ * injectable for deterministic tests/benchmarks.
1635
+ */
1636
+ nowMs?: number;
1637
+ /**
1638
+ * Entities extracted from the query (populated automatically by
1639
+ * `hybridSearch` via `extractQueryEntities`). When non-empty, memories
1640
+ * whose tags / `metadata.entities` overlap the query entities receive a
1641
+ * post-fusion boost — the third retrieval signal alongside keyword and
1642
+ * semantic (see the 2026 fused multi-signal retrieval consensus).
1643
+ */
1644
+ queryEntities?: string[];
1645
+ /**
1646
+ * Strength of the entity-overlap boost: `score *= 1 + entityWeight *
1647
+ * overlap`. Default 0.15. Set to 0 to disable entity-fused scoring.
1648
+ *
1649
+ * Distinct from `entityLegWeight`: the overlap boost only re-scores
1650
+ * candidates the keyword/semantic legs already retrieved, while the
1651
+ * entity leg adds recall (entity-matched memories the other legs
1652
+ * missed enter the candidate pool).
1653
+ */
1654
+ entityWeight?: number;
1655
+ /**
1656
+ * ── item2: entity leg ── weight of the entity-inverted-index RRF leg
1657
+ * (the third retrieval signal alongside keyword and semantic). Applied
1658
+ * as `entityLegWeight / (rrfK + rank)` per candidate, so entity-matched
1659
+ * memories surface even when FTS and embeddings missed them. Default
1660
+ * 0.1 (deliberately below the semantic leg's 0.2 weight — see
1661
+ * DEFAULT_ENTITY_LEG_WEIGHT). Set to 0 to disable the leg.
1662
+ */
1663
+ entityLegWeight?: number;
1664
+ /**
1665
+ * Strength of the provenance-tier trust multiplier from the
1666
+ * provenance-trust layer. Applied as
1667
+ * `score *= 1 - strength * (1 - tierTrust)` with per-tier trust from
1668
+ * `PROVENANCE_TRUST` (user-verified 1.0 … imported 0.72). Default
1669
+ * 0.5 — low-trust content is slightly down-ranked without overriding
1670
+ * relevance. Set to 0 to disable trust-weighted recall. Calibrated
1671
+ * neutral-or-better on the retrieval eval (scripts/eval-retrieval.ts).
1672
+ */
1673
+ provenanceWeightStrength?: number;
1674
+ /**
1675
+ * Single-step PPR-lite graph expansion after fusion (HippoRAG-style,
1676
+ * see `src/graph-expansion.ts`). The top `graphExpansionSeeds` fused
1677
+ * results seed a personalized PageRank (damping 0.5, `graphExpansionHops`
1678
+ * hops) over graph edges plus shared-entity links; the final score
1679
+ * blends as `(1 - graphExpansionAlpha) * fused + graphExpansionAlpha *
1680
+ * pprNorm` with PPR scores normalized to [0,1]. Graph neighbours of
1681
+ * seeds that neither retrieval leg surfaced can enter the results this
1682
+ * way — the multi-hop recall win without iterative LLM retrieval.
1683
+ * Default: false (opt-in; expansion is off unless enabled here or per
1684
+ * query via `SearchFilter.graphExpansion: true`). When disabled the
1685
+ * pipeline is byte-identical to pre-expansion behaviour (no extra
1686
+ * storage reads, no score changes).
1687
+ */
1688
+ graphExpansion?: boolean;
1689
+ /**
1690
+ * Blend weight of the normalized PPR score in the post-fusion blend.
1691
+ * Default 0.2.
1692
+ */
1693
+ graphExpansionAlpha?: number;
1694
+ /** PPR neighbourhood depth explored from each seed. Default 2. */
1695
+ graphExpansionHops?: number;
1696
+ /** How many top fused results seed the PPR walk. Default 10. */
1697
+ graphExpansionSeeds?: number;
1698
+ /**
1699
+ * Fusion algorithm for combining the retrieval legs.
1700
+ *
1701
+ * - `"rrf"` — weighted Reciprocal Rank Fusion (rank-based voting,
1702
+ * robust to score outliers; the pre-round-4 default).
1703
+ * - `"convex"` — min-max normalize each leg's native scores to [0,1],
1704
+ * then take the weighted sum with renormalized leg weights. Lets
1705
+ * strong absolute scores (a near-exact embedding match, a dominant
1706
+ * bm25 hit) dominate instead of being flattened to rank votes.
1707
+ * Default `"convex"` (round 4; Sept 2026 TOIS analysis found convex
1708
+ * combination beats RRF in- and out-of-domain, and Weaviate made the
1709
+ * same switch). Set to `"rrf"` to restore the legacy behavior.
1710
+ */
1711
+ fusionMode?: "rrf" | "convex";
1712
+ /**
1713
+ * Raw query text, used only for the deterministic adaptive leg
1714
+ * weighting (short-query keyword emphasis, entity-dense entity-leg
1715
+ * emphasis, temporal-query recency). Populated automatically by
1716
+ * `hybridSearch`; no effect when `adaptiveWeighting` is false.
1717
+ */
1718
+ query?: string;
1719
+ /**
1720
+ * Master switch for the deterministic query-type adaptive weighting
1721
+ * (round 4). Default true. Set to false for fixed leg weights.
1722
+ */
1723
+ adaptiveWeighting?: boolean;
1724
+ /**
1725
+ * Strength of the temporal-query recency multiplier:
1726
+ * `score *= 1 + temporalRecencyStrength * 0.5^(age/halfLife)`,
1727
+ * applied only when the query carries temporal markers (today,
1728
+ * yesterday, last week, …) and `adaptiveWeighting` is on. Default
1729
+ * 0.05 (at most a 5% nudge toward fresh memories). Set to 0 to
1730
+ * disable.
1731
+ */
1732
+ temporalRecencyStrength?: number;
1733
+ /**
1734
+ * Weight of the CLIP image leg (Track B of image memory). Applied
1735
+ * exactly like the entity leg: `imageLegWeight / (rrfK + rank)` per
1736
+ * candidate in RRF mode, as a renormalized convex term otherwise.
1737
+ *
1738
+ * Defaults to {@link DEFAULT_IMAGE_LEG_WEIGHT} (0.1) whenever the leg
1739
+ * actually has results, so Track B contributes without any config.
1740
+ * The leg is inert when `vision.clip.enabled` is unset or the store
1741
+ * holds no image embeddings — a text-only install never pays for it
1742
+ * and its results are byte-identical to before. Set to 0 explicitly
1743
+ * to disable the leg even when images exist.
1744
+ */
1745
+ imageLegWeight?: number;
1746
+ }
1747
+ /**
1748
+ * Configuration options for a MemOS instance.
1749
+ */
1750
+ export interface MemOSConfig {
1751
+ /**
1752
+ * Optional write-time contextual enrichment hook (contextual retrieval,
1753
+ * Anthropic-style). Called once per `store()` with the memory's signals;
1754
+ * return a single line describing the situation the memory was captured
1755
+ * in (e.g. "stated while debugging the deploy pipeline"). The line is
1756
+ * stored in `metadata.context`, prepended to the embedded text, and
1757
+ * surfaced in context packs — it makes embeddings carry situational
1758
+ * meaning, which is the best-attested cheap retrieval upgrade in the
1759
+ * literature. Wire this to a local LLM (0.6B-class is enough) or any
1760
+ * heuristic. Errors are swallowed (fail-soft) and `opts.context`
1761
+ * always takes precedence over the hook.
1762
+ */
1763
+ enrichMemory?: (input: {
1764
+ content: string;
1765
+ type: MemoryType;
1766
+ tags: string[];
1767
+ source: MemorySource;
1768
+ namespace: string;
1769
+ }) => Promise<string | null | undefined> | string | null | undefined;
1770
+ /**
1771
+ * Deployment-specific entity aliases for fused retrieval scoring,
1772
+ * merged over the built-in table (`BUILTIN_ENTITY_ALIASES` in
1773
+ * `src/entity-extraction.ts`). Keys and values are matched
1774
+ * case-insensitively. Use this to canonicalize domain vocabulary —
1775
+ * e.g. `{ "sso": "auth", "okta": "auth" }` — so memories surface no
1776
+ * matter which phrasing a query uses.
1777
+ */
1778
+ entityAliases?: Record<string, string>;
1779
+ /**
1780
+ * Optional LLM distillation hook for `summarizeCluster` /
1781
+ * `consolidate`. Receives the contents of one cluster and returns an
1782
+ * abstractive summary (a runbook-style note — the highest-value
1783
+ * granularity in the LongMemEval-V2 ablations). When omitted or when
1784
+ * the hook fails/returns empty, the extractive summarizer is used.
1785
+ * Wire this to a local 0.6B–4B model for fully-offline consolidation.
1786
+ */
1787
+ summarizeClusterLlm?: (input: {
1788
+ contents: string[];
1789
+ sourceIds: string[];
1790
+ }) => Promise<string | null | undefined> | string | null | undefined;
1791
+ /**
1792
+ * Hybrid-search fusion tuning forwarded to `fuseResults()` on every
1793
+ * hybrid search. Unset fields use `src/retrieval.ts` defaults
1794
+ * (keyword 0.8 / semantic 0.2 / K 60 — tuned for the hash baseline;
1795
+ * stronger embedding models generally want a higher semantic weight).
1796
+ */
1797
+ fusion?: FusionOptions;
1798
+ /**
1799
+ * Path to the SQLite database file.
1800
+ * @default "~/.memos/memos.db"
1801
+ */
1802
+ dbPath?: string;
1803
+ /**
1804
+ * Enable WAL mode for SQLite.
1805
+ * @default true
1806
+ */
1807
+ wal?: boolean;
1808
+ /**
1809
+ * Maximum number of memories to keep before LRU eviction.
1810
+ * Set to `0` to disable eviction.
1811
+ * @default 0
1812
+ */
1813
+ maxMemories?: number;
1814
+ /**
1815
+ * Auto-link threshold: minimum cosine-similarity score (bag-of-words)
1816
+ * between two nodes to automatically create an edge.
1817
+ * Set to `0` to disable auto-linking.
1818
+ * @default 0.3
1819
+ */
1820
+ autoLinkThreshold?: number;
1821
+ /**
1822
+ * Custom storage adapter. When provided, `dbPath` is ignored.
1823
+ */
1824
+ storage?: StorageAdapter;
1825
+ /**
1826
+ * Options forwarded to the built-in SQLite storage adapter when
1827
+ * `storage` is not supplied. `vectorCacheEntries` bounds the in-process
1828
+ * parsed-vector cache (default 25,000 ≈ 100MB at 1024 dims); lower it
1829
+ * for memory-constrained hosts.
1830
+ */
1831
+ storageOptions?: {
1832
+ vectorCacheEntries?: number;
1833
+ /**
1834
+ * How the semantic leg (`querySimilarEmbeddings`) picks which stored
1835
+ * vectors to score.
1836
+ *
1837
+ * - `"exact"` (default): every candidate vector is scored. Cosine
1838
+ * results and rankings are bit-identical to the pre-optimisation
1839
+ * implementation — the scan only got cheaper per candidate
1840
+ * (cached norms, fused dot product, streaming bounded top-K,
1841
+ * early exit once a perfect match is found).
1842
+ * - `"prefilter"`: candidates are first ranked by a coarse strided
1843
+ * projection and only the top `max(32, limit * 4)` are exactly
1844
+ * rescored. Bounds the scan on large corpora, but is APPROXIMATE:
1845
+ * a true neighbour ranked below the cutoff is never returned.
1846
+ *
1847
+ * Only the built-in SQLite adapter reads this.
1848
+ */
1849
+ semanticScan?: "exact" | "prefilter";
1850
+ };
1851
+ /**
1852
+ * Encryption key for at-rest encryption of the SQLite database.
1853
+ * Requires the optional `better-sqlite3-multiple-ciphers` driver
1854
+ * (`npm i better-sqlite3-multiple-ciphers`). Falls back to the
1855
+ * `MEMOS_KEY` environment variable. Only NEW databases get encrypted —
1856
+ * convert an existing plaintext DB with `memos encrypt`.
1857
+ */
1858
+ cipherKey?: string;
1859
+ /**
1860
+ * Interval in seconds for the TTL expiration sweep.
1861
+ * Set to `0` to disable the sweep.
1862
+ * @default 60
1863
+ */
1864
+ sweepInterval?: number;
1865
+ /**
1866
+ * Experimental feature flags.
1867
+ */
1868
+ experimental?: ExperimentalConfig;
1869
+ /**
1870
+ * Effective importance model tuning. Controls how recency decay and
1871
+ * access reinforcement modulate the base `importance` for eviction,
1872
+ * archival, decay-forgetting, and (since the ranking wiring) hybrid
1873
+ * search ranking. See `ImportanceConfig` in `src/importance.ts`.
1874
+ *
1875
+ * OPT-IN: leaving this unset (or passing `{}`) keeps the historical
1876
+ * behaviour byte-for-byte — raw `node.importance` is still what
1877
+ * eviction, archival, and ranking use. Setting at least one field
1878
+ * switches those paths to `computeEffectiveImportance()`, so an old,
1879
+ * frequently-reinforced memory now outranks an equally-scored fresh
1880
+ * one, and a long-untouched memory is evicted sooner.
1881
+ */
1882
+ importance?: ImportanceConfig;
1883
+ /**
1884
+ * Retrieval-quality knobs: the relevance gate (abstention + tail
1885
+ * trimming). Off by default — see `RelevanceGateConfig.enabled` for
1886
+ * why turning it on is an explicit opt-in.
1887
+ */
1888
+ retrieval?: {
1889
+ relevanceGate?: RelevanceGateConfig;
1890
+ };
1891
+ /**
1892
+ * Half-life (days) for the optional recency boost in hybrid search
1893
+ * ranking. Only used when `experimental.recencyBoost` is enabled.
1894
+ * @default 14
1895
+ */
1896
+ recencyHalfLifeDays?: number;
1897
+ /**
1898
+ * Embedding provider configuration for semantic and hybrid retrieval.
1899
+ */
1900
+ embeddings?: EmbeddingConfig;
1901
+ /**
1902
+ * Background embedding queue tuning. Only takes effect when an
1903
+ * embedding provider is configured. See `EmbeddingQueueConfig`.
1904
+ */
1905
+ embeddingQueue?: EmbeddingQueueConfig;
1906
+ /**
1907
+ * Image memory (vision) configuration. Disabled by default: a bare
1908
+ * `new MemOS()` changes nothing — no new vector rows, no new search
1909
+ * results, no new pack bytes. See {@link VisionConfig}.
1910
+ */
1911
+ vision?: VisionConfig;
1912
+ }
1913
+ /**
1914
+ * Coarse taxonomy for what an image *is*, used for filtering and prompt
1915
+ * context — never as the type discriminator (see `metadata.image`).
1916
+ */
1917
+ export type ImageKind = "photo" | "screenshot" | "chart" | "diagram" | "memo" | "meme" | "other";
1918
+ /**
1919
+ * Reference form of an image carried by context packs and API results.
1920
+ * The bytes are NEVER inlined — consumers resolve the `ref` through the
1921
+ * blob store.
1922
+ */
1923
+ export interface ImageAttachment {
1924
+ /** Content-addressed key, `img_<sha256[0:12]>`. */
1925
+ ref: string;
1926
+ mime: string;
1927
+ width: number;
1928
+ height: number;
1929
+ kind: ImageKind;
1930
+ /** The caption text stored as the node's `content`. */
1931
+ caption: string;
1932
+ /** Full hex digest of the image bytes (dedupe + integrity). */
1933
+ sha256: string;
1934
+ /** Size of the stored blob in bytes. */
1935
+ bytes: number;
1936
+ }
1937
+ /**
1938
+ * The vision payload stored in `MemoryNode.metadata.image`. Presence of
1939
+ * this key — not `type`, not a new `MemoryType` member — is what marks a
1940
+ * node as an image memory (same discriminator pattern as
1941
+ * `metadata.context`), so `MemoryType` exhaustiveness stays intact
1942
+ * everywhere (sync allowlist, fidelity labels, adapters, MCP schema).
1943
+ */
1944
+ export interface ImageMemoryMeta extends ImageAttachment {
1945
+ /** Blob path, resolved relative to the database directory. */
1946
+ path: string;
1947
+ /** When the image was captured (not stored). Unix ms. */
1948
+ capturedAt: number;
1949
+ /** Optional conversation this image was shared in. */
1950
+ conversationId?: string;
1951
+ /** Who supplied the image. */
1952
+ source: ImageSource;
1953
+ /** Which caption production path produced the caption. */
1954
+ captionSource: "user" | "llm" | "generated";
1955
+ }
1956
+ /** Where an image came from. */
1957
+ export type ImageSource = "user" | "agent" | "tool";
1958
+ /**
1959
+ * CLIP leg status recorded in `metadata.clip.status`. Track A (caption →
1960
+ * text embeddings) works regardless of this value.
1961
+ */
1962
+ export type ClipStatus = "ready" | "pending" | "failed" | "skipped";
1963
+ /** CLIP bookkeeping recorded in `metadata.clip` when Track B is enabled. */
1964
+ export interface ClipMeta {
1965
+ model: string;
1966
+ dims: number;
1967
+ status: ClipStatus;
1968
+ /** Set when `status` is `"failed"`. */
1969
+ error?: string;
1970
+ /** Unix ms of the last status transition. */
1971
+ updatedAt: number;
1972
+ }
1973
+ /**
1974
+ * A provider that encodes images — and optionally the CLIP text side, for
1975
+ * text→image queries.
1976
+ *
1977
+ * Deliberately separate from `EmbeddingProvider`: CLIP vectors live in a
1978
+ * different vector space (and a different table) than text embeddings, so
1979
+ * the image encoder must never be handed to the text embedding queue.
1980
+ */
1981
+ export interface EmbedImageProvider {
1982
+ /** Stable provider identifier, e.g. `"clip"`. */
1983
+ readonly id: string;
1984
+ /** Model the provider encodes with. */
1985
+ readonly model: string;
1986
+ /** Vector dimensionality (512 for `clip-vit-base-patch32`). */
1987
+ readonly dimensions: number;
1988
+ /** Encode image bytes (or a path/URL) to a normalized vector. */
1989
+ embedImage(image: Buffer | string): Promise<EmbeddingVector>;
1990
+ /**
1991
+ * Encode a text query into the CLIP image space. Optional: providers
1992
+ * that can only do image→image search leave it unimplemented, and the
1993
+ * text→image leg silently degrades to the caption leg.
1994
+ */
1995
+ embedImageText?(query: string): Promise<EmbeddingVector>;
1996
+ }
1997
+ /** Image-memory configuration. Disabled by default — a bare
1998
+ * `new MemOS()` is byte-for-byte unchanged. */
1999
+ export interface VisionConfig {
2000
+ /** Master switch. Default false. */
2001
+ enabled?: boolean;
2002
+ clip?: {
2003
+ /** Track B opt-in. Default false (no ~350 MB model download). */
2004
+ enabled?: boolean;
2005
+ /** CLIP model id. Default `"Xenova/clip-vit-base-patch32"`. */
2006
+ model?: string;
2007
+ /** Expected dimensionality. Default 512. */
2008
+ dimensions?: number;
2009
+ /**
2010
+ * Explicit image encoder. When omitted, `ClipEmbeddingProvider` is
2011
+ * constructed lazily; when the transformers package is missing,
2012
+ * Track B fails soft to Track A — it never throws and never
2013
+ * substitutes a text vector.
2014
+ */
2015
+ embedImage?: EmbedImageProvider;
2016
+ };
2017
+ /** Blob store root. Default `<dbDir>/memos-images`. */
2018
+ storeRoot?: string;
2019
+ /** Max accepted image size in bytes. Default 5 MiB. */
2020
+ maxImageBytes?: number;
2021
+ /** Max edge length before re-encode is required. Default 4096. */
2022
+ maxDimension?: number;
2023
+ }
2024
+ /**
2025
+ * Every shape `addImageMemory` accepts, resolved by one normalizer.
2026
+ *
2027
+ * - `string` → a filesystem path (or a `data:` URL, detected by prefix)
2028
+ * - `Buffer` / `Uint8Array` → raw bytes
2029
+ * - `{ data, mime }` → base64 payload plus its declared MIME type
2030
+ * - `{ url }` → an http(s)/file/data URL to fetch
2031
+ */
2032
+ export type ImageInput = string | Buffer | Uint8Array | {
2033
+ data: string;
2034
+ mime: string;
2035
+ } | {
2036
+ url: string;
2037
+ };
2038
+ /** Options for {@link MemOS.addImageMemory}. Extends the store options. */
2039
+ export interface AddImageMemoryOptions extends Omit<CreateMemoryInput, "content"> {
2040
+ /**
2041
+ * The caption stored as the node's `content` — this is what text
2042
+ * retrieval actually matches. When omitted, a generated placeholder
2043
+ * records the kind and dimensions so the memory is still findable by
2044
+ * tag and still resolvable.
2045
+ */
2046
+ caption?: string;
2047
+ /** Coarse taxonomy override. Defaults to the MIME-derived kind. */
2048
+ kind?: ImageKind;
2049
+ /** When the image was captured (not stored). Defaults to now. */
2050
+ capturedAt?: number;
2051
+ /** Who supplied the image. Default `"user"`. */
2052
+ imageSource?: ImageSource;
2053
+ /** Optional conversation this image was shared in. */
2054
+ conversationId?: string;
2055
+ }
2056
+ /** What {@link MemOS.addImageMemory} returns. */
2057
+ export interface AddImageMemoryResult {
2058
+ /** The memory node (caption as content, `metadata.image` present). */
2059
+ node: MemoryNode;
2060
+ /** The image payload now carried by the node. */
2061
+ image: ImageMemoryMeta;
2062
+ /** Track B status: `ready` | `pending` | `skipped` | `failed`. */
2063
+ clipStatus: ClipStatus;
2064
+ /** True when identical bytes already existed and no new node was written. */
2065
+ deduped: boolean;
2066
+ }
2067
+ /** Options for {@link MemOS.searchImages}. */
2068
+ export interface SearchImagesOptions {
2069
+ limit?: number;
2070
+ /** Minimum CLIP cosine for the image leg. Default 0.15. */
2071
+ threshold?: number;
2072
+ namespace?: string;
2073
+ namespaces?: string[];
2074
+ /** Restrict to one image kind (e.g. `"diagram"`). */
2075
+ kind?: ImageKind;
2076
+ }
2077
+ /** Options for {@link MemOS.listImages}. */
2078
+ export interface ListImagesOptions {
2079
+ limit?: number;
2080
+ namespace?: string;
2081
+ }
2082
+ /** One image hit: the node, its fused score, and the attachment. */
2083
+ export interface ImageSearchResult {
2084
+ node: MemoryNode;
2085
+ score: number;
2086
+ image: ImageMemoryMeta;
2087
+ }
2088
+ /**
2089
+ * Export format options.
2090
+ */
2091
+ export type ExportFormat = "json" | "markdown" | "obsidian";
2092
+ /**
2093
+ * Options for exporting memories.
2094
+ */
2095
+ export interface ExportOptions {
2096
+ /** Export format. */
2097
+ format?: ExportFormat;
2098
+ /** Output directory path (for markdown/obsidian). */
2099
+ output?: string;
2100
+ /** Only export memories with this tag. */
2101
+ tag?: string;
2102
+ }
2103
+ /**
2104
+ * Result of an export operation.
2105
+ */
2106
+ export interface ExportResult {
2107
+ /** The format used. */
2108
+ format: ExportFormat;
2109
+ /** For JSON format, the serialized data. For file-based formats, the output directory. */
2110
+ data: string;
2111
+ /** Number of memories exported. */
2112
+ count: number;
2113
+ }
2114
+ /**
2115
+ * Options for importing memories.
2116
+ */
2117
+ export interface ImportOptions {
2118
+ /** Source format: json file path, or directory of markdown/obsidian files. */
2119
+ source: string;
2120
+ /** Import format: json, markdown, or obsidian. Auto-detected from path if omitted. */
2121
+ format?: ImportFormat;
2122
+ }
2123
+ /**
2124
+ * Import format options.
2125
+ */
2126
+ export type ImportFormat = "json" | "markdown" | "obsidian";
2127
+ /**
2128
+ * Result of an import operation.
2129
+ */
2130
+ export interface ImportResult {
2131
+ /** Number of memories imported. */
2132
+ count: number;
2133
+ /** Number of edges recreated (from wikilinks in obsidian format). */
2134
+ edgesCreated: number;
2135
+ }
2136
+ /**
2137
+ * Per-harness memory count, as returned by `getHarnessCounts()` /
2138
+ * `memos harness list`. Memories written before harness attribution
2139
+ * existed read as `"unknown"`.
2140
+ */
2141
+ export interface HarnessCount {
2142
+ /** Harness slug (or `"unknown"` for unattributed rows). */
2143
+ harness: string;
2144
+ /** Number of memories stamped with this harness. */
2145
+ count: number;
2146
+ }
2147
+ /** Options for `MemOS.mergeHarnessDb` (`memos harness merge`). */
2148
+ export interface HarnessMergeOptions {
2149
+ /**
2150
+ * When true, report the merge plan without writing anything.
2151
+ * Default false.
2152
+ */
2153
+ dryRun?: boolean;
2154
+ }
2155
+ /**
2156
+ * One source node in a harness-merge plan/result. `remapped` is true
2157
+ * when the target DB already held a node with the same id — the source
2158
+ * node is imported under a fresh id and every incident edge endpoint is
2159
+ * rewritten to it.
2160
+ */
2161
+ export interface HarnessMergeNode {
2162
+ /** Original id in the source DB. */
2163
+ sourceId: string;
2164
+ /** Id under which the node is (or would be) stored in the target. */
2165
+ targetId: string;
2166
+ /** True when the id had to be remapped (collision in the target). */
2167
+ remapped: boolean;
2168
+ /** Harness that originally wrote the memory (preserved verbatim). */
2169
+ harness: string;
2170
+ }
2171
+ /**
2172
+ * Outcome of `MemOS.mergeHarnessDb` (`memos harness merge --from`).
2173
+ * `dryRun: true` fills the plan fields and writes nothing.
2174
+ */
2175
+ export interface HarnessMergeResult {
2176
+ /** Source database path. */
2177
+ from: string;
2178
+ /** When true, no writes were performed. */
2179
+ dryRun: boolean;
2180
+ /** Source nodes examined. */
2181
+ sourceNodes: number;
2182
+ /** Source edges examined. */
2183
+ sourceEdges: number;
2184
+ /** Nodes imported (or that would be imported under `dryRun`). */
2185
+ nodesImported: number;
2186
+ /** Nodes whose ids collided and were remapped. */
2187
+ nodesRemapped: number;
2188
+ /** Edges imported (or that would be imported under `dryRun`). */
2189
+ edgesImported: number;
2190
+ /** Edges skipped because their endpoints were missing. */
2191
+ edgesSkipped: number;
2192
+ /** Per-node import plan (id mapping + preserved harness). */
2193
+ nodes: HarnessMergeNode[];
2194
+ /** Milliseconds the merge took. */
2195
+ durationMs: number;
2196
+ }
2197
+ /** Events emitted by the MemoryManager. */
2198
+ export type MemOSEvent = "node:created" | "node:updated" | "node:deleted" | "edge:created" | "edge:deleted" | "link:auto" | "eviction" | "ttl:expired" | "embedding:queued" | "embedding:started" | "embedding:complete" | "embedding:failed" | "embedding:retry" | "consolidation:complete" | "trust:changed" | "validity:changed" | "facts:extracted" | "memory:reinforced" | "memory:superseded" | "memory:reverted" | "contradiction:detected";
2199
+ /** Event listener signature. */
2200
+ export type MemOSEventListener = (data: unknown) => void;
2201
+ /** Options for {@link MemOS.dedupe}. */
2202
+ export interface DedupeOptions {
2203
+ /** Cosine-similarity threshold above which two memories are merged. Default 0.92. */
2204
+ threshold?: number;
2205
+ /** Only consider memories in this namespace. Default "default". */
2206
+ namespace?: string;
2207
+ /** If true, do not delete or merge anything. Default false. */
2208
+ dryRun?: boolean;
2209
+ /** Cap on how many pairs to compare. Default 10_000. */
2210
+ maxPairs?: number;
2211
+ }
2212
+ /** A single merge performed by `dedupe()`. */
2213
+ export interface DedupeMerge {
2214
+ /** The id of the surviving node. */
2215
+ kept: string;
2216
+ /** The ids of the nodes merged into the survivor and removed. */
2217
+ removed: string[];
2218
+ /** The reason this merge was selected. */
2219
+ reason: string;
2220
+ /** Mean cosine similarity across the cluster that was merged. */
2221
+ similarity: number;
2222
+ }
2223
+ /** Result returned by {@link MemOS.dedupe}. */
2224
+ export interface DedupeResult {
2225
+ merges: DedupeMerge[];
2226
+ /** Number of distinct clusters that were detected. */
2227
+ clustersFound: number;
2228
+ dryRun: boolean;
2229
+ durationMs: number;
2230
+ }
2231
+ /** Options for {@link MemOS.archive}. */
2232
+ export interface ArchiveOptions {
2233
+ /** Move memories older than this many days. Default 90. */
2234
+ afterDays?: number;
2235
+ /** Cap on importance for archival. Default 0.3. */
2236
+ importanceBelow?: number;
2237
+ /** Only consider memories in this namespace. Default "default". */
2238
+ namespace?: string;
2239
+ /** If true, do not actually move anything. Default false. */
2240
+ dryRun?: boolean;
2241
+ }
2242
+ /** A single archive operation. */
2243
+ export interface ArchiveMove {
2244
+ /** The id of the moved memory. */
2245
+ id: string;
2246
+ /** Reason it was archived (e.g. "stale_and_low_importance"). */
2247
+ reason: string;
2248
+ }
2249
+ /** Result returned by {@link MemOS.archive}. */
2250
+ export interface ArchiveResult {
2251
+ moves: ArchiveMove[];
2252
+ dryRun: boolean;
2253
+ durationMs: number;
2254
+ }
2255
+ /** Options for {@link MemOS.summarizeCluster}. */
2256
+ export interface SummarizeClusterOptions {
2257
+ /** Namespace to cluster. Default "default". */
2258
+ namespace?: string;
2259
+ /** Minimum cluster size to summarize. Default 3. */
2260
+ minClusterSize?: number;
2261
+ /** Cosine-similarity threshold for cluster membership. Default 0.78. */
2262
+ threshold?: number;
2263
+ /** If true, do not actually create summary nodes. Default false. */
2264
+ dryRun?: boolean;
2265
+ }
2266
+ /** A cluster that was summarized. */
2267
+ export interface ClusterSummary {
2268
+ /** The id of the newly-created summary node. Null when `dryRun: true`. */
2269
+ summaryId: string | null;
2270
+ /** The ids of the source nodes that the summary was derived from. */
2271
+ derivedFrom: string[];
2272
+ /** The generated summary text. */
2273
+ summary: string;
2274
+ }
2275
+ /** Result returned by {@link MemOS.summarizeCluster}. */
2276
+ export interface SummarizeClusterResult {
2277
+ clusters: ClusterSummary[];
2278
+ dryRun: boolean;
2279
+ durationMs: number;
2280
+ }
2281
+ /** Options for {@link MemOS.consolidate}. */
2282
+ export interface ConsolidateOptions {
2283
+ /** Cosine threshold for dedupe. Default 0.92. */
2284
+ dedupeThreshold?: number;
2285
+ /** Move memories older than this many days. Default 90. */
2286
+ archiveAfterDays?: number;
2287
+ /** Cap on importance for archival. Default 0.3. */
2288
+ archiveImportanceBelow?: number;
2289
+ /** Only consider memories in this namespace. Default "default". */
2290
+ namespace?: string;
2291
+ /** If true, do not actually mutate anything. Default false. */
2292
+ dryRun?: boolean;
2293
+ /** Generate cluster summaries in addition to dedupe + archive. Default true. */
2294
+ summarize?: boolean;
2295
+ /** Minimum cluster size for summarization. Default 3. */
2296
+ minClusterSize?: number;
2297
+ /** Cosine threshold for cluster membership. Default 0.78. */
2298
+ clusterThreshold?: number;
2299
+ /**
2300
+ * Run decay-based forgetting (algorithmic forgetting with an exponential
2301
+ * recency half-life). Superseded memories are marked historical
2302
+ * (`validTo = now`) — never deleted — so they stay queryable via
2303
+ * `searchTemporal`. Default true.
2304
+ */
2305
+ decay?: boolean;
2306
+ /** Exponential half-life (days) for the recency term of the retention score. Default 60. */
2307
+ decayHalfLifeDays?: number;
2308
+ /** Retention scores below this supersede the memory. Default 0.2. */
2309
+ minRetentionScore?: number;
2310
+ /** Only memories created more than this many days ago are eligible. Default 60. */
2311
+ olderThanDays?: number;
2312
+ }
2313
+ /**
2314
+ * A single memory superseded by the decay-forgetting stage of
2315
+ * `consolidate()`.
2316
+ */
2317
+ export interface DecaySuperseded {
2318
+ /** The superseded memory's id. */
2319
+ id: string;
2320
+ /** The retention score that fell below `minRetentionScore`. */
2321
+ score: number;
2322
+ }
2323
+ /** Options for {@link MemOS.forgetByDecay}. */
2324
+ export interface DecayForgettingOptions {
2325
+ /** Only consider memories in this namespace. Default "default". */
2326
+ namespace?: string;
2327
+ /** Exponential half-life (days) for the recency term. Default 60. */
2328
+ halfLifeDays?: number;
2329
+ /** Retention scores below this supersede the memory. Default 0.2. */
2330
+ minScore?: number;
2331
+ /** Only memories untouched for this many days are eligible. Default 60. */
2332
+ olderThanDays?: number;
2333
+ /** If true, do not actually supersede anything. Default false. */
2334
+ dryRun?: boolean;
2335
+ }
2336
+ /** Result returned by {@link MemOS.forgetByDecay}. */
2337
+ export interface DecayForgetResult {
2338
+ superseded: DecaySuperseded[];
2339
+ dryRun: boolean;
2340
+ durationMs: number;
2341
+ }
2342
+ /** Options for {@link MemOS.history}. */
2343
+ export interface HistoryOptions {
2344
+ /** Minimum similarity for related versions. Default 0.8. */
2345
+ threshold?: number;
2346
+ /** Cap on related versions per direction. Default 10. */
2347
+ limit?: number;
2348
+ }
2349
+ /**
2350
+ * The full version timeline for one memory: the memory itself, the older
2351
+ * versions it replaced, the newer versions that replaced it, and any
2352
+ * consolidated notes derived from it. Supersession is inferred from
2353
+ * content similarity plus temporal-validity windows — superseded versions
2354
+ * are historical (`validTo` set), the live version is not.
2355
+ */
2356
+ export interface MemoryHistory {
2357
+ node: MemoryNode;
2358
+ /** Older versions this memory replaced (oldest first). */
2359
+ supersedes: ScoredMemory[];
2360
+ /** Newer versions that replaced this memory (newest first). */
2361
+ supersededBy: ScoredMemory[];
2362
+ /** Notes (note pool) derived from this memory via `derived_from` edges. */
2363
+ derivedNotes: MemoryNode[];
2364
+ /** All graph edges touching this memory. */
2365
+ edges: MemoryEdge[];
2366
+ }
2367
+ /** Result returned by {@link MemOS.consolidate}. */
2368
+ export interface ConsolidateResult {
2369
+ merges: DedupeMerge[];
2370
+ moves: ArchiveMove[];
2371
+ clusters: ClusterSummary[];
2372
+ /** Memories superseded by decay-based forgetting. */
2373
+ decayed: DecaySuperseded[];
2374
+ dryRun: boolean;
2375
+ durationMs: number;
2376
+ }
2377
+ /**
2378
+ * A single message in a conversation, used by `extractFacts`.
2379
+ */
2380
+ export interface ConversationMessage {
2381
+ /** Speaker role: "user", "assistant", or "system". */
2382
+ role: "user" | "assistant" | "system";
2383
+ /** Message text content. */
2384
+ content: string;
2385
+ /** Optional speaker name for multi-user conversations. */
2386
+ speaker?: string;
2387
+ }
2388
+ /**
2389
+ * A candidate fact extracted from a conversation.
2390
+ */
2391
+ export interface ExtractedFact {
2392
+ /** The extracted fact text. */
2393
+ content: string;
2394
+ /** Inferred memory type. */
2395
+ type: MemoryType;
2396
+ /** Confidence in [0, 1]. */
2397
+ confidence: number;
2398
+ /** Optional tags inferred from context. */
2399
+ tags: string[];
2400
+ /** Source of the fact — usually `user_input` or `agent_inferred`. */
2401
+ source: MemorySource;
2402
+ }
2403
+ /**
2404
+ * Options for {@link MemOS.extractFacts}.
2405
+ */
2406
+ export interface ExtractFactsOptions {
2407
+ /**
2408
+ * If true, automatically store all extracted facts with confidence >=
2409
+ * `minConfidence`. Default false — returns candidates without storing.
2410
+ */
2411
+ autoStore?: boolean;
2412
+ /** Only auto-store facts with confidence >= this threshold. Default 0.6. */
2413
+ minConfidence?: number;
2414
+ /** Namespace to store facts in (when autoStore is true). */
2415
+ namespace?: string;
2416
+ /**
2417
+ * When true, skip facts that are near-duplicates of existing memories.
2418
+ * Default true.
2419
+ */
2420
+ dedupe?: boolean;
2421
+ /** Cosine similarity threshold for dedup. Default 0.85. */
2422
+ dedupeThreshold?: number;
2423
+ }
2424
+ /** Result returned by {@link MemOS.extractFacts}. */
2425
+ export interface ExtractFactsResult {
2426
+ /** Extracted fact candidates. */
2427
+ facts: ExtractedFact[];
2428
+ /** IDs of stored nodes (when `autoStore` is true). */
2429
+ storedIds: string[];
2430
+ /** Number of facts skipped as near-duplicates. */
2431
+ duplicates: number;
2432
+ }
2433
+ /**
2434
+ * Detailed diagnostics snapshot returned by `memos.diagnostics()`.
2435
+ */
2436
+ export interface DiagnosticsResult {
2437
+ /** Total number of stored memories. */
2438
+ totalNodes: number;
2439
+ /** Total number of edges. */
2440
+ totalEdges: number;
2441
+ /** Number of memories with embeddings. */
2442
+ nodesWithEmbeddings: number;
2443
+ /** Number of memories with temporal validity set. */
2444
+ nodesWithValidity: number;
2445
+ /** Number of historical (superseded) memories. */
2446
+ historicalNodes: number;
2447
+ /** Number of memories with a TTL. */
2448
+ nodesWithTTL: number;
2449
+ /** Number of expired memories pending sweep. */
2450
+ expiredNodes: number;
2451
+ /** Average importance across all nodes. */
2452
+ avgImportance: number;
2453
+ /** Average trust score across all nodes. */
2454
+ avgTrustScore: number;
2455
+ /** Breakdown of nodes by provenance source. */
2456
+ bySource: Record<string, number>;
2457
+ /** Breakdown of nodes by memory type. */
2458
+ byType: Record<string, number>;
2459
+ /** Breakdown of nodes by namespace. */
2460
+ byNamespace: Record<string, number>;
2461
+ /** Database file size in bytes. */
2462
+ dbSizeBytes: number;
2463
+ /** Embedding queue status, if configured. */
2464
+ embeddingQueue?: EmbeddingQueueStatus;
2465
+ /** Whether the storage adapter supports optional methods. */
2466
+ storageCapabilities: {
2467
+ peekNode: boolean;
2468
+ evictLeastImportant: boolean;
2469
+ saveEmbedding: boolean;
2470
+ getAllEmbeddings: boolean;
2471
+ setNodeNamespace: boolean;
2472
+ };
2473
+ }
2474
+ //# sourceMappingURL=types.d.ts.map