synapse-sdk 1.0.0a11__py3-none-any.whl → 2026.1.1b2__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.

Potentially problematic release.


This version of synapse-sdk might be problematic. Click here for more details.

Files changed (261) hide show
  1. synapse_sdk/__init__.py +24 -0
  2. synapse_sdk/cli/__init__.py +9 -8
  3. synapse_sdk/cli/agent/__init__.py +25 -0
  4. synapse_sdk/cli/agent/config.py +104 -0
  5. synapse_sdk/cli/agent/select.py +197 -0
  6. synapse_sdk/cli/auth.py +104 -0
  7. synapse_sdk/cli/main.py +1025 -0
  8. synapse_sdk/cli/plugin/__init__.py +58 -0
  9. synapse_sdk/cli/plugin/create.py +566 -0
  10. synapse_sdk/cli/plugin/job.py +196 -0
  11. synapse_sdk/cli/plugin/publish.py +322 -0
  12. synapse_sdk/cli/plugin/run.py +131 -0
  13. synapse_sdk/cli/plugin/test.py +200 -0
  14. synapse_sdk/clients/README.md +239 -0
  15. synapse_sdk/clients/__init__.py +5 -0
  16. synapse_sdk/clients/_template.py +266 -0
  17. synapse_sdk/clients/agent/__init__.py +84 -29
  18. synapse_sdk/clients/agent/async_ray.py +289 -0
  19. synapse_sdk/clients/agent/container.py +83 -0
  20. synapse_sdk/clients/agent/plugin.py +101 -0
  21. synapse_sdk/clients/agent/ray.py +296 -39
  22. synapse_sdk/clients/backend/__init__.py +152 -12
  23. synapse_sdk/clients/backend/annotation.py +164 -22
  24. synapse_sdk/clients/backend/core.py +101 -0
  25. synapse_sdk/clients/backend/data_collection.py +292 -0
  26. synapse_sdk/clients/backend/hitl.py +87 -0
  27. synapse_sdk/clients/backend/integration.py +374 -46
  28. synapse_sdk/clients/backend/ml.py +134 -22
  29. synapse_sdk/clients/backend/models.py +247 -0
  30. synapse_sdk/clients/base.py +538 -59
  31. synapse_sdk/clients/exceptions.py +35 -7
  32. synapse_sdk/clients/pipeline/__init__.py +5 -0
  33. synapse_sdk/clients/pipeline/client.py +636 -0
  34. synapse_sdk/clients/protocols.py +178 -0
  35. synapse_sdk/clients/utils.py +86 -8
  36. synapse_sdk/clients/validation.py +58 -0
  37. synapse_sdk/enums.py +76 -0
  38. synapse_sdk/exceptions.py +168 -0
  39. synapse_sdk/integrations/__init__.py +74 -0
  40. synapse_sdk/integrations/_base.py +119 -0
  41. synapse_sdk/integrations/_context.py +53 -0
  42. synapse_sdk/integrations/ultralytics/__init__.py +78 -0
  43. synapse_sdk/integrations/ultralytics/_callbacks.py +126 -0
  44. synapse_sdk/integrations/ultralytics/_patches.py +124 -0
  45. synapse_sdk/loggers.py +476 -95
  46. synapse_sdk/mcp/MCP.md +69 -0
  47. synapse_sdk/mcp/__init__.py +48 -0
  48. synapse_sdk/mcp/__main__.py +6 -0
  49. synapse_sdk/mcp/config.py +349 -0
  50. synapse_sdk/mcp/prompts/__init__.py +4 -0
  51. synapse_sdk/mcp/resources/__init__.py +4 -0
  52. synapse_sdk/mcp/server.py +1352 -0
  53. synapse_sdk/mcp/tools/__init__.py +6 -0
  54. synapse_sdk/plugins/__init__.py +133 -9
  55. synapse_sdk/plugins/action.py +229 -0
  56. synapse_sdk/plugins/actions/__init__.py +82 -0
  57. synapse_sdk/plugins/actions/dataset/__init__.py +37 -0
  58. synapse_sdk/plugins/actions/dataset/action.py +471 -0
  59. synapse_sdk/plugins/actions/export/__init__.py +55 -0
  60. synapse_sdk/plugins/actions/export/action.py +183 -0
  61. synapse_sdk/plugins/actions/export/context.py +59 -0
  62. synapse_sdk/plugins/actions/inference/__init__.py +84 -0
  63. synapse_sdk/plugins/actions/inference/action.py +285 -0
  64. synapse_sdk/plugins/actions/inference/context.py +81 -0
  65. synapse_sdk/plugins/actions/inference/deployment.py +322 -0
  66. synapse_sdk/plugins/actions/inference/serve.py +252 -0
  67. synapse_sdk/plugins/actions/train/__init__.py +54 -0
  68. synapse_sdk/plugins/actions/train/action.py +326 -0
  69. synapse_sdk/plugins/actions/train/context.py +57 -0
  70. synapse_sdk/plugins/actions/upload/__init__.py +49 -0
  71. synapse_sdk/plugins/actions/upload/action.py +165 -0
  72. synapse_sdk/plugins/actions/upload/context.py +61 -0
  73. synapse_sdk/plugins/config.py +98 -0
  74. synapse_sdk/plugins/context/__init__.py +109 -0
  75. synapse_sdk/plugins/context/env.py +113 -0
  76. synapse_sdk/plugins/datasets/__init__.py +113 -0
  77. synapse_sdk/plugins/datasets/converters/__init__.py +76 -0
  78. synapse_sdk/plugins/datasets/converters/base.py +347 -0
  79. synapse_sdk/plugins/datasets/converters/yolo/__init__.py +9 -0
  80. synapse_sdk/plugins/datasets/converters/yolo/from_dm.py +468 -0
  81. synapse_sdk/plugins/datasets/converters/yolo/to_dm.py +381 -0
  82. synapse_sdk/plugins/datasets/formats/__init__.py +82 -0
  83. synapse_sdk/plugins/datasets/formats/dm.py +351 -0
  84. synapse_sdk/plugins/datasets/formats/yolo.py +240 -0
  85. synapse_sdk/plugins/decorators.py +83 -0
  86. synapse_sdk/plugins/discovery.py +790 -0
  87. synapse_sdk/plugins/docs/ACTION_DEV_GUIDE.md +933 -0
  88. synapse_sdk/plugins/docs/ARCHITECTURE.md +1225 -0
  89. synapse_sdk/plugins/docs/LOGGING_SYSTEM.md +683 -0
  90. synapse_sdk/plugins/docs/OVERVIEW.md +531 -0
  91. synapse_sdk/plugins/docs/PIPELINE_GUIDE.md +145 -0
  92. synapse_sdk/plugins/docs/README.md +513 -0
  93. synapse_sdk/plugins/docs/STEP.md +656 -0
  94. synapse_sdk/plugins/enums.py +70 -10
  95. synapse_sdk/plugins/errors.py +92 -0
  96. synapse_sdk/plugins/executors/__init__.py +43 -0
  97. synapse_sdk/plugins/executors/local.py +99 -0
  98. synapse_sdk/plugins/executors/ray/__init__.py +18 -0
  99. synapse_sdk/plugins/executors/ray/base.py +282 -0
  100. synapse_sdk/plugins/executors/ray/job.py +298 -0
  101. synapse_sdk/plugins/executors/ray/jobs_api.py +511 -0
  102. synapse_sdk/plugins/executors/ray/packaging.py +137 -0
  103. synapse_sdk/plugins/executors/ray/pipeline.py +792 -0
  104. synapse_sdk/plugins/executors/ray/task.py +257 -0
  105. synapse_sdk/plugins/models/__init__.py +26 -0
  106. synapse_sdk/plugins/models/logger.py +173 -0
  107. synapse_sdk/plugins/models/pipeline.py +25 -0
  108. synapse_sdk/plugins/pipelines/__init__.py +81 -0
  109. synapse_sdk/plugins/pipelines/action_pipeline.py +417 -0
  110. synapse_sdk/plugins/pipelines/context.py +107 -0
  111. synapse_sdk/plugins/pipelines/display.py +311 -0
  112. synapse_sdk/plugins/runner.py +114 -0
  113. synapse_sdk/plugins/schemas/__init__.py +19 -0
  114. synapse_sdk/plugins/schemas/results.py +152 -0
  115. synapse_sdk/plugins/steps/__init__.py +63 -0
  116. synapse_sdk/plugins/steps/base.py +128 -0
  117. synapse_sdk/plugins/steps/context.py +90 -0
  118. synapse_sdk/plugins/steps/orchestrator.py +128 -0
  119. synapse_sdk/plugins/steps/registry.py +103 -0
  120. synapse_sdk/plugins/steps/utils/__init__.py +20 -0
  121. synapse_sdk/plugins/steps/utils/logging.py +85 -0
  122. synapse_sdk/plugins/steps/utils/timing.py +71 -0
  123. synapse_sdk/plugins/steps/utils/validation.py +68 -0
  124. synapse_sdk/plugins/templates/__init__.py +50 -0
  125. synapse_sdk/plugins/templates/base/.gitignore.j2 +26 -0
  126. synapse_sdk/plugins/templates/base/.synapseignore.j2 +11 -0
  127. synapse_sdk/plugins/templates/base/README.md.j2 +26 -0
  128. synapse_sdk/plugins/templates/base/plugin/__init__.py.j2 +1 -0
  129. synapse_sdk/plugins/templates/base/pyproject.toml.j2 +14 -0
  130. synapse_sdk/plugins/templates/base/requirements.txt.j2 +1 -0
  131. synapse_sdk/plugins/templates/custom/plugin/main.py.j2 +18 -0
  132. synapse_sdk/plugins/templates/data_validation/plugin/validate.py.j2 +32 -0
  133. synapse_sdk/plugins/templates/export/plugin/export.py.j2 +36 -0
  134. synapse_sdk/plugins/templates/neural_net/plugin/inference.py.j2 +36 -0
  135. synapse_sdk/plugins/templates/neural_net/plugin/train.py.j2 +33 -0
  136. synapse_sdk/plugins/templates/post_annotation/plugin/post_annotate.py.j2 +32 -0
  137. synapse_sdk/plugins/templates/pre_annotation/plugin/pre_annotate.py.j2 +32 -0
  138. synapse_sdk/plugins/templates/smart_tool/plugin/auto_label.py.j2 +44 -0
  139. synapse_sdk/plugins/templates/upload/plugin/upload.py.j2 +35 -0
  140. synapse_sdk/plugins/testing/__init__.py +25 -0
  141. synapse_sdk/plugins/testing/sample_actions.py +98 -0
  142. synapse_sdk/plugins/types.py +206 -0
  143. synapse_sdk/plugins/upload.py +595 -64
  144. synapse_sdk/plugins/utils.py +325 -37
  145. synapse_sdk/shared/__init__.py +25 -0
  146. synapse_sdk/utils/__init__.py +1 -0
  147. synapse_sdk/utils/auth.py +74 -0
  148. synapse_sdk/utils/file/__init__.py +58 -0
  149. synapse_sdk/utils/file/archive.py +449 -0
  150. synapse_sdk/utils/file/checksum.py +167 -0
  151. synapse_sdk/utils/file/download.py +286 -0
  152. synapse_sdk/utils/file/io.py +129 -0
  153. synapse_sdk/utils/file/requirements.py +36 -0
  154. synapse_sdk/utils/network.py +168 -0
  155. synapse_sdk/utils/storage/__init__.py +238 -0
  156. synapse_sdk/utils/storage/config.py +188 -0
  157. synapse_sdk/utils/storage/errors.py +52 -0
  158. synapse_sdk/utils/storage/providers/__init__.py +13 -0
  159. synapse_sdk/utils/storage/providers/base.py +76 -0
  160. synapse_sdk/utils/storage/providers/gcs.py +168 -0
  161. synapse_sdk/utils/storage/providers/http.py +250 -0
  162. synapse_sdk/utils/storage/providers/local.py +126 -0
  163. synapse_sdk/utils/storage/providers/s3.py +177 -0
  164. synapse_sdk/utils/storage/providers/sftp.py +208 -0
  165. synapse_sdk/utils/storage/registry.py +125 -0
  166. synapse_sdk/utils/websocket.py +99 -0
  167. synapse_sdk-2026.1.1b2.dist-info/METADATA +715 -0
  168. synapse_sdk-2026.1.1b2.dist-info/RECORD +172 -0
  169. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/WHEEL +1 -1
  170. synapse_sdk-2026.1.1b2.dist-info/licenses/LICENSE +201 -0
  171. locale/en/LC_MESSAGES/messages.mo +0 -0
  172. locale/en/LC_MESSAGES/messages.po +0 -39
  173. locale/ko/LC_MESSAGES/messages.mo +0 -0
  174. locale/ko/LC_MESSAGES/messages.po +0 -34
  175. synapse_sdk/cli/create_plugin.py +0 -10
  176. synapse_sdk/clients/agent/core.py +0 -7
  177. synapse_sdk/clients/agent/service.py +0 -15
  178. synapse_sdk/clients/backend/dataset.py +0 -51
  179. synapse_sdk/clients/ray/__init__.py +0 -6
  180. synapse_sdk/clients/ray/core.py +0 -22
  181. synapse_sdk/clients/ray/serve.py +0 -20
  182. synapse_sdk/i18n.py +0 -35
  183. synapse_sdk/plugins/categories/__init__.py +0 -0
  184. synapse_sdk/plugins/categories/base.py +0 -235
  185. synapse_sdk/plugins/categories/data_validation/__init__.py +0 -0
  186. synapse_sdk/plugins/categories/data_validation/actions/__init__.py +0 -0
  187. synapse_sdk/plugins/categories/data_validation/actions/validation.py +0 -10
  188. synapse_sdk/plugins/categories/data_validation/templates/config.yaml +0 -3
  189. synapse_sdk/plugins/categories/data_validation/templates/plugin/__init__.py +0 -0
  190. synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +0 -5
  191. synapse_sdk/plugins/categories/decorators.py +0 -13
  192. synapse_sdk/plugins/categories/export/__init__.py +0 -0
  193. synapse_sdk/plugins/categories/export/actions/__init__.py +0 -0
  194. synapse_sdk/plugins/categories/export/actions/export.py +0 -10
  195. synapse_sdk/plugins/categories/import/__init__.py +0 -0
  196. synapse_sdk/plugins/categories/import/actions/__init__.py +0 -0
  197. synapse_sdk/plugins/categories/import/actions/import.py +0 -10
  198. synapse_sdk/plugins/categories/neural_net/__init__.py +0 -0
  199. synapse_sdk/plugins/categories/neural_net/actions/__init__.py +0 -0
  200. synapse_sdk/plugins/categories/neural_net/actions/deployment.py +0 -45
  201. synapse_sdk/plugins/categories/neural_net/actions/inference.py +0 -18
  202. synapse_sdk/plugins/categories/neural_net/actions/test.py +0 -10
  203. synapse_sdk/plugins/categories/neural_net/actions/train.py +0 -143
  204. synapse_sdk/plugins/categories/neural_net/templates/config.yaml +0 -12
  205. synapse_sdk/plugins/categories/neural_net/templates/plugin/__init__.py +0 -0
  206. synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +0 -4
  207. synapse_sdk/plugins/categories/neural_net/templates/plugin/test.py +0 -2
  208. synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py +0 -14
  209. synapse_sdk/plugins/categories/post_annotation/__init__.py +0 -0
  210. synapse_sdk/plugins/categories/post_annotation/actions/__init__.py +0 -0
  211. synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py +0 -10
  212. synapse_sdk/plugins/categories/post_annotation/templates/config.yaml +0 -3
  213. synapse_sdk/plugins/categories/post_annotation/templates/plugin/__init__.py +0 -0
  214. synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.py +0 -3
  215. synapse_sdk/plugins/categories/pre_annotation/__init__.py +0 -0
  216. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +0 -0
  217. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py +0 -10
  218. synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +0 -3
  219. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py +0 -0
  220. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py +0 -3
  221. synapse_sdk/plugins/categories/registry.py +0 -16
  222. synapse_sdk/plugins/categories/smart_tool/__init__.py +0 -0
  223. synapse_sdk/plugins/categories/smart_tool/actions/__init__.py +0 -0
  224. synapse_sdk/plugins/categories/smart_tool/actions/auto_label.py +0 -37
  225. synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +0 -7
  226. synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py +0 -0
  227. synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py +0 -11
  228. synapse_sdk/plugins/categories/templates.py +0 -32
  229. synapse_sdk/plugins/cli/__init__.py +0 -21
  230. synapse_sdk/plugins/cli/publish.py +0 -37
  231. synapse_sdk/plugins/cli/run.py +0 -67
  232. synapse_sdk/plugins/exceptions.py +0 -22
  233. synapse_sdk/plugins/models.py +0 -121
  234. synapse_sdk/plugins/templates/cookiecutter.json +0 -11
  235. synapse_sdk/plugins/templates/hooks/post_gen_project.py +0 -3
  236. synapse_sdk/plugins/templates/hooks/pre_prompt.py +0 -21
  237. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
  238. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
  239. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.gitignore +0 -27
  240. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.pre-commit-config.yaml +0 -7
  241. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/README.md +0 -5
  242. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +0 -6
  243. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
  244. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/plugin/__init__.py +0 -0
  245. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml +0 -13
  246. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +0 -1
  247. synapse_sdk/shared/enums.py +0 -8
  248. synapse_sdk/utils/debug.py +0 -5
  249. synapse_sdk/utils/file.py +0 -87
  250. synapse_sdk/utils/module_loading.py +0 -29
  251. synapse_sdk/utils/pydantic/__init__.py +0 -0
  252. synapse_sdk/utils/pydantic/config.py +0 -4
  253. synapse_sdk/utils/pydantic/errors.py +0 -33
  254. synapse_sdk/utils/pydantic/validators.py +0 -7
  255. synapse_sdk/utils/storage.py +0 -91
  256. synapse_sdk/utils/string.py +0 -11
  257. synapse_sdk-1.0.0a11.dist-info/LICENSE +0 -21
  258. synapse_sdk-1.0.0a11.dist-info/METADATA +0 -43
  259. synapse_sdk-1.0.0a11.dist-info/RECORD +0 -111
  260. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/entry_points.txt +0 -0
  261. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1225 @@
