wavemind 2.1.0__tar.gz → 2.2.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.
- {wavemind-2.1.0 → wavemind-2.2.0}/CONTRIBUTING.md +2 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/MANIFEST.in +6 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/PKG-INFO +273 -125
- {wavemind-2.1.0 → wavemind-2.2.0}/README.md +272 -124
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/ann_index_curve_benchmark.py +7 -4
- {wavemind-2.1.0 → wavemind-2.2.0}/docker-compose.yml +1 -1
- wavemind-2.2.0/docs/CHROMA_MIGRATION.md +412 -0
- wavemind-2.2.0/docs/DEMO_SCRIPT.md +116 -0
- wavemind-2.2.0/docs/LAUNCH_KIT.md +361 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/docs/PROJECT_BOARD.md +6 -1
- {wavemind-2.1.0 → wavemind-2.2.0}/docs/ROADMAP.md +4 -2
- wavemind-2.2.0/docs/RU_LAUNCH_POSTS.md +192 -0
- wavemind-2.2.0/docs/USE_CASES.md +274 -0
- wavemind-2.2.0/docs/assets/wavemind-social-card.svg +104 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/examples/demo.py +2 -2
- wavemind-2.2.0/examples/dynamic_memory_demo.py +134 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/pyproject.toml +1 -1
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_api.py +77 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_cli_smoke.py +31 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_core_persistence.py +26 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_examples.py +25 -3
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_indexes_encoders.py +17 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_packaging_files.py +7 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/__init__.py +1 -1
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/api.py +47 -1
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/cli.py +95 -1
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/core.py +101 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/indexes.py +199 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/storage.py +51 -0
- wavemind-2.2.0/wavemind/studio.py +703 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind.egg-info/PKG-INFO +273 -125
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind.egg-info/SOURCES.txt +8 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/Dockerfile +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/LICENSE +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/SECURITY.md +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/SUPPORT.md +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/BENCHMARK_REPORT.md +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/agent_memory_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/agent_memory_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/ann_index_curve_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/benchmark_matrix_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/benchmark_registry.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/dynamic_memory_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/dynamic_memory_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/field_memory_dynamics_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/field_memory_dynamics_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/locomo_evidence_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/locomo_memory_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/locomo_sentence_evidence_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/long_memory_evidence_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/long_memory_evidence_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/longmemeval_answer_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/longmemeval_answer_extractive_20_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/longmemeval_evidence_50_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/longmemeval_evidence_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/longmemeval_memory_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/open_retrieval_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/open_retrieval_scifact_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/render_benchmark_charts.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/render_benchmark_report.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/ru_sentences_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/benchmarks/wavemind_capacity_results.json +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/docs/RELEASE.md +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/docs/assets/benchmark-summary.svg +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/examples/agent_with_memory.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/examples/framework_integrations.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/examples/langchain_memory.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/examples/sharded_memory.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/install.bat +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/install.sh +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/requirements-optional.txt +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/requirements.txt +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/setup.cfg +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_agent_memory_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_ann_index_curve_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_api_process_persistence.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_benchmark_charts.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_benchmark_registry.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_benchmark_report.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_dynamic_memory_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_field_graph.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_field_graph_integration.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_field_memory_dynamics_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_framework_adapters.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_import_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_langchain_integration.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_locomo_memory_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_long_memory_evidence_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_longmemeval_answer_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_longmemeval_memory_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_observability.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_open_retrieval_benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_postgres_storage.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_semantic_and_latency.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/tests/test_sharding.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/__main__.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/benchmark.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/encoders.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/field_graph.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/importers.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/integrations/__init__.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/integrations/autogen.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/integrations/crewai.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/integrations/langchain.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/integrations/langgraph.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/integrations/llamaindex.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/observability.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind/sharding.py +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind.egg-info/dependency_links.txt +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind.egg-info/entry_points.txt +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind.egg-info/requires.txt +0 -0
- {wavemind-2.1.0 → wavemind-2.2.0}/wavemind.egg-info/top_level.txt +0 -0
|
@@ -92,6 +92,8 @@ Current scale roadmap:
|
|
|
92
92
|
|
|
93
93
|
See [`docs/ROADMAP.md`](docs/ROADMAP.md) for the full roadmap.
|
|
94
94
|
See [`docs/RELEASE.md`](docs/RELEASE.md) for release mechanics.
|
|
95
|
+
See [`docs/LAUNCH_KIT.md`](docs/LAUNCH_KIT.md) for public positioning,
|
|
96
|
+
benchmark-claim guardrails, and community launch drafts.
|
|
95
97
|
|
|
96
98
|
## Pull Request Style
|
|
97
99
|
|
|
@@ -12,7 +12,13 @@ include requirements-optional.txt
|
|
|
12
12
|
include docs/ROADMAP.md
|
|
13
13
|
include docs/RELEASE.md
|
|
14
14
|
include docs/PROJECT_BOARD.md
|
|
15
|
+
include docs/DEMO_SCRIPT.md
|
|
16
|
+
include docs/LAUNCH_KIT.md
|
|
17
|
+
include docs/CHROMA_MIGRATION.md
|
|
18
|
+
include docs/RU_LAUNCH_POSTS.md
|
|
19
|
+
include docs/USE_CASES.md
|
|
15
20
|
include docs/assets/benchmark-summary.svg
|
|
21
|
+
include docs/assets/wavemind-social-card.svg
|
|
16
22
|
include benchmarks/*.py
|
|
17
23
|
include benchmarks/*.json
|
|
18
24
|
include benchmarks/*.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wavemind
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Local-first dynamic memory field with vector search and wave-field re-ranking
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/CaspianG/wavemind
|
|
@@ -52,25 +52,29 @@ Dynamic: license-file
|
|
|
52
52
|
|
|
53
53
|
# WaveMind
|
|
54
54
|
|
|
55
|
-
**
|
|
55
|
+
**Local-first dynamic memory for apps, agents, notebooks, and tools.**
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
It stores text, vectors, metadata, and recall state in SQLite. A wave-field
|
|
62
|
-
priority layer then reinforces useful memories, lets stale facts fade, respects
|
|
63
|
-
namespaces, and keeps the final recall set small enough for real applications.
|
|
57
|
+
WaveMind stores memories in SQLite, finds relevant candidates with vector
|
|
58
|
+
search, then uses a wave-field priority layer to decide what still matters:
|
|
59
|
+
hot facts rise, stale facts fade, temporary facts expire, and namespaces keep
|
|
60
|
+
users or projects isolated.
|
|
64
61
|
|
|
65
62
|

|
|
66
63
|
[](https://pypi.org/project/wavemind/)
|
|
67
64
|
[](https://github.com/CaspianG/wavemind/actions/workflows/tests.yml)
|
|
68
65
|

|
|
69
66
|
|
|
70
|
-
|
|
67
|
+
<img src="https://raw.githubusercontent.com/CaspianG/wavemind/main/docs/assets/wavemind-social-card.svg" alt="WaveMind dynamic memory overview" width="820">
|
|
68
|
+
|
|
71
69
|
[Quick Start](#quick-start) |
|
|
70
|
+
[CLI](#cli-cheat-sheet) |
|
|
71
|
+
[Studio](#wavemind-studio) |
|
|
72
|
+
[Python Example](#python-example) |
|
|
73
|
+
[HTTP Example](#http-example) |
|
|
74
|
+
[Where Data Lives](#where-data-lives) |
|
|
72
75
|
[LangChain](#langchain-memory) |
|
|
73
|
-
[
|
|
76
|
+
[Chroma Migration](docs/CHROMA_MIGRATION.md) |
|
|
77
|
+
[Use Cases](docs/USE_CASES.md) |
|
|
74
78
|
[HTTP API](#http-api) |
|
|
75
79
|
[Benchmarks](#benchmark) |
|
|
76
80
|
[Roadmap](#roadmap) |
|
|
@@ -79,38 +83,246 @@ namespaces, and keeps the final recall set small enough for real applications.
|
|
|
79
83
|
|
|
80
84
|
</div>
|
|
81
85
|
|
|
82
|
-
##
|
|
86
|
+
## What Is WaveMind?
|
|
87
|
+
|
|
88
|
+
WaveMind is a dynamic memory engine you can embed in a product.
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
small-to-medium knowledge stream where "latest", "repeated", "expired", and
|
|
88
|
-
"scoped to this user/project" matter.
|
|
90
|
+
Use it when your app needs to remember things like user preferences, decisions,
|
|
91
|
+
corrections, notes, research snippets, support history, agent context, or
|
|
92
|
+
temporary facts.
|
|
89
93
|
|
|
90
|
-
The
|
|
94
|
+
The short version:
|
|
91
95
|
|
|
92
96
|
```text
|
|
93
|
-
|
|
94
|
-
WaveMind:
|
|
97
|
+
normal vector search: find the nearest text
|
|
98
|
+
WaveMind: find the nearest useful memory
|
|
95
99
|
```
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
and optional
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
WaveMind is not trying to replace every vector database. It is the memory layer
|
|
102
|
+
around retrieval: persistence, namespaces, TTL, hotness, priority, decay,
|
|
103
|
+
explicit forgetting, audit events, and optional graph dynamics.
|
|
104
|
+
|
|
105
|
+
## 60-Second Version
|
|
106
|
+
|
|
107
|
+
| Question | Answer |
|
|
108
|
+
|---|---|
|
|
109
|
+
| What does it store? | Text memories, vectors, metadata, tags, TTL, priority, and recall state. |
|
|
110
|
+
| Where does it store data? | A local SQLite file by default; Postgres is available for production state. |
|
|
111
|
+
| How do I use it? | CLI, Python API, FastAPI HTTP server, LangChain memory, or framework adapters. |
|
|
112
|
+
| What is different from Chroma/Qdrant? | WaveMind adds memory policy: hotness, decay, TTL, correction handling, and scoped recall. |
|
|
113
|
+
| When should I not use it? | For huge static document search where a mature vector DB is already the right tool. |
|
|
114
|
+
| What is the simplest install? | `python -m pip install wavemind` |
|
|
102
115
|
|
|
103
|
-
##
|
|
116
|
+
## Why Use It?
|
|
104
117
|
|
|
105
118
|
| If you need... | WaveMind gives you... |
|
|
106
119
|
|---|---|
|
|
107
|
-
| Memory that survives restarts | SQLite
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
120
|
+
| Memory that survives restarts | One SQLite file stores text, vectors, metadata, TTL, and recall state. |
|
|
121
|
+
| Per-user or per-project recall | Namespaces and tags keep memories separated. |
|
|
122
|
+
| Temporary facts | `ttl_seconds` lets facts expire automatically. |
|
|
123
|
+
| Corrections and changing preferences | Newer or reinforced memories can outrank stale ones. |
|
|
124
|
+
| A simple integration path | Python API, CLI, FastAPI server, and LangChain memory class. |
|
|
125
|
+
| Production hygiene | Backups, audit log, API keys, rate limits, Prometheus metrics, and OpenTelemetry traces. |
|
|
126
|
+
|
|
127
|
+
## Quick Start
|
|
128
|
+
|
|
129
|
+
The shortest path from install to first recall:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
python -m pip install wavemind
|
|
133
|
+
wavemind remember "Andrey is a trader" --namespace demo
|
|
134
|
+
wavemind query "What does Andrey do?" --namespace demo
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Need a reminder after install?
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
wavemind quickstart
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Want to see and manage memory in a browser?
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
wavemind studio
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
By default, WaveMind creates `wavemind.sqlite3` in the current working
|
|
150
|
+
directory. That file is the local source of truth. Keep it out of git and back
|
|
151
|
+
it up like application state.
|
|
152
|
+
|
|
153
|
+
## CLI Cheat Sheet
|
|
154
|
+
|
|
155
|
+
Start here if you only want to use WaveMind from the terminal:
|
|
156
|
+
|
|
157
|
+
| Goal | Command |
|
|
158
|
+
|---|---|
|
|
159
|
+
| Show first-run help | `wavemind quickstart` |
|
|
160
|
+
| Store a memory | `wavemind remember "Andrey prefers short answers" --namespace user:42` |
|
|
161
|
+
| Search memory | `wavemind query "answer style" --namespace user:42` |
|
|
162
|
+
| Open local dashboard | `wavemind studio` |
|
|
163
|
+
| See stored state | `wavemind stats --namespace user:42` |
|
|
164
|
+
| Delete a namespace | `wavemind forget --namespace user:42` |
|
|
165
|
+
| Import notes | `wavemind import ./notes.txt --namespace project:alpha` |
|
|
166
|
+
| Use another database file | `wavemind --db ./state/memory.sqlite3 query "budget" --namespace user:42` |
|
|
167
|
+
| Start the HTTP API | `wavemind --db ./state/memory.sqlite3 serve --host 127.0.0.1 --port 8000` |
|
|
168
|
+
|
|
169
|
+
After this point, choose the integration path you need: Python, HTTP, LangChain,
|
|
170
|
+
framework adapters, benchmarks, or production deployment.
|
|
171
|
+
|
|
172
|
+
## WaveMind Studio
|
|
173
|
+
|
|
174
|
+
WaveMind Studio is the built-in local dashboard. It runs on top of the same
|
|
175
|
+
FastAPI app and SQLite database as the CLI:
|
|
176
|
+
|
|
177
|
+
```sh
|
|
178
|
+
wavemind studio
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
It opens `http://127.0.0.1:8000/studio` and gives you:
|
|
182
|
+
|
|
183
|
+
| View | What it is for |
|
|
184
|
+
|---|---|
|
|
185
|
+
| Memory map | See field energy as a heatmap. |
|
|
186
|
+
| Namespace explorer | Inspect memories per user, project, agent, or tenant. |
|
|
187
|
+
| Live query tester | Test recall before wiring it into an app. |
|
|
188
|
+
| Feedback buttons | Mark recalled memories as useful or not useful. |
|
|
189
|
+
| Import/export | Import local files and export a namespace snapshot. |
|
|
190
|
+
| Backup | Create SQLite backups from the browser. |
|
|
191
|
+
| Conflict visualizer | Inspect correction groups when memories disagree. |
|
|
192
|
+
|
|
193
|
+
For a server-safe local bind:
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
wavemind --db ./state/wavemind.sqlite3 studio --host 127.0.0.1 --port 8000
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Python Example
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from wavemind import WaveMind
|
|
203
|
+
|
|
204
|
+
memory = WaveMind(db_path="./state/wavemind.sqlite3")
|
|
205
|
+
|
|
206
|
+
memory.remember(
|
|
207
|
+
"The user prefers short practical answers.",
|
|
208
|
+
namespace="user:42",
|
|
209
|
+
tags=["preference"],
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
hits = memory.query("How should I answer this user?", namespace="user:42", top_k=3)
|
|
213
|
+
for hit in hits:
|
|
214
|
+
print(hit.score, hit.text)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The integration pattern is intentionally small:
|
|
218
|
+
|
|
219
|
+
1. Call `query()` before your app, agent, tool, or UI needs context.
|
|
220
|
+
2. Pass the returned memories into your prompt, screen, search result, or
|
|
221
|
+
decision function.
|
|
222
|
+
3. Call `remember()` after something worth keeping happens.
|
|
223
|
+
|
|
224
|
+
## HTTP Example
|
|
225
|
+
|
|
226
|
+
The FastAPI server is included in the base install:
|
|
227
|
+
|
|
228
|
+
```sh
|
|
229
|
+
wavemind --db ./state/wavemind.sqlite3 serve --host 127.0.0.1 --port 8000
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Then use WaveMind from any language:
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
curl -X POST http://127.0.0.1:8000/remember \
|
|
236
|
+
-H "Content-Type: application/json" \
|
|
237
|
+
-d "{\"text\":\"Andrey prefers short answers\",\"namespace\":\"user:42\",\"tags\":[\"preference\"]}"
|
|
238
|
+
|
|
239
|
+
curl -X POST http://127.0.0.1:8000/query \
|
|
240
|
+
-H "Content-Type: application/json" \
|
|
241
|
+
-d "{\"query\":\"How should I answer?\",\"namespace\":\"user:42\",\"top_k\":3}"
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Where Data Lives
|
|
245
|
+
|
|
246
|
+
WaveMind is local-first. The SQLite database stores memories, vectors, metadata,
|
|
247
|
+
namespaces, tags, TTL, hotness, priority, and audit events.
|
|
248
|
+
|
|
249
|
+
| runtime | Suggested database path |
|
|
250
|
+
|---|---|
|
|
251
|
+
| quick CLI experiment | `./wavemind.sqlite3` |
|
|
252
|
+
| Python app or agent | `./state/wavemind.sqlite3` |
|
|
253
|
+
| desktop app | user data directory, for example `%APPDATA%` or `~/.local/share` |
|
|
254
|
+
| server daemon | `/var/lib/wavemind/wavemind.sqlite3` |
|
|
255
|
+
| Docker | mounted volume, for example `/data/wavemind.sqlite3` |
|
|
256
|
+
|
|
257
|
+
Explicit path:
|
|
258
|
+
|
|
259
|
+
```sh
|
|
260
|
+
wavemind --db ./state/app_memory.sqlite3 remember "Andrey prefers short answers" --namespace user:42
|
|
261
|
+
wavemind --db ./state/app_memory.sqlite3 query "answer style" --namespace user:42
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Common Ways To Use It
|
|
265
|
+
|
|
266
|
+
| You are building... | Start with... |
|
|
267
|
+
|---|---|
|
|
268
|
+
| Python app | `from wavemind import WaveMind` |
|
|
269
|
+
| LangChain agent | `WaveMindMemory` from `wavemind.integrations.langchain` |
|
|
270
|
+
| LangGraph workflow | `make_recall_node()` and `make_persist_node()` |
|
|
271
|
+
| LlamaIndex pipeline | `WaveMindRetriever` |
|
|
272
|
+
| CrewAI or AutoGen loop | The adapters in `wavemind.integrations` |
|
|
273
|
+
| Node, Go, Ruby, PHP, or no-code app | `wavemind serve` and the HTTP API |
|
|
274
|
+
| Personal knowledge base | Store notes by project namespace and query locally |
|
|
275
|
+
| Support or CRM workflow | Store customer issues, resolutions, preferences, and corrections |
|
|
276
|
+
| Research or trading notebook | Store observations with source metadata and TTL for temporary hypotheses |
|
|
277
|
+
|
|
278
|
+
For migrations from existing local vector memory, start with
|
|
279
|
+
[`docs/CHROMA_MIGRATION.md`](docs/CHROMA_MIGRATION.md).
|
|
280
|
+
|
|
281
|
+
## Minimal Agent Loop
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
from wavemind import WaveMind
|
|
285
|
+
|
|
286
|
+
memory = WaveMind(db_path="./state/agent.sqlite3")
|
|
287
|
+
|
|
288
|
+
def run_turn(user_id: str, user_text: str) -> str:
|
|
289
|
+
namespace = f"user:{user_id}"
|
|
290
|
+
hits = memory.query(user_text, namespace=namespace, top_k=5, min_score=0.25)
|
|
291
|
+
recalled = "\n".join(f"- {hit.text}" for hit in hits)
|
|
292
|
+
|
|
293
|
+
answer = call_your_llm(f"Relevant memory:\n{recalled}\n\nUser: {user_text}")
|
|
294
|
+
|
|
295
|
+
memory.remember(f"User said: {user_text}", namespace=namespace, tags=["conversation"])
|
|
296
|
+
memory.remember(f"Assistant answered: {answer}", namespace=namespace, tags=["conversation"])
|
|
297
|
+
return answer
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Terminal Demo
|
|
301
|
+
|
|
302
|
+
From a cloned repository:
|
|
303
|
+
|
|
304
|
+
```text
|
|
305
|
+
$ python examples/demo.py
|
|
306
|
+
[ok] Remembered: "Andrey is a trader who tracks market breakouts."
|
|
307
|
+
[ok] Remembered: "Andrey prefers short practical answers about product decisions."
|
|
308
|
+
|
|
309
|
+
Query: "Andrey trader preferences"
|
|
310
|
+
-> Result 1 (0.60): "Andrey is a trader who tracks market breakouts."
|
|
311
|
+
-> Result 2 (0.30): "Andrey prefers short practical answers about product decisions."
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
The demo is offline, keyless, and uses the built-in hash encoder.
|
|
315
|
+
|
|
316
|
+
To see the behavior that plain vector search does not provide:
|
|
317
|
+
|
|
318
|
+
```sh
|
|
319
|
+
python examples/dynamic_memory_demo.py
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
That demo shows corrected facts outranking stale facts, temporary memory
|
|
323
|
+
expiring, namespace isolation, and index-health reporting.
|
|
324
|
+
|
|
325
|
+
## How The Memory Field Works
|
|
114
326
|
|
|
115
327
|
```mermaid
|
|
116
328
|
flowchart LR
|
|
@@ -125,10 +337,9 @@ flowchart LR
|
|
|
125
337
|
F --> D
|
|
126
338
|
```
|
|
127
339
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
marketing name for embeddings.
|
|
340
|
+
The wave field is the dynamic layer around stored memories. It is not a
|
|
341
|
+
replacement for embeddings; it is the policy that decides which candidate
|
|
342
|
+
memories should still matter.
|
|
132
343
|
|
|
133
344
|
| signal | Plain meaning | Effect |
|
|
134
345
|
|---|---|---|
|
|
@@ -145,39 +356,6 @@ memories, not a continuous mathematical physics field. That honesty matters:
|
|
|
145
356
|
WaveMind is useful today as a dynamic memory engine, while the research path is
|
|
146
357
|
to make the field dynamics more explicit, measurable, and scalable.
|
|
147
358
|
|
|
148
|
-
## Terminal Demo
|
|
149
|
-
|
|
150
|
-
From a cloned repository:
|
|
151
|
-
|
|
152
|
-
```text
|
|
153
|
-
$ python examples/demo.py
|
|
154
|
-
[ok] Remembered: "Andrey is a trader who tracks market breakouts."
|
|
155
|
-
[ok] Remembered: "Andrey prefers short practical answers about product decisions."
|
|
156
|
-
|
|
157
|
-
Query: "Andrey trader preferences"
|
|
158
|
-
-> Result 1 (0.60): "Andrey is a trader who tracks market breakouts."
|
|
159
|
-
-> Result 2 (0.30): "Andrey prefers short practical answers about product decisions."
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
The demo is offline, keyless, and uses the built-in hash encoder.
|
|
163
|
-
|
|
164
|
-
## Quick Start
|
|
165
|
-
|
|
166
|
-
Install from PyPI and create your first local memory:
|
|
167
|
-
|
|
168
|
-
```sh
|
|
169
|
-
python -m pip install wavemind
|
|
170
|
-
wavemind remember "Andrey is a trader" --namespace demo
|
|
171
|
-
wavemind query "trader" --namespace demo
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
What happens here:
|
|
175
|
-
|
|
176
|
-
- `remember` writes the text and its vector pattern into a local SQLite database.
|
|
177
|
-
- By default, the database file is `wavemind.sqlite3` in your current working directory.
|
|
178
|
-
- `--namespace demo` keeps this memory separate from other users, agents, or projects.
|
|
179
|
-
- `query` reads from the same SQLite file and returns the closest remembered texts.
|
|
180
|
-
|
|
181
359
|
## Optional Embeddings
|
|
182
360
|
|
|
183
361
|
For sentence-transformer embeddings:
|
|
@@ -215,6 +393,16 @@ wavemind --index faiss-persisted query "trader" --namespace demo
|
|
|
215
393
|
SQLite or Postgres remains the source of truth. The persisted FAISS files are a
|
|
216
394
|
candidate-index snapshot and are validated against the current memory ids on
|
|
217
395
|
load. If the snapshot does not match the stored memories, WaveMind rebuilds it.
|
|
396
|
+
You can also check and rebuild the candidate index explicitly:
|
|
397
|
+
|
|
398
|
+
```sh
|
|
399
|
+
wavemind --index faiss-persisted index-health --json
|
|
400
|
+
wavemind --index faiss-persisted rebuild-index
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Index health compares durable memory ids against the candidate index. Local
|
|
404
|
+
indexes report exact missing/extra ids; service backends report exact ids when
|
|
405
|
+
the backend exposes an id scan and otherwise fall back to count-based health.
|
|
218
406
|
|
|
219
407
|
pgvector setup:
|
|
220
408
|
|
|
@@ -250,38 +438,6 @@ production latency and durability should be measured against a real Qdrant
|
|
|
250
438
|
service. If `WAVEMIND_QDRANT_URL` is missing, WaveMind raises a clear error
|
|
251
439
|
instead of silently falling back to another backend.
|
|
252
440
|
|
|
253
|
-
## Data Location
|
|
254
|
-
|
|
255
|
-
For an explicit database path, put global options before the command:
|
|
256
|
-
|
|
257
|
-
```sh
|
|
258
|
-
wavemind --db ./app_memory.sqlite3 remember "Andrey is a trader" --namespace demo
|
|
259
|
-
wavemind --db ./app_memory.sqlite3 query "trader" --namespace demo
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
WaveMind is local-first. One SQLite file is the source of truth for texts,
|
|
263
|
-
metadata, vectors, namespaces, tags, TTL, and recall state. For real agents,
|
|
264
|
-
prefer an explicit path under your application's state directory:
|
|
265
|
-
|
|
266
|
-
```python
|
|
267
|
-
from wavemind import WaveMind
|
|
268
|
-
|
|
269
|
-
memory = WaveMind(db_path="./state/wavemind.sqlite3")
|
|
270
|
-
memory.remember("The user prefers short answers.", namespace="user:42", tags=["preference"])
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
Useful storage patterns:
|
|
274
|
-
|
|
275
|
-
| runtime | Suggested database path |
|
|
276
|
-
|---|---|
|
|
277
|
-
| local CLI experiment | `./wavemind.sqlite3` |
|
|
278
|
-
| Python app or agent | `./state/wavemind.sqlite3` |
|
|
279
|
-
| OpenClaw sidecar | `~/.openclaw/wavemind/<agent-id>.sqlite3` |
|
|
280
|
-
| server daemon | `/var/lib/wavemind/wavemind.sqlite3` |
|
|
281
|
-
| Docker | mounted volume, for example `/data/wavemind.sqlite3` |
|
|
282
|
-
|
|
283
|
-
Keep the SQLite file out of git. Back it up like any other application state.
|
|
284
|
-
|
|
285
441
|
## Storage Backends
|
|
286
442
|
|
|
287
443
|
SQLite is the default source of truth. For multi-tenant production deployments,
|
|
@@ -355,6 +511,8 @@ curl http://127.0.0.1:8000/stats?namespace=demo
|
|
|
355
511
|
curl http://127.0.0.1:8000/audit?namespace=demo
|
|
356
512
|
curl http://127.0.0.1:8000/metrics
|
|
357
513
|
curl http://127.0.0.1:8000/observability
|
|
514
|
+
curl http://127.0.0.1:8000/index/health
|
|
515
|
+
curl -X POST http://127.0.0.1:8000/index/rebuild
|
|
358
516
|
curl -X POST http://127.0.0.1:8000/backup -H "Content-Type: application/json" -d '{"path":"./backups","keep_last":7}'
|
|
359
517
|
```
|
|
360
518
|
|
|
@@ -362,6 +520,9 @@ curl -X POST http://127.0.0.1:8000/backup -H "Content-Type: application/json" -d
|
|
|
362
520
|
`purge_expired`. Query audit is opt-in with `WAVEMIND_AUDIT_QUERIES=1` because
|
|
363
521
|
writing an audit row for every query changes latency. `/metrics` returns a
|
|
364
522
|
Prometheus-compatible text payload without adding a required dependency.
|
|
523
|
+
`/index/health` reports source-of-truth versus candidate-index consistency.
|
|
524
|
+
`/index/rebuild` rebuilds the candidate index from stored active memories and
|
|
525
|
+
logs an `index_rebuild` audit event.
|
|
365
526
|
|
|
366
527
|
OpenTelemetry traces are optional and off by default:
|
|
367
528
|
|
|
@@ -392,9 +553,9 @@ Role behavior:
|
|
|
392
553
|
|
|
393
554
|
| role | Env var | Allows |
|
|
394
555
|
|---|---|---|
|
|
395
|
-
| read | `WAVEMIND_READ_KEYS` | `/query`, `/stats`, `/metrics` |
|
|
556
|
+
| read | `WAVEMIND_READ_KEYS` | `/query`, `/stats`, `/metrics`, `/index/health` |
|
|
396
557
|
| write | `WAVEMIND_WRITE_KEYS` | read actions plus `/remember` and `/import` |
|
|
397
|
-
| admin | `WAVEMIND_ADMIN_KEYS` or `WAVEMIND_API_KEYS` | all actions, including `/audit`, `/backup`, and `/forget` |
|
|
558
|
+
| admin | `WAVEMIND_ADMIN_KEYS` or `WAVEMIND_API_KEYS` | all actions, including `/audit`, `/backup`, `/index/rebuild`, and `/forget` |
|
|
398
559
|
|
|
399
560
|
Keys are accepted through `Authorization: Bearer <key>` or `X-API-Key: <key>`.
|
|
400
561
|
If no key env vars are set, authentication is disabled for local development.
|
|
@@ -442,7 +603,7 @@ Offline runnable example from a cloned repository:
|
|
|
442
603
|
python examples/langchain_memory.py
|
|
443
604
|
```
|
|
444
605
|
|
|
445
|
-
##
|
|
606
|
+
## Framework Integrations
|
|
446
607
|
|
|
447
608
|
WaveMind only needs two touch points in an agent, service, notebook, or app:
|
|
448
609
|
|
|
@@ -471,6 +632,9 @@ That makes it usable in more than LangChain:
|
|
|
471
632
|
| Preference/profile memory | Store with tags such as `profile`, `preference`, `project`, `decision`. |
|
|
472
633
|
| Corrections/privacy | Use `forget()` or namespace deletion workflows. |
|
|
473
634
|
|
|
635
|
+
More examples: [`docs/USE_CASES.md`](docs/USE_CASES.md).
|
|
636
|
+
Migrating from a Chroma memory store: [`docs/CHROMA_MIGRATION.md`](docs/CHROMA_MIGRATION.md).
|
|
637
|
+
|
|
474
638
|
Framework examples in this repository:
|
|
475
639
|
|
|
476
640
|
| Framework / pattern | Example |
|
|
@@ -483,26 +647,6 @@ Framework examples in this repository:
|
|
|
483
647
|
| AutoGen-style hooks | `wavemind.integrations.autogen`, `examples/framework_integrations.py` |
|
|
484
648
|
| Namespace sharding | `examples/sharded_memory.py` |
|
|
485
649
|
|
|
486
|
-
Minimal custom agent loop:
|
|
487
|
-
|
|
488
|
-
```python
|
|
489
|
-
from wavemind import WaveMind
|
|
490
|
-
|
|
491
|
-
memory = WaveMind(db_path="./state/wavemind.sqlite3")
|
|
492
|
-
|
|
493
|
-
def run_turn(user_id: str, user_text: str, history: list[str]) -> str:
|
|
494
|
-
namespace = f"user:{user_id}"
|
|
495
|
-
hits = memory.query(user_text, namespace=namespace, top_k=5, min_score=0.25)
|
|
496
|
-
recalled = "\n".join(f"- {hit.text}" for hit in hits)
|
|
497
|
-
|
|
498
|
-
prompt = f"Relevant memory:\n{recalled}\n\nUser: {user_text}"
|
|
499
|
-
answer = call_your_llm(prompt, history)
|
|
500
|
-
|
|
501
|
-
memory.remember(f"User said: {user_text}", namespace=namespace, tags=["conversation"])
|
|
502
|
-
memory.remember(f"Assistant answered: {answer}", namespace=namespace, tags=["conversation"])
|
|
503
|
-
return answer
|
|
504
|
-
```
|
|
505
|
-
|
|
506
650
|
## OpenClaw Integration
|
|
507
651
|
|
|
508
652
|
[OpenClaw memory](https://docs.openclaw.ai/concepts/memory) is file-centered:
|
|
@@ -1071,6 +1215,9 @@ python benchmarks/dynamic_memory_benchmark.py --engines wavemind chroma --memori
|
|
|
1071
1215
|
|
|
1072
1216
|
WaveMind is not trying to replace dedicated vector databases at scale. The intended product gap is dynamic priority: frequently used memories can become hotter while old or low-priority memories fade. For static RAG over large document collections, use a mature vector database. For memory that needs persistence, scoped recall, TTL, forgetting, and reinforcement, WaveMind is designed to sit above or beside the vector index.
|
|
1073
1217
|
|
|
1218
|
+
If you already use Chroma for local memory, see the practical migration guide:
|
|
1219
|
+
[`docs/CHROMA_MIGRATION.md`](docs/CHROMA_MIGRATION.md).
|
|
1220
|
+
|
|
1074
1221
|
## Known Limitations
|
|
1075
1222
|
|
|
1076
1223
|
- Optimal capacity on the current NumPy exact index is up to 1000 records.
|
|
@@ -1107,6 +1254,7 @@ WaveMind is not trying to replace dedicated vector databases at scale. The inten
|
|
|
1107
1254
|
## Roadmap
|
|
1108
1255
|
|
|
1109
1256
|
Full roadmap: [`docs/ROADMAP.md`](docs/ROADMAP.md).
|
|
1257
|
+
Launch and positioning kit: [`docs/LAUNCH_KIT.md`](docs/LAUNCH_KIT.md).
|
|
1110
1258
|
|
|
1111
1259
|
Near-term priorities:
|
|
1112
1260
|
|