wavemind 2.0.1__tar.gz → 2.0.3__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.
Files changed (34) hide show
  1. {wavemind-2.0.1/wavemind.egg-info → wavemind-2.0.3}/PKG-INFO +88 -9
  2. {wavemind-2.0.1 → wavemind-2.0.3}/README.md +86 -8
  3. {wavemind-2.0.1 → wavemind-2.0.3}/pyproject.toml +2 -1
  4. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_api.py +40 -1
  5. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_packaging_files.py +21 -0
  6. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/__init__.py +3 -0
  7. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/api.py +4 -3
  8. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/integrations/langchain.py +4 -11
  9. {wavemind-2.0.1 → wavemind-2.0.3/wavemind.egg-info}/PKG-INFO +88 -9
  10. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind.egg-info/requires.txt +1 -0
  11. {wavemind-2.0.1 → wavemind-2.0.3}/LICENSE +0 -0
  12. {wavemind-2.0.1 → wavemind-2.0.3}/setup.cfg +0 -0
  13. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_agent_memory_benchmark.py +0 -0
  14. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_api_process_persistence.py +0 -0
  15. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_cli_smoke.py +0 -0
  16. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_core_persistence.py +0 -0
  17. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_examples.py +0 -0
  18. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_import_benchmark.py +0 -0
  19. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_indexes_encoders.py +0 -0
  20. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_langchain_integration.py +0 -0
  21. {wavemind-2.0.1 → wavemind-2.0.3}/tests/test_semantic_and_latency.py +0 -0
  22. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/__main__.py +0 -0
  23. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/benchmark.py +0 -0
  24. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/cli.py +0 -0
  25. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/core.py +0 -0
  26. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/encoders.py +0 -0
  27. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/importers.py +0 -0
  28. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/indexes.py +0 -0
  29. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/integrations/__init__.py +0 -0
  30. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind/storage.py +0 -0
  31. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind.egg-info/SOURCES.txt +0 -0
  32. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind.egg-info/dependency_links.txt +0 -0
  33. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind.egg-info/entry_points.txt +0 -0
  34. {wavemind-2.0.1 → wavemind-2.0.3}/wavemind.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wavemind
3
- Version: 2.0.1
3
+ Version: 2.0.3
4
4
  Summary: Persistent dynamic memory engine with vector search and wave-field re-ranking
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/CaspianG/wavemind
@@ -27,6 +27,7 @@ Requires-Dist: langchain-classic>=1.0; extra == "langchain"
27
27
  Provides-Extra: dev
28
28
  Requires-Dist: pytest>=8; extra == "dev"
29
29
  Requires-Dist: httpx>=0.27; extra == "dev"
30
+ Requires-Dist: langchain-classic>=1.0; extra == "dev"
30
31
  Dynamic: license-file
31
32
 
32
33
  # WaveMind is persistent dynamic memory for AI agents: vector search first, wave-field priority second, SQLite as the source of truth.
@@ -37,6 +38,8 @@ Dynamic: license-file
37
38
 
38
39
  ## Terminal Demo
39
40
 
41
+ From a cloned repository:
42
+
40
43
  ```text
41
44
  $ python examples/demo.py
42
45
  ✓ Remembered: "Andrey is a trader who tracks market breakouts."
@@ -51,23 +54,66 @@ The demo is offline, keyless, and uses the built-in hash encoder.
51
54
 
52
55
  ## Quick Start
53
56
 
57
+ Install from PyPI and create your first local memory:
58
+
54
59
  ```sh
55
- python -m pip install -e .
60
+ python -m pip install wavemind
56
61
  wavemind remember "Andrey is a trader" --namespace demo
57
62
  wavemind query "trader" --namespace demo
58
63
  ```
59
64
 
60
- This creates `wavemind.sqlite3` in your current working directory.
65
+ What happens here:
66
+
67
+ - `remember` writes the text and its vector pattern into a local SQLite database.
68
+ - By default, the database file is `wavemind.sqlite3` in your current working directory.
69
+ - `--namespace demo` keeps this memory separate from other users, agents, or projects.
70
+ - `query` reads from the same SQLite file and returns the closest remembered texts.
71
+
72
+ ## Optional Embeddings
61
73
 
62
74
  For sentence-transformer embeddings:
63
75
 
64
76
  ```sh
65
- python -m pip install -e ".[sentence]"
77
+ python -m pip install "wavemind[sentence]"
66
78
  wavemind --encoder sentence remember "Andrey is a trader" --namespace demo
67
79
  wavemind --encoder sentence query "What does Andrey do?" --namespace demo
