memplex 3.2.0__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.
- memplex-3.2.0/PKG-INFO +37 -0
- memplex-3.2.0/memnex/__init__.py +31 -0
- memplex-3.2.0/memnex/__main__.py +6 -0
- memplex-3.2.0/memnex/_plugin/.claude-plugin/plugin.json +24 -0
- memplex-3.2.0/memnex/_plugin/.mcp.json +9 -0
- memplex-3.2.0/memnex/_plugin/__init__.py +0 -0
- memplex-3.2.0/memnex/_plugin/hooks/hooks.json +43 -0
- memplex-3.2.0/memnex/_plugin/scripts/hook-runner.py +166 -0
- memplex-3.2.0/memnex/_plugin/skills/mem-explore/SKILL.md +83 -0
- memplex-3.2.0/memnex/_plugin/skills/mem-manage/SKILL.md +92 -0
- memplex-3.2.0/memnex/_plugin/skills/mem-search/SKILL.md +85 -0
- memplex-3.2.0/memnex/_plugin/skills/mem-write/SKILL.md +78 -0
- memplex-3.2.0/memnex/adapters/__init__.py +14 -0
- memplex-3.2.0/memnex/adapters/claude_skill.py +169 -0
- memplex-3.2.0/memnex/adapters/cli.py +525 -0
- memplex-3.2.0/memnex/adapters/http_api.py +314 -0
- memplex-3.2.0/memnex/adapters/mcp_server.py +448 -0
- memplex-3.2.0/memnex/compaction.py +563 -0
- memplex-3.2.0/memnex/config.py +366 -0
- memplex-3.2.0/memnex/core/__init__.py +13 -0
- memplex-3.2.0/memnex/core/associator/__init__.py +8 -0
- memplex-3.2.0/memnex/core/associator/domain_classifier.py +75 -0
- memplex-3.2.0/memnex/core/associator/entity_aligner.py +127 -0
- memplex-3.2.0/memnex/core/associator/ref_linker.py +197 -0
- memplex-3.2.0/memnex/core/associator/term_mapper.py +77 -0
- memplex-3.2.0/memnex/core/dictionaries/__init__.py +50 -0
- memplex-3.2.0/memnex/core/engine.py +667 -0
- memplex-3.2.0/memnex/core/extractors/__init__.py +15 -0
- memplex-3.2.0/memnex/core/extractors/docx.py +97 -0
- memplex-3.2.0/memnex/core/extractors/image.py +233 -0
- memplex-3.2.0/memnex/core/extractors/markdown.py +139 -0
- memplex-3.2.0/memnex/core/extractors/pdf.py +133 -0
- memplex-3.2.0/memnex/core/extractors/vision_mapper.py +131 -0
- memplex-3.2.0/memnex/core/handlers/__init__.py +7 -0
- memplex-3.2.0/memnex/core/handlers/clipboard.py +40 -0
- memplex-3.2.0/memnex/core/handlers/file_handler.py +62 -0
- memplex-3.2.0/memnex/core/handlers/url_handler.py +132 -0
- memplex-3.2.0/memnex/llm/__init__.py +25 -0
- memplex-3.2.0/memnex/llm/enhancer.py +226 -0
- memplex-3.2.0/memnex/llm/fallback_chain.py +87 -0
- memplex-3.2.0/memnex/llm/injection_guard.py +178 -0
- memplex-3.2.0/memnex/llm/provider.py +130 -0
- memplex-3.2.0/memnex/llm/providers/__init__.py +22 -0
- memplex-3.2.0/memnex/llm/providers/anthropic.py +135 -0
- memplex-3.2.0/memnex/llm/providers/local.py +135 -0
- memplex-3.2.0/memnex/llm/providers/rule_based.py +68 -0
- memplex-3.2.0/memnex/llm/sanitizer.py +67 -0
- memplex-3.2.0/memnex/models/__init__.py +68 -0
- memplex-3.2.0/memnex/models/feedback.py +42 -0
- memplex-3.2.0/memnex/models/graph.py +33 -0
- memplex-3.2.0/memnex/models/memory.py +102 -0
- memplex-3.2.0/memnex/models/misc.py +185 -0
- memplex-3.2.0/memnex/models/paragraph.py +45 -0
- memplex-3.2.0/memnex/models/search.py +51 -0
- memplex-3.2.0/memnex/models/source.py +23 -0
- memplex-3.2.0/memnex/models/task.py +62 -0
- memplex-3.2.0/memnex/processing/__init__.py +1 -0
- memplex-3.2.0/memnex/processing/graph_builder.py +278 -0
- memplex-3.2.0/memnex/processing/merger/__init__.py +6 -0
- memplex-3.2.0/memnex/processing/merger/confidence_calculator.py +127 -0
- memplex-3.2.0/memnex/processing/merger/conflict_resolver.py +116 -0
- memplex-3.2.0/memnex/retrieval/__init__.py +1 -0
- memplex-3.2.0/memnex/retrieval/dedup.py +386 -0
- memplex-3.2.0/memnex/retrieval/embedding.py +289 -0
- memplex-3.2.0/memnex/retrieval/reranker.py +299 -0
- memplex-3.2.0/memnex/service.py +902 -0
- memplex-3.2.0/memnex/storage/__init__.py +65 -0
- memplex-3.2.0/memnex/storage/base.py +132 -0
- memplex-3.2.0/memnex/storage/changelog.py +106 -0
- memplex-3.2.0/memnex/storage/feedback.py +486 -0
- memplex-3.2.0/memnex/storage/lite/__init__.py +5 -0
- memplex-3.2.0/memnex/storage/lite/store.py +606 -0
- memplex-3.2.0/memnex/storage/vector.py +265 -0
- memplex-3.2.0/memnex/wiki/__init__.py +11 -0
- memplex-3.2.0/memnex/wiki/community.py +221 -0
- memplex-3.2.0/memnex/wiki/compiler.py +545 -0
- memplex-3.2.0/memnex/wiki/generator.py +270 -0
- memplex-3.2.0/memnex/wiki/search.py +282 -0
- memplex-3.2.0/memnex/worker.py +412 -0
- memplex-3.2.0/memplex.egg-info/PKG-INFO +37 -0
- memplex-3.2.0/memplex.egg-info/SOURCES.txt +94 -0
- memplex-3.2.0/memplex.egg-info/dependency_links.txt +1 -0
- memplex-3.2.0/memplex.egg-info/entry_points.txt +2 -0
- memplex-3.2.0/memplex.egg-info/requires.txt +42 -0
- memplex-3.2.0/memplex.egg-info/top_level.txt +1 -0
- memplex-3.2.0/pyproject.toml +71 -0
- memplex-3.2.0/setup.cfg +4 -0
- memplex-3.2.0/tests/test_associators.py +282 -0
- memplex-3.2.0/tests/test_config.py +200 -0
- memplex-3.2.0/tests/test_core_engine.py +224 -0
- memplex-3.2.0/tests/test_graph_builder.py +259 -0
- memplex-3.2.0/tests/test_hooks.py +453 -0
- memplex-3.2.0/tests/test_llm.py +290 -0
- memplex-3.2.0/tests/test_models.py +322 -0
- memplex-3.2.0/tests/test_service.py +232 -0
- memplex-3.2.0/tests/test_storage.py +485 -0
memplex-3.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: memplex
|
|
3
|
+
Version: 3.2.0
|
|
4
|
+
Summary: Memplex - Memory Complex: multi-agent knowledge graph memory system with 3-layer retrieval
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: pyyaml>=6.0
|
|
7
|
+
Requires-Dist: numpy>=1.24.0
|
|
8
|
+
Requires-Dist: requests>=2.28.0
|
|
9
|
+
Provides-Extra: embedding
|
|
10
|
+
Requires-Dist: sentence-transformers>=2.0; extra == "embedding"
|
|
11
|
+
Provides-Extra: extractors
|
|
12
|
+
Requires-Dist: pdfplumber>=0.9.0; extra == "extractors"
|
|
13
|
+
Requires-Dist: python-docx>=0.8.11; extra == "extractors"
|
|
14
|
+
Requires-Dist: Pillow>=9.0; extra == "extractors"
|
|
15
|
+
Requires-Dist: pytesseract>=0.3.10; extra == "extractors"
|
|
16
|
+
Provides-Extra: vector
|
|
17
|
+
Requires-Dist: chromadb>=0.4.0; extra == "vector"
|
|
18
|
+
Requires-Dist: sentence-transformers>=2.0; extra == "vector"
|
|
19
|
+
Provides-Extra: graph
|
|
20
|
+
Requires-Dist: networkx>=3.0; extra == "graph"
|
|
21
|
+
Requires-Dist: python-louvain>=0.16; extra == "graph"
|
|
22
|
+
Provides-Extra: http
|
|
23
|
+
Requires-Dist: fastapi>=0.100.0; extra == "http"
|
|
24
|
+
Requires-Dist: uvicorn>=0.23.0; extra == "http"
|
|
25
|
+
Provides-Extra: llm
|
|
26
|
+
Requires-Dist: anthropic>=0.30.0; extra == "llm"
|
|
27
|
+
Requires-Dist: openai>=1.0.0; extra == "llm"
|
|
28
|
+
Provides-Extra: postgres
|
|
29
|
+
Requires-Dist: asyncpg>=0.29.0; extra == "postgres"
|
|
30
|
+
Provides-Extra: neo4j
|
|
31
|
+
Requires-Dist: neo4j>=5.0.0; extra == "neo4j"
|
|
32
|
+
Provides-Extra: all
|
|
33
|
+
Requires-Dist: memnex[embedding,extractors,graph,http,llm,vector]; extra == "all"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
37
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""MemNex -- multi-agent memory system.
|
|
2
|
+
|
|
3
|
+
Primary entry point::
|
|
4
|
+
|
|
5
|
+
from memnex import MemNexService
|
|
6
|
+
|
|
7
|
+
svc = MemNexService()
|
|
8
|
+
result = svc.query("登录函数在哪")
|
|
9
|
+
|
|
10
|
+
CLI usage::
|
|
11
|
+
|
|
12
|
+
memnex query "search text"
|
|
13
|
+
memnex write --text "content"
|
|
14
|
+
memnex health
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from memnex.core import CoreEngine
|
|
18
|
+
from memnex.service import MemNexService
|
|
19
|
+
|
|
20
|
+
__all__ = ["CoreEngine", "MemNexService", "main"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main() -> None:
|
|
24
|
+
"""CLI entry point for ``memnex`` command.
|
|
25
|
+
|
|
26
|
+
Delegates to :func:`memnex.adapters.cli.main`.
|
|
27
|
+
"""
|
|
28
|
+
import sys
|
|
29
|
+
from memnex.adapters.cli import main as cli_main
|
|
30
|
+
|
|
31
|
+
sys.exit(cli_main())
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "memplex",
|
|
3
|
+
"version": "3.2.0",
|
|
4
|
+
"description": "Multi-agent memory system -- persistent knowledge graph with 3-layer retrieval, compaction, and wiki",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "articultur"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/articultur/MemNex",
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"claude",
|
|
12
|
+
"claude-code",
|
|
13
|
+
"mcp",
|
|
14
|
+
"plugin",
|
|
15
|
+
"memory",
|
|
16
|
+
"knowledge-graph",
|
|
17
|
+
"retrieval",
|
|
18
|
+
"compaction",
|
|
19
|
+
"wiki",
|
|
20
|
+
"python",
|
|
21
|
+
"fastapi"
|
|
22
|
+
],
|
|
23
|
+
"homepage": "https://github.com/articultur/MemNex#readme"
|
|
24
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "MemNex memory system hooks",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "startup|clear|compact",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"shell": "bash",
|
|
11
|
+
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; MEMNEX_ROOT=\"${MEMNEX_PLUGIN_ROOT:-$(cd \"$(dirname \"$0\")/..\" && pwd)}\"; python \"$MEMNEX_ROOT/scripts/hook-runner.py\" session-start",
|
|
12
|
+
"timeout": 30
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"PostToolUse": [
|
|
18
|
+
{
|
|
19
|
+
"matcher": "Write|Edit|Bash",
|
|
20
|
+
"hooks": [
|
|
21
|
+
{
|
|
22
|
+
"type": "command",
|
|
23
|
+
"shell": "bash",
|
|
24
|
+
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; MEMNEX_ROOT=\"${MEMNEX_PLUGIN_ROOT:-$(cd \"$(dirname \"$0\")/..\" && pwd)}\"; python \"$MEMNEX_ROOT/scripts/hook-runner.py\" observation \"$MEMNEX_TOOL_NAME\" \"$MEMNEX_SESSION_ID\"",
|
|
25
|
+
"timeout": 15
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"Stop": [
|
|
31
|
+
{
|
|
32
|
+
"hooks": [
|
|
33
|
+
{
|
|
34
|
+
"type": "command",
|
|
35
|
+
"shell": "bash",
|
|
36
|
+
"command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; MEMNEX_ROOT=\"${MEMNEX_PLUGIN_ROOT:-$(cd \"$(dirname \"$0\")/..\" && pwd)}\"; python \"$MEMNEX_ROOT/scripts/hook-runner.py\" session-stop",
|
|
37
|
+
"timeout": 60
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""MemNex Hook Runner -- dispatches lifecycle hooks for Claude Code.
|
|
3
|
+
|
|
4
|
+
Called by plugin/hooks/hooks.json with subcommands:
|
|
5
|
+
session-start - Load project context on session start
|
|
6
|
+
observation - Auto-collect observation from tool usage
|
|
7
|
+
session-stop - Compact session, update stats on stop
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python hook-runner.py session-start
|
|
11
|
+
python hook-runner.py observation <tool_name> <session_id>
|
|
12
|
+
python hook-runner.py session-stop
|
|
13
|
+
|
|
14
|
+
Exit codes (Claude Code hook contract):
|
|
15
|
+
0 - Success (output may be injected as context)
|
|
16
|
+
1 - Non-blocking error (stderr shown, continues)
|
|
17
|
+
2 - Blocking error (stderr fed to Claude)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
import re
|
|
25
|
+
import sys
|
|
26
|
+
import time
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Optional
|
|
29
|
+
|
|
30
|
+
# Ensure memnex package is importable when run from plugin directory
|
|
31
|
+
_PLUGIN_DIR = Path(__file__).resolve().parent
|
|
32
|
+
_PROJECT_ROOT = _PLUGIN_DIR.parent.parent
|
|
33
|
+
if str(_PROJECT_ROOT) not in sys.path:
|
|
34
|
+
sys.path.insert(0, str(_PROJECT_ROOT))
|
|
35
|
+
|
|
36
|
+
_RATE_FILE = Path("/tmp/.memnex_last_obs")
|
|
37
|
+
_RATE_LIMIT_SECONDS = 30
|
|
38
|
+
_PRIVATE_TAG_RE = re.compile(r"<private>.*?</private>", re.DOTALL)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _strip_private_tags(text: str) -> str:
|
|
42
|
+
return _PRIVATE_TAG_RE.sub("", text)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _get_store_path() -> Optional[Path]:
|
|
46
|
+
project_root = os.environ.get("MEMNEX_PROJECT_ROOT", "")
|
|
47
|
+
if project_root:
|
|
48
|
+
p = Path(project_root) / ".memnex" / "memory.json"
|
|
49
|
+
if p.parent.exists():
|
|
50
|
+
return p
|
|
51
|
+
cwd = Path.cwd()
|
|
52
|
+
p = cwd / ".memnex" / "memory.json"
|
|
53
|
+
return p if p.parent.exists() else None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _init_service():
|
|
57
|
+
from memnex.config import load_config
|
|
58
|
+
from memnex.service import MemNexService
|
|
59
|
+
|
|
60
|
+
cfg = load_config()
|
|
61
|
+
return MemNexService(config=cfg)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def cmd_session_start() -> None:
|
|
65
|
+
"""Load project context and inject relevant memories."""
|
|
66
|
+
try:
|
|
67
|
+
service = _init_service()
|
|
68
|
+
result = service.query(text="", top_k=5)
|
|
69
|
+
if result.results:
|
|
70
|
+
lines = ["[MemNex Context] Top recent memories:"]
|
|
71
|
+
for r in result.results[:5]:
|
|
72
|
+
lines.append(f" - {r.name} (domain: {r.domain}, relevance: {r.relevance_score:.2f})")
|
|
73
|
+
output = "\n".join(lines)
|
|
74
|
+
print(output)
|
|
75
|
+
else:
|
|
76
|
+
print("[MemNex] No memories stored yet for this project.")
|
|
77
|
+
except Exception as e:
|
|
78
|
+
print(f"[MemNex] session-start error: {e}", file=sys.stderr)
|
|
79
|
+
sys.exit(0)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def cmd_observation(tool_name: str = "", session_id: str = "") -> None:
|
|
83
|
+
"""Auto-collect observation from tool usage."""
|
|
84
|
+
if not tool_name:
|
|
85
|
+
tool_name = os.environ.get("MEMNEX_TOOL_NAME", "unknown")
|
|
86
|
+
|
|
87
|
+
# Rate limit
|
|
88
|
+
if _RATE_FILE.exists():
|
|
89
|
+
try:
|
|
90
|
+
last = float(_RATE_FILE.read_text().strip())
|
|
91
|
+
if time.time() - last < _RATE_LIMIT_SECONDS:
|
|
92
|
+
sys.exit(0)
|
|
93
|
+
except (ValueError, OSError):
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
# Read tool input from stdin (Claude Code provides it)
|
|
97
|
+
tool_input = ""
|
|
98
|
+
try:
|
|
99
|
+
if not sys.stdin.isatty():
|
|
100
|
+
raw = sys.stdin.read()
|
|
101
|
+
data = json.loads(raw) if raw.strip() else {}
|
|
102
|
+
tool_input = json.dumps(data, ensure_ascii=False)[:500]
|
|
103
|
+
except (json.JSONDecodeError, OSError):
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
tool_input = _strip_private_tags(tool_input)
|
|
107
|
+
if not tool_input:
|
|
108
|
+
sys.exit(0)
|
|
109
|
+
|
|
110
|
+
obs_text = f"[{tool_name}] {tool_input}"
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
service = _init_service()
|
|
114
|
+
service.write_text(text=obs_text, source_type="observation")
|
|
115
|
+
except Exception:
|
|
116
|
+
pass # Non-blocking -- never fail the hook
|
|
117
|
+
|
|
118
|
+
# Update rate limit
|
|
119
|
+
try:
|
|
120
|
+
_RATE_FILE.write_text(str(time.time()))
|
|
121
|
+
except OSError:
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
sys.exit(0)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def cmd_session_stop() -> None:
|
|
128
|
+
"""Compact session observations and update stats."""
|
|
129
|
+
try:
|
|
130
|
+
service = _init_service()
|
|
131
|
+
health = service.health()
|
|
132
|
+
stats = service.stats()
|
|
133
|
+
|
|
134
|
+
summary = json.dumps({
|
|
135
|
+
"status": health.get("status", "unknown"),
|
|
136
|
+
"total_memories": stats.get("total_functions", 0),
|
|
137
|
+
"total_edges": stats.get("total_edges", 0),
|
|
138
|
+
}, ensure_ascii=False)
|
|
139
|
+
print(f"[MemNex] Session ended. {summary}")
|
|
140
|
+
except Exception as e:
|
|
141
|
+
print(f"[MemNex] session-stop error: {e}", file=sys.stderr)
|
|
142
|
+
sys.exit(0)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def main() -> None:
|
|
146
|
+
if len(sys.argv) < 2:
|
|
147
|
+
print("Usage: hook-runner.py <command> [args]", file=sys.stderr)
|
|
148
|
+
sys.exit(1)
|
|
149
|
+
|
|
150
|
+
command = sys.argv[1]
|
|
151
|
+
|
|
152
|
+
if command == "session-start":
|
|
153
|
+
cmd_session_start()
|
|
154
|
+
elif command == "observation":
|
|
155
|
+
tool_name = sys.argv[2] if len(sys.argv) > 2 else ""
|
|
156
|
+
session_id = sys.argv[3] if len(sys.argv) > 3 else ""
|
|
157
|
+
cmd_observation(tool_name, session_id)
|
|
158
|
+
elif command == "session-stop":
|
|
159
|
+
cmd_session_stop()
|
|
160
|
+
else:
|
|
161
|
+
print(f"Unknown command: {command}", file=sys.stderr)
|
|
162
|
+
sys.exit(1)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if __name__ == "__main__":
|
|
166
|
+
main()
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mem-explore
|
|
3
|
+
description: Explore MemNex knowledge graph. Use when user asks "what do we know about X?", "explore memories", "show related concepts", or wants to browse the knowledge base.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory Explore
|
|
7
|
+
|
|
8
|
+
Browse and explore the MemNex knowledge graph to understand related concepts and connections.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Use when users want to explore stored knowledge:
|
|
13
|
+
|
|
14
|
+
- "What do we know about X?"
|
|
15
|
+
- "Show me everything related to Y"
|
|
16
|
+
- "Explore the knowledge graph"
|
|
17
|
+
- "What memories are in the database?"
|
|
18
|
+
|
|
19
|
+
## Workflow
|
|
20
|
+
|
|
21
|
+
### Broad Exploration
|
|
22
|
+
|
|
23
|
+
Search with a general query to discover what's stored:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
memory_search(query="authentication", top_k=20)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Drill Down
|
|
30
|
+
|
|
31
|
+
Pick interesting results and fetch details:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
memory_get(memory_id="func_abc123")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Check Health and Stats
|
|
38
|
+
|
|
39
|
+
Use CLI to see overall state:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Service health
|
|
43
|
+
memnex health
|
|
44
|
+
|
|
45
|
+
# Statistics (total memories, types breakdown, graph edges)
|
|
46
|
+
memnex stats
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Review Pending Conflicts
|
|
50
|
+
|
|
51
|
+
Check if any memories need resolution:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
memory_pending_reviews(limit=20)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Resolve conflicts:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
memory_resolve(memory_id="func_abc123", field_role="action", action="accept")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Understanding Memory Structure
|
|
64
|
+
|
|
65
|
+
Each memory has metadata:
|
|
66
|
+
|
|
67
|
+
- **version**: Incremented on merge/update
|
|
68
|
+
- **confidence**: 0.0-1.0 quality score
|
|
69
|
+
- **access_count**: How often this memory has been retrieved
|
|
70
|
+
- **domain**: Category (security, testing, devops, etc.)
|
|
71
|
+
- **source_type**: Where it came from (wiki, file, url, text)
|
|
72
|
+
|
|
73
|
+
## Graph Relationships
|
|
74
|
+
|
|
75
|
+
MemNex auto-detects three edge types:
|
|
76
|
+
|
|
77
|
+
| Edge | Meaning |
|
|
78
|
+
|------|---------|
|
|
79
|
+
| REFERENCES | Memory A references Memory B |
|
|
80
|
+
| DEPENDS_ON | Memory A depends on Memory B |
|
|
81
|
+
| CONFLICTS_WITH | Memory A contradicts Memory B |
|
|
82
|
+
|
|
83
|
+
These are discovered during write operations via term mapping, reference linking, entity alignment, and domain classification.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mem-manage
|
|
3
|
+
description: Manage MemNex memory system. Use when user asks to "compact memories", "cleanup database", "memory stats", "run compaction", or perform maintenance operations.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory Manage
|
|
7
|
+
|
|
8
|
+
Perform maintenance and management operations on the MemNex knowledge base.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Use when users want to maintain or manage memories:
|
|
13
|
+
|
|
14
|
+
- "Compact the memory database"
|
|
15
|
+
- "Clean up old memories"
|
|
16
|
+
- "Show me memory stats"
|
|
17
|
+
- "Run compaction"
|
|
18
|
+
- "Check memory health"
|
|
19
|
+
|
|
20
|
+
## Operations
|
|
21
|
+
|
|
22
|
+
### Health Check
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
memory_health()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or via CLI:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
memnex health
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Statistics
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
memnex stats
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Shows total memories, breakdown by type, graph edges, storage size.
|
|
41
|
+
|
|
42
|
+
### Run Compaction
|
|
43
|
+
|
|
44
|
+
5-stage pipeline: Extract → Dedup → Summarize → Prune → Archive
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Compact project-level memories
|
|
48
|
+
memnex compact --scope project
|
|
49
|
+
|
|
50
|
+
# Compact all memories
|
|
51
|
+
memnex compact --scope global
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Compaction automatically:
|
|
55
|
+
- Deduplicates memories with similar names
|
|
56
|
+
- Summarizes verbose field values
|
|
57
|
+
- Prunes low-confidence entries
|
|
58
|
+
- Archives stale memories
|
|
59
|
+
|
|
60
|
+
### Submit Feedback
|
|
61
|
+
|
|
62
|
+
Improve memory quality over time:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
memory_feedback(memory_id="func_abc123", role="trigger", index=0, verdict="correct")
|
|
66
|
+
memory_feedback(memory_id="func_abc123", role="action", index=1, verdict="wrong", reason="Should be POST not GET")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Delete Memories
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
memory_delete(memory_id="func_abc123")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Or via CLI:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
memnex delete func_abc123
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Update Memory Fields
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
memory_update(memory_id="func_abc123", role="action", new_value="Use OAuth2 with PKCE flow")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Notes
|
|
88
|
+
|
|
89
|
+
- Compaction is safe: it creates backups before modifying
|
|
90
|
+
- Feedback weights affect future retrieval relevance
|
|
91
|
+
- Delete is permanent -- use with care
|
|
92
|
+
- Stats refresh after each operation
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mem-search
|
|
3
|
+
description: Search MemNex persistent memory. Use when user asks "did we already solve this?", "how did we do X?", "recall", "lookup", or needs work from previous sessions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory Search
|
|
7
|
+
|
|
8
|
+
Search MemNex knowledge graph across all sessions. Simple workflow: search → filter → fetch.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Use when users ask about PREVIOUS sessions or stored knowledge (not current conversation):
|
|
13
|
+
|
|
14
|
+
- "Did we already fix this?"
|
|
15
|
+
- "How did we solve X last time?"
|
|
16
|
+
- "What do we know about Y?"
|
|
17
|
+
- "Recall the steps for Z"
|
|
18
|
+
|
|
19
|
+
## 3-Layer Workflow (ALWAYS Follow)
|
|
20
|
+
|
|
21
|
+
**NEVER fetch full details without filtering first. 10x token savings.**
|
|
22
|
+
|
|
23
|
+
### Step 1: Search -- Get Index with IDs
|
|
24
|
+
|
|
25
|
+
Use the `memory_search` MCP tool:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
memory_search(query="authentication", top_k=20)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Returns:** Table with IDs, names, relevance scores, domains (~50-100 tokens/result)
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
| ID | Name | Relevance | Domain |
|
|
35
|
+
|----|------|-----------|--------|
|
|
36
|
+
| func_abc123 | JWT Auth Flow | 0.92 | security |
|
|
37
|
+
| func_def456 | Token Refresh | 0.85 | security |
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Parameters:**
|
|
41
|
+
|
|
42
|
+
- `query` (string) - Natural language search query
|
|
43
|
+
- `top_k` (number) - Max results, default 10
|
|
44
|
+
|
|
45
|
+
### Step 2: Filter -- Review Results
|
|
46
|
+
|
|
47
|
+
Review names and relevance scores from Step 1. Pick relevant IDs. Discard the rest.
|
|
48
|
+
|
|
49
|
+
### Step 3: Fetch -- Get Full Details ONLY for Filtered IDs
|
|
50
|
+
|
|
51
|
+
Use the `memory_get` MCP tool:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
memory_get(memory_id="func_abc123")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Returns:** Complete memory object with trigger, condition, action, benefit fields, plus metadata
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
**Find recent knowledge about a topic:**
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
memory_search(query="authentication", top_k=20)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Get details for specific memories:**
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
memory_get(memory_id="func_abc123")
|
|
71
|
+
memory_get(memory_id="func_def456")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Submit feedback on a memory:**
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
memory_feedback(memory_id="func_abc123", role="trigger", index=0, verdict="correct")
|
|
78
|
+
memory_feedback(memory_id="func_abc123", role="action", index=1, verdict="wrong")
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Why This Workflow?
|
|
82
|
+
|
|
83
|
+
- **Search index:** ~50-100 tokens per result
|
|
84
|
+
- **Full memory:** ~500-1000 tokens each
|
|
85
|
+
- **10x token savings** by filtering before fetching
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mem-write
|
|
3
|
+
description: Store knowledge into MemNex memory. Use when user says "remember this", "save this", "memorize", "store", or provides documents/URLs/content for future reference.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory Write
|
|
7
|
+
|
|
8
|
+
Store knowledge into MemNex for persistent cross-session retrieval.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Use when users want to save knowledge for later:
|
|
13
|
+
|
|
14
|
+
- "Remember this: ..."
|
|
15
|
+
- "Save this for later"
|
|
16
|
+
- "Store this document/URL"
|
|
17
|
+
- "Memorize these steps"
|
|
18
|
+
|
|
19
|
+
## Workflow
|
|
20
|
+
|
|
21
|
+
### Store Text Content
|
|
22
|
+
|
|
23
|
+
Use the `memory_add` MCP tool:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
memory_add(content="Steps to deploy: 1) Run tests 2) Build 3) Push to main", source_type="text")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Returns:** Extracted function IDs, graph edges created
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
{
|
|
33
|
+
"functions_extracted": 2,
|
|
34
|
+
"edges": 3,
|
|
35
|
+
"function_ids": ["func_abc123", "func_def456"]
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Store from File
|
|
40
|
+
|
|
41
|
+
Use the CLI:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
memnex write --file /path/to/document.md
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Store from URL
|
|
48
|
+
|
|
49
|
+
Use the CLI:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
memnex write --url https://example.com/docs
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Review What Was Stored
|
|
56
|
+
|
|
57
|
+
After writing, use `memory_get` to verify the extracted knowledge:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
memory_get(memory_id="func_abc123")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## What Gets Stored
|
|
64
|
+
|
|
65
|
+
MemNex extracts structured knowledge into 4 memory types:
|
|
66
|
+
|
|
67
|
+
| Type | Structure | Example |
|
|
68
|
+
|------|-----------|---------|
|
|
69
|
+
| Function | trigger → condition → action → benefit | "When deploying, if tests pass, run build, to ship faster" |
|
|
70
|
+
| Fact | subject → predicate → object | "Python uses GIL for thread safety" |
|
|
71
|
+
| Preference | aspect → preference | "User prefers pytest over unittest" |
|
|
72
|
+
| Observation | event → context | "Bug in auth module at line 42" |
|
|
73
|
+
|
|
74
|
+
## Notes
|
|
75
|
+
|
|
76
|
+
- Content is deduplicated automatically (same name → merge)
|
|
77
|
+
- Graph edges (REFERENCES, DEPENDS_ON, CONFLICTS_WITH) are auto-detected
|
|
78
|
+
- Private content wrapped in `<private>...</private>` is stripped before storage
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""MemNex Agent Adapters -- protocol-specific interfaces.
|
|
2
|
+
|
|
3
|
+
Provides adapters for different consumption patterns:
|
|
4
|
+
|
|
5
|
+
- CLI: command-line interface (``memnex`` command)
|
|
6
|
+
- HTTP: REST API via FastAPI (``create_app`` factory)
|
|
7
|
+
- MCP: Model Context Protocol server over stdio JSON-RPC
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from memnex.adapters.cli import main as cli_main
|
|
11
|
+
from memnex.adapters.http_api import create_app
|
|
12
|
+
from memnex.adapters.mcp_server import MCPServer
|
|
13
|
+
|
|
14
|
+
__all__ = ["cli_main", "create_app", "MCPServer"]
|