synapse-framework 0.2.4__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.
Files changed (54) hide show
  1. synapse/__init__.py +207 -0
  2. synapse/app.py +942 -0
  3. synapse/cli.py +88 -0
  4. synapse/config.py +103 -0
  5. synapse/connectors/__init__.py +29 -0
  6. synapse/connectors/base.py +222 -0
  7. synapse/connectors/factory.py +202 -0
  8. synapse/connectors/gmail.py +292 -0
  9. synapse/connectors/mcp_wrapper.py +153 -0
  10. synapse/connectors/notion.py +161 -0
  11. synapse/connectors/photos.py +141 -0
  12. synapse/database/__init__.py +19 -0
  13. synapse/database/base.py +63 -0
  14. synapse/database/chroma.py +175 -0
  15. synapse/database/memory.py +132 -0
  16. synapse/database/pgvector.py +99 -0
  17. synapse/database/qdrant.py +138 -0
  18. synapse/embeddings/__init__.py +21 -0
  19. synapse/embeddings/base.py +262 -0
  20. synapse/export/__init__.py +14 -0
  21. synapse/export/mcp_exporter.py +202 -0
  22. synapse/graph/__init__.py +21 -0
  23. synapse/graph/base.py +130 -0
  24. synapse/graph/memory.py +20 -0
  25. synapse/graph/neo4j_store.py +176 -0
  26. synapse/graph/networkx_store.py +221 -0
  27. synapse/inspector/__init__.py +5 -0
  28. synapse/inspector/template.py +530 -0
  29. synapse/models/__init__.py +73 -0
  30. synapse/models/base.py +95 -0
  31. synapse/models/gemini.py +328 -0
  32. synapse/models/ollama.py +322 -0
  33. synapse/models/openai.py +289 -0
  34. synapse/oauth/__init__.py +7 -0
  35. synapse/oauth/google.py +194 -0
  36. synapse/oauth/notion.py +35 -0
  37. synapse/rag/__init__.py +8 -0
  38. synapse/rag/chunker.py +219 -0
  39. synapse/rag/hybrid_rag.py +122 -0
  40. synapse/resource/__init__.py +5 -0
  41. synapse/resource/resource.py +304 -0
  42. synapse/resources/__init__.py +5 -0
  43. synapse/skills/__init__.py +5 -0
  44. synapse/skills/skill.py +321 -0
  45. synapse/storage/__init__.py +24 -0
  46. synapse/storage/graph_exporter.py +624 -0
  47. synapse/storage/graph_store.py +162 -0
  48. synapse/storage/vector_store.py +103 -0
  49. synapse_framework-0.2.4.dist-info/METADATA +415 -0
  50. synapse_framework-0.2.4.dist-info/RECORD +54 -0
  51. synapse_framework-0.2.4.dist-info/WHEEL +5 -0
  52. synapse_framework-0.2.4.dist-info/entry_points.txt +2 -0
  53. synapse_framework-0.2.4.dist-info/licenses/LICENSE +21 -0
  54. synapse_framework-0.2.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,321 @@