68
80
  ```
69
81
 
70
- One-file setup scripts are also included:
82
+ ## Data Location
83
+
84
+ For an explicit database path, put global options before the command:
85
+
86
+ ```sh
87
+ wavemind --db ./agent_memory.sqlite3 remember "Andrey is a trader" --namespace demo
88
+ wavemind --db ./agent_memory.sqlite3 query "trader" --namespace demo
89
+ ```
90
+
91
+ ## HTTP API
92
+
93
+ Run the local FastAPI server:
94
+
95
+ ```sh
96
+ wavemind --db ./agent_memory.sqlite3 serve --host 127.0.0.1 --port 8000
97
+ ```
98
+
99
+ Store and query memory over HTTP:
100
+
101
+ ```sh
102
+ curl -X POST http://127.0.0.1:8000/remember -H "Content-Type: application/json" -d "{\"text\":\"Andrey is a trader\",\"namespace\":\"demo\"}"
103
+ curl -X POST http://127.0.0.1:8000/query -H "Content-Type: application/json" -d "{\"query\":\"trader\",\"namespace\":\"demo\",\"top_k\":1}"
104
+ ```
105
+
106
+ ## Install From Source
107
+
108
+ For contributors installing from a local clone:
109
+
110
+ ```sh
111
+ git clone https://github.com/CaspianG/wavemind.git
112
+ cd wavemind
113
+ python -m pip install -e ".[sentence]"
114
+ ```
115
+
116
+ One-file setup scripts are also included in the repository:
71
117
 
72
118
  ```sh
73
119
  sh install.sh
@@ -94,12 +140,41 @@ memory = WaveMindMemory(db_path="agent_memory.sqlite3")
94
140
  # Replace: memory = ConversationBufferMemory()
95
141
  ```
96
142
 
97
- Offline runnable example:
143
+ Offline runnable example from a cloned repository:
98
144
 
99
145
  ```sh
100
146
  python examples/langchain_memory.py
101
147
  ```
102
148
 
149
+ ## Why Dynamic Memory
150
+
151
+ WaveMind is not positioned as "a faster Chroma." Chroma, Qdrant, Pinecone, and Weaviate are vector databases: they store embeddings and return nearest neighbors. That is the right tool for many static RAG workloads.
152
+
153
+ WaveMind is an agent memory layer. It still uses vector search first, but then applies memory-specific signals that a plain vector store does not model by default:
154
+
155
+ | memory behavior | Why it matters for agents | WaveMind mechanism |
156
+ |---|---|---|
157
+ | Hot memories | Facts recalled repeatedly should become easier to recall again. | Wave-field hotness and priority updates. |
158
+ | Aging memories | Old low-value facts should fade instead of competing forever. | TTL and decay-aware scoring. |
159
+ | Scoped memory | One user, agent, workspace, or project should not leak into another. | Namespaces and tags. |
160
+ | Explicit forgetting | Agents need deletion, privacy cleanup, and correction workflows. | `forget()` plus SQLite persistence. |
161
+ | Stable restart behavior | A memory system must survive process restarts. | SQLite source of truth, reloadable indexes. |
162
+ | Vector plus memory rank | Semantic similarity is necessary but not sufficient for long-running agents. | k-NN candidates first, wave field as re-ranker. |
163
+
164
+ The current Chroma benchmark below is intentionally conservative: it compares static retrieval on the same facts and the same hash embeddings. That benchmark is useful, but it does not exercise WaveMind's main product thesis: memory that changes over time as an agent recalls, reinforces, ages, and forgets information.
165
+
166
+ The benchmark that should decide whether WaveMind is worth using is a dynamic agent-memory benchmark:
167
+
168
+ | scenario | What should happen |
169
+ |---|---|
170
+ | A user repeats a preference many times. | WaveMind should rank it higher than equally similar but unused facts. |
171
+ | A fact expires via TTL. | WaveMind should suppress it without requiring manual vector cleanup. |
172
+ | A user corrects an old fact. | WaveMind should prefer the newer or reinforced memory. |
173
+ | A query is ambiguous across namespaces. | WaveMind should return only the scoped user's memory. |
174
+ | A long conversation has many irrelevant facts. | WaveMind should preserve useful recall instead of treating all vectors equally. |
175
+
176
+ In short: static vector search answers "what is nearest?" Agent memory also asks "what is still relevant, reinforced, scoped, and allowed to be remembered?"
177
+
103
178
  ## Benchmark
104
179
 
105
180
  Real Russian sentences from Tatoeba, 50 one-word queries, NumPy exact index.
@@ -118,7 +193,7 @@ Capacity check with the hash encoder:
118
193
  | 1000 | 0.88 | 1.00 | 1.50 ms |
119
194
  | 5000 | 0.72 | 0.88 | 5.68 ms |
120
195
 
121
- Run locally:
196
+ Run locally from a cloned repository:
122
197
 
123
198
  ```sh
124
199
  python benchmarks/ru_sentences_benchmark.py --sentences 200 --queries 50 --encoder hash --index numpy
@@ -130,12 +205,14 @@ Agent-memory benchmark against Chroma:
130
205
  200 Russian user facts, 50 natural-language questions, same precomputed `HashingTextEncoder` embeddings for WaveMind and Chroma.
