neural-memory 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- neural_memory/__init__.py +38 -0
- neural_memory/cli/__init__.py +15 -0
- neural_memory/cli/__main__.py +6 -0
- neural_memory/cli/config.py +176 -0
- neural_memory/cli/main.py +2702 -0
- neural_memory/cli/storage.py +169 -0
- neural_memory/cli/tui.py +471 -0
- neural_memory/core/__init__.py +52 -0
- neural_memory/core/brain.py +301 -0
- neural_memory/core/brain_mode.py +273 -0
- neural_memory/core/fiber.py +236 -0
- neural_memory/core/memory_types.py +331 -0
- neural_memory/core/neuron.py +168 -0
- neural_memory/core/project.py +257 -0
- neural_memory/core/synapse.py +215 -0
- neural_memory/engine/__init__.py +15 -0
- neural_memory/engine/activation.py +335 -0
- neural_memory/engine/encoder.py +391 -0
- neural_memory/engine/retrieval.py +440 -0
- neural_memory/extraction/__init__.py +42 -0
- neural_memory/extraction/entities.py +547 -0
- neural_memory/extraction/parser.py +337 -0
- neural_memory/extraction/router.py +396 -0
- neural_memory/extraction/temporal.py +428 -0
- neural_memory/mcp/__init__.py +9 -0
- neural_memory/mcp/__main__.py +6 -0
- neural_memory/mcp/server.py +621 -0
- neural_memory/py.typed +0 -0
- neural_memory/safety/__init__.py +31 -0
- neural_memory/safety/freshness.py +238 -0
- neural_memory/safety/sensitive.py +304 -0
- neural_memory/server/__init__.py +5 -0
- neural_memory/server/app.py +99 -0
- neural_memory/server/dependencies.py +33 -0
- neural_memory/server/models.py +138 -0
- neural_memory/server/routes/__init__.py +7 -0
- neural_memory/server/routes/brain.py +221 -0
- neural_memory/server/routes/memory.py +169 -0
- neural_memory/server/routes/sync.py +387 -0
- neural_memory/storage/__init__.py +17 -0
- neural_memory/storage/base.py +441 -0
- neural_memory/storage/factory.py +329 -0
- neural_memory/storage/memory_store.py +896 -0
- neural_memory/storage/shared_store.py +650 -0
- neural_memory/storage/sqlite_store.py +1613 -0
- neural_memory/sync/__init__.py +5 -0
- neural_memory/sync/client.py +435 -0
- neural_memory/unified_config.py +315 -0
- neural_memory/utils/__init__.py +5 -0
- neural_memory/utils/config.py +98 -0
- neural_memory-0.1.0.dist-info/METADATA +314 -0
- neural_memory-0.1.0.dist-info/RECORD +55 -0
- neural_memory-0.1.0.dist-info/WHEEL +4 -0
- neural_memory-0.1.0.dist-info/entry_points.txt +4 -0
- neural_memory-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
"""Abstract base class for neural storage backends."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import TYPE_CHECKING, Literal
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from neural_memory.core.brain import Brain, BrainSnapshot
|
|
11
|
+
from neural_memory.core.fiber import Fiber
|
|
12
|
+
from neural_memory.core.neuron import Neuron, NeuronState, NeuronType
|
|
13
|
+
from neural_memory.core.synapse import Synapse, SynapseType
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class NeuralStorage(ABC):
|
|
17
|
+
"""
|
|
18
|
+
Abstract interface for neural graph storage.
|
|
19
|
+
|
|
20
|
+
Implementations must provide all methods for storing and
|
|
21
|
+
retrieving neurons, synapses, fibers, and brain metadata.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# ========== Neuron Operations ==========
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def add_neuron(self, neuron: Neuron) -> str:
|
|
28
|
+
"""
|
|
29
|
+
Add a neuron to storage.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
neuron: The neuron to add
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
The neuron ID
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
ValueError: If neuron with same ID already exists
|
|
39
|
+
"""
|
|
40
|
+
...
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
async def get_neuron(self, neuron_id: str) -> Neuron | None:
|
|
44
|
+
"""
|
|
45
|
+
Get a neuron by ID.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
neuron_id: The neuron ID
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
The neuron if found, None otherwise
|
|
52
|
+
"""
|
|
53
|
+
...
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
async def find_neurons(
|
|
57
|
+
self,
|
|
58
|
+
type: NeuronType | None = None,
|
|
59
|
+
content_contains: str | None = None,
|
|
60
|
+
content_exact: str | None = None,
|
|
61
|
+
time_range: tuple[datetime, datetime] | None = None,
|
|
62
|
+
limit: int = 100,
|
|
63
|
+
) -> list[Neuron]:
|
|
64
|
+
"""
|
|
65
|
+
Find neurons matching criteria.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
type: Filter by neuron type
|
|
69
|
+
content_contains: Filter by content substring (case-insensitive)
|
|
70
|
+
content_exact: Filter by exact content match
|
|
71
|
+
time_range: Filter by created_at within range
|
|
72
|
+
limit: Maximum results to return
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
List of matching neurons
|
|
76
|
+
"""
|
|
77
|
+
...
|
|
78
|
+
|
|
79
|
+
@abstractmethod
|
|
80
|
+
async def update_neuron(self, neuron: Neuron) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Update an existing neuron.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
neuron: The updated neuron (must have existing ID)
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
ValueError: If neuron doesn't exist
|
|
89
|
+
"""
|
|
90
|
+
...
|
|
91
|
+
|
|
92
|
+
@abstractmethod
|
|
93
|
+
async def delete_neuron(self, neuron_id: str) -> bool:
|
|
94
|
+
"""
|
|
95
|
+
Delete a neuron and its connected synapses.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
neuron_id: The neuron ID to delete
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
True if deleted, False if not found
|
|
102
|
+
"""
|
|
103
|
+
...
|
|
104
|
+
|
|
105
|
+
# ========== Neuron State Operations ==========
|
|
106
|
+
|
|
107
|
+
@abstractmethod
|
|
108
|
+
async def get_neuron_state(self, neuron_id: str) -> NeuronState | None:
|
|
109
|
+
"""
|
|
110
|
+
Get the activation state for a neuron.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
neuron_id: The neuron ID
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
The state if found, None otherwise
|
|
117
|
+
"""
|
|
118
|
+
...
|
|
119
|
+
|
|
120
|
+
@abstractmethod
|
|
121
|
+
async def update_neuron_state(self, state: NeuronState) -> None:
|
|
122
|
+
"""
|
|
123
|
+
Update or create neuron activation state.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
state: The state to save
|
|
127
|
+
"""
|
|
128
|
+
...
|
|
129
|
+
|
|
130
|
+
# ========== Synapse Operations ==========
|
|
131
|
+
|
|
132
|
+
@abstractmethod
|
|
133
|
+
async def add_synapse(self, synapse: Synapse) -> str:
|
|
134
|
+
"""
|
|
135
|
+
Add a synapse to storage.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
synapse: The synapse to add
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
The synapse ID
|
|
142
|
+
|
|
143
|
+
Raises:
|
|
144
|
+
ValueError: If synapse with same ID exists, or neurons don't exist
|
|
145
|
+
"""
|
|
146
|
+
...
|
|
147
|
+
|
|
148
|
+
@abstractmethod
|
|
149
|
+
async def get_synapse(self, synapse_id: str) -> Synapse | None:
|
|
150
|
+
"""
|
|
151
|
+
Get a synapse by ID.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
synapse_id: The synapse ID
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
The synapse if found, None otherwise
|
|
158
|
+
"""
|
|
159
|
+
...
|
|
160
|
+
|
|
161
|
+
@abstractmethod
|
|
162
|
+
async def get_synapses(
|
|
163
|
+
self,
|
|
164
|
+
source_id: str | None = None,
|
|
165
|
+
target_id: str | None = None,
|
|
166
|
+
type: SynapseType | None = None,
|
|
167
|
+
min_weight: float | None = None,
|
|
168
|
+
) -> list[Synapse]:
|
|
169
|
+
"""
|
|
170
|
+
Find synapses matching criteria.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
source_id: Filter by source neuron
|
|
174
|
+
target_id: Filter by target neuron
|
|
175
|
+
type: Filter by synapse type
|
|
176
|
+
min_weight: Filter by minimum weight
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
List of matching synapses
|
|
180
|
+
"""
|
|
181
|
+
...
|
|
182
|
+
|
|
183
|
+
@abstractmethod
|
|
184
|
+
async def update_synapse(self, synapse: Synapse) -> None:
|
|
185
|
+
"""
|
|
186
|
+
Update an existing synapse.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
synapse: The updated synapse
|
|
190
|
+
|
|
191
|
+
Raises:
|
|
192
|
+
ValueError: If synapse doesn't exist
|
|
193
|
+
"""
|
|
194
|
+
...
|
|
195
|
+
|
|
196
|
+
@abstractmethod
|
|
197
|
+
async def delete_synapse(self, synapse_id: str) -> bool:
|
|
198
|
+
"""
|
|
199
|
+
Delete a synapse.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
synapse_id: The synapse ID to delete
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
True if deleted, False if not found
|
|
206
|
+
"""
|
|
207
|
+
...
|
|
208
|
+
|
|
209
|
+
# ========== Graph Traversal ==========
|
|
210
|
+
|
|
211
|
+
@abstractmethod
|
|
212
|
+
async def get_neighbors(
|
|
213
|
+
self,
|
|
214
|
+
neuron_id: str,
|
|
215
|
+
direction: Literal["out", "in", "both"] = "both",
|
|
216
|
+
synapse_types: list[SynapseType] | None = None,
|
|
217
|
+
min_weight: float | None = None,
|
|
218
|
+
) -> list[tuple[Neuron, Synapse]]:
|
|
219
|
+
"""
|
|
220
|
+
Get neighboring neurons connected by synapses.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
neuron_id: The central neuron ID
|
|
224
|
+
direction: Which direction to traverse
|
|
225
|
+
- "out": Only follow outgoing synapses
|
|
226
|
+
- "in": Only follow incoming synapses
|
|
227
|
+
- "both": Follow both directions
|
|
228
|
+
synapse_types: Only follow these synapse types
|
|
229
|
+
min_weight: Only follow synapses with weight >= this
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
List of (neighbor_neuron, connecting_synapse) tuples
|
|
233
|
+
"""
|
|
234
|
+
...
|
|
235
|
+
|
|
236
|
+
@abstractmethod
|
|
237
|
+
async def get_path(
|
|
238
|
+
self,
|
|
239
|
+
source_id: str,
|
|
240
|
+
target_id: str,
|
|
241
|
+
max_hops: int = 4,
|
|
242
|
+
) -> list[tuple[Neuron, Synapse]] | None:
|
|
243
|
+
"""
|
|
244
|
+
Find shortest path between two neurons.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
source_id: Starting neuron ID
|
|
248
|
+
target_id: Target neuron ID
|
|
249
|
+
max_hops: Maximum path length
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
List of (neuron, synapse) pairs representing path, or None if no path
|
|
253
|
+
"""
|
|
254
|
+
...
|
|
255
|
+
|
|
256
|
+
# ========== Fiber Operations ==========
|
|
257
|
+
|
|
258
|
+
@abstractmethod
|
|
259
|
+
async def add_fiber(self, fiber: Fiber) -> str:
|
|
260
|
+
"""
|
|
261
|
+
Add a fiber to storage.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
fiber: The fiber to add
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
The fiber ID
|
|
268
|
+
|
|
269
|
+
Raises:
|
|
270
|
+
ValueError: If fiber with same ID exists
|
|
271
|
+
"""
|
|
272
|
+
...
|
|
273
|
+
|
|
274
|
+
@abstractmethod
|
|
275
|
+
async def get_fiber(self, fiber_id: str) -> Fiber | None:
|
|
276
|
+
"""
|
|
277
|
+
Get a fiber by ID.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
fiber_id: The fiber ID
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
The fiber if found, None otherwise
|
|
284
|
+
"""
|
|
285
|
+
...
|
|
286
|
+
|
|
287
|
+
@abstractmethod
|
|
288
|
+
async def find_fibers(
|
|
289
|
+
self,
|
|
290
|
+
contains_neuron: str | None = None,
|
|
291
|
+
time_overlaps: tuple[datetime, datetime] | None = None,
|
|
292
|
+
tags: set[str] | None = None,
|
|
293
|
+
min_salience: float | None = None,
|
|
294
|
+
limit: int = 100,
|
|
295
|
+
) -> list[Fiber]:
|
|
296
|
+
"""
|
|
297
|
+
Find fibers matching criteria.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
contains_neuron: Filter by containing this neuron ID
|
|
301
|
+
time_overlaps: Filter by time range overlap
|
|
302
|
+
tags: Filter by having all these tags
|
|
303
|
+
min_salience: Filter by minimum salience
|
|
304
|
+
limit: Maximum results
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
List of matching fibers
|
|
308
|
+
"""
|
|
309
|
+
...
|
|
310
|
+
|
|
311
|
+
@abstractmethod
|
|
312
|
+
async def update_fiber(self, fiber: Fiber) -> None:
|
|
313
|
+
"""
|
|
314
|
+
Update an existing fiber.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
fiber: The updated fiber
|
|
318
|
+
|
|
319
|
+
Raises:
|
|
320
|
+
ValueError: If fiber doesn't exist
|
|
321
|
+
"""
|
|
322
|
+
...
|
|
323
|
+
|
|
324
|
+
@abstractmethod
|
|
325
|
+
async def delete_fiber(self, fiber_id: str) -> bool:
|
|
326
|
+
"""
|
|
327
|
+
Delete a fiber.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
fiber_id: The fiber ID to delete
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
True if deleted, False if not found
|
|
334
|
+
"""
|
|
335
|
+
...
|
|
336
|
+
|
|
337
|
+
@abstractmethod
|
|
338
|
+
async def get_fibers(
|
|
339
|
+
self,
|
|
340
|
+
limit: int = 10,
|
|
341
|
+
order_by: Literal["created_at", "salience", "frequency"] = "created_at",
|
|
342
|
+
descending: bool = True,
|
|
343
|
+
) -> list[Fiber]:
|
|
344
|
+
"""
|
|
345
|
+
Get fibers with ordering.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
limit: Maximum results
|
|
349
|
+
order_by: Field to order by
|
|
350
|
+
descending: Sort descending if True
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
List of fibers
|
|
354
|
+
"""
|
|
355
|
+
...
|
|
356
|
+
|
|
357
|
+
# ========== Brain Operations ==========
|
|
358
|
+
|
|
359
|
+
@abstractmethod
|
|
360
|
+
async def save_brain(self, brain: Brain) -> None:
|
|
361
|
+
"""
|
|
362
|
+
Save or update brain metadata.
|
|
363
|
+
|
|
364
|
+
Args:
|
|
365
|
+
brain: The brain to save
|
|
366
|
+
"""
|
|
367
|
+
...
|
|
368
|
+
|
|
369
|
+
@abstractmethod
|
|
370
|
+
async def get_brain(self, brain_id: str) -> Brain | None:
|
|
371
|
+
"""
|
|
372
|
+
Get brain metadata by ID.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
brain_id: The brain ID
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
The brain if found, None otherwise
|
|
379
|
+
"""
|
|
380
|
+
...
|
|
381
|
+
|
|
382
|
+
@abstractmethod
|
|
383
|
+
async def export_brain(self, brain_id: str) -> BrainSnapshot:
|
|
384
|
+
"""
|
|
385
|
+
Export entire brain as a snapshot.
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
brain_id: The brain ID to export
|
|
389
|
+
|
|
390
|
+
Returns:
|
|
391
|
+
Complete snapshot of the brain
|
|
392
|
+
|
|
393
|
+
Raises:
|
|
394
|
+
ValueError: If brain doesn't exist
|
|
395
|
+
"""
|
|
396
|
+
...
|
|
397
|
+
|
|
398
|
+
@abstractmethod
|
|
399
|
+
async def import_brain(
|
|
400
|
+
self,
|
|
401
|
+
snapshot: BrainSnapshot,
|
|
402
|
+
target_brain_id: str | None = None,
|
|
403
|
+
) -> str:
|
|
404
|
+
"""
|
|
405
|
+
Import a brain snapshot.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
snapshot: The snapshot to import
|
|
409
|
+
target_brain_id: Optional ID for the imported brain
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
The ID of the imported brain
|
|
413
|
+
"""
|
|
414
|
+
...
|
|
415
|
+
|
|
416
|
+
# ========== Statistics ==========
|
|
417
|
+
|
|
418
|
+
@abstractmethod
|
|
419
|
+
async def get_stats(self, brain_id: str) -> dict[str, int]:
|
|
420
|
+
"""
|
|
421
|
+
Get statistics for a brain.
|
|
422
|
+
|
|
423
|
+
Args:
|
|
424
|
+
brain_id: The brain ID
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
Dict with keys: neuron_count, synapse_count, fiber_count
|
|
428
|
+
"""
|
|
429
|
+
...
|
|
430
|
+
|
|
431
|
+
# ========== Cleanup ==========
|
|
432
|
+
|
|
433
|
+
@abstractmethod
|
|
434
|
+
async def clear(self, brain_id: str) -> None:
|
|
435
|
+
"""
|
|
436
|
+
Clear all data for a brain.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
brain_id: The brain ID to clear
|
|
440
|
+
"""
|
|
441
|
+
...
|