formative-memory 0.1.0 → 0.2.1
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/README.md +153 -123
- package/dist/cli.js +1 -1
- package/dist/{db-D2pzT6fw.js → db-D1Sc76VE.js} +1 -1
- package/dist/index.js +649 -227
- package/openclaw.plugin.json +82 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,93 +1,118 @@
|
|
|
1
1
|
# Formative Memory
|
|
2
2
|
|
|
3
|
-
**Memory that
|
|
3
|
+
**Memory that actively forms around what matters.**
|
|
4
4
|
|
|
5
|
-
Formative Memory is an
|
|
5
|
+
Formative Memory is an [OpenClaw](https://openclaw.ai) plugin that gives your agent a self-optimizing memory. It strengthens relevant context through use, weakens unused details, and automatically builds associations between related concepts. In each session, it helps by injecting relevant memories into context before every response. It also evaluates memory quality — each retrieval affects the strength of the memory, so useful ones rise and unused ones fade. Every night, your agent sleeps: a consolidation process prunes and combines memories to keep the quality of recalled context high.
|
|
6
6
|
|
|
7
|
+
Over time, this combination process builds beyond raw facts into interpretations, nuanced awareness, and deeper understanding.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/formative-memory)
|
|
7
10
|
[](LICENSE)
|
|
8
11
|

|
|
9
12
|

|
|
10
|
-