131
206
  Full machine-readable result: `benchmarks/agent_memory_results.json`.
132
207
 
208
+ This is a static retrieval benchmark. It measures baseline ranking and latency, not hotness, TTL, repeated recall, or memory aging.
209
+
133
210
  | engine | precision@1 | precision@3 | avg latency |
134
211
  |---|---:|---:|---:|
135
212
  | WaveMind | 0.82 | 0.90 | 2.25 ms |
136
213
  | Chroma | 0.82 | 0.88 | 0.93 ms |
137
214
 
138
- Run locally:
215
+ Run locally from a cloned repository:
139
216
 
140
217
  ```sh
141
218
  pip install -e ".[bench]"
@@ -154,7 +231,7 @@ python benchmarks/agent_memory_benchmark.py --engines wavemind chroma --facts 20
154
231
  | Best fit | Small to medium agent memory with dynamic recall | Local RAG apps and prototypes | Large-scale vector search |
155
232
  | Scale target today | Up to 1000 optimal on NumPy, FAISS recommended beyond 5000 | Larger than WaveMind local mode | Production scale |
156
233
 
157
- WaveMind is not trying to replace dedicated vector databases at scale. Its difference is dynamic priority: frequently used memories can become hotter while old or low-priority memories fade.
234
+ 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 agent memory that needs persistence, scoped recall, TTL, forgetting, and reinforcement, WaveMind is designed to sit above or beside the vector index.
158
235
 
159
236
  ## Known Limitations
160
237
 
@@ -164,10 +241,12 @@ WaveMind is not trying to replace dedicated vector databases at scale. Its diffe
164
241
  - `sentence-transformers/paraphrase-multilingual-mpnet-base-v2` requires about 420 MB of model files and measured about 53 ms per query on the benchmark machine.
165
242
  - The Chroma comparison currently uses shared precomputed hash embeddings to isolate retrieval/ranking behavior; semantic model comparisons should be run separately.
166
243
  - In the 200-fact agent benchmark, Chroma is faster on average while WaveMind is slightly higher at `precision@3`.
244
+ - The current public benchmark does not yet prove the dynamic-memory advantage. The next benchmark must test hotness, TTL, corrections, namespace isolation, and repeated recall.
167
245
 
168
246
  ## Roadmap
169
247
 
170
248
  - FAISS-first production index path with persisted index rebuilds.
249
+ - Dynamic agent-memory benchmark against Chroma/Qdrant: hotness, TTL, stale-fact suppression, corrections, and namespace isolation.
171
250
  - Expand the agent-memory benchmark to sentence-transformers, FAISS, Chroma default embeddings, and Qdrant.
172
251
  - Better semantic query expansion for short and ambiguous queries.
173
252
  - Namespace quotas, backups, and daemon hardening for SaaS use.
@@ -6,6 +6,8 @@
6
6
 
7
7
  ## Terminal Demo
8
8
 
9
+ From a cloned repository:
10
+
9
11
  ```text
10
12
  $ python examples/demo.py
11
13
  ✓ Remembered: "Andrey is a trader who tracks market breakouts."
@@ -20,23 +22,66 @@ The demo is offline, keyless, and uses the built-in hash encoder.
20
22
 
21
23
  ## Quick Start
22
24
 
25
+ Install from PyPI and create your first local memory:
26
+
23
27
  ```sh
24
- python -m pip install -e .
28
+ python -m pip install wavemind
25
29
  wavemind remember "Andrey is a trader" --namespace demo
26
30
  wavemind query "trader" --namespace demo
27
31
  ```
28
32
 
29
- This creates `wavemind.sqlite3` in your current working directory.
33
+ What happens here:
34
+
35
+ - `remember` writes the text and its vector pattern into a local SQLite database.
36
+ - By default, the database file is `wavemind.sqlite3` in your current working directory.
37
+ - `--namespace demo` keeps this memory separate from other users, agents, or projects.
38
+ - `query` reads from the same SQLite file and returns the closest remembered texts.
39
+
40
+ ## Optional Embeddings
30
41
 
31
42
  For sentence-transformer embeddings:
32
43
 
33
44
  ```sh
34
- python -m pip install -e ".[sentence]"
45
+ python -m pip install "wavemind[sentence]"
35
46
  wavemind --encoder sentence remember "Andrey is a trader" --namespace demo
36
47
  wavemind --encoder sentence query "What does Andrey do?" --namespace demo
37
48
  ```
38
49
 
