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.
@@ -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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
mem7/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from mem7.client import Mem7, Memory
2
+
3
+ __all__ = ["Mem7", "Memory"]
4
+ __version__ = "0.5.0"
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)