memplex 3.2.4__tar.gz → 3.2.7__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 (124) hide show
  1. {memplex-3.2.4 → memplex-3.2.7}/PKG-INFO +5 -2
  2. memplex-3.2.7/README.md +186 -0
  3. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/.claude-plugin/plugin.json +1 -1
  4. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/scripts/hook-runner.py +27 -1
  5. {memplex-3.2.4 → memplex-3.2.7}/memplex/adapters/agent_installer.py +13 -1
  6. {memplex-3.2.4 → memplex-3.2.7}/memplex/adapters/agent_runtime.py +2 -7
  7. {memplex-3.2.4 → memplex-3.2.7}/memplex/adapters/cli.py +5 -13
  8. {memplex-3.2.4 → memplex-3.2.7}/memplex/adapters/mcp_server.py +1 -1
  9. {memplex-3.2.4 → memplex-3.2.7}/memplex/config.py +2 -4
  10. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/associator/term_mapper.py +8 -1
  11. {memplex-3.2.4 → memplex-3.2.7}/memplex/retrieval/embedding.py +191 -8
  12. {memplex-3.2.4 → memplex-3.2.7}/memplex/service.py +21 -2
  13. memplex-3.2.7/memplex/storage/lite/search_index.py +305 -0
  14. {memplex-3.2.4 → memplex-3.2.7}/memplex/storage/lite/store.py +76 -63
  15. {memplex-3.2.4 → memplex-3.2.7}/memplex.egg-info/PKG-INFO +5 -2
  16. {memplex-3.2.4 → memplex-3.2.7}/memplex.egg-info/SOURCES.txt +3 -0
  17. {memplex-3.2.4 → memplex-3.2.7}/memplex.egg-info/requires.txt +5 -1
  18. {memplex-3.2.4 → memplex-3.2.7}/pyproject.toml +6 -2
  19. {memplex-3.2.4 → memplex-3.2.7}/tests/test_agent_hot_paths.py +9 -11
  20. {memplex-3.2.4 → memplex-3.2.7}/tests/test_agent_runtime.py +27 -0
  21. {memplex-3.2.4 → memplex-3.2.7}/tests/test_associators.py +15 -0
  22. {memplex-3.2.4 → memplex-3.2.7}/tests/test_config.py +5 -0
  23. memplex-3.2.7/tests/test_e2e_robustness.py +203 -0
  24. memplex-3.2.7/tests/test_embedding.py +187 -0
  25. {memplex-3.2.4 → memplex-3.2.7}/tests/test_hooks.py +9 -2
  26. {memplex-3.2.4 → memplex-3.2.7}/tests/test_install_scripts.py +3 -3
  27. {memplex-3.2.4 → memplex-3.2.7}/tests/test_storage.py +144 -0
  28. memplex-3.2.4/README.md +0 -136
  29. {memplex-3.2.4 → memplex-3.2.7}/LICENSE +0 -0
  30. {memplex-3.2.4 → memplex-3.2.7}/memplex/__init__.py +0 -0
  31. {memplex-3.2.4 → memplex-3.2.7}/memplex/__main__.py +0 -0
  32. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/.mcp.json +0 -0
  33. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/__init__.py +0 -0
  34. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/hooks/hooks.json +0 -0
  35. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/skills/mem-explore/SKILL.md +0 -0
  36. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/skills/mem-manage/SKILL.md +0 -0
  37. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/skills/mem-search/SKILL.md +0 -0
  38. {memplex-3.2.4 → memplex-3.2.7}/memplex/_plugin/skills/mem-write/SKILL.md +0 -0
  39. {memplex-3.2.4 → memplex-3.2.7}/memplex/adapters/__init__.py +0 -0
  40. {memplex-3.2.4 → memplex-3.2.7}/memplex/adapters/claude_skill.py +0 -0
  41. {memplex-3.2.4 → memplex-3.2.7}/memplex/adapters/http_api.py +0 -0
  42. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/__init__.py +0 -0
  43. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/base.py +0 -0
  44. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/benchmark_cli.py +0 -0
  45. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/evaluator.py +0 -0
  46. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/loader.py +0 -0
  47. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/locomo.py +0 -0
  48. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/memory_eval.py +0 -0
  49. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/memory_metrics.py +0 -0
  50. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/metrics.py +0 -0
  51. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/nq_trivia.py +0 -0
  52. {memplex-3.2.4 → memplex-3.2.7}/memplex/benchmarks/popqa_hotpot.py +0 -0
  53. {memplex-3.2.4 → memplex-3.2.7}/memplex/compaction.py +0 -0
  54. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/__init__.py +0 -0
  55. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/associator/__init__.py +0 -0
  56. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/associator/domain_classifier.py +0 -0
  57. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/associator/entity_aligner.py +0 -0
  58. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/associator/ref_linker.py +0 -0
  59. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/dictionaries/__init__.py +0 -0
  60. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/engine.py +0 -0
  61. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/extractors/__init__.py +0 -0
  62. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/extractors/docx.py +0 -0
  63. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/extractors/image.py +0 -0
  64. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/extractors/markdown.py +0 -0
  65. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/extractors/pdf.py +0 -0
  66. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/extractors/vision_mapper.py +0 -0
  67. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/handlers/__init__.py +0 -0
  68. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/handlers/clipboard.py +0 -0
  69. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/handlers/file_handler.py +0 -0
  70. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/handlers/url_handler.py +0 -0
  71. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/hooks/__init__.py +0 -0
  72. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/hooks/collector.py +0 -0
  73. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/hooks/hook_event.py +0 -0
  74. {memplex-3.2.4 → memplex-3.2.7}/memplex/core/hooks/registry.py +0 -0
  75. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/__init__.py +0 -0
  76. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/enhancer.py +0 -0
  77. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/fallback_chain.py +0 -0
  78. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/injection_guard.py +0 -0
  79. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/provider.py +0 -0
  80. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/providers/__init__.py +0 -0
  81. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/providers/anthropic.py +0 -0
  82. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/providers/local.py +0 -0
  83. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/providers/rule_based.py +0 -0
  84. {memplex-3.2.4 → memplex-3.2.7}/memplex/llm/sanitizer.py +0 -0
  85. {memplex-3.2.4 → memplex-3.2.7}/memplex/logging_utils.py +0 -0
  86. {memplex-3.2.4 → memplex-3.2.7}/memplex/metrics.py +0 -0
  87. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/__init__.py +0 -0
  88. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/feedback.py +0 -0
  89. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/graph.py +0 -0
  90. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/memory.py +0 -0
  91. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/misc.py +0 -0
  92. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/paragraph.py +0 -0
  93. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/search.py +0 -0
  94. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/source.py +0 -0
  95. {memplex-3.2.4 → memplex-3.2.7}/memplex/models/task.py +0 -0
  96. {memplex-3.2.4 → memplex-3.2.7}/memplex/processing/__init__.py +0 -0
  97. {memplex-3.2.4 → memplex-3.2.7}/memplex/processing/graph_builder.py +0 -0
  98. {memplex-3.2.4 → memplex-3.2.7}/memplex/processing/merger/__init__.py +0 -0
  99. {memplex-3.2.4 → memplex-3.2.7}/memplex/processing/merger/confidence_calculator.py +0 -0
  100. {memplex-3.2.4 → memplex-3.2.7}/memplex/processing/merger/conflict_resolver.py +0 -0
  101. {memplex-3.2.4 → memplex-3.2.7}/memplex/retrieval/__init__.py +0 -0
  102. {memplex-3.2.4 → memplex-3.2.7}/memplex/retrieval/dedup.py +0 -0
  103. {memplex-3.2.4 → memplex-3.2.7}/memplex/retrieval/reranker.py +0 -0
  104. {memplex-3.2.4 → memplex-3.2.7}/memplex/storage/__init__.py +0 -0
  105. {memplex-3.2.4 → memplex-3.2.7}/memplex/storage/base.py +0 -0
  106. {memplex-3.2.4 → memplex-3.2.7}/memplex/storage/changelog.py +0 -0
  107. {memplex-3.2.4 → memplex-3.2.7}/memplex/storage/feedback.py +0 -0
  108. {memplex-3.2.4 → memplex-3.2.7}/memplex/storage/lite/__init__.py +0 -0
  109. {memplex-3.2.4 → memplex-3.2.7}/memplex/storage/vector.py +0 -0
  110. {memplex-3.2.4 → memplex-3.2.7}/memplex/wiki/__init__.py +0 -0
  111. {memplex-3.2.4 → memplex-3.2.7}/memplex/wiki/community.py +0 -0
  112. {memplex-3.2.4 → memplex-3.2.7}/memplex/wiki/compiler.py +0 -0
  113. {memplex-3.2.4 → memplex-3.2.7}/memplex/wiki/generator.py +0 -0
  114. {memplex-3.2.4 → memplex-3.2.7}/memplex/wiki/search.py +0 -0
  115. {memplex-3.2.4 → memplex-3.2.7}/memplex/worker.py +0 -0
  116. {memplex-3.2.4 → memplex-3.2.7}/memplex.egg-info/dependency_links.txt +0 -0
  117. {memplex-3.2.4 → memplex-3.2.7}/memplex.egg-info/entry_points.txt +0 -0
  118. {memplex-3.2.4 → memplex-3.2.7}/memplex.egg-info/top_level.txt +0 -0
  119. {memplex-3.2.4 → memplex-3.2.7}/setup.cfg +0 -0
  120. {memplex-3.2.4 → memplex-3.2.7}/tests/test_core_engine.py +0 -0
  121. {memplex-3.2.4 → memplex-3.2.7}/tests/test_graph_builder.py +0 -0
  122. {memplex-3.2.4 → memplex-3.2.7}/tests/test_llm.py +0 -0
  123. {memplex-3.2.4 → memplex-3.2.7}/tests/test_models.py +0 -0
  124. {memplex-3.2.4 → memplex-3.2.7}/tests/test_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memplex
