engramma-memory 0.1.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.
- engramma_memory/__init__.py +21 -0
- engramma_memory/async_core.py +418 -0
- engramma_memory/backends/__init__.py +4 -0
- engramma_memory/backends/async_cloud.py +403 -0
- engramma_memory/backends/cloud.py +931 -0
- engramma_memory/backends/local.py +89 -0
- engramma_memory/core.py +192 -0
- engramma_memory/engine.py +439 -0
- engramma_memory/integrations/__init__.py +10 -0
- engramma_memory/integrations/crewai.py +111 -0
- engramma_memory/integrations/fastapi.py +169 -0
- engramma_memory/integrations/langchain.py +122 -0
- engramma_memory/integrations/llamaindex.py +154 -0
- engramma_memory/integrations/openai_assistants.py +250 -0
- engramma_memory/py.typed +0 -0
- engramma_memory-0.1.0.dist-info/METADATA +379 -0
- engramma_memory-0.1.0.dist-info/RECORD +19 -0
- engramma_memory-0.1.0.dist-info/WHEEL +4 -0
- engramma_memory-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Engramma Memory - A composable memory engine for AI systems.
|
|
3
|
+
|
|
4
|
+
Quick start:
|
|
5
|
+
>>> from engramma_memory import EngrammaMemory
|
|
6
|
+
>>> mem = EngrammaMemory(dim=256, backend="local")
|
|
7
|
+
>>> mem.store(key=embedding, value=data)
|
|
8
|
+
>>> result = mem.query(embedding, top_k=3)
|
|
9
|
+
>>> blend = mem.compose([key_a, key_b])
|
|
10
|
+
|
|
11
|
+
Async:
|
|
12
|
+
>>> from engramma_memory import EngrammaMemoryAsync
|
|
13
|
+
>>> mem = EngrammaMemoryAsync(dim=256, backend="cloud", api_key="nx_live_...")
|
|
14
|
+
>>> await mem.store(key=embedding, value=data)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from .async_core import EngrammaMemoryAsync
|
|
18
|
+
from .core import EngrammaMemory
|
|
19
|
+
|
|
20
|
+
__version__ = "0.1.0"
|
|
21
|
+
__all__ = ["EngrammaMemory", "EngrammaMemoryAsync"]
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
"""
|
|
2
|
+
EngrammaMemory Async - Async-first interface for modern frameworks.
|
|
3
|
+
|
|
4
|
+
Full Phase 1-10 feature set with async/await.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from engramma_memory import EngrammaMemoryAsync
|
|
8
|
+
|
|
9
|
+
async def main():
|
|
10
|
+
mem = EngrammaMemoryAsync(dim=256, backend="cloud", api_key="nx_live_...")
|
|
11
|
+
await mem.store(key=embedding, value=data)
|
|
12
|
+
results = await mem.query(embedding, top_k=5)
|
|
13
|
+
|
|
14
|
+
# Cloud-exclusive premium features
|
|
15
|
+
explanation = await mem.explain(query)
|
|
16
|
+
regime = await mem.get_current_regime()
|
|
17
|
+
await mem.consolidate()
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from typing import Any, Dict, List, Optional, Union
|
|
21
|
+
|
|
22
|
+
import numpy as np
|
|
23
|
+
from numpy.typing import NDArray
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class EngrammaMemoryAsync:
|
|
27
|
+
"""
|
|
28
|
+
Async interface for Engramma Memory (cloud backend recommended).
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
dim : int
|
|
33
|
+
Dimension of key/value vectors.
|
|
34
|
+
backend : str
|
|
35
|
+
"cloud" (recommended for async) or "local" (runs sync, no premium features).
|
|
36
|
+
api_key : str, optional
|
|
37
|
+
Required for cloud backend.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
dim: int,
|
|
43
|
+
backend: str = "cloud",
|
|
44
|
+
api_key: Optional[str] = None,
|
|
45
|
+
max_patterns: int = 1000,
|
|
46
|
+
**kwargs,
|
|
47
|
+
):
|
|
48
|
+
self.dim = dim
|
|
49
|
+
self.backend_name = backend
|
|
50
|
+
self._is_local = backend == "local"
|
|
51
|
+
|
|
52
|
+
if backend == "cloud":
|
|
53
|
+
if not api_key:
|
|
54
|
+
raise ValueError(
|
|
55
|
+
"Cloud backend requires an API key.\n"
|
|
56
|
+
"Get your free key: https://www.engramma-memory.com/signup"
|
|
57
|
+
)
|
|
58
|
+
from .backends.async_cloud import AsyncCloudBackend
|
|
59
|
+
|
|
60
|
+
self._backend = AsyncCloudBackend(dim=dim, api_key=api_key, **kwargs)
|
|
61
|
+
elif backend == "local":
|
|
62
|
+
from .backends.local import LocalBackend
|
|
63
|
+
|
|
64
|
+
self._backend = LocalBackend(dim=dim, max_patterns=max_patterns, **kwargs)
|
|
65
|
+
else:
|
|
66
|
+
raise ValueError(f"Unknown backend '{backend}'. Use 'local' or 'cloud'.")
|
|
67
|
+
|
|
68
|
+
def _require_cloud(self, method_name: str):
|
|
69
|
+
if self._is_local:
|
|
70
|
+
raise RuntimeError(
|
|
71
|
+
f"{method_name}() is a cloud-only feature.\n"
|
|
72
|
+
f"Switch to cloud: EngrammaMemoryAsync(backend='cloud', api_key='nx_...')"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
76
|
+
# CORE OPERATIONS
|
|
77
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
78
|
+
|
|
79
|
+
async def store(
|
|
80
|
+
self,
|
|
81
|
+
key: Union[NDArray, List[float]],
|
|
82
|
+
value: Union[NDArray, List[float], Any],
|
|
83
|
+
metadata: Optional[Dict] = None,
|
|
84
|
+
) -> None:
|
|
85
|
+
key = np.asarray(key, dtype=np.float32)
|
|
86
|
+
if self._is_local:
|
|
87
|
+
self._backend.store(key, value)
|
|
88
|
+
else:
|
|
89
|
+
await self._backend.store(key, value, metadata=metadata)
|
|
90
|
+
|
|
91
|
+
async def query(
|
|
92
|
+
self,
|
|
93
|
+
query: Union[NDArray, List[float]],
|
|
94
|
+
top_k: int = 1,
|
|
95
|
+
filters: Optional[Dict] = None,
|
|
96
|
+
use_phi_b: bool = False,
|
|
97
|
+
) -> List[Dict[str, Any]]:
|
|
98
|
+
query = np.asarray(query, dtype=np.float32)
|
|
99
|
+
if self._is_local:
|
|
100
|
+
return self._backend.query(query, top_k=top_k)
|
|
101
|
+
return await self._backend.query(query, top_k=top_k, filters=filters, use_phi_b=use_phi_b)
|
|
102
|
+
|
|
103
|
+
async def retrieve(self, query: Union[NDArray, List[float]]) -> NDArray:
|
|
104
|
+
query = np.asarray(query, dtype=np.float32)
|
|
105
|
+
if self._is_local:
|
|
106
|
+
return self._backend.retrieve(query)
|
|
107
|
+
return await self._backend.retrieve(query)
|
|
108
|
+
|
|
109
|
+
async def compose(
|
|
110
|
+
self,
|
|
111
|
+
keys: List[Union[NDArray, List[float]]],
|
|
112
|
+
weights: Optional[List[float]] = None,
|
|
113
|
+
mode: str = "attention",
|
|
114
|
+
) -> NDArray:
|
|
115
|
+
keys_arr = [np.asarray(k, dtype=np.float32) for k in keys]
|
|
116
|
+
if self._is_local:
|
|
117
|
+
return self._backend.compose(keys_arr, weights)
|
|
118
|
+
return await self._backend.compose(keys_arr, weights, mode=mode)
|
|
119
|
+
|
|
120
|
+
async def forget(self, key: Union[NDArray, List[float]], strategy: str = "decay") -> None:
|
|
121
|
+
key = np.asarray(key, dtype=np.float32)
|
|
122
|
+
if self._is_local:
|
|
123
|
+
self._backend.forget(key, strategy)
|
|
124
|
+
else:
|
|
125
|
+
await self._backend.forget(key, strategy)
|
|
126
|
+
|
|
127
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
128
|
+
# PHASE 1 — NEUROMODULATION
|
|
129
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
130
|
+
|
|
131
|
+
async def get_modulation_state(self) -> Dict[str, Any]:
|
|
132
|
+
"""Get current neuromodulation state M(t). Cloud-only."""
|
|
133
|
+
self._require_cloud("get_modulation_state")
|
|
134
|
+
return await self._backend.get_modulation_state()
|
|
135
|
+
|
|
136
|
+
async def get_surprise_history(self, window: int = 100) -> Dict[str, Any]:
|
|
137
|
+
"""Return surprise trajectory. Cloud-only."""
|
|
138
|
+
self._require_cloud("get_surprise_history")
|
|
139
|
+
return await self._backend.get_surprise_history(window)
|
|
140
|
+
|
|
141
|
+
async def configure_neuromodulation(
|
|
142
|
+
self, baseline: float = 0.5, sensitivity: float = 2.0, tau: float = 10.0
|
|
143
|
+
) -> Dict[str, Any]:
|
|
144
|
+
"""Fine-tune plasticity gate. Cloud-only."""
|
|
145
|
+
self._require_cloud("configure_neuromodulation")
|
|
146
|
+
return await self._backend.configure_neuromodulation(baseline, sensitivity, tau)
|
|
147
|
+
|
|
148
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
149
|
+
# PHASE 2 — PHI_B ROUTING
|
|
150
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
151
|
+
|
|
152
|
+
async def get_router_trace(self, query: Union[NDArray, List[float]]) -> Dict[str, Any]:
|
|
153
|
+
"""Explain pathway selection for a query. Cloud-only."""
|
|
154
|
+
self._require_cloud("get_router_trace")
|
|
155
|
+
return await self._backend.get_router_trace(np.asarray(query, dtype=np.float32))
|
|
156
|
+
|
|
157
|
+
async def set_routing_geometry(self, geometry: str = "phi_b") -> Dict[str, Any]:
|
|
158
|
+
"""Switch routing geometry. Cloud-only."""
|
|
159
|
+
self._require_cloud("set_routing_geometry")
|
|
160
|
+
return await self._backend.set_routing_geometry(geometry)
|
|
161
|
+
|
|
162
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
163
|
+
# PHASE 3 — EFE STRATEGIC ROUTING
|
|
164
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
165
|
+
|
|
166
|
+
async def query_with_epistemic_weight(
|
|
167
|
+
self,
|
|
168
|
+
query: Union[NDArray, List[float]],
|
|
169
|
+
epistemic_w: float = 1.0,
|
|
170
|
+
pragmatic_w: float = 0.5,
|
|
171
|
+
top_k: int = 1,
|
|
172
|
+
) -> List[Dict[str, Any]]:
|
|
173
|
+
"""Query with exploration/exploitation tradeoff. Cloud-only."""
|
|
174
|
+
self._require_cloud("query_with_epistemic_weight")
|
|
175
|
+
return await self._backend.query_with_epistemic_weight(
|
|
176
|
+
np.asarray(query, dtype=np.float32), epistemic_w, pragmatic_w, top_k
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
async def get_efe_scores(self, query: Union[NDArray, List[float]]) -> Dict[str, Any]:
|
|
180
|
+
"""Get EFE scores per pathway. Cloud-only."""
|
|
181
|
+
self._require_cloud("get_efe_scores")
|
|
182
|
+
return await self._backend.get_efe_scores(np.asarray(query, dtype=np.float32))
|
|
183
|
+
|
|
184
|
+
async def set_pathway_strategy(self, strategy: str = "balanced") -> Dict[str, Any]:
|
|
185
|
+
"""Set exploit/explore/balanced. Cloud-only."""
|
|
186
|
+
self._require_cloud("set_pathway_strategy")
|
|
187
|
+
return await self._backend.set_pathway_strategy(strategy)
|
|
188
|
+
|
|
189
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
190
|
+
# PHASE 4 — STDP
|
|
191
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
192
|
+
|
|
193
|
+
async def get_head_specialization(self) -> Dict[str, Any]:
|
|
194
|
+
"""Which heads specialized for what. Cloud-only."""
|
|
195
|
+
self._require_cloud("get_head_specialization")
|
|
196
|
+
return await self._backend.get_head_specialization()
|
|
197
|
+
|
|
198
|
+
async def get_head_temperatures(self) -> Dict[str, Any]:
|
|
199
|
+
"""Inspect head temperatures. Cloud-only."""
|
|
200
|
+
self._require_cloud("get_head_temperatures")
|
|
201
|
+
return await self._backend.get_head_temperatures()
|
|
202
|
+
|
|
203
|
+
async def enable_stdp_learning(
|
|
204
|
+
self, enabled: bool = True, eta: float = 0.01, tau: float = 5.0
|
|
205
|
+
) -> Dict[str, Any]:
|
|
206
|
+
"""Configure STDP plasticity. Cloud-only."""
|
|
207
|
+
self._require_cloud("enable_stdp_learning")
|
|
208
|
+
return await self._backend.enable_stdp_learning(enabled, eta, tau)
|
|
209
|
+
|
|
210
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
211
|
+
# PHASE 6 — CAUSAL & ADVANCED COMPOSITION
|
|
212
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
213
|
+
|
|
214
|
+
async def compose_fractional(
|
|
215
|
+
self,
|
|
216
|
+
key_a: Union[NDArray, List[float]],
|
|
217
|
+
key_b: Union[NDArray, List[float]],
|
|
218
|
+
alpha: float = 0.5,
|
|
219
|
+
) -> NDArray:
|
|
220
|
+
"""Continuous interpolation between patterns. Cloud-only."""
|
|
221
|
+
self._require_cloud("compose_fractional")
|
|
222
|
+
return await self._backend.compose_fractional(
|
|
223
|
+
np.asarray(key_a, dtype=np.float32), np.asarray(key_b, dtype=np.float32), alpha
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
async def get_causal_graph(self) -> Dict[str, Any]:
|
|
227
|
+
"""Get discovered causal DAG. Cloud-only."""
|
|
228
|
+
self._require_cloud("get_causal_graph")
|
|
229
|
+
return await self._backend.get_causal_graph()
|
|
230
|
+
|
|
231
|
+
async def predict_causal_effect(
|
|
232
|
+
self, cause_key: Union[NDArray, List[float]], effect_key: Union[NDArray, List[float]]
|
|
233
|
+
) -> Dict[str, Any]:
|
|
234
|
+
"""Predict causal effect of perturbing a pattern. Cloud-only."""
|
|
235
|
+
self._require_cloud("predict_causal_effect")
|
|
236
|
+
return await self._backend.predict_causal_effect(
|
|
237
|
+
np.asarray(cause_key, dtype=np.float32),
|
|
238
|
+
np.asarray(effect_key, dtype=np.float32),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
async def is_confounded(
|
|
242
|
+
self,
|
|
243
|
+
key_a: Union[NDArray, List[float]],
|
|
244
|
+
key_b: Union[NDArray, List[float]],
|
|
245
|
+
threshold: float = 0.5,
|
|
246
|
+
) -> Dict[str, Any]:
|
|
247
|
+
"""Detect hidden confounders. Cloud-only."""
|
|
248
|
+
self._require_cloud("is_confounded")
|
|
249
|
+
return await self._backend.is_confounded(
|
|
250
|
+
np.asarray(key_a, dtype=np.float32), np.asarray(key_b, dtype=np.float32), threshold
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
async def enable_active_exploration(self, enabled: bool = True) -> Dict[str, Any]:
|
|
254
|
+
"""System autonomously probes uncertain relationships. Cloud-only."""
|
|
255
|
+
self._require_cloud("enable_active_exploration")
|
|
256
|
+
return await self._backend.enable_active_exploration(enabled)
|
|
257
|
+
|
|
258
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
259
|
+
# PHASE 7 — STRUCTURE DISCOVERY
|
|
260
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
261
|
+
|
|
262
|
+
async def get_skeleton_entropy(self) -> Dict[str, Any]:
|
|
263
|
+
"""Quantify structural uncertainty. Cloud-only."""
|
|
264
|
+
self._require_cloud("get_skeleton_entropy")
|
|
265
|
+
return await self._backend.get_skeleton_entropy()
|
|
266
|
+
|
|
267
|
+
async def get_uncertain_pairs(self, n_top: int = 10) -> Dict[str, Any]:
|
|
268
|
+
"""Which relationships need testing. Cloud-only."""
|
|
269
|
+
self._require_cloud("get_uncertain_pairs")
|
|
270
|
+
return await self._backend.get_uncertain_pairs(n_top)
|
|
271
|
+
|
|
272
|
+
async def auto_select_thresholds(self) -> Dict[str, Any]:
|
|
273
|
+
"""Auto-calibrate thresholds via StARS. Cloud-only."""
|
|
274
|
+
self._require_cloud("auto_select_thresholds")
|
|
275
|
+
return await self._backend.auto_select_thresholds()
|
|
276
|
+
|
|
277
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
278
|
+
# PHASE 8 — SAFETY & CONSOLIDATION
|
|
279
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
280
|
+
|
|
281
|
+
async def get_current_regime(self) -> Dict[str, Any]:
|
|
282
|
+
"""Get A/B/C regime status. Cloud-only."""
|
|
283
|
+
self._require_cloud("get_current_regime")
|
|
284
|
+
return await self._backend.get_current_regime()
|
|
285
|
+
|
|
286
|
+
async def enable_anomaly_protection(self, enabled: bool = True) -> Dict[str, Any]:
|
|
287
|
+
"""Activate safety circuit. Cloud-only."""
|
|
288
|
+
self._require_cloud("enable_anomaly_protection")
|
|
289
|
+
return await self._backend.enable_anomaly_protection(enabled)
|
|
290
|
+
|
|
291
|
+
async def consolidate(self) -> Dict[str, Any]:
|
|
292
|
+
"""Trigger Sleep/Wake consolidation. Cloud-only."""
|
|
293
|
+
self._require_cloud("consolidate")
|
|
294
|
+
return await self._backend.consolidate()
|
|
295
|
+
|
|
296
|
+
async def set_regime_thresholds(
|
|
297
|
+
self, theta_b: float = 1.0, theta_c: float = 2.0
|
|
298
|
+
) -> Dict[str, Any]:
|
|
299
|
+
"""Configure regime entry thresholds. Cloud-only."""
|
|
300
|
+
self._require_cloud("set_regime_thresholds")
|
|
301
|
+
return await self._backend.set_regime_thresholds(theta_b, theta_c)
|
|
302
|
+
|
|
303
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
304
|
+
# PHASE 9 — TEMPORAL CAUSALITY
|
|
305
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
306
|
+
|
|
307
|
+
async def test_granger_causality(
|
|
308
|
+
self,
|
|
309
|
+
key_a: Union[NDArray, List[float]],
|
|
310
|
+
key_b: Union[NDArray, List[float]],
|
|
311
|
+
max_lag: int = 10,
|
|
312
|
+
) -> Dict[str, Any]:
|
|
313
|
+
"""Test temporal Granger causality. Cloud-only."""
|
|
314
|
+
self._require_cloud("test_granger_causality")
|
|
315
|
+
return await self._backend.test_granger_causality(
|
|
316
|
+
np.asarray(key_a, dtype=np.float32), np.asarray(key_b, dtype=np.float32), max_lag
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
async def get_causal_predictions(
|
|
320
|
+
self, query: Union[NDArray, List[float]], n_predictions: int = 3
|
|
321
|
+
) -> Dict[str, Any]:
|
|
322
|
+
"""Predict next pattern accesses. Cloud-only."""
|
|
323
|
+
self._require_cloud("get_causal_predictions")
|
|
324
|
+
return await self._backend.get_causal_predictions(
|
|
325
|
+
np.asarray(query, dtype=np.float32), n_predictions
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
async def enable_prefetch(self, enabled: bool = True) -> Dict[str, Any]:
|
|
329
|
+
"""Enable predictive prefetching. Cloud-only."""
|
|
330
|
+
self._require_cloud("enable_prefetch")
|
|
331
|
+
return await self._backend.enable_prefetch(enabled)
|
|
332
|
+
|
|
333
|
+
async def get_prefetch_hit_rate(self) -> Dict[str, Any]:
|
|
334
|
+
"""Cache hit rate from predictions. Cloud-only."""
|
|
335
|
+
self._require_cloud("get_prefetch_hit_rate")
|
|
336
|
+
return await self._backend.get_prefetch_hit_rate()
|
|
337
|
+
|
|
338
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
339
|
+
# PHASE 10 — TEXT, TIERS, XAI
|
|
340
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
341
|
+
|
|
342
|
+
async def store_text(
|
|
343
|
+
self, text: str, value_embedding: Optional[NDArray] = None, metadata: Optional[Dict] = None
|
|
344
|
+
) -> None:
|
|
345
|
+
"""Store semantic text (HDC auto-encoding). Cloud-only."""
|
|
346
|
+
self._require_cloud("store_text")
|
|
347
|
+
await self._backend.store_text(text, value_embedding, metadata)
|
|
348
|
+
|
|
349
|
+
async def query_text(
|
|
350
|
+
self, query_text: str, top_k: int = 5, filters: Optional[Dict] = None
|
|
351
|
+
) -> List[Dict[str, Any]]:
|
|
352
|
+
"""Query by natural language. Cloud-only."""
|
|
353
|
+
self._require_cloud("query_text")
|
|
354
|
+
return await self._backend.query_text(query_text, top_k, filters)
|
|
355
|
+
|
|
356
|
+
async def compose_text(
|
|
357
|
+
self, texts: List[str], weights: Optional[List[float]] = None
|
|
358
|
+
) -> Dict[str, Any]:
|
|
359
|
+
"""Compose blends of text patterns. Cloud-only."""
|
|
360
|
+
self._require_cloud("compose_text")
|
|
361
|
+
return await self._backend.compose_text(texts, weights)
|
|
362
|
+
|
|
363
|
+
async def get_text_encoding(self, text: str) -> NDArray:
|
|
364
|
+
"""Get HDC encoding of text. Cloud-only."""
|
|
365
|
+
self._require_cloud("get_text_encoding")
|
|
366
|
+
return await self._backend.get_text_encoding(text)
|
|
367
|
+
|
|
368
|
+
async def move_to_tier(
|
|
369
|
+
self, key: Union[NDArray, List[float]], tier: str = "warm"
|
|
370
|
+
) -> Dict[str, Any]:
|
|
371
|
+
"""Move pattern between hot/warm/cold tiers. Cloud-only."""
|
|
372
|
+
self._require_cloud("move_to_tier")
|
|
373
|
+
return await self._backend.move_to_tier(np.asarray(key, dtype=np.float32), tier)
|
|
374
|
+
|
|
375
|
+
async def get_tier_stats(self) -> Dict[str, Any]:
|
|
376
|
+
"""Storage tier statistics. Cloud-only."""
|
|
377
|
+
self._require_cloud("get_tier_stats")
|
|
378
|
+
return await self._backend.get_tier_stats()
|
|
379
|
+
|
|
380
|
+
async def explain(self, query: Union[NDArray, List[float]]) -> Dict[str, Any]:
|
|
381
|
+
"""Full XAI explanation of retrieval. Cloud-only."""
|
|
382
|
+
self._require_cloud("explain")
|
|
383
|
+
return await self._backend.explain(np.asarray(query, dtype=np.float32))
|
|
384
|
+
|
|
385
|
+
async def get_xai_dashboard(self) -> Dict[str, Any]:
|
|
386
|
+
"""Full dashboard data for visualization. Cloud-only."""
|
|
387
|
+
self._require_cloud("get_xai_dashboard")
|
|
388
|
+
return await self._backend.get_xai_dashboard()
|
|
389
|
+
|
|
390
|
+
async def snapshot(self, name: Optional[str] = None) -> Dict[str, Any]:
|
|
391
|
+
"""Create persistent memory snapshot. Cloud-only."""
|
|
392
|
+
self._require_cloud("snapshot")
|
|
393
|
+
return await self._backend.snapshot(name)
|
|
394
|
+
|
|
395
|
+
async def restore(self, snapshot_id: str) -> Dict[str, Any]:
|
|
396
|
+
"""Restore from snapshot. Cloud-only."""
|
|
397
|
+
self._require_cloud("restore")
|
|
398
|
+
return await self._backend.restore(snapshot_id)
|
|
399
|
+
|
|
400
|
+
async def analytics(self, period: str = "24h") -> Dict[str, Any]:
|
|
401
|
+
"""Usage analytics. Cloud-only."""
|
|
402
|
+
self._require_cloud("analytics")
|
|
403
|
+
return await self._backend.analytics(period)
|
|
404
|
+
|
|
405
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
406
|
+
# LIFECYCLE
|
|
407
|
+
# ═══════════════════════════════════════════════════════════════════
|
|
408
|
+
|
|
409
|
+
async def close(self):
|
|
410
|
+
"""Close the async HTTP client."""
|
|
411
|
+
if not self._is_local and hasattr(self._backend, "close"):
|
|
412
|
+
await self._backend.close()
|
|
413
|
+
|
|
414
|
+
async def __aenter__(self):
|
|
415
|
+
return self
|
|
416
|
+
|
|
417
|
+
async def __aexit__(self, *args):
|
|
418
|
+
await self.close()
|