memgraph-sdk 0.1.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.
- memgraph_sdk-0.1.0/.gitignore +16 -0
- memgraph_sdk-0.1.0/LICENSE +21 -0
- memgraph_sdk-0.1.0/PKG-INFO +183 -0
- memgraph_sdk-0.1.0/README.md +119 -0
- memgraph_sdk-0.1.0/memgraph_sdk/__init__.py +12 -0
- memgraph_sdk-0.1.0/memgraph_sdk/async_client.py +163 -0
- memgraph_sdk-0.1.0/memgraph_sdk/cli.py +308 -0
- memgraph_sdk-0.1.0/memgraph_sdk/client.py +115 -0
- memgraph_sdk-0.1.0/memgraph_sdk/py.typed +0 -0
- memgraph_sdk-0.1.0/pyproject.toml +80 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Memgraph
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: memgraph-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for Memgraph - the memory graph for AI agents
|
|
5
|
+
Project-URL: Homepage, https://memgraph.ai
|
|
6
|
+
Project-URL: Documentation, https://memgraph.ai/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/memgraph-ai/memgraph-sdk
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/memgraph-ai/memgraph-sdk/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/memgraph-ai/memgraph-sdk/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Memgraph Team <sdk@memgraph.ai>
|
|
11
|
+
License: MIT License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2026 Memgraph
|
|
14
|
+
|
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
+
in the Software without restriction, including without limitation the rights
|
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
+
furnished to do so, subject to the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
|
23
|
+
copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Keywords: agents,ai,context,llm,memgraph,memory,rag
|
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
|
35
|
+
Classifier: Intended Audience :: Developers
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Operating System :: OS Independent
|
|
38
|
+
Classifier: Programming Language :: Python :: 3
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
45
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
46
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
47
|
+
Requires-Python: >=3.8
|
|
48
|
+
Requires-Dist: pydantic>=2.0.0
|
|
49
|
+
Requires-Dist: requests>=2.25.0
|
|
50
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
51
|
+
Provides-Extra: all
|
|
52
|
+
Requires-Dist: httpx>=0.24.0; extra == 'all'
|
|
53
|
+
Requires-Dist: rich>=13.0.0; extra == 'all'
|
|
54
|
+
Provides-Extra: async
|
|
55
|
+
Requires-Dist: httpx>=0.24.0; extra == 'async'
|
|
56
|
+
Provides-Extra: cli
|
|
57
|
+
Requires-Dist: rich>=13.0.0; extra == 'cli'
|
|
58
|
+
Provides-Extra: dev
|
|
59
|
+
Requires-Dist: httpx>=0.24.0; extra == 'dev'
|
|
60
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
61
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
62
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
63
|
+
Description-Content-Type: text/markdown
|
|
64
|
+
|
|
65
|
+
# Memgraph SDK
|
|
66
|
+
|
|
67
|
+
The official Python SDK for **[Memgraph](https://memgraph.ai)** -- the memory graph for AI agents.
|
|
68
|
+
|
|
69
|
+
[](https://pypi.org/project/memgraph-sdk/)
|
|
70
|
+
[](https://www.python.org/downloads/)
|
|
71
|
+
[](https://opensource.org/licenses/MIT)
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install memgraph-sdk
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
For async support:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install "memgraph-sdk[async]"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Quick Start
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from memgraph_sdk import MemgraphClient
|
|
89
|
+
|
|
90
|
+
client = MemgraphClient(
|
|
91
|
+
api_key="mg_your_api_key",
|
|
92
|
+
tenant_id="your-tenant-id",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Store a memory
|
|
96
|
+
client.add(
|
|
97
|
+
text="User prefers dark mode and uses PyTorch.",
|
|
98
|
+
user_id="user_123",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Search for relevant context
|
|
102
|
+
result = client.search(
|
|
103
|
+
query="What does this user prefer?",
|
|
104
|
+
user_id="user_123",
|
|
105
|
+
)
|
|
106
|
+
print(result)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Async Client
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from memgraph_sdk import AsyncMemgraphClient
|
|
113
|
+
|
|
114
|
+
async with AsyncMemgraphClient(
|
|
115
|
+
api_key="mg_your_api_key",
|
|
116
|
+
tenant_id="your-tenant-id",
|
|
117
|
+
) as client:
|
|
118
|
+
await client.add("User prefers dark mode", user_id="user_123")
|
|
119
|
+
result = await client.search("user preferences", user_id="user_123")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Memory Intelligence API
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
# Memory health metrics
|
|
126
|
+
health = client.health(user_id="user_123")
|
|
127
|
+
|
|
128
|
+
# Detect contradictions
|
|
129
|
+
contradictions = client.contradictions(user_id="user_123")
|
|
130
|
+
|
|
131
|
+
# Evaluate retrieval quality
|
|
132
|
+
evaluation = client.evaluate(query="test query", user_id="user_123")
|
|
133
|
+
|
|
134
|
+
# Cognitive Integrity Score (0-100)
|
|
135
|
+
score = client.mcis(user_id="user_123")
|
|
136
|
+
|
|
137
|
+
# Run benchmarks
|
|
138
|
+
result = client.benchmark(scenario="contradiction_storm")
|
|
139
|
+
scenarios = client.benchmark_scenarios()
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## CLI
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Initialize Memgraph in your project
|
|
146
|
+
memgraph init
|
|
147
|
+
|
|
148
|
+
# Store a memory
|
|
149
|
+
memgraph remember "We decided to use PostgreSQL" -c decision
|
|
150
|
+
|
|
151
|
+
# Search memories
|
|
152
|
+
memgraph recall "database choice"
|
|
153
|
+
|
|
154
|
+
# Check connection
|
|
155
|
+
memgraph status
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Configuration
|
|
159
|
+
|
|
160
|
+
The client reads the API URL from the `MEMGRAPH_API_URL` environment variable, defaulting to `http://localhost:8001/v1`. You can also pass it explicitly:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
client = MemgraphClient(
|
|
164
|
+
api_key="mg_your_key",
|
|
165
|
+
tenant_id="your-tenant-id",
|
|
166
|
+
base_url="https://api.memgraph.ai/v1",
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Examples
|
|
171
|
+
|
|
172
|
+
See the [examples/](examples/) directory for complete integration examples:
|
|
173
|
+
|
|
174
|
+
- [Quick Start](examples/quick_start.py) -- Basic add and search
|
|
175
|
+
- [Agent Integration](examples/agent_integration.py) -- OpenAI-powered agent with memory
|
|
176
|
+
- [MCP Server](examples/integrations/mcp_server.py) -- Model Context Protocol server for Claude/Cursor
|
|
177
|
+
- [LangChain](examples/integrations/langchain_integration.py) -- LangChain integration
|
|
178
|
+
- [OpenAI](examples/integrations/openai_integration.py) -- OpenAI integration
|
|
179
|
+
- [Benchmarks](examples/integrations/benchmark.py) -- Performance benchmarking
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Memgraph SDK
|
|
2
|
+
|
|
3
|
+
The official Python SDK for **[Memgraph](https://memgraph.ai)** -- the memory graph for AI agents.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/memgraph-sdk/)
|
|
6
|
+
[](https://www.python.org/downloads/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install memgraph-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
For async support:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install "memgraph-sdk[async]"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from memgraph_sdk import MemgraphClient
|
|
25
|
+
|
|
26
|
+
client = MemgraphClient(
|
|
27
|
+
api_key="mg_your_api_key",
|
|
28
|
+
tenant_id="your-tenant-id",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Store a memory
|
|
32
|
+
client.add(
|
|
33
|
+
text="User prefers dark mode and uses PyTorch.",
|
|
34
|
+
user_id="user_123",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Search for relevant context
|
|
38
|
+
result = client.search(
|
|
39
|
+
query="What does this user prefer?",
|
|
40
|
+
user_id="user_123",
|
|
41
|
+
)
|
|
42
|
+
print(result)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Async Client
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from memgraph_sdk import AsyncMemgraphClient
|
|
49
|
+
|
|
50
|
+
async with AsyncMemgraphClient(
|
|
51
|
+
api_key="mg_your_api_key",
|
|
52
|
+
tenant_id="your-tenant-id",
|
|
53
|
+
) as client:
|
|
54
|
+
await client.add("User prefers dark mode", user_id="user_123")
|
|
55
|
+
result = await client.search("user preferences", user_id="user_123")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Memory Intelligence API
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# Memory health metrics
|
|
62
|
+
health = client.health(user_id="user_123")
|
|
63
|
+
|
|
64
|
+
# Detect contradictions
|
|
65
|
+
contradictions = client.contradictions(user_id="user_123")
|
|
66
|
+
|
|
67
|
+
# Evaluate retrieval quality
|
|
68
|
+
evaluation = client.evaluate(query="test query", user_id="user_123")
|
|
69
|
+
|
|
70
|
+
# Cognitive Integrity Score (0-100)
|
|
71
|
+
score = client.mcis(user_id="user_123")
|
|
72
|
+
|
|
73
|
+
# Run benchmarks
|
|
74
|
+
result = client.benchmark(scenario="contradiction_storm")
|
|
75
|
+
scenarios = client.benchmark_scenarios()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## CLI
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Initialize Memgraph in your project
|
|
82
|
+
memgraph init
|
|
83
|
+
|
|
84
|
+
# Store a memory
|
|
85
|
+
memgraph remember "We decided to use PostgreSQL" -c decision
|
|
86
|
+
|
|
87
|
+
# Search memories
|
|
88
|
+
memgraph recall "database choice"
|
|
89
|
+
|
|
90
|
+
# Check connection
|
|
91
|
+
memgraph status
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Configuration
|
|
95
|
+
|
|
96
|
+
The client reads the API URL from the `MEMGRAPH_API_URL` environment variable, defaulting to `http://localhost:8001/v1`. You can also pass it explicitly:
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
client = MemgraphClient(
|
|
100
|
+
api_key="mg_your_key",
|
|
101
|
+
tenant_id="your-tenant-id",
|
|
102
|
+
base_url="https://api.memgraph.ai/v1",
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Examples
|
|
107
|
+
|
|
108
|
+
See the [examples/](examples/) directory for complete integration examples:
|
|
109
|
+
|
|
110
|
+
- [Quick Start](examples/quick_start.py) -- Basic add and search
|
|
111
|
+
- [Agent Integration](examples/agent_integration.py) -- OpenAI-powered agent with memory
|
|
112
|
+
- [MCP Server](examples/integrations/mcp_server.py) -- Model Context Protocol server for Claude/Cursor
|
|
113
|
+
- [LangChain](examples/integrations/langchain_integration.py) -- LangChain integration
|
|
114
|
+
- [OpenAI](examples/integrations/openai_integration.py) -- OpenAI integration
|
|
115
|
+
- [Benchmarks](examples/integrations/benchmark.py) -- Performance benchmarking
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Memgraph SDK - The official Python SDK for Memgraph, the memory graph for AI agents."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
|
|
5
|
+
from .client import MemgraphClient
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from .async_client import AsyncMemgraphClient
|
|
9
|
+
except ImportError:
|
|
10
|
+
AsyncMemgraphClient = None # httpx not installed
|
|
11
|
+
|
|
12
|
+
__all__ = ["MemgraphClient", "AsyncMemgraphClient", "__version__"]
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Async SDK client for Memgraph.
|
|
3
|
+
|
|
4
|
+
Uses httpx for non-blocking HTTP calls, suitable for async frameworks
|
|
5
|
+
(FastAPI, aiohttp, etc.) and high-throughput pipelines.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from memgraph_sdk import AsyncMemgraphClient
|
|
9
|
+
|
|
10
|
+
async with AsyncMemgraphClient(api_key="...", tenant_id="...") as client:
|
|
11
|
+
await client.add("User prefers dark mode", user_id="u1")
|
|
12
|
+
ctx = await client.search("What theme does the user prefer?", user_id="u1")
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
from typing import Dict, Any, Optional
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
import httpx
|
|
20
|
+
except ImportError:
|
|
21
|
+
raise ImportError(
|
|
22
|
+
"httpx is required for AsyncMemgraphClient. Install it with: pip install httpx"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AsyncMemgraphClient:
|
|
27
|
+
def __init__(self, api_key: str, tenant_id: str, base_url: str = None, timeout: float = 30.0):
|
|
28
|
+
self.api_key = api_key
|
|
29
|
+
self.tenant_id = tenant_id
|
|
30
|
+
self.base_url = base_url or os.getenv("MEMGRAPH_API_URL", "http://localhost:8001/v1")
|
|
31
|
+
self._client = httpx.AsyncClient(
|
|
32
|
+
base_url=self.base_url,
|
|
33
|
+
headers={"X-API-KEY": api_key},
|
|
34
|
+
timeout=timeout,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
async def __aenter__(self):
|
|
38
|
+
return self
|
|
39
|
+
|
|
40
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
41
|
+
await self.close()
|
|
42
|
+
|
|
43
|
+
async def close(self):
|
|
44
|
+
await self._client.aclose()
|
|
45
|
+
|
|
46
|
+
async def add(self, text: str, user_id: str, metadata: Optional[Dict] = None) -> Dict:
|
|
47
|
+
"""Add a memory via the /ingest endpoint."""
|
|
48
|
+
data = {
|
|
49
|
+
"tenant_id": self.tenant_id,
|
|
50
|
+
"user_id": user_id,
|
|
51
|
+
"text": text,
|
|
52
|
+
}
|
|
53
|
+
resp = await self._client.post("/ingest", data=data)
|
|
54
|
+
resp.raise_for_status()
|
|
55
|
+
return resp.json()
|
|
56
|
+
|
|
57
|
+
async def search(self, query: str, user_id: str, agent_id: str = "sdk_client") -> Dict[str, Any]:
|
|
58
|
+
"""Retrieve relevant context for a query via /context endpoint."""
|
|
59
|
+
payload = {
|
|
60
|
+
"task": query,
|
|
61
|
+
"user_id": user_id,
|
|
62
|
+
"tenant_id": self.tenant_id,
|
|
63
|
+
"agent_id": agent_id,
|
|
64
|
+
}
|
|
65
|
+
resp = await self._client.post("/context", json=payload)
|
|
66
|
+
resp.raise_for_status()
|
|
67
|
+
return resp.json()
|
|
68
|
+
|
|
69
|
+
async def get_context(self, query: str, user_id: str) -> Dict[str, Any]:
|
|
70
|
+
"""Alias for search()."""
|
|
71
|
+
return await self.search(query, user_id)
|
|
72
|
+
|
|
73
|
+
async def log_event(
|
|
74
|
+
self,
|
|
75
|
+
event_type: str,
|
|
76
|
+
content: Dict[str, Any],
|
|
77
|
+
user_id: str = "default_user",
|
|
78
|
+
agent_id: str = "sdk_client",
|
|
79
|
+
thread_id: Optional[str] = None,
|
|
80
|
+
) -> Dict:
|
|
81
|
+
"""Log a raw event to the /events endpoint."""
|
|
82
|
+
payload = {
|
|
83
|
+
"tenant_id": self.tenant_id,
|
|
84
|
+
"user_id": user_id,
|
|
85
|
+
"agent_id": agent_id,
|
|
86
|
+
"event_type": event_type,
|
|
87
|
+
"content": content,
|
|
88
|
+
}
|
|
89
|
+
if thread_id:
|
|
90
|
+
payload["thread_id"] = thread_id
|
|
91
|
+
|
|
92
|
+
resp = await self._client.post("/events", json=payload)
|
|
93
|
+
resp.raise_for_status()
|
|
94
|
+
return resp.json()
|
|
95
|
+
|
|
96
|
+
async def get_beliefs(self, user_id: str, limit: int = 50) -> list:
|
|
97
|
+
"""Fetch beliefs for a user via /beliefs endpoint."""
|
|
98
|
+
resp = await self._client.get(
|
|
99
|
+
"/beliefs",
|
|
100
|
+
params={"tenant_id": self.tenant_id, "subject_id": user_id, "limit": limit},
|
|
101
|
+
)
|
|
102
|
+
resp.raise_for_status()
|
|
103
|
+
return resp.json()
|
|
104
|
+
|
|
105
|
+
# ------------------------------------------------------------------
|
|
106
|
+
# Memory Intelligence API
|
|
107
|
+
# ------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
async def health(self, user_id: Optional[str] = None) -> Dict[str, Any]:
|
|
110
|
+
"""Get memory health metrics for the tenant (optionally scoped to a user)."""
|
|
111
|
+
params = {}
|
|
112
|
+
if user_id:
|
|
113
|
+
params["user_id"] = user_id
|
|
114
|
+
resp = await self._client.get("/intelligence/health", params=params)
|
|
115
|
+
resp.raise_for_status()
|
|
116
|
+
return resp.json()
|
|
117
|
+
|
|
118
|
+
async def contradictions(self, user_id: Optional[str] = None) -> Dict[str, Any]:
|
|
119
|
+
"""Get contradiction report — all detected contradictions with resolution history."""
|
|
120
|
+
params = {}
|
|
121
|
+
if user_id:
|
|
122
|
+
params["user_id"] = user_id
|
|
123
|
+
resp = await self._client.get("/intelligence/contradictions", params=params)
|
|
124
|
+
resp.raise_for_status()
|
|
125
|
+
return resp.json()
|
|
126
|
+
|
|
127
|
+
async def evaluate(self, query: str, user_id: str) -> Dict[str, Any]:
|
|
128
|
+
"""Run a retrieval query and get detailed scoring breakdown."""
|
|
129
|
+
payload = {"query": query, "user_id": user_id}
|
|
130
|
+
resp = await self._client.post("/intelligence/evaluate", json=payload)
|
|
131
|
+
resp.raise_for_status()
|
|
132
|
+
return resp.json()
|
|
133
|
+
|
|
134
|
+
async def mcis(self, user_id: Optional[str] = None, save: bool = False) -> Dict[str, Any]:
|
|
135
|
+
"""Compute the Memgraph Cognitive Integrity Score (0-100)."""
|
|
136
|
+
params = {"save": str(save).lower()}
|
|
137
|
+
if user_id:
|
|
138
|
+
params["user_id"] = user_id
|
|
139
|
+
resp = await self._client.get("/intelligence/mcis", params=params)
|
|
140
|
+
resp.raise_for_status()
|
|
141
|
+
return resp.json()
|
|
142
|
+
|
|
143
|
+
async def mcis_history(self, user_id: Optional[str] = None, limit: int = 30) -> Dict[str, Any]:
|
|
144
|
+
"""Get historical MCIS snapshots for trend visualization."""
|
|
145
|
+
params = {"limit": limit}
|
|
146
|
+
if user_id:
|
|
147
|
+
params["user_id"] = user_id
|
|
148
|
+
resp = await self._client.get("/intelligence/mcis/history", params=params)
|
|
149
|
+
resp.raise_for_status()
|
|
150
|
+
return resp.json()
|
|
151
|
+
|
|
152
|
+
async def benchmark(self, scenario: str) -> Dict[str, Any]:
|
|
153
|
+
"""Run a memory benchmark scenario (e.g. 'contradiction_storm', 'retrieval_accuracy')."""
|
|
154
|
+
payload = {"scenario": scenario}
|
|
155
|
+
resp = await self._client.post("/benchmark/run", json=payload)
|
|
156
|
+
resp.raise_for_status()
|
|
157
|
+
return resp.json()
|
|
158
|
+
|
|
159
|
+
async def benchmark_scenarios(self) -> list:
|
|
160
|
+
"""List available benchmark scenarios."""
|
|
161
|
+
resp = await self._client.get("/benchmark/scenarios")
|
|
162
|
+
resp.raise_for_status()
|
|
163
|
+
return resp.json().get("scenarios", [])
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Memgraph CLI - One-command setup for AI agent memory integration.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
memgraph init # Set up Memgraph in current project
|
|
7
|
+
memgraph remember # Store a memory
|
|
8
|
+
memgraph recall # Search memories
|
|
9
|
+
memgraph status # Check connection
|
|
10
|
+
"""
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
import shutil
|
|
14
|
+
import argparse
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
import requests
|
|
19
|
+
except ImportError:
|
|
20
|
+
requests = None
|
|
21
|
+
|
|
22
|
+
# --- Constants ---
|
|
23
|
+
CLOUD_URL = "https://api.memgraph.ai/v1"
|
|
24
|
+
LOCAL_URL = os.getenv("MEMGRAPH_API_URL", "http://localhost:8001/v1")
|
|
25
|
+
CONFIG_FILE = ".memgraph.env"
|
|
26
|
+
SKILL_DIR = ".agent/skills/memgraph"
|
|
27
|
+
|
|
28
|
+
# Template for skill file
|
|
29
|
+
SKILL_TEMPLATE = '''---
|
|
30
|
+
name: Memgraph Memory
|
|
31
|
+
description: Seamless long-term memory for AI agents via Memgraph. Auto-learn, inject context, and suggest based on project history.
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# Memgraph Memory Skill
|
|
35
|
+
|
|
36
|
+
This skill gives you persistent memory across sessions.
|
|
37
|
+
|
|
38
|
+
## MCP Tools Available
|
|
39
|
+
|
|
40
|
+
| Tool | Use For |
|
|
41
|
+
|------|---------|
|
|
42
|
+
| `memgraph_search` | Find past decisions, architecture, context |
|
|
43
|
+
| `memgraph_remember` | Store new facts and learnings |
|
|
44
|
+
|
|
45
|
+
## When to SEARCH
|
|
46
|
+
Call `memgraph_search` BEFORE answering questions about:
|
|
47
|
+
- Architecture or design patterns
|
|
48
|
+
- Previous decisions or bugs
|
|
49
|
+
- "How does X work?" / "Why did we choose Y?"
|
|
50
|
+
|
|
51
|
+
## When to REMEMBER
|
|
52
|
+
Call `memgraph_remember` AFTER:
|
|
53
|
+
- Completing a significant feature or fix
|
|
54
|
+
- User makes an architectural decision
|
|
55
|
+
- Resolving a tricky bug
|
|
56
|
+
|
|
57
|
+
Categories: `decision`, `architecture`, `bug_fix`, `preference`, `general`
|
|
58
|
+
'''
|
|
59
|
+
|
|
60
|
+
MCP_CONFIG_TEMPLATE = '''{
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"memgraph": {
|
|
63
|
+
"command": "python3",
|
|
64
|
+
"args": ["${MCP_SERVER_PATH}"],
|
|
65
|
+
"env": {
|
|
66
|
+
"MEMGRAPH_API_URL": "${API_URL}",
|
|
67
|
+
"MEMGRAPH_TENANT_ID": "${TENANT_ID}",
|
|
68
|
+
"MEMGRAPH_API_KEY": "${API_KEY}"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
'''
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_package_dir():
|
|
77
|
+
"""Get the memgraph-sdk package installation directory."""
|
|
78
|
+
return Path(__file__).parent.parent
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def init_project():
|
|
82
|
+
"""Initialize Memgraph in the current project."""
|
|
83
|
+
print("🚀 Memgraph Agent Memory Setup\n")
|
|
84
|
+
|
|
85
|
+
# 1. Choose deployment mode
|
|
86
|
+
print("Where is your Memgraph server running?")
|
|
87
|
+
print(" 1) Cloud (api.memgraph.ai)")
|
|
88
|
+
print(" 2) On-prem / Local (localhost:8001)")
|
|
89
|
+
print(" 3) Custom URL")
|
|
90
|
+
|
|
91
|
+
choice = input("\nChoose [1/2/3]: ").strip()
|
|
92
|
+
|
|
93
|
+
if choice == "1":
|
|
94
|
+
api_url = CLOUD_URL
|
|
95
|
+
elif choice == "2":
|
|
96
|
+
api_url = LOCAL_URL
|
|
97
|
+
elif choice == "3":
|
|
98
|
+
api_url = input("Enter API URL: ").strip()
|
|
99
|
+
else:
|
|
100
|
+
print("Invalid choice")
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
# 2. Get credentials
|
|
104
|
+
tenant_id = input("\nTenant ID: ").strip()
|
|
105
|
+
api_key = input("API Key (optional, press Enter to skip): ").strip()
|
|
106
|
+
|
|
107
|
+
# 3. Create .memgraph.env
|
|
108
|
+
config_path = Path(CONFIG_FILE)
|
|
109
|
+
with open(config_path, "w") as f:
|
|
110
|
+
f.write(f"MEMGRAPH_API_URL={api_url}\n")
|
|
111
|
+
f.write(f"MEMGRAPH_TENANT_ID={tenant_id}\n")
|
|
112
|
+
if api_key:
|
|
113
|
+
f.write(f"MEMGRAPH_API_KEY={api_key}\n")
|
|
114
|
+
print(f"\n✅ Created {CONFIG_FILE}")
|
|
115
|
+
|
|
116
|
+
# 4. Create skill directory
|
|
117
|
+
skill_path = Path(SKILL_DIR)
|
|
118
|
+
skill_path.mkdir(parents=True, exist_ok=True)
|
|
119
|
+
|
|
120
|
+
skill_file = skill_path / "SKILL.md"
|
|
121
|
+
with open(skill_file, "w") as f:
|
|
122
|
+
f.write(SKILL_TEMPLATE)
|
|
123
|
+
print(f"✅ Created {skill_file}")
|
|
124
|
+
|
|
125
|
+
# 5. Copy or reference MCP server
|
|
126
|
+
mcp_server_path = get_package_dir() / "examples" / "integrations" / "mcp_server.py"
|
|
127
|
+
if mcp_server_path.exists():
|
|
128
|
+
mcp_dest = skill_path / "mcp_server.py"
|
|
129
|
+
shutil.copy(mcp_server_path, mcp_dest)
|
|
130
|
+
print(f"✅ Copied MCP server to {mcp_dest}")
|
|
131
|
+
|
|
132
|
+
# 6. Create MCP config hints
|
|
133
|
+
print("\n📋 To enable MCP in your editor:")
|
|
134
|
+
print("\n For Cursor, add to .cursor/mcp.json:")
|
|
135
|
+
mcp_config = MCP_CONFIG_TEMPLATE.replace("${API_URL}", api_url)
|
|
136
|
+
mcp_config = mcp_config.replace("${TENANT_ID}", tenant_id)
|
|
137
|
+
mcp_config = mcp_config.replace("${API_KEY}", api_key or "")
|
|
138
|
+
mcp_config = mcp_config.replace("${MCP_SERVER_PATH}", str(skill_path / "mcp_server.py"))
|
|
139
|
+
print(mcp_config)
|
|
140
|
+
|
|
141
|
+
print("\n🎉 Memgraph agent memory is ready!")
|
|
142
|
+
print(" Your AI agent can now use memgraph_search and memgraph_remember tools.")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def remember_cmd(text: str, category: str = "general"):
|
|
146
|
+
"""Store a memory via CLI."""
|
|
147
|
+
if not requests:
|
|
148
|
+
print("Error: 'requests' package not installed. Run: pip install requests")
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
config = load_config()
|
|
152
|
+
if not config:
|
|
153
|
+
print("Error: Not initialized. Run 'memgraph init' first.")
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
resp = requests.post(
|
|
158
|
+
f"{config['api_url']}/ingest",
|
|
159
|
+
data={
|
|
160
|
+
"tenant_id": config["tenant_id"],
|
|
161
|
+
"user_id": "cli_user",
|
|
162
|
+
"text": f"[{category}] {text}",
|
|
163
|
+
},
|
|
164
|
+
headers={"X-API-KEY": config.get("api_key", "")},
|
|
165
|
+
timeout=10
|
|
166
|
+
)
|
|
167
|
+
if resp.status_code == 200:
|
|
168
|
+
print(f"✅ Remembered: {text[:80]}...")
|
|
169
|
+
else:
|
|
170
|
+
print(f"❌ Error: {resp.text}")
|
|
171
|
+
except requests.ConnectionError:
|
|
172
|
+
print("❌ Cannot connect to Memgraph server")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def recall_cmd(query: str):
|
|
176
|
+
"""Search memories via CLI."""
|
|
177
|
+
if not requests:
|
|
178
|
+
print("Error: 'requests' package not installed. Run: pip install requests")
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
config = load_config()
|
|
182
|
+
if not config:
|
|
183
|
+
print("Error: Not initialized. Run 'memgraph init' first.")
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
resp = requests.post(
|
|
188
|
+
f"{config['api_url']}/context",
|
|
189
|
+
json={
|
|
190
|
+
"tenant_id": config["tenant_id"],
|
|
191
|
+
"user_id": "cli_user",
|
|
192
|
+
"task": query,
|
|
193
|
+
"agent_id": "cli"
|
|
194
|
+
},
|
|
195
|
+
headers={"X-API-KEY": config.get("api_key", "")},
|
|
196
|
+
timeout=10
|
|
197
|
+
)
|
|
198
|
+
if resp.status_code == 200:
|
|
199
|
+
data = resp.json()
|
|
200
|
+
results = data.get("results", [])
|
|
201
|
+
if results:
|
|
202
|
+
print(f"\n🔍 Found {len(results)} results for '{query}':\n")
|
|
203
|
+
for r in results:
|
|
204
|
+
if isinstance(r, dict):
|
|
205
|
+
print(f" • {r.get('text', r)}")
|
|
206
|
+
else:
|
|
207
|
+
print(f" • {r}")
|
|
208
|
+
else:
|
|
209
|
+
print("No memories found for this query.")
|
|
210
|
+
else:
|
|
211
|
+
print(f"❌ Error: {resp.text}")
|
|
212
|
+
except requests.ConnectionError:
|
|
213
|
+
print("❌ Cannot connect to Memgraph server")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def status_cmd():
|
|
217
|
+
"""Check Memgraph connection status."""
|
|
218
|
+
config = load_config()
|
|
219
|
+
if not config:
|
|
220
|
+
print("❌ Not initialized. Run 'memgraph init' first.")
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
print(f"📡 API URL: {config['api_url']}")
|
|
224
|
+
print(f"🏢 Tenant: {config['tenant_id']}")
|
|
225
|
+
print(f"🔑 API Key: {'***' + config['api_key'][-4:] if config.get('api_key') else '(not set)'}")
|
|
226
|
+
|
|
227
|
+
if requests:
|
|
228
|
+
try:
|
|
229
|
+
resp = requests.get(f"{config['api_url']}/health", timeout=5)
|
|
230
|
+
if resp.status_code == 200:
|
|
231
|
+
print("\n✅ Server is reachable")
|
|
232
|
+
else:
|
|
233
|
+
print(f"\n⚠️ Server returned: {resp.status_code}")
|
|
234
|
+
except requests.ConnectionError:
|
|
235
|
+
print("\n❌ Cannot connect to server")
|
|
236
|
+
else:
|
|
237
|
+
print("\n⚠️ Cannot check connection (requests not installed)")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def load_config():
|
|
241
|
+
"""Load config from .memgraph.env file."""
|
|
242
|
+
config_path = Path(CONFIG_FILE)
|
|
243
|
+
if not config_path.exists():
|
|
244
|
+
return None
|
|
245
|
+
|
|
246
|
+
config = {}
|
|
247
|
+
with open(config_path) as f:
|
|
248
|
+
for line in f:
|
|
249
|
+
line = line.strip()
|
|
250
|
+
if "=" in line and not line.startswith("#"):
|
|
251
|
+
key, value = line.split("=", 1)
|
|
252
|
+
key = key.strip().lower().replace("memgraph_", "")
|
|
253
|
+
config[key] = value.strip()
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
"api_url": config.get("api_url", LOCAL_URL),
|
|
257
|
+
"tenant_id": config.get("tenant_id"),
|
|
258
|
+
"api_key": config.get("api_key")
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def main():
|
|
263
|
+
parser = argparse.ArgumentParser(
|
|
264
|
+
description="Memgraph - AI Agent Memory Graph",
|
|
265
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
266
|
+
epilog="""
|
|
267
|
+
Examples:
|
|
268
|
+
memgraph init # Set up Memgraph in current project
|
|
269
|
+
memgraph remember "Used JWT" # Store a memory
|
|
270
|
+
memgraph recall "authentication" # Search memories
|
|
271
|
+
memgraph status # Check connection
|
|
272
|
+
"""
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
276
|
+
|
|
277
|
+
# init
|
|
278
|
+
subparsers.add_parser("init", help="Initialize Memgraph in current project")
|
|
279
|
+
|
|
280
|
+
# remember
|
|
281
|
+
rem_parser = subparsers.add_parser("remember", help="Store a memory")
|
|
282
|
+
rem_parser.add_argument("text", help="Text to remember")
|
|
283
|
+
rem_parser.add_argument("-c", "--category", default="general",
|
|
284
|
+
choices=["decision", "architecture", "bug_fix", "preference", "general"])
|
|
285
|
+
|
|
286
|
+
# recall
|
|
287
|
+
rec_parser = subparsers.add_parser("recall", help="Search memories")
|
|
288
|
+
rec_parser.add_argument("query", help="Search query")
|
|
289
|
+
|
|
290
|
+
# status
|
|
291
|
+
subparsers.add_parser("status", help="Check connection status")
|
|
292
|
+
|
|
293
|
+
args = parser.parse_args()
|
|
294
|
+
|
|
295
|
+
if args.command == "init":
|
|
296
|
+
init_project()
|
|
297
|
+
elif args.command == "remember":
|
|
298
|
+
remember_cmd(args.text, args.category)
|
|
299
|
+
elif args.command == "recall":
|
|
300
|
+
recall_cmd(args.query)
|
|
301
|
+
elif args.command == "status":
|
|
302
|
+
status_cmd()
|
|
303
|
+
else:
|
|
304
|
+
parser.print_help()
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
if __name__ == "__main__":
|
|
308
|
+
main()
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import requests
|
|
3
|
+
from typing import List, Dict, Any, Optional
|
|
4
|
+
|
|
5
|
+
class MemgraphClient:
|
|
6
|
+
def __init__(self, api_key: str, tenant_id: str, base_url: str = None):
|
|
7
|
+
self.api_key = api_key
|
|
8
|
+
self.tenant_id = tenant_id
|
|
9
|
+
self.base_url = base_url or os.getenv("MEMGRAPH_API_URL", "http://localhost:8001/v1")
|
|
10
|
+
self.headers = {
|
|
11
|
+
"X-API-KEY": api_key,
|
|
12
|
+
# "Content-Type" is handled automatically by requests for Form data or JSON
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def add(self, text: str, user_id: str, metadata: Optional[Dict] = None) -> Dict:
|
|
16
|
+
"""
|
|
17
|
+
Add a memory via the /ingest endpoint.
|
|
18
|
+
Uses multipart/form-data as required by the backend.
|
|
19
|
+
"""
|
|
20
|
+
data = {
|
|
21
|
+
"tenant_id": self.tenant_id,
|
|
22
|
+
"user_id": user_id,
|
|
23
|
+
"text": text,
|
|
24
|
+
}
|
|
25
|
+
# If we had metadata/files, we would add them here.
|
|
26
|
+
# Verify if metadata is supported by ingest_omni (it currently isn't in the Form params shown in ingest.py,
|
|
27
|
+
# but the logic creates an event with content_payload which we might want to extend later).
|
|
28
|
+
|
|
29
|
+
resp = requests.post(f"{self.base_url}/ingest", data=data, headers=self.headers)
|
|
30
|
+
resp.raise_for_status()
|
|
31
|
+
return resp.json()
|
|
32
|
+
|
|
33
|
+
def search(self, query: str, user_id: str, agent_id: str = "sdk_client") -> Dict[str, Any]:
|
|
34
|
+
"""
|
|
35
|
+
Retrieve relevant context for a query via /context endpoint.
|
|
36
|
+
"""
|
|
37
|
+
payload = {
|
|
38
|
+
"task": query, # Server expects 'task', not 'query' based on E2E
|
|
39
|
+
"user_id": user_id,
|
|
40
|
+
"tenant_id": self.tenant_id,
|
|
41
|
+
"agent_id": agent_id
|
|
42
|
+
}
|
|
43
|
+
resp = requests.post(f"{self.base_url}/context", json=payload, headers=self.headers)
|
|
44
|
+
resp.raise_for_status()
|
|
45
|
+
return resp.json()
|
|
46
|
+
|
|
47
|
+
# Deprecated/Legacy methods mapped to new ones for compatibility
|
|
48
|
+
def log_event(self, event_type: str, content: Dict[str, Any], metadata: Optional[Dict] = None) -> Dict:
|
|
49
|
+
# Fallback to ingest if content has text
|
|
50
|
+
if "text" in content:
|
|
51
|
+
return self.add(content["text"], "legacy_user")
|
|
52
|
+
raise NotImplementedError("Generic log_event not fully supported yet.")
|
|
53
|
+
|
|
54
|
+
def get_context(self, query: str, user_id: str) -> Dict[str, Any]:
|
|
55
|
+
return self.search(query, user_id)
|
|
56
|
+
|
|
57
|
+
# ------------------------------------------------------------------
|
|
58
|
+
# Memory Intelligence API
|
|
59
|
+
# ------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
def health(self, user_id: Optional[str] = None) -> Dict[str, Any]:
|
|
62
|
+
"""Get memory health metrics for the tenant (optionally scoped to a user)."""
|
|
63
|
+
params = {}
|
|
64
|
+
if user_id:
|
|
65
|
+
params["user_id"] = user_id
|
|
66
|
+
resp = requests.get(f"{self.base_url}/intelligence/health", params=params, headers=self.headers)
|
|
67
|
+
resp.raise_for_status()
|
|
68
|
+
return resp.json()
|
|
69
|
+
|
|
70
|
+
def contradictions(self, user_id: Optional[str] = None) -> Dict[str, Any]:
|
|
71
|
+
"""Get contradiction report — all detected contradictions with resolution history."""
|
|
72
|
+
params = {}
|
|
73
|
+
if user_id:
|
|
74
|
+
params["user_id"] = user_id
|
|
75
|
+
resp = requests.get(f"{self.base_url}/intelligence/contradictions", params=params, headers=self.headers)
|
|
76
|
+
resp.raise_for_status()
|
|
77
|
+
return resp.json()
|
|
78
|
+
|
|
79
|
+
def evaluate(self, query: str, user_id: str) -> Dict[str, Any]:
|
|
80
|
+
"""Run a retrieval query and get detailed scoring breakdown."""
|
|
81
|
+
payload = {"query": query, "user_id": user_id}
|
|
82
|
+
resp = requests.post(f"{self.base_url}/intelligence/evaluate", json=payload, headers=self.headers)
|
|
83
|
+
resp.raise_for_status()
|
|
84
|
+
return resp.json()
|
|
85
|
+
|
|
86
|
+
def mcis(self, user_id: Optional[str] = None, save: bool = False) -> Dict[str, Any]:
|
|
87
|
+
"""Compute the Memgraph Cognitive Integrity Score (0-100)."""
|
|
88
|
+
params = {"save": str(save).lower()}
|
|
89
|
+
if user_id:
|
|
90
|
+
params["user_id"] = user_id
|
|
91
|
+
resp = requests.get(f"{self.base_url}/intelligence/mcis", params=params, headers=self.headers)
|
|
92
|
+
resp.raise_for_status()
|
|
93
|
+
return resp.json()
|
|
94
|
+
|
|
95
|
+
def mcis_history(self, user_id: Optional[str] = None, limit: int = 30) -> Dict[str, Any]:
|
|
96
|
+
"""Get historical MCIS snapshots for trend visualization."""
|
|
97
|
+
params = {"limit": limit}
|
|
98
|
+
if user_id:
|
|
99
|
+
params["user_id"] = user_id
|
|
100
|
+
resp = requests.get(f"{self.base_url}/intelligence/mcis/history", params=params, headers=self.headers)
|
|
101
|
+
resp.raise_for_status()
|
|
102
|
+
return resp.json()
|
|
103
|
+
|
|
104
|
+
def benchmark(self, scenario: str) -> Dict[str, Any]:
|
|
105
|
+
"""Run a memory benchmark scenario (e.g. 'contradiction_storm', 'retrieval_accuracy')."""
|
|
106
|
+
payload = {"scenario": scenario}
|
|
107
|
+
resp = requests.post(f"{self.base_url}/benchmark/run", json=payload, headers=self.headers)
|
|
108
|
+
resp.raise_for_status()
|
|
109
|
+
return resp.json()
|
|
110
|
+
|
|
111
|
+
def benchmark_scenarios(self) -> List[Dict]:
|
|
112
|
+
"""List available benchmark scenarios."""
|
|
113
|
+
resp = requests.get(f"{self.base_url}/benchmark/scenarios", headers=self.headers)
|
|
114
|
+
resp.raise_for_status()
|
|
115
|
+
return resp.json().get("scenarios", [])
|
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "memgraph-sdk"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Official Python SDK for Memgraph - the memory graph for AI agents"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Memgraph Team", email = "sdk@memgraph.ai" },
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.8",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
28
|
+
]
|
|
29
|
+
keywords = ["memgraph", "ai", "memory", "agents", "llm", "rag", "context"]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"requests>=2.25.0",
|
|
32
|
+
"pydantic>=2.0.0",
|
|
33
|
+
"typing-extensions>=4.0.0",
|
|
34
|
+
]
|
|
35
|
+
requires-python = ">=3.8"
|
|
36
|
+
|
|
37
|
+
[project.scripts]
|
|
38
|
+
memgraph = "memgraph_sdk.cli:main"
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
async = ["httpx>=0.24.0"]
|
|
42
|
+
cli = ["rich>=13.0.0"]
|
|
43
|
+
all = ["httpx>=0.24.0", "rich>=13.0.0"]
|
|
44
|
+
dev = [
|
|
45
|
+
"pytest>=7.0.0",
|
|
46
|
+
"pytest-asyncio>=0.21.0",
|
|
47
|
+
"httpx>=0.24.0",
|
|
48
|
+
"ruff>=0.1.0",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://memgraph.ai"
|
|
53
|
+
Documentation = "https://memgraph.ai/docs"
|
|
54
|
+
Repository = "https://github.com/memgraph-ai/memgraph-sdk"
|
|
55
|
+
"Bug Tracker" = "https://github.com/memgraph-ai/memgraph-sdk/issues"
|
|
56
|
+
Changelog = "https://github.com/memgraph-ai/memgraph-sdk/blob/main/CHANGELOG.md"
|
|
57
|
+
|
|
58
|
+
[tool.hatch.version]
|
|
59
|
+
path = "memgraph_sdk/__init__.py"
|
|
60
|
+
|
|
61
|
+
[tool.hatch.build.targets.sdist]
|
|
62
|
+
include = [
|
|
63
|
+
"memgraph_sdk/",
|
|
64
|
+
"LICENSE",
|
|
65
|
+
"README.md",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[tool.hatch.build.targets.wheel]
|
|
69
|
+
packages = ["memgraph_sdk"]
|
|
70
|
+
|
|
71
|
+
[tool.ruff]
|
|
72
|
+
line-length = 100
|
|
73
|
+
target-version = "py38"
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint]
|
|
76
|
+
select = ["E", "F", "W", "I"]
|
|
77
|
+
ignore = ["E501"]
|
|
78
|
+
|
|
79
|
+
[tool.pytest.ini_options]
|
|
80
|
+
testpaths = ["tests"]
|