rewind-memory 0.1.0__tar.gz
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.
- rewind_memory-0.1.0/LICENSE +17 -0
- rewind_memory-0.1.0/PKG-INFO +220 -0
- rewind_memory-0.1.0/README.md +188 -0
- rewind_memory-0.1.0/pyproject.toml +45 -0
- rewind_memory-0.1.0/rewind/__init__.py +7 -0
- rewind_memory-0.1.0/rewind/__main__.py +213 -0
- rewind_memory-0.1.0/rewind/client.py +289 -0
- rewind_memory-0.1.0/rewind/config.py +176 -0
- rewind_memory-0.1.0/rewind/embedding/__init__.py +13 -0
- rewind_memory-0.1.0/rewind/embedding/base.py +32 -0
- rewind_memory-0.1.0/rewind/embedding/ollama.py +55 -0
- rewind_memory-0.1.0/rewind/ingest.py +705 -0
- rewind_memory-0.1.0/rewind/integrations/__init__.py +1 -0
- rewind_memory-0.1.0/rewind/integrations/mcp_server.py +453 -0
- rewind_memory-0.1.0/rewind/integrations/openclaw.py +273 -0
- rewind_memory-0.1.0/rewind/layers/__init__.py +29 -0
- rewind_memory-0.1.0/rewind/layers/l0_fts.py +115 -0
- rewind_memory-0.1.0/rewind/layers/l1_system.py +143 -0
- rewind_memory-0.1.0/rewind/layers/l2_orchestrator.py +287 -0
- rewind_memory-0.1.0/rewind/layers/l3_graph_sqlite.py +316 -0
- rewind_memory-0.1.0/rewind/layers/l4_vector.py +198 -0
- rewind_memory-0.1.0/rewind/migrate.py +455 -0
- rewind_memory-0.1.0/rewind/utils.py +83 -0
- rewind_memory-0.1.0/rewind_memory.egg-info/PKG-INFO +220 -0
- rewind_memory-0.1.0/rewind_memory.egg-info/SOURCES.txt +30 -0
- rewind_memory-0.1.0/rewind_memory.egg-info/dependency_links.txt +1 -0
- rewind_memory-0.1.0/rewind_memory.egg-info/entry_points.txt +4 -0
- rewind_memory-0.1.0/rewind_memory.egg-info/requires.txt +12 -0
- rewind_memory-0.1.0/rewind_memory.egg-info/top_level.txt +1 -0
- rewind_memory-0.1.0/setup.cfg +4 -0
- rewind_memory-0.1.0/tests/test_l0_fts.py +68 -0
- rewind_memory-0.1.0/tests/test_l2_orchestrator.py +126 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 SARAI Defence Ltd
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rewind-memory
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bio-inspired persistent memory for AI agents. 5-layer architecture with FTS5, vector search, knowledge graph, and HybridRAG fusion.
|
|
5
|
+
Author-email: SARAI Defence <vova@saraidefence.com>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://saraidefence.com
|
|
8
|
+
Project-URL: Documentation, https://saraidefence.com/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/saraidefence/rewind-memory
|
|
10
|
+
Keywords: memory,ai,agents,rag,bio-inspired,knowledge-graph
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: pyyaml>=6.0
|
|
23
|
+
Requires-Dist: httpx>=0.24
|
|
24
|
+
Provides-Extra: vector
|
|
25
|
+
Requires-Dist: sqlite-vec>=0.0.1; extra == "vector"
|
|
26
|
+
Provides-Extra: mcp
|
|
27
|
+
Requires-Dist: httpx>=0.24; extra == "mcp"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.1; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# π§ Rewind
|
|
34
|
+
|
|
35
|
+
**7-layer bio-inspired memory architecture for AI agents.**
|
|
36
|
+
|
|
37
|
+
Rewind gives AI agents persistent, structured memory that works like biological memory β with sensory buffers, short-term recall, knowledge graphs, semantic search, and natural forgetting curves.
|
|
38
|
+
|
|
39
|
+
## Architecture
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
43
|
+
β L2 Orchestrator β
|
|
44
|
+
β (fusion Β· ranking Β· entity extraction) β
|
|
45
|
+
βββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββ¬ββββββββ€
|
|
46
|
+
β L0 β L1 β L3 β L4 β L5 β L6 β
|
|
47
|
+
βSensory β STM β Graph βWorkspaceβCommsβ Docs β
|
|
48
|
+
β Buffer β(Vector) β β (Files) β β β
|
|
49
|
+
β β β β β β β
|
|
50
|
+
β FTS5/ βsqlite- βSQLite/ βsqlite- βsqliteβ FTS β
|
|
51
|
+
β BM25 β vec β Neo4j β vec β/Qdrantβ β
|
|
52
|
+
βββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββ΄ββββββββ
|
|
53
|
+
+
|
|
54
|
+
Bio Layer (Pro/MOS only)
|
|
55
|
+
(decay Β· consolidation Β· Hebbian Β· pruning)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Layers
|
|
59
|
+
|
|
60
|
+
| Layer | Name | Bio Analogy | Backend | Purpose |
|
|
61
|
+
|-------|------|-------------|---------|---------|
|
|
62
|
+
| **L0** | Sensory Buffer | Sensory cortex | SQLite FTS5 | Fast keyword search, BM25 ranking |
|
|
63
|
+
| **L1** | Short-Term Memory | Hippocampus | sqlite-vec | Vector similarity, recent context |
|
|
64
|
+
| **L2** | Orchestrator | Prefrontal cortex | In-process | Fusion, dedup, adaptive scoring |
|
|
65
|
+
| **L3** | Graph Memory | Association cortex | SQLite / Neo4j | Entity relationships, spreading activation |
|
|
66
|
+
| **L4** | Workspace | Working memory | sqlite-vec | Project files, semantic search |
|
|
67
|
+
| **L5** | Communications | Social memory | sqlite-vec / Qdrant | Chat history, email, contacts |
|
|
68
|
+
| **L6** | Documents | Declarative memory | SQLite FTS5 | PDFs, docs, arena-based retrieval |
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install rewind-memory
|
|
74
|
+
|
|
75
|
+
# Minimal β zero external dependencies
|
|
76
|
+
python -c "
|
|
77
|
+
from rewind.client import RewindClient
|
|
78
|
+
client = RewindClient()
|
|
79
|
+
results = client.search('what is Hebbian learning')
|
|
80
|
+
for r in results:
|
|
81
|
+
print(f'{r.score:.2f} [{r.layer}] {r.text[:80]}')
|
|
82
|
+
"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### With production backends
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install rewind-memory[all] # includes neo4j, qdrant-client, etc.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Configuration Tiers
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from rewind.config import default_config
|
|
95
|
+
|
|
96
|
+
# Core (Free) β local SQLite only, zero external deps
|
|
97
|
+
config = default_config("free")
|
|
98
|
+
|
|
99
|
+
# Pro β all layers, optional Neo4j/Qdrant migration
|
|
100
|
+
config = default_config("pro")
|
|
101
|
+
|
|
102
|
+
# MOS (Enterprise) β full stack + bio lifecycle
|
|
103
|
+
config = default_config("enterprise")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Feature | Core (Free) | Pro ($9/mo) | MOS (Custom) |
|
|
107
|
+
|---------|-------------|-------------|--------------|
|
|
108
|
+
| L0 Full-text search (FTS5) | β
| β
| β
|
|
|
109
|
+
| L1 System memory (sqlite-vec) | β
| β
| β
|
|
|
110
|
+
| L2 HybridRAG fusion | basic | full | full |
|
|
111
|
+
| L3 Knowledge graph | β
SQLite | β
SQLite or Neo4j | β
Neo4j |
|
|
112
|
+
| L4 Semantic vector search | β
sqlite-vec | β
sqlite-vec or Qdrant | β
Qdrant |
|
|
113
|
+
| L5 Communications memory | β | β
| β
|
|
|
114
|
+
| L6 Document store | β | β
| β
|
|
|
115
|
+
| Query orchestrator | β | β
| β
|
|
|
116
|
+
| Retrieval feedback learning | β | β
| β
|
|
|
117
|
+
| Cloud GPU embeddings | β | β
100K/mo | Custom |
|
|
118
|
+
| Migration assist (SQLite β Neo4j/Qdrant) | β | β
| β |
|
|
119
|
+
| Bio lifecycle (decay, consolidation, pruning) | β | β | β
|
|
|
120
|
+
| Air-gapped deployment | β | β | β
|
|
|
121
|
+
| Custom graph schemas | β | β | β
|
|
|
122
|
+
| Dedicated engineer + SLA | β | β | β
|
|
|
123
|
+
| API Server | β
| β
| β
|
|
|
124
|
+
|
|
125
|
+
### Backend Flexibility (Pro)
|
|
126
|
+
|
|
127
|
+
Pro users can keep running on SQLite (zero-dependency) or upgrade to production backends locally:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Migrate graph from SQLite to Neo4j
|
|
131
|
+
rewind migrate --backend neo4j --uri bolt://localhost:7687
|
|
132
|
+
|
|
133
|
+
# Migrate vectors from sqlite-vec to Qdrant
|
|
134
|
+
rewind migrate --backend qdrant --url http://localhost:6333
|
|
135
|
+
|
|
136
|
+
# Both migrations preserve all data and validate counts
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## API Server
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Start the server
|
|
143
|
+
python -m rewind.api.server --tier pro --port 8080
|
|
144
|
+
|
|
145
|
+
# Search
|
|
146
|
+
curl -X POST http://localhost:8080/v1/search \
|
|
147
|
+
-H "Content-Type: application/json" \
|
|
148
|
+
-d '{"query": "memory consolidation", "limit": 10}'
|
|
149
|
+
|
|
150
|
+
# Convenience GET
|
|
151
|
+
curl "http://localhost:8080/search?q=memory+consolidation&limit=10"
|
|
152
|
+
|
|
153
|
+
# Health check
|
|
154
|
+
curl http://localhost:8080/health
|
|
155
|
+
|
|
156
|
+
# Stats
|
|
157
|
+
curl http://localhost:8080/stats
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Authentication
|
|
161
|
+
|
|
162
|
+
Set `REWIND_API_KEY` environment variable or pass keys programmatically:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
REWIND_API_KEY=sk-your-key python -m rewind.api.server
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
curl http://localhost:8080/v1/search \
|
|
170
|
+
-H "X-API-Key: sk-your-key" \
|
|
171
|
+
-H "Content-Type: application/json" \
|
|
172
|
+
-d '{"query": "test"}'
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Docker Deployment
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
cd docker
|
|
179
|
+
|
|
180
|
+
# Full stack (Neo4j + Qdrant + Rewind API)
|
|
181
|
+
docker compose up -d
|
|
182
|
+
|
|
183
|
+
# Just the API
|
|
184
|
+
docker build -f Dockerfile -t rewind ..
|
|
185
|
+
docker run -p 8080:8080 rewind
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Bio-Inspired Features
|
|
189
|
+
|
|
190
|
+
> Available on MOS (Enterprise) tier only.
|
|
191
|
+
|
|
192
|
+
### Hebbian Learning
|
|
193
|
+
*"Neurons that fire together wire together."*
|
|
194
|
+
|
|
195
|
+
When a search result is accessed, its connections to co-occurring results strengthen. Frequently co-retrieved memories form stronger associations over time, just like synaptic potentiation.
|
|
196
|
+
|
|
197
|
+
### Spreading Activation
|
|
198
|
+
Queries activate not just direct matches but related concepts through the graph layer (L3). Activating "memory" spreads to "hippocampus", "consolidation", "encoding" β mimicking how biological neural networks propagate signals.
|
|
199
|
+
|
|
200
|
+
### Decay (Ebbinghaus Forgetting Curve)
|
|
201
|
+
Memories lose confidence over time following an exponential decay curve: `C(t) = Cβ Β· e^(-Ξ»t)`. Frequently accessed memories decay slower (reduced Ξ»), mirroring spaced repetition effects. A minimum confidence floor prevents complete forgetting.
|
|
202
|
+
|
|
203
|
+
### Consolidation
|
|
204
|
+
Periodically, high-value short-term memories (L1) are consolidated into long-term graph storage (L3), similar to how sleep consolidates hippocampal memories into neocortical storage.
|
|
205
|
+
|
|
206
|
+
### Pruning
|
|
207
|
+
Low-confidence memories below a threshold are pruned to prevent unbounded growth β analogous to synaptic pruning during development.
|
|
208
|
+
|
|
209
|
+
## Development
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
git clone https://github.com/sarai-defence/rewind-memory.git
|
|
213
|
+
cd rewind
|
|
214
|
+
pip install -e ".[dev]"
|
|
215
|
+
pytest tests/
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
Elastic License 2.0
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# π§ Rewind
|
|
2
|
+
|
|
3
|
+
**7-layer bio-inspired memory architecture for AI agents.**
|
|
4
|
+
|
|
5
|
+
Rewind gives AI agents persistent, structured memory that works like biological memory β with sensory buffers, short-term recall, knowledge graphs, semantic search, and natural forgetting curves.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
11
|
+
β L2 Orchestrator β
|
|
12
|
+
β (fusion Β· ranking Β· entity extraction) β
|
|
13
|
+
βββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββ¬ββββββββ€
|
|
14
|
+
β L0 β L1 β L3 β L4 β L5 β L6 β
|
|
15
|
+
βSensory β STM β Graph βWorkspaceβCommsβ Docs β
|
|
16
|
+
β Buffer β(Vector) β β (Files) β β β
|
|
17
|
+
β β β β β β β
|
|
18
|
+
β FTS5/ βsqlite- βSQLite/ βsqlite- βsqliteβ FTS β
|
|
19
|
+
β BM25 β vec β Neo4j β vec β/Qdrantβ β
|
|
20
|
+
βββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββ΄ββββββββ
|
|
21
|
+
+
|
|
22
|
+
Bio Layer (Pro/MOS only)
|
|
23
|
+
(decay Β· consolidation Β· Hebbian Β· pruning)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Layers
|
|
27
|
+
|
|
28
|
+
| Layer | Name | Bio Analogy | Backend | Purpose |
|
|
29
|
+
|-------|------|-------------|---------|---------|
|
|
30
|
+
| **L0** | Sensory Buffer | Sensory cortex | SQLite FTS5 | Fast keyword search, BM25 ranking |
|
|
31
|
+
| **L1** | Short-Term Memory | Hippocampus | sqlite-vec | Vector similarity, recent context |
|
|
32
|
+
| **L2** | Orchestrator | Prefrontal cortex | In-process | Fusion, dedup, adaptive scoring |
|
|
33
|
+
| **L3** | Graph Memory | Association cortex | SQLite / Neo4j | Entity relationships, spreading activation |
|
|
34
|
+
| **L4** | Workspace | Working memory | sqlite-vec | Project files, semantic search |
|
|
35
|
+
| **L5** | Communications | Social memory | sqlite-vec / Qdrant | Chat history, email, contacts |
|
|
36
|
+
| **L6** | Documents | Declarative memory | SQLite FTS5 | PDFs, docs, arena-based retrieval |
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install rewind-memory
|
|
42
|
+
|
|
43
|
+
# Minimal β zero external dependencies
|
|
44
|
+
python -c "
|
|
45
|
+
from rewind.client import RewindClient
|
|
46
|
+
client = RewindClient()
|
|
47
|
+
results = client.search('what is Hebbian learning')
|
|
48
|
+
for r in results:
|
|
49
|
+
print(f'{r.score:.2f} [{r.layer}] {r.text[:80]}')
|
|
50
|
+
"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### With production backends
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install rewind-memory[all] # includes neo4j, qdrant-client, etc.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Configuration Tiers
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from rewind.config import default_config
|
|
63
|
+
|
|
64
|
+
# Core (Free) β local SQLite only, zero external deps
|
|
65
|
+
config = default_config("free")
|
|
66
|
+
|
|
67
|
+
# Pro β all layers, optional Neo4j/Qdrant migration
|
|
68
|
+
config = default_config("pro")
|
|
69
|
+
|
|
70
|
+
# MOS (Enterprise) β full stack + bio lifecycle
|
|
71
|
+
config = default_config("enterprise")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| Feature | Core (Free) | Pro ($9/mo) | MOS (Custom) |
|
|
75
|
+
|---------|-------------|-------------|--------------|
|
|
76
|
+
| L0 Full-text search (FTS5) | β
| β
| β
|
|
|
77
|
+
| L1 System memory (sqlite-vec) | β
| β
| β
|
|
|
78
|
+
| L2 HybridRAG fusion | basic | full | full |
|
|
79
|
+
| L3 Knowledge graph | β
SQLite | β
SQLite or Neo4j | β
Neo4j |
|
|
80
|
+
| L4 Semantic vector search | β
sqlite-vec | β
sqlite-vec or Qdrant | β
Qdrant |
|
|
81
|
+
| L5 Communications memory | β | β
| β
|
|
|
82
|
+
| L6 Document store | β | β
| β
|
|
|
83
|
+
| Query orchestrator | β | β
| β
|
|
|
84
|
+
| Retrieval feedback learning | β | β
| β
|
|
|
85
|
+
| Cloud GPU embeddings | β | β
100K/mo | Custom |
|
|
86
|
+
| Migration assist (SQLite β Neo4j/Qdrant) | β | β
| β |
|
|
87
|
+
| Bio lifecycle (decay, consolidation, pruning) | β | β | β
|
|
|
88
|
+
| Air-gapped deployment | β | β | β
|
|
|
89
|
+
| Custom graph schemas | β | β | β
|
|
|
90
|
+
| Dedicated engineer + SLA | β | β | β
|
|
|
91
|
+
| API Server | β
| β
| β
|
|
|
92
|
+
|
|
93
|
+
### Backend Flexibility (Pro)
|
|
94
|
+
|
|
95
|
+
Pro users can keep running on SQLite (zero-dependency) or upgrade to production backends locally:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Migrate graph from SQLite to Neo4j
|
|
99
|
+
rewind migrate --backend neo4j --uri bolt://localhost:7687
|
|
100
|
+
|
|
101
|
+
# Migrate vectors from sqlite-vec to Qdrant
|
|
102
|
+
rewind migrate --backend qdrant --url http://localhost:6333
|
|
103
|
+
|
|
104
|
+
# Both migrations preserve all data and validate counts
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## API Server
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Start the server
|
|
111
|
+
python -m rewind.api.server --tier pro --port 8080
|
|
112
|
+
|
|
113
|
+
# Search
|
|
114
|
+
curl -X POST http://localhost:8080/v1/search \
|
|
115
|
+
-H "Content-Type: application/json" \
|
|
116
|
+
-d '{"query": "memory consolidation", "limit": 10}'
|
|
117
|
+
|
|
118
|
+
# Convenience GET
|
|
119
|
+
curl "http://localhost:8080/search?q=memory+consolidation&limit=10"
|
|
120
|
+
|
|
121
|
+
# Health check
|
|
122
|
+
curl http://localhost:8080/health
|
|
123
|
+
|
|
124
|
+
# Stats
|
|
125
|
+
curl http://localhost:8080/stats
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Authentication
|
|
129
|
+
|
|
130
|
+
Set `REWIND_API_KEY` environment variable or pass keys programmatically:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
REWIND_API_KEY=sk-your-key python -m rewind.api.server
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
curl http://localhost:8080/v1/search \
|
|
138
|
+
-H "X-API-Key: sk-your-key" \
|
|
139
|
+
-H "Content-Type: application/json" \
|
|
140
|
+
-d '{"query": "test"}'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Docker Deployment
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
cd docker
|
|
147
|
+
|
|
148
|
+
# Full stack (Neo4j + Qdrant + Rewind API)
|
|
149
|
+
docker compose up -d
|
|
150
|
+
|
|
151
|
+
# Just the API
|
|
152
|
+
docker build -f Dockerfile -t rewind ..
|
|
153
|
+
docker run -p 8080:8080 rewind
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Bio-Inspired Features
|
|
157
|
+
|
|
158
|
+
> Available on MOS (Enterprise) tier only.
|
|
159
|
+
|
|
160
|
+
### Hebbian Learning
|
|
161
|
+
*"Neurons that fire together wire together."*
|
|
162
|
+
|
|
163
|
+
When a search result is accessed, its connections to co-occurring results strengthen. Frequently co-retrieved memories form stronger associations over time, just like synaptic potentiation.
|
|
164
|
+
|
|
165
|
+
### Spreading Activation
|
|
166
|
+
Queries activate not just direct matches but related concepts through the graph layer (L3). Activating "memory" spreads to "hippocampus", "consolidation", "encoding" β mimicking how biological neural networks propagate signals.
|
|
167
|
+
|
|
168
|
+
### Decay (Ebbinghaus Forgetting Curve)
|
|
169
|
+
Memories lose confidence over time following an exponential decay curve: `C(t) = Cβ Β· e^(-Ξ»t)`. Frequently accessed memories decay slower (reduced Ξ»), mirroring spaced repetition effects. A minimum confidence floor prevents complete forgetting.
|
|
170
|
+
|
|
171
|
+
### Consolidation
|
|
172
|
+
Periodically, high-value short-term memories (L1) are consolidated into long-term graph storage (L3), similar to how sleep consolidates hippocampal memories into neocortical storage.
|
|
173
|
+
|
|
174
|
+
### Pruning
|
|
175
|
+
Low-confidence memories below a threshold are pruned to prevent unbounded growth β analogous to synaptic pruning during development.
|
|
176
|
+
|
|
177
|
+
## Development
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
git clone https://github.com/sarai-defence/rewind-memory.git
|
|
181
|
+
cd rewind
|
|
182
|
+
pip install -e ".[dev]"
|
|
183
|
+
pytest tests/
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
Elastic License 2.0
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rewind-memory"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Bio-inspired persistent memory for AI agents. 5-layer architecture with FTS5, vector search, knowledge graph, and HybridRAG fusion."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "Apache-2.0"}
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{name = "SARAI Defence", email = "vova@saraidefence.com"}]
|
|
13
|
+
keywords = ["memory", "ai", "agents", "rag", "bio-inspired", "knowledge-graph"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: Apache Software License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"pyyaml>=6.0",
|
|
26
|
+
"httpx>=0.24",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
vector = ["sqlite-vec>=0.0.1"]
|
|
31
|
+
mcp = ["httpx>=0.24"]
|
|
32
|
+
dev = ["pytest>=7.0", "ruff>=0.1"]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
rewind = "rewind.__main__:main"
|
|
36
|
+
rewind-mcp = "rewind.integrations.mcp_server:main"
|
|
37
|
+
rewind-openclaw = "rewind.integrations.openclaw:main"
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://saraidefence.com"
|
|
41
|
+
Documentation = "https://saraidefence.com/docs"
|
|
42
|
+
Repository = "https://github.com/saraidefence/rewind-memory"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
include = ["rewind*"]
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Rewind CLI β memory stack for AI agents.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
rewind ingest <path> [--tier free|pro|enterprise] [--db ./data/vector.db]
|
|
5
|
+
rewind search <query> [--tier free|pro|enterprise] [--limit 10]
|
|
6
|
+
rewind health [--tier free|pro|enterprise]
|
|
7
|
+
rewind stats
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import logging
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def cmd_ingest(args: argparse.Namespace) -> None:
|
|
19
|
+
"""Ingest files into the memory stack."""
|
|
20
|
+
from rewind.config import default_config
|
|
21
|
+
from rewind.ingest import IngestPipeline
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
cfg = default_config(args.tier)
|
|
25
|
+
if args.db:
|
|
26
|
+
cfg.vector_db_path = args.db
|
|
27
|
+
|
|
28
|
+
pipeline = IngestPipeline(cfg)
|
|
29
|
+
|
|
30
|
+
path = Path(args.path)
|
|
31
|
+
if path.is_dir():
|
|
32
|
+
stats = pipeline.ingest_directory(str(path))
|
|
33
|
+
elif path.is_file():
|
|
34
|
+
stats = pipeline.ingest_file(str(path))
|
|
35
|
+
else:
|
|
36
|
+
print(f"Error: {args.path} not found", file=sys.stderr)
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
pipeline.close()
|
|
40
|
+
|
|
41
|
+
# Print summary
|
|
42
|
+
print(f"Files: {stats.get('files', 1)}")
|
|
43
|
+
print(f"Chunks: {stats.get('chunks', 0)}")
|
|
44
|
+
print(f"Vectors: {stats.get('vectors', 0)}")
|
|
45
|
+
print(f"Entities: {stats.get('entities', 0)}")
|
|
46
|
+
if "elapsed_seconds" in stats:
|
|
47
|
+
print(f"Time: {stats['elapsed_seconds']}s")
|
|
48
|
+
if stats.get("errors"):
|
|
49
|
+
print(f"Errors: {stats['errors']}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def cmd_search(args: argparse.Namespace) -> None:
|
|
53
|
+
"""Search the memory stack."""
|
|
54
|
+
from rewind.client import RewindClient
|
|
55
|
+
from rewind.config import default_config
|
|
56
|
+
|
|
57
|
+
cfg = default_config(args.tier)
|
|
58
|
+
if args.db:
|
|
59
|
+
cfg.vector_db_path = args.db
|
|
60
|
+
|
|
61
|
+
client = RewindClient(cfg)
|
|
62
|
+
results = client.search(args.query, limit=args.limit)
|
|
63
|
+
client.close()
|
|
64
|
+
|
|
65
|
+
if not results:
|
|
66
|
+
print("No results found.")
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
if args.json:
|
|
70
|
+
print(json.dumps([{
|
|
71
|
+
"score": r.score, "layer": r.layer,
|
|
72
|
+
"path": r.path, "text": r.text[:200],
|
|
73
|
+
} for r in results], indent=2))
|
|
74
|
+
else:
|
|
75
|
+
for i, r in enumerate(results, 1):
|
|
76
|
+
print(f"\n{'β' * 60}")
|
|
77
|
+
print(f" #{i} score={r.score:.3f} layer={r.layer}")
|
|
78
|
+
if r.path:
|
|
79
|
+
print(f" path: {r.path}")
|
|
80
|
+
print(f" {r.text[:200]}")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def cmd_health(args: argparse.Namespace) -> None:
|
|
84
|
+
"""Health check."""
|
|
85
|
+
from rewind.client import RewindClient
|
|
86
|
+
from rewind.config import default_config
|
|
87
|
+
|
|
88
|
+
cfg = default_config(args.tier)
|
|
89
|
+
if args.db:
|
|
90
|
+
cfg.vector_db_path = args.db
|
|
91
|
+
|
|
92
|
+
client = RewindClient(cfg)
|
|
93
|
+
health = client.health()
|
|
94
|
+
client.close()
|
|
95
|
+
|
|
96
|
+
print(f"Tier: {health['tier']}")
|
|
97
|
+
print(f"Orchestrator: {'β
' if health['orchestrator'] else 'β'}")
|
|
98
|
+
print(f"Bio: {'β
' if health['bio'] else 'β'}")
|
|
99
|
+
print(f"Healthy: {'β
' if health['healthy'] else 'β'}")
|
|
100
|
+
print()
|
|
101
|
+
for name, status in health.get("layers", {}).items():
|
|
102
|
+
s = status.get("status", "unknown")
|
|
103
|
+
icon = "β
" if s == "ok" else "β" if s == "error" else "β οΈ"
|
|
104
|
+
extra = ""
|
|
105
|
+
if "nodes" in status:
|
|
106
|
+
extra = f" ({status['nodes']} nodes, {status.get('edges', 0)} edges)"
|
|
107
|
+
elif "total_chunks" in status:
|
|
108
|
+
extra = f" ({status['total_chunks']} chunks)"
|
|
109
|
+
elif "backend" in status:
|
|
110
|
+
extra = f" ({status['backend']})"
|
|
111
|
+
print(f" {icon} {name}: {s}{extra}")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def cmd_migrate(args: argparse.Namespace) -> None:
|
|
115
|
+
"""Migrate SQLite backends to Neo4j/Qdrant."""
|
|
116
|
+
from rewind.migrate import Migrator
|
|
117
|
+
|
|
118
|
+
db = args.db or "./data/vector.db"
|
|
119
|
+
migrator = Migrator(sqlite_db=db)
|
|
120
|
+
|
|
121
|
+
if args.subcmd == "status":
|
|
122
|
+
import json
|
|
123
|
+
print(json.dumps(migrator.status(), indent=2))
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
if args.subcmd == "graph":
|
|
127
|
+
result = migrator.migrate_graph_to_neo4j(
|
|
128
|
+
uri=args.uri or "bolt://localhost:7687",
|
|
129
|
+
user=args.user or "neo4j",
|
|
130
|
+
password=args.password or "",
|
|
131
|
+
dry_run=args.dry_run,
|
|
132
|
+
)
|
|
133
|
+
elif args.subcmd == "vectors":
|
|
134
|
+
result = migrator.migrate_vectors_to_qdrant(
|
|
135
|
+
qdrant_url=args.uri or "http://localhost:6333",
|
|
136
|
+
collection=args.collection or "rewind_chunks",
|
|
137
|
+
dry_run=args.dry_run,
|
|
138
|
+
)
|
|
139
|
+
else:
|
|
140
|
+
print("Usage: rewind migrate {status|graph|vectors}", file=sys.stderr)
|
|
141
|
+
sys.exit(1)
|
|
142
|
+
|
|
143
|
+
if "error" in result:
|
|
144
|
+
print(f"Error: {result['error']}", file=sys.stderr)
|
|
145
|
+
sys.exit(1)
|
|
146
|
+
|
|
147
|
+
import json
|
|
148
|
+
print(json.dumps(result, indent=2))
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def main() -> None:
|
|
152
|
+
parser = argparse.ArgumentParser(
|
|
153
|
+
prog="rewind",
|
|
154
|
+
description="Rewind β bio-inspired memory stack for AI agents",
|
|
155
|
+
)
|
|
156
|
+
parser.add_argument(
|
|
157
|
+
"-v", "--verbose", action="store_true",
|
|
158
|
+
help="Enable debug logging",
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
sub = parser.add_subparsers(dest="command")
|
|
162
|
+
|
|
163
|
+
# ingest
|
|
164
|
+
p_ingest = sub.add_parser("ingest", help="Ingest files into memory")
|
|
165
|
+
p_ingest.add_argument("path", help="File or directory to ingest")
|
|
166
|
+
p_ingest.add_argument("--tier", default="free", choices=["free", "pro", "enterprise"])
|
|
167
|
+
p_ingest.add_argument("--db", default=None, help="Path to vector DB")
|
|
168
|
+
|
|
169
|
+
# search
|
|
170
|
+
p_search = sub.add_parser("search", help="Search memory")
|
|
171
|
+
p_search.add_argument("query", help="Search query")
|
|
172
|
+
p_search.add_argument("--tier", default="free", choices=["free", "pro", "enterprise"])
|
|
173
|
+
p_search.add_argument("--db", default=None, help="Path to vector DB")
|
|
174
|
+
p_search.add_argument("--limit", type=int, default=10)
|
|
175
|
+
p_search.add_argument("--json", action="store_true", help="Output JSON")
|
|
176
|
+
|
|
177
|
+
# health
|
|
178
|
+
p_health = sub.add_parser("health", help="Health check")
|
|
179
|
+
p_health.add_argument("--tier", default="free", choices=["free", "pro", "enterprise"])
|
|
180
|
+
p_health.add_argument("--db", default=None, help="Path to vector DB")
|
|
181
|
+
|
|
182
|
+
# migrate
|
|
183
|
+
p_migrate = sub.add_parser("migrate", help="Migrate backends (Pro)")
|
|
184
|
+
p_migrate.add_argument("subcmd", choices=["status", "graph", "vectors"],
|
|
185
|
+
help="Migration target")
|
|
186
|
+
p_migrate.add_argument("--db", default=None, help="Path to SQLite DB")
|
|
187
|
+
p_migrate.add_argument("--uri", default=None, help="Target URI (bolt:// or http://)")
|
|
188
|
+
p_migrate.add_argument("--user", default="neo4j", help="Neo4j username")
|
|
189
|
+
p_migrate.add_argument("--password", default="", help="Neo4j password")
|
|
190
|
+
p_migrate.add_argument("--collection", default="rewind_chunks", help="Qdrant collection")
|
|
191
|
+
p_migrate.add_argument("--dry-run", action="store_true", help="Report only, don't write")
|
|
192
|
+
|
|
193
|
+
args = parser.parse_args()
|
|
194
|
+
|
|
195
|
+
if args.verbose:
|
|
196
|
+
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s %(name)s: %(message)s")
|
|
197
|
+
else:
|
|
198
|
+
logging.basicConfig(level=logging.WARNING)
|
|
199
|
+
|
|
200
|
+
if args.command == "ingest":
|
|
201
|
+
cmd_ingest(args)
|
|
202
|
+
elif args.command == "search":
|
|
203
|
+
cmd_search(args)
|
|
204
|
+
elif args.command == "health":
|
|
205
|
+
cmd_health(args)
|
|
206
|
+
elif args.command == "migrate":
|
|
207
|
+
cmd_migrate(args)
|
|
208
|
+
else:
|
|
209
|
+
parser.print_help()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
if __name__ == "__main__":
|
|
213
|
+
main()
|