3
- Version: 3.2.4
3
+ Version: 3.2.7
4
4
  Summary: Memplex - Memory Complex: multi-agent knowledge graph memory system with 3-layer retrieval
5
5
  Requires-Python: >=3.11
6
6
  License-File: LICENSE
@@ -17,6 +17,9 @@ Requires-Dist: pytesseract>=0.3.10; extra == "extractors"
17
17
  Provides-Extra: vector
18
18
  Requires-Dist: chromadb>=0.4.0; extra == "vector"
19
19
  Requires-Dist: sentence-transformers>=2.0; extra == "vector"
20
+ Provides-Extra: local-onnx
21
+ Requires-Dist: onnxruntime>=1.17.0; extra == "local-onnx"
22
+ Requires-Dist: tokenizers>=0.15.0; extra == "local-onnx"
20
23
  Provides-Extra: graph
21
24
  Requires-Dist: networkx>=3.0; extra == "graph"
22
25
  Requires-Dist: python-louvain>=0.16; extra == "graph"
@@ -31,7 +34,7 @@ Requires-Dist: asyncpg>=0.29.0; extra == "postgres"
31
34
  Provides-Extra: neo4j
32
35
  Requires-Dist: neo4j>=5.0.0; extra == "neo4j"
33
36
  Provides-Extra: all
