graph-mind-memory 0.1.0__tar.gz → 0.1.2__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.
- {graph_mind_memory-0.1.0/graph_mind_memory.egg-info → graph_mind_memory-0.1.2}/PKG-INFO +22 -5
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/README.md +20 -3
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/brain_log.py +8 -2
- graph_mind_memory-0.1.2/clock.py +19 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/coding_memory.py +1 -1
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/conversation_memory.py +1 -1
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/development_memory.py +1 -1
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2/graph_mind_memory.egg-info}/PKG-INFO +22 -5
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/graph_mind_memory.egg-info/SOURCES.txt +2 -18
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/graph_mind_memory.egg-info/requires.txt +3 -1
- graph_mind_memory-0.1.2/graph_mind_memory.egg-info/top_level.txt +21 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/install.py +8 -5
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/local_brain.py +1 -1
- graph_mind_memory-0.1.2/local_embedder.py +112 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/pyproject.toml +7 -22
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/semantic_recall.py +1 -1
- graph_mind_memory-0.1.0/concept_plan_benchmark_v071.py +0 -248
- graph_mind_memory-0.1.0/executable_memory.py +0 -312
- graph_mind_memory-0.1.0/executable_plan_v2_diagnostic.py +0 -272
- graph_mind_memory-0.1.0/graph_mind_memory.egg-info/top_level.txt +0 -37
- graph_mind_memory-0.1.0/grounded_concept_bridge_v072.py +0 -511
- graph_mind_memory-0.1.0/ingestion_gate.py +0 -113
- graph_mind_memory-0.1.0/ingestion_synonyms.py +0 -165
- graph_mind_memory-0.1.0/llm_concept_planner.py +0 -170
- graph_mind_memory-0.1.0/longmemeval_adapter.py +0 -120
- graph_mind_memory-0.1.0/longmemeval_ingestion_calibration.py +0 -366
- graph_mind_memory-0.1.0/longmemeval_ingestion_preflight.py +0 -188
- graph_mind_memory-0.1.0/longmemeval_ingestion_v7.py +0 -356
- graph_mind_memory-0.1.0/memory_algebra.py +0 -155
- graph_mind_memory-0.1.0/memory_contract.py +0 -154
- graph_mind_memory-0.1.0/memory_normalization.py +0 -13
- graph_mind_memory-0.1.0/memory_vocabulary.py +0 -34
- graph_mind_memory-0.1.0/semantic_grounding_v073.py +0 -501
- graph_mind_memory-0.1.0/state_relation_contract.py +0 -158
- graph_mind_memory-0.1.0/temporal_state.py +0 -210
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/LICENSE +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/associative_memory.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/automatic_capture.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/automatic_capture_cli.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/development_paths.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/embedding_warmup.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/entity_timeline.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/graph_mind_mcp_server.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/graph_mind_memory.egg-info/dependency_links.txt +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/graph_mind_memory.egg-info/entry_points.txt +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/semantic_llm_extractor.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/semantic_memory.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/setup.cfg +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/temporal_resolver.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/universal_personal_memory.py +0 -0
- {graph_mind_memory-0.1.0 → graph_mind_memory-0.1.2}/vector_cache.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graph-mind-memory
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time.
|
|
5
5
|
Author-email: Yohan Ko <goyohan0611@gmail.com>
|
|
6
6
|
License-Expression: AGPL-3.0-only
|
|
@@ -18,7 +18,7 @@ Requires-Dist: mcp<3,>=2
|
|
|
18
18
|
Requires-Dist: numpy
|
|
19
19
|
Requires-Dist: transformers
|
|
20
20
|
Requires-Dist: tiktoken
|
|
21
|
-
Requires-Dist: pgserver
|
|
21
|
+
Requires-Dist: pgserver; python_version < "3.13"
|
|
22
22
|
Requires-Dist: psycopg[binary]
|
|
23
23
|
Requires-Dist: psutil
|
|
24
24
|
Requires-Dist: fasteners
|
|
@@ -37,6 +37,7 @@ Local-first memory for AI coding assistants. Verbatim storage, on your own PC:
|
|
|
37
37
|
[![][platform-shield]][platform-link]
|
|
38
38
|
[![][longmemeval-shield]][benchmarks-link]
|
|
39
39
|
[![][ci-shield]][ci-link]
|
|
40
|
+
[![][pypi-shield]][pypi-link]
|
|
40
41
|
|
|
41
42
|
*Switch models; keep the memory.*
|
|
42
43
|
|
|
@@ -107,7 +108,9 @@ saves them. Graph-MIND does not.
|
|
|
107
108
|
|
|
108
109
|
## Install
|
|
109
110
|
|
|
110
|
-
Requires Python 3.10+ (64-bit). Windows, macOS or Linux.
|
|
111
|
+
Requires Python 3.10+ (64-bit). Windows, macOS or Linux. Hosting a brain that other PCs join
|
|
112
|
+
needs Python 3.12 or older on that one PC (its Postgres helper, pgserver, has no newer build yet);
|
|
113
|
+
everything else, joining included, works on 3.13 and 3.14 too.
|
|
111
114
|
|
|
112
115
|
```bash
|
|
113
116
|
pip install graph-mind-memory
|
|
@@ -131,7 +134,8 @@ The installer:
|
|
|
131
134
|
autostart entry on Linux);
|
|
132
135
|
- downloads the embedding model.
|
|
133
136
|
|
|
134
|
-
Then restart your AI apps.
|
|
137
|
+
Then restart your AI apps. The server is also listed in the
|
|
138
|
+
[MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.goyohan0611-png/graph-mind`. Running the installer again is safe. Run it again if you move the folder.
|
|
135
139
|
|
|
136
140
|
> [!TIP]
|
|
137
141
|
> If `pip` fails with "No such file or directory", Windows' 260-character path limit is the usual
|
|
@@ -224,10 +228,21 @@ python -m unittest discover -p "test_*.py"
|
|
|
224
228
|
can stop capture until Graph-MIND is updated.
|
|
225
229
|
- **Multi-session questions are the weakest type at 80%.** These are questions that count or
|
|
226
230
|
combine facts across many conversations.
|
|
227
|
-
- **The
|
|
231
|
+
- **The repository still holds the research-phase experiments** next to the product (see
|
|
232
|
+
[Repository layout](#repository-layout)); the installed package carries only the 21 product
|
|
233
|
+
modules.
|
|
228
234
|
|
|
229
235
|
The full list is in [REPORT.md §9](REPORT.md#9-known-limits).
|
|
230
236
|
|
|
237
|
+
## Repository layout
|
|
238
|
+
|
|
239
|
+
| | files |
|
|
240
|
+
|---|---|
|
|
241
|
+
| **Product** (what `pip install graph-mind-memory` installs) | `graph_mind_mcp_server.py` (MCP server), `automatic_capture*.py` (capture service), `install.py`, `brain_log.py` (sharing across PCs), `local_brain.py` / `conversation_memory.py` / `coding_memory.py` / `development_memory.py` (stores), `semantic_recall.py` / `local_embedder.py` / `vector_cache.py` / `embedding_warmup.py` (search), and their helpers |
|
|
242
|
+
| **Benchmarks** | `product_answer_eval.py`, `official_judge_v073.py`, `rival_mem0.py`, `rival_mempalace.py`, `rival_clean_prereg.py`, and the result files under `runs/` |
|
|
243
|
+
| **Research phase** | the other modules: earlier extraction pipelines and analyses that REPORT.md cites |
|
|
244
|
+
| **Tests** | `test_*.py` |
|
|
245
|
+
|
|
231
246
|
## Contributing
|
|
232
247
|
|
|
233
248
|
Issues and pull requests are welcome. Contributions are accepted under the [CLA](CLA.md), which
|
|
@@ -250,3 +265,5 @@ available for products that cannot.
|
|
|
250
265
|
[benchmarks-link]: #benchmarks
|
|
251
266
|
[ci-shield]: https://img.shields.io/github/actions/workflow/status/goyohan0611-png/graph-mind/tests.yml?style=flat-square&label=tests
|
|
252
267
|
[ci-link]: https://github.com/goyohan0611-png/graph-mind/actions/workflows/tests.yml
|
|
268
|
+
[pypi-shield]: https://img.shields.io/pypi/v/graph-mind-memory?style=flat-square&label=pypi
|
|
269
|
+
[pypi-link]: https://pypi.org/project/graph-mind-memory/
|
|
@@ -11,6 +11,7 @@ Local-first memory for AI coding assistants. Verbatim storage, on your own PC:
|
|
|
11
11
|
[![][platform-shield]][platform-link]
|
|
12
12
|
[![][longmemeval-shield]][benchmarks-link]
|
|
13
13
|
[![][ci-shield]][ci-link]
|
|
14
|
+
[![][pypi-shield]][pypi-link]
|
|
14
15
|
|
|
15
16
|
*Switch models; keep the memory.*
|
|
16
17
|
|
|
@@ -81,7 +82,9 @@ saves them. Graph-MIND does not.
|
|
|
81
82
|
|
|
82
83
|
## Install
|
|
83
84
|
|
|
84
|
-
Requires Python 3.10+ (64-bit). Windows, macOS or Linux.
|
|
85
|
+
Requires Python 3.10+ (64-bit). Windows, macOS or Linux. Hosting a brain that other PCs join
|
|
86
|
+
needs Python 3.12 or older on that one PC (its Postgres helper, pgserver, has no newer build yet);
|
|
87
|
+
everything else, joining included, works on 3.13 and 3.14 too.
|
|
85
88
|
|
|
86
89
|
```bash
|
|
87
90
|
pip install graph-mind-memory
|
|
@@ -105,7 +108,8 @@ The installer:
|
|
|
105
108
|
autostart entry on Linux);
|
|
106
109
|
- downloads the embedding model.
|
|
107
110
|
|
|
108
|
-
Then restart your AI apps.
|
|
111
|
+
Then restart your AI apps. The server is also listed in the
|
|
112
|
+
[MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.goyohan0611-png/graph-mind`. Running the installer again is safe. Run it again if you move the folder.
|
|
109
113
|
|
|
110
114
|
> [!TIP]
|
|
111
115
|
> If `pip` fails with "No such file or directory", Windows' 260-character path limit is the usual
|
|
@@ -198,10 +202,21 @@ python -m unittest discover -p "test_*.py"
|
|
|
198
202
|
can stop capture until Graph-MIND is updated.
|
|
199
203
|
- **Multi-session questions are the weakest type at 80%.** These are questions that count or
|
|
200
204
|
combine facts across many conversations.
|
|
201
|
-
- **The
|
|
205
|
+
- **The repository still holds the research-phase experiments** next to the product (see
|
|
206
|
+
[Repository layout](#repository-layout)); the installed package carries only the 21 product
|
|
207
|
+
modules.
|
|
202
208
|
|
|
203
209
|
The full list is in [REPORT.md §9](REPORT.md#9-known-limits).
|
|
204
210
|
|
|
211
|
+
## Repository layout
|
|
212
|
+
|
|
213
|
+
| | files |
|
|
214
|
+
|---|---|
|
|
215
|
+
| **Product** (what `pip install graph-mind-memory` installs) | `graph_mind_mcp_server.py` (MCP server), `automatic_capture*.py` (capture service), `install.py`, `brain_log.py` (sharing across PCs), `local_brain.py` / `conversation_memory.py` / `coding_memory.py` / `development_memory.py` (stores), `semantic_recall.py` / `local_embedder.py` / `vector_cache.py` / `embedding_warmup.py` (search), and their helpers |
|
|
216
|
+
| **Benchmarks** | `product_answer_eval.py`, `official_judge_v073.py`, `rival_mem0.py`, `rival_mempalace.py`, `rival_clean_prereg.py`, and the result files under `runs/` |
|
|
217
|
+
| **Research phase** | the other modules: earlier extraction pipelines and analyses that REPORT.md cites |
|
|
218
|
+
| **Tests** | `test_*.py` |
|
|
219
|
+
|
|
205
220
|
## Contributing
|
|
206
221
|
|
|
207
222
|
Issues and pull requests are welcome. Contributions are accepted under the [CLA](CLA.md), which
|
|
@@ -224,3 +239,5 @@ available for products that cannot.
|
|
|
224
239
|
[benchmarks-link]: #benchmarks
|
|
225
240
|
[ci-shield]: https://img.shields.io/github/actions/workflow/status/goyohan0611-png/graph-mind/tests.yml?style=flat-square&label=tests
|
|
226
241
|
[ci-link]: https://github.com/goyohan0611-png/graph-mind/actions/workflows/tests.yml
|
|
242
|
+
[pypi-shield]: https://img.shields.io/pypi/v/graph-mind-memory?style=flat-square&label=pypi
|
|
243
|
+
[pypi-link]: https://pypi.org/project/graph-mind-memory/
|
|
@@ -85,7 +85,13 @@ def local_postgres() -> str:
|
|
|
85
85
|
role other PCs log in as."""
|
|
86
86
|
if "uri" not in _LOCAL_URI:
|
|
87
87
|
import fasteners
|
|
88
|
-
|
|
88
|
+
try:
|
|
89
|
+
from pgserver._commands import initdb, pg_ctl
|
|
90
|
+
except ImportError:
|
|
91
|
+
raise RuntimeError(
|
|
92
|
+
"Hosting the shared brain on this PC needs pgserver, which is built for Python "
|
|
93
|
+
"3.9-3.12 only. Run Graph-MIND on this PC with Python 3.12, or use a synced "
|
|
94
|
+
"folder instead. Joining a brain another PC hosts works on any Python.") from None
|
|
89
95
|
from pgserver.utils import PostmasterInfo
|
|
90
96
|
data = _pg_data()
|
|
91
97
|
data.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -121,8 +127,8 @@ def share(open_firewall: bool = True) -> dict:
|
|
|
121
127
|
to the user and never posted anywhere."""
|
|
122
128
|
import psycopg
|
|
123
129
|
import secrets
|
|
130
|
+
local_postgres() # first: it explains a missing pgserver
|
|
124
131
|
from pgserver._commands import pg_ctl
|
|
125
|
-
local_postgres()
|
|
126
132
|
password = _config().get("share_password") or secrets.token_urlsafe(18)
|
|
127
133
|
data = _pg_data()
|
|
128
134
|
with psycopg.connect(_admin_uri(), autocommit=True) as admin:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Timestamps as the stores accept them: ISO 8601 with a time, in one declared clock."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def timestamp(value, clock):
|
|
8
|
+
if not isinstance(value, str) or "T" not in value:
|
|
9
|
+
raise ValueError("TIMESTAMP_REQUIRED")
|
|
10
|
+
try:
|
|
11
|
+
result = datetime.fromisoformat(value)
|
|
12
|
+
except ValueError:
|
|
13
|
+
raise ValueError("INVALID_TIMESTAMP") from None
|
|
14
|
+
aware = result.utcoffset() is not None
|
|
15
|
+
if clock == "UTC" and aware:
|
|
16
|
+
return result.astimezone(timezone.utc)
|
|
17
|
+
if clock == "SOURCE_LOCAL" and not aware:
|
|
18
|
+
return result
|
|
19
|
+
raise ValueError("CLOCK_DOMAIN_MISMATCH")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graph-mind-memory
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time.
|
|
5
5
|
Author-email: Yohan Ko <goyohan0611@gmail.com>
|
|
6
6
|
License-Expression: AGPL-3.0-only
|
|
@@ -18,7 +18,7 @@ Requires-Dist: mcp<3,>=2
|
|
|
18
18
|
Requires-Dist: numpy
|
|
19
19
|
Requires-Dist: transformers
|
|
20
20
|
Requires-Dist: tiktoken
|
|
21
|
-
Requires-Dist: pgserver
|
|
21
|
+
Requires-Dist: pgserver; python_version < "3.13"
|
|
22
22
|
Requires-Dist: psycopg[binary]
|
|
23
23
|
Requires-Dist: psutil
|
|
24
24
|
Requires-Dist: fasteners
|
|
@@ -37,6 +37,7 @@ Local-first memory for AI coding assistants. Verbatim storage, on your own PC:
|
|
|
37
37
|
[![][platform-shield]][platform-link]
|
|
38
38
|
[![][longmemeval-shield]][benchmarks-link]
|
|
39
39
|
[![][ci-shield]][ci-link]
|
|
40
|
+
[![][pypi-shield]][pypi-link]
|
|
40
41
|
|
|
41
42
|
*Switch models; keep the memory.*
|
|
42
43
|
|
|
@@ -107,7 +108,9 @@ saves them. Graph-MIND does not.
|
|
|
107
108
|
|
|
108
109
|
## Install
|
|
109
110
|
|
|
110
|
-
Requires Python 3.10+ (64-bit). Windows, macOS or Linux.
|
|
111
|
+
Requires Python 3.10+ (64-bit). Windows, macOS or Linux. Hosting a brain that other PCs join
|
|
112
|
+
needs Python 3.12 or older on that one PC (its Postgres helper, pgserver, has no newer build yet);
|
|
113
|
+
everything else, joining included, works on 3.13 and 3.14 too.
|
|
111
114
|
|
|
112
115
|
```bash
|
|
113
116
|
pip install graph-mind-memory
|
|
@@ -131,7 +134,8 @@ The installer:
|
|
|
131
134
|
autostart entry on Linux);
|
|
132
135
|
- downloads the embedding model.
|
|
133
136
|
|
|
134
|
-
Then restart your AI apps.
|
|
137
|
+
Then restart your AI apps. The server is also listed in the
|
|
138
|
+
[MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.goyohan0611-png/graph-mind`. Running the installer again is safe. Run it again if you move the folder.
|
|
135
139
|
|
|
136
140
|
> [!TIP]
|
|
137
141
|
> If `pip` fails with "No such file or directory", Windows' 260-character path limit is the usual
|
|
@@ -224,10 +228,21 @@ python -m unittest discover -p "test_*.py"
|
|
|
224
228
|
can stop capture until Graph-MIND is updated.
|
|
225
229
|
- **Multi-session questions are the weakest type at 80%.** These are questions that count or
|
|
226
230
|
combine facts across many conversations.
|
|
227
|
-
- **The
|
|
231
|
+
- **The repository still holds the research-phase experiments** next to the product (see
|
|
232
|
+
[Repository layout](#repository-layout)); the installed package carries only the 21 product
|
|
233
|
+
modules.
|
|
228
234
|
|
|
229
235
|
The full list is in [REPORT.md §9](REPORT.md#9-known-limits).
|
|
230
236
|
|
|
237
|
+
## Repository layout
|
|
238
|
+
|
|
239
|
+
| | files |
|
|
240
|
+
|---|---|
|
|
241
|
+
| **Product** (what `pip install graph-mind-memory` installs) | `graph_mind_mcp_server.py` (MCP server), `automatic_capture*.py` (capture service), `install.py`, `brain_log.py` (sharing across PCs), `local_brain.py` / `conversation_memory.py` / `coding_memory.py` / `development_memory.py` (stores), `semantic_recall.py` / `local_embedder.py` / `vector_cache.py` / `embedding_warmup.py` (search), and their helpers |
|
|
242
|
+
| **Benchmarks** | `product_answer_eval.py`, `official_judge_v073.py`, `rival_mem0.py`, `rival_mempalace.py`, `rival_clean_prereg.py`, and the result files under `runs/` |
|
|
243
|
+
| **Research phase** | the other modules: earlier extraction pipelines and analyses that REPORT.md cites |
|
|
244
|
+
| **Tests** | `test_*.py` |
|
|
245
|
+
|
|
231
246
|
## Contributing
|
|
232
247
|
|
|
233
248
|
Issues and pull requests are welcome. Contributions are accepted under the [CLA](CLA.md), which
|
|
@@ -250,3 +265,5 @@ available for products that cannot.
|
|
|
250
265
|
[benchmarks-link]: #benchmarks
|
|
251
266
|
[ci-shield]: https://img.shields.io/github/actions/workflow/status/goyohan0611-png/graph-mind/tests.yml?style=flat-square&label=tests
|
|
252
267
|
[ci-link]: https://github.com/goyohan0611-png/graph-mind/actions/workflows/tests.yml
|
|
268
|
+
[pypi-shield]: https://img.shields.io/pypi/v/graph-mind-memory?style=flat-square&label=pypi
|
|
269
|
+
[pypi-link]: https://pypi.org/project/graph-mind-memory/
|
|
@@ -4,38 +4,22 @@ associative_memory.py
|
|
|
4
4
|
automatic_capture.py
|
|
5
5
|
automatic_capture_cli.py
|
|
6
6
|
brain_log.py
|
|
7
|
+
clock.py
|
|
7
8
|
coding_memory.py
|
|
8
|
-
concept_plan_benchmark_v071.py
|
|
9
9
|
conversation_memory.py
|
|
10
10
|
development_memory.py
|
|
11
11
|
development_paths.py
|
|
12
12
|
embedding_warmup.py
|
|
13
13
|
entity_timeline.py
|
|
14
|
-
executable_memory.py
|
|
15
|
-
executable_plan_v2_diagnostic.py
|
|
16
14
|
graph_mind_mcp_server.py
|
|
17
|
-
grounded_concept_bridge_v072.py
|
|
18
|
-
ingestion_gate.py
|
|
19
|
-
ingestion_synonyms.py
|
|
20
15
|
install.py
|
|
21
|
-
llm_concept_planner.py
|
|
22
16
|
local_brain.py
|
|
23
|
-
|
|
24
|
-
longmemeval_ingestion_calibration.py
|
|
25
|
-
longmemeval_ingestion_preflight.py
|
|
26
|
-
longmemeval_ingestion_v7.py
|
|
27
|
-
memory_algebra.py
|
|
28
|
-
memory_contract.py
|
|
29
|
-
memory_normalization.py
|
|
30
|
-
memory_vocabulary.py
|
|
17
|
+
local_embedder.py
|
|
31
18
|
pyproject.toml
|
|
32
|
-
semantic_grounding_v073.py
|
|
33
19
|
semantic_llm_extractor.py
|
|
34
20
|
semantic_memory.py
|
|
35
21
|
semantic_recall.py
|
|
36
|
-
state_relation_contract.py
|
|
37
22
|
temporal_resolver.py
|
|
38
|
-
temporal_state.py
|
|
39
23
|
universal_personal_memory.py
|
|
40
24
|
vector_cache.py
|
|
41
25
|
graph_mind_memory.egg-info/PKG-INFO
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
associative_memory
|
|
2
|
+
automatic_capture
|
|
3
|
+
automatic_capture_cli
|
|
4
|
+
brain_log
|
|
5
|
+
clock
|
|
6
|
+
coding_memory
|
|
7
|
+
conversation_memory
|
|
8
|
+
development_memory
|
|
9
|
+
development_paths
|
|
10
|
+
embedding_warmup
|
|
11
|
+
entity_timeline
|
|
12
|
+
graph_mind_mcp_server
|
|
13
|
+
install
|
|
14
|
+
local_brain
|
|
15
|
+
local_embedder
|
|
16
|
+
semantic_llm_extractor
|
|
17
|
+
semantic_memory
|
|
18
|
+
semantic_recall
|
|
19
|
+
temporal_resolver
|
|
20
|
+
universal_personal_memory
|
|
21
|
+
vector_cache
|
|
@@ -108,10 +108,13 @@ def capture_service(start: bool) -> str:
|
|
|
108
108
|
sys.path.insert(0, str(HERE))
|
|
109
109
|
from automatic_capture import _atomic_json, default_config_path, default_service_state_dir, make_config
|
|
110
110
|
if not default_config_path().exists():
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
config = make_config(workspace=str(HERE), project_id="project:graph-mind",
|
|
112
|
+
session_id="service:automatic-capture-v0.2",
|
|
113
|
+
sessions_root=str(Path.home() / ".codex" / "sessions"))
|
|
114
|
+
# Conversations only. Watching a code folder is opt-in: this folder is Graph-MIND itself,
|
|
115
|
+
# or site-packages after a pip install, and the service would rescan it every 2 minutes.
|
|
116
|
+
config["code_workspaces"], config["workspace_scopes"] = [], {}
|
|
117
|
+
_atomic_json(default_config_path(), config)
|
|
115
118
|
script = HERE / "automatic_capture_cli.py"
|
|
116
119
|
system = platform.system()
|
|
117
120
|
if system == "Windows":
|
|
@@ -156,7 +159,7 @@ def capture_service(start: bool) -> str:
|
|
|
156
159
|
|
|
157
160
|
def embedding_model():
|
|
158
161
|
sys.path.insert(0, str(HERE))
|
|
159
|
-
from
|
|
162
|
+
from local_embedder import LOCAL_MODEL
|
|
160
163
|
from transformers import AutoModel, AutoTokenizer
|
|
161
164
|
AutoTokenizer.from_pretrained(LOCAL_MODEL)
|
|
162
165
|
AutoModel.from_pretrained(LOCAL_MODEL)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""The on-device embedder: multilingual MiniLM, mean pooling, vectors cached on disk.
|
|
2
|
+
|
|
3
|
+
No text leaves the machine. Split out of the v0.7.3 research script (semantic_grounding_v073.py),
|
|
4
|
+
which still imports it from here, so the product no longer pulls that script's experiment chain.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import hashlib
|
|
10
|
+
import math
|
|
11
|
+
import threading
|
|
12
|
+
|
|
13
|
+
from associative_memory import _terms
|
|
14
|
+
from vector_cache import VectorCache, convert
|
|
15
|
+
|
|
16
|
+
LOCAL_MODEL = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
|
|
17
|
+
ACTIVATE = dict(seed_limit=12, hops=2, fanout=8, max_nodes=24, limit=8) # frozen v0.7.1 params
|
|
18
|
+
SEED_LIMIT = ACTIVATE["seed_limit"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LocalEmbedder:
|
|
22
|
+
"""On-device multilingual embeddings via raw transformers (mean pooling, L2-normalized).
|
|
23
|
+
No text leaves the machine — required by the user-owned local-brain promise."""
|
|
24
|
+
|
|
25
|
+
_model = None
|
|
26
|
+
_tok = None
|
|
27
|
+
_lock = threading.RLock() # model load + cache writes are not thread-safe
|
|
28
|
+
|
|
29
|
+
FLUSH_EVERY = 5000 # vectors between writes: bounds lost work without rewriting per call
|
|
30
|
+
|
|
31
|
+
def __init__(self, cache_path, model=LOCAL_MODEL):
|
|
32
|
+
# float32 rows in a sibling directory: the old JSON cache turned 1.1GB on disk into 3-4GB
|
|
33
|
+
# of Python float objects and got two evaluation runs killed for memory pressure.
|
|
34
|
+
self.cache_path = Path(cache_path)
|
|
35
|
+
self.model_name = model
|
|
36
|
+
self.cache = VectorCache(self.cache_path.with_suffix(".vec"), model=model)
|
|
37
|
+
if not len(self.cache) and self.cache_path.exists():
|
|
38
|
+
self.cache = convert(self.cache_path, self.cache_path.with_suffix(".vec"), model)
|
|
39
|
+
self._since = 0
|
|
40
|
+
|
|
41
|
+
def _load(self):
|
|
42
|
+
if LocalEmbedder._model is None:
|
|
43
|
+
import torch
|
|
44
|
+
from transformers import AutoModel, AutoTokenizer
|
|
45
|
+
LocalEmbedder._tok = AutoTokenizer.from_pretrained(self.model_name)
|
|
46
|
+
LocalEmbedder._model = AutoModel.from_pretrained(self.model_name).eval()
|
|
47
|
+
LocalEmbedder._torch = torch
|
|
48
|
+
|
|
49
|
+
def _key(self, text):
|
|
50
|
+
return hashlib.sha256((self.model_name + "\0" + text).encode("utf-8")).hexdigest()
|
|
51
|
+
|
|
52
|
+
def _encode(self, texts):
|
|
53
|
+
import torch
|
|
54
|
+
torch = LocalEmbedder._torch
|
|
55
|
+
batch = LocalEmbedder._tok(texts, padding=True, truncation=True,
|
|
56
|
+
max_length=256, return_tensors="pt")
|
|
57
|
+
with torch.no_grad():
|
|
58
|
+
out = LocalEmbedder._model(**batch)
|
|
59
|
+
mask = batch["attention_mask"].unsqueeze(-1).float()
|
|
60
|
+
emb = (out.last_hidden_state * mask).sum(1) / mask.sum(1).clamp(min=1e-9)
|
|
61
|
+
emb = torch.nn.functional.normalize(emb, dim=1)
|
|
62
|
+
return emb.tolist()
|
|
63
|
+
|
|
64
|
+
def embed(self, texts):
|
|
65
|
+
texts = [t.strip()[:2000] for t in texts]
|
|
66
|
+
missing = [t for t in dict.fromkeys(texts) if self._key(t) not in self.cache]
|
|
67
|
+
if missing:
|
|
68
|
+
with LocalEmbedder._lock:
|
|
69
|
+
missing = [t for t in dict.fromkeys(texts) if self._key(t) not in self.cache]
|
|
70
|
+
self._load()
|
|
71
|
+
for start in range(0, len(missing), 128): # larger batch = higher CPU throughput
|
|
72
|
+
chunk = missing[start:start + 128]
|
|
73
|
+
for text, vector in zip(chunk, self._encode(chunk)):
|
|
74
|
+
self.cache.put(self._key(text), vector)
|
|
75
|
+
self._since += 1
|
|
76
|
+
if self._since >= LocalEmbedder.FLUSH_EVERY:
|
|
77
|
+
self.flush()
|
|
78
|
+
return [self.cache.get(self._key(t)) for t in texts]
|
|
79
|
+
|
|
80
|
+
def flush(self):
|
|
81
|
+
with LocalEmbedder._lock:
|
|
82
|
+
self.cache.flush()
|
|
83
|
+
self._since = 0
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def cosine(a, b):
|
|
87
|
+
dot = sum(i * j for i, j in zip(a, b))
|
|
88
|
+
na = math.sqrt(sum(i * i for i in a))
|
|
89
|
+
nb = math.sqrt(sum(j * j for j in b))
|
|
90
|
+
return dot / (na * nb) if na and nb else 0.0
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def semantic_coverage(cue_vecs, seed_vecs):
|
|
94
|
+
"""Mean over cues of the best cosine similarity of that cue to any seed text."""
|
|
95
|
+
if not cue_vecs or not seed_vecs:
|
|
96
|
+
return 0.0
|
|
97
|
+
return sum(max(cosine(c, s) for s in seed_vecs) for c in cue_vecs) / len(cue_vecs)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _seed_texts(index, query, cues):
|
|
101
|
+
terms = _terms(" ".join([query, *cues]))
|
|
102
|
+
if not terms:
|
|
103
|
+
return []
|
|
104
|
+
expression = " OR ".join('"' + t.replace('"', '""') + '"' for t in terms)
|
|
105
|
+
rows = index.db.execute(
|
|
106
|
+
"""SELECT associative_engrams_fts.text AS text
|
|
107
|
+
FROM associative_engrams_fts JOIN associative_engrams e
|
|
108
|
+
ON e.engram_id=associative_engrams_fts.engram_id
|
|
109
|
+
WHERE associative_engrams_fts MATCH ?
|
|
110
|
+
ORDER BY bm25(associative_engrams_fts), e.revision DESC LIMIT ?""",
|
|
111
|
+
[expression, SEED_LIMIT]).fetchall()
|
|
112
|
+
return [r["text"] for r in rows]
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "graph-mind-memory"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -23,7 +23,9 @@ dependencies = [
|
|
|
23
23
|
"numpy",
|
|
24
24
|
"transformers",
|
|
25
25
|
"tiktoken",
|
|
26
|
-
|
|
26
|
+
# hosts the shared brain's Postgres; built for Python 3.9-3.12 only. Joining another PC's
|
|
27
|
+
# brain (psycopg) and everything else work on any supported Python.
|
|
28
|
+
"pgserver; python_version < '3.13'",
|
|
27
29
|
"psycopg[binary]",
|
|
28
30
|
"psutil",
|
|
29
31
|
"fasteners",
|
|
@@ -39,44 +41,27 @@ graph-mind-install = "install:main"
|
|
|
39
41
|
graph-mind-capture = "automatic_capture_cli:main"
|
|
40
42
|
|
|
41
43
|
[tool.setuptools]
|
|
42
|
-
# ponytail: flat modules, as in the repository; a graph_mind/ package is the upgrade
|
|
43
|
-
# research-phase modules are trimmed out of the product's imports.
|
|
44
|
+
# ponytail: flat modules, as in the repository; a graph_mind/ package is the upgrade path.
|
|
44
45
|
py-modules = [
|
|
45
46
|
"associative_memory",
|
|
46
47
|
"automatic_capture",
|
|
47
48
|
"automatic_capture_cli",
|
|
48
49
|
"brain_log",
|
|
50
|
+
"clock",
|
|
49
51
|
"coding_memory",
|
|
50
|
-
"concept_plan_benchmark_v071",
|
|
51
52
|
"conversation_memory",
|
|
52
53
|
"development_memory",
|
|
53
54
|
"development_paths",
|
|
54
55
|
"embedding_warmup",
|
|
55
56
|
"entity_timeline",
|
|
56
|
-
"executable_memory",
|
|
57
|
-
"executable_plan_v2_diagnostic",
|
|
58
57
|
"graph_mind_mcp_server",
|
|
59
|
-
"grounded_concept_bridge_v072",
|
|
60
|
-
"ingestion_gate",
|
|
61
|
-
"ingestion_synonyms",
|
|
62
58
|
"install",
|
|
63
|
-
"llm_concept_planner",
|
|
64
59
|
"local_brain",
|
|
65
|
-
"
|
|
66
|
-
"longmemeval_ingestion_calibration",
|
|
67
|
-
"longmemeval_ingestion_preflight",
|
|
68
|
-
"longmemeval_ingestion_v7",
|
|
69
|
-
"memory_algebra",
|
|
70
|
-
"memory_contract",
|
|
71
|
-
"memory_normalization",
|
|
72
|
-
"memory_vocabulary",
|
|
73
|
-
"semantic_grounding_v073",
|
|
60
|
+
"local_embedder",
|
|
74
61
|
"semantic_llm_extractor",
|
|
75
62
|
"semantic_memory",
|
|
76
63
|
"semantic_recall",
|
|
77
|
-
"state_relation_contract",
|
|
78
64
|
"temporal_resolver",
|
|
79
|
-
"temporal_state",
|
|
80
65
|
"universal_personal_memory",
|
|
81
66
|
"vector_cache",
|
|
82
67
|
]
|
|
@@ -16,7 +16,7 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
|
|
19
|
-
from
|
|
19
|
+
from local_embedder import (ACTIVATE, LocalEmbedder, cosine,
|
|
20
20
|
_seed_texts, semantic_coverage)
|
|
21
21
|
|
|
22
22
|
DEFAULT_THRESHOLD = 0.35 # pre-registered on the local MiniLM scale (dev safe window [0.30,0.40])
|