synapse-layer 0.7.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,45 @@
1
+ # ── Dependencies ──────────────────────────────────────────────────
2
+ node_modules/
3
+ .pnp.*
4
+ .yarn/
5
+
6
+ # ── Build outputs ─────────────────────────────────────────────────
7
+ dist/
8
+ build/
9
+ *.js.map
10
+
11
+ # ── Environment & Secrets ─────────────────────────────────────────
12
+ .env
13
+ .env.local
14
+ .env.*.local
15
+
16
+ # ── IDE ───────────────────────────────────────────────────────────
17
+ .vscode/
18
+ .idea/
19
+ *.swp
20
+ *.swo
21
+ *~
22
+
23
+ # ── OS ────────────────────────────────────────────────────────────
24
+ .DS_Store
25
+ Thumbs.db
26
+
27
+ # ── Python ────────────────────────────────────────────────────────
28
+ __pycache__/
29
+ *.py[cod]
30
+ *.egg-info/
31
+ .eggs/
32
+ venv/
33
+ .venv/
34
+ *.whl
35
+
36
+ # ── Testing ───────────────────────────────────────────────────────
37
+ coverage/
38
+ .jest/
39
+
40
+ # ── Logs ──────────────────────────────────────────────────────────
41
+ *.log
42
+ npm-debug.log*
43
+
44
+ # ── Supabase ──────────────────────────────────────────────────────
45
+ supabase/.temp/
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: synapse-layer
3
+ Version: 0.7.0
4
+ Summary: Universal memory layer for AI agents - Persistent, Private, Model-agnostic, Open-source
5
+ Project-URL: Homepage, https://synapse-layer.org
6
+ Project-URL: Documentation, https://docs.synapse-layer.org
7
+ Project-URL: Repository, https://github.com/synapse-layer/synapse-layer
8
+ Project-URL: Issues, https://github.com/synapse-layer/synapse-layer/issues
9
+ Author-email: Ismael Marchi <ismael@synapse-layer.org>
10
+ License: Apache-2.0
11
+ Keywords: a2a,agents,ai,crewai,encryption,langchain,memory,persistence
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Natural Language :: English
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: httpx>=0.27.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Provides-Extra: all
26
+ Requires-Dist: crewai>=0.1.0; extra == 'all'
27
+ Requires-Dist: langchain-core>=0.1.0; extra == 'all'
28
+ Provides-Extra: crewai
29
+ Requires-Dist: crewai>=0.1.0; extra == 'crewai'
30
+ Provides-Extra: dev
31
+ Requires-Dist: black>=23.0.0; extra == 'dev'
32
+ Requires-Dist: isort>=5.0.0; extra == 'dev'
33
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
36
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
38
+ Requires-Dist: sphinx>=6.0.0; extra == 'dev'
39
+ Provides-Extra: langchain
40
+ Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
@@ -0,0 +1,145 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "synapse-layer"
7
+ version = "0.7.0"
8
+ description = "Universal memory layer for AI agents - Persistent, Private, Model-agnostic, Open-source"
9
+ license = {text = "Apache-2.0"}
10
+ authors = [
11
+ {name = "Ismael Marchi", email = "ismael@synapse-layer.org"},
12
+ ]
13
+ keywords = [
14
+ "ai",
15
+ "agents",
16
+ "memory",
17
+ "persistence",
18
+ "langchain",
19
+ "crewai",
20
+ "a2a",
21
+ "encryption",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 4 - Beta",
25
+ "Intended Audience :: Developers",
26
+ "License :: OSI Approved :: Apache Software License",
27
+ "Natural Language :: English",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.9",
30
+ "Programming Language :: Python :: 3.10",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Topic :: Software Development :: Libraries :: Python Modules",
34
+ ]
35
+ requires-python = ">=3.9"
36
+
37
+ dependencies = [
38
+ "httpx>=0.27.0",
39
+ "pydantic>=2.0.0",
40
+ ]
41
+
42
+ [project.optional-dependencies]
43
+ langchain = [
44
+ "langchain-core>=0.1.0",
45
+ ]
46
+ crewai = [
47
+ "crewai>=0.1.0",
48
+ ]
49
+ all = [
50
+ "langchain-core>=0.1.0",
51
+ "crewai>=0.1.0",
52
+ ]
53
+ dev = [
54
+ "pytest>=7.0.0",
55
+ "pytest-asyncio>=0.21.0",
56
+ "pytest-cov>=4.0.0",
57
+ "ruff>=0.1.0",
58
+ "mypy>=1.0.0",
59
+ "black>=23.0.0",
60
+ "isort>=5.0.0",
61
+ "sphinx>=6.0.0",
62
+ ]
63
+
64
+ [project.urls]
65
+ Homepage = "https://synapse-layer.org"
66
+ Documentation = "https://docs.synapse-layer.org"
67
+ Repository = "https://github.com/synapse-layer/synapse-layer"
68
+ Issues = "https://github.com/synapse-layer/synapse-layer/issues"
69
+
70
+ [tool.hatch.build.targets.wheel]
71
+ packages = ["synapse_layer"]
72
+
73
+ [tool.pytest.ini_options]
74
+ testpaths = ["tests"]
75
+ python_files = ["test_*.py"]
76
+ python_classes = ["Test*"]
77
+ python_functions = ["test_*"]
78
+ asyncio_mode = "auto"
79
+ addopts = "-v --tb=short --strict-markers"
80
+ markers = [
81
+ "asyncio: marks tests as async (deselect with '-m \"not asyncio\"')",
82
+ "integration: marks tests as integration tests (deselect with '-m \"not integration\"')",
83
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')",
84
+ ]
85
+
86
+ [tool.ruff]
87
+ line-length = 100
88
+ target-version = "py39"
89
+ exclude = [
90
+ ".git",
91
+ ".venv",
92
+ "build",
93
+ "dist",
94
+ ".eggs",
95
+ "__pycache__",
96
+ ]
97
+
98
+ [tool.ruff.lint]
99
+ select = [
100
+ "E",
101
+ "F",
102
+ "W",
103
+ "I",
104
+ "N",
105
+ "UP",
106
+ "B",
107
+ "A",
108
+ "C4",
109
+ "SIM",
110
+ ]
111
+ ignore = [
112
+ "E501",
113
+ "E203",
114
+ ]
115
+
116
+ [tool.mypy]
117
+ python_version = "3.9"
118
+ check_untyped_defs = true
119
+ strict_optional = true
120
+ warn_redundant_casts = true
121
+ warn_unused_configs = true
122
+ warn_unused_ignores = true
123
+
124
+ [tool.isort]
125
+ profile = "black"
126
+ line_length = 100
127
+ skip_gitignore = true
128
+
129
+ [tool.black]
130
+ line-length = 100
131
+ target-version = ["py39"]
132
+ include = '\.pyi?$'
133
+ extend-exclude = '''
134
+ /(
135
+ # directories
136
+ \.eggs
137
+ | \.git
138
+ | \.hg
139
+ | \.mypy_cache
140
+ | \.tox
141
+ | \.venv
142
+ | build
143
+ | dist
144
+ )/
145
+ '''
@@ -0,0 +1,92 @@
1
+ """
2
+ Synapse Layer - Universal Memory Layer for AI Agents
3
+
4
+ A persistent, private, model-agnostic, open-source memory solution for AI agents.
5
+ Provides seamless integration with LangChain, CrewAI, and custom Agent-to-Agent (A2A) protocols.
6
+
7
+ Modules:
8
+ a2a_client: JSON-RPC 2.0 client for Agent-to-Agent communication
9
+ langchain_memory: LangChain adapters (SynapseMemory, SynapseChatHistory)
10
+ crewai_tools: CrewAI tools (SynapseStoreMemoryTool, SynapseRecallMemoryTool, SynapseHandoverTool)
11
+
12
+ Key Features:
13
+ - Persistent encrypted memory storage
14
+ - Trust Quotient (TQ) weighting: TQ = (confidence_score * 0.4) + (recency_score * 0.3) + (usage_normalized * 0.3)
15
+ - Semantic search with pgvector HNSW
16
+ - Neural Handover with HMAC-SHA256 signatures
17
+ - GDPR/LGPD compliance (soft-delete with audit trail)
18
+ - Zero-Knowledge Context preservation
19
+
20
+ Author: Ismael Marchi
21
+ License: Apache 2.0
22
+ Version: 0.7.0
23
+
24
+ Example:
25
+ >>> from synapse_layer import SynapseA2AClient
26
+ >>> async with SynapseA2AClient(api_key="your-key") as client:
27
+ ... result = await client.store_memory(
28
+ ... user_id="user-123",
29
+ ... content="Important context",
30
+ ... source_type="inference",
31
+ ... confidence=0.9
32
+ ... )
33
+ ... print(result)
34
+ """
35
+
36
+ __version__ = "0.7.0"
37
+ __author__ = "Ismael Marchi"
38
+ __license__ = "Apache-2.0"
39
+ __all__ = [
40
+ # Core client
41
+ "SynapseA2AClient",
42
+ # Data types
43
+ "TaskResult",
44
+ "TaskState",
45
+ # Constants
46
+ "DEFAULT_BASE_URL",
47
+ "VALID_SKILL_IDS",
48
+ # Version
49
+ "__version__",
50
+ "__author__",
51
+ "__license__",
52
+ ]
53
+
54
+ # Import core components
55
+ from .a2a_client import (
56
+ DEFAULT_BASE_URL,
57
+ VALID_SKILL_IDS,
58
+ SynapseA2AClient,
59
+ TaskResult,
60
+ TaskState,
61
+ )
62
+
63
+ # Try to import optional adapters
64
+ try:
65
+ from .langchain_memory import SynapseMemory, SynapseChatHistory
66
+
67
+ __all__.extend(["SynapseMemory", "SynapseChatHistory"])
68
+ except ImportError:
69
+ pass
70
+
71
+ try:
72
+ from .crewai_tools import (
73
+ SynapseHandoverTool,
74
+ SynapseRecallMemoryTool,
75
+ SynapseStoreMemoryTool,
76
+ HandoverInput,
77
+ RecallMemoryInput,
78
+ StoreMemoryInput,
79
+ )
80
+
81
+ __all__.extend(
82
+ [
83
+ "SynapseStoreMemoryTool",
84
+ "SynapseRecallMemoryTool",
85
+ "SynapseHandoverTool",
86
+ "StoreMemoryInput",
87
+ "RecallMemoryInput",
88
+ "HandoverInput",
89
+ ]
90
+ )
91
+ except ImportError:
92
+ pass
@@ -0,0 +1,337 @@
1
+ """
2
+ Synapse Layer A2A Client — JSON-RPC 2.0 over HTTPS
3
+
4
+ Provides async client for Agent-to-Agent (A2A) communication with Synapse Layer MCP server.
5
+ Implements Trust Quotient (TQ) formula for memory confidence evaluation:
6
+
7
+ TQ = (confidence_score * 0.4) + (recency_score * 0.3) + (usage_normalized * 0.3)
8
+
9
+ where:
10
+ - confidence_score: Precision of memory (0.0-1.0)
11
+ - recency_score: How recent the memory is (0.0-1.0, decays over time)
12
+ - usage_normalized: Normalized count of times memory was recalled (0.0-1.0)
13
+ """
14
+
15
+ import asyncio
16
+ import json
17
+ from dataclasses import dataclass
18
+ from enum import Enum
19
+ from typing import Any, Dict, Optional
20
+ import aiohttp
21
+
22
+
23
+ # Constants
24
+ DEFAULT_BASE_URL = "https://rbeycxzizrrdmxpilepc.supabase.co/functions/v1/mcp-server"
25
+ VALID_SKILL_IDS = {
26
+ "store_memory",
27
+ "recall_memory",
28
+ "create_handover",
29
+ "resolve_conflict",
30
+ "forget_memory"
31
+ }
32
+
33
+
34
+ # Enums
35
+ class TaskState(str, Enum):
36
+ """State enum for A2A task lifecycle."""
37
+ SUBMITTED = "submitted"
38
+ WORKING = "working"
39
+ COMPLETED = "completed"
40
+ FAILED = "failed"
41
+ CANCELLED = "cancelled"
42
+
43
+
44
+ # Dataclasses
45
+ @dataclass
46
+ class TaskResult:
47
+ """Result of a skill invocation."""
48
+ task_id: str
49
+ status: TaskState
50
+ output: Optional[Dict[str, Any]] = None
51
+ error: Optional[str] = None
52
+
53
+ def __post_init__(self):
54
+ """Convert status string to TaskState enum if needed."""
55
+ if isinstance(self.status, str):
56
+ self.status = TaskState(self.status)
57
+
58
+
59
+ # Main Client Class
60
+ class SynapseA2AClient:
61
+ """
62
+ Async client for Synapse Layer A2A protocol (JSON-RPC 2.0).
63
+
64
+ Provides methods to interact with Synapse Layer's memory, handover, and
65
+ conflict resolution skills through the MCP server.
66
+
67
+ Trust Quotient (TQ) formula applied to all memory operations:
68
+ TQ = (confidence_score * 0.4) + (recency_score * 0.3) + (usage_normalized * 0.3)
69
+
70
+ Example:
71
+ async with SynapseA2AClient(api_key="...") as client:
72
+ result = await client.store_memory(
73
+ user_id="user-123",
74
+ content="My preferences...",
75
+ source_type="user_input",
76
+ confidence=0.95
77
+ )
78
+ """
79
+
80
+ def __init__(
81
+ self,
82
+ api_key: str,
83
+ base_url: str = DEFAULT_BASE_URL,
84
+ timeout: int = 30
85
+ ):
86
+ """
87
+ Initialize A2A client.
88
+
89
+ Args:
90
+ api_key: Synapse Layer API key for authentication
91
+ base_url: MCP server base URL (defaults to production Supabase Edge Function)
92
+ timeout: Request timeout in seconds
93
+ """
94
+ self.api_key = api_key
95
+ self.base_url = base_url.rstrip("/")
96
+ self.timeout = timeout
97
+ self.session: Optional[aiohttp.ClientSession] = None
98
+ self._request_id_counter = 0
99
+
100
+ async def __aenter__(self):
101
+ """Async context manager entry."""
102
+ self.session = aiohttp.ClientSession()
103
+ return self
104
+
105
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
106
+ """Async context manager exit."""
107
+ if self.session:
108
+ await self.session.close()
109
+
110
+ def _get_next_request_id(self) -> int:
111
+ """Get next JSON-RPC request ID."""
112
+ self._request_id_counter += 1
113
+ return self._request_id_counter
114
+
115
+ async def send_task(self, skill_id: str, params: Dict[str, Any]) -> TaskResult:
116
+ """
117
+ Send a skill invocation task via JSON-RPC 2.0.
118
+
119
+ Core method for all A2A communication. Validates skill_id and formats
120
+ the JSON-RPC request according to MCP spec.
121
+
122
+ Args:
123
+ skill_id: One of VALID_SKILL_IDS
124
+ params: Skill-specific parameters dict
125
+
126
+ Returns:
127
+ TaskResult with task_id, status, output or error
128
+
129
+ Raises:
130
+ ValueError: If skill_id is invalid
131
+ aiohttp.ClientError: If HTTP request fails
132
+ """
133
+ if skill_id not in VALID_SKILL_IDS:
134
+ raise ValueError(f"Unknown skill: {skill_id}. Valid: {VALID_SKILL_IDS}")
135
+
136
+ if not self.session:
137
+ raise RuntimeError("Client not in async context. Use 'async with' syntax.")
138
+
139
+ # Build JSON-RPC 2.0 request
140
+ request_id = self._get_next_request_id()
141
+ rpc_payload = {
142
+ "jsonrpc": "2.0",
143
+ "method": skill_id,
144
+ "params": params,
145
+ "id": request_id
146
+ }
147
+
148
+ headers = {
149
+ "Authorization": f"Bearer {self.api_key}",
150
+ "Content-Type": "application/json"
151
+ }
152
+
153
+ try:
154
+ async with self.session.post(
155
+ self.base_url,
156
+ json=rpc_payload,
157
+ headers=headers,
158
+ timeout=aiohttp.ClientTimeout(total=self.timeout)
159
+ ) as response:
160
+ body = await response.json()
161
+ return self._parse_response(body, request_id)
162
+ except asyncio.TimeoutError:
163
+ return TaskResult(
164
+ task_id=f"req-{request_id}",
165
+ status=TaskState.FAILED,
166
+ error="Request timeout"
167
+ )
168
+ except Exception as e:
169
+ return TaskResult(
170
+ task_id=f"req-{request_id}",
171
+ status=TaskState.FAILED,
172
+ error=str(e)
173
+ )
174
+
175
+ @staticmethod
176
+ def _parse_response(body: Dict[str, Any], request_id: int) -> TaskResult:
177
+ """
178
+ Parse JSON-RPC 2.0 response.
179
+
180
+ Handles both success (result) and error responses according to JSON-RPC spec.
181
+
182
+ Args:
183
+ body: Response body from server
184
+ request_id: Original request ID for correlation
185
+
186
+ Returns:
187
+ TaskResult with parsed output or error
188
+ """
189
+ task_id = body.get("id", request_id)
190
+
191
+ if "error" in body:
192
+ error_obj = body["error"]
193
+ error_msg = error_obj.get("message", "Unknown error")
194
+ return TaskResult(
195
+ task_id=str(task_id),
196
+ status=TaskState.FAILED,
197
+ error=error_msg
198
+ )
199
+
200
+ if "result" in body:
201
+ result = body["result"]
202
+ return TaskResult(
203
+ task_id=str(task_id),
204
+ status=TaskState.COMPLETED,
205
+ output=result
206
+ )
207
+
208
+ return TaskResult(
209
+ task_id=str(task_id),
210
+ status=TaskState.FAILED,
211
+ error="Invalid JSON-RPC response"
212
+ )
213
+
214
+ # Skill Convenience Wrappers
215
+
216
+ async def store_memory(
217
+ self,
218
+ user_id: str,
219
+ content: str,
220
+ source_type: str,
221
+ confidence: float
222
+ ) -> TaskResult:
223
+ """
224
+ Store encrypted memory with semantic embedding.
225
+
226
+ TQ formula applied: confidence contributes 40% to final Trust Quotient.
227
+
228
+ Args:
229
+ user_id: UUID of memory owner
230
+ content: Plaintext content to encrypt and store
231
+ source_type: Origin type (user_input, api_response, inference, handover, system)
232
+ confidence: Confidence score (0.0-1.0)
233
+
234
+ Returns:
235
+ TaskResult with memory_id, fact_hash, and tq_score
236
+ """
237
+ return await self.send_task("store_memory", {
238
+ "user_id": user_id,
239
+ "content": content,
240
+ "source_type": source_type,
241
+ "confidence": confidence
242
+ })
243
+
244
+ async def recall_memory(
245
+ self,
246
+ user_id: str,
247
+ query: str,
248
+ limit: int = 10
249
+ ) -> TaskResult:
250
+ """
251
+ Semantic search over encrypted memories with TQ weighting.
252
+
253
+ Results ordered by Trust Quotient = (confidence * 0.4) + (recency * 0.3) + (usage * 0.3).
254
+
255
+ Args:
256
+ user_id: UUID of agent requesting recall
257
+ query: Natural language query for semantic search
258
+ limit: Max memories to return (default 10, max 100)
259
+
260
+ Returns:
261
+ TaskResult with memories array (memory_id, similarity, tq_score)
262
+ """
263
+ return await self.send_task("recall_memory", {
264
+ "user_id": user_id,
265
+ "query": query,
266
+ "limit": min(limit, 100)
267
+ })
268
+
269
+ async def create_handover(
270
+ self,
271
+ user_id: str,
272
+ target_model: str,
273
+ summary: str
274
+ ) -> TaskResult:
275
+ """
276
+ Create Neural Handover package for context transfer to another model.
277
+
278
+ Package includes HMAC-SHA256 signature and list of transferred memories.
279
+
280
+ Args:
281
+ user_id: UUID of agent context to transfer
282
+ target_model: Target model identifier (claude-3-opus, gpt-4, gemini-2.5, etc)
283
+ summary: Brief context summary for handover
284
+
285
+ Returns:
286
+ TaskResult with handover_package (Base64), signature, and memories_count
287
+ """
288
+ return await self.send_task("create_handover", {
289
+ "user_id": user_id,
290
+ "target_model": target_model,
291
+ "summary": summary
292
+ })
293
+
294
+ async def resolve_conflict(
295
+ self,
296
+ user_id: str,
297
+ memory_id: str
298
+ ) -> TaskResult:
299
+ """
300
+ Detect and auto-resolve conflicting memories using Consensus Engine.
301
+
302
+ Uses Trust Quotient to select winner among conflicts:
303
+ TQ = (confidence * 0.4) + (recency * 0.3) + (usage * 0.3)
304
+
305
+ Args:
306
+ user_id: UUID of memory vault
307
+ memory_id: Primary memory ID to check for conflicts
308
+
309
+ Returns:
310
+ TaskResult with conflict_detected, winner_id, winner_tq, resolution_method
311
+ """
312
+ return await self.send_task("resolve_conflict", {
313
+ "user_id": user_id,
314
+ "memory_id": memory_id
315
+ })
316
+
317
+ async def forget_memory(
318
+ self,
319
+ user_id: str,
320
+ memory_id: str
321
+ ) -> TaskResult:
322
+ """
323
+ Soft-delete memory with GDPR/LGPD compliance.
324
+
325
+ Memory marked inactive but audit trail preserved for compliance.
326
+
327
+ Args:
328
+ user_id: UUID of memory owner
329
+ memory_id: UUID of memory to delete
330
+
331
+ Returns:
332
+ TaskResult with deleted flag, deletion_timestamp, and audit_id
333
+ """
334
+ return await self.send_task("forget_memory", {
335
+ "user_id": user_id,
336
+ "memory_id": memory_id
337
+ })