34
- Requires-Dist: memplex[embedding,extractors,graph,http,llm,vector]; extra == "all"
37
+ Requires-Dist: memplex[embedding,extractors,graph,http,llm,local-onnx,vector]; extra == "all"
35
38
  Provides-Extra: dev
36
39
  Requires-Dist: pytest>=7.0; extra == "dev"
37
40
  Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
@@ -0,0 +1,186 @@
1
+ # Memplex
2
+
3
+ Memplex is a shared long-term memory layer for AI agents. It gives Codex,
4
+ Claude Code, OpenClaw, Hermes, and similar local agents the same closed loop:
5
+ recall useful memory before a turn, capture what happened after the turn, and
6
+ compact old context in the background.
7
+
8
+ ## Install
9
+
10
+ No source checkout is required.
11
+
12
+ ```bash
13
+ npx memplex setup
14
+ ```
15
+
16
+ Install into a specific agent:
17
+
18
+ ```bash
19
+ npx memplex setup --agent codex --project-path "$PWD"
20
+ npx memplex setup --agent claude-code --project-path "$PWD"
21
+ npx memplex setup --agent openclaw --project-path "$PWD"
22
+ npx memplex setup --agent hermes --project-path "$PWD"
23
+ ```
24
+
25
+ Install every supported local agent:
26
+
27
+ ```bash
28
+ npx memplex setup --agent all --project-path "$PWD"
29
+ ```
30
+
31
+ Uninstall is symmetrical:
32
+
33
+ ```bash
34
+ npx memplex uninstall --agent all
35
+ ```
36
+
37
+ The npm wrapper creates a persistent Python environment at
38
+ `~/.local/share/memplex/agent-venv`, installs `memplex==3.2.7`, detects local
39
+ agent config directories, and registers Memplex into the selected hosts. It uses
40
+ `uv` when available and falls back to `python -m venv` plus `pip`.
41
+
42
+ Python-first users can skip npm:
43
+
44
+ ```bash
45
+ uv tool install memplex==3.2.7
46
+ memplex setup --agent all --project-path "$PWD"
47
+ ```
48
+
49
+ Shell-only fallback:
50
+
51
+ ```bash
52
+ curl -fsSL https://raw.githubusercontent.com/articultur/memplex/main/scripts/install-agent.sh | bash
53
+ ```
54
+
55
+ ## What Gets Installed
56
+
57
+ | Agent | Integration | Installed shape |
58
+ | --- | --- | --- |
59
+ | Codex | MCP server | marker-bounded `mcp_servers.memplex` config |
60
+ | Claude Code | plugin + lifecycle hooks + MCP | packaged plugin and hook runner |
61
+ | OpenClaw | memory plugin slot | `plugins.slots.memory = "memplex"` plus extension files |
62
+ | Hermes | memory provider plugin | provider descriptor and `plugins/memory/memplex` |
63
+
64
+ All installers are reversible and refuse to overwrite unmanaged existing
65
+ Memplex entries.
66
+
67
+ ## Verify
68
+
69
+ List supported profiles:
70
+
71
+ ```bash
72
+ memplex --output json agent list
73
+ ```
74
+
75
+ Run a local closed-loop smoke:
76
+
77
+ ```bash
78
+ memplex --output json agent capture \
79
+ --agent codex \
80
+ --user-message "Use lite storage for local development." \
81
+ --assistant-message "Recorded."
82
+
83
+ memplex --output json agent recall \
84
+ --agent codex \
85
+ "What storage should local development use?"
86
+ ```
87
+
88
+ For a no-write preview:
89
+
90
+ ```bash
91
+ npx memplex setup --agent all --project-path "$PWD" --dry-run
92
+ ```
93
+
94
+ ## Offline And Mainland China
95
+
96
+ Memplex's default local retrieval uses a SQLite FTS5 sidecar index with
97
+ `bm25()` ranking plus generated trigram tokens for Chinese, code symbols,
98
+ paths, and short memory fragments. If SQLite FTS5 is unavailable, it falls back
99
+ to pure-Python local BM25/trigram matching. The agent hot path does not need
100
+ HuggingFace, so `npx memplex setup`, capture, recall, MCP tools, and hooks
101
+ continue to work when HuggingFace is blocked or unavailable.
102
+
103
+ The embedding fallback is also local. To force that path explicitly:
104
+
105
+ ```bash
106
+ MEMPLEX_EMBEDDING_MODEL=tfidf memplex query "local memory"
107
+ ```
108
+
109
+ To enhance semantic recall with a local model and no network downloads:
110
+
111
+ ```bash
112
+ python -m pip install "memplex[local-onnx]"
113
+ export MEMPLEX_LOCAL_ONNX_MODEL=/models/bge-small/model.onnx
114
+ export MEMPLEX_LOCAL_ONNX_TOKENIZER=/models/bge-small/tokenizer.json
115
+ memplex query "local semantic memory"
116
+ ```
117
+
118
+ `MEMPLEX_EMBEDDING_MODEL=local-onnx` or
119
+ `MEMPLEX_EMBEDDING_MODEL=local-onnx:/models/bge-small/model.onnx` opts in
120
+ explicitly and reports configuration errors. With the default auto-enhancement
121
+ path, a missing local ONNX runtime or model keeps the SQLite
122
+ FTS5/BM25+trigram retrieval path alive and falls back to local embedding.
123
+
124
+ Opt into HuggingFace only when the environment can reach it or the model is
125
+ already cached:
126
+
127
+ ```bash
128
+ MEMPLEX_EMBEDDING_MODEL=minilm memplex query "semantic memory"
129
+ MEMPLEX_EMBEDDING_MODEL=bge-m3 memplex query "中文记忆"
130
+ MEMPLEX_EMBEDDING_MODEL=hf:BAAI/bge-m3 memplex query "中文记忆"
131
+ ```
132
+
133
+ If your organization provides an approved HuggingFace mirror, configure it in
134
+ the Python/HuggingFace environment before enabling those models. Otherwise keep
135
+ the default local retrieval and embedding path for agent reliability.
136
+
137
+ ## Core Features
138
+
139
+ - **Automatic agent loop**: pre-turn recall, post-turn capture, background
140
+ consolidation.
141
+ - **4 memory types**: Function, Fact, Preference, Observation.
142
+ - **3-layer retrieval**: SQLite FTS5/BM25+trigram search, timeline, get.
143
+ - **5-dim reranking**: raw relevance, semantic similarity, recency, source
144
+ authority, frequency.
145
+ - **5-stage compaction**: extract, dedup, summarize, prune, archive.
146
+ - **Wiki layer**: full-text/vector retrieval plus graph-aware synthesis.
147
+ - **Namespacing**: user, session, project path, and storage path isolation.
148
+
149
+ ## Docs
150
+
151
+ - [Getting Started](docs/getting-started.md): install, verify, uninstall, and
152
+ troubleshoot.
153
+ - [Explainer](docs/explainer.md): what Memplex is and how the memory loop works.
154
+ - [Agent Integration Loop](docs/agent-integration.md): adapter contracts for
155
+ Codex, Claude Code, OpenClaw, and Hermes.
156
+ - [Release Automation](docs/release-automation.md): npm token handling and
157
+ automated npm publishing.
158
+
159
+ ## From Source
160
+
161
+ ```bash
162
+ git clone https://github.com/articultur/memplex.git
163
+ cd memplex
164
+ pip install -e .
165
+ ```
166
+
167
+ ## CLI Basics
168
+
169
+ ```bash
170
+ memplex write --text "Python list comprehensions are faster than loops"
171
+ memplex query "python performance"
172
+ memplex compact
173
+ memplex health
174
+ ```
175
+
176
+ ## Storage And Privacy
177
+
178
+ The default local backend is a JSON-backed LiteMemoryStore at
179
+ `.memplex/memory.json`. Memplex can also use vector and feedback backends when
180
+ configured.
181
+
182
+ Content wrapped in `<private>...</private>` is not stored.
183
+
184
+ ## License
185
+
186
+ MIT
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memplex",
3
- "version": "3.2.4",
3
+ "version": "3.2.7",
4
4
  "description": "Multi-agent memory system -- persistent knowledge graph with 3-layer retrieval, compaction, and wiki",
