graph-mind-memory 0.3.3__tar.gz → 0.3.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.
Files changed (33) hide show
  1. {graph_mind_memory-0.3.3/graph_mind_memory.egg-info → graph_mind_memory-0.3.4}/PKG-INFO +4 -3
  2. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/README.md +3 -2
  3. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/graph_mind_mcp_server.py +11 -1
  4. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4/graph_mind_memory.egg-info}/PKG-INFO +4 -3
  5. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/local_embedder.py +24 -0
  6. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/pyproject.toml +1 -1
  7. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/LICENSE +0 -0
  8. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/associative_memory.py +0 -0
  9. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/automatic_capture.py +0 -0
  10. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/automatic_capture_cli.py +0 -0
  11. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/brain_log.py +0 -0
  12. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/clock.py +0 -0
  13. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/coding_memory.py +0 -0
  14. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/conversation_memory.py +0 -0
  15. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/development_memory.py +0 -0
  16. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/development_paths.py +0 -0
  17. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/embedding_warmup.py +0 -0
  18. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/entity_timeline.py +0 -0
  19. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/forget.py +0 -0
  20. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/graph_mind_memory.egg-info/SOURCES.txt +0 -0
  21. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/graph_mind_memory.egg-info/dependency_links.txt +0 -0
  22. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/graph_mind_memory.egg-info/entry_points.txt +0 -0
  23. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/graph_mind_memory.egg-info/requires.txt +0 -0
  24. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/graph_mind_memory.egg-info/top_level.txt +0 -0
  25. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/install.py +0 -0
  26. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/local_brain.py +0 -0
  27. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/semantic_llm_extractor.py +0 -0
  28. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/semantic_memory.py +0 -0
  29. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/semantic_recall.py +0 -0
  30. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/setup.cfg +0 -0
  31. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/temporal_resolver.py +0 -0
  32. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/universal_personal_memory.py +0 -0
  33. {graph_mind_memory-0.3.3 → graph_mind_memory-0.3.4}/vector_cache.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graph-mind-memory
3
- Version: 0.3.3
3
+ Version: 0.3.4
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
@@ -258,8 +258,9 @@ python -m unittest discover -p "test_*.py"
258
258
 
259
259
  ## Known limits
260
260
 
261
- - **The first question after an AI app starts waits for the embedding model to load** (a few
262
- seconds; 30-50 s on a slow or synced disk). Later questions take well under a second.
261
+ - **For about the first half minute after an AI app starts, answers use word search only** while the
262
+ embedding model loads in the background (the first answer takes ~2.5 s instead of waiting out a
263
+ 30-50 s load on a slow or synced disk). After that, questions take well under a second.
263
264
  - **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
264
265
  use.
265
266
  - **Capture follows each app's transcript format,** which is not a public interface. An app update
@@ -232,8 +232,9 @@ python -m unittest discover -p "test_*.py"
232
232
 
233
233
  ## Known limits
234
234
 
235
- - **The first question after an AI app starts waits for the embedding model to load** (a few
236
- seconds; 30-50 s on a slow or synced disk). Later questions take well under a second.
235
+ - **For about the first half minute after an AI app starts, answers use word search only** while the
236
+ embedding model loads in the background (the first answer takes ~2.5 s instead of waiting out a
237
+ 30-50 s load on a slow or synced disk). After that, questions take well under a second.
237
238
  - **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
238
239
  use.
239
240
  - **Capture follows each app's transcript format,** which is not a public interface. An app update