1
+ """Skills module for specialized agent instructions, personas, and domain knowledge."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ try:
10
+ import yaml
11
+ except ImportError:
12
+ yaml = None # type: ignore
13
+
14
+
15
+ class Skill:
16
+ """Represents a discrete skill, persona, or behavioral capability for Synapse.
17
+
18
+ Skills package natural language instructions (typically loaded from Markdown files
19
+ with optional YAML frontmatter), domain guidelines, and optional tool associations
20
+ that guide the model's responses.
21
+
22
+ Example:
23
+ ```python
24
+ from synapse.skills import makeskills
25
+
26
+ # From a markdown file:
27
+ skill = makeskills("skills/python_expert.md")
28
+
29
+ # Or inline:
30
+ reviewer = makeskills(
31
+ prompt="# PR Reviewer\nCarefully inspect code diffs for edge cases.",
32
+ name="reviewer",
33
+ description="Reviews code PRs for performance and edge cases",
34
+ )
35
+ ```
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ name: str,
41
+ description: str = "",
42
+ instructions: str = "",
43
+ tools: list[Any] | None = None,
44
+ tags: list[str] | None = None,
45
+ path: str | Path | None = None,
46
+ metadata: dict[str, Any] | None = None,
47
+ ) -> None:
48
+ """Initializes a Skill instance.
49
+
50
+ Args:
51
+ name: Human-readable identifier for the skill.
52
+ description: Concise summary of what this skill does.
53
+ instructions: Full markdown instructions given to the LLM.
54
+ tools: Optional list of callables or connector tools associated with the skill.
55
+ tags: Categorical tags (e.g. ['coding', 'review', 'research']).
56
+ path: Optional source filesystem path if loaded from disk.
57
+ metadata: Arbitrary additional properties.
58
+ """
59
+ self.name = name
60
+ self.description = description
61
+ self.instructions = instructions.strip()
62
+ self.tools = list(tools or [])
63
+ self.tags = list(tags or [])
64
+ self.path = Path(path).resolve() if path else None
65
+ self.metadata = dict(metadata or {})
66
+
67
+ @property
68
+ def prompt(self) -> str:
69
+ """Alias for instructions."""
70
+ return self.instructions
71
+
72
+ def format_prompt(self) -> str:
73
+ """Renders the skill into a formatted system prompt section."""
74
+ lines = [f"### SKILL: {self.name}"]
75
+ if self.description:
76
+ lines.append(f"Description: {self.description}")
77
+ if self.tags:
78
+ lines.append(f"Tags: {', '.join(self.tags)}")
79
+ lines.append("")
80
+ lines.append(self.instructions)
81
+ return "\n".join(lines)
82
+
83
+ def to_dict(self) -> dict[str, Any]:
84
+ """Serializes the skill metadata into a dictionary."""
85
+ return {
86
+ "name": self.name,
87
+ "description": self.description,
88
+ "instructions": self.instructions,
89
+ "tags": self.tags,
90
+ "tools": [getattr(t, "name", str(t)) for t in self.tools],
91
+ "path": str(self.path) if self.path else None,
92
+ "metadata": self.metadata,
93
+ }
94
+
95
+ @classmethod
96
+ def from_markdown(
97
+ cls,
98
+ content: str,
99
+ name: str | None = None,
100
+ description: str | None = None,
101
+ tools: list[Any] | None = None,
102
+ tags: list[str] | None = None,
103
+ path: str | Path | None = None,
104
+ **extra_metadata: Any,
105
+ ) -> Skill:
106
+ """Parses a markdown string with optional YAML frontmatter into a Skill.
107
+
108
+ Args:
109
+ content: Markdown content string.
110
+ name: Optional explicit name override.
111
+ description: Optional description override.
112
+ tools: Associated tools.
113
+ tags: Categorical tags.
114
+ path: Optional source path.
115
+ **extra_metadata: Additional metadata fields.
116
+
117
+ Returns:
118
+ A populated Skill instance.
119
+ """
120
+ text = content.strip()
121
+ frontmatter: dict[str, Any] = {}
122
+ body = text
123
+
124
+ # Check for YAML frontmatter block: --- ... ---
125
+ if text.startswith("---"):
126
+ parts = text.split("---", 2)
127
+ if len(parts) >= 3:
128
+ raw_yaml = parts[1].strip()
129
+ body = parts[2].strip()
130
+ if yaml:
131
+ try:
132
+ parsed = yaml.safe_load(raw_yaml)
133
+ if isinstance(parsed, dict):
134
+ frontmatter = parsed
135
+ except Exception:
136
+ pass # nosec B110
137
+ else:
138
+ # Fallback simple line parser if PyYAML is not present
139
+ for line in raw_yaml.splitlines():
140
+ if ":" in line:
141
+ k, v = line.split(":", 1)
142
+ frontmatter[k.strip()] = v.strip().strip("\"'")
143
+
144
+ # Infer name if not specified
145
+ resolved_name = (
146
+ name
147
+ or frontmatter.get("name")
148
+ or frontmatter.get("title")
149
+ )
150
+ if not resolved_name:
151
+ # Try to grab top markdown header: # Skill Name
152
+ match = re.search(r"^#+\s+(.+)$", body, re.MULTILINE)
153
+ if match:
154
+ resolved_name = match.group(1).strip()
155
+ elif path:
156
+ resolved_name = Path(path).stem.replace("_", " ").replace("-", " ").title()
157
+ else:
158
+ resolved_name = "Custom Skill"
159
+
160
+ # Infer description if not specified
161
+ resolved_desc = (
162
+ description
163
+ or frontmatter.get("description")
164
+ or frontmatter.get("summary")
165
+ or ""
166
+ )
167
+ if not resolved_desc:
168
+ # Grab the first non-header paragraph
169
+ for para in body.split("\n\n"):
170
+ para_clean = para.strip()
171
+ if para_clean and not para_clean.startswith("#"):
172
+ resolved_desc = para_clean[:200]
173
+ break
174
+
175
+ resolved_tags = list(tags or frontmatter.get("tags") or [])
176
+ merged_meta = {**frontmatter, **extra_metadata}
177
+
178
+ return cls(
179
+ name=str(resolved_name),
180
+ description=str(resolved_desc),
181
+ instructions=body,
182
+ tools=tools,
183
+ tags=resolved_tags,
184
+ path=path,
185
+ metadata=merged_meta,
186
+ )
187
+
188
+ @classmethod
189
+ def from_file(
190
+ cls,
191
+ file_path: str | Path,
192
+ name: str | None = None,
193
+ description: str | None = None,
194
+ tools: list[Any] | None = None,
195
+ tags: list[str] | None = None,
196
+ **extra_metadata: Any,
197
+ ) -> Skill:
198
+ """Loads a Skill from a Markdown or text file on disk.
199
+
200
+ Args:
201
+ file_path: Filesystem path to the skill file (.md, .txt).
202
+ name: Optional explicit skill name override.
203
+ description: Optional description override.
204
+ tools: Associated tools.
205
+ tags: Categorical tags.
206
+ **extra_metadata: Additional metadata fields.
207
+
208
+ Returns:
209
+ A populated Skill instance.
210
+
211
+ Raises:
212
+ FileNotFoundError: If the specified file does not exist.
213
+ """
214
+ p = Path(file_path).resolve()
215
+ if not p.exists():
216
+ raise FileNotFoundError(f"Skill file not found at: {p}")
217
+
218
+ content = p.read_text(encoding="utf-8")
219
+ return cls.from_markdown(
220
+ content=content,
221
+ name=name,
222
+ description=description,
223
+ tools=tools,
224
+ tags=tags,
225
+ path=p,
226
+ **extra_metadata,
227
+ )
228
+
229
+ def __repr__(self) -> str:
230
+ return f"<Skill name='{self.name}' description='{self.description[:40]}...'>"
231
+
232
+
233
+ def makeskills(
234
+ prompt: str | Path | Skill,
235
+ name: str | None = None,
236
+ description: str | None = None,
237
+ tools: list[Any] | None = None,
238
+ tags: list[str] | None = None,
239
+ **metadata: Any,
240
+ ) -> Skill:
241
+ """Factory function for creating or loading a Synapse Skill.
242
+
243
+ Accepts a filepath (.md or .txt), raw markdown string, or existing Skill instance.
244
+
245
+ Args:
246
+ prompt: File path (str or Path) to a markdown file, raw markdown instructions,
247
+ or an existing Skill object.
248
+ name: Optional explicit skill name.
249
+ description: Optional summary of the skill's purpose.
250
+ tools: Optional list of callables or connector tools.
251
+ tags: Optional list of categories/tags.
252
+ **metadata: Additional keyword attributes stored on the skill.
253
+
254
+ Returns:
255
+ A fully initialized Skill instance.
256
+
257
+ Example:
258
+ ```python
259
+ from synapse.skills import makeskills
260
+
261
+ # Load from file:
262
+ python_skill = makeskills("skills/python_expert.md")
263
+
264
+ # Create inline:
265
+ fastapi_skill = makeskills(
266
+ prompt="Write asynchronous FastAPI routes using Pydantic v2 schemas.",
267
+ name="FastAPI Architect",
268
+ description="Designs modern async APIs",
269
+ )
270
+ ```
271
+ """
272
+ if isinstance(prompt, Skill):
273
+ if name:
274
+ prompt.name = name
275
+ if description:
276
+ prompt.description = description
277
+ if tools:
278
+ prompt.tools.extend(tools)
279
+ if tags:
280
+ prompt.tags.extend(tags)
281
+ prompt.metadata.update(metadata)
282
+ return prompt
283
+
284
+ if isinstance(prompt, Path):
285
+ return Skill.from_file(
286
+ file_path=prompt,
287
+ name=name,
288
+ description=description,
289
+ tools=tools,
290
+ tags=tags,
291
+ **metadata,
292
+ )
293
+
294
+ # String input: check if it points to an existing file
295
+ raw_str = str(prompt).strip()
296
+ candidate_path = Path(raw_str)
297
+ if candidate_path.exists() and candidate_path.is_file():
298
+ return Skill.from_file(
299
+ file_path=candidate_path,
300
+ name=name,
301
+ description=description,
302
+ tools=tools,
303
+ tags=tags,
304
+ **metadata,
305
+ )
306
+
307
+ # Otherwise treat as markdown text
308
+ return Skill.from_markdown(
309
+ content=raw_str,
310
+ name=name,
311
+ description=description,
312
+ tools=tools,
313
+ tags=tags,
314
+ **metadata,
315
+ )
316
+
317
+
318
+ # Developer-friendly alias
319
+ make_skill = makeskills
320
+
321
+ __all__ = ["Skill", "make_skill", "makeskills"]
@@ -0,0 +1,24 @@
1
+ """Storage layer exports for vector and knowledge graph persistence."""
2
+
3
+ from synapse.storage.graph_exporter import GraphExporter
4
+ from synapse.storage.graph_store import PersistentGraphStore
5
+ from synapse.storage.vector_store import (
6
+ LocalVectorStorage,
7
+ LocalVectorStore,
8
+ VectorStorage,
9
+ vectorStorage,
10
+ )
11
+
12
+ KnowledgeGraphStore = PersistentGraphStore
13
+ VectorStore = VectorStorage
14
+
15
+ __all__ = [
16
+ "GraphExporter",
17
+ "KnowledgeGraphStore",
18
+ "LocalVectorStorage",
19
+ "LocalVectorStore",
20
+ "PersistentGraphStore",
21
+ "VectorStorage",
22
+ "VectorStore",
23
+ "vectorStorage",
24
+ ]