ai-memory-layer 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +765 -0
  4. package/bin/memory-server.mjs +157 -0
  5. package/dist/adapters/memory/embeddings.d.ts +4 -0
  6. package/dist/adapters/memory/embeddings.d.ts.map +1 -0
  7. package/dist/adapters/memory/embeddings.js +53 -0
  8. package/dist/adapters/memory/embeddings.js.map +1 -0
  9. package/dist/adapters/memory/index.d.ts +7 -0
  10. package/dist/adapters/memory/index.d.ts.map +1 -0
  11. package/dist/adapters/memory/index.js +650 -0
  12. package/dist/adapters/memory/index.js.map +1 -0
  13. package/dist/adapters/postgres/index.d.ts +38 -0
  14. package/dist/adapters/postgres/index.d.ts.map +1 -0
  15. package/dist/adapters/postgres/index.js +982 -0
  16. package/dist/adapters/postgres/index.js.map +1 -0
  17. package/dist/adapters/sqlite/embeddings.d.ts +5 -0
  18. package/dist/adapters/sqlite/embeddings.d.ts.map +1 -0
  19. package/dist/adapters/sqlite/embeddings.js +122 -0
  20. package/dist/adapters/sqlite/embeddings.js.map +1 -0
  21. package/dist/adapters/sqlite/index.d.ts +8 -0
  22. package/dist/adapters/sqlite/index.d.ts.map +1 -0
  23. package/dist/adapters/sqlite/index.js +839 -0
  24. package/dist/adapters/sqlite/index.js.map +1 -0
  25. package/dist/adapters/sqlite/mappers.d.ts +40 -0
  26. package/dist/adapters/sqlite/mappers.d.ts.map +1 -0
  27. package/dist/adapters/sqlite/mappers.js +95 -0
  28. package/dist/adapters/sqlite/mappers.js.map +1 -0
  29. package/dist/adapters/sqlite/schema.d.ts +4 -0
  30. package/dist/adapters/sqlite/schema.d.ts.map +1 -0
  31. package/dist/adapters/sqlite/schema.js +394 -0
  32. package/dist/adapters/sqlite/schema.js.map +1 -0
  33. package/dist/adapters/sync-to-async.d.ts +15 -0
  34. package/dist/adapters/sync-to-async.d.ts.map +1 -0
  35. package/dist/adapters/sync-to-async.js +95 -0
  36. package/dist/adapters/sync-to-async.js.map +1 -0
  37. package/dist/cli/inspect.d.ts +34 -0
  38. package/dist/cli/inspect.d.ts.map +1 -0
  39. package/dist/cli/inspect.js +190 -0
  40. package/dist/cli/inspect.js.map +1 -0
  41. package/dist/contracts/async-storage.d.ts +86 -0
  42. package/dist/contracts/async-storage.d.ts.map +1 -0
  43. package/dist/contracts/async-storage.js +2 -0
  44. package/dist/contracts/async-storage.js.map +1 -0
  45. package/dist/contracts/embedding.d.ts +22 -0
  46. package/dist/contracts/embedding.d.ts.map +1 -0
  47. package/dist/contracts/embedding.js +2 -0
  48. package/dist/contracts/embedding.js.map +1 -0
  49. package/dist/contracts/identity.d.ts +29 -0
  50. package/dist/contracts/identity.d.ts.map +1 -0
  51. package/dist/contracts/identity.js +34 -0
  52. package/dist/contracts/identity.js.map +1 -0
  53. package/dist/contracts/observability.d.ts +18 -0
  54. package/dist/contracts/observability.d.ts.map +1 -0
  55. package/dist/contracts/observability.js +7 -0
  56. package/dist/contracts/observability.js.map +1 -0
  57. package/dist/contracts/policy.d.ts +108 -0
  58. package/dist/contracts/policy.d.ts.map +1 -0
  59. package/dist/contracts/policy.js +107 -0
  60. package/dist/contracts/policy.js.map +1 -0
  61. package/dist/contracts/storage.d.ts +78 -0
  62. package/dist/contracts/storage.d.ts.map +1 -0
  63. package/dist/contracts/storage.js +2 -0
  64. package/dist/contracts/storage.js.map +1 -0
  65. package/dist/contracts/types.d.ts +381 -0
  66. package/dist/contracts/types.d.ts.map +1 -0
  67. package/dist/contracts/types.js +94 -0
  68. package/dist/contracts/types.js.map +1 -0
  69. package/dist/core/circuit-breaker.d.ts +11 -0
  70. package/dist/core/circuit-breaker.d.ts.map +1 -0
  71. package/dist/core/circuit-breaker.js +38 -0
  72. package/dist/core/circuit-breaker.js.map +1 -0
  73. package/dist/core/context.d.ts +56 -0
  74. package/dist/core/context.d.ts.map +1 -0
  75. package/dist/core/context.js +345 -0
  76. package/dist/core/context.js.map +1 -0
  77. package/dist/core/events.d.ts +8 -0
  78. package/dist/core/events.d.ts.map +1 -0
  79. package/dist/core/events.js +25 -0
  80. package/dist/core/events.js.map +1 -0
  81. package/dist/core/extractor.d.ts +37 -0
  82. package/dist/core/extractor.d.ts.map +1 -0
  83. package/dist/core/extractor.js +448 -0
  84. package/dist/core/extractor.js.map +1 -0
  85. package/dist/core/formatter.d.ts +25 -0
  86. package/dist/core/formatter.d.ts.map +1 -0
  87. package/dist/core/formatter.js +97 -0
  88. package/dist/core/formatter.js.map +1 -0
  89. package/dist/core/knowledge-lifecycle.d.ts +15 -0
  90. package/dist/core/knowledge-lifecycle.d.ts.map +1 -0
  91. package/dist/core/knowledge-lifecycle.js +103 -0
  92. package/dist/core/knowledge-lifecycle.js.map +1 -0
  93. package/dist/core/maintenance.d.ts +13 -0
  94. package/dist/core/maintenance.d.ts.map +1 -0
  95. package/dist/core/maintenance.js +102 -0
  96. package/dist/core/maintenance.js.map +1 -0
  97. package/dist/core/manager.d.ts +110 -0
  98. package/dist/core/manager.d.ts.map +1 -0
  99. package/dist/core/manager.js +640 -0
  100. package/dist/core/manager.js.map +1 -0
  101. package/dist/core/monitor.d.ts +73 -0
  102. package/dist/core/monitor.d.ts.map +1 -0
  103. package/dist/core/monitor.js +395 -0
  104. package/dist/core/monitor.js.map +1 -0
  105. package/dist/core/orchestrator.d.ts +64 -0
  106. package/dist/core/orchestrator.d.ts.map +1 -0
  107. package/dist/core/orchestrator.js +916 -0
  108. package/dist/core/orchestrator.js.map +1 -0
  109. package/dist/core/presets.d.ts +15 -0
  110. package/dist/core/presets.d.ts.map +1 -0
  111. package/dist/core/presets.js +99 -0
  112. package/dist/core/presets.js.map +1 -0
  113. package/dist/core/provider-managers.d.ts +47 -0
  114. package/dist/core/provider-managers.d.ts.map +1 -0
  115. package/dist/core/provider-managers.js +112 -0
  116. package/dist/core/provider-managers.js.map +1 -0
  117. package/dist/core/quick.d.ts +62 -0
  118. package/dist/core/quick.d.ts.map +1 -0
  119. package/dist/core/quick.js +300 -0
  120. package/dist/core/quick.js.map +1 -0
  121. package/dist/core/retrieval.d.ts +29 -0
  122. package/dist/core/retrieval.d.ts.map +1 -0
  123. package/dist/core/retrieval.js +150 -0
  124. package/dist/core/retrieval.js.map +1 -0
  125. package/dist/core/runtime.d.ts +67 -0
  126. package/dist/core/runtime.d.ts.map +1 -0
  127. package/dist/core/runtime.js +84 -0
  128. package/dist/core/runtime.js.map +1 -0
  129. package/dist/core/streaming.d.ts +37 -0
  130. package/dist/core/streaming.d.ts.map +1 -0
  131. package/dist/core/streaming.js +51 -0
  132. package/dist/core/streaming.js.map +1 -0
  133. package/dist/core/sync.d.ts +13 -0
  134. package/dist/core/sync.d.ts.map +1 -0
  135. package/dist/core/sync.js +46 -0
  136. package/dist/core/sync.js.map +1 -0
  137. package/dist/core/telemetry.d.ts +8 -0
  138. package/dist/core/telemetry.d.ts.map +1 -0
  139. package/dist/core/telemetry.js +14 -0
  140. package/dist/core/telemetry.js.map +1 -0
  141. package/dist/core/tokens.d.ts +8 -0
  142. package/dist/core/tokens.d.ts.map +1 -0
  143. package/dist/core/tokens.js +59 -0
  144. package/dist/core/tokens.js.map +1 -0
  145. package/dist/core/trust.d.ts +23 -0
  146. package/dist/core/trust.d.ts.map +1 -0
  147. package/dist/core/trust.js +164 -0
  148. package/dist/core/trust.js.map +1 -0
  149. package/dist/core/validation.d.ts +36 -0
  150. package/dist/core/validation.d.ts.map +1 -0
  151. package/dist/core/validation.js +185 -0
  152. package/dist/core/validation.js.map +1 -0
  153. package/dist/embeddings/local.d.ts +5 -0
  154. package/dist/embeddings/local.d.ts.map +1 -0
  155. package/dist/embeddings/local.js +128 -0
  156. package/dist/embeddings/local.js.map +1 -0
  157. package/dist/embeddings/openai.d.ts +26 -0
  158. package/dist/embeddings/openai.d.ts.map +1 -0
  159. package/dist/embeddings/openai.js +48 -0
  160. package/dist/embeddings/openai.js.map +1 -0
  161. package/dist/embeddings/resilience.d.ts +5 -0
  162. package/dist/embeddings/resilience.d.ts.map +1 -0
  163. package/dist/embeddings/resilience.js +53 -0
  164. package/dist/embeddings/resilience.js.map +1 -0
  165. package/dist/embeddings/voyage.d.ts +30 -0
  166. package/dist/embeddings/voyage.d.ts.map +1 -0
  167. package/dist/embeddings/voyage.js +53 -0
  168. package/dist/embeddings/voyage.js.map +1 -0
  169. package/dist/index.d.ts +72 -0
  170. package/dist/index.d.ts.map +1 -0
  171. package/dist/index.js +40 -0
  172. package/dist/index.js.map +1 -0
  173. package/dist/integrations/claude-agent.d.ts +21 -0
  174. package/dist/integrations/claude-agent.d.ts.map +1 -0
  175. package/dist/integrations/claude-agent.js +44 -0
  176. package/dist/integrations/claude-agent.js.map +1 -0
  177. package/dist/integrations/claude-tools.d.ts +18 -0
  178. package/dist/integrations/claude-tools.d.ts.map +1 -0
  179. package/dist/integrations/claude-tools.js +60 -0
  180. package/dist/integrations/claude-tools.js.map +1 -0
  181. package/dist/integrations/langchain.d.ts +24 -0
  182. package/dist/integrations/langchain.d.ts.map +1 -0
  183. package/dist/integrations/langchain.js +48 -0
  184. package/dist/integrations/langchain.js.map +1 -0
  185. package/dist/integrations/mcp.d.ts +23 -0
  186. package/dist/integrations/mcp.d.ts.map +1 -0
  187. package/dist/integrations/mcp.js +60 -0
  188. package/dist/integrations/mcp.js.map +1 -0
  189. package/dist/integrations/middleware.d.ts +15 -0
  190. package/dist/integrations/middleware.d.ts.map +1 -0
  191. package/dist/integrations/middleware.js +27 -0
  192. package/dist/integrations/middleware.js.map +1 -0
  193. package/dist/integrations/openai-tools.d.ts +21 -0
  194. package/dist/integrations/openai-tools.d.ts.map +1 -0
  195. package/dist/integrations/openai-tools.js +69 -0
  196. package/dist/integrations/openai-tools.js.map +1 -0
  197. package/dist/integrations/vercel-ai.d.ts +19 -0
  198. package/dist/integrations/vercel-ai.d.ts.map +1 -0
  199. package/dist/integrations/vercel-ai.js +41 -0
  200. package/dist/integrations/vercel-ai.js.map +1 -0
  201. package/dist/server/http-server.d.ts +61 -0
  202. package/dist/server/http-server.d.ts.map +1 -0
  203. package/dist/server/http-server.js +684 -0
  204. package/dist/server/http-server.js.map +1 -0
  205. package/dist/server/index.d.ts +5 -0
  206. package/dist/server/index.d.ts.map +1 -0
  207. package/dist/server/index.js +3 -0
  208. package/dist/server/index.js.map +1 -0
  209. package/dist/server/mcp-server.d.ts +61 -0
  210. package/dist/server/mcp-server.d.ts.map +1 -0
  211. package/dist/server/mcp-server.js +465 -0
  212. package/dist/server/mcp-server.js.map +1 -0
  213. package/dist/summarizers/claude.d.ts +11 -0
  214. package/dist/summarizers/claude.d.ts.map +1 -0
  215. package/dist/summarizers/claude.js +39 -0
  216. package/dist/summarizers/claude.js.map +1 -0
  217. package/dist/summarizers/client.d.ts +23 -0
  218. package/dist/summarizers/client.d.ts.map +1 -0
  219. package/dist/summarizers/client.js +24 -0
  220. package/dist/summarizers/client.js.map +1 -0
  221. package/dist/summarizers/extractive.d.ts +6 -0
  222. package/dist/summarizers/extractive.d.ts.map +1 -0
  223. package/dist/summarizers/extractive.js +204 -0
  224. package/dist/summarizers/extractive.js.map +1 -0
  225. package/dist/summarizers/extractor.d.ts +12 -0
  226. package/dist/summarizers/extractor.d.ts.map +1 -0
  227. package/dist/summarizers/extractor.js +75 -0
  228. package/dist/summarizers/extractor.js.map +1 -0
  229. package/dist/summarizers/openai.d.ts +11 -0
  230. package/dist/summarizers/openai.d.ts.map +1 -0
  231. package/dist/summarizers/openai.js +41 -0
  232. package/dist/summarizers/openai.js.map +1 -0
  233. package/dist/summarizers/prompts.d.ts +11 -0
  234. package/dist/summarizers/prompts.d.ts.map +1 -0
  235. package/dist/summarizers/prompts.js +104 -0
  236. package/dist/summarizers/prompts.js.map +1 -0
  237. package/docs/DEPLOYMENT.md +84 -0
  238. package/docs/INTEGRATIONS.md +64 -0
  239. package/docs/MEMORY_QUALITY_BASELINE.md +55 -0
  240. package/docs/MEMORY_QUALITY_RELEASE_GATE.md +63 -0
  241. package/docs/MEMORY_QUALITY_RUBRIC.md +249 -0
  242. package/docs/OPERATIONS.md +49 -0
  243. package/docs/SECURITY.md +25 -0
  244. package/openapi.yaml +843 -0
  245. package/package.json +157 -0
