graph-mind-memory 0.5.3__tar.gz → 0.5.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 (65) hide show
  1. {graph_mind_memory-0.5.3/src/graph_mind_memory.egg-info → graph_mind_memory-0.5.4}/PKG-INFO +2 -2
  2. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/README.md +1 -1
  3. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/pyproject.toml +1 -1
  4. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/brain_log.py +23 -3
  5. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/graph_mind_mcp_server.py +4 -1
  6. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4/src/graph_mind_memory.egg-info}/PKG-INFO +2 -2
  7. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/local_brain.py +2 -0
  8. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_recent_recall.py +1 -1
  9. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/LICENSE +0 -0
  10. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/setup.cfg +0 -0
  11. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/associative_memory.py +0 -0
  12. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/automatic_capture.py +0 -0
  13. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/automatic_capture_cli.py +0 -0
  14. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/clock.py +0 -0
  15. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/coding_memory.py +0 -0
  16. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/conversation_memory.py +0 -0
  17. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/development_memory.py +0 -0
  18. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/development_paths.py +0 -0
  19. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/embedding_warmup.py +0 -0
  20. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/entity_timeline.py +0 -0
  21. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/forget.py +0 -0
  22. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/graph_mind_memory.egg-info/SOURCES.txt +0 -0
  23. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/graph_mind_memory.egg-info/dependency_links.txt +0 -0
  24. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/graph_mind_memory.egg-info/entry_points.txt +0 -0
  25. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/graph_mind_memory.egg-info/requires.txt +0 -0
  26. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/graph_mind_memory.egg-info/top_level.txt +0 -0
  27. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/install.py +0 -0
  28. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/local_embedder.py +0 -0
  29. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/semantic_llm_extractor.py +0 -0
  30. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/semantic_memory.py +0 -0
  31. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/semantic_recall.py +0 -0
  32. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/temporal_resolver.py +0 -0
  33. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/universal_personal_memory.py +0 -0
  34. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/src/vector_cache.py +0 -0
  35. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_associative_memory.py +0 -0
  36. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_automatic_capture.py +0 -0
  37. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_capture_health.py +0 -0
  38. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_coding_memory.py +0 -0
  39. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_cold_start.py +0 -0
  40. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_concurrent_use.py +0 -0
  41. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_conversation_memory.py +0 -0
  42. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_executable_memory.py +0 -0
  43. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_executable_plan_v2_diagnostic.py +0 -0
  44. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_forget.py +0 -0
  45. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_forget_conversation.py +0 -0
  46. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_graph_mind_mcp_server.py +0 -0
  47. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_ingestion_gate.py +0 -0
  48. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_ingestion_synonyms.py +0 -0
  49. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_install.py +0 -0
  50. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_llm_concept_planner.py +0 -0
  51. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_local_brain.py +0 -0
  52. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_longmemeval_adapter.py +0 -0
  53. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_longmemeval_ingestion_calibration.py +0 -0
  54. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_longmemeval_ingestion_preflight.py +0 -0
  55. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_longmemeval_ingestion_v7.py +0 -0
  56. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_memory_algebra.py +0 -0
  57. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_precondition_verifier.py +0 -0
  58. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_resume_retries.py +0 -0
  59. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_secret_masking.py +0 -0
  60. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_semantic_llm_extractor.py +0 -0
  61. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_semantic_memory.py +0 -0
  62. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_semantic_recall.py +0 -0
  63. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_shared_brain.py +0 -0
  64. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_temporal_state.py +0 -0
  65. {graph_mind_memory-0.5.3 → graph_mind_memory-0.5.4}/tests/test_universal_personal_memory.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graph-mind-memory
3
- Version: 0.5.3
3
+ Version: 0.5.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
@@ -272,7 +272,7 @@ python -m unittest discover -s tests -p "test_*.py"
272
272
  ## Known limits
273
273
 
274
274
  - **For the first few seconds after an AI app starts, answers use word search only** while the