1
+ # Plugin System Architecture
2
+
3
+ This document provides a detailed technical overview of the Synapse SDK plugin system architecture, covering all major components, their interactions, and extension points.
4
+
5
+ ---
6
+
7
+ ## System Architecture
8
+
9
+ ### High-Level Overview
10
+
11
+ ```mermaid
12
+ flowchart TB
13
+ subgraph UserCode["User Code"]
14
+ decorator["@action decorator"]
15
+ baseaction["BaseAction subclass"]
16
+ end
17
+
18
+ subgraph PluginFramework["Plugin Framework"]
19
+ discovery["PluginDiscovery<br/>- from_path()<br/>- from_module()<br/>- get_action_class()"]
20
+ actionclass["Action Class<br/>- params_model<br/>- result_model<br/>- execute()"]
21
+ context["RuntimeContext<br/>- logger<br/>- env<br/>- job_id"]
22
+ executor["Executor<br/>- LocalExecutor<br/>- RayActorExecutor<br/>- RayJobExecutor"]
23
+ end
24
+
25
+ subgraph Config["Configuration"]
26
+ configyaml["config.yaml<br/>- actions<br/>- method"]
27
+ pluginenv["PluginEnvironment<br/>- from_environ()<br/>- from_file()"]
28
+ end
29
+
30
+ decorator -->|discover| discovery
31
+ baseaction -->|discover| discovery
32
+ discovery -->|load| actionclass
33
+ actionclass -->|instantiate| context
34
+ pluginenv -->|inject| context
35
+ context -->|execute via| executor
36
+
37
+ style UserCode fill:#e1f5fe
38
+ style PluginFramework fill:#f3e5f5
39
+ style Config fill:#fff3e0
40
+ ```
41
+
42
+ ### Component Interaction Flow
43
+
44
+ ```mermaid
45
+ flowchart TD
46
+ A["run_plugin(plugin_code, action, params, mode)"] --> B["_discover_action"]
47
+ B --> C["PluginDiscovery.get_action_class()"]
48
+ C --> D{"Select Executor"}
49
+
50
+ D -->|"mode='local'"| E1["LocalExecutor"]
51
+ D -->|"mode='task'"| E2["RayActorExecutor"]
52
+ D -->|"mode='job'"| E3["RayJobExecutor"]
53
+
54
+ E1 --> F["executor.execute()"]
55
+ E2 --> F
56
+ E3 --> F
57
+
58
+ F --> G["1. Validate params<br/>(Pydantic)"]
59
+ G --> H["2. Create RuntimeContext<br/>(logger, env)"]
60
+ H --> I["3. Instantiate action<br/>action_cls(params, ctx)"]
61
+ I --> J["4. Call execute()<br/>(user's method)"]
62
+ J --> K["5. Validate result<br/>(optional schema)"]
63
+ K --> L["Result"]
64
+
65
+ style A fill:#e8f5e9
66
+ style L fill:#e8f5e9
67
+ style D fill:#fff9c4
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Core Components
73
+
74
+ ### BaseAction[P] - Action Base Class
75
+
76
+ Location: `synapse_sdk/plugins/action.py`
77
+
78
+ The `BaseAction` class is a generic abstract base class parameterized by a Pydantic model type `P` representing the action's parameters.
79
+
80
+ #### Class Definition
81
+
82
+ ```python
83
+ from abc import ABC, abstractmethod
84
+ from typing import Generic, TypeVar
85
+ from pydantic import BaseModel
86
+
87
+ P = TypeVar('P', bound=BaseModel)
88
+
89
+ class BaseAction(ABC, Generic[P]):
90
+ # Class attributes (optional, can be injected from config)
91
+ action_name: str | None = None
92
+ category: PluginCategory | None = None
93
+
94
+ # Semantic type declarations for pipeline validation
95
+ input_type: type[DataType] | None = None
96
+ output_type: type[DataType] | None = None
97
+
98
+ # Auto-extracted from generic parameter
99
+ params_model: type[P]
100
+
101
+ # Optional result schema for validation
102
+ result_model: type[BaseModel] | type[NoResult] = NoResult
103
+
104
+ # Instance attributes (set in __init__)
105
+ params: P
106
+ ctx: RuntimeContext
107
+
108
+ @abstractmethod
109
+ def execute(self) -> Any:
110
+ """Execute the action logic."""
111
+ ...
112
+ ```
113
+
114
+ #### Generic Parameter Extraction
115
+
116
+ The `params_model` is automatically extracted from the generic type parameter via `__init_subclass__`:
117
+
118
+ ```python
119
+ class TrainParams(BaseModel):
120
+ epochs: int = 10
121
+
122
+ class TrainAction(BaseAction[TrainParams]): # P = TrainParams
123
+ pass
124
+
125
+ # After class creation:
126
+ TrainAction.params_model # == TrainParams (auto-extracted)
127
+ ```
128
+
129
+ #### Complete Implementation Example
130
+
131
+ ```python
132
+ from synapse_sdk.plugins import BaseAction
133
+ from synapse_sdk.plugins.enums import PluginCategory
134
+ from synapse_sdk.plugins.types import YOLODataset, ModelWeights
135
+ from pydantic import BaseModel, Field
136
+
137
+ class TrainParams(BaseModel):
138
+ """Training parameters."""
139
+ epochs: int = Field(default=100, ge=1, le=1000)
140
+ batch_size: int = Field(default=16, ge=1, le=256)
141
+ learning_rate: float = Field(default=0.001, gt=0)
142
+ model_size: str = Field(default='n', pattern='^[nsmlx]$')
143
+
144
+ class TrainResult(BaseModel):
145
+ """Training result."""
146
+ weights_path: str
147
+ final_loss: float
148
+ best_map: float
149
+
150
+ class YOLOTrainAction(BaseAction[TrainParams]):
151
+ """Train a YOLO model on a dataset."""
152
+
153
+ # Metadata (optional, can come from config.yaml)
154
+ action_name = 'train'
155
+ category = PluginCategory.NEURAL_NET
156
+
157
+ # Semantic types for pipeline compatibility
158
+ input_type = YOLODataset
159
+ output_type = ModelWeights
160
+
161
+ # Enable result validation
162
+ result_model = TrainResult
163
+
164
+ def execute(self) -> TrainResult:
165
+ # Enable automatic framework logging
166
+ self.autolog('ultralytics')
167
+
168
+ # Access parameters
169
+ epochs = self.params.epochs
170
+ batch_size = self.params.batch_size
171
+
172
+ # Log start event
173
+ self.log('train_start', {
174
+ 'epochs': epochs,
175
+ 'batch_size': batch_size,
176
+ })
177
+
178
+ # Training loop with progress tracking
179
+ model = self._create_model()
180
+
181
+ for epoch in range(epochs):
182
+ loss = self._train_epoch(model, epoch)
183
+ self.set_progress(epoch + 1, epochs, category='train')
184
+ self.set_metrics({'loss': loss}, category='epoch')
185
+
186
+ # Save model
187
+ weights_path = self._save_model(model)
188
+
189
+ # Log completion
190
+ self.log('train_complete', {'weights_path': weights_path})
191
+
192
+ return TrainResult(
193
+ weights_path=weights_path,
194
+ final_loss=model.final_loss,
195
+ best_map=model.best_map,
196
+ )
197
+
198
+ def _create_model(self):
199
+ # Model creation logic
200
+ ...
201
+
202
+ def _train_epoch(self, model, epoch):
203
+ # Training epoch logic
204
+ ...
205
+
206
+ def _save_model(self, model):
207
+ # Model saving logic
208
+ ...
209
+ ```
210
+
211
+ #### Method Reference
212
+
213
+ | Method | Description |
214
+ |--------|-------------|
215
+ | `execute()` | Abstract. Implement your action logic here. |
216
+ | `log(event, data, file=None)` | Log a structured event. |
217
+ | `set_progress(current, total, category=None)` | Update progress tracking. |
218
+ | `set_metrics(value, category)` | Record metrics for a category. |
219
+ | `autolog(framework)` | Enable automatic logging for ML frameworks. |
220
+
221
+ | Property | Description |
222
+ |----------|-------------|
223
+ | `logger` | Access the logger from context. |
224
+ | `params` | Validated parameters (Pydantic model instance). |
225
+ | `ctx` | RuntimeContext with services. |
226
+
227
+ ---
228
+
229
+ ### RuntimeContext - Dependency Injection Container
230
+
231
+ Location: `synapse_sdk/plugins/context/__init__.py`
232
+
233
+ The `RuntimeContext` provides runtime services to actions.
234
+
235
+ #### Structure
236
+
237
+ ```python
238
+ from dataclasses import dataclass
239
+ from typing import Any
240
+
241
+ @dataclass
242
+ class RuntimeContext:
243
+ """Runtime context for action execution."""
244
+
245
+ logger: BaseLogger # Logging interface
246
+ env: dict[str, Any] # Environment variables
247
+ job_id: str | None = None # Job tracking ID
248
+ client: BackendClient | None = None # API client
249
+ agent_client: AgentClient | None = None # Ray operations
250
+ checkpoint: dict | None = None # Pretrained model info
251
+ ```
252
+
253
+ #### Usage Patterns
254
+
255
+ ```python
256
+ def execute(self) -> dict:
257
+ # Logging
258
+ self.ctx.logger.info('Starting execution')
259
+ self.ctx.logger.warning('Rate limit approaching')
260
+ self.ctx.logger.error('Failed to connect')
261
+
262
+ # Environment access
263
+ api_key = self.ctx.env.get('API_KEY', '')
264
+ debug_mode = self.ctx.env.get('DEBUG', 'false') == 'true'
265
+
266
+ # Structured logging
267
+ self.ctx.log('process_start', {'input_size': 1000})
268
+
269
+ # Progress tracking (with optional category)
270
+ self.ctx.set_progress(50, 100) # 50% complete
271
+ self.ctx.set_progress(5, 10, category='download') # Category-specific
272
+
273
+ # Metrics recording
274
+ self.ctx.set_metrics({'loss': 0.05}, category='train')
275
+ self.ctx.set_metrics({'accuracy': 0.95}, category='eval')
276
+
277
+ # User-visible messages
278
+ self.ctx.log_message('Model training complete!')
279
+
280
+ # Developer debug events
281
+ self.ctx.log_dev_event('checkpoint_saved', {'epoch': 10})
282
+
283
+ # Finalize logging
284
+ self.ctx.end_log()
285
+
286
+ return {'status': 'done'}
287
+ ```
288
+
289
+ ---
290
+
291
+ ### PluginEnvironment - Configuration Management
292
+
293
+ Location: `synapse_sdk/plugins/context/env.py`
294
+
295
+ Type-safe configuration loading from environment or files.
296
+
297
+ #### Loading Methods
298
+
299
+ ```python
300
+ from synapse_sdk.plugins.context.env import PluginEnvironment
301
+
302
+ # From environment variables with prefix
303
+ # PLUGIN_API_KEY=xxx, PLUGIN_BATCH_SIZE=32, etc.
304
+ env = PluginEnvironment.from_environ(prefix='PLUGIN_')
305
+
306
+ # From TOML file
307
+ env = PluginEnvironment.from_file('config.toml')
308
+
309
+ # From explicit dictionary
310
+ env = PluginEnvironment({'API_KEY': 'xxx', 'BATCH_SIZE': 32})
311
+
312
+ # Merge environments (later values override)
313
+ merged = env1.merge(env2)
314
+ ```
315
+
316
+ #### Type-Safe Getters
317
+
318
+ ```python
319
+ # String (required - raises if missing)
320
+ api_key = env.get_str('API_KEY')
321
+
322
+ # String with default
323
+ mode = env.get_str('MODE', default='production')
324
+
325
+ # Integer
326
+ batch_size = env.get_int('BATCH_SIZE', default=32)
327
+
328
+ # Float
329
+ learning_rate = env.get_float('LEARNING_RATE', default=0.001)
330
+
331
+ # Boolean (true/false, 1/0, yes/no)
332
+ debug = env.get_bool('DEBUG', default=False)
333
+
334
+ # List (comma-separated string or actual list)
335
+ tags = env.get_list('TAGS', default=[])
336
+ ```
337
+
338
+ ---
339
+
340
+ ### PluginConfig & ActionConfig
341
+
342
+ Location: `synapse_sdk/plugins/config.py`
343
+
344
+ Configuration models for plugin metadata.
345
+
346
+ #### ActionConfig
347
+
348
+ ```python
349
+ from pydantic import BaseModel
350
+ from synapse_sdk.plugins.enums import RunMethod
351
+
352
+ class ActionConfig(BaseModel):
353
+ name: str # Display name
354
+ description: str = '' # Human-readable description
355
+ entrypoint: str # Module path (module:Class or module.Class)
356
+ method: RunMethod = RunMethod.TASK # Execution method
357
+ params_schema: type[BaseModel] | None = None # Parameter schema
358
+ input_type: str | None = None # Semantic input type name
359
+ output_type: str | None = None # Semantic output type name
360
+ ```
361
+
362
+ #### PluginConfig
363
+
364
+ ```python
365
+ class PluginConfig(BaseModel):
366
+ name: str # Plugin display name
367
+ code: str # Unique identifier
368
+ version: str = '0.1.0' # Semantic version
369
+ category: PluginCategory # Plugin category
370
+
371
+ # Package management
372
+ package_manager: PackageManager = PackageManager.PIP
373
+ package_manager_options: list[str] = []
374
+ wheels_dir: str = 'wheels'
375
+
376
+ # Runtime configuration
377
+ env: dict[str, Any] = {} # Default environment
378
+ runtime_env: dict[str, Any] = {} # Ray runtime_env
379
+
380
+ # Data type configuration
381
+ data_type: DataType | None = None # IMAGE, TEXT, VIDEO, etc.
382
+ tasks: list[str] = [] # Supported annotation tasks
383
+
384
+ # Smart tool configuration
385
+ annotation_category: AnnotationCategory | None = None
386
+ annotation_type: AnnotationType | None = None
387
+ smart_tool: SmartToolType | None = None
388
+
389
+ # Actions
390
+ actions: dict[str, ActionConfig] = {}
391
+ ```
392
+
393
+ #### config.yaml Example
394
+
395
+ ```yaml
396
+ name: YOLO Training Plugin
397
+ code: yolo_train
398
+ version: 1.0.0
399
+ category: neural_net
400
+ data_type: image
401
+ package_manager: uv
402
+
403
+ env:
404
+ DEFAULT_MODEL: yolov8n.pt
405
+ MAX_EPOCHS: 300
406
+
407
+ runtime_env:
408
+ pip:
409
+ - ultralytics>=8.0.0
410
+ - torch>=2.0.0
411
+
412
+ actions:
413
+ train:
414
+ name: Train YOLO Model
415
+ description: Train a YOLO model on a labeled dataset
416
+ entrypoint: yolo_plugin.actions:TrainAction
417
+ method: job
418
+ input_type: YOLODataset
419
+ output_type: ModelWeights
420
+
421
+ export:
422
+ name: Export Model
423
+ description: Export trained model to ONNX format
424
+ entrypoint: yolo_plugin.actions:ExportAction
425
+ method: task
426
+ input_type: ModelWeights
427
+ output_type: ONNXModel
428
+ ```
429
+
430
+ ---
431
+
432
+ ## Step-Based Workflow System
433
+
434
+ For complex multi-phase operations, use the step-based workflow system.
435
+
436
+ ### BaseStep[C] - Step Base Class
437
+
438
+ Location: `synapse_sdk/plugins/steps/base.py`
439
+
440
+ ```python
441
+ from abc import ABC, abstractmethod
442
+
443
+ class BaseStep[C: BaseStepContext](ABC):
444
+ """Abstract base for workflow steps."""
445
+
446
+ @property
447
+ @abstractmethod
448
+ def name(self) -> str:
449
+ """Unique step identifier."""
450
+ ...
451
+
452
+ @property
453
+ @abstractmethod
454
+ def progress_weight(self) -> float:
455
+ """Weight for progress calculation (0.0-1.0)."""
456
+ ...
457
+
458
+ @abstractmethod
459
+ def execute(self, context: C) -> StepResult:
460
+ """Execute the step."""
461
+ ...
462
+
463
+ def can_skip(self, context: C) -> bool:
464
+ """Optional skip condition."""
465
+ return False
466
+
467
+ def rollback(self, context: C, result: StepResult) -> None:
468
+ """Optional cleanup on workflow failure."""
469
+ pass
470
+ ```
471
+
472
+ ### StepResult - Step Outcome
473
+
474
+ ```python
475
+ from dataclasses import dataclass, field
476
+ from datetime import datetime
477
+ from typing import Any
478
+
479
+ @dataclass
480
+ class StepResult:
481
+ success: bool = True
482
+ data: dict[str, Any] = field(default_factory=dict)
483
+ error: str | None = None
484
+ rollback_data: dict[str, Any] = field(default_factory=dict)
485
+ skipped: bool = False
486
+ timestamp: datetime = field(default_factory=datetime.now)
487
+ ```
488
+
489
+ ### Creating Custom Steps
490
+
491
+ ```python
492
+ from synapse_sdk.plugins.steps import BaseStep, StepResult, BaseStepContext
493
+ from dataclasses import dataclass, field
494
+
495
+ # 1. Define context with shared state
496
+ @dataclass
497
+ class UploadContext(BaseStepContext):
498
+ """Context for upload workflow."""
499
+ files: list[str] = field(default_factory=list)
500
+ uploaded_urls: list[str] = field(default_factory=list)
501
+ total_bytes: int = 0
502
+
503
+ # 2. Implement steps
504
+ class ValidateFilesStep(BaseStep[UploadContext]):
505
+ @property
506
+ def name(self) -> str:
507
+ return 'validate_files'
508
+
509
+ @property
510
+ def progress_weight(self) -> float:
511
+ return 0.1 # 10% of workflow
512
+
513
+ def execute(self, context: UploadContext) -> StepResult:
514
+ # Validate each file exists
515
+ missing = []
516
+ for path in context.files:
517
+ if not os.path.exists(path):
518
+ missing.append(path)
519
+
520
+ if missing:
521
+ return StepResult(
522
+ success=False,
523
+ error=f"Missing files: {missing}",
524
+ )
525
+
526
+ # Calculate total size
527
+ context.total_bytes = sum(
528
+ os.path.getsize(f) for f in context.files
529
+ )
530
+
531
+ return StepResult(
532
+ success=True,
533
+ data={'total_bytes': context.total_bytes},
534
+ )
535
+
536
+
537
+ class UploadFilesStep(BaseStep[UploadContext]):
538
+ @property
539
+ def name(self) -> str:
540
+ return 'upload_files'
541
+
542
+ @property
543
+ def progress_weight(self) -> float:
544
+ return 0.8 # 80% of workflow
545
+
546
+ def execute(self, context: UploadContext) -> StepResult:
547
+ uploaded = []
548
+
549
+ for i, path in enumerate(context.files):
550
+ # Report per-file progress
551
+ context.set_progress(i, len(context.files))
552
+
553
+ url = upload_to_storage(path)
554
+ uploaded.append(url)
555
+ context.uploaded_urls.append(url)
556
+
557
+ return StepResult(
558
+ success=True,
559
+ data={'urls': uploaded},
560
+ rollback_data={'urls': uploaded}, # For cleanup
561
+ )
562
+
563
+ def rollback(self, context: UploadContext, result: StepResult) -> None:
564
+ # Clean up uploaded files on failure
565
+ for url in result.rollback_data.get('urls', []):
566
+ try:
567
+ delete_from_storage(url)
568
+ except Exception:
569
+ context.errors.append(f"Failed to delete: {url}")
570
+
571
+
572
+ class FinalizeStep(BaseStep[UploadContext]):
573
+ @property
574
+ def name(self) -> str:
575
+ return 'finalize'
576
+
577
+ @property
578
+ def progress_weight(self) -> float:
579
+ return 0.1 # 10% of workflow
580
+
581
+ def can_skip(self, context: UploadContext) -> bool:
582
+ # Skip if nothing was uploaded
583
+ return len(context.uploaded_urls) == 0
584
+
585
+ def execute(self, context: UploadContext) -> StepResult:
586
+ # Register uploads in database
587
+ register_uploads(context.uploaded_urls)
588
+
589
+ return StepResult(
590
+ success=True,
591
+ data={'finalized': True},
592
+ )
593
+ ```
594
+
595
+ ### StepRegistry - Step Management
596
+
597
+ Location: `synapse_sdk/plugins/steps/registry.py`
598
+
599
+ ```python
600
+ from synapse_sdk.plugins.steps import StepRegistry
601
+
602
+ # Create registry
603
+ registry = StepRegistry[UploadContext]()
604
+
605
+ # Register steps in order
606
+ registry.register(ValidateFilesStep())
607
+ registry.register(UploadFilesStep())
608
+ registry.register(FinalizeStep())
609
+
610
+ # Dynamic insertion
611
+ registry.insert_after('validate_files', CompressionStep())
612
+ registry.insert_before('finalize', VerifyStep())
613
+
614
+ # Remove step
615
+ registry.unregister('compression')
616
+
617
+ # Access steps
618
+ steps = registry.get_steps() # Returns copy of step list
619
+ total = registry.total_weight # Sum of all progress weights
620
+ ```
621
+
622
+ ### Orchestrator - Step Execution
623
+
624
+ Location: `synapse_sdk/plugins/steps/orchestrator.py`
625
+
626
+ ```python
627
+ from synapse_sdk.plugins.steps import Orchestrator, StepRegistry
628
+
629
+ # Setup
630
+ registry = StepRegistry[UploadContext]()
631
+ registry.register(ValidateFilesStep())
632
+ registry.register(UploadFilesStep())
633
+ registry.register(FinalizeStep())
634
+
635
+ # Create context
636
+ context = UploadContext(
637
+ runtime_ctx=runtime_ctx,
638
+ files=['/data/file1.jpg', '/data/file2.jpg'],
639
+ )
640
+
641
+ # Optional progress callback
642
+ def on_progress(current: int, total: int):
643
+ print(f"Progress: {current}/{total}%")
644
+
645
+ # Execute workflow
646
+ orchestrator = Orchestrator(
647
+ registry=registry,
648
+ context=context,
649
+ progress_callback=on_progress,
650
+ )
651
+
652
+ try:
653
+ result = orchestrator.execute()
654
+ # {'success': True, 'steps_executed': 3, 'steps_total': 3}
655
+ print(f"Uploaded: {context.uploaded_urls}")
656
+ except RuntimeError as e:
657
+ print(f"Workflow failed: {e}")
658
+ # Rollback already performed automatically
659
+ ```
660
+
661
+ ### Orchestrator Execution Flow
662
+
663
+ ```mermaid
664
+ flowchart TD
665
+ A["orchestrator.execute()"] --> B["For each step in registry"]
666
+ B --> C["Set context.current_step = step.name"]
667
+ C --> D{"step.can_skip(context)?"}
668
+
669
+ D -->|Yes| E["Create skipped StepResult"]
670
+ D -->|No| F["Try: result = step.execute(context)"]
671
+
672
+ F -->|Exception| G["result = StepResult(success=False, error)"]
673
+ F -->|Success| H["result from execute()"]
674
+
675
+ E --> I["Append result to context.step_results"]
676
+ G --> I
677
+ H --> I
678
+
679
+ I --> J{"result.success?"}
680
+
681
+ J -->|No| K["_rollback() in reverse order"]
682
+ K --> L["Raise RuntimeError"]
683
+
684
+ J -->|Yes| M["Update progress via callback"]
685
+ M --> N{"More steps?"}
686
+
687
+ N -->|Yes| B
688
+ N -->|No| O["Clear context.current_step"]
689
+ O --> P["Return success summary"]
690
+
691
+ style A fill:#e8f5e9
692
+ style P fill:#e8f5e9
693
+ style L fill:#ffcdd2
694
+ style D fill:#fff9c4
695
+ style J fill:#fff9c4
696
+ style N fill:#fff9c4
697
+ ```
698
+
699
+ ### Utility Steps
700
+
701
+ #### LoggingStep - Execution Logging
702
+
703
+ ```python
704
+ from synapse_sdk.plugins.steps.utils import LoggingStep
705
+
706
+ # Wrap any step with logging
707
+ logged_upload = LoggingStep(UploadFilesStep())
708
+
709
+ # Will log:
710
+ # - step_start: {step: 'logged_upload_files'}
711
+ # - step_end: {step: 'logged_upload_files', elapsed: 1.23, success: True}
712
+ ```
713
+
714
+ #### TimingStep - Execution Timing
715
+
716
+ ```python
717
+ from synapse_sdk.plugins.steps.utils import TimingStep
718
+
719
+ # Wrap any step with timing
720
+ timed_upload = TimingStep(UploadFilesStep())
721
+
722
+ # Result will include:
723
+ # result.data['duration_seconds'] = 1.234567
724
+ ```
725
+
726
+ #### ValidationStep - Context Validation
727
+
728
+ ```python
729
+ from synapse_sdk.plugins.steps.utils import ValidationStep
730
+
731
+ def validate_files_exist(context: UploadContext) -> tuple[bool, str | None]:
732
+ if not context.files:
733
+ return False, "No files provided"
734
+ return True, None
735
+
736
+ # Create validation step
737
+ validate_step = ValidationStep(
738
+ validator=validate_files_exist,
739
+ name='validate_input',
740
+ progress_weight=0.05,
741
+ )
742
+ ```
743
+
744
+ ---
745
+
746
+ ## Action Specializations
747
+
748
+ ### BaseTrainAction
749
+
750
+ Location: `synapse_sdk/plugins/actions/train/`
751
+
752
+ Base class for ML training actions with step-based workflow support.
753
+
754
+ ```python
755
+ from synapse_sdk.plugins.actions.train import BaseTrainAction, TrainContext
756
+ from synapse_sdk.plugins.steps import StepRegistry
757
+
758
+ class MyTrainAction(BaseTrainAction[TrainParams]):
759
+ def setup_steps(self, registry: StepRegistry[TrainContext]) -> None:
760
+ """Override to register training steps."""
761
+ registry.register(PrepareDatasetStep())
762
+ registry.register(InitModelStep())
763
+ registry.register(TrainStep())
764
+ registry.register(SaveModelStep())
765
+
766
+ def execute(self) -> dict:
767
+ # Base class handles step orchestration
768
+ return super().execute()
769
+ ```
770
+
771
+ TrainContext provides:
772
+ - `dataset`: Loaded dataset reference
773
+ - `model_path`: Path to model weights
774
+ - `model`: Model instance
775
+ - Progress categories: `DATASET`, `TRAIN`, `MODEL_UPLOAD`
776
+
777
+ ### BaseExportAction
778
+
779
+ Location: `synapse_sdk/plugins/actions/export/`
780
+
781
+ ```python
782
+ from synapse_sdk.plugins.actions.export import BaseExportAction, ExportContext
783
+
784
+ class ONNXExportAction(BaseExportAction[ExportParams]):
785
+ def execute(self) -> dict:
786
+ # Load model
787
+ model = load_model(self.params.model_path)
788
+
789
+ # Export to ONNX
790
+ self.set_progress(0, 100, category='export')
791
+ output_path = export_to_onnx(model, self.params.output_path)
792
+ self.set_progress(100, 100, category='export')
793
+
794
+ return {'output_path': output_path}
795
+ ```
796
+
797
+ ### BaseUploadAction
798
+
799
+ Location: `synapse_sdk/plugins/actions/upload/`
800
+
801
+ ```python
802
+ from synapse_sdk.plugins.actions.upload import BaseUploadAction, UploadContext
803
+
804
+ class S3UploadAction(BaseUploadAction[UploadParams]):
805
+ def setup_steps(self, registry: StepRegistry[UploadContext]) -> None:
806
+ registry.register(ValidateFilesStep())
807
+ registry.register(UploadToS3Step())
808
+ registry.register(VerifyUploadStep())
809
+ ```
810
+
811
+ UploadContext provides:
812
+ - `organized_files`: Files prepared for upload
813
+ - `uploaded_files`: Successfully uploaded file references
814
+ - `data_units`: Data unit tracking
815
+ - Progress categories: `VALIDATION`, `UPLOAD`, `FINALIZATION`
816
+
817
+ ### BaseInferenceAction & BaseDeploymentAction
818
+
819
+ Location: `synapse_sdk/plugins/actions/inference/`
820
+
821
+ ```python
822
+ from synapse_sdk.plugins.actions.inference import (
823
+ BaseInferenceAction,
824
+ BaseDeploymentAction,
825
+ InferenceContext,
826
+ )
827
+
828
+ class YOLOInferenceAction(BaseInferenceAction[InferenceParams]):
829
+ def execute(self) -> dict:
830
+ # Load model
831
+ self.set_progress(0, 100, category='model_download')
832
+ model = load_model(self.params.model_path)
833
+ self.set_progress(100, 100, category='model_download')
834
+
835
+ # Run inference
836
+ results = []
837
+ images = self.params.images
838
+ for i, image in enumerate(images):
839
+ self.set_progress(i, len(images), category='inference')
840
+ result = model.predict(image)
841
+ results.append(result)
842
+
843
+ return {'predictions': results}
844
+ ```
845
+
846
+ ---
847
+
848
+ ## Executor System
849
+
850
+ ### LocalExecutor
851
+
852
+ Location: `synapse_sdk/plugins/executors/local.py`
853
+
854
+ Synchronous, in-process execution for development.
855
+
856
+ ```python
857
+ from synapse_sdk.plugins.executors import LocalExecutor
858
+
859
+ executor = LocalExecutor(
860
+ env={'DEBUG': 'true', 'API_KEY': 'xxx'},
861
+ job_id='local-test-001',
862
+ )
863
+
864
+ result = executor.execute(
865
+ action_cls=TrainAction,
866
+ params={'epochs': 10, 'batch_size': 32},
867
+ )
868
+
869
+ # Result is returned directly
870
+ print(result)
871
+ ```
872
+
873
+ ### RayActorExecutor
874
+
875
+ Location: `synapse_sdk/plugins/executors/ray/task.py`
876
+
877
+ Persistent Ray Actor for serial task execution.
878
+
879
+ ```python
880
+ from synapse_sdk.plugins.executors.ray import RayActorExecutor
881
+
882
+ executor = RayActorExecutor(
883
+ working_dir='/path/to/plugin', # Plugin source code
884
+ num_gpus=1, # GPU allocation per task
885
+ num_cpus=4, # CPU allocation per task
886
+ runtime_env={ # Additional Ray runtime_env
887
+ 'pip': ['torch>=2.0'],
888
+ },
889
+ )
890
+
891
+ # Execute action on Ray cluster
892
+ result = executor.execute(
893
+ action_cls=TrainAction,
894
+ params={'epochs': 100},
895
+ )
896
+
897
+ # Cleanup actor
898
+ executor.shutdown()
899
+ ```
900
+
901
+ ### RayJobExecutor
902
+
903
+ Location: `synapse_sdk/plugins/executors/ray/job.py`
904
+
905
+ Full job isolation via Ray Job API.
906
+
907
+ ```python
908
+ from synapse_sdk.plugins.executors.ray import RayJobExecutor
909
+
910
+ executor = RayJobExecutor(
911
+ dashboard_url='http://ray-head:8265',
912
+ working_dir='/path/to/plugin',
913
+ runtime_env={
914
+ 'pip': ['ultralytics>=8.0'],
915
+ 'env_vars': {'CUDA_VISIBLE_DEVICES': '0'},
916
+ },
917
+ )
918
+
919
+ # Submit job (returns immediately)
920
+ job_id = executor.submit(
921
+ action_name='train',
922
+ params={'epochs': 100},
923
+ )
924
+
925
+ # Monitor status
926
+ status = executor.get_status(job_id)
927
+ # Returns: 'PENDING', 'RUNNING', 'SUCCEEDED', 'FAILED', 'STOPPED'
928
+
929
+ # Stream logs
930
+ for line in executor.stream_logs(job_id):
931
+ print(line)
932
+
933
+ # Wait for completion with timeout
934
+ result = executor.wait(job_id, timeout_seconds=3600)
935
+
936
+ # Or get logs after completion
937
+ logs = executor.get_logs(job_id)
938
+ ```
939
+
940
+ ### RayPipelineExecutor
941
+
942
+ Location: `synapse_sdk/plugins/executors/ray/pipeline.py`
943
+
944
+ Multi-action workflow execution. See [PIPELINE_GUIDE.md](PIPELINE_GUIDE.md) for details.
945
+
946
+ ```python
947
+ from synapse_sdk.plugins.pipelines import ActionPipeline
948
+ from synapse_sdk.plugins.executors.ray import RayPipelineExecutor
949
+
950
+ # Define pipeline
951
+ pipeline = ActionPipeline([
952
+ DownloadAction,
953
+ PreprocessAction,
954
+ TrainAction,
955
+ ExportAction,
956
+ ])
957
+
958
+ # Create executor
959
+ executor = RayPipelineExecutor(
960
+ ray_address='auto',
961
+ working_dir='/path/to/plugin',
962
+ pipeline_service_url='http://localhost:8100',
963
+ )
964
+
965
+ # Submit pipeline
966
+ run_id = pipeline.submit({'dataset_id': 123}, executor)
967
+
968
+ # Monitor progress
969
+ progress = executor.get_progress(run_id)
970
+
971
+ # Wait for result
972
+ result = pipeline.wait(run_id, executor)
973
+ ```
974
+
975
+ ---
976
+
977
+ ## Plugin Discovery System
978
+
979
+ Location: `synapse_sdk/plugins/discovery.py`
980
+
981
+ ### PluginDiscovery Class
982
+
983
+ ```python
984
+ from synapse_sdk.plugins.discovery import PluginDiscovery
985
+
986
+ # Load from config file
987
+ discovery = PluginDiscovery.from_path('/path/to/plugin')
988
+
989
+ # Load from Python module
990
+ discovery = PluginDiscovery.from_module('my_plugin')
991
+
992
+ # List available actions
993
+ actions = discovery.list_actions()
994
+ # ['train', 'export', 'inference']
995
+
996
+ # Get action class with metadata injection
997
+ action_cls = discovery.get_action_class('train')
998
+ # action_cls.action_name == 'train' (injected from config)
999
+ # action_cls.category == PluginCategory.NEURAL_NET
1000
+
1001
+ # Get params model for validation
1002
+ params_model = discovery.get_action_params_model('train')
1003
+
1004
+ # Get result model
1005
+ result_model = discovery.get_action_result_model('train')
1006
+
1007
+ # Get semantic types
1008
+ input_type = discovery.get_action_input_type('train') # YOLODataset
1009
+ output_type = discovery.get_action_output_type('train') # ModelWeights
1010
+ ```
1011
+
1012
+ ### UI Schema Generation
1013
+
1014
+ Generate FormKit UI schemas from Pydantic models:
1015
+
1016
+ ```python
1017
+ # Get UI schema for action params
1018
+ ui_schema = discovery.get_action_ui_schema('train')
1019
+
1020
+ # Returns FormKit-compatible schema:
1021
+ # {
1022
+ # '$formkit': 'group',
1023
+ # 'children': [
1024
+ # {
1025
+ # '$formkit': 'number',
1026
+ # 'name': 'epochs',
1027
+ # 'label': 'Epochs',
1028
+ # 'value': 10,
1029
+ # 'validation': 'required|min:1|max:1000',
1030
+ # },
1031
+ # ...
1032
+ # ]
1033
+ # }
1034
+ ```
1035
+
1036
+ ### Config Synchronization
1037
+
1038
+ Update config.yaml from discovered code:
1039
+
1040
+ ```python
1041
+ # Discover actions and update config file
1042
+ PluginDiscovery.sync_config_file('/path/to/plugin/config.yaml')
1043
+
1044
+ # This will:
1045
+ # 1. Scan Python files for BaseAction subclasses
1046
+ # 2. Extract entrypoints, input_type, output_type
1047
+ # 3. Add new actions to config.yaml
1048
+ # 4. Update existing action entrypoints
1049
+ ```
1050
+
1051
+ ### Static Discovery (AST-Based)
1052
+
1053
+ Discover actions without importing (safer for broken modules):
1054
+
1055
+ ```python
1056
+ # Returns list of discovered action info
1057
+ actions = PluginDiscovery.discover_actions('/path/to/plugin')
1058
+
1059
+ # Each action contains:
1060
+ # {
1061
+ # 'name': 'train',
1062
+ # 'entrypoint': 'my_plugin.actions:TrainAction',
1063
+ # 'input_type': 'YOLODataset',
1064
+ # 'output_type': 'ModelWeights',
1065
+ # }
1066
+ ```
1067
+
1068
+ ---
1069
+
1070
+ ## Type System
1071
+
1072
+ Location: `synapse_sdk/plugins/types.py`
1073
+
1074
+ ### DataType Hierarchy
1075
+
1076
+ ```python
1077
+ class DataType:
1078
+ """Base class for semantic data types."""
1079
+ name: ClassVar[str]
1080
+ format: ClassVar[str | None] = None
1081
+ description: ClassVar[str] = ''
1082
+
1083
+ @classmethod
1084
+ def is_compatible_with(cls, other: type[DataType]) -> bool:
1085
+ """Check if this type is compatible with another."""
1086
+ return issubclass(cls, other) or issubclass(other, cls)
1087
+
1088
+ # Built-in types
1089
+ class Dataset(DataType):
1090
+ name = 'dataset'
1091
+
1092
+ class YOLODataset(Dataset):
1093
+ name = 'yolo_dataset'
1094
+ format = 'yolo'
1095
+
1096
+ class COCODataset(Dataset):
1097
+ name = 'coco_dataset'
1098
+ format = 'coco'
1099
+
1100
+ class Model(DataType):
1101
+ name = 'model'
1102
+
1103
+ class ModelWeights(Model):
1104
+ name = 'model_weights'
1105
+
1106
+ class ONNXModel(Model):
1107
+ name = 'onnx_model'
1108
+ format = 'onnx'
1109
+ ```
1110
+
1111
+ ### Creating Custom Types
1112
+
1113
+ ```python
1114
+ from synapse_sdk.plugins.types import DataType
1115
+
1116
+ class CustomDataset(DataType):
1117
+ name = 'custom_dataset'
1118
+ format = 'custom'
1119
+ description = 'My custom dataset format'
1120
+
1121
+ class CustomModel(DataType):
1122
+ name = 'custom_model'
1123
+ format = 'custom'
1124
+ ```
1125
+
1126
+ ### Pipeline Compatibility
1127
+
1128
+ Types enable automatic pipeline validation:
1129
+
1130
+ ```python
1131
+ from synapse_sdk.plugins.pipelines import ActionPipeline
1132
+
1133
+ # This validates that:
1134
+ # - Action1.output_type is compatible with Action2.input_type
1135
+ # - etc.
1136
+ pipeline = ActionPipeline([Action1, Action2, Action3])
1137
+ ```
1138
+
1139
+ ---
1140
+
1141
+ ## Directory Structure
1142
+
1143
+ ```
1144
+ synapse_sdk/plugins/
1145
+ ├── __init__.py # Public API exports (136 items)
1146
+ ├── action.py # BaseAction[P], NoResult, validate_result
1147
+ ├── decorators.py # @action decorator
1148
+ ├── config.py # PluginConfig, ActionConfig
1149
+ ├── discovery.py # PluginDiscovery class
1150
+ ├── runner.py # run_plugin() entry point
1151
+ ├── types.py # DataType hierarchy
1152
+ ├── enums.py # PluginCategory, RunMethod, etc.
1153
+ ├── errors.py # Exception hierarchy
1154
+ ├── utils.py # Utility functions
1155
+
1156
+ ├── context/
1157
+ │ ├── __init__.py # RuntimeContext
1158
+ │ └── env.py # PluginEnvironment
1159
+
1160
+ ├── steps/
1161
+ │ ├── __init__.py # Step exports
1162
+ │ ├── base.py # BaseStep[C], StepResult
1163
+ │ ├── context.py # BaseStepContext
1164
+ │ ├── registry.py # StepRegistry[C]
1165
+ │ ├── orchestrator.py # Orchestrator[C]
1166
+ │ └── utils/
1167
+ │ ├── __init__.py
1168
+ │ ├── logging.py # LoggingStep
1169
+ │ ├── timing.py # TimingStep
1170
+ │ └── validation.py # ValidationStep
1171
+
1172
+ ├── actions/
1173
+ │ ├── __init__.py # Action exports
1174
+ │ ├── train/ # BaseTrainAction, TrainContext
1175
+ │ ├── export/ # BaseExportAction, ExportContext
1176
+ │ ├── upload/ # BaseUploadAction, UploadContext
1177
+ │ ├── inference/ # BaseInferenceAction, BaseDeploymentAction
1178
+ │ └── dataset/ # DatasetAction
1179
+
1180
+ ├── executors/
1181
+ │ ├── __init__.py # ExecutorProtocol, LocalExecutor
1182
+ │ ├── local.py # LocalExecutor
1183
+ │ └── ray/
1184
+ │ ├── __init__.py # Ray executor exports
1185
+ │ ├── base.py # BaseRayExecutor
1186
+ │ ├── task.py # RayTaskExecutor, RayActorExecutor
1187
+ │ ├── job.py # RayJobExecutor
1188
+ │ ├── pipeline.py # RayPipelineExecutor
1189
+ │ └── packaging.py # Dependency packaging
1190
+
1191
+ ├── pipelines/
1192
+ │ ├── __init__.py # Pipeline exports
1193
+ │ ├── action_pipeline.py # ActionPipeline
1194
+ │ ├── context.py # PipelineContext
1195
+ │ ├── display.py # Progress display utilities
1196
+ │ └── (see docs/PIPELINE_GUIDE.md)
1197
+
1198
+ ├── models/
1199
+ │ ├── logger.py # LogLevel, ActionProgress, PipelineProgress
1200
+ │ └── pipeline.py # RunStatus, ActionStatus
1201
+
1202
+ ├── schemas/
1203
+ │ └── results.py # WeightsResult, TrainResult, etc.
1204
+
1205
+ ├── datasets/
1206
+ │ ├── formats/ # Format definitions (DM, YOLO)
1207
+ │ └── converters/ # Format converters
1208
+
1209
+ ├── templates/ # Plugin generation templates
1210
+ │ └── base/ # Base plugin templates
1211
+
1212
+ └── testing/
1213
+ └── sample_actions.py # Test fixtures
1214
+ ```
1215
+
1216
+ ---
1217
+
1218
+ ## Next Steps
1219
+
1220
+ - **[OVERVIEW.md](OVERVIEW.md)**: Quick start and tutorials
1221
+ - **[ACTION_DEV_GUIDE.md](ACTION_DEV_GUIDE.md)**: Action development guide
1222
+ - **[STEP.md](STEP.md)**: Step implementations guide
1223
+ - **[LOGGING_SYSTEM.md](LOGGING_SYSTEM.md)**: Logging and progress tracking
1224
+ - **[README.md](README.md)**: Extension guide and best practices
1225
+ - **[PIPELINE_GUIDE.md](PIPELINE_GUIDE.md)**: Multi-action pipelines