39
- One-file setup scripts are also included:
50
+ ## Data Location
51
+
52
+ For an explicit database path, put global options before the command:
53
+
54
+ ```sh
55
+ wavemind --db ./agent_memory.sqlite3 remember "Andrey is a trader" --namespace demo
56
+ wavemind --db ./agent_memory.sqlite3 query "trader" --namespace demo
57
+ ```
58
+
59
+ ## HTTP API
60
+
61
+ Run the local FastAPI server:
62
+
63
+ ```sh
64
+ wavemind --db ./agent_memory.sqlite3 serve --host 127.0.0.1 --port 8000
65
+ ```
66
+
67
+ Store and query memory over HTTP:
68
+
69
+ ```sh
70
+ curl -X POST http://127.0.0.1:8000/remember -H "Content-Type: application/json" -d "{\"text\":\"Andrey is a trader\",\"namespace\":\"demo\"}"
71
+ curl -X POST http://127.0.0.1:8000/query -H "Content-Type: application/json" -d "{\"query\":\"trader\",\"namespace\":\"demo\",\"top_k\":1}"
72
+ ```
73
+
74
+ ## Install From Source
75
+
76
+ For contributors installing from a local clone:
77
+
78
+ ```sh
79
+ git clone https://github.com/CaspianG/wavemind.git
80
+ cd wavemind
81
+ python -m pip install -e ".[sentence]"
82
+ ```
83
+
84
+ One-file setup scripts are also included in the repository:
40
85
 
41
86
  ```sh
42
87
  sh install.sh
@@ -63,12 +108,41 @@ memory = WaveMindMemory(db_path="agent_memory.sqlite3")
63
108
  # Replace: memory = ConversationBufferMemory()
64
109
  ```
65
110
 
66
- Offline runnable example:
111
+ Offline runnable example from a cloned repository:
67
112
 
68
113
  ```sh
69
114
  python examples/langchain_memory.py
70
115
  ```
71
116
 
117
+ ## Why Dynamic Memory
118
+
119
+ WaveMind is not positioned as "a faster Chroma." Chroma, Qdrant, Pinecone, and Weaviate are vector databases: they store embeddings and return nearest neighbors. That is the right tool for many static RAG workloads.
120
+
121
+ WaveMind is an agent memory layer. It still uses vector search first, but then applies memory-specific signals that a plain vector store does not model by default:
122
+
123
+ | memory behavior | Why it matters for agents | WaveMind mechanism |
124
+ |---|---|---|
125
+ | Hot memories | Facts recalled repeatedly should become easier to recall again. | Wave-field hotness and priority updates. |
126
+ | Aging memories | Old low-value facts should fade instead of competing forever. | TTL and decay-aware scoring. |
127
+ | Scoped memory | One user, agent, workspace, or project should not leak into another. | Namespaces and tags. |
128
+ | Explicit forgetting | Agents need deletion, privacy cleanup, and correction workflows. | `forget()` plus SQLite persistence. |
129
+ | Stable restart behavior | A memory system must survive process restarts. | SQLite source of truth, reloadable indexes. |
130
+ | Vector plus memory rank | Semantic similarity is necessary but not sufficient for long-running agents. | k-NN candidates first, wave field as re-ranker. |
131
+
132
+ The current Chroma benchmark below is intentionally conservative: it compares static retrieval on the same facts and the same hash embeddings. That benchmark is useful, but it does not exercise WaveMind's main product thesis: memory that changes over time as an agent recalls, reinforces, ages, and forgets information.
133
+
134
+ The benchmark that should decide whether WaveMind is worth using is a dynamic agent-memory benchmark:
135
+
136
+ | scenario | What should happen |
137
+ |---|---|
138
+ | A user repeats a preference many times. | WaveMind should rank it higher than equally similar but unused facts. |
139
+ | A fact expires via TTL. | WaveMind should suppress it without requiring manual vector cleanup. |
140
+ | A user corrects an old fact. | WaveMind should prefer the newer or reinforced memory. |
141
+ | A query is ambiguous across namespaces. | WaveMind should return only the scoped user's memory. |
142
+ | A long conversation has many irrelevant facts. | WaveMind should preserve useful recall instead of treating all vectors equally. |
143
+
144
+ In short: static vector search answers "what is nearest?" Agent memory also asks "what is still relevant, reinforced, scoped, and allowed to be remembered?"
145
+
72
146
  ## Benchmark
73
147
 
74
148
  Real Russian sentences from Tatoeba, 50 one-word queries, NumPy exact index.
@@ -87,7 +161,7 @@ Capacity check with the hash encoder:
87
161
  | 1000 | 0.88 | 1.00 | 1.50 ms |
88
162
  | 5000 | 0.72 | 0.88 | 5.68 ms |
89
163
 
90
- Run locally:
164
+ Run locally from a cloned repository:
91
165
 
92
166
  ```sh
93
167
  python benchmarks/ru_sentences_benchmark.py --sentences 200 --queries 50 --encoder hash --index numpy
@@ -99,12 +173,14 @@ Agent-memory benchmark against Chroma:
99
173
  200 Russian user facts, 50 natural-language questions, same precomputed `HashingTextEncoder` embeddings for WaveMind and Chroma.
100
174
  Full machine-readable result: `benchmarks/agent_memory_results.json`.
101
175
 
176
+ This is a static retrieval benchmark. It measures baseline ranking and latency, not hotness, TTL, repeated recall, or memory aging.
177
+
102
178
  | engine | precision@1 | precision@3 | avg latency |
103
179
  |---|---:|---:|---:|
104
180
  | WaveMind | 0.82 | 0.90 | 2.25 ms |
105
181
  | Chroma | 0.82 | 0.88 | 0.93 ms |
106
182
 
107
- Run locally:
183
+ Run locally from a cloned repository:
108
184
 
109
185
  ```sh