275
- embedding model loads in the background (6-9 s on a slow, synced disk; it was 50-70 s before
275
+ embedding model loads in the background (6-30 s on a slow, synced disk, depending on load; it was 50-70 s before
276
276
  0.4). The first answer never waits for it; later answers take well under a second.
277
277
  - **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
278
278
  use.
@@ -244,7 +244,7 @@ python -m unittest discover -s tests -p "test_*.py"
244
244
  ## Known limits
245
245
 
246
246
  - **For the first few seconds after an AI app starts, answers use word search only** while the
247
- embedding model loads in the background (6-9 s on a slow, synced disk; it was 50-70 s before
247
+ embedding model loads in the background (6-30 s on a slow, synced disk, depending on load; it was 50-70 s before
248
248
  0.4). The first answer never waits for it; later answers take well under a second.
249
249
  - **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
250
250
  use.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "graph-mind-memory"
7
- version = "0.5.3"
7
+ version = "0.5.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"
@@ -461,6 +461,27 @@ def _pg(url):
461
461
  return connection
462
462
 
463
463
 
464
+ _READERS: dict = {}
465
+
466
+
467
+ def _read_rows(url, query, parameters):
468
+ """A read on one connection kept open per hub: the sync before every answer paid a fresh
469
+ connection (password handshake included) each time, 0.2 s of a 0.9 s answer. A connection
470
+ the hub dropped (it restarted) is replaced once."""
471
+ import psycopg
472
+ for attempt in (1, 2):
473
+ connection = _READERS.get(url)
474
+ if connection is None or connection.closed:
475
+ connection = _READERS[url] = _pg(url)
476
+ connection.autocommit = True
477
+ try:
478
+ return connection.execute(query, parameters).fetchall()
479
+ except psycopg.OperationalError:
480
+ _READERS.pop(url, None)
481
+ if attempt == 2:
482
+ raise
483
+
484
+
464
485
  def _outbox() -> Path:
465
486
  from development_paths import graph_mind_home
466
487
  return graph_mind_home() / "outbox.jsonl"
@@ -514,9 +535,8 @@ def _new_lines(db: sqlite3.Connection, shared) -> list[str]:
514
535
  source = "postgres"
515
536
  row = db.execute("SELECT offset FROM brain_log_cursor WHERE source=?",
516
537
  (source,)).fetchone()
517
- with _pg(shared) as connection:
518
- rows = connection.execute("SELECT seq, line FROM brain_log WHERE seq > %s ORDER BY seq",
519
- (row[0] if row else 0,)).fetchall()
538
+ rows = _read_rows(shared, "SELECT seq, line FROM brain_log WHERE seq > %s ORDER BY seq",
539
+ (row[0] if row else 0,))
520
540
  if rows:
521
541
  with db:
522
542
  db.execute("INSERT OR REPLACE INTO brain_log_cursor VALUES(?,?)",
@@ -573,12 +573,15 @@ def build_server(db_path=None):
573
573
  return {"status": "SKIPPED", "route": route,
574
574
  "scope_completeness": "NOT_APPLICABLE", "char_budget": max_chars,
575
575
  "used_chars": 0, "estimated_tokens": 0, "selected_items": 0,
576
- "omitted_items": 0, "items": [], "context": ""}
576
+ "omitted_items": 0, "ids": [], "context": ""}
577
577
  recalled = gather(database, query, scopes=scopes, as_of=as_of or _now(),
578
578
  knowledge_cutoff=knowledge_cutoff, limit=limit, recent=recent,
579
579
  since=since, about_assistant=about_assistant, around=around)
580
580
  packet = build_context_pack(recalled, max_chars=max_chars,
581
581
  order="time" if recent else "relevance")
582
+ # `context` already carries each item's kind, date, title, text and source; the item
583
+ # list repeated all of it and was 2/3 of what the model had to read (43K -> 16K chars)
584
+ packet["ids"] = [item["id"] for item in packet.pop("items")]
582
585
  packet["route"] = route
583
586
  warnings = capture_warnings()
584
587
  if warnings:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graph-mind-memory
3
- Version: 0.5.3
3
+ Version: 0.5.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
@@ -272,7 +272,7 @@ python -m unittest discover -s tests -p "test_*.py"
272
272
  ## Known limits
273
273
 
274
274
  - **For the first few seconds after an AI app starts, answers use word search only** while the
275
- embedding model loads in the background (6-9 s on a slow, synced disk; it was 50-70 s before
275
+ embedding model loads in the background (6-30 s on a slow, synced disk, depending on load; it was 50-70 s before
276
276
  0.4). The first answer never waits for it; later answers take well under a second.
277
277
  - **Daily use on Windows only so far.** macOS and Linux pass the tests in CI but have not seen real
278
278
  use.
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
  from development_paths import use_wal
5
5
 
6
6
  from pathlib import Path
7
+ import functools
7
8
  import hashlib
8
9
  import json
9
10
  import re
@@ -39,6 +40,7 @@ def _string_list(value, error):
39
40
  return list(dict.fromkeys(item.strip() for item in value))
40
41
 
41
42
 
43
+ @functools.lru_cache(maxsize=65536) # every memory's title and tags, on every question
42
44
  def _normalized(value):
43
45
  text = unicodedata.normalize("NFKC", value).casefold()
44
46
  return " ".join(re.findall(r"[^\W_]+", text, flags=re.UNICODE))
@@ -71,7 +71,7 @@ CASES = [
71
71
 
72
72
 
73
73
  def ids(packet):
74
- return [item["id"] for item in packet["items"][:3]]
74
+ return packet["ids"][:3]
75
75
 
76
76
 
77
77
  class RecentRecallTests(unittest.IsolatedAsyncioTestCase):