@@ -218,7 +218,15 @@ def semantic_turns(database, query, *, scopes=None, since=None, until=None, limi
218
218
  # new pieces are embedded inline; a backlog is filled in the background while this question
219
219
  # is answered from what is already embedded (word search covers the rest meanwhile).
220
220
  missing = [p for p in pieces if embedder._key(p.strip()[:2000]) not in embedder.cache]
221
- if len(missing) > INLINE_EMBED_LIMIT:
221
+ # Nor wait for the model itself: an app's first question used to sit through the torch import
222
+ # (38.8 s measured). If it is not loaded within WAIT_FOR_MODEL seconds, this question is
223
+ # answered from word search plus what is embedded already, and loading carries on.
224
+ asked = embedder._key(query.strip()[:2000]) in embedder.cache
225
+ wait = getattr(embedder, "WAIT_FOR_MODEL", None)
226
+ loading = (wait is not None and (missing or not asked) and not embedder.ready(wait))
227
+ if loading and not asked:
228
+ return []
229
+ if len(missing) > INLINE_EMBED_LIMIT or (loading and missing):
222
230
  embed_in_background(embedder, missing)
223
231
  keep = [i for i, p in enumerate(pieces)
224
232
  if embedder._key(p.strip()[:2000]) in embedder.cache]
@@ -741,6 +749,8 @@ def preload(database):
741
749
 
742
750
 
743
751
  def main():
752
+ from local_embedder import LocalEmbedder
753
+ LocalEmbedder.WAIT_FOR_MODEL = 0.5 # an app's question never waits out a model load
744
754
  preload(configured_db_path())
745
755
  server.run(transport="stdio")
746
756
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graph-mind-memory
3
- Version: 0.3.3
3
+ Version: 0.3.4
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
@@ -258,8 +258,9 @@ python -m unittest discover -p "test_*.py"
258
258
 
259
259
  ## Known limits
260
260
 
261
- - **The first question after an AI app starts waits for the embedding model to load** (a few
262
- seconds; 30-50 s on a slow or synced disk). Later questions take well under a second.
261
+ - **For about the first half minute after an AI app starts, answers use word search only** while the
262
+ embedding model loads in the background (the first answer takes ~2.5 s instead of waiting out a
263
+ 30-50 s load on a slow or synced disk). After that, questions take well under a second.
263
264
  - **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
264
265
  use.
265
266
  - **Capture follows each app's transcript format,** which is not a public interface. An app update
@@ -50,6 +50,12 @@ class LocalEmbedder:
50
50
  _lock = threading.RLock() # model load + cache writes are not thread-safe
51
51
 
52
52
  FLUSH_EVERY = 5000 # vectors between writes: bounds lost work without rewriting per call
53
+ # Seconds a question may wait for the model to load before it is answered by word search
54
+ # alone. None waits (benchmarks, tests, the capture service); the MCP server sets 0.5: loading
55
+ # torch took 38.8 s for an app's first question on a OneDrive-synced Windows PC; now 2.4 s.
56
+ WAIT_FOR_MODEL = None
57
+ _loaded = threading.Event()
58
+ _loading = threading.Lock()
53
59
 
54
60
  def __init__(self, cache_path, model=LOCAL_MODEL):
55
61
  # float32 rows in a sibling directory: the old JSON cache turned 1.1GB on disk into 3-4GB
@@ -68,6 +74,24 @@ class LocalEmbedder:
68
74
  LocalEmbedder._tok = AutoTokenizer.from_pretrained(self.model_name)
69
75
  LocalEmbedder._model = AutoModel.from_pretrained(self.model_name).eval()
70
76
  LocalEmbedder._torch = torch
77
+ LocalEmbedder._loaded.set()
78
+
79
+ def ready(self, timeout) -> bool:
80
+ """Whether the model is loaded, waiting at most `timeout` seconds. The first call starts
81
+ loading it in the background, so a later question finds it ready."""
82
+ if LocalEmbedder._model is not None:
83
+ return True
84
+ if LocalEmbedder._loading.acquire(blocking=False):
85
+ def load():
86
+ try:
87
+ with LocalEmbedder._lock:
88
+ self._load()
89
+ except Exception:
90
+ pass # no model on disk: word search keeps answering
91
+ finally:
92
+ LocalEmbedder._loading.release()
93
+ threading.Thread(target=load, name="graph-mind-model", daemon=True).start()
94
+ return LocalEmbedder._loaded.wait(timeout)
71
95
 
72
96
  def _key(self, text):
73
97
  return hashlib.sha256((self.model_name + "\0" + text).encode("utf-8")).hexdigest()
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "graph-mind-memory"
7
- version = "0.3.3"
7
+ version = "0.3.4"
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"