110
186
  pip install -e ".[bench]"
@@ -123,7 +199,7 @@ python benchmarks/agent_memory_benchmark.py --engines wavemind chroma --facts 20
123
199
  | Best fit | Small to medium agent memory with dynamic recall | Local RAG apps and prototypes | Large-scale vector search |
124
200
  | Scale target today | Up to 1000 optimal on NumPy, FAISS recommended beyond 5000 | Larger than WaveMind local mode | Production scale |
125
201
 
126
- WaveMind is not trying to replace dedicated vector databases at scale. Its difference is dynamic priority: frequently used memories can become hotter while old or low-priority memories fade.
202
+ 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 agent memory that needs persistence, scoped recall, TTL, forgetting, and reinforcement, WaveMind is designed to sit above or beside the vector index.
127
203
 
128
204
  ## Known Limitations
129
205
 
@@ -133,10 +209,12 @@ WaveMind is not trying to replace dedicated vector databases at scale. Its diffe
133
209
  - `sentence-transformers/paraphrase-multilingual-mpnet-base-v2` requires about 420 MB of model files and measured about 53 ms per query on the benchmark machine.
134
210
  - The Chroma comparison currently uses shared precomputed hash embeddings to isolate retrieval/ranking behavior; semantic model comparisons should be run separately.
135
211
  - In the 200-fact agent benchmark, Chroma is faster on average while WaveMind is slightly higher at `precision@3`.
212
+ - The current public benchmark does not yet prove the dynamic-memory advantage. The next benchmark must test hotness, TTL, corrections, namespace isolation, and repeated recall.
136
213
 
137
214
  ## Roadmap
138
215
 
139
216
  - FAISS-first production index path with persisted index rebuilds.
217
+ - Dynamic agent-memory benchmark against Chroma/Qdrant: hotness, TTL, stale-fact suppression, corrections, and namespace isolation.
140
218
  - Expand the agent-memory benchmark to sentence-transformers, FAISS, Chroma default embeddings, and Qdrant.
141
219
  - Better semantic query expansion for short and ambiguous queries.
142
220
  - Namespace quotas, backups, and daemon hardening for SaaS use.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wavemind"
