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.
- package/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +765 -0
- package/bin/memory-server.mjs +157 -0
- package/dist/adapters/memory/embeddings.d.ts +4 -0
- package/dist/adapters/memory/embeddings.d.ts.map +1 -0
- package/dist/adapters/memory/embeddings.js +53 -0
- package/dist/adapters/memory/embeddings.js.map +1 -0
- package/dist/adapters/memory/index.d.ts +7 -0
- package/dist/adapters/memory/index.d.ts.map +1 -0
- package/dist/adapters/memory/index.js +650 -0
- package/dist/adapters/memory/index.js.map +1 -0
- package/dist/adapters/postgres/index.d.ts +38 -0
- package/dist/adapters/postgres/index.d.ts.map +1 -0
- package/dist/adapters/postgres/index.js +982 -0
- package/dist/adapters/postgres/index.js.map +1 -0
- package/dist/adapters/sqlite/embeddings.d.ts +5 -0
- package/dist/adapters/sqlite/embeddings.d.ts.map +1 -0
- package/dist/adapters/sqlite/embeddings.js +122 -0
- package/dist/adapters/sqlite/embeddings.js.map +1 -0
- package/dist/adapters/sqlite/index.d.ts +8 -0
- package/dist/adapters/sqlite/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/index.js +839 -0
- package/dist/adapters/sqlite/index.js.map +1 -0
- package/dist/adapters/sqlite/mappers.d.ts +40 -0
- package/dist/adapters/sqlite/mappers.d.ts.map +1 -0
- package/dist/adapters/sqlite/mappers.js +95 -0
- package/dist/adapters/sqlite/mappers.js.map +1 -0
- package/dist/adapters/sqlite/schema.d.ts +4 -0
- package/dist/adapters/sqlite/schema.d.ts.map +1 -0
- package/dist/adapters/sqlite/schema.js +394 -0
- package/dist/adapters/sqlite/schema.js.map +1 -0
- package/dist/adapters/sync-to-async.d.ts +15 -0
- package/dist/adapters/sync-to-async.d.ts.map +1 -0
- package/dist/adapters/sync-to-async.js +95 -0
- package/dist/adapters/sync-to-async.js.map +1 -0
- package/dist/cli/inspect.d.ts +34 -0
- package/dist/cli/inspect.d.ts.map +1 -0
- package/dist/cli/inspect.js +190 -0
- package/dist/cli/inspect.js.map +1 -0
- package/dist/contracts/async-storage.d.ts +86 -0
- package/dist/contracts/async-storage.d.ts.map +1 -0
- package/dist/contracts/async-storage.js +2 -0
- package/dist/contracts/async-storage.js.map +1 -0
- package/dist/contracts/embedding.d.ts +22 -0
- package/dist/contracts/embedding.d.ts.map +1 -0
- package/dist/contracts/embedding.js +2 -0
- package/dist/contracts/embedding.js.map +1 -0
- package/dist/contracts/identity.d.ts +29 -0
- package/dist/contracts/identity.d.ts.map +1 -0
- package/dist/contracts/identity.js +34 -0
- package/dist/contracts/identity.js.map +1 -0
- package/dist/contracts/observability.d.ts +18 -0
- package/dist/contracts/observability.d.ts.map +1 -0
- package/dist/contracts/observability.js +7 -0
- package/dist/contracts/observability.js.map +1 -0
- package/dist/contracts/policy.d.ts +108 -0
- package/dist/contracts/policy.d.ts.map +1 -0
- package/dist/contracts/policy.js +107 -0
- package/dist/contracts/policy.js.map +1 -0
- package/dist/contracts/storage.d.ts +78 -0
- package/dist/contracts/storage.d.ts.map +1 -0
- package/dist/contracts/storage.js +2 -0
- package/dist/contracts/storage.js.map +1 -0
- package/dist/contracts/types.d.ts +381 -0
- package/dist/contracts/types.d.ts.map +1 -0
- package/dist/contracts/types.js +94 -0
- package/dist/contracts/types.js.map +1 -0
- package/dist/core/circuit-breaker.d.ts +11 -0
- package/dist/core/circuit-breaker.d.ts.map +1 -0
- package/dist/core/circuit-breaker.js +38 -0
- package/dist/core/circuit-breaker.js.map +1 -0
- package/dist/core/context.d.ts +56 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +345 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/events.d.ts +8 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +25 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/extractor.d.ts +37 -0
- package/dist/core/extractor.d.ts.map +1 -0
- package/dist/core/extractor.js +448 -0
- package/dist/core/extractor.js.map +1 -0
- package/dist/core/formatter.d.ts +25 -0
- package/dist/core/formatter.d.ts.map +1 -0
- package/dist/core/formatter.js +97 -0
- package/dist/core/formatter.js.map +1 -0
- package/dist/core/knowledge-lifecycle.d.ts +15 -0
- package/dist/core/knowledge-lifecycle.d.ts.map +1 -0
- package/dist/core/knowledge-lifecycle.js +103 -0
- package/dist/core/knowledge-lifecycle.js.map +1 -0
- package/dist/core/maintenance.d.ts +13 -0
- package/dist/core/maintenance.d.ts.map +1 -0
- package/dist/core/maintenance.js +102 -0
- package/dist/core/maintenance.js.map +1 -0
- package/dist/core/manager.d.ts +110 -0
- package/dist/core/manager.d.ts.map +1 -0
- package/dist/core/manager.js +640 -0
- package/dist/core/manager.js.map +1 -0
- package/dist/core/monitor.d.ts +73 -0
- package/dist/core/monitor.d.ts.map +1 -0
- package/dist/core/monitor.js +395 -0
- package/dist/core/monitor.js.map +1 -0
- package/dist/core/orchestrator.d.ts +64 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +916 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/presets.d.ts +15 -0
- package/dist/core/presets.d.ts.map +1 -0
- package/dist/core/presets.js +99 -0
- package/dist/core/presets.js.map +1 -0
- package/dist/core/provider-managers.d.ts +47 -0
- package/dist/core/provider-managers.d.ts.map +1 -0
- package/dist/core/provider-managers.js +112 -0
- package/dist/core/provider-managers.js.map +1 -0
- package/dist/core/quick.d.ts +62 -0
- package/dist/core/quick.d.ts.map +1 -0
- package/dist/core/quick.js +300 -0
- package/dist/core/quick.js.map +1 -0
- package/dist/core/retrieval.d.ts +29 -0
- package/dist/core/retrieval.d.ts.map +1 -0
- package/dist/core/retrieval.js +150 -0
- package/dist/core/retrieval.js.map +1 -0
- package/dist/core/runtime.d.ts +67 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +84 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/streaming.d.ts +37 -0
- package/dist/core/streaming.d.ts.map +1 -0
- package/dist/core/streaming.js +51 -0
- package/dist/core/streaming.js.map +1 -0
- package/dist/core/sync.d.ts +13 -0
- package/dist/core/sync.d.ts.map +1 -0
- package/dist/core/sync.js +46 -0
- package/dist/core/sync.js.map +1 -0
- package/dist/core/telemetry.d.ts +8 -0
- package/dist/core/telemetry.d.ts.map +1 -0
- package/dist/core/telemetry.js +14 -0
- package/dist/core/telemetry.js.map +1 -0
- package/dist/core/tokens.d.ts +8 -0
- package/dist/core/tokens.d.ts.map +1 -0
- package/dist/core/tokens.js +59 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core/trust.d.ts +23 -0
- package/dist/core/trust.d.ts.map +1 -0
- package/dist/core/trust.js +164 -0
- package/dist/core/trust.js.map +1 -0
- package/dist/core/validation.d.ts +36 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +185 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/embeddings/local.d.ts +5 -0
- package/dist/embeddings/local.d.ts.map +1 -0
- package/dist/embeddings/local.js +128 -0
- package/dist/embeddings/local.js.map +1 -0
- package/dist/embeddings/openai.d.ts +26 -0
- package/dist/embeddings/openai.d.ts.map +1 -0
- package/dist/embeddings/openai.js +48 -0
- package/dist/embeddings/openai.js.map +1 -0
- package/dist/embeddings/resilience.d.ts +5 -0
- package/dist/embeddings/resilience.d.ts.map +1 -0
- package/dist/embeddings/resilience.js +53 -0
- package/dist/embeddings/resilience.js.map +1 -0
- package/dist/embeddings/voyage.d.ts +30 -0
- package/dist/embeddings/voyage.d.ts.map +1 -0
- package/dist/embeddings/voyage.js +53 -0
- package/dist/embeddings/voyage.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/claude-agent.d.ts +21 -0
- package/dist/integrations/claude-agent.d.ts.map +1 -0
- package/dist/integrations/claude-agent.js +44 -0
- package/dist/integrations/claude-agent.js.map +1 -0
- package/dist/integrations/claude-tools.d.ts +18 -0
- package/dist/integrations/claude-tools.d.ts.map +1 -0
- package/dist/integrations/claude-tools.js +60 -0
- package/dist/integrations/claude-tools.js.map +1 -0
- package/dist/integrations/langchain.d.ts +24 -0
- package/dist/integrations/langchain.d.ts.map +1 -0
- package/dist/integrations/langchain.js +48 -0
- package/dist/integrations/langchain.js.map +1 -0
- package/dist/integrations/mcp.d.ts +23 -0
- package/dist/integrations/mcp.d.ts.map +1 -0
- package/dist/integrations/mcp.js +60 -0
- package/dist/integrations/mcp.js.map +1 -0
- package/dist/integrations/middleware.d.ts +15 -0
- package/dist/integrations/middleware.d.ts.map +1 -0
- package/dist/integrations/middleware.js +27 -0
- package/dist/integrations/middleware.js.map +1 -0
- package/dist/integrations/openai-tools.d.ts +21 -0
- package/dist/integrations/openai-tools.d.ts.map +1 -0
- package/dist/integrations/openai-tools.js +69 -0
- package/dist/integrations/openai-tools.js.map +1 -0
- package/dist/integrations/vercel-ai.d.ts +19 -0
- package/dist/integrations/vercel-ai.d.ts.map +1 -0
- package/dist/integrations/vercel-ai.js +41 -0
- package/dist/integrations/vercel-ai.js.map +1 -0
- package/dist/server/http-server.d.ts +61 -0
- package/dist/server/http-server.d.ts.map +1 -0
- package/dist/server/http-server.js +684 -0
- package/dist/server/http-server.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp-server.d.ts +61 -0
- package/dist/server/mcp-server.d.ts.map +1 -0
- package/dist/server/mcp-server.js +465 -0
- package/dist/server/mcp-server.js.map +1 -0
- package/dist/summarizers/claude.d.ts +11 -0
- package/dist/summarizers/claude.d.ts.map +1 -0
- package/dist/summarizers/claude.js +39 -0
- package/dist/summarizers/claude.js.map +1 -0
- package/dist/summarizers/client.d.ts +23 -0
- package/dist/summarizers/client.d.ts.map +1 -0
- package/dist/summarizers/client.js +24 -0
- package/dist/summarizers/client.js.map +1 -0
- package/dist/summarizers/extractive.d.ts +6 -0
- package/dist/summarizers/extractive.d.ts.map +1 -0
- package/dist/summarizers/extractive.js +204 -0
- package/dist/summarizers/extractive.js.map +1 -0
- package/dist/summarizers/extractor.d.ts +12 -0
- package/dist/summarizers/extractor.d.ts.map +1 -0
- package/dist/summarizers/extractor.js +75 -0
- package/dist/summarizers/extractor.js.map +1 -0
- package/dist/summarizers/openai.d.ts +11 -0
- package/dist/summarizers/openai.d.ts.map +1 -0
- package/dist/summarizers/openai.js +41 -0
- package/dist/summarizers/openai.js.map +1 -0
- package/dist/summarizers/prompts.d.ts +11 -0
- package/dist/summarizers/prompts.d.ts.map +1 -0
- package/dist/summarizers/prompts.js +104 -0
- package/dist/summarizers/prompts.js.map +1 -0
- package/docs/DEPLOYMENT.md +84 -0
- package/docs/INTEGRATIONS.md +64 -0
- package/docs/MEMORY_QUALITY_BASELINE.md +55 -0
- package/docs/MEMORY_QUALITY_RELEASE_GATE.md +63 -0
- package/docs/MEMORY_QUALITY_RUBRIC.md +249 -0
- package/docs/OPERATIONS.md +49 -0
- package/docs/SECURITY.md +25 -0
- package/openapi.yaml +843 -0
- 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> •
|
|
12
|
+
<a href="#how-it-works">How It Works</a> •
|
|
13
|
+
<a href="#integration-patterns">Integrations</a> •
|
|
14
|
+
<a href="#python">Python</a> •
|
|
15
|
+
<a href="#api-reference">API</a> •
|
|
16
|
+
<a href="#configuration">Config</a> •
|
|
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`
|