5
5
  "author": {
6
6
  "name": "articultur"
@@ -199,6 +199,31 @@ def _print_contract(content: str = "") -> None:
199
199
  print(OUTPUT_CONTRACT)
200
200
 
201
201
 
202
+ def _package_version(memplex_module: Any) -> str:
203
+ """Resolve package version, preferring source-tree pyproject metadata."""
204
+ try:
205
+ import tomllib
206
+
207
+ for parent in Path(__file__).resolve().parents:
208
+ pyproject = parent / "pyproject.toml"
209
+ if not pyproject.exists():
210
+ continue
211
+ project = tomllib.loads(pyproject.read_text(encoding="utf-8")).get(
212
+ "project", {}
213
+ )
214
+ if project.get("name") == "memplex" and project.get("version"):
215
+ return str(project["version"])
216
+ except Exception:
217
+ pass
218
+
219
+ try:
220
+ from importlib.metadata import version as pkg_version
221
+
222
+ return pkg_version("memplex")
223
+ except Exception:
224
+ return getattr(memplex_module, "__version__", "unknown")
225
+
226
+
202
227
  def cmd_setup() -> None:
203
228
  """Check environment on plugin install."""
204
229
  try:
@@ -207,7 +232,7 @@ def cmd_setup() -> None:
207
232
  from memplex.config import load_config
208
233
 
209
234
  # Verify memplex is importable
210
- version = getattr(memplex, "__version__", "unknown")
235
+ version = _package_version(memplex)
211
236
 
212
237
  # Check config
213
238
  try:
@@ -219,6 +244,7 @@ def cmd_setup() -> None:
219
244
  # Initialize service if config exists
220
245
  if cfg:
221
246
  from memplex.service import MemplexService
247
+
222
248
  service = MemplexService(config=cfg)
223
249
  health = service.health()
224
250
  print(f"[Memplex] v{version} installed. Status: {health.get('status', 'unknown')}")
@@ -938,9 +938,21 @@ def _marketplace_json() -> str:
938
938
 
939
939
 
940
940
  def _package_version() -> str:
941
+ pyproject = Path(__file__).resolve().parents[2] / "pyproject.toml"
942
+ if pyproject.exists():
943
+ try:
944
+ import tomllib
945
+
946
+ data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
947
+ project = data.get("project", {})
948
+ if project.get("name") == "memplex" and project.get("version"):
949
+ return str(project["version"])
950
+ except Exception:
951
+ pass
952
+
941
953
  from importlib.metadata import version as pkg_version
942
954
 
943
955
  try:
944
956
  return pkg_version("memplex")
945
957
  except Exception:
946
- return "3.2.4"
958
+ return "3.2.7"
@@ -235,9 +235,7 @@ class AgentMemoryRuntime:
235
235
  self.auto_recall = auto_recall
236
236
  capabilities = AGENT_PROFILES[self.agent].capabilities
237
237
  self.prefetch_enabled = (
238
- capabilities.get("zero_latency_prefetch", False)
239
- if prefetch is None
240
- else prefetch
238
+ capabilities.get("zero_latency_prefetch", False) if prefetch is None else prefetch
241
239
  )
242
240
  self._prefetch_cache = _PREFETCH_CACHE
243
241
 
@@ -338,10 +336,7 @@ class AgentMemoryRuntime:
338
336
  wrapped = IndirectInjectionGuard.filter_and_wrap(result.results, self.service.store)
339
337
  if wrapped:
340
338
  return wrapped
341
- lines = []
342
- for item in result.results:
343
- lines.append(f"[MEMORY id={item.func_id}] {item.summary}")
344
- return "\n".join(lines)
339
+ return "[MEMORY FILTERED | reason=indirect_injection]\nUnsafe recalled memory was omitted."
345
340
 
346
341
  @staticmethod
347
342
  def _query_from_prompt(prompt: str) -> str:
@@ -268,7 +268,7 @@ def cmd_health(args: argparse.Namespace) -> int:
268
268
  try:
269
269
  info = svc.health()
270
270
  print(_fmt(info, args.output))
271
- return 0 if info.get("status") == "ok" else 1
271
+ return 0 if info.get("status") in {"healthy", "warning"} else 1
272
272
  finally:
273
273
  svc.stop()
274
274
 
@@ -477,9 +477,7 @@ def build_parser() -> argparse.ArgumentParser:
477
477
  # -- feedback --
478
478
  p_fb = sub.add_parser("feedback", help="Submit feedback on a memory field")
479
479
  p_fb.add_argument("memory_id", help="Memory ID")
480
- p_fb.add_argument(
481
- "--role", required=True, help="Field role (trigger|action|condition|benefit)"
482
- )
480
+ p_fb.add_argument("--role", required=True, help="Field role (trigger|action|condition|benefit)")
483
481
  p_fb.add_argument("--index", type=int, required=True, help="Value index")
484
482
  p_fb.add_argument(
485
483
  "--verdict",
@@ -508,9 +506,7 @@ def build_parser() -> argparse.ArgumentParser:
508
506
 
509
507
  # -- agent --
510
508
  p_agent = sub.add_parser("agent", help="Portable agent integration commands")
511
- agent_sub = p_agent.add_subparsers(
512
- dest="agent_command", help="Agent integration command"
513
- )
509
+ agent_sub = p_agent.add_subparsers(dest="agent_command", help="Agent integration command")
514
510
  agent_sub.add_parser("list", help="List supported agent profiles")
515
511
 
516
512
  p_agent_manifest = agent_sub.add_parser("manifest", help="Show agent manifest")
@@ -520,9 +516,7 @@ def build_parser() -> argparse.ArgumentParser:
520
516
  help="Agent id: codex | claude-code | openclaw | hermes | all",
521
517
  )
522
518
 
523
- p_agent_install = agent_sub.add_parser(
524
- "install", help="Install Memplex into an agent host"
525
- )
519
+ p_agent_install = agent_sub.add_parser("install", help="Install Memplex into an agent host")
526
520
  p_agent_install.add_argument(
527
521
  "--agent",
528
522
  default="all",
@@ -565,9 +559,7 @@ def build_parser() -> argparse.ArgumentParser:
565
559
  p_agent_recall.add_argument("--top-k", type=int, default=5)
566
560
  p_agent_recall.add_argument("--token-budget", type=int, default=1500)
567
561
 
568
- p_agent_capture = agent_sub.add_parser(
569
- "capture", help="Capture a completed agent turn"
570
- )
562
+ p_agent_capture = agent_sub.add_parser("capture", help="Capture a completed agent turn")
571
563
  p_agent_capture.add_argument("--agent", default="codex")
572
564
  p_agent_capture.add_argument("--user-id", default=None)
573
565
  p_agent_capture.add_argument("--session-id", default="default")
@@ -331,7 +331,7 @@ class MCPServer:
331
331
  },
332
332
  "serverInfo": {
333
333
  "name": "memplex",
334
- "version": "3.2.4",
334
+ "version": "3.2.7",
335
335
  },
336
336
  }