7
- version = "2.0.1"
7
+ version = "2.0.3"
8
8
  description = "Persistent dynamic memory engine with vector search and wave-field re-ranking"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -37,6 +37,7 @@ langchain = [
37
37
  dev = [
38
38
  "pytest>=8",
39
39
  "httpx>=0.27",
40
+ "langchain-classic>=1.0",
40
41
  ]
41
42
 
42
43
  [project.scripts]
@@ -1,6 +1,6 @@
1
1
  from fastapi.testclient import TestClient
2
2
 
3
- from wavemind import HashingTextEncoder, WaveMind
3
+ from wavemind import HashingTextEncoder, WaveMind, __version__
4
4
  from wavemind.api import create_app
5
5
 
6
6
 
@@ -50,3 +50,42 @@ def test_fastapi_remember_query_forget_and_stats(tmp_path):
50
50
  empty = client.post("/query", json={"text": "кошка", "namespace": "pets"})
51
51
  assert empty.json()["results"] == []
52
52
 
53
+
54
+ def test_fastapi_query_accepts_query_alias(tmp_path):
55
+ mind = WaveMind(
56
+ db_path=tmp_path / "api.sqlite3",
57
+ width=32,
58
+ height=32,
59
+ layers=2,
60
+ encoder=HashingTextEncoder(vector_dim=64),
61
+ score_threshold=0.0,
62
+ )
63
+ client = TestClient(create_app(mind=mind))
64
+
65
+ remember = client.post(
66
+ "/remember",
67
+ json={"text": "Andrey is a trader", "namespace": "demo"},
68
+ )
69
+ assert remember.status_code == 200
70
+
71
+ query = client.post(
72
+ "/query",
73
+ json={"query": "trader", "namespace": "demo", "top_k": 1},
74
+ )
75
+
76
+ assert query.status_code == 200
77
+ assert query.json()["results"][0]["text"] == "Andrey is a trader"
78
+
79
+
80
+ def test_fastapi_version_matches_package_version():
81
+ app = create_app(
82
+ mind=WaveMind(
83
+ db_path=None,
84
+ width=16,
85
+ height=16,
86
+ layers=1,
87
+ encoder=HashingTextEncoder(vector_dim=16),
88
+ )
89
+ )
90
+
91
+ assert app.version == __version__
@@ -1,4 +1,13 @@
1
1
  from pathlib import Path
2
+ import tomllib
3
+
4
+ import wavemind
5
+
6
+
7
+ def test_package_version_matches_pyproject():
8
+ pyproject = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
9
+
10
+ assert wavemind.__version__ == pyproject["project"]["version"]
2
11
 
3
12
 
4
13
  def test_sentence_extra_is_available_for_install_scripts():
@@ -22,6 +31,18 @@ def test_langchain_extra_installs_classic_memory_api():
22
31
  assert '"langchain-classic>=1.0"' in pyproject
23
32
 
24
33
 
34
+ def test_dev_extra_runs_against_real_langchain_memory_api():
35
+ pyproject = Path("pyproject.toml").read_text(encoding="utf-8")
36
+ integration = Path("wavemind/integrations/langchain.py").read_text(
37
+ encoding="utf-8"
38
+ )
39
+
40
+ assert "dev = [" in pyproject
41
+ assert '"langchain-classic>=1.0"' in pyproject
42
+ assert "class BaseMemory" not in integration
43
+ assert 'pip install "wavemind[langchain]"' in integration
44
+
45
+
25
46
  def test_install_scripts_create_venv_and_install_sentence_extra():
26
47
  install_sh = Path("install.sh").read_text(encoding="utf-8")
27
48
  install_bat = Path("install.bat").read_text(encoding="utf-8")
@@ -8,6 +8,8 @@ from .encoders import (
8
8
  )
9
9
  from .storage import MemoryRecord, SQLiteMemoryStore
10
10
 
11
+ __version__ = "2.0.3"
12
+
11
13
  __all__ = [
12
14
  "FieldProjector",
13
15
  "HashingTextEncoder",
@@ -18,5 +20,6 @@ __all__ = [
18
20
  "TextEncoder",
19
21
  "WaveField",
20
22
  "WaveMind",
23
+ "__version__",
21
24
  "create_text_encoder",
22
25
  ]
@@ -6,8 +6,9 @@ from pathlib import Path
6
6
  from typing import Any
7
7
 
8
8
  from fastapi import Body, FastAPI, Query
9
- from pydantic import BaseModel, Field
9
+ from pydantic import AliasChoices, BaseModel, Field
10
10
 
11
+ from . import __version__
11
12
  from .core import WaveMind
12
13
  from .encoders import create_text_encoder
13
14
  from .importers import import_path
@@ -30,7 +31,7 @@ class RememberResponse(BaseModel):
30
31
 
31
32
 
32
33
  class QueryRequest(BaseModel):
33
- text: str
34
+ text: str = Field(validation_alias=AliasChoices("text", "query"))
34
35
  namespace: str = "default"
35
36
  top_k: int = 3
36
37
  tags: list[str] = Field(default_factory=list)
@@ -101,7 +102,7 @@ def build_default_mind() -> WaveMind:
101
102
 
102
103
  def create_app(mind: WaveMind | None = None) -> FastAPI:
103
104
  logging.basicConfig(level=os.environ.get("WAVEMIND_LOG_LEVEL", "INFO"))
104
- app = FastAPI(title="WaveMind", version="2.0.0")
105
+ app = FastAPI(title="WaveMind", version=__version__)
105
106
  app.state.mind = mind or build_default_mind()
106
107
 
107
108
  @app.post("/remember", response_model=RememberResponse)
@@ -11,17 +11,10 @@ from wavemind import WaveMind
11
11
 
12
12
  try:
13
13
  from langchain_classic.base_memory import BaseMemory
14
- except ImportError:
15
- try:
16
- from langchain.schema import BaseMemory
17
- except ImportError:
18
-
19
- class BaseMemory:
20
- """Small fallback so the integration can be imported without LangChain."""
21
-
22
- def __init__(self, **data: Any):
23
- for key, value in data.items():
24
- setattr(self, key, value)
14
+ except ImportError as exc: # pragma: no cover - exercised in clean installs.
15
+ raise ImportError(
16
+ 'WaveMindMemory requires LangChain. Install it with: pip install "wavemind[langchain]"'
17
+ ) from exc
25
18
 
26
19
 
27
20
  class WaveMindMemory(BaseMemory):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wavemind
3
- Version: 2.0.1
3
+ Version: 2.0.3
4
4
  Summary: Persistent dynamic memory engine with vector search and wave-field re-ranking
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/CaspianG/wavemind
@@ -27,6 +27,7 @@ Requires-Dist: langchain-classic>=1.0; extra == "langchain"
27
27
  Provides-Extra: dev
28
28
  Requires-Dist: pytest>=8; extra == "dev"
29
29
  Requires-Dist: httpx>=0.27; extra == "dev"
30
+ Requires-Dist: langchain-classic>=1.0; extra == "dev"
30
31
  Dynamic: license-file
31
32
 
32
33
  # WaveMind is persistent dynamic memory for AI agents: vector search first, wave-field priority second, SQLite as the source of truth.
@@ -37,6 +38,8 @@ Dynamic: license-file
37
38
 
38
39
  ## Terminal Demo
39
40
 
41
+ From a cloned repository:
42
+
40
43
  ```text
41
44
  $ python examples/demo.py
42
45
  ✓ Remembered: "Andrey is a trader who tracks market breakouts."
@@ -51,23 +54,66 @@ The demo is offline, keyless, and uses the built-in hash encoder.
51
54
 
52
55
  ## Quick Start
53
56
 
57
+ Install from PyPI and create your first local memory:
58
+
54
59
  ```sh
55
- python -m pip install -e .
60
+ python -m pip install wavemind
56
61
  wavemind remember "Andrey is a trader" --namespace demo
57
62
  wavemind query "trader" --namespace demo
58
63
  ```
59
64
 
60
- This creates `wavemind.sqlite3` in your current working directory.
65
+ What happens here:
66
+
67
+ - `remember` writes the text and its vector pattern into a local SQLite database.
68
+ - By default, the database file is `wavemind.sqlite3` in your current working directory.
69
+ - `--namespace demo` keeps this memory separate from other users, agents, or projects.
70
+ - `query` reads from the same SQLite file and returns the closest remembered texts.
71
+
72
+ ## Optional Embeddings
61
73
 
62
74
  For sentence-transformer embeddings:
63
75
 
64
76
  ```sh
65
- python -m pip install -e ".[sentence]"
77
+ python -m pip install "wavemind[sentence]"
66
78
  wavemind --encoder sentence remember "Andrey is a trader" --namespace demo
67
79
  wavemind --encoder sentence query "What does Andrey do?" --namespace demo
68
80
  ```
69
81
 
70
- One-file setup scripts are also included:
82
+ ## Data Location
83
+
84
+ For an explicit database path, put global options before the command:
85
+
86
+ ```sh
87
+ wavemind --db ./agent_memory.sqlite3 remember "Andrey is a trader" --namespace demo
88
+ wavemind --db ./agent_memory.sqlite3 query "trader" --namespace demo
89
+ ```
90
+
91
+ ## HTTP API
92
+
93
+ Run the local FastAPI server:
94
+
95
+ ```sh
96
+ wavemind --db ./agent_memory.sqlite3 serve --host 127.0.0.1 --port 8000
97
+ ```
98
+
99
+ Store and query memory over HTTP:
100
+
101
+ ```sh
102
+ curl -X POST http://127.0.0.1:8000/remember -H "Content-Type: application/json" -d "{\"text\":\"Andrey is a trader\",\"namespace\":\"demo\"}"
103
+ curl -X POST http://127.0.0.1:8000/query -H "Content-Type: application/json" -d "{\"query\":\"trader\",\"namespace\":\"demo\",\"top_k\":1}"
104
+ ```
105
+
106
+ ## Install From Source
107
+
108
+ For contributors installing from a local clone:
109
+
110
+ ```sh
111
+ git clone https://github.com/CaspianG/wavemind.git
112
+ cd wavemind
113
+ python -m pip install -e ".[sentence]"
114
+ ```
115
+
116
+ One-file setup scripts are also included in the repository:
71
117
 
72
118
  ```sh
73
119
  sh install.sh
@@ -94,12 +140,41 @@ memory = WaveMindMemory(db_path="agent_memory.sqlite3")
94
140
  # Replace: memory = ConversationBufferMemory()
95
141
  ```
96
142
 
97
- Offline runnable example:
143
+ Offline runnable example from a cloned repository:
98
144
 
99
145
  ```sh
100
146
  python examples/langchain_memory.py
101
147
  ```
102
148
 
149
+ ## Why Dynamic Memory
150
+
151
+ WaveMind is not positioned as "a faster Chroma." Chroma, Qdrant, Pinecone, and Weaviate are vector databases: they store embeddings and return nearest neighbors. That is the right tool for many static RAG workloads.
152
+
153
+ WaveMind is an agent memory layer. It still uses vector search first, but then applies memory-specific signals that a plain vector store does not model by default:
154
+
155
+ | memory behavior | Why it matters for agents | WaveMind mechanism |
156
+ |---|---|---|
157
+ | Hot memories | Facts recalled repeatedly should become easier to recall again. | Wave-field hotness and priority updates. |
158
+ | Aging memories | Old low-value facts should fade instead of competing forever. | TTL and decay-aware scoring. |
159
+ | Scoped memory | One user, agent, workspace, or project should not leak into another. | Namespaces and tags. |
160
+ | Explicit forgetting | Agents need deletion, privacy cleanup, and correction workflows. | `forget()` plus SQLite persistence. |
161
+ | Stable restart behavior | A memory system must survive process restarts. | SQLite source of truth, reloadable indexes. |
162
+ | Vector plus memory rank | Semantic similarity is necessary but not sufficient for long-running agents. | k-NN candidates first, wave field as re-ranker. |
163
+
164
+ The current Chroma benchmark below is intentionally conservative: it compares static retrieval on the same facts and the same hash embeddings. That benchmark is useful, but it does not exercise WaveMind's main product thesis: memory that changes over time as an agent recalls, reinforces, ages, and forgets information.
165
+
166
+ The benchmark that should decide whether WaveMind is worth using is a dynamic agent-memory benchmark:
167
+
168
+ | scenario | What should happen |
169
+ |---|---|
170
+ | A user repeats a preference many times. | WaveMind should rank it higher than equally similar but unused facts. |
171
+ | A fact expires via TTL. | WaveMind should suppress it without requiring manual vector cleanup. |
172
+ | A user corrects an old fact. | WaveMind should prefer the newer or reinforced memory. |
173
+ | A query is ambiguous across namespaces. | WaveMind should return only the scoped user's memory. |
174
+ | A long conversation has many irrelevant facts. | WaveMind should preserve useful recall instead of treating all vectors equally. |
175
+
176
+ In short: static vector search answers "what is nearest?" Agent memory also asks "what is still relevant, reinforced, scoped, and allowed to be remembered?"
177
+
103
178
  ## Benchmark
104
179
 
105
180
  Real Russian sentences from Tatoeba, 50 one-word queries, NumPy exact index.
@@ -118,7 +193,7 @@ Capacity check with the hash encoder:
118
193
  | 1000 | 0.88 | 1.00 | 1.50 ms |
119
194
  | 5000 | 0.72 | 0.88 | 5.68 ms |
120
195
 
121
- Run locally:
196
+ Run locally from a cloned repository:
122
197
 
123
198
  ```sh
124
199
  python benchmarks/ru_sentences_benchmark.py --sentences 200 --queries 50 --encoder hash --index numpy
@@ -130,12 +205,14 @@ Agent-memory benchmark against Chroma:
130
205
  200 Russian user facts, 50 natural-language questions, same precomputed `HashingTextEncoder` embeddings for WaveMind and Chroma.
131
206
  Full machine-readable result: `benchmarks/agent_memory_results.json`.
132
207
 
208
+ This is a static retrieval benchmark. It measures baseline ranking and latency, not hotness, TTL, repeated recall, or memory aging.
209
+
133
210
  | engine | precision@1 | precision@3 | avg latency |
134
211
  |---|---:|---:|---:|
135
212
  | WaveMind | 0.82 | 0.90 | 2.25 ms |
136
213
  | Chroma | 0.82 | 0.88 | 0.93 ms |
137
214
 
138
- Run locally:
215
+ Run locally from a cloned repository:
139
216
 
140
217
  ```sh
141
218
  pip install -e ".[bench]"
@@ -154,7 +231,7 @@ python benchmarks/agent_memory_benchmark.py --engines wavemind chroma --facts 20
154
231
  | Best fit | Small to medium agent memory with dynamic recall | Local RAG apps and prototypes | Large-scale vector search |
155
232
  | Scale target today | Up to 1000 optimal on NumPy, FAISS recommended beyond 5000 | Larger than WaveMind local mode | Production scale |
156
233
 
157
- WaveMind is not trying to replace dedicated vector databases at scale. Its difference is dynamic priority: frequently used memories can become hotter while old or low-priority memories fade.
234
+ 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 agent memory that needs persistence, scoped recall, TTL, forgetting, and reinforcement, WaveMind is designed to sit above or beside the vector index.
158
235
 
159
236
  ## Known Limitations
160
237
 
@@ -164,10 +241,12 @@ WaveMind is not trying to replace dedicated vector databases at scale. Its diffe
164
241
  - `sentence-transformers/paraphrase-multilingual-mpnet-base-v2` requires about 420 MB of model files and measured about 53 ms per query on the benchmark machine.
165
242
  - The Chroma comparison currently uses shared precomputed hash embeddings to isolate retrieval/ranking behavior; semantic model comparisons should be run separately.
166
243
  - In the 200-fact agent benchmark, Chroma is faster on average while WaveMind is slightly higher at `precision@3`.
244
+ - The current public benchmark does not yet prove the dynamic-memory advantage. The next benchmark must test hotness, TTL, corrections, namespace isolation, and repeated recall.
167
245
 
168
246
  ## Roadmap
169
247
 
170
248
  - FAISS-first production index path with persisted index rebuilds.
249
+ - Dynamic agent-memory benchmark against Chroma/Qdrant: hotness, TTL, stale-fact suppression, corrections, and namespace isolation.
171
250
  - Expand the agent-memory benchmark to sentence-transformers, FAISS, Chroma default embeddings, and Qdrant.
172
251
  - Better semantic query expansion for short and ambiguous queries.
173
252
  - Namespace quotas, backups, and daemon hardening for SaaS use.
@@ -10,6 +10,7 @@ chromadb>=1.0
10
10
  [dev]
11
11
  pytest>=8
12
12
  httpx>=0.27
13
+ langchain-classic>=1.0
13
14
 
14
15
  [indexes]
15
16
  annoy>=1.17
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes