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.
- synapse/__init__.py +207 -0
- synapse/app.py +942 -0
- synapse/cli.py +88 -0
- synapse/config.py +103 -0
- synapse/connectors/__init__.py +29 -0
- synapse/connectors/base.py +222 -0
- synapse/connectors/factory.py +202 -0
- synapse/connectors/gmail.py +292 -0
- synapse/connectors/mcp_wrapper.py +153 -0
- synapse/connectors/notion.py +161 -0
- synapse/connectors/photos.py +141 -0
- synapse/database/__init__.py +19 -0
- synapse/database/base.py +63 -0
- synapse/database/chroma.py +175 -0
- synapse/database/memory.py +132 -0
- synapse/database/pgvector.py +99 -0
- synapse/database/qdrant.py +138 -0
- synapse/embeddings/__init__.py +21 -0
- synapse/embeddings/base.py +262 -0
- synapse/export/__init__.py +14 -0
- synapse/export/mcp_exporter.py +202 -0
- synapse/graph/__init__.py +21 -0
- synapse/graph/base.py +130 -0
- synapse/graph/memory.py +20 -0
- synapse/graph/neo4j_store.py +176 -0
- synapse/graph/networkx_store.py +221 -0
- synapse/inspector/__init__.py +5 -0
- synapse/inspector/template.py +530 -0
- synapse/models/__init__.py +73 -0
- synapse/models/base.py +95 -0
- synapse/models/gemini.py +328 -0
- synapse/models/ollama.py +322 -0
- synapse/models/openai.py +289 -0
- synapse/oauth/__init__.py +7 -0
- synapse/oauth/google.py +194 -0
- synapse/oauth/notion.py +35 -0
- synapse/rag/__init__.py +8 -0
- synapse/rag/chunker.py +219 -0
- synapse/rag/hybrid_rag.py +122 -0
- synapse/resource/__init__.py +5 -0
- synapse/resource/resource.py +304 -0
- synapse/resources/__init__.py +5 -0
- synapse/skills/__init__.py +5 -0
- synapse/skills/skill.py +321 -0
- synapse/storage/__init__.py +24 -0
- synapse/storage/graph_exporter.py +624 -0
- synapse/storage/graph_store.py +162 -0
- synapse/storage/vector_store.py +103 -0
- synapse_framework-0.2.4.dist-info/METADATA +415 -0
- synapse_framework-0.2.4.dist-info/RECORD +54 -0
- synapse_framework-0.2.4.dist-info/WHEEL +5 -0
- synapse_framework-0.2.4.dist-info/entry_points.txt +2 -0
- synapse_framework-0.2.4.dist-info/licenses/LICENSE +21 -0
- synapse_framework-0.2.4.dist-info/top_level.txt +1 -0
synapse/skills/skill.py
ADDED
|
@@ -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
|
+
]
|