337
337
 
@@ -29,7 +29,7 @@ class StorageConfig:
29
29
  class EmbeddingConfig:
30
30
  """Embedding model configuration."""
31
31
 
32
- model: str = "default" # default | bge-m3 | bge-small | openai
32
+ model: str = "default" # default=local, optional local ONNX; hf:<id>=HF
33
33
  dimension: int = 384
34
34
  batch_size: int = 32
35
35
  contextual_retrieval: bool = True
@@ -263,9 +263,7 @@ def _apply_env_overrides(config: MemplexConfig) -> None:
263
263
  # Handle LLM fallback_chain via MEMPLEX_LLM_FALLBACK_CHAIN (comma-separated)
264
264
  fallback_env = os.environ.get("MEMPLEX_LLM_FALLBACK_CHAIN")
265
265
  if fallback_env is not None:
266
- config.llm.fallback_chain = [
267
- s.strip() for s in fallback_env.split(",") if s.strip()
268
- ]
266
+ config.llm.fallback_chain = [s.strip() for s in fallback_env.split(",") if s.strip()]
269
267
 
270
268
 
271
269
  # ── YAML loading helpers ────────────────────────────────────────
@@ -1,10 +1,13 @@
1
1
  """Term-based association using dictionary lookup."""
2
2
 
