wavemind 2.0.2__tar.gz → 2.0.4__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.0.2/wavemind.egg-info → wavemind-2.0.4}/PKG-INFO +17 -1
- {wavemind-2.0.2 → wavemind-2.0.4}/README.md +15 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/pyproject.toml +2 -1
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_api.py +40 -1
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_packaging_files.py +23 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/__init__.py +3 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/api.py +4 -3
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/integrations/langchain.py +4 -11
- {wavemind-2.0.2 → wavemind-2.0.4/wavemind.egg-info}/PKG-INFO +17 -1
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind.egg-info/requires.txt +1 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/LICENSE +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/setup.cfg +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_agent_memory_benchmark.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_api_process_persistence.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_cli_smoke.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_core_persistence.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_examples.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_import_benchmark.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_indexes_encoders.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_langchain_integration.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/tests/test_semantic_and_latency.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/__main__.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/benchmark.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/cli.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/core.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/encoders.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/importers.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/indexes.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/integrations/__init__.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind/storage.py +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind.egg-info/SOURCES.txt +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind.egg-info/dependency_links.txt +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/wavemind.egg-info/entry_points.txt +0 -0
- {wavemind-2.0.2 → wavemind-2.0.4}/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.
|
|
3
|
+
Version: 2.0.4
|
|
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.
|
|
@@ -87,6 +88,21 @@ wavemind --db ./agent_memory.sqlite3 remember "Andrey is a trader" --namespace d
|
|
|
87
88
|
wavemind --db ./agent_memory.sqlite3 query "trader" --namespace demo
|
|
88
89
|
```
|
|
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
|
+
|
|
90
106
|
## Install From Source
|
|
91
107
|
|
|
92
108
|
For contributors installing from a local clone:
|
|
@@ -56,6 +56,21 @@ wavemind --db ./agent_memory.sqlite3 remember "Andrey is a trader" --namespace d
|
|
|
56
56
|
wavemind --db ./agent_memory.sqlite3 query "trader" --namespace demo
|
|
57
57
|
```
|
|
58
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
|
+
|
|
59
74
|
## Install From Source
|
|
60
75
|
|
|
61
76
|
For contributors installing from a local clone:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "wavemind"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.4"
|
|
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,15 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
import wavemind
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_package_version_matches_pyproject():
|
|
8
|
+
pyproject = Path("pyproject.toml").read_text(encoding="utf-8")
|
|
9
|
+
match = re.search(r'^version = "([^"]+)"$', pyproject, flags=re.MULTILINE)
|
|
10
|
+
|
|
11
|
+
assert match is not None
|
|
12
|
+
assert wavemind.__version__ == match.group(1)
|
|
2
13
|
|
|
3
14
|
|
|
4
15
|
def test_sentence_extra_is_available_for_install_scripts():
|
|
@@ -22,6 +33,18 @@ def test_langchain_extra_installs_classic_memory_api():
|
|
|
22
33
|
assert '"langchain-classic>=1.0"' in pyproject
|
|
23
34
|
|
|
24
35
|
|
|
36
|
+
def test_dev_extra_runs_against_real_langchain_memory_api():
|
|
37
|
+
pyproject = Path("pyproject.toml").read_text(encoding="utf-8")
|
|
38
|
+
integration = Path("wavemind/integrations/langchain.py").read_text(
|
|
39
|
+
encoding="utf-8"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
assert "dev = [" in pyproject
|
|
43
|
+
assert '"langchain-classic>=1.0"' in pyproject
|
|
44
|
+
assert "class BaseMemory" not in integration
|
|
45
|
+
assert 'pip install "wavemind[langchain]"' in integration
|
|
46
|
+
|
|
47
|
+
|
|
25
48
|
def test_install_scripts_create_venv_and_install_sentence_extra():
|
|
26
49
|
install_sh = Path("install.sh").read_text(encoding="utf-8")
|
|
27
50
|
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.4"
|
|
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=
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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.
|
|
3
|
+
Version: 2.0.4
|
|
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.
|
|
@@ -87,6 +88,21 @@ wavemind --db ./agent_memory.sqlite3 remember "Andrey is a trader" --namespace d
|
|
|
87
88
|
wavemind --db ./agent_memory.sqlite3 query "trader" --namespace demo
|
|
88
89
|
```
|
|
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
|
+
|
|
90
106
|
## Install From Source
|
|
91
107
|
|
|
92
108
|
For contributors installing from a local clone:
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|