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.
Files changed (55) hide show
  1. neural_memory/__init__.py +38 -0
  2. neural_memory/cli/__init__.py +15 -0
  3. neural_memory/cli/__main__.py +6 -0
  4. neural_memory/cli/config.py +176 -0
  5. neural_memory/cli/main.py +2702 -0
  6. neural_memory/cli/storage.py +169 -0
  7. neural_memory/cli/tui.py +471 -0
  8. neural_memory/core/__init__.py +52 -0
  9. neural_memory/core/brain.py +301 -0
  10. neural_memory/core/brain_mode.py +273 -0
  11. neural_memory/core/fiber.py +236 -0
  12. neural_memory/core/memory_types.py +331 -0
  13. neural_memory/core/neuron.py +168 -0
  14. neural_memory/core/project.py +257 -0
  15. neural_memory/core/synapse.py +215 -0
  16. neural_memory/engine/__init__.py +15 -0
  17. neural_memory/engine/activation.py +335 -0
  18. neural_memory/engine/encoder.py +391 -0
  19. neural_memory/engine/retrieval.py +440 -0
  20. neural_memory/extraction/__init__.py +42 -0
  21. neural_memory/extraction/entities.py +547 -0
  22. neural_memory/extraction/parser.py +337 -0
  23. neural_memory/extraction/router.py +396 -0
  24. neural_memory/extraction/temporal.py +428 -0
  25. neural_memory/mcp/__init__.py +9 -0
  26. neural_memory/mcp/__main__.py +6 -0
  27. neural_memory/mcp/server.py +621 -0
  28. neural_memory/py.typed +0 -0
  29. neural_memory/safety/__init__.py +31 -0
  30. neural_memory/safety/freshness.py +238 -0
  31. neural_memory/safety/sensitive.py +304 -0
  32. neural_memory/server/__init__.py +5 -0
  33. neural_memory/server/app.py +99 -0
  34. neural_memory/server/dependencies.py +33 -0
  35. neural_memory/server/models.py +138 -0
  36. neural_memory/server/routes/__init__.py +7 -0
  37. neural_memory/server/routes/brain.py +221 -0
  38. neural_memory/server/routes/memory.py +169 -0
  39. neural_memory/server/routes/sync.py +387 -0
  40. neural_memory/storage/__init__.py +17 -0
  41. neural_memory/storage/base.py +441 -0
  42. neural_memory/storage/factory.py +329 -0
  43. neural_memory/storage/memory_store.py +896 -0
  44. neural_memory/storage/shared_store.py +650 -0
  45. neural_memory/storage/sqlite_store.py +1613 -0
  46. neural_memory/sync/__init__.py +5 -0
  47. neural_memory/sync/client.py +435 -0
  48. neural_memory/unified_config.py +315 -0
  49. neural_memory/utils/__init__.py +5 -0
  50. neural_memory/utils/config.py +98 -0
  51. neural_memory-0.1.0.dist-info/METADATA +314 -0
  52. neural_memory-0.1.0.dist-info/RECORD +55 -0
  53. neural_memory-0.1.0.dist-info/WHEEL +4 -0
  54. neural_memory-0.1.0.dist-info/entry_points.txt +4 -0
  55. neural_memory-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,315 @@
1
+ """Unified configuration for NeuralMemory across all tools.
2
+
3
+ This module provides a single configuration system that works across:
4
+ - CLI (nmem command)
5
+ - MCP server (Claude Code, Cursor, AntiGravity)
6
+ - REST API server
7
+ - Any future integrations
8
+
9
+ Configuration is stored in ~/.neuralmemory/config.toml
10
+ Brain data is stored in ~/.neuralmemory/brains/<name>.db (SQLite)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import os
16
+ from dataclasses import dataclass, field
17
+ from datetime import datetime
18
+ from pathlib import Path
19
+ from typing import Any
20
+
21
+ # Try to import tomllib (Python 3.11+) or fallback
22
+ try:
23
+ import tomllib
24
+ except ImportError:
25
+ import tomli as tomllib # type: ignore
26
+
27
+
28
+ def get_neuralmemory_dir() -> Path:
29
+ """Get NeuralMemory data directory.
30
+
31
+ Priority:
32
+ 1. NEURALMEMORY_DIR environment variable
33
+ 2. ~/.neuralmemory/
34
+ """
35
+ env_dir = os.environ.get("NEURALMEMORY_DIR")
36
+ if env_dir:
37
+ return Path(env_dir)
38
+ return Path.home() / ".neuralmemory"
39
+
40
+
41
+ def get_default_brain() -> str:
42
+ """Get default brain name.
43
+
44
+ Priority:
45
+ 1. NEURALMEMORY_BRAIN environment variable
46
+ 2. "default"
47
+ """
48
+ return os.environ.get("NEURALMEMORY_BRAIN", "default")
49
+
50
+
51
+ @dataclass
52
+ class AutoConfig:
53
+ """Auto-capture configuration for MCP server."""
54
+
55
+ enabled: bool = False
56
+ capture_decisions: bool = True
57
+ capture_errors: bool = True
58
+ capture_todos: bool = True
59
+ capture_facts: bool = True
60
+ min_confidence: float = 0.7
61
+
62
+ def to_dict(self) -> dict[str, Any]:
63
+ return {
64
+ "enabled": self.enabled,
65
+ "capture_decisions": self.capture_decisions,
66
+ "capture_errors": self.capture_errors,
67
+ "capture_todos": self.capture_todos,
68
+ "capture_facts": self.capture_facts,
69
+ "min_confidence": self.min_confidence,
70
+ }
71
+
72
+ @classmethod
73
+ def from_dict(cls, data: dict[str, Any]) -> AutoConfig:
74
+ return cls(
75
+ enabled=data.get("enabled", False),
76
+ capture_decisions=data.get("capture_decisions", True),
77
+ capture_errors=data.get("capture_errors", True),
78
+ capture_todos=data.get("capture_todos", True),
79
+ capture_facts=data.get("capture_facts", True),
80
+ min_confidence=data.get("min_confidence", 0.7),
81
+ )
82
+
83
+
84
+ @dataclass
85
+ class BrainSettings:
86
+ """Settings for brain behavior."""
87
+
88
+ decay_rate: float = 0.1
89
+ reinforcement_delta: float = 0.05
90
+ activation_threshold: float = 0.2
91
+ max_spread_hops: int = 4
92
+ max_context_tokens: int = 1500
93
+
94
+ def to_dict(self) -> dict[str, Any]:
95
+ return {
96
+ "decay_rate": self.decay_rate,
97
+ "reinforcement_delta": self.reinforcement_delta,
98
+ "activation_threshold": self.activation_threshold,
99
+ "max_spread_hops": self.max_spread_hops,
100
+ "max_context_tokens": self.max_context_tokens,
101
+ }
102
+
103
+ @classmethod
104
+ def from_dict(cls, data: dict[str, Any]) -> BrainSettings:
105
+ return cls(
106
+ decay_rate=data.get("decay_rate", 0.1),
107
+ reinforcement_delta=data.get("reinforcement_delta", 0.05),
108
+ activation_threshold=data.get("activation_threshold", 0.2),
109
+ max_spread_hops=data.get("max_spread_hops", 4),
110
+ max_context_tokens=data.get("max_context_tokens", 1500),
111
+ )
112
+
113
+
114
+ @dataclass
115
+ class UnifiedConfig:
116
+ """Unified configuration for NeuralMemory.
117
+
118
+ This configuration is shared across all tools:
119
+ - CLI: nmem commands
120
+ - MCP: Claude Code, Cursor, AntiGravity
121
+ - API: REST server
122
+
123
+ Storage location: ~/.neuralmemory/config.toml
124
+ Brain location: ~/.neuralmemory/brains/<name>.db
125
+ """
126
+
127
+ # Base directory for all NeuralMemory data
128
+ data_dir: Path = field(default_factory=get_neuralmemory_dir)
129
+
130
+ # Current active brain
131
+ current_brain: str = field(default_factory=get_default_brain)
132
+
133
+ # Brain settings
134
+ brain: BrainSettings = field(default_factory=BrainSettings)
135
+
136
+ # Auto-capture settings for MCP
137
+ auto: AutoConfig = field(default_factory=AutoConfig)
138
+
139
+ # CLI preferences
140
+ json_output: bool = False
141
+ default_depth: int | None = None
142
+ default_max_tokens: int = 500
143
+
144
+ # Metadata
145
+ version: str = "1.0"
146
+ updated_at: datetime | None = None
147
+
148
+ @classmethod
149
+ def load(cls, config_path: Path | None = None) -> UnifiedConfig:
150
+ """Load configuration from file, or create default if doesn't exist."""
151
+ if config_path is None:
152
+ data_dir = get_neuralmemory_dir()
153
+ config_path = data_dir / "config.toml"
154
+ else:
155
+ data_dir = config_path.parent
156
+
157
+ if not config_path.exists():
158
+ # Create default config
159
+ config = cls(data_dir=data_dir)
160
+ config.save()
161
+ return config
162
+
163
+ with open(config_path, "rb") as f:
164
+ data = tomllib.load(f)
165
+
166
+ return cls(
167
+ data_dir=data_dir,
168
+ current_brain=data.get("current_brain", get_default_brain()),
169
+ brain=BrainSettings.from_dict(data.get("brain", {})),
170
+ auto=AutoConfig.from_dict(data.get("auto", {})),
171
+ json_output=data.get("cli", {}).get("json_output", False),
172
+ default_depth=data.get("cli", {}).get("default_depth"),
173
+ default_max_tokens=data.get("cli", {}).get("default_max_tokens", 500),
174
+ version=data.get("version", "1.0"),
175
+ )
176
+
177
+ def save(self) -> None:
178
+ """Save configuration to TOML file."""
179
+ self.data_dir.mkdir(parents=True, exist_ok=True)
180
+ config_path = self.data_dir / "config.toml"
181
+
182
+ # Build TOML content manually (no toml write dependency)
183
+ lines = [
184
+ "# NeuralMemory Configuration",
185
+ "# This config is shared by CLI, MCP server, and all integrations",
186
+ "",
187
+ f'version = "{self.version}"',
188
+ f'current_brain = "{self.current_brain}"',
189
+ "",
190
+ "# Brain behavior settings",
191
+ "[brain]",
192
+ f"decay_rate = {self.brain.decay_rate}",
193
+ f"reinforcement_delta = {self.brain.reinforcement_delta}",
194
+ f"activation_threshold = {self.brain.activation_threshold}",
195
+ f"max_spread_hops = {self.brain.max_spread_hops}",
196
+ f"max_context_tokens = {self.brain.max_context_tokens}",
197
+ "",
198
+ "# Auto-capture settings for MCP server",
199
+ "[auto]",
200
+ f"enabled = {'true' if self.auto.enabled else 'false'}",
201
+ f"capture_decisions = {'true' if self.auto.capture_decisions else 'false'}",
202
+ f"capture_errors = {'true' if self.auto.capture_errors else 'false'}",
203
+ f"capture_todos = {'true' if self.auto.capture_todos else 'false'}",
204
+ f"capture_facts = {'true' if self.auto.capture_facts else 'false'}",
205
+ f"min_confidence = {self.auto.min_confidence}",
206
+ "",
207
+ "# CLI preferences",
208
+ "[cli]",
209
+ f"json_output = {'true' if self.json_output else 'false'}",
210
+ f"default_max_tokens = {self.default_max_tokens}",
211
+ ]
212
+
213
+ if self.default_depth is not None:
214
+ lines.append(f"default_depth = {self.default_depth}")
215
+
216
+ with open(config_path, "w", encoding="utf-8") as f:
217
+ f.write("\n".join(lines) + "\n")
218
+
219
+ @property
220
+ def brains_dir(self) -> Path:
221
+ """Get directory where brain databases are stored."""
222
+ return self.data_dir / "brains"
223
+
224
+ @property
225
+ def config_path(self) -> Path:
226
+ """Get path to config file."""
227
+ return self.data_dir / "config.toml"
228
+
229
+ def get_brain_db_path(self, brain_name: str | None = None) -> Path:
230
+ """Get path to brain SQLite database.
231
+
232
+ Args:
233
+ brain_name: Brain name, or use current_brain if None
234
+
235
+ Returns:
236
+ Path to SQLite database file
237
+ """
238
+ name = brain_name or self.current_brain
239
+ return self.brains_dir / f"{name}.db"
240
+
241
+ def list_brains(self) -> list[str]:
242
+ """List available brains (by database files)."""
243
+ if not self.brains_dir.exists():
244
+ return []
245
+ return [p.stem for p in self.brains_dir.glob("*.db")]
246
+
247
+ def switch_brain(self, brain_name: str) -> None:
248
+ """Switch to a different brain and save config."""
249
+ self.current_brain = brain_name
250
+ self.save()
251
+
252
+
253
+ # Singleton instance for easy access
254
+ _config: UnifiedConfig | None = None
255
+
256
+
257
+ def get_config(reload: bool = False) -> UnifiedConfig:
258
+ """Get the unified configuration (singleton).
259
+
260
+ Args:
261
+ reload: Force reload from disk
262
+
263
+ Returns:
264
+ UnifiedConfig instance
265
+ """
266
+ global _config
267
+ if _config is None or reload:
268
+ _config = UnifiedConfig.load()
269
+ return _config
270
+
271
+
272
+ async def get_shared_storage(brain_name: str | None = None):
273
+ """Get SQLite storage for shared brain access.
274
+
275
+ This is the main entry point for getting storage that works
276
+ across CLI, MCP, and other tools.
277
+
278
+ Args:
279
+ brain_name: Brain name, or use config's current_brain if None
280
+
281
+ Returns:
282
+ SQLiteStorage instance, initialized and ready to use
283
+ """
284
+ from neural_memory.core.brain import Brain
285
+ from neural_memory.storage.sqlite_store import SQLiteStorage
286
+
287
+ config = get_config()
288
+ db_path = config.get_brain_db_path(brain_name)
289
+
290
+ # Ensure directory exists
291
+ db_path.parent.mkdir(parents=True, exist_ok=True)
292
+
293
+ # Create and initialize storage
294
+ storage = SQLiteStorage(db_path)
295
+ await storage.initialize()
296
+
297
+ # Create brain if it doesn't exist
298
+ name = brain_name or config.current_brain
299
+ brain = await storage.get_brain(name)
300
+
301
+ if brain is None:
302
+ from neural_memory.core.brain import BrainConfig
303
+
304
+ brain_config = BrainConfig(
305
+ decay_rate=config.brain.decay_rate,
306
+ reinforcement_delta=config.brain.reinforcement_delta,
307
+ activation_threshold=config.brain.activation_threshold,
308
+ max_spread_hops=config.brain.max_spread_hops,
309
+ max_context_tokens=config.brain.max_context_tokens,
310
+ )
311
+ brain = Brain.create(name=name, config=brain_config, brain_id=name)
312
+ await storage.save_brain(brain)
313
+
314
+ storage.set_brain(brain.id)
315
+ return storage
@@ -0,0 +1,5 @@
1
+ """Utility modules for NeuralMemory."""
2
+
3
+ from neural_memory.utils.config import Config, get_config
4
+
5
+ __all__ = ["Config", "get_config"]
@@ -0,0 +1,98 @@
1
+ """Configuration management for NeuralMemory."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from dataclasses import dataclass, field
7
+
8
+
9
+ @dataclass
10
+ class Config:
11
+ """
12
+ Application configuration.
13
+
14
+ Loaded from environment variables with sensible defaults.
15
+ """
16
+
17
+ # Server settings
18
+ host: str = "0.0.0.0"
19
+ port: int = 8000
20
+ debug: bool = False
21
+
22
+ # Storage settings
23
+ storage_backend: str = "memory" # memory, sqlite, neo4j
24
+ sqlite_path: str | None = None
25
+ neo4j_uri: str | None = None
26
+ neo4j_user: str | None = None
27
+ neo4j_password: str | None = None
28
+
29
+ # Brain defaults
30
+ default_decay_rate: float = 0.1
31
+ default_activation_threshold: float = 0.2
32
+ default_max_spread_hops: int = 4
33
+ default_max_context_tokens: int = 1500
34
+
35
+ # CORS settings
36
+ cors_origins: list[str] = field(default_factory=lambda: ["*"])
37
+
38
+ @classmethod
39
+ def from_env(cls) -> Config:
40
+ """Load configuration from environment variables."""
41
+
42
+ def get_bool(key: str, default: bool) -> bool:
43
+ value = os.getenv(key)
44
+ if value is None:
45
+ return default
46
+ return value.lower() in ("true", "1", "yes")
47
+
48
+ def get_int(key: str, default: int) -> int:
49
+ value = os.getenv(key)
50
+ if value is None:
51
+ return default
52
+ return int(value)
53
+
54
+ def get_float(key: str, default: float) -> float:
55
+ value = os.getenv(key)
56
+ if value is None:
57
+ return default
58
+ return float(value)
59
+
60
+ def get_list(key: str, default: list[str]) -> list[str]:
61
+ value = os.getenv(key)
62
+ if value is None:
63
+ return default
64
+ return [s.strip() for s in value.split(",")]
65
+
66
+ return cls(
67
+ host=os.getenv("NEURAL_MEMORY_HOST", "0.0.0.0"),
68
+ port=get_int("NEURAL_MEMORY_PORT", 8000),
69
+ debug=get_bool("NEURAL_MEMORY_DEBUG", False),
70
+ storage_backend=os.getenv("NEURAL_MEMORY_STORAGE", "memory"),
71
+ sqlite_path=os.getenv("NEURAL_MEMORY_SQLITE_PATH"),
72
+ neo4j_uri=os.getenv("NEURAL_MEMORY_NEO4J_URI"),
73
+ neo4j_user=os.getenv("NEURAL_MEMORY_NEO4J_USER"),
74
+ neo4j_password=os.getenv("NEURAL_MEMORY_NEO4J_PASSWORD"),
75
+ default_decay_rate=get_float("NEURAL_MEMORY_DECAY_RATE", 0.1),
76
+ default_activation_threshold=get_float("NEURAL_MEMORY_ACTIVATION_THRESHOLD", 0.2),
77
+ default_max_spread_hops=get_int("NEURAL_MEMORY_MAX_SPREAD_HOPS", 4),
78
+ default_max_context_tokens=get_int("NEURAL_MEMORY_MAX_CONTEXT_TOKENS", 1500),
79
+ cors_origins=get_list("NEURAL_MEMORY_CORS_ORIGINS", ["*"]),
80
+ )
81
+
82
+
83
+ # Singleton config instance
84
+ _config: Config | None = None
85
+
86
+
87
+ def get_config() -> Config:
88
+ """Get the global configuration instance."""
89
+ global _config
90
+ if _config is None:
91
+ _config = Config.from_env()
92
+ return _config
93
+
94
+
95
+ def reset_config() -> None:
96
+ """Reset the global configuration (useful for testing)."""
97
+ global _config
98
+ _config = None