neoagent 2.4.4-beta.0 → 2.4.4-beta.4
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 +5 -3
- package/docs/capabilities.md +16 -7
- package/docs/index.md +1 -0
- package/docs/security-boundaries.md +122 -0
- package/docs/supermemory-memory-review.md +852 -0
- package/flutter_app/lib/features/memory/views/retrieval_inspector_view.dart +128 -0
- package/flutter_app/lib/main.dart +3 -0
- package/flutter_app/lib/main_app_shell.dart +22 -0
- package/flutter_app/lib/main_controller.dart +36 -1
- package/flutter_app/lib/main_operations.dart +13 -0
- package/flutter_app/lib/main_security.dart +971 -0
- package/flutter_app/lib/main_settings.dart +61 -0
- package/flutter_app/lib/src/backend_client.dart +60 -3
- package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +2 -0
- package/flutter_app/pubspec.lock +32 -0
- package/flutter_app/pubspec.yaml +1 -0
- package/lib/schema_migrations.js +237 -0
- package/package.json +4 -2
- package/server/db/database.js +3 -0
- package/server/http/routes.js +2 -1
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/NOTICES +86 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +80911 -79117
- package/server/routes/memory.js +39 -2
- package/server/routes/security.js +112 -0
- package/server/services/ai/engine.js +267 -10
- package/server/services/ai/systemPrompt.js +13 -2
- package/server/services/cli/shell_worker.js +135 -0
- package/server/services/cli/shell_worker_pool.js +125 -0
- package/server/services/manager.js +20 -1
- package/server/services/memory/consolidation.js +111 -0
- package/server/services/memory/embedding_index.js +175 -0
- package/server/services/memory/embeddings.js +22 -2
- package/server/services/memory/evaluation.js +187 -0
- package/server/services/memory/ingestion_chunking.js +191 -0
- package/server/services/memory/ingestion_documents.js +96 -26
- package/server/services/memory/intelligence.js +3 -1
- package/server/services/memory/manager.js +855 -40
- package/server/services/memory/policy.js +0 -40
- package/server/services/memory/retrieval_reasoning.js +191 -0
- package/server/services/runtime/manager.js +7 -0
- package/server/services/security/approval_gate_service.js +93 -0
- package/server/services/security/tool_categories.js +105 -0
- package/server/services/security/tool_policy_service.js +92 -0
- package/server/services/security/tool_security_hook.js +77 -0
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
# Supermemory Review and NeoAgent Memory Parity Plan
|
|
2
|
+
|
|
3
|
+
Date reviewed: 2026-06-13
|
|
4
|
+
|
|
5
|
+
Reviewed sources:
|
|
6
|
+
|
|
7
|
+
- Supermemory repository at commit `39ef7e1e5ea01b34d2cdd1801d0d227d445a985d`
|
|
8
|
+
- MemoryBench repository at commit `118209a746d97d0d85e5a7234267f0b6962857e9`
|
|
9
|
+
- Supermemory research page and March 22, 2026 benchmark post
|
|
10
|
+
- NeoAgent memory, AI engine, ingestion, database, and evaluation code
|
|
11
|
+
|
|
12
|
+
Primary sources:
|
|
13
|
+
|
|
14
|
+
- https://github.com/supermemoryai/supermemory
|
|
15
|
+
- https://github.com/supermemoryai/memorybench
|
|
16
|
+
- https://supermemory.ai/research/
|
|
17
|
+
- https://supermemory.ai/blog/we-broke-the-frontier-in-agent-memory-introducing-99-sota-memory-system/
|
|
18
|
+
- https://supermemory.ai/docs/concepts/graph-memory
|
|
19
|
+
- https://supermemory.ai/docs/concepts/memory-vs-rag
|
|
20
|
+
- https://supermemory.ai/docs/concepts/user-profiles
|
|
21
|
+
- https://supermemory.ai/docs/search/overview
|
|
22
|
+
|
|
23
|
+
## Executive Verdict
|
|
24
|
+
|
|
25
|
+
The useful conclusion is not "copy Supermemory" and not "add a Supermemory API call."
|
|
26
|
+
|
|
27
|
+
Supermemory's strongest production ideas are:
|
|
28
|
+
|
|
29
|
+
1. Separate raw source documents from extracted memories.
|
|
30
|
+
2. Store atomic, source-grounded facts instead of conversation-shaped blobs.
|
|
31
|
+
3. Model updates, extensions, derivations, and expiry explicitly.
|
|
32
|
+
4. Maintain a broad user profile separately from query-specific retrieval.
|
|
33
|
+
5. Retrieve current facts first, then attach graph and version context.
|
|
34
|
+
6. Use hybrid retrieval, candidate expansion, and reranking.
|
|
35
|
+
7. Evaluate answer quality, retrieval quality, latency, and context tokens together.
|
|
36
|
+
|
|
37
|
+
NeoAgent already had parts of this shape before this review:
|
|
38
|
+
|
|
39
|
+
- SQLite memories with embeddings and FTS5
|
|
40
|
+
- memory facts and entities
|
|
41
|
+
- temporal columns and supersession IDs
|
|
42
|
+
- core memory and conversation working state
|
|
43
|
+
- ingestion jobs and source documents
|
|
44
|
+
- hybrid semantic, lexical, and entity ranking
|
|
45
|
+
- per-user and per-agent isolation
|
|
46
|
+
|
|
47
|
+
The main problem was semantic depth, not the number of tables. Facts were generally sentence copies with a category used as the predicate. Automatic conversation extraction depended mostly on the main model voluntarily calling `memory_save`. Superseded facts could still compete in normal recall. There was no automatic static/dynamic profile built from active facts.
|
|
48
|
+
|
|
49
|
+
This review implements the first high-impact correction:
|
|
50
|
+
|
|
51
|
+
- automatic structured memory extraction during the existing post-conversation state pass
|
|
52
|
+
- atomic subject, predicate, object facts
|
|
53
|
+
- `new`, `updates`, `extends`, and `derives` relation classification
|
|
54
|
+
- confidence, importance, static/dynamic type, evidence, and temporal bounds
|
|
55
|
+
- automatic supersession of conflicting current facts
|
|
56
|
+
- exclusion of superseded and expired facts from normal recall
|
|
57
|
+
- labeled version history attached to the current result
|
|
58
|
+
- automatic static and dynamic user profile injection
|
|
59
|
+
- confidence-aware ranking
|
|
60
|
+
- prompt cache invalidation after consolidation
|
|
61
|
+
- correct agent-scoped memory retrieval for subagents
|
|
62
|
+
|
|
63
|
+
This materially improves NeoAgent, but it does not establish parity. Parity must be demonstrated on reproducible benchmarks and production constraints.
|
|
64
|
+
|
|
65
|
+
## The 99 Percent Claim
|
|
66
|
+
|
|
67
|
+
The quoted claim is not a valid target for NeoAgent's production architecture.
|
|
68
|
+
|
|
69
|
+
Supermemory's own March 22, 2026 post states:
|
|
70
|
+
|
|
71
|
+
- The result was from an experimental flow, not the production Supermemory engine.
|
|
72
|
+
- Three reader agents extracted structured findings from sessions.
|
|
73
|
+
- Three search agents reasoned over those findings.
|
|
74
|
+
- The 98.60 percent result counted a question correct if any of eight answer variants was correct.
|
|
75
|
+
- A twelve-answer decision forest plus aggregator produced one answer at 97.20 percent.
|
|
76
|
+
- The post now labels the release a parody and social experiment.
|
|
77
|
+
|
|
78
|
+
The 98.60 percent number is best-of-eight coverage, not single-answer user-visible accuracy. It is useful as an upper-bound experiment, but it is not a fair production memory score.
|
|
79
|
+
|
|
80
|
+
Supermemory's current research page reports a different result:
|
|
81
|
+
|
|
82
|
+
- 95 percent Recall@15 with aggregation
|
|
83
|
+
- about 720 retrieved context tokens
|
|
84
|
+
- 99.4 percent context reduction
|
|
85
|
+
- category recall from 90 to 100 percent on LongMemEval_s
|
|
86
|
+
|
|
87
|
+
That is retrieval recall, not end-to-end answer accuracy. The number near 99 percent in that report is context reduction, while 99 percent is also reported for the knowledge-update category. These metrics must not be collapsed into one "99 percent memory" claim.
|
|
88
|
+
|
|
89
|
+
The repository README reports 81.6 percent on LongMemEval. This appears to describe a production or earlier end-to-end result, while the research page describes a later retrieval-focused result. The difference reinforces the need to record:
|
|
90
|
+
|
|
91
|
+
- dataset version
|
|
92
|
+
- sample set
|
|
93
|
+
- retrieval `k`
|
|
94
|
+
- answering model
|
|
95
|
+
- judge model and prompt
|
|
96
|
+
- single answer versus best-of-N
|
|
97
|
+
- context token count
|
|
98
|
+
- search and total latency
|
|
99
|
+
- ingestion cost
|
|
100
|
+
|
|
101
|
+
NeoAgent should not claim parity from one headline accuracy number.
|
|
102
|
+
|
|
103
|
+
## What Supermemory Actually Does
|
|
104
|
+
|
|
105
|
+
### 1. It Separates Documents and Memories
|
|
106
|
+
|
|
107
|
+
Documents are the source of truth:
|
|
108
|
+
|
|
109
|
+
- conversations
|
|
110
|
+
- email
|
|
111
|
+
- web pages
|
|
112
|
+
- PDFs
|
|
113
|
+
- images
|
|
114
|
+
- videos
|
|
115
|
+
- code
|
|
116
|
+
- connector objects
|
|
117
|
+
|
|
118
|
+
Memories are extracted knowledge units:
|
|
119
|
+
|
|
120
|
+
- user facts
|
|
121
|
+
- preferences
|
|
122
|
+
- events
|
|
123
|
+
- project state
|
|
124
|
+
- relationships
|
|
125
|
+
- inferred facts
|
|
126
|
+
|
|
127
|
+
This distinction matters because a memory should retain provenance to its source. The system can update its interpretation without losing the original evidence.
|
|
128
|
+
|
|
129
|
+
Before this review, NeoAgent had `memory_ingestion_documents` and `memories`, but ingestion saved one compacted title and summary as one memory. The implementation now preserves source chunks, spans, and many-to-many chunk-to-memory links.
|
|
130
|
+
|
|
131
|
+
### 2. It Uses Fact-on-Fact Graph Relations
|
|
132
|
+
|
|
133
|
+
The public schemas expose:
|
|
134
|
+
|
|
135
|
+
- `version`
|
|
136
|
+
- `isLatest`
|
|
137
|
+
- `parentMemoryId`
|
|
138
|
+
- `rootMemoryId`
|
|
139
|
+
- `memoryRelations`
|
|
140
|
+
- `sourceCount`
|
|
141
|
+
- `isInference`
|
|
142
|
+
- `isForgotten`
|
|
143
|
+
- `isStatic`
|
|
144
|
+
- `forgetAfter`
|
|
145
|
+
- `forgetReason`
|
|
146
|
+
|
|
147
|
+
Relation types are:
|
|
148
|
+
|
|
149
|
+
- `updates`: replaces an older fact
|
|
150
|
+
- `extends`: adds compatible detail
|
|
151
|
+
- `derives`: records an inference
|
|
152
|
+
|
|
153
|
+
This is not a conventional entity-relation-entity knowledge graph. The primary graph edges connect facts to other facts.
|
|
154
|
+
|
|
155
|
+
That is useful for agent memory because the important question is often not "what entities exist?" but "which version of this claim is current, what did it replace, and what evidence supports it?"
|
|
156
|
+
|
|
157
|
+
### 3. It Treats Time as Part of Truth
|
|
158
|
+
|
|
159
|
+
Supermemory distinguishes:
|
|
160
|
+
|
|
161
|
+
- when a fact was learned
|
|
162
|
+
- when it became valid
|
|
163
|
+
- when it stopped being valid
|
|
164
|
+
- when it should be forgotten
|
|
165
|
+
- whether it is the latest version
|
|
166
|
+
|
|
167
|
+
This avoids a common RAG failure:
|
|
168
|
+
|
|
169
|
+
1. The user once liked a product.
|
|
170
|
+
2. The product failed.
|
|
171
|
+
3. The user switched to another product.
|
|
172
|
+
4. Similarity search retrieves the old positive statement.
|
|
173
|
+
|
|
174
|
+
NeoAgent already had `valid_from`, `valid_to`, `learned_at`, `invalidated_at`, `status`, and `supersedes_fact_id`, but the old extractor rarely produced canonical predicates that could identify conflicts. The schema therefore had more capability than the extraction layer could use.
|
|
175
|
+
|
|
176
|
+
### 4. It Maintains Static and Dynamic Profiles
|
|
177
|
+
|
|
178
|
+
Supermemory profiles separate:
|
|
179
|
+
|
|
180
|
+
- static facts: identity, role, durable preferences
|
|
181
|
+
- dynamic facts: current projects, recent focus, temporary state
|
|
182
|
+
|
|
183
|
+
This solves a retrieval blind spot. A narrow search for a project update will not necessarily retrieve the user's communication style, timezone, role, or stable tool preferences. Profile context provides the broad baseline while search supplies question-specific detail.
|
|
184
|
+
|
|
185
|
+
NeoAgent now builds this profile from active facts and injects a bounded version into the system prompt.
|
|
186
|
+
|
|
187
|
+
### 5. It Uses More Than Vector Similarity
|
|
188
|
+
|
|
189
|
+
The documented retrieval stack includes:
|
|
190
|
+
|
|
191
|
+
- semantic vector search
|
|
192
|
+
- keyword or hybrid search
|
|
193
|
+
- metadata and container filtering
|
|
194
|
+
- query rewriting
|
|
195
|
+
- result merging and deduplication
|
|
196
|
+
- reranking
|
|
197
|
+
- relationship expansion
|
|
198
|
+
- current-version filtering
|
|
199
|
+
- optional source document and neighboring chunk context
|
|
200
|
+
|
|
201
|
+
The production value is in the combination. Embeddings provide broad semantic matching. Lexical search protects exact names, IDs, dates, and technical terms. Graph expansion provides temporal and relational context. Reranking removes noise before prompt injection.
|
|
202
|
+
|
|
203
|
+
NeoAgent now combines approximate semantic, FTS, entity, relation, importance, usage, freshness, confidence, and temporal signals. When direct retrieval is structurally weak or ambiguous, a bounded structured planner generates query variants and temporal intent, then a configured model reranks only known candidates. Confident retrieval stays on the zero-LLM fast path.
|
|
204
|
+
|
|
205
|
+
### 6. It Scopes Memory Strictly
|
|
206
|
+
|
|
207
|
+
Supermemory uses container tags as vector and access namespaces. NeoAgent's user, agent, and scope fields provide the corresponding boundary.
|
|
208
|
+
|
|
209
|
+
NeoAgent should keep its native scoping instead of importing Supermemory's container abstraction. The existing model is more expressive for:
|
|
210
|
+
|
|
211
|
+
- agent scope
|
|
212
|
+
- conversation scope
|
|
213
|
+
- task scope
|
|
214
|
+
- channel scope
|
|
215
|
+
- shared scope
|
|
216
|
+
|
|
217
|
+
### 7. It Runs Ingestion Asynchronously
|
|
218
|
+
|
|
219
|
+
The self-hosted documentation describes:
|
|
220
|
+
|
|
221
|
+
- immediate acceptance of additions
|
|
222
|
+
- background extraction and indexing
|
|
223
|
+
- search traffic prioritized over ingestion
|
|
224
|
+
- bounded ingestion concurrency and memory use
|
|
225
|
+
- local embedding workers
|
|
226
|
+
|
|
227
|
+
NeoAgent's integration ingestion is asynchronous, but conversation consolidation now waits for the existing post-turn structured pass. This favors immediate cross-turn consistency. If latency becomes material, it should move to a durable per-conversation queue with read-your-writes behavior rather than untracked fire-and-forget work.
|
|
228
|
+
|
|
229
|
+
### 8. It Measures Multiple Dimensions
|
|
230
|
+
|
|
231
|
+
MemoryBench reports:
|
|
232
|
+
|
|
233
|
+
- answer accuracy
|
|
234
|
+
- search latency
|
|
235
|
+
- context token count
|
|
236
|
+
- per-question-type accuracy
|
|
237
|
+
- Hit@K
|
|
238
|
+
- Precision@K
|
|
239
|
+
- Recall@K
|
|
240
|
+
- F1@K
|
|
241
|
+
- MRR
|
|
242
|
+
- NDCG
|
|
243
|
+
|
|
244
|
+
This is the correct direction. Accuracy alone rewards expensive ensembles and oversized context.
|
|
245
|
+
|
|
246
|
+
## Important Limits of the Public Supermemory Repository
|
|
247
|
+
|
|
248
|
+
The reviewed repository does not expose the complete hosted production engine.
|
|
249
|
+
|
|
250
|
+
It contains:
|
|
251
|
+
|
|
252
|
+
- public schemas
|
|
253
|
+
- client integrations
|
|
254
|
+
- MCP
|
|
255
|
+
- UI
|
|
256
|
+
- documentation
|
|
257
|
+
- SDK wrappers
|
|
258
|
+
- graph visualization
|
|
259
|
+
|
|
260
|
+
The self-hosted documentation explicitly says the hosted platform uses proprietary models tuned for long-horizon extraction. The reviewed checkout does not contain a directly reusable implementation of the hosted extraction and ranking stack.
|
|
261
|
+
|
|
262
|
+
Therefore:
|
|
263
|
+
|
|
264
|
+
- there is no complete production algorithm to copy
|
|
265
|
+
- direct code copying would not reproduce hosted quality
|
|
266
|
+
- integrating the hosted API would create an external source of truth, privacy dependency, and network dependency
|
|
267
|
+
- a native NeoAgent implementation is the correct architecture
|
|
268
|
+
|
|
269
|
+
Supermemory can still be used as a benchmark comparison provider, not as NeoAgent's primary memory store.
|
|
270
|
+
|
|
271
|
+
## NeoAgent Audit Before This Change
|
|
272
|
+
|
|
273
|
+
### Existing Strengths
|
|
274
|
+
|
|
275
|
+
1. Local-first storage in the existing SQLite database.
|
|
276
|
+
2. User and agent isolation in queries and indexes.
|
|
277
|
+
3. FTS5 plus embeddings plus entity matching.
|
|
278
|
+
4. Source references and confidence fields.
|
|
279
|
+
5. Temporal fact columns.
|
|
280
|
+
6. Integration ingestion jobs and freshness policies.
|
|
281
|
+
7. Conversation summaries and working state.
|
|
282
|
+
8. Manual core memory with confirmation.
|
|
283
|
+
9. UI and API support for memory inspection.
|
|
284
|
+
|
|
285
|
+
### Critical Gaps Before This Review
|
|
286
|
+
|
|
287
|
+
These describe the baseline that motivated the implementation below.
|
|
288
|
+
|
|
289
|
+
#### Extraction
|
|
290
|
+
|
|
291
|
+
- Conversation memory was not consolidated automatically in a reliable, structured way.
|
|
292
|
+
- Local fact extraction used sentence splitting and the memory category as a predicate.
|
|
293
|
+
- Entity extraction was regex-based and could not establish canonical semantic identity.
|
|
294
|
+
- Assistant statements could become memory if the model called `memory_save` incorrectly.
|
|
295
|
+
- There was no evidence field in the normal conversational extraction path.
|
|
296
|
+
|
|
297
|
+
#### Temporal Updates
|
|
298
|
+
|
|
299
|
+
- Conflicts required matching subject and predicate, but weak extraction rarely produced stable predicates.
|
|
300
|
+
- Superseded facts remained eligible as memory rows in normal recall.
|
|
301
|
+
- Historical context was not attached to the current fact.
|
|
302
|
+
- Expiry influenced freshness but did not always exclude a memory immediately.
|
|
303
|
+
|
|
304
|
+
#### Retrieval
|
|
305
|
+
|
|
306
|
+
- Embedding search scanned at most 800 recent memories in JavaScript.
|
|
307
|
+
- Old but important memories outside that window were invisible to semantic scoring.
|
|
308
|
+
- Embeddings were JSON stored in SQLite, with no approximate nearest-neighbor index.
|
|
309
|
+
- There was no query rewriting.
|
|
310
|
+
- There was no cross-encoder or LLM reranking stage.
|
|
311
|
+
- Confidence did not affect ranking.
|
|
312
|
+
- Source-document chunks and extracted memories were not searched as a unified result set.
|
|
313
|
+
|
|
314
|
+
#### Profiles
|
|
315
|
+
|
|
316
|
+
- Core memory required explicit management.
|
|
317
|
+
- There was no automatic broad user profile from active facts.
|
|
318
|
+
- Dynamic and static context were not separated.
|
|
319
|
+
|
|
320
|
+
#### Ingestion
|
|
321
|
+
|
|
322
|
+
- A source document generally became one title and compacted summary memory.
|
|
323
|
+
- There was no semantic chunk graph or source-span citation model.
|
|
324
|
+
- Materialized knowledge views are deterministic grouped summaries, not model-maintained profiles.
|
|
325
|
+
|
|
326
|
+
#### Evaluation
|
|
327
|
+
|
|
328
|
+
- `representative_tasks.json` checks event coverage, not memory answer quality.
|
|
329
|
+
- There was no LongMemEval, LoCoMo, or ConvoMem retrieval harness.
|
|
330
|
+
- There was no retrieval metric collection.
|
|
331
|
+
- There was no memory latency or context-token budget.
|
|
332
|
+
|
|
333
|
+
## Implemented in This Review
|
|
334
|
+
|
|
335
|
+
### Structured Post-Turn Consolidation
|
|
336
|
+
|
|
337
|
+
The existing conversation-state model call now also returns `memory_candidates`.
|
|
338
|
+
|
|
339
|
+
Each candidate includes:
|
|
340
|
+
|
|
341
|
+
- standalone memory text
|
|
342
|
+
- subject
|
|
343
|
+
- predicate
|
|
344
|
+
- object
|
|
345
|
+
- relation
|
|
346
|
+
- category
|
|
347
|
+
- confidence
|
|
348
|
+
- importance
|
|
349
|
+
- static flag
|
|
350
|
+
- valid-from time
|
|
351
|
+
- valid-to time
|
|
352
|
+
- forget-after time
|
|
353
|
+
- source-grounded evidence
|
|
354
|
+
|
|
355
|
+
The prompt explicitly excludes:
|
|
356
|
+
|
|
357
|
+
- secrets and credentials
|
|
358
|
+
- assistant guesses
|
|
359
|
+
- questions
|
|
360
|
+
- unverified claims
|
|
361
|
+
- raw tool output
|
|
362
|
+
- routine task narration
|
|
363
|
+
- thread-only details
|
|
364
|
+
|
|
365
|
+
This is implemented in:
|
|
366
|
+
|
|
367
|
+
- `server/services/memory/consolidation.js`
|
|
368
|
+
- `server/services/ai/engine.js`
|
|
369
|
+
|
|
370
|
+
### Temporal Fact Reconciliation
|
|
371
|
+
|
|
372
|
+
Structured facts now drive the existing temporal schema.
|
|
373
|
+
|
|
374
|
+
When the same canonical subject and predicate receives a different object:
|
|
375
|
+
|
|
376
|
+
- `updates` supersedes the previous active fact
|
|
377
|
+
- `extends` keeps both facts active
|
|
378
|
+
- `derives` keeps the inference separate
|
|
379
|
+
- unclassified conflicting values default to update behavior
|
|
380
|
+
|
|
381
|
+
The new fact records:
|
|
382
|
+
|
|
383
|
+
- relation metadata
|
|
384
|
+
- static status
|
|
385
|
+
- evidence
|
|
386
|
+
- source type
|
|
387
|
+
- validity bounds
|
|
388
|
+
- previous fact ID for updates
|
|
389
|
+
|
|
390
|
+
### Current-First Recall With Version Context
|
|
391
|
+
|
|
392
|
+
Normal recall now excludes:
|
|
393
|
+
|
|
394
|
+
- superseded facts
|
|
395
|
+
- expired facts
|
|
396
|
+
|
|
397
|
+
The current result includes labeled previous-value context. This supports both:
|
|
398
|
+
|
|
399
|
+
- "Where does Neo live now?"
|
|
400
|
+
- "Where did Neo live before Berlin?"
|
|
401
|
+
|
|
402
|
+
without allowing the old value to outrank the current value.
|
|
403
|
+
|
|
404
|
+
### Auto-Maintained Profile
|
|
405
|
+
|
|
406
|
+
Active facts are divided into:
|
|
407
|
+
|
|
408
|
+
- stable facts
|
|
409
|
+
- current context
|
|
410
|
+
|
|
411
|
+
The profile is bounded and injected into the system prompt. Cache entries are invalidated after consolidation so the next turn can see the update.
|
|
412
|
+
|
|
413
|
+
### Confidence-Aware Ranking
|
|
414
|
+
|
|
415
|
+
Candidate score now includes confidence. A low-confidence derived memory cannot rank exactly like a verified high-confidence fact with otherwise identical signals.
|
|
416
|
+
|
|
417
|
+
### Subagent Recall Fix
|
|
418
|
+
|
|
419
|
+
The subagent call passed the options object as the third `topK` argument to `recallMemory`. It now passes `4` as `topK` and the agent scope as the fourth argument.
|
|
420
|
+
|
|
421
|
+
### Persistent Approximate Semantic Index
|
|
422
|
+
|
|
423
|
+
The newest-800-memory scan has been removed.
|
|
424
|
+
|
|
425
|
+
NeoAgent now stores ten versioned locality-sensitive hash bands per embedding in SQLite. Search uses:
|
|
426
|
+
|
|
427
|
+
1. ten independent 14-bit bands
|
|
428
|
+
2. Hamming-distance-zero, one, and two probes
|
|
429
|
+
3. direct indexed SQLite lookups per band
|
|
430
|
+
4. vote aggregation in memory
|
|
431
|
+
5. exact cosine reranking over the bounded candidate set
|
|
432
|
+
|
|
433
|
+
This keeps the existing single-database deployment model and does not require a native vector extension or a second vector service.
|
|
434
|
+
|
|
435
|
+
Index versioning is explicit. Existing embeddings are rebuilt incrementally in the background when the index geometry changes. New and updated memories are indexed synchronously.
|
|
436
|
+
|
|
437
|
+
Synthetic measurements on this development machine:
|
|
438
|
+
|
|
439
|
+
- 100,000 memories
|
|
440
|
+
- 1,000,000 band rows
|
|
441
|
+
- 500 semantic candidates
|
|
442
|
+
- mean candidate lookup: 7.87 ms
|
|
443
|
+
- p95 candidate lookup: 9.17 ms
|
|
444
|
+
- synthetic recall@500 for a planted cosine-0.80 neighbor: 98.0 percent
|
|
445
|
+
- cosine-0.85 neighbor recall: 99.5 percent
|
|
446
|
+
|
|
447
|
+
These measurements validate the candidate index, not full end-to-end retrieval. Full retrieval also includes the embedding API call, FTS/entity retrieval, temporal filtering, exact scoring, provenance attachment, and SQLite telemetry.
|
|
448
|
+
|
|
449
|
+
### Hybrid Candidate Expansion and Context Budget
|
|
450
|
+
|
|
451
|
+
Recall now unions:
|
|
452
|
+
|
|
453
|
+
- approximate semantic candidates
|
|
454
|
+
- FTS candidates
|
|
455
|
+
- entity candidates
|
|
456
|
+
- relation neighbors
|
|
457
|
+
- a bounded importance and recency baseline
|
|
458
|
+
|
|
459
|
+
It then applies exact semantic scoring, lexical/entity scores, confidence, importance, usage, freshness, scope, and temporal validity.
|
|
460
|
+
|
|
461
|
+
Fact relation neighbors are expanded before final ranking. Prompt injection is bounded to approximately 750 memory-context tokens rather than blindly injecting every returned summary.
|
|
462
|
+
|
|
463
|
+
### First-Class Relations and Provenance
|
|
464
|
+
|
|
465
|
+
NeoAgent now persists:
|
|
466
|
+
|
|
467
|
+
- memory-to-memory `updates`, `extends`, and `derives` relations
|
|
468
|
+
- source documents
|
|
469
|
+
- source chunks
|
|
470
|
+
- stable character spans
|
|
471
|
+
- chunk-to-memory links
|
|
472
|
+
- source timestamps
|
|
473
|
+
- extraction method
|
|
474
|
+
- source relevance
|
|
475
|
+
- evidence metadata
|
|
476
|
+
|
|
477
|
+
Recall results expose source document, chunk, and span information. Recalled context includes a compact citation label. Source refresh removes obsolete chunks but preserves a memory that is still supported by another source.
|
|
478
|
+
|
|
479
|
+
### Structure-Aware Ingestion
|
|
480
|
+
|
|
481
|
+
External documents no longer collapse into one compact summary.
|
|
482
|
+
|
|
483
|
+
The ingestion path now:
|
|
484
|
+
|
|
485
|
+
1. preserves raw normalized source documents
|
|
486
|
+
2. uses message boundaries when structured messages are available
|
|
487
|
+
3. otherwise uses headings and paragraph boundaries
|
|
488
|
+
4. only uses character limits to split an oversized structural block
|
|
489
|
+
5. embeds and indexes every resulting chunk
|
|
490
|
+
6. links each memory back to its exact source span
|
|
491
|
+
|
|
492
|
+
Repository AST boundaries and format-specific email quote parsing remain future specialization work.
|
|
493
|
+
|
|
494
|
+
### Embedding Lineage
|
|
495
|
+
|
|
496
|
+
New embeddings record:
|
|
497
|
+
|
|
498
|
+
- provider
|
|
499
|
+
- model
|
|
500
|
+
- dimensions
|
|
501
|
+
- generated time
|
|
502
|
+
- approximate-index version
|
|
503
|
+
|
|
504
|
+
Legacy embeddings are marked as having an unknown provider and are incrementally reindexed.
|
|
505
|
+
|
|
506
|
+
### Reinforcement and Trust Boundaries
|
|
507
|
+
|
|
508
|
+
Repeated identical evidence now raises confidence on the existing memory and active fact instead of becoming a no-op.
|
|
509
|
+
|
|
510
|
+
External-source memories:
|
|
511
|
+
|
|
512
|
+
- carry an explicit `external_source` trust label
|
|
513
|
+
- are excluded from the automatic user profile
|
|
514
|
+
- are presented to the model as untrusted data, never instructions
|
|
515
|
+
|
|
516
|
+
Conversation-consolidated facts carry a separate user-or-verified-conversation trust label. The old phrase-based storage rejection policy was removed; durable-memory selection is handled by structured model output and source metadata rather than scenario regexes.
|
|
517
|
+
|
|
518
|
+
### Retrieval Evaluation and Telemetry
|
|
519
|
+
|
|
520
|
+
`npm run benchmark:memory` runs deterministic retrieval evaluation against an existing NeoAgent memory corpus. It accepts NeoAgent relevance IDs and MemoryBench-style question/session identifiers and reports:
|
|
521
|
+
|
|
522
|
+
- Hit@K
|
|
523
|
+
- Precision@K
|
|
524
|
+
- Recall@K
|
|
525
|
+
- F1@K
|
|
526
|
+
- MRR
|
|
527
|
+
- NDCG
|
|
528
|
+
- category breakdown
|
|
529
|
+
- latency mean, median, p95, p99, and maximum
|
|
530
|
+
- estimated context tokens
|
|
531
|
+
- candidate counts
|
|
532
|
+
|
|
533
|
+
Production recall also records privacy-preserving events with a query hash, candidate source counts, relation expansion count, result IDs, latency, and context-token estimate. Raw queries are not stored in telemetry.
|
|
534
|
+
|
|
535
|
+
### Tests
|
|
536
|
+
|
|
537
|
+
Regression coverage now verifies:
|
|
538
|
+
|
|
539
|
+
- malformed extraction output is rejected
|
|
540
|
+
- candidates are normalized and deduplicated
|
|
541
|
+
- updates supersede old facts
|
|
542
|
+
- current recall excludes stale values
|
|
543
|
+
- version history remains available
|
|
544
|
+
- static profiles contain only the current value
|
|
545
|
+
- extensions remain active
|
|
546
|
+
- expired memories are excluded
|
|
547
|
+
- the post-conversation engine path persists extracted candidates
|
|
548
|
+
- semantic recall can recover an old target behind more than 800 newer rows
|
|
549
|
+
- retrieval metrics use explicit relevance identifiers
|
|
550
|
+
- source chunks preserve structural and message boundaries
|
|
551
|
+
- source citations survive recall
|
|
552
|
+
- updates and extensions create graph edges
|
|
553
|
+
- relation expansion contributes candidates
|
|
554
|
+
- repeated evidence reinforces confidence
|
|
555
|
+
- external documents cannot become automatic profile facts
|
|
556
|
+
- storage does not use phrase-based scenario filters
|
|
557
|
+
|
|
558
|
+
## Remaining Work Required for Parity
|
|
559
|
+
|
|
560
|
+
### Phase 0: Establish a Reproducible Baseline
|
|
561
|
+
|
|
562
|
+
The local retrieval harness and an executable MemoryBench provider are implemented. Held-out runs remain mandatory before a parity claim.
|
|
563
|
+
|
|
564
|
+
The provider supplies:
|
|
565
|
+
|
|
566
|
+
- isolated temporary NeoAgent data per question
|
|
567
|
+
- one agent and user per benchmark container
|
|
568
|
+
- session ingestion with original timestamps
|
|
569
|
+
- deterministic wait for consolidation completion
|
|
570
|
+
- production retrieval planning and reranking through `AgentEngine.buildMemoryRecall`
|
|
571
|
+
- a clear method to reset the container
|
|
572
|
+
- compact source-aware answer prompts
|
|
573
|
+
|
|
574
|
+
Install it into a MemoryBench checkout with:
|
|
575
|
+
|
|
576
|
+
```bash
|
|
577
|
+
NEOAGENT_REPO_PATH=/absolute/path/to/NeoAgent \
|
|
578
|
+
npm run benchmark:memorybench:install -- /absolute/path/to/memorybench
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
The adapter and bridge have been smoke-tested as an actual TypeScript-loaded provider, including isolated empty-index search and container cleanup. A representative ingestion/search run still requires configured extraction and embedding credentials.
|
|
582
|
+
|
|
583
|
+
Run at minimum:
|
|
584
|
+
|
|
585
|
+
- LongMemEval_s
|
|
586
|
+
- LoCoMo
|
|
587
|
+
- ConvoMem
|
|
588
|
+
|
|
589
|
+
Record:
|
|
590
|
+
|
|
591
|
+
- answering model
|
|
592
|
+
- judge model
|
|
593
|
+
- extraction model
|
|
594
|
+
- embedding model
|
|
595
|
+
- dataset commit or checksum
|
|
596
|
+
- category accuracy
|
|
597
|
+
- Recall@5, Recall@10, Recall@15
|
|
598
|
+
- MRR and NDCG
|
|
599
|
+
- search p50, p95, p99
|
|
600
|
+
- ingestion latency
|
|
601
|
+
- context tokens
|
|
602
|
+
- extraction and answering cost
|
|
603
|
+
|
|
604
|
+
Do not tune on the full test set. Keep a development subset and a held-out final run.
|
|
605
|
+
|
|
606
|
+
### Phase 1: Provenance and Graph Completeness
|
|
607
|
+
|
|
608
|
+
Implemented in this review:
|
|
609
|
+
|
|
610
|
+
#### `memory_relations`
|
|
611
|
+
|
|
612
|
+
- source memory ID
|
|
613
|
+
- target memory ID
|
|
614
|
+
- relation type
|
|
615
|
+
- confidence
|
|
616
|
+
- evidence source ID
|
|
617
|
+
- created time
|
|
618
|
+
|
|
619
|
+
The existing memory-level relation schema is now populated and used for retrieval expansion. `supersedes_fact_id` remains the direct fact-version pointer.
|
|
620
|
+
|
|
621
|
+
#### Source chunks and links
|
|
622
|
+
|
|
623
|
+
- memory or fact ID
|
|
624
|
+
- source document ID
|
|
625
|
+
- source span or message IDs
|
|
626
|
+
- relevance score
|
|
627
|
+
- source timestamp
|
|
628
|
+
- extraction model and prompt version
|
|
629
|
+
|
|
630
|
+
This enables:
|
|
631
|
+
|
|
632
|
+
- citations
|
|
633
|
+
- reprocessing
|
|
634
|
+
- deletion propagation
|
|
635
|
+
- confidence recalculation
|
|
636
|
+
- auditing incorrect memories
|
|
637
|
+
|
|
638
|
+
#### Embedding Version Metadata
|
|
639
|
+
|
|
640
|
+
Store:
|
|
641
|
+
|
|
642
|
+
- model ID
|
|
643
|
+
- vector dimensions
|
|
644
|
+
- embedding version
|
|
645
|
+
- generated time
|
|
646
|
+
|
|
647
|
+
Implemented for new embeddings, with legacy-provider marking and versioned index backfill.
|
|
648
|
+
|
|
649
|
+
### Phase 2: Scalable Retrieval
|
|
650
|
+
|
|
651
|
+
Implemented. There is no fixed recent-memory semantic cutoff.
|
|
652
|
+
|
|
653
|
+
Required behavior:
|
|
654
|
+
|
|
655
|
+
1. Retrieve lexical and entity candidates from SQLite indexes.
|
|
656
|
+
2. Retrieve semantic candidates from an ANN index.
|
|
657
|
+
3. Merge with reciprocal rank fusion.
|
|
658
|
+
4. Expand update and relation neighbors.
|
|
659
|
+
5. Apply temporal and scope filters.
|
|
660
|
+
6. Rerank only the top candidate set.
|
|
661
|
+
7. Enforce a context token budget.
|
|
662
|
+
|
|
663
|
+
Implementation options must be tested against NeoAgent's deployment constraints. The preferred shape is an embedded local vector index or a SQLite extension that does not create a second application database.
|
|
664
|
+
|
|
665
|
+
Current evidence:
|
|
666
|
+
|
|
667
|
+
- no fixed recent-memory cutoff: verified by regression test
|
|
668
|
+
- index candidate lookup p95 at 100,000 memories: 9.17 ms
|
|
669
|
+
- planted-neighbor candidate recall at cosine 0.80: 98.0 percent
|
|
670
|
+
|
|
671
|
+
Still required:
|
|
672
|
+
|
|
673
|
+
- end-to-end p95 including remote query embedding
|
|
674
|
+
- exact-brute-force comparison on real benchmark embeddings
|
|
675
|
+
- Recall@15 on held-out LongMemEval data
|
|
676
|
+
|
|
677
|
+
### Phase 3: Retrieval Planning and Reranking
|
|
678
|
+
|
|
679
|
+
Implemented as a confidence-triggered path. It produces structured intent, not phrase filters:
|
|
680
|
+
|
|
681
|
+
- entities
|
|
682
|
+
- requested time frame
|
|
683
|
+
- current versus historical intent
|
|
684
|
+
- expected fact predicates
|
|
685
|
+
- query variants
|
|
686
|
+
- whether source documents are needed
|
|
687
|
+
|
|
688
|
+
It runs only when cheap retrieval confidence is insufficient. Default retrieval remains one embedding request plus local indexes and performs no retrieval model call.
|
|
689
|
+
|
|
690
|
+
The configured model reranks at most 24 merged candidates through `engine.js`. It receives:
|
|
691
|
+
|
|
692
|
+
- query
|
|
693
|
+
- candidate fact
|
|
694
|
+
- validity interval
|
|
695
|
+
- relation context
|
|
696
|
+
- source evidence
|
|
697
|
+
|
|
698
|
+
It returns a bounded structured ordering and cannot introduce unknown memories. Planner or reranker failure falls back to deterministic retrieval. Enhancement reason, plan, candidate counts, selected IDs, latency, and run linkage are recorded without retaining the raw query.
|
|
699
|
+
|
|
700
|
+
Still required:
|
|
701
|
+
|
|
702
|
+
- measurable MRR and NDCG improvement on the development set
|
|
703
|
+
- less than 150 ms added p95 for local reranking, or explicit cost and latency accounting for remote reranking
|
|
704
|
+
- no accuracy regression on adversarial or abstention questions
|
|
705
|
+
|
|
706
|
+
### Phase 4: Source Document Processing
|
|
707
|
+
|
|
708
|
+
Implemented:
|
|
709
|
+
|
|
710
|
+
1. content normalization
|
|
711
|
+
2. structure-aware chunking
|
|
712
|
+
3. source-span preservation
|
|
713
|
+
4. embeddings per chunk
|
|
714
|
+
5. document-to-memory provenance links
|
|
715
|
+
|
|
716
|
+
Still required:
|
|
717
|
+
|
|
718
|
+
- memory extraction across related chunks
|
|
719
|
+
- repository AST or symbol-aware boundaries
|
|
720
|
+
- email quote-chain and attachment-aware boundaries
|
|
721
|
+
- neighboring-chunk expansion when a source answer crosses boundaries
|
|
722
|
+
|
|
723
|
+
Chunking should be content-aware:
|
|
724
|
+
|
|
725
|
+
- email threads by message and quoted history
|
|
726
|
+
- chat by turn windows
|
|
727
|
+
- calendar by event
|
|
728
|
+
- repositories by AST or symbol boundaries
|
|
729
|
+
- documents by headings and paragraphs
|
|
730
|
+
|
|
731
|
+
Do not use one universal character cutoff as the primary boundary.
|
|
732
|
+
|
|
733
|
+
### Phase 5: Forgetting and Reinforcement
|
|
734
|
+
|
|
735
|
+
Implemented:
|
|
736
|
+
|
|
737
|
+
- expire facts at `forget_after`
|
|
738
|
+
- downrank old episodes
|
|
739
|
+
- preserve high-value episodes
|
|
740
|
+
- strengthen repeated compatible preferences
|
|
741
|
+
|
|
742
|
+
Still required:
|
|
743
|
+
|
|
744
|
+
- lower confidence on unsupported derivations
|
|
745
|
+
- flag conflicting high-confidence facts for review
|
|
746
|
+
- propagate source deletion where required
|
|
747
|
+
|
|
748
|
+
Forgetting must not mean destructive deletion by default. Expired and superseded facts should remain available for historical questions and audit.
|
|
749
|
+
|
|
750
|
+
### Phase 6: Memory Observability
|
|
751
|
+
|
|
752
|
+
Implemented retrieval event logging:
|
|
753
|
+
|
|
754
|
+
- query hash
|
|
755
|
+
- selected candidates
|
|
756
|
+
- component scores
|
|
757
|
+
- relation expansion
|
|
758
|
+
- token count
|
|
759
|
+
- latency by stage
|
|
760
|
+
|
|
761
|
+
Still required:
|
|
762
|
+
|
|
763
|
+
- answering outcome linkage
|
|
764
|
+
- an operator-facing retrieval inspector
|
|
765
|
+
- stage-specific timing beyond total local retrieval
|
|
766
|
+
|
|
767
|
+
The UI should let an operator answer:
|
|
768
|
+
|
|
769
|
+
- Why was this memory stored?
|
|
770
|
+
- Which source supports it?
|
|
771
|
+
- What did it replace?
|
|
772
|
+
- Why was it retrieved?
|
|
773
|
+
- Why was another result excluded?
|
|
774
|
+
- When will it expire?
|
|
775
|
+
|
|
776
|
+
### Phase 7: Security and Memory Poisoning
|
|
777
|
+
|
|
778
|
+
Memory is a persistent attack surface.
|
|
779
|
+
|
|
780
|
+
Required controls:
|
|
781
|
+
|
|
782
|
+
- distinguish user-authored, assistant-authored, tool-derived, and external-source facts
|
|
783
|
+
- never treat external content instructions as user preferences
|
|
784
|
+
- preserve source trust level
|
|
785
|
+
- require stronger evidence for identity, security, financial, and health facts
|
|
786
|
+
- prevent secrets from entering extracted memories
|
|
787
|
+
- enforce user and agent scope in every relation and source query
|
|
788
|
+
- test deletion and IDOR behavior for new tables
|
|
789
|
+
|
|
790
|
+
## Production Acceptance Standard
|
|
791
|
+
|
|
792
|
+
NeoAgent should be called "as good as Supermemory" only when all of the following are true on a fixed, published configuration:
|
|
793
|
+
|
|
794
|
+
### Quality
|
|
795
|
+
|
|
796
|
+
- LongMemEval_s Recall@15 at least 95 percent
|
|
797
|
+
- knowledge-update recall at least 98 percent
|
|
798
|
+
- no more than one percentage point current-value regression from adding history context
|
|
799
|
+
- LoCoMo single-hop, multi-hop, temporal, and adversarial results reported separately
|
|
800
|
+
- ConvoMem personalization score reported
|
|
801
|
+
- single-answer evaluation only
|
|
802
|
+
|
|
803
|
+
### Efficiency
|
|
804
|
+
|
|
805
|
+
- mean injected memory context at or below 800 tokens
|
|
806
|
+
- p95 local retrieval below 200 ms at 100,000 memories
|
|
807
|
+
- no more than one extraction model call per completed conversational turn
|
|
808
|
+
- no retrieval LLM call on the default fast path
|
|
809
|
+
|
|
810
|
+
### Reliability
|
|
811
|
+
|
|
812
|
+
- read-your-writes behavior for the next conversation turn
|
|
813
|
+
- deterministic user and agent isolation
|
|
814
|
+
- source-backed update history
|
|
815
|
+
- expired facts excluded from current recall
|
|
816
|
+
- historical questions can still recover prior values
|
|
817
|
+
- failed consolidation never blocks the user's main response
|
|
818
|
+
|
|
819
|
+
### Honesty
|
|
820
|
+
|
|
821
|
+
Every published result must include:
|
|
822
|
+
|
|
823
|
+
- exact commit
|
|
824
|
+
- exact dataset
|
|
825
|
+
- exact models
|
|
826
|
+
- exact prompts
|
|
827
|
+
- sample count
|
|
828
|
+
- latency
|
|
829
|
+
- context tokens
|
|
830
|
+
- cost
|
|
831
|
+
- failures
|
|
832
|
+
- whether any ensemble or retry was used
|
|
833
|
+
|
|
834
|
+
## Recommended Order of Work
|
|
835
|
+
|
|
836
|
+
1. Run the local retrieval harness on a development relevance set.
|
|
837
|
+
2. Record MemoryBench LongMemEval_s, LoCoMo, and ConvoMem baselines.
|
|
838
|
+
3. Measure planner/reranker quality, latency, token use, and trigger rate.
|
|
839
|
+
4. Add format-specific ingestion boundaries and cross-chunk extraction.
|
|
840
|
+
5. Add retrieval inspection and answer-outcome linkage.
|
|
841
|
+
6. Harden poisoning, deletion propagation, and high-confidence conflict review.
|
|
842
|
+
7. Re-run held-out benchmarks and only then make parity claims.
|
|
843
|
+
|
|
844
|
+
## Bottom Line
|
|
845
|
+
|
|
846
|
+
NeoAgent should adopt Supermemory's useful architecture principles, not its marketing number and not its hosted API as a second brain.
|
|
847
|
+
|
|
848
|
+
The immediate quality problem was that NeoAgent's temporal schema was fed weak facts. That path is now materially stronger: conversations produce atomic, evidenced, time-aware facts; updates replace prior current values; prior values remain available as history; and active facts form an automatic profile.
|
|
849
|
+
|
|
850
|
+
The 800-row vector ceiling is gone, source provenance is first-class, relations participate in retrieval, external content is trust-separated, difficult queries can be planned and reranked, and retrieval can now be measured through both the local harness and MemoryBench. The next limiting factors are real benchmark evidence, planner/reranker measurement, and format-specific extraction quality.
|
|
851
|
+
|
|
852
|
+
There is still no defensible basis for claiming Supermemory-level quality until held-out LongMemEval_s, LoCoMo, and ConvoMem results satisfy the production acceptance standard above. The implementation is now capable of being evaluated against that standard instead of relying on architecture claims alone.
|