3
+ import logging
3
4
  from typing import List, Optional, Set, Tuple
4
5
 
5
6
  from memplex.core.dictionaries import TermDictionary
6
7
  from memplex.models.memory import Function
7
8
 
9
+ logger = logging.getLogger(__name__)
10
+
8
11
 
9
12
  class TermMapper:
10
13
  """Maps terms between documents using dictionary lookup."""
@@ -13,7 +16,7 @@ class TermMapper:
13
16
  self.dictionary = dictionary or TermDictionary()
14
17
 
15
18
  def embed_text(self, text: str) -> Optional[List[float]]:
16
- """Generate embedding vector using sentence-transformers (if available)."""
19
+ """Generate embedding vector using sentence-transformers when available."""
17
20
  try:
18
21
  from sentence_transformers import SentenceTransformer
19
22
 
@@ -22,6 +25,10 @@ class TermMapper:
22
25
  embedding = self._embedding_model.encode([text])[0]
23
26
  return embedding.tolist()
24
27
  except ImportError:
28
+ logger.debug("sentence-transformers not installed; skipping term embedding")
29
+ return None
30
+ except Exception as exc:
31
+ logger.debug("Term embedding unavailable: %s", exc)
25
32
  return None
26
33
 
27
34
  def extract_terms(self, text: str) -> Set[str]: