flux7-memory 0.5.0__py3-none-any.whl
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.
- flux7_memory-0.5.0.dist-info/METADATA +26 -0
- flux7_memory-0.5.0.dist-info/RECORD +5 -0
- flux7_memory-0.5.0.dist-info/WHEEL +4 -0
- mem7/__init__.py +4 -0
- mem7/client.py +226 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flux7-memory
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Python SDK for mem7 — governed memory substrate for AI agents
|
|
5
|
+
Project-URL: Homepage, https://github.com/KTCrisis/flux7-memory
|
|
6
|
+
Project-URL: Repository, https://github.com/KTCrisis/flux7-memory
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Requires-Dist: requests>=2.28
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# flux7-memory
|
|
13
|
+
|
|
14
|
+
Python client for [mem7](https://github.com/KTCrisis/flux7-memory) — governed memory substrate for AI agents.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install flux7-memory
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from mem7 import Mem7
|
|
22
|
+
|
|
23
|
+
m = Mem7("http://localhost:9070", token="my-token")
|
|
24
|
+
m.store("deploy.decision", "approved by ops lead", tags=["decision"], agent="supervisor")
|
|
25
|
+
results = m.search("deployment approval", limit=5)
|
|
26
|
+
```
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
mem7/__init__.py,sha256=0ALx-z5t9z7yIGqv6e-AFI2qjcxi03ldOOY31MeGshg,89
|
|
2
|
+
mem7/client.py,sha256=JEdoZ-F57wGg425T9g8yiz9RfcyvQiTE_EO3SKbf2zE,6753
|
|
3
|
+
flux7_memory-0.5.0.dist-info/METADATA,sha256=wG_ugoNnbjGvkIp3bIm9aS4-NtRE9zwad1fXsZ9oaQg,782
|
|
4
|
+
flux7_memory-0.5.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
5
|
+
flux7_memory-0.5.0.dist-info/RECORD,,
|
mem7/__init__.py
ADDED
mem7/client.py
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"""mem7 Python SDK — governed memory substrate for AI agents.
|
|
2
|
+
|
|
3
|
+
Usage::
|
|
4
|
+
|
|
5
|
+
from mem7 import Mem7
|
|
6
|
+
|
|
7
|
+
m = Mem7("http://localhost:9070", token="my-token")
|
|
8
|
+
m.store("user.prefs", "prefers dark mode", tags=["user"])
|
|
9
|
+
results = m.search("dark mode", limit=5)
|
|
10
|
+
memories = m.context("dark mode", limit=5) # structured JSON
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
import requests
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class Memory:
|
|
23
|
+
key: str
|
|
24
|
+
value: str
|
|
25
|
+
tags: list[str] = field(default_factory=list)
|
|
26
|
+
agent: str = ""
|
|
27
|
+
updated: str = ""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Mem7Error(Exception):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Mem7:
|
|
35
|
+
def __init__(self, url: str, token: str = "", timeout: int = 30) -> None:
|
|
36
|
+
self._url = url.rstrip("/")
|
|
37
|
+
self._token = token
|
|
38
|
+
self._timeout = timeout
|
|
39
|
+
self._session = requests.Session()
|
|
40
|
+
if token:
|
|
41
|
+
self._session.headers["Authorization"] = f"Bearer {token}"
|
|
42
|
+
self._session.headers["Content-Type"] = "application/json"
|
|
43
|
+
self._req_id = 0
|
|
44
|
+
|
|
45
|
+
def _call(self, tool: str, arguments: dict[str, Any]) -> Any:
|
|
46
|
+
self._req_id += 1
|
|
47
|
+
payload = {
|
|
48
|
+
"jsonrpc": "2.0",
|
|
49
|
+
"id": self._req_id,
|
|
50
|
+
"method": "tools/call",
|
|
51
|
+
"params": {"name": tool, "arguments": arguments},
|
|
52
|
+
}
|
|
53
|
+
resp = self._session.post(
|
|
54
|
+
f"{self._url}/rpc", json=payload, timeout=self._timeout
|
|
55
|
+
)
|
|
56
|
+
resp.raise_for_status()
|
|
57
|
+
data = resp.json()
|
|
58
|
+
if "error" in data and data["error"]:
|
|
59
|
+
raise Mem7Error(data["error"].get("message", str(data["error"])))
|
|
60
|
+
result = data.get("result", {})
|
|
61
|
+
if result.get("isError"):
|
|
62
|
+
text = result.get("content", [{}])[0].get("text", "unknown error")
|
|
63
|
+
raise Mem7Error(text)
|
|
64
|
+
content = result.get("content", [])
|
|
65
|
+
if content:
|
|
66
|
+
return content[0].get("text", "")
|
|
67
|
+
return ""
|
|
68
|
+
|
|
69
|
+
# ── Core tools ───────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
def store(
|
|
72
|
+
self,
|
|
73
|
+
key: str,
|
|
74
|
+
value: str,
|
|
75
|
+
*,
|
|
76
|
+
tags: list[str] | None = None,
|
|
77
|
+
agent: str = "",
|
|
78
|
+
ttl: int = 0,
|
|
79
|
+
) -> str:
|
|
80
|
+
args: dict[str, Any] = {"key": key, "value": value}
|
|
81
|
+
if tags:
|
|
82
|
+
args["tags"] = tags
|
|
83
|
+
if agent:
|
|
84
|
+
args["agent"] = agent
|
|
85
|
+
if ttl > 0:
|
|
86
|
+
args["ttl"] = ttl
|
|
87
|
+
return self._call("memory_store", args)
|
|
88
|
+
|
|
89
|
+
def recall(
|
|
90
|
+
self,
|
|
91
|
+
*,
|
|
92
|
+
key: str = "",
|
|
93
|
+
tags: list[str] | None = None,
|
|
94
|
+
agent: str = "",
|
|
95
|
+
limit: int = 10,
|
|
96
|
+
) -> str:
|
|
97
|
+
args: dict[str, Any] = {"limit": limit}
|
|
98
|
+
if key:
|
|
99
|
+
args["key"] = key
|
|
100
|
+
if tags:
|
|
101
|
+
args["tags"] = tags
|
|
102
|
+
if agent:
|
|
103
|
+
args["agent"] = agent
|
|
104
|
+
return self._call("memory_recall", args)
|
|
105
|
+
|
|
106
|
+
def search(
|
|
107
|
+
self,
|
|
108
|
+
query: str,
|
|
109
|
+
*,
|
|
110
|
+
mode: str = "natural",
|
|
111
|
+
tags: list[str] | None = None,
|
|
112
|
+
agent: str = "",
|
|
113
|
+
limit: int = 10,
|
|
114
|
+
include_neighbors: bool = False,
|
|
115
|
+
neighbor_radius: int = 1,
|
|
116
|
+
since: str = "",
|
|
117
|
+
until: str = "",
|
|
118
|
+
) -> str:
|
|
119
|
+
args: dict[str, Any] = {"query": query, "mode": mode, "limit": limit}
|
|
120
|
+
if tags:
|
|
121
|
+
args["tags"] = tags
|
|
122
|
+
if agent:
|
|
123
|
+
args["agent"] = agent
|
|
124
|
+
if include_neighbors:
|
|
125
|
+
args["include_neighbors"] = True
|
|
126
|
+
args["neighbor_radius"] = neighbor_radius
|
|
127
|
+
if since:
|
|
128
|
+
args["since"] = since
|
|
129
|
+
if until:
|
|
130
|
+
args["until"] = until
|
|
131
|
+
return self._call("memory_search", args)
|
|
132
|
+
|
|
133
|
+
def context(
|
|
134
|
+
self,
|
|
135
|
+
query: str,
|
|
136
|
+
*,
|
|
137
|
+
mode: str = "natural",
|
|
138
|
+
tags: list[str] | None = None,
|
|
139
|
+
agent: str = "",
|
|
140
|
+
limit: int = 10,
|
|
141
|
+
include_neighbors: bool = False,
|
|
142
|
+
neighbor_radius: int = 1,
|
|
143
|
+
since: str = "",
|
|
144
|
+
until: str = "",
|
|
145
|
+
) -> list[Memory]:
|
|
146
|
+
args: dict[str, Any] = {"query": query, "mode": mode, "limit": limit}
|
|
147
|
+
if tags:
|
|
148
|
+
args["tags"] = tags
|
|
149
|
+
if agent:
|
|
150
|
+
args["agent"] = agent
|
|
151
|
+
if include_neighbors:
|
|
152
|
+
args["include_neighbors"] = True
|
|
153
|
+
args["neighbor_radius"] = neighbor_radius
|
|
154
|
+
if since:
|
|
155
|
+
args["since"] = since
|
|
156
|
+
if until:
|
|
157
|
+
args["until"] = until
|
|
158
|
+
raw = self._call("memory_context", args)
|
|
159
|
+
items = json.loads(raw) if raw else []
|
|
160
|
+
return [
|
|
161
|
+
Memory(
|
|
162
|
+
key=it.get("key", ""),
|
|
163
|
+
value=it.get("value", ""),
|
|
164
|
+
tags=it.get("tags") or [],
|
|
165
|
+
agent=it.get("agent", ""),
|
|
166
|
+
updated=it.get("updated", ""),
|
|
167
|
+
)
|
|
168
|
+
for it in items
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
def get(self, path: str, *, from_line: int = 0, to_line: int = 0) -> str:
|
|
172
|
+
args: dict[str, Any] = {"path": path}
|
|
173
|
+
if from_line > 0:
|
|
174
|
+
args["from_line"] = from_line
|
|
175
|
+
if to_line > 0:
|
|
176
|
+
args["to_line"] = to_line
|
|
177
|
+
return self._call("memory_get", args)
|
|
178
|
+
|
|
179
|
+
def list(
|
|
180
|
+
self, *, tags: list[str] | None = None, agent: str = ""
|
|
181
|
+
) -> str:
|
|
182
|
+
args: dict[str, Any] = {}
|
|
183
|
+
if tags:
|
|
184
|
+
args["tags"] = tags
|
|
185
|
+
if agent:
|
|
186
|
+
args["agent"] = agent
|
|
187
|
+
return self._call("memory_list", args)
|
|
188
|
+
|
|
189
|
+
def forget(self, *, key: str = "", tags: list[str] | None = None) -> str:
|
|
190
|
+
args: dict[str, Any] = {}
|
|
191
|
+
if key:
|
|
192
|
+
args["key"] = key
|
|
193
|
+
if tags:
|
|
194
|
+
args["tags"] = tags
|
|
195
|
+
return self._call("memory_forget", args)
|
|
196
|
+
|
|
197
|
+
# ── Convenience ──────────────────────────────────────────────
|
|
198
|
+
|
|
199
|
+
def health(self) -> bool:
|
|
200
|
+
try:
|
|
201
|
+
resp = self._session.get(
|
|
202
|
+
f"{self._url}/healthz", timeout=self._timeout
|
|
203
|
+
)
|
|
204
|
+
return resp.status_code == 200
|
|
205
|
+
except requests.RequestException:
|
|
206
|
+
return False
|
|
207
|
+
|
|
208
|
+
def context_block(
|
|
209
|
+
self,
|
|
210
|
+
query: str,
|
|
211
|
+
*,
|
|
212
|
+
limit: int = 10,
|
|
213
|
+
**kwargs: Any,
|
|
214
|
+
) -> str:
|
|
215
|
+
"""Search and return a formatted text block ready for LLM prompt injection."""
|
|
216
|
+
memories = self.context(query, limit=limit, **kwargs)
|
|
217
|
+
if not memories:
|
|
218
|
+
return ""
|
|
219
|
+
parts = []
|
|
220
|
+
for m in memories:
|
|
221
|
+
header = f"[{m.key}]" if m.key else ""
|
|
222
|
+
if header:
|
|
223
|
+
parts.append(f"{header}\n{m.value}")
|
|
224
|
+
else:
|
|
225
|
+
parts.append(m.value)
|
|
226
|
+
return "\n\n".join(parts)
|