|
|
11
13
|
|
|
12
14
|
---
|
|
13
15
|
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
Traditional memory systems treat all information equally and rely on recency to decide what's relevant. Over time, noise accumulates: duplicates pile up, outdated facts coexist with corrections, and important patterns get buried under recent but trivial details. The more you use memory, the harder it becomes to find what matters. You end up teaching the same lessons over and over.
|
|
16
|
+
## How It Works
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
### Recall
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Before every response, the plugin searches for memories relevant to
|
|
21
|
+
the current conversation using hybrid search (embedding similarity +
|
|
22
|
+
BM25 full-text), ranked by memory strength. Matching memories are
|
|
23
|
+
injected into the agent's context automatically. Each retrieval
|
|
24
|
+
strengthens the memories that were surfaced.
|
|
21
25
|
|
|
22
|
-
```bash
|
|
23
|
-
npm install formative-memory
|
|
24
26
|
```
|
|
27
|
+
User: "Do you remember that restaurant? The one by the beach
|
|
28
|
+
last summer. I'm trying to book for our anniversary."
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
Injected memories:
|
|
31
|
+
[a3f2|fact|strength=0.82] "Dinner at Maininki, Hanko, July 2024"
|
|
32
|
+
[b7d1|event|2026-07-04] "Wedding anniversary — 12 years"
|
|
33
|
+
[c9f3|preference|str=0.74] "Sanna loves peonies"
|
|
34
|
+
[d2e6|fact|2026-07-02] "Sanna: private doctor's appointment"
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"extensions": ["formative-memory"]
|
|
31
|
-
}
|
|
36
|
+
Agent: "Of course! It was Maininki, in Hanko. Shall I book a table?
|
|
37
|
+
Your 12th anniversary is coming up on July 4th."
|
|
32
38
|
```
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- **Auto-recall** surfaces relevant memories before every response
|
|
37
|
-
- **Agent tools** let the agent store, search, and rate memories
|
|
38
|
-
- **Consolidation** runs automatically to maintain memory quality
|
|
39
|
-
|
|
40
|
-
No configuration needed — sensible defaults are built in.
|
|
41
|
-
|
|
42
|
-
## How It Works
|
|
40
|
+
The agent sees recalled memories as context, not instructions — this
|
|
41
|
+
reduces prompt injection risk from stored content.
|
|
43
42
|
|
|
44
|
-
###
|
|
43
|
+
### Capture
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
Memories are collected in two ways. The agent can store a memory
|
|
46
|
+
explicitly with `memory_store`, and auto-capture extracts durable
|
|
47
|
+
facts from conversations automatically after each turn.
|
|
47
48
|
|
|
48
49
|
```
|
|
49
|
-
|
|
50
|
-
→
|
|
51
|
-
|
|
50
|
+
After the turn above, auto-capture extracts:
|
|
51
|
+
→ store("Booking anniversary dinner at Maininki", type: event,
|
|
52
|
+
temporal_anchor: 2026-07-04, temporal_state: future)
|
|
53
|
+
|
|
54
|
+
A later turn — user asks for Sanna's favorite foods:
|
|
55
|
+
Agent explicitly stores:
|
|
56
|
+
→ memory_store("Sanna's favorites: salmon soup (her mother's recipe,
|
|
57
|
+
no cream), pistachio ice cream, meat pies from Market Hall
|
|
58
|
+
on Saturdays", type: preference)
|
|
59
|
+
→ id: e8b2a1f4, strength: 1.0
|
|
52
60
|
```
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
Each memory is content-addressed (SHA-256) — same content always
|
|
63
|
+
produces the same ID, so duplicates are prevented by design.
|
|
55
64
|
|
|
56
|
-
|
|
65
|
+
### Consolidate
|
|
66
|
+
|
|
67
|
+
Every night, the agent sleeps. A consolidation process runs through
|
|
68
|
+
the accumulated memories:
|
|
69
|
+
|
|
70
|
+
| Step | What happens |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| **Reinforce** | Memories that influenced responses gain strength |
|
|
73
|
+
| **Decay** | All strengths decrease — recent memories fade faster than established ones |
|
|
74
|
+
| **Associate** | Memories retrieved together form links; connections grow stronger with co-occurrence |
|
|
75
|
+
| **Temporal shift** | Future memories transition to present or past based on anchor dates |
|
|
76
|
+
| **Prune** | Weak memories and associations are removed |
|
|
77
|
+
| **Merge** | Similar memories are combined into coherent summaries |
|
|
57
78
|
|
|
58
79
|
```
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
80
|
+
Before consolidation:
|
|
81
|
+
[a3f2|strength=0.82] "Dinner at Maininki, Hanko, July 2024"
|
|
82
|
+
[f1c4|strength=0.65] "Maininki — beachfront restaurant, good wine list"
|
|
83
|
+
[a9b3|strength=0.41] "Tried booking Maininki in June, fully booked"
|
|
84
|
+
|
|
85
|
+
After consolidation:
|
|
86
|
+
[g7e2|strength=1.00] "Maininki, Hanko: beachfront restaurant with good
|
|
87
|
+
wine list. Visited July 2024. Book early — fills up in summer."
|
|
88
|
+
|
|
89
|
+
Associations formed:
|
|
90
|
+
"Maininki" ←0.7→ "Wedding anniversary"
|
|
91
|
+
"Maininki" ←0.4→ "Sanna loves peonies"
|
|
62
92
|
```
|
|
63
93
|
|
|
64
|
-
|
|
94
|
+
All mutation happens during consolidation — live chat stays fast and
|
|
95
|
+
predictable. Over time, simple facts combine into richer structures:
|
|
96
|
+
merged summaries, connected associations, and deeper understanding.
|
|
65
97
|
|
|
66
|
-
|
|
98
|
+
## Quick Start
|
|
67
99
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
2. "Migrated to Tailwind v4 last week" (strength: 0.71, score: 0.64)
|
|
73
|
-
3. "tailwind.config.ts in project root" (strength: 0.68, score: 0.51)
|
|
100
|
+
Install the plugin:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
openclaw plugins install formative-memory
|
|
74
104
|
```
|
|
75
105
|
|
|
76
|
-
|
|
106
|
+
This installs from npm, enables the plugin, and assigns it the memory
|
|
107
|
+
slot automatically. Restart the gateway to load the plugin.
|
|
77
108
|
|
|
78
|
-
|
|
109
|
+
That's it. The plugin works out of the box:
|
|
79
110
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
| **Decay** | All strengths decrease — working memory fades faster than consolidated |
|
|
84
|
-
| **Associate** | Co-retrieved memories form or strengthen links; transitive paths are discovered |
|
|
85
|
-
| **Temporal shift** | Future memories transition to present or past based on anchor dates |
|
|
86
|
-
| **Prune** | Very weak memories and associations are deleted |
|
|
87
|
-
| **Merge** | Similar memories are combined via LLM into coherent summaries |
|
|
88
|
-
| **Cleanup** | Old provenance records are garbage collected |
|
|
111
|
+
- **Auto-capture** records conversations for consolidation
|
|
112
|
+
- **Auto-recall** surfaces relevant memories before every response
|
|
113
|
+
- **Consolidation** runs automatically to maintain memory quality
|
|
89
114
|
|
|
90
|
-
|
|
115
|
+
No configuration needed — sensible defaults are built in.
|
|
91
116
|
|
|
92
117
|
## Memory Tools
|
|
93
118
|
|
|
@@ -96,29 +121,34 @@ The plugin registers five tools the agent can use during conversation:
|
|
|
96
121
|
| Tool | What it does |
|
|
97
122
|
|------|-------------|
|
|
98
123
|
| `memory_store` | Store a new memory with type and optional temporal anchor |
|
|
99
|
-
| `memory_search` | Search by meaning and keywords, ranked by relevance
|
|
124
|
+
| `memory_search` | Search by meaning and keywords, ranked by relevance x strength |
|
|
100
125
|
| `memory_get` | Retrieve a specific memory by ID |
|
|
101
|
-
| `memory_feedback` | Rate a memory's usefulness — feeds into reinforcement |
|
|
102
|
-
| `memory_browse` | Browse all memories sorted by importance |
|
|
126
|
+
| `memory_feedback` | Rate a memory's usefulness (1-5) — feeds into reinforcement |
|
|
127
|
+
| `memory_browse` | Browse all memories sorted by importance, with type diversity |
|
|
103
128
|
|
|
104
129
|
Memory types: `fact`, `preference`, `decision`, `plan`, `observation`.
|
|
105
130
|
|
|
106
131
|
## Configuration
|
|
107
132
|
|
|
108
|
-
All settings are optional
|
|
133
|
+
All settings are optional — defaults are designed to work out of the box.
|
|
134
|
+
Configuration goes in `openclaw.json` under the plugin entry:
|
|
109
135
|
|
|
110
136
|
```json
|
|
111
137
|
{
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
138
|
+
"plugins": {
|
|
139
|
+
"entries": {
|
|
140
|
+
"formative-memory": {
|
|
141
|
+
"enabled": true,
|
|
142
|
+
"config": {
|
|
143
|
+
"autoRecall": true,
|
|
144
|
+
"autoCapture": true,
|
|
145
|
+
"requireEmbedding": true,
|
|
146
|
+
"embedding": {
|
|
147
|
+
"provider": "auto"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
122
152
|
}
|
|
123
153
|
}
|
|
124
154
|
```
|
|
@@ -126,76 +156,61 @@ All settings are optional:
|
|
|
126
156
|
| Key | Default | Description |
|
|
127
157
|
|-----|---------|-------------|
|
|
128
158
|
| `autoRecall` | `true` | Inject relevant memories into context before every response |
|
|
129
|
-
| `autoCapture` | `
|
|
130
|
-
| `
|
|
159
|
+
| `autoCapture` | `true` | Automatically capture conversations for consolidation |
|
|
160
|
+
| `requireEmbedding` | `true` | Require a working embedding provider. Set `false` to allow BM25-only fallback |
|
|
161
|
+
| `embedding.provider` | `"auto"` | Embedding provider: `auto`, `openai`, `gemini`, `voyage`, `mistral`, `ollama`, `local` |
|
|
131
162
|
| `embedding.model` | — | Override the provider's default embedding model |
|
|
132
163
|
| `dbPath` | `~/.openclaw/memory/associative` | SQLite database location |
|
|
133
|
-
| `verbose` | `false` | Enable debug
|
|
164
|
+
| `verbose` | `false` | Enable debug logging |
|
|
134
165
|
| `logQueries` | `false` | Include raw query text in debug logs (disabled by default for privacy) |
|
|
135
166
|
|
|
136
|
-
The `"auto"` provider selects the best available embedding provider from
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
The plugin has centralized logging with configurable verbosity. By default only significant events are logged (info level): memory stores, context injection, and circuit breaker state changes.
|
|
141
|
-
|
|
142
|
-
Enable debug logging for full diagnostics:
|
|
143
|
-
|
|
144
|
-
```json
|
|
145
|
-
{ "verbose": true }
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
Or via environment variable (no config change needed):
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
FORMATIVE_MEMORY_DEBUG=1
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
**What gets logged at each level:**
|
|
155
|
-
|
|
156
|
-
| Level | What |
|
|
157
|
-
|-------|------|
|
|
158
|
-
| **info** | Memory stored, memories injected into context, circuit breaker state changes |
|
|
159
|
-
| **debug** | Search result count and top score, embedding fallback reasons, cache hit/miss, consolidation timing, provenance counts, duplicate store skips |
|
|
160
|
-
| **warn** | Circuit breaker opening (degraded to keyword-only), recall failures, migration issues |
|
|
161
|
-
|
|
162
|
-
All log lines are prefixed with `[formative-memory] [level]` for easy filtering.
|
|
163
|
-
|
|
164
|
-
**Privacy:** Query text is never included in logs by default. Set `logQueries: true` to opt in — useful for debugging retrieval quality, but queries may contain personal data.
|
|
167
|
+
The `"auto"` provider selects the best available embedding provider from
|
|
168
|
+
your configured API keys. When `requireEmbedding` is `true` (the
|
|
169
|
+
default), the plugin will not start without a working embedding provider.
|
|
170
|
+
Set it to `false` to allow graceful degradation to keyword-only search.
|
|
165
171
|
|
|
166
172
|
## Architecture
|
|
167
173
|
|
|
168
174
|
```
|
|
169
175
|
OpenClaw Runtime
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
(automatic)
|
|
176
|
+
|
|
|
177
|
+
|-- Context Engine --- assemble() -> auto-recall into context
|
|
178
|
+
| (budget-aware) afterTurn() -> log exposures + attributions
|
|
179
|
+
|
|
|
180
|
+
|-- Memory Tools ----- memory_store - create memory
|
|
181
|
+
| (agent-initiated) memory_search - hybrid search
|
|
182
|
+
| memory_get - lookup by ID
|
|
183
|
+
| memory_feedback - rate usefulness
|
|
184
|
+
| memory_browse - browse by importance
|
|
185
|
+
|
|
|
186
|
+
+-- Consolidation ---- reinforce -> decay -> associate -> transition
|
|
187
|
+
(automatic) -> prune -> merge (LLM) -> cleanup
|
|
182
188
|
```
|
|
183
189
|
|
|
184
|
-
**Storage:** SQLite with FTS5 for full-text search. Single file, no
|
|
190
|
+
**Storage:** SQLite with FTS5 for full-text search. Single file, no
|
|
191
|
+
external services.
|
|
185
192
|
|
|
186
|
-
**Embedding:** Auto-detected from configured API keys. Supports OpenAI,
|
|
193
|
+
**Embedding:** Auto-detected from configured API keys. Supports OpenAI,
|
|
194
|
+
Gemini, Voyage, Mistral, Ollama. Circuit breaker with graceful fallback
|
|
195
|
+
to keyword-only search when `requireEmbedding` is `false`.
|
|
187
196
|
|
|
188
|
-
**Consolidation LLM:** Uses Anthropic (Claude) or OpenAI for memory
|
|
197
|
+
**Consolidation LLM:** Uses Anthropic (Claude) or OpenAI for memory
|
|
198
|
+
merging. Runs only during consolidation, not during normal chat.
|
|
189
199
|
|
|
190
200
|
## Trust & Security
|
|
191
201
|
|
|
192
|
-
Automatically recalled memories are framed as reference data, not
|
|
202
|
+
Automatically recalled memories are framed as reference data, not
|
|
203
|
+
instructions. This reduces prompt injection risk from stored memory
|
|
204
|
+
content, but memory remains untrusted input — the framing is
|
|
205
|
+
probabilistic, not a hard security boundary.
|
|
193
206
|
|
|
194
|
-
Do not store secrets (API keys, passwords) in memories. They will be
|
|
207
|
+
Do not store secrets (API keys, passwords) in memories. They will be
|
|
208
|
+
surfaced to the model during recall.
|
|
195
209
|
|
|
196
210
|
## CLI
|
|
197
211
|
|
|
198
|
-
A standalone diagnostic CLI operates directly on the SQLite database —
|
|
212
|
+
A standalone diagnostic CLI operates directly on the SQLite database —
|
|
213
|
+
no OpenClaw runtime needed:
|
|
199
214
|
|
|
200
215
|
```bash
|
|
201
216
|
memory stats <memory-dir> # Database overview
|
|
@@ -207,12 +222,26 @@ memory history <memory-dir> # Retrieval history
|
|
|
207
222
|
memory graph <memory-dir> # Association graph
|
|
208
223
|
```
|
|
209
224
|
|
|
210
|
-
##
|
|
225
|
+
## Logging
|
|
226
|
+
|
|
227
|
+
Centralized logging with configurable verbosity. By default only
|
|
228
|
+
significant events are logged (info level).
|
|
229
|
+
|
|
230
|
+
Enable debug logging:
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{ "verbose": true }
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
| Level | What |
|
|
237
|
+
|-------|------|
|
|
238
|
+
| **info** | Memory stored, memories injected into context, circuit breaker state changes |
|
|
239
|
+
| **debug** | Search results, embedding fallback reasons, cache hit/miss, consolidation timing |
|
|
240
|
+
| **warn** | Circuit breaker opening (degraded to keyword-only), recall failures |
|
|
211
241
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
- [ ] Cross-project memory sharing
|
|
242
|
+
All log lines are prefixed with `[formative-memory] [level]` for easy
|
|
243
|
+
filtering. Query text is never included in logs by default — set
|
|
244
|
+
`logQueries: true` to opt in.
|
|
216
245
|
|
|
217
246
|
## Documentation
|
|
218
247
|
|
|
@@ -239,6 +268,7 @@ Contributions welcome. Areas where help is especially useful:
|
|
|
239
268
|
|
|
240
269
|
- Consolidation algorithm tuning and evaluation
|
|
241
270
|
- Embedding model benchmarks
|
|
271
|
+
- Adapters for other AI coding agents
|
|
242
272
|
- Documentation and examples
|
|
243
273
|
|
|
244
274
|
## License
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as MemorySourceGuard, r as TemporalStateGuard, t as MemoryDatabase } from "./db-
|
|
2
|
+
import { n as MemorySourceGuard, r as TemporalStateGuard, t as MemoryDatabase } from "./db-D1Sc76VE.js";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
//#region src/cli.ts
|