muninn-python 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.
@@ -0,0 +1,17 @@
1
+ # Binaries (root-level only, not cmd/muninndb/ directory)
2
+ /muninndb
3
+ /muninndb-server
4
+
5
+ # Data directories
6
+ muninndb-data/
7
+ /tmp/
8
+
9
+ # macOS
10
+ .DS_Store
11
+
12
+ # Go test cache
13
+ *.test
14
+ *.out
15
+
16
+ # Worktrees
17
+ .worktrees/
@@ -0,0 +1,373 @@
1
+ Metadata-Version: 2.4
2
+ Name: muninn-python
3
+ Version: 0.1.0
4
+ Summary: Python SDK for MuninnDB — the cognitive memory database
5
+ Project-URL: Homepage, https://muninndb.com
6
+ Project-URL: Repository, https://github.com/scrypster/muninndb
7
+ Project-URL: Documentation, https://github.com/scrypster/muninndb/blob/main/sdk/python/README.md
8
+ Project-URL: Bug Tracker, https://github.com/scrypster/muninndb/issues
9
+ Author-email: MuninnDB <hello@muninndb.com>
10
+ License: Apache-2.0
11
+ Keywords: agent-memory,ai,cognitive,database,embeddings,langchain,llm,memory,semantic-search,vector-database
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Database
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: python-dotenv>=1.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: langchain-anthropic>=0.3; extra == 'dev'
27
+ Requires-Dist: langchain-core>=0.3; extra == 'dev'
28
+ Requires-Dist: langchain>=0.3; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
30
+ Requires-Dist: pytest>=8.0; extra == 'dev'
31
+ Provides-Extra: langchain
32
+ Requires-Dist: langchain-core>=0.3; extra == 'langchain'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # MuninnDB Python SDK
36
+
37
+ An async-first Python client for **MuninnDB**, a cognitive memory database with semantic search, graph traversal, and real-time subscriptions.
38
+
39
+ ## Features
40
+
41
+ - **Async/await throughout** — Built on `httpx` for concurrent, non-blocking operations
42
+ - **Semantic memory activation** — Query memories by meaning, not keywords
43
+ - **Graph associations** — Link engrams and traverse relationships
44
+ - **Real-time subscriptions** — Server-Sent Events (SSE) with auto-reconnect
45
+ - **Automatic retry logic** — Exponential backoff with jitter for transient failures
46
+ - **Type-safe** — Full type hints for IDE support and runtime validation
47
+ - **Connection pooling** — Configurable keepalive and concurrent connections
48
+
49
+ ## Installation
50
+
51
+ ### Requirements
52
+ - Python 3.11+
53
+
54
+ ### Setup
55
+
56
+ ```bash
57
+ pip install -r requirements.txt
58
+ ```
59
+
60
+ ## Quick Start
61
+
62
+ ```python
63
+ import asyncio
64
+ from muninn import MuninnClient
65
+
66
+ async def main():
67
+ async with MuninnClient("http://localhost:8476") as client:
68
+ # Write a memory
69
+ engram_id = await client.write(
70
+ vault="default",
71
+ concept="neural plasticity",
72
+ content="The brain's ability to reorganize neural connections.",
73
+ tags=["neuroscience", "learning"]
74
+ )
75
+ print(f"Created: {engram_id}")
76
+
77
+ # Activate memory (semantic search)
78
+ results = await client.activate(
79
+ vault="default",
80
+ context=["how does learning work?"],
81
+ max_results=10
82
+ )
83
+
84
+ for item in results.activations:
85
+ print(f"[{item.score:.2f}] {item.concept}")
86
+
87
+ asyncio.run(main())
88
+ ```
89
+
90
+ ## API Reference
91
+
92
+ ### Core Methods
93
+
94
+ #### `write(vault, concept, content, tags=None, confidence=0.9, stability=0.5) → str`
95
+
96
+ Write an engram (memory) to the database.
97
+
98
+ ```python
99
+ engram_id = await client.write(
100
+ vault="default",
101
+ concept="example",
102
+ content="Long-form content",
103
+ tags=["tag1", "tag2"],
104
+ confidence=0.95,
105
+ stability=0.8
106
+ )
107
+ ```
108
+
109
+ **Returns:** ULID string ID of created engram
110
+
111
+ ---
112
+
113
+ #### `activate(vault, context, max_results=10, threshold=0.1, brief_mode="auto") → ActivateResponse`
114
+
115
+ Activate memory using semantic search and optional graph traversal.
116
+
117
+ ```python
118
+ result = await client.activate(
119
+ vault="default",
120
+ context=["query", "terms"],
121
+ max_results=10,
122
+ threshold=0.1,
123
+ brief_mode="extractive" # "auto", "extractive", "abstractive"
124
+ )
125
+
126
+ for item in result.activations:
127
+ print(f"Score: {item.score}, Concept: {item.concept}")
128
+
129
+ for sentence in result.brief or []:
130
+ print(f"Brief: {sentence.text}")
131
+ ```
132
+
133
+ **Returns:** `ActivateResponse` with:
134
+ - `query_id` — Query identifier
135
+ - `total_found` — Total matching engrams
136
+ - `activations` — List of `ActivationItem` (id, concept, content, score, confidence, why, hop_path, dormant)
137
+ - `latency_ms` — Query latency
138
+ - `brief` — Optional extractive/abstractive summary
139
+
140
+ ---
141
+
142
+ #### `read(id, vault="default") → ReadResponse`
143
+
144
+ Read a specific engram by ID.
145
+
146
+ ```python
147
+ engram = await client.read("01JM2345...", vault="default")
148
+ print(engram.concept, engram.confidence)
149
+ ```
150
+
151
+ **Returns:** `ReadResponse` with full engram details
152
+
153
+ ---
154
+
155
+ #### `forget(id, vault="default", hard=False) → bool`
156
+
157
+ Delete an engram (soft or hard).
158
+
159
+ ```python
160
+ # Soft delete (recoverable)
161
+ await client.forget(engram_id, vault="default")
162
+
163
+ # Hard delete (permanent)
164
+ await client.forget(engram_id, vault="default", hard=True)
165
+ ```
166
+
167
+ **Returns:** `True` on success
168
+
169
+ ---
170
+
171
+ #### `link(source_id, target_id, vault="default", rel_type=5, weight=1.0) → bool`
172
+
173
+ Create an association between two engrams.
174
+
175
+ ```python
176
+ await client.link(
177
+ source_id="01JM...",
178
+ target_id="01JM...",
179
+ vault="default",
180
+ rel_type=5,
181
+ weight=0.9
182
+ )
183
+ ```
184
+
185
+ **Returns:** `True` on success
186
+
187
+ ---
188
+
189
+ #### `stats() → StatResponse`
190
+
191
+ Get database statistics and coherence metrics.
192
+
193
+ ```python
194
+ stats = await client.stats()
195
+ print(f"Engrams: {stats.engram_count}")
196
+ print(f"Storage: {stats.storage_bytes} bytes")
197
+
198
+ if stats.coherence:
199
+ for vault_name, coherence in stats.coherence.items():
200
+ print(f"Vault {vault_name} coherence: {coherence.score:.2f}")
201
+ ```
202
+
203
+ **Returns:** `StatResponse` with engram_count, vault_count, storage_bytes, and coherence dict
204
+
205
+ ---
206
+
207
+ #### `subscribe(vault="default", push_on_write=True, threshold=0.0) → SSEStream`
208
+
209
+ Subscribe to real-time vault events via Server-Sent Events.
210
+
211
+ ```python
212
+ stream = client.subscribe(vault="default", push_on_write=True)
213
+ async for push in stream:
214
+ print(f"New engram: {push.engram_id}")
215
+ if condition:
216
+ await stream.close()
217
+ ```
218
+
219
+ **Returns:** Async iterable yielding `Push` events with:
220
+ - `subscription_id` — Subscription ID
221
+ - `trigger` — Event type ("new_write", etc.)
222
+ - `push_number` — Push sequence number
223
+ - `engram_id` — ID of written engram
224
+ - `at` — Unix timestamp
225
+
226
+ ---
227
+
228
+ #### `health() → bool`
229
+
230
+ Check if MuninnDB server is reachable and healthy.
231
+
232
+ ```python
233
+ if await client.health():
234
+ print("Server OK")
235
+ ```
236
+
237
+ **Returns:** `True` if server responds with 200 OK
238
+
239
+ ---
240
+
241
+ ### Configuration
242
+
243
+ Create a client with custom settings:
244
+
245
+ ```python
246
+ client = MuninnClient(
247
+ base_url="http://localhost:8476", # Server address
248
+ token="your-bearer-token", # Optional auth token
249
+ timeout=5.0, # Request timeout (seconds)
250
+ max_retries=3, # Max retry attempts
251
+ retry_backoff=0.5, # Initial backoff multiplier
252
+ max_connections=20, # Max concurrent connections
253
+ keepalive_connections=10 # Max keepalive pool size
254
+ )
255
+ ```
256
+
257
+ ## Error Handling
258
+
259
+ The SDK raises semantic error types:
260
+
261
+ ```python
262
+ from muninn import (
263
+ MuninnError, # Base error
264
+ MuninnAuthError, # 401 Unauthorized
265
+ MuninnNotFound, # 404 Not Found
266
+ MuninnConflict, # 409 Conflict
267
+ MuninnServerError, # 5xx Server errors
268
+ MuninnConnectionError, # Network errors
269
+ MuninnTimeoutError # Request timeout
270
+ )
271
+
272
+ async with MuninnClient() as client:
273
+ try:
274
+ result = await client.activate(vault="default", context=["query"])
275
+ except MuninnAuthError:
276
+ print("Invalid token")
277
+ except MuninnNotFound:
278
+ print("Vault not found")
279
+ except MuninnConnectionError:
280
+ print("Network error - will retry automatically")
281
+ except MuninnError as e:
282
+ print(f"Error: {e.status_code} - {e}")
283
+ ```
284
+
285
+ ## Examples
286
+
287
+ ### Example 1: Write and Activate
288
+
289
+ ```bash
290
+ python examples/write_activate.py
291
+ ```
292
+
293
+ Writes multiple neuroscience engrams and activates them with a query.
294
+
295
+ ### Example 2: Real-Time Subscriptions
296
+
297
+ ```bash
298
+ python examples/subscribe.py
299
+ ```
300
+
301
+ Subscribes to a vault and writes an engram, demonstrating SSE push events.
302
+
303
+ ### Example 3: Cognitive Loop
304
+
305
+ ```bash
306
+ python examples/cognitive_loop.py
307
+ ```
308
+
309
+ Full workflow: write → activate → link → inspect coherence.
310
+
311
+ ## Retry Logic
312
+
313
+ The client automatically retries transient failures:
314
+
315
+ - **Retried errors:** 502, 503, 504, network errors, timeouts
316
+ - **Not retried:** 4xx client errors
317
+ - **Backoff:** Exponential with jitter: `retry_backoff * (2^attempt) + random(0, 0.1)`
318
+ - **Max attempts:** Configured via `max_retries` (default: 3)
319
+
320
+ Example with custom retry settings:
321
+
322
+ ```python
323
+ async with MuninnClient(
324
+ base_url="http://localhost:8476",
325
+ max_retries=5,
326
+ retry_backoff=1.0
327
+ ) as client:
328
+ # This will retry up to 5 times with longer delays
329
+ result = await client.activate(vault="default", context=["query"])
330
+ ```
331
+
332
+ ## Type System
333
+
334
+ Full type hints enable IDE autocomplete:
335
+
336
+ ```python
337
+ from muninn import (
338
+ MuninnClient,
339
+ ActivateResponse,
340
+ ActivationItem,
341
+ ReadResponse,
342
+ StatResponse,
343
+ Push
344
+ )
345
+
346
+ async with MuninnClient() as client:
347
+ result: ActivateResponse = await client.activate(vault="default", context=[])
348
+ for item: ActivationItem in result.activations:
349
+ print(item.score, item.concept)
350
+ ```
351
+
352
+ ## Performance Tips
353
+
354
+ 1. **Reuse client:** Create one `MuninnClient` and reuse it for multiple operations
355
+ 2. **Batch operations:** Use concurrent tasks for parallel writes/activations
356
+ 3. **Connection pooling:** Adjust `max_connections` and `keepalive_connections` based on workload
357
+ 4. **Timeout tuning:** Increase `timeout` for large activation queries
358
+
359
+ ```python
360
+ import asyncio
361
+
362
+ async with MuninnClient() as client:
363
+ # Parallel writes
364
+ tasks = [
365
+ client.write(vault="default", concept=f"item-{i}", content="...")
366
+ for i in range(100)
367
+ ]
368
+ ids = await asyncio.gather(*tasks)
369
+ ```
370
+
371
+ ## License
372
+
373
+ MIT