package/README.md ADDED
@@ -0,0 +1,765 @@
1
+ <p align="center">
2
+ <h1 align="center">memory-layer</h1>
3
+ <p align="center">
4
+ Persistent memory for AI systems.<br/>
5
+ Drop it into any agent, IDE, or autonomous loop.<br/>
6
+ Two lines to remember. Zero lines to forget.
7
+ </p>
8
+ </p>
9
+
10
+ <p align="center">
11
+ <a href="#quick-start">Quick Start</a> &nbsp;&bull;&nbsp;
12
+ <a href="#how-it-works">How It Works</a> &nbsp;&bull;&nbsp;
13
+ <a href="#integration-patterns">Integrations</a> &nbsp;&bull;&nbsp;
14
+ <a href="#python">Python</a> &nbsp;&bull;&nbsp;
15
+ <a href="#api-reference">API</a> &nbsp;&bull;&nbsp;
16
+ <a href="#configuration">Config</a> &nbsp;&bull;&nbsp;
17
+ <a href="docs/DEPLOYMENT.md">Deploy</a>
18
+ </p>
19
+
20
+ ---
21
+
22
+ ## The Problem
23
+
24
+ AI systems have no memory. Every session starts cold. Context vanishes. Learned preferences disappear. Mistakes repeat.
25
+
26
+ If you're building an autonomous agent, a coding assistant, or a dark-factory loop, the model forgets everything the moment the conversation ends. Bolting on memory means building compaction, extraction, trust scoring, retrieval, multi-tenant scoping, and lifecycle management from scratch.
27
+
28
+ **memory-layer** is that entire stack as a drop-in package.
29
+
30
+ ```typescript
31
+ import { createMemory } from 'ai-memory-layer';
32
+
33
+ const memory = createMemory();
34
+ ```
35
+
36
+ That's a working memory system. No API keys. No infrastructure. No configuration.
37
+
38
+ ---
39
+
40
+ ## Quick Start
41
+
42
+ ### Install
43
+
44
+ ```bash
45
+ npm install ai-memory-layer
46
+ ```
47
+
48
+ ### Zero-Config (in-memory, fully offline)
49
+
50
+ ```typescript
51
+ import { createMemory } from 'ai-memory-layer';
52
+
53
+ const memory = createMemory();
54
+
55
+ await memory.processExchange(
56
+ 'Always use TypeScript strict mode in this project.',
57
+ 'Got it — TypeScript strict mode is now a stored constraint.',
58
+ );
59
+
60
+ // Later, in a new session or turn:
61
+ const ctx = await memory.getContext('typescript config');
62
+ // ctx.relevantKnowledge → [{ fact: "Use TypeScript strict mode", knowledge_class: "constraint", ... }]
63
+ ```
64
+
65
+ No API keys required. Uses a pure-JS extractive summarizer, heuristic fact extractor, and local embedding fallback. Good enough to start. Upgrades automatically when provider credentials appear.
66
+
67
+ ### Persistent (SQLite)
68
+
69
+ ```bash
70
+ npm install better-sqlite3
71
+ ```
72
+
73
+ ```typescript
74
+ const memory = createMemory({
75
+ adapter: 'sqlite',
76
+ path: './data/memory.db',
77
+ scope: 'my-agent',
78
+ });
79
+ ```
80
+
81
+ Memory survives restarts. Same API. One line changed.
82
+
83
+ ### Provider-Backed (strongest quality)
84
+
85
+ ```bash
86
+ npm install openai # or @anthropic-ai/sdk
87
+ ```
88
+
89
+ ```typescript
90
+ const memory = createMemory({
91
+ adapter: 'sqlite',
92
+ path: './data/memory.db',
93
+ preset: 'autonomous_agent',
94
+ qualityMode: 'high_fidelity_memory',
95
+ summarizer: 'openai',
96
+ extractor: 'openai',
97
+ });
98
+ ```
99
+
100
+ When `OPENAI_API_KEY` or `VOYAGE_API_KEY` is present, `createMemory()` auto-upgrades to provider-backed embeddings. You don't have to change anything — the quality tier shifts silently.
101
+
102
+ ---
103
+
104
+ ## How It Works
105
+
106
+ ```
107
+ User Input ──> Turn Storage ──> Compaction ──> Working Memory
108
+
109
+ Extraction ──> Knowledge Memory
110
+
111
+ Retrieval ──> Prompt-Ready Context
112
+ ```
113
+
114
+ ### Three-Tier Memory
115
+
116
+ Memory flows through three tiers, each optimized for a different time horizon:
117
+
118
+ | Tier | What It Stores | How Long It Lives |
119
+ |------|---------------|-------------------|
120
+ | **Short-term** (Turns) | Raw conversation exchanges | Until compacted |
121
+ | **Medium-term** (Working Memory) | Summaries with entities and topic tags | Days to weeks (TTL) |
122
+ | **Long-term** (Knowledge) | Extracted facts with trust scores and evidence | Weeks to years (lifecycle) |
123
+
124
+ ### Knowledge Trust Lifecycle
125
+
126
+ Extracted facts aren't blindly trusted. Every fact has a state:
127
+
128
+ ```
129
+ candidate ──> provisional ──> trusted
130
+ │ │
131
+ └── disputed └── superseded ──> retired
132
+ ```
133
+
134
+ Promotion requires evidence. A fact needs grounding in source turns, explicit user statements, tool verification, or repeated corroboration before it reaches `trusted`. Contradictions are detected and facts are marked `disputed` — not silently overwritten.
135
+
136
+ Every decision is audited. You can inspect why any fact was promoted, demoted, or retired.
137
+
138
+ ### Hybrid Retrieval
139
+
140
+ When you call `getContext()`, the engine scores every candidate fact across multiple dimensions:
141
+
142
+ - **Lexical** — full-text search relevance
143
+ - **Semantic** — vector similarity (when embeddings are available)
144
+ - **Recency** — when the fact was last accessed
145
+ - **Trust** — knowledge state and confidence score
146
+ - **Class importance** — identity facts rank higher than episodic ones
147
+ - **Evidence density** — better-grounded facts rank higher
148
+ - **Scope relation** — local facts rank higher than cross-scope ones
149
+ - **Diversity** — penalizes clustering of same-type results
150
+
151
+ The result is a `MemoryContext` object ready to inject into any model call.
152
+
153
+ ---
154
+
155
+ ## Integration Patterns
156
+
157
+ ### Before/After Hooks (recommended)
158
+
159
+ ```typescript
160
+ import { createMemory, createMemoryRuntime } from 'ai-memory-layer';
161
+
162
+ const manager = createMemory({ adapter: 'sqlite', path: './memory.db' });
163
+ const runtime = createMemoryRuntime(manager);
164
+
165
+ // Before the model call — get context
166
+ const { prompt, messages } = await runtime.beforeModelCall(userInput);
167
+
168
+ // Call your model with enriched context
169
+ const result = await model.generate(prompt);
170
+
171
+ // After the model call — store the exchange, trigger compaction + extraction
172
+ await runtime.afterModelCall({ userInput, assistantOutput: result });
173
+ ```
174
+
175
+ ### Single-Line Wrapper
176
+
177
+ ```typescript
178
+ const { result } = await runtime.wrapModelCall(
179
+ (prepared) => model.generate(prepared.prompt),
180
+ userInput,
181
+ );
182
+ ```
183
+
184
+ `wrapModelCall` handles the full cycle: context assembly, model call, turn storage, compaction, extraction, and work item tracking.
185
+
186
+ ### Claude Agent SDK
187
+
188
+ ```typescript
189
+ import { wrapClaudeAgentModel } from 'ai-memory-layer';
190
+
191
+ const run = wrapClaudeAgentModel(runtime, ({ system, messages, tools }) =>
192
+ client.messages.create({ model: 'claude-sonnet-4-20250514', system, messages, tools }),
193
+ );
194
+
195
+ const { result } = await run(userInput);
196
+ ```
197
+
198
+ ### OpenAI / Vercel AI / LangChain
199
+
200
+ ```typescript
201
+ // OpenAI function tools
202
+ import { createOpenAIMemoryTools } from 'ai-memory-layer';
203
+ const tools = createOpenAIMemoryTools(runtime);
204
+
205
+ // Vercel AI SDK
206
+ import { wrapVercelAIModel } from 'ai-memory-layer';
207
+ const run = wrapVercelAIModel(runtime, ({ system, messages }) =>
208
+ generateText({ system, messages }),
209
+ );
210
+
211
+ // LangChain memory bridge
212
+ import { createLangChainMemoryBridge } from 'ai-memory-layer';
213
+ const langchainMemory = createLangChainMemoryBridge(manager);
214
+ ```
215
+
216
+ ### Middleware (message-list passthrough)
217
+
218
+ ```typescript
219
+ import { wrapWithMemory } from 'ai-memory-layer';
220
+
221
+ const handler = wrapWithMemory(
222
+ (messages) => callModel(messages),
223
+ manager,
224
+ { injectContext: true, contextPosition: 'system' },
225
+ );
226
+ ```
227
+
228
+ ### MCP Server
229
+
230
+ ```typescript
231
+ import { createMemoryMcpAdapter } from 'ai-memory-layer';
232
+
233
+ const mcp = createMemoryMcpAdapter(runtime);
234
+ // mcp.tools — tool definitions
235
+ // mcp.callTool(name, args) — dispatcher
236
+ ```
237
+
238
+ Or run as a standalone MCP server:
239
+
240
+ ```bash
241
+ npx memory-layer serve --transport mcp --db ./memory.db
242
+ ```
243
+
244
+ ### HTTP Service
245
+
246
+ For polyglot deployments, run memory-layer as a standalone HTTP service:
247
+
248
+ ```bash
249
+ npx memory-layer serve --transport http --db ./memory.db --port 3100
250
+ ```
251
+
252
+ Full REST API documented in [`openapi.yaml`](openapi.yaml). Supports multi-tenant routing via scope headers, event streaming via SSE, and API key authentication.
253
+
254
+ ---
255
+
256
+ ## Python
257
+
258
+ ```bash
259
+ pip install memory-layer-client
260
+ ```
261
+
262
+ The Python client mirrors the HTTP API surface. It's an HTTP client, not a second engine — run the Node service and point Python at it.
263
+
264
+ ```python
265
+ from memory_layer_client import MemoryClient, MemoryRuntimeClient, MemoryScope
266
+
267
+ client = MemoryClient(
268
+ "http://localhost:3100",
269
+ default_scope=MemoryScope(
270
+ tenant_id="acme",
271
+ system_id="research-agent",
272
+ scope_id="session-1",
273
+ ),
274
+ )
275
+
276
+ runtime = MemoryRuntimeClient(client)
277
+
278
+ # Full before/after cycle with your model
279
+ result = runtime.run_turn(
280
+ "What constraints apply to this project?",
281
+ lambda prepared: call_model(prepared.context),
282
+ )
283
+
284
+ # Direct operations
285
+ client.learn_fact("Deployment target is AWS us-east-1", "constraint")
286
+ results = client.search("deployment")
287
+ context = client.get_context("deployment constraints")
288
+ ```
289
+
290
+ Async support included:
291
+
292
+ ```python
293
+ from memory_layer_client import AsyncMemoryClient, AsyncMemoryRuntimeClient
294
+
295
+ async with AsyncMemoryClient("http://localhost:3100") as client:
296
+ runtime = AsyncMemoryRuntimeClient(client)
297
+ result = await runtime.run_turn(user_input, model_call)
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Presets
303
+
304
+ Start with a preset. Override only when you need to.
305
+
306
+ | Preset | Designed For | Compaction | Cross-Scope | Knowledge TTL |
307
+ |--------|-------------|------------|-------------|---------------|
308
+ | `ai_ide` | Coding assistants, refactoring tools | Moderate (18/30 turns) | Workspace-shared | 14 days |
309
+ | `chat_agent` | Conversational agents, support bots | Balanced (14/24 turns) | Scope-local | 7 days |
310
+ | `autonomous_agent` | Dark factories, autonomous loops | Aggressive (10/18 turns) | Workspace-shared | 3 days |
311
+
312
+ ```typescript
313
+ const memory = createMemory({ preset: 'autonomous_agent' });
314
+ ```
315
+
316
+ ### Quality Modes
317
+
318
+ Orthogonal to presets. Controls how aggressively the system trusts and retains knowledge.
319
+
320
+ | Mode | Trust Threshold | Retention | Best For |
321
+ |------|----------------|-----------|----------|
322
+ | `fast_adoption` | 0.55 | 60-day core | Prototyping, low-stakes agents |
323
+ | `balanced_memory` | 0.70 | 365-day core | Production default |
324
+ | `high_fidelity_memory` | 0.82 | 730-day core | Safety-critical, long-running systems |
325
+
326
+ ```typescript
327
+ const memory = createMemory({
328
+ preset: 'autonomous_agent',
329
+ qualityMode: 'high_fidelity_memory',
330
+ });
331
+ ```
332
+
333
+ ---
334
+
335
+ ## Quality Tiers
336
+
337
+ `createMemory()` auto-detects your environment and resolves to the best available tier:
338
+
339
+ | Tier | Extraction | Retrieval | Requires |
340
+ |------|-----------|-----------|----------|
341
+ | **Offline default** | Regex + heuristic | Lexical + local embeddings | Nothing |
342
+ | **Local semantic** | Composite heuristic | Lexical + local TF-IDF embeddings | Nothing |
343
+ | **Provider-backed** | Claude/OpenAI LLM | Lexical + provider embeddings | API key |
344
+
345
+ Pass `onEvent` to see which tier resolved at startup:
346
+
347
+ ```typescript
348
+ const memory = createMemory({
349
+ onEvent: (event) => {
350
+ if (event.type === 'capability') {
351
+ console.log(event.meta);
352
+ // { qualityMode: 'balanced_memory', extractorTier: 'local_heuristic',
353
+ // embeddingTier: 'local_semantic', providerBacked: false }
354
+ }
355
+ },
356
+ });
357
+ ```
358
+
359
+ The local path is an honest fallback — functional, not aspirational. Provider-backed is the gold standard for extraction and retrieval quality.
360
+
361
+ ---
362
+
363
+ ## Scoping & Multi-Tenancy
364
+
365
+ Every record belongs to a scope. Scopes enable isolation and selective sharing across agents, workspaces, and tenants.
366
+
367
+ ```typescript
368
+ const memory = createMemory({
369
+ scope: {
370
+ tenant_id: 'acme-corp', // Organization boundary
371
+ system_id: 'code-assistant', // Which agent
372
+ workspace_id: 'backend-repo', // Shared project context
373
+ scope_id: 'task-refactor-auth', // This specific task
374
+ },
375
+ crossScopeLevel: 'workspace', // Can read workspace-wide knowledge
376
+ });
377
+ ```
378
+
379
+ ### Cross-Scope Retrieval
380
+
381
+ ```typescript
382
+ // Search across the workspace
383
+ const results = await memory.searchCrossScope('rate limiting', 'workspace');
384
+
385
+ // Poll for knowledge changes from other agents
386
+ const changes = await memory.pollForChanges(lastSyncTimestamp);
387
+ ```
388
+
389
+ Retrieval levels: `scope` (exact match) → `workspace` → `system` → `tenant`
390
+
391
+ ---
392
+
393
+ ## API Reference
394
+
395
+ ### MemoryManager
396
+
397
+ Returned by `createMemory()`, `createMemoryManager()`, and provider factories.
398
+
399
+ ```typescript
400
+ interface MemoryManager {
401
+ // --- Store ---
402
+ processTurn(role, content, actor?): Promise<Turn>
403
+ processExchange(userContent, assistantContent, actors?): Promise<{
404
+ userTurn: Turn; assistantTurn: Turn; compactionResult: CompactionResult | null;
405
+ }>
406
+
407
+ // --- Retrieve ---
408
+ getContext(relevanceQuery?): Promise<MemoryContext>
409
+ getContextAt(asOf, relevanceQuery?): Promise<MemoryContext>
410
+ getSessionBootstrap(relevanceQuery?): Promise<SessionBootstrap>
411
+ search(query, options?): Promise<{ turns, knowledge }>
412
+ searchCrossScope(query, level, options?): Promise<{ knowledge }>
413
+ recall(timeRange): Promise<{ turns, workingMemory, knowledge, workItems }>
414
+ pollForChanges(since, options?): Promise<KnowledgeMemory[]>
415
+
416
+ // --- Knowledge ---
417
+ learnFact(fact, factType, confidence?): Promise<KnowledgeMemory>
418
+ trackWorkItem(title, kind?, status?, detail?): Promise<WorkItem>
419
+ inspectKnowledge(id): Promise<{ knowledge, evidence, audits }>
420
+ listKnowledge(options?): Promise<PaginatedResult<KnowledgeMemory>>
421
+
422
+ // --- System ---
423
+ forceCompact(): Promise<CompactionResult | null>
424
+ runMaintenance(policy?): Promise<MaintenanceReport>
425
+ runReverification(options?): Promise<{ reverifiedIds, demotedIds }>
426
+ close(): Promise<void>
427
+ }
428
+ ```
429
+
430
+ ### MemoryRuntime
431
+
432
+ Returned by `createMemoryRuntime(manager)`. Higher-level hooks for model call integration.
433
+
434
+ ```typescript
435
+ interface MemoryRuntime {
436
+ startSession(relevanceQuery?): Promise<{ bootstrap, bootstrapPrompt }>
437
+ resumeSession(relevanceQuery?): Promise<{ bootstrap, bootstrapPrompt }>
438
+ beforeModelCall(input): Promise<{
439
+ bootstrap, context, bootstrapPrompt, prompt, messages
440
+ }>
441
+ afterModelCall(input): Promise<{ exchange, trackedWorkItems }>
442
+ wrapModelCall(modelFn, input, actors?): Promise<{
443
+ result, runtime, exchange, trackedWorkItems
444
+ }>
445
+ }
446
+ ```
447
+
448
+ ### MemoryContext
449
+
450
+ The structured object returned by `getContext()`. Ready for prompt injection.
451
+
452
+ ```typescript
453
+ interface MemoryContext {
454
+ mode: 'chat' | 'coding' | 'autonomous_agent' | 'review';
455
+ activeTurns: Turn[];
456
+ workingMemory: WorkingMemory | null;
457
+ trustedCoreMemory: KnowledgeMemory[]; // High-confidence, durable facts
458
+ taskRelevantKnowledge: KnowledgeMemory[]; // Matched to current query
459
+ provisionalKnowledge: KnowledgeMemory[]; // Not yet fully trusted
460
+ disputedKnowledge: KnowledgeMemory[]; // Contradicted facts
461
+ relevantKnowledge: KnowledgeMemory[]; // All selected facts
462
+ recentSummaries: WorkingMemory[];
463
+ currentObjective: string | null;
464
+ activeObjectives: WorkItem[];
465
+ unresolvedWork: string[];
466
+ knowledgeSelectionReasons: KnowledgeSelectionReason[];
467
+ tokenEstimate: number;
468
+ }
469
+ ```
470
+
471
+ ---
472
+
473
+ ## Configuration
474
+
475
+ ### createMemory() Options
476
+
477
+ ```typescript
478
+ createMemory({
479
+ // Storage
480
+ adapter?: 'sqlite' | 'memory' | StorageAdapter,
481
+ path?: string,
482
+
483
+ // Identity
484
+ scope?: string | MemoryScope,
485
+ sessionId?: string,
486
+
487
+ // Behavior
488
+ preset?: 'ai_ide' | 'chat_agent' | 'autonomous_agent',
489
+ qualityMode?: 'fast_adoption' | 'balanced_memory' | 'high_fidelity_memory',
490
+
491
+ // Components (auto-resolved if omitted)
492
+ summarizer?: 'extractive' | 'claude' | 'openai' | Summarizer,
493
+ extractor?: 'regex' | 'heuristic' | 'claude' | 'openai' | Extractor | false,
494
+ embeddingGenerator?: 'local' | EmbeddingGenerator | false,
495
+
496
+ // Fine-tuning (partial overrides merge with preset/quality defaults)
497
+ policies?: {
498
+ monitor?: Partial<MonitorPolicy>,
499
+ extraction?: Partial<ExtractionPolicy>,
500
+ context?: Partial<ContextPolicy>,
501
+ maintenance?: Partial<MaintenancePolicy>,
502
+ },
503
+
504
+ // Automation
505
+ autoCompact?: boolean, // default: true
506
+ autoExtract?: boolean, // default: true (when extractor present)
507
+ crossScopeLevel?: ScopeLevel,
508
+
509
+ // Observability
510
+ logger?: Logger,
511
+ onEvent?: EventHook,
512
+ redactText?: (input: { kind: string; text: string }) => string,
513
+
514
+ // Resilience
515
+ failurePolicy?: {
516
+ summarizer?: 'throw' | 'retry_once' | 'log_and_continue',
517
+ extractor?: 'throw' | 'retry_once' | 'log_and_continue' | 'disable_auto_extract',
518
+ },
519
+ })
520
+ ```
521
+
522
+ ### Policy Reference
523
+
524
+ <details>
525
+ <summary><strong>MonitorPolicy</strong> — when compaction triggers</summary>
526
+
527
+ | Field | Default | Description |
528
+ |-------|---------|-------------|
529
+ | `softTurnThreshold` | 15 | Turns before soft compaction is considered |
530
+ | `hardTurnThreshold` | 30 | Turns that force compaction |
531
+ | `softTokenThreshold` | 3000 | Token estimate for soft trigger |
532
+ | `hardTokenThreshold` | 6000 | Token estimate that forces compaction |
533
+ | `softRetainTurns` | 12 | Turns to keep after soft compaction |
534
+ | `hardRetainTurns` | 8 | Turns to keep after hard compaction |
535
+ | `intraSessionGapSeconds` | 1800 | Idle gap that triggers session_gap compaction |
536
+
537
+ </details>
538
+
539
+ <details>
540
+ <summary><strong>ExtractionPolicy</strong> — how facts are extracted and promoted</summary>
541
+
542
+ | Field | Default | Description |
543
+ |-------|---------|-------------|
544
+ | `autoExtractAfterCompaction` | true | Run extraction after each compaction |
545
+ | `maxFactsPerExtraction` | 10 | Max facts per compaction cycle |
546
+ | `deduplicateFacts` | true | Deduplicate against existing knowledge |
547
+ | `minConfidenceForPromotion` | `'medium'` | Minimum confidence for storage |
548
+ | `trustPromotionThreshold` | 0.7 | Score required for `trusted` state |
549
+ | `contradictionDisputeThreshold` | 0.35 | Score that marks facts `disputed` |
550
+ | `requireGroundingForTrusted` | true | Require evidence in source turns |
551
+ | `conflictStrategy` | `'supersede'` | How to handle conflicting facts |
552
+
553
+ </details>
554
+
555
+ <details>
556
+ <summary><strong>ContextPolicy</strong> — how knowledge is selected for prompts</summary>
557
+
558
+ | Field | Default | Description |
559
+ |-------|---------|-------------|
560
+ | `mode` | `'chat'` | Scoring profile: `chat`, `coding`, `autonomous_agent`, `review` |
561
+ | `maxKnowledgeItems` | 20 | Max facts in assembled context |
562
+ | `maxRecentSummaries` | 3 | Max summaries in context |
563
+ | `tokenBudget` | unlimited | Token cap for context |
564
+ | `lexicalWeight` | 1.0 | Full-text search weight |
565
+ | `semanticWeight` | 1.0 | Embedding similarity weight |
566
+ | `recencyWeight` | 1.0 | Access recency weight |
567
+ | `trustWeight` | 1.3 | Knowledge confidence weight |
568
+ | `importanceWeight` | 0.25 | Access frequency weight |
569
+ | `diversityPenalty` | 0.2 | Same-type clustering penalty |
570
+
571
+ </details>
572
+
573
+ <details>
574
+ <summary><strong>MaintenancePolicy</strong> — data lifecycle and cleanup</summary>
575
+
576
+ | Field | Default | Description |
577
+ |-------|---------|-------------|
578
+ | `workingMemoryTtlSeconds` | 30 days | Summary expiry |
579
+ | `completedWorkItemTtlSeconds` | 14 days | Completed work item cleanup |
580
+ | `knowledgeStaleAfterSeconds` | 60 days | Knowledge staleness threshold |
581
+ | `minKnowledgeAccessCount` | 1 | Minimum accesses to avoid retirement |
582
+ | `maxActiveKnowledgeItems` | 500 | Hard cap on active knowledge |
583
+ | `reverificationCadenceDays` | 30 | Days between reverification checks |
584
+ | `trustedCoreRetentionDays` | 365 | Retention for identity/preference/constraint |
585
+ | `provisionalRetentionDays` | 7 | Retention for provisional facts |
586
+
587
+ </details>
588
+
589
+ ---
590
+
591
+ ## Observability
592
+
593
+ ### Event Hooks
594
+
595
+ ```typescript
596
+ const memory = createMemory({
597
+ onEvent: (event) => {
598
+ // event.type: 'compaction' | 'extraction' | 'promotion' | 'retrieval' |
599
+ // 'search' | 'maintenance' | 'capability' | 'knowledge_change'
600
+ console.log(`[${event.type}] scope=${event.scope.scope_id} duration=${event.durationMs}ms`);
601
+ },
602
+ });
603
+ ```
604
+
605
+ ### Typed Event Emitter
606
+
607
+ ```typescript
608
+ import { createMemoryEventEmitter } from 'ai-memory-layer';
609
+
610
+ const emitter = createMemoryEventEmitter();
611
+ emitter.on('compaction', (e) => metrics.track('compaction', e.durationMs));
612
+ emitter.on('extraction', (e) => metrics.track('facts_extracted', e.meta.factCount));
613
+
614
+ const memory = createMemory({ eventEmitter: emitter });
615
+ ```
616
+
617
+ ### PII Redaction
618
+
619
+ ```typescript
620
+ const memory = createMemory({
621
+ redactText: ({ kind, text }) =>
622
+ text.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[REDACTED-SSN]'),
623
+ });
624
+ ```
625
+
626
+ ---
627
+
628
+ ## Surfaces
629
+
630
+ One memory engine, multiple access patterns:
631
+
632
+ | Surface | Best For | How to Start |
633
+ |---------|---------|-------------|
634
+ | **Node package** | In-process agents, IDEs | `import { createMemory } from 'ai-memory-layer'` |
635
+ | **HTTP API** | Polyglot services, hosted deployments | `npx memory-layer serve --transport http` |
636
+ | **MCP server** | Tool ecosystems that speak MCP | `npx memory-layer serve --transport mcp` |
637
+ | **CLI** | Inspection, admin, debugging | `npx memory-layer inspect` |
638
+ | **Python client** | Python agents consuming the HTTP API | `pip install memory-layer-client` |
639
+
640
+ The Node package is the source of truth. HTTP mirrors it over REST ([`openapi.yaml`](openapi.yaml)). MCP and CLI are operational wrappers. The Python client follows the HTTP contract.
641
+
642
+ ---
643
+
644
+ ## Storage
645
+
646
+ | Backend | Best For | Install |
647
+ |---------|---------|---------|
648
+ | **In-memory** | Tests, prototypes, zero-friction | Built-in |
649
+ | **SQLite** | Single-process production, local agents | `npm install better-sqlite3` |
650
+ | **PostgreSQL + pgvector** | Multi-writer, hosted, high-volume | `npm install pg` |
651
+
652
+ SQLite is the low-friction path. Postgres + pgvector is the strongest scaling path with ANN indexing for semantic retrieval.
653
+
654
+ ---
655
+
656
+ ## Embeddings
657
+
658
+ ```typescript
659
+ // Auto-resolved: local heuristic if no API key, OpenAI/Voyage if key present
660
+ const memory = createMemory(); // just works
661
+
662
+ // Explicit local (offline, pure-JS)
663
+ const memory = createMemory({ embeddingGenerator: 'local' });
664
+
665
+ // Explicit provider
666
+ import { createOpenAIEmbeddingGenerator } from 'ai-memory-layer';
667
+ const memory = createMemory({
668
+ embeddingGenerator: createOpenAIEmbeddingGenerator({ apiKey: process.env.OPENAI_API_KEY }),
669
+ });
670
+
671
+ // Custom
672
+ const memory = createMemory({
673
+ embeddingGenerator: async (texts) => texts.map(t => new Float32Array(/* your vectors */)),
674
+ });
675
+ ```
676
+
677
+ Built-in resilience for provider embeddings: `withRetry()`, `batchedGenerate()`, `createCachedEmbeddingGenerator()`.
678
+
679
+ ---
680
+
681
+ ## Testing & Evals
682
+
683
+ ### Unit Tests
684
+
685
+ ```bash
686
+ npm test # 257 test cases across 30+ files
687
+ npm run test:coverage # with coverage reporting
688
+ ```
689
+
690
+ ### Memory Quality Gate
691
+
692
+ A 14-metric behavioral eval suite that acts as a hard release gate:
693
+
694
+ ```bash
695
+ npm run eval:memory-quality:enforce # all 14 metrics must pass
696
+ npm run eval:memory-quality:delta:enforce # must not regress from baseline
697
+ ```
698
+
699
+ Metrics include: constraint retention, preference retention, identity retention, update correctness, false memory rate, contradiction resolution, trusted memory precision/recall, scope isolation, compaction fidelity, and maintenance fidelity.
700
+
701
+ Current baseline: **100/100** on all 14 metrics.
702
+
703
+ ### Full Release Gate
704
+
705
+ ```bash
706
+ npm run release:check
707
+ ```
708
+
709
+ Runs: lint, test coverage, retrieval eval, scenario eval, memory quality gate, delta regression check, Python client checks, platform quality proof (HTTP + Node CLI + Python CLI), and package validation.
710
+
711
+ ---
712
+
713
+ ## Docker
714
+
715
+ ```bash
716
+ docker build -t memory-layer .
717
+ docker run --rm -p 3100:3100 -v "$(pwd)/data:/data" memory-layer
718
+ ```
719
+
720
+ ---
721
+
722
+ ## Examples
723
+
724
+ | Example | What It Shows |
725
+ |---------|--------------|
726
+ | [`zero-config.ts`](examples/zero-config.ts) | Ephemeral memory, no setup |
727
+ | [`chat-assistant.ts`](examples/chat-assistant.ts) | Claude-backed conversation agent |
728
+ | [`ai-ide.ts`](examples/ai-ide.ts) | OpenAI-backed coding assistant with work items |
729
+ | [`autonomous-agent.ts`](examples/autonomous-agent.ts) | Claude agent wrapper with work item inference |
730
+ | [`dark-factory.ts`](examples/dark-factory.ts) | Autonomous loop with streaming and maintenance |
731
+ | [`tool-calling-agent.ts`](examples/tool-calling-agent.ts) | OpenAI/Claude tool schemas |
732
+ | [`mcp-server.ts`](examples/mcp-server.ts) | MCP tool adapter |
733
+ | [`hosted-service.ts`](examples/hosted-service.ts) | Standalone HTTP service |
734
+ | [`vercel-ai.ts`](examples/vercel-ai.ts) | Vercel AI SDK wrapper |
735
+ | [`langchain.ts`](examples/langchain.ts) | LangChain memory bridge |
736
+ | [`multi-agent-postgres.ts`](examples/multi-agent-postgres.ts) | Shared Postgres memory across agents |
737
+ | [`python-client/agent.py`](examples/python-client/agent.py) | Python agent consuming HTTP API |
738
+
739
+ ---
740
+
741
+ ## Export / Import
742
+
743
+ ```bash
744
+ node scripts/export-memory.mjs ./data/memory.db ./backup.json
745
+ node scripts/import-memory.mjs ./data/restored.db ./backup.json
746
+ ```
747
+
748
+ ---
749
+
750
+ ## Further Reading
751
+
752
+ - [Deployment Guide](docs/DEPLOYMENT.md) — embedded, HTTP, MCP, Docker
753
+ - [Integration Patterns](docs/INTEGRATIONS.md) — AI IDE, hosted service, autonomous agent, framework adapters
754
+ - [Memory Quality Rubric](docs/MEMORY_QUALITY_RUBRIC.md) — the 14-metric eval framework
755
+ - [Release Gate](docs/MEMORY_QUALITY_RELEASE_GATE.md) — how quality gates enforce the baseline
756
+ - [OpenAPI Spec](openapi.yaml) — full HTTP API contract
757
+ - [Security Guide](docs/SECURITY.md)
758
+
759
+ ---
760
+
761
+ ## Requirements
762
+
763
+ - Node 20+
764
+ - MIT licensed
765
+ - Optional provider SDKs are dynamically imported — no hard dependencies on `@anthropic-ai/sdk`, `openai`, `better-sqlite3`, or `pg`