synapse-memory-engine 1.3.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,112 @@
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ import sys
4
+ import os
5
+
6
+ # Align python sys path to resolve absolute imports correctly
7
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
8
+
9
+ from synapse_memory.core.decay_engine import DecayEngine
10
+ from synapse_memory.core.embedder import SynapseEmbedder
11
+ from synapse_memory.core.hybrid_search import HybridSearch
12
+ from synapse_memory.core.knapsack_packer import KnapsackPacker
13
+ from synapse_memory.core.memory_manager import MemoryManager
14
+ from synapse_memory.core.sqlite_db import SQLiteMemoryStore
15
+
16
+
17
+ def main():
18
+ parser = argparse.ArgumentParser(
19
+ description="SynapseMemory: Sovereign Command-Line Cognitive Console & Debugger."
20
+ )
21
+ subparsers = parser.add_subparsers(dest="command", help="Command to execute")
22
+
23
+ # Ingest subcommand
24
+ ingest_parser = subparsers.add_parser("ingest", help="Ingest a cognitive memory segment with semantic deduplication")
25
+ ingest_parser.add_argument("--content", required=True, type=str, help="Text content of the memory")
26
+ ingest_parser.add_argument("--category", type=str, default="interaction", help="Cognitive category")
27
+ ingest_parser.add_argument("--confidence", type=float, default=0.95, help="Confidence factor (0.0 to 1.0)")
28
+
29
+ # Query subcommand
30
+ query_parser = subparsers.add_parser("query", help="Query long-term memory with Knapsack context budget constraints")
31
+ query_parser.add_argument("--prompt", required=True, type=str, help="The search or context prompt")
32
+ query_parser.add_argument("--budget", type=int, default=1500, help="Maximum tokens allowed in context pack")
33
+
34
+ # List subcommand
35
+ subparsers.add_parser("list", help="List all indexed sqlite memories")
36
+
37
+ # Clear subcommand
38
+ subparsers.add_parser("clear", help="Clear the entire local SQLite memory table")
39
+
40
+ # Prune subcommand
41
+ prune_parser = subparsers.add_parser("prune", help="Manually force a temporal Ebbinghaus decay pruning sweep")
42
+ prune_parser.add_argument("--limit", type=int, default=10, help="Set database maximum record limit")
43
+
44
+ args = parser.parse_args()
45
+
46
+ # Initialize store, embedder and engines
47
+ store = SQLiteMemoryStore("synapse_memory.db")
48
+ embedder = SynapseEmbedder(provider="local")
49
+ manager = MemoryManager(store=store, embedder=embedder)
50
+ searcher = HybridSearch()
51
+ decay = DecayEngine()
52
+ packer = KnapsackPacker()
53
+
54
+ if args.command == "ingest":
55
+ mem_id, action, cost = manager.ingest_with_deduplication(
56
+ content=args.content,
57
+ category=args.category,
58
+ confidence=args.confidence
59
+ )
60
+ print("[+] Ingestion Finished:")
61
+ print(f" - Memory ID : {mem_id}")
62
+ print(f" - Event Type : {action}")
63
+ print(f" - Token Cost : {cost} tokens")
64
+
65
+ elif args.command == "query":
66
+ memories = store.get_all_memories()
67
+ if not memories:
68
+ print("[-] Store is empty. Ingest memories before querying.")
69
+ return
70
+
71
+ candidates = searcher.fused_search(args.prompt, memories, top_k=25)
72
+
73
+ # Apply temporal decay calculations
74
+ decayed = []
75
+ for c in candidates:
76
+ current = decay.calculate_retention(
77
+ base_relevance=c["relevance_score"],
78
+ created_epoch=c["created_at"],
79
+ access_count=c["access_count"]
80
+ )
81
+ c_copy = c.copy()
82
+ c_copy["relevance_score"] = current
83
+ decayed.append(c_copy)
84
+
85
+ packed = packer.pack(decayed, args.budget)
86
+
87
+ print(f"\n[+] Retained {len(packed)} optimal context segments under a {args.budget}-token budget:")
88
+ for idx, m in enumerate(packed):
89
+ print(f" {idx + 1}. [{m['id']}] (Cost: {m['token_cost']} tokens, Relevance: {m['relevance_score']:.3f}):")
90
+ print(f" \"{m['content']}\"")
91
+
92
+ elif args.command == "list":
93
+ memories = store.get_all_memories()
94
+ print(f"[+] Active Database Records ({len(memories)} items):")
95
+ for m in memories:
96
+ print(f" - [{m['id']}] Category: {m['category'].upper()} | Cost: {m['token_cost']} | Content: \"{m['content'][:60]}...\"")
97
+
98
+ elif args.command == "clear":
99
+ os.remove("synapse_memory.db") if os.path.exists("synapse_memory.db") else None
100
+ print("[+] Erased local sqlite database table cleanly.")
101
+
102
+ elif args.command == "prune":
103
+ manager.max_record_limit = args.limit
104
+ evicted = manager.auto_prune_store()
105
+ print(f"[+] Manual Prune Complete: Evicted {evicted} memories. Active store contains max {args.limit} items.")
106
+
107
+ else:
108
+ parser.print_help()
109
+
110
+
111
+ if __name__ == "__main__":
112
+ main()
@@ -0,0 +1,127 @@
1
+ """Canonical SynapseMemory Python client (Phase 6.1).
2
+
3
+ Small, typed surface over the REST gateway — the supported path for
4
+ external applications. Handles auth headers, timeouts, retries on
5
+ retryable (429/5xx) failures, and the canonical {success, data} envelope.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import time
10
+ from dataclasses import dataclass
11
+ from typing import Any, Dict, List, Optional
12
+
13
+ import requests
14
+
15
+ __all__ = ["SynapseClient", "SynapseError", "CreateResult", "QueryResult"]
16
+
17
+ SDK_VERSION = "1.2.0"
18
+ API_COMPAT_VERSION = "v1"
19
+
20
+
21
+ class SynapseError(Exception):
22
+ def __init__(self, message: str, *, status: Optional[int] = None, retryable: bool = False):
23
+ super().__init__(message)
24
+ self.status = status
25
+ self.retryable = retryable
26
+
27
+
28
+ @dataclass
29
+ class CreateResult:
30
+ id: str
31
+ status: str
32
+ token_cost: int
33
+ tenant_id: str
34
+
35
+
36
+ @dataclass
37
+ class QueryResult:
38
+ fused_context: str
39
+ injected_nodes_count: int
40
+ injected_nodes: List[Dict[str, Any]]
41
+ storage_backend: str
42
+
43
+
44
+ class SynapseClient:
45
+ """Synchronous client; also usable as a context manager."""
46
+
47
+ def __init__(
48
+ self,
49
+ base_url: str = "http://127.0.0.1:8008",
50
+ api_key: Optional[str] = None,
51
+ tenant_id: str = "default",
52
+ timeout: float = 10.0,
53
+ max_retries: int = 3,
54
+ ):
55
+ self.base_url = base_url.rstrip("/")
56
+ self.api_key = api_key
57
+ self.tenant_id = tenant_id
58
+ self.timeout = timeout
59
+ self.max_retries = max_retries
60
+ self._session = requests.Session()
61
+
62
+ def __enter__(self) -> "SynapseClient":
63
+ return self
64
+
65
+ def __exit__(self, *exc: Any) -> None:
66
+ self.close()
67
+
68
+ def close(self) -> None:
69
+ self._session.close()
70
+
71
+ def _headers(self) -> Dict[str, str]:
72
+ headers = {"Content-Type": "application/json", "X-Tenant-ID": self.tenant_id}
73
+ if self.api_key:
74
+ headers["X-Synapse-API-Key"] = self.api_key
75
+ return headers
76
+
77
+ def _request(self, method: str, path: str, payload: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
78
+ url = f"{self.base_url}{path}"
79
+ last_error: Optional[SynapseError] = None
80
+ for attempt in range(self.max_retries + 1):
81
+ try:
82
+ resp = self._session.request(method, url, json=payload, headers=self._headers(), timeout=self.timeout)
83
+ except requests.RequestException as e:
84
+ last_error = SynapseError(f"Connection failed: {e}", retryable=True)
85
+ else:
86
+ if resp.status_code in (429, 502, 503, 504):
87
+ last_error = SynapseError(f"Retryable {resp.status_code}: {resp.text[:200]}", status=resp.status_code, retryable=True)
88
+ elif not resp.ok:
89
+ raise SynapseError(f"Request failed {resp.status_code}: {resp.text[:500]}", status=resp.status_code)
90
+ else:
91
+ body = resp.json()
92
+ if isinstance(body, dict) and "success" in body and "data" in body:
93
+ if not body["success"]:
94
+ raise SynapseError(f"API error: {body.get('error')}", status=resp.status_code)
95
+ return body["data"]
96
+ return body
97
+ if attempt < self.max_retries:
98
+ time.sleep(min(2.0, 0.25 * (2 ** attempt)))
99
+ raise last_error or SynapseError("Request failed")
100
+
101
+ def create_memory(self, content: str, category: str = "interaction", confidence: float = 0.95) -> CreateResult:
102
+ data = self._request("POST", "/ingest", {"content": content, "category": category, "confidence": confidence})
103
+ return CreateResult(id=data["id"], status=data["status"], token_cost=data["token_cost"], tenant_id=data["tenant_id"])
104
+
105
+ def retrieve(self, query: str, max_tokens: int = 1500) -> QueryResult:
106
+ data = self._request("POST", "/query", {"prompt": query, "maxTokens": max_tokens})
107
+ return QueryResult(
108
+ fused_context=data.get("fused_context", ""),
109
+ injected_nodes_count=data.get("injected_nodes_count", 0),
110
+ injected_nodes=data.get("injected_nodes", []),
111
+ storage_backend=data.get("active_storage_backend", "unknown"),
112
+ )
113
+
114
+ def list_memories(self, limit: int = 50, offset: int = 0) -> Dict[str, Any]:
115
+ return self._request("GET", f"/api/memories/list?limit={limit}&offset={offset}")
116
+
117
+ def delete_memory(self, memory_id: str) -> Dict[str, Any]:
118
+ return self._request("DELETE", f"/api/memories/{memory_id}")
119
+
120
+ def feedback(self, memory_id: str, feedback_type: str) -> Dict[str, Any]:
121
+ return self._request("POST", "/feedback", {"memory_id": memory_id, "feedback_type": feedback_type})
122
+
123
+ def health(self) -> Dict[str, Any]:
124
+ return self._request("GET", "/health")
125
+
126
+ def readiness(self) -> Dict[str, Any]:
127
+ return self._request("GET", "/readiness")
@@ -0,0 +1,50 @@
1
+ # Expose core components for internal and public access
2
+ from synapse_memory.core.sqlite_db import SQLiteMemoryStore
3
+ from synapse_memory.core.embedder import SynapseEmbedder
4
+ from synapse_memory.core.memory_manager import MemoryManager
5
+ from synapse_memory.core.hybrid_search import HybridSearch
6
+ from synapse_memory.core.knapsack_packer import KnapsackPacker, MemoryNodeResult
7
+ from synapse_memory.core.decay_engine import DecayEngine
8
+ from synapse_memory.core.deduplicator import Deduplicator, Action, DeduplicationResult
9
+ from synapse_memory.core.pruner import (
10
+ PruningEngine,
11
+ CapacityPruningPolicy,
12
+ TTLPruningPolicy,
13
+ ConfidencePruningPolicy,
14
+ )
15
+ from synapse_memory.core.embedding_provider import (
16
+ EmbeddingManager,
17
+ LocalEmbeddingProvider,
18
+ GeminiEmbeddingProvider,
19
+ OpenAIEmbeddingProvider,
20
+ )
21
+ from synapse_memory.core.encryption import EncryptedMemoryStore, FernetKeyManager
22
+ from synapse_memory.core.pgvector_db import PGVectorMemoryStore
23
+ from synapse_memory.core.auth import SecurityManager, APIKeyRecord, AuthAuditLog
24
+
25
+ __all__ = [
26
+ "SQLiteMemoryStore",
27
+ "PGVectorMemoryStore",
28
+ "SecurityManager",
29
+ "APIKeyRecord",
30
+ "AuthAuditLog",
31
+ "SynapseEmbedder",
32
+ "MemoryManager",
33
+ "HybridSearch",
34
+ "KnapsackPacker",
35
+ "MemoryNodeResult",
36
+ "DecayEngine",
37
+ "Deduplicator",
38
+ "Action",
39
+ "DeduplicationResult",
40
+ "PruningEngine",
41
+ "CapacityPruningPolicy",
42
+ "TTLPruningPolicy",
43
+ "ConfidencePruningPolicy",
44
+ "EmbeddingManager",
45
+ "LocalEmbeddingProvider",
46
+ "GeminiEmbeddingProvider",
47
+ "OpenAIEmbeddingProvider",
48
+ "EncryptedMemoryStore",
49
+ "FernetKeyManager",
50
+ ]