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,326 @@
1
+ """Train action base class with optional step support."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING, Any, TypeVar
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+ from synapse_sdk.plugins.action import BaseAction
11
+ from synapse_sdk.plugins.actions.train.context import TrainContext
12
+ from synapse_sdk.plugins.enums import PluginCategory
13
+ from synapse_sdk.plugins.steps import Orchestrator, StepRegistry
14
+
15
+ P = TypeVar('P', bound=BaseModel)
16
+
17
+ if TYPE_CHECKING:
18
+ from synapse_sdk.clients.backend import BackendClient
19
+
20
+
21
+ class BaseTrainParams(BaseModel):
22
+ """Base parameters for training actions.
23
+
24
+ Provides common fields used across training workflows.
25
+ Extend this class to add plugin-specific training parameters.
26
+
27
+ Attributes:
28
+ checkpoint: Optional model ID to use as starting checkpoint.
29
+
30
+ Example:
31
+ >>> class MyTrainParams(BaseTrainParams):
32
+ ... epochs: int = 100
33
+ ... batch_size: int = 32
34
+ """
35
+
36
+ checkpoint: int | None = Field(default=None, description='Checkpoint model ID to resume from')
37
+
38
+
39
+ class TrainProgressCategories:
40
+ """Standard progress category names for training workflows.
41
+
42
+ Use these constants with set_progress() to track multi-phase training:
43
+ - DATASET: Data loading and preprocessing
44
+ - TRAIN: Model training iterations
45
+ - MODEL_UPLOAD: Final model upload to backend
46
+
47
+ Example:
48
+ >>> self.set_progress(1, 10, TrainProgressCategories.DATASET)
49
+ >>> self.set_progress(50, 100, TrainProgressCategories.TRAIN)
50
+ """
51
+
52
+ DATASET: str = 'dataset'
53
+ TRAIN: str = 'train'
54
+ MODEL_UPLOAD: str = 'model_upload'
55
+
56
+
57
+ class BaseTrainAction(BaseAction[P]):
58
+ """Base class for training actions.
59
+
60
+ Provides helper methods for common training workflows:
61
+ dataset fetching, model creation, and progress tracking.
62
+
63
+ Supports two execution modes:
64
+ 1. Simple execute: Override execute() directly for simple workflows
65
+ 2. Step-based: Override setup_steps() to register workflow steps
66
+
67
+ If setup_steps() registers any steps, the step-based workflow
68
+ takes precedence and execute() is not called directly.
69
+
70
+ Attributes:
71
+ category: Plugin category (defaults to NEURAL_NET).
72
+ progress: Standard progress category names.
73
+
74
+ Example (without result schema):
75
+ >>> class MyTrainAction(BaseTrainAction[MyParams]):
76
+ ... def execute(self) -> dict[str, Any]:
77
+ ... return {'weights_path': '/model.pt'}
78
+
79
+ Example (with result schema):
80
+ >>> class TrainResult(BaseModel):
81
+ ... weights_path: str
82
+ ... final_loss: float
83
+ >>>
84
+ >>> class MyTrainAction(BaseTrainAction[MyParams]):
85
+ ... result_model = TrainResult
86
+ ...
87
+ ... def execute(self) -> TrainResult:
88
+ ... return TrainResult(weights_path='/model.pt', final_loss=0.1)
89
+
90
+ Example (step-based):
91
+ >>> class MyTrainAction(BaseTrainAction[MyParams]):
92
+ ... def setup_steps(self, registry: StepRegistry[TrainContext]) -> None:
93
+ ... registry.register(LoadDatasetStep())
94
+ ... registry.register(TrainStep())
95
+ ... registry.register(UploadModelStep())
96
+ """
97
+
98
+ category = PluginCategory.NEURAL_NET
99
+ progress = TrainProgressCategories()
100
+
101
+ def autolog(self, framework: str) -> None:
102
+ """Enable automatic logging for an ML framework.
103
+
104
+ Call this before creating model objects. The SDK will automatically
105
+ attach callbacks to log progress, metrics, and artifacts.
106
+
107
+ Supported frameworks:
108
+ - 'ultralytics': YOLO object detection models
109
+
110
+ Args:
111
+ framework: Framework name (e.g., 'ultralytics').
112
+
113
+ Raises:
114
+ ValueError: If framework is not recognized.
115
+ ImportError: If framework package is not installed.
116
+
117
+ Example:
118
+ >>> def execute(self):
119
+ ... self.autolog('ultralytics')
120
+ ... model = YOLO('yolov8n.pt') # Callbacks auto-attached
121
+ ... model.train(epochs=100) # Metrics logged automatically
122
+ """
123
+ from synapse_sdk.integrations import autolog as _autolog
124
+
125
+ _autolog(framework, self)
126
+
127
+ @property
128
+ def client(self) -> BackendClient:
129
+ """Backend client from context.
130
+
131
+ Returns:
132
+ BackendClient instance.
133
+
134
+ Raises:
135
+ RuntimeError: If no client in context.
136
+ """
137
+ if self.ctx.client is None:
138
+ raise RuntimeError(
139
+ 'No client in context. Either provide a client via RuntimeContext '
140
+ 'or override the helper methods (get_dataset, create_model, get_model).'
141
+ )
142
+ return self.ctx.client
143
+
144
+ def setup_steps(self, registry: StepRegistry[TrainContext]) -> None:
145
+ """Register workflow steps for step-based execution.
146
+
147
+ Override this method to register custom steps for your training workflow.
148
+ If steps are registered, step-based execution takes precedence.
149
+
150
+ Args:
151
+ registry: StepRegistry to register steps with.
152
+
153
+ Example:
154
+ >>> def setup_steps(self, registry: StepRegistry[TrainContext]) -> None:
155
+ ... registry.register(LoadDatasetStep())
156
+ ... registry.register(TrainStep())
157
+ ... registry.register(UploadModelStep())
158
+ """
159
+ pass # Default: no steps, uses simple execute()
160
+
161
+ def create_context(self) -> TrainContext:
162
+ """Create training context for step-based workflow.
163
+
164
+ Override to customize context creation or add additional state.
165
+
166
+ Returns:
167
+ TrainContext instance with params and runtime context.
168
+ """
169
+ params_dict = self.params.model_dump() if hasattr(self.params, 'model_dump') else dict(self.params)
170
+ return TrainContext(
171
+ runtime_ctx=self.ctx,
172
+ params=params_dict,
173
+ )
174
+
175
+ def run(self) -> Any:
176
+ """Run the action, using steps if registered.
177
+
178
+ This method is called by executors. It checks if steps are
179
+ registered and uses step-based execution if so.
180
+
181
+ Returns:
182
+ Action result (dict or any return type).
183
+ """
184
+ # Check if steps are registered
185
+ registry: StepRegistry[TrainContext] = StepRegistry()
186
+ self.setup_steps(registry)
187
+
188
+ if registry:
189
+ # Step-based execution
190
+ context = self.create_context()
191
+ orchestrator: Orchestrator[TrainContext] = Orchestrator(
192
+ registry=registry,
193
+ context=context,
194
+ progress_callback=lambda curr, total: self.set_progress(curr, total),
195
+ )
196
+ result = orchestrator.execute()
197
+
198
+ # Add context data to result
199
+ if context.model:
200
+ result['model'] = context.model
201
+
202
+ return result
203
+
204
+ # Simple execute mode
205
+ return self.execute()
206
+
207
+ def get_dataset(self) -> dict[str, Any]:
208
+ """Fetch training dataset from backend.
209
+
210
+ Default implementation uses params.dataset_id to fetch
211
+ via client.get_data_collection(). Override for custom behavior.
212
+
213
+ Returns:
214
+ Dataset metadata dictionary.
215
+
216
+ Raises:
217
+ ValueError: If params.dataset_id is not set.
218
+ RuntimeError: If no client in context.
219
+
220
+ Example:
221
+ >>> # Override for S3:
222
+ >>> def get_dataset(self) -> dict[str, Any]:
223
+ ... return download_from_s3(self.params.s3_path)
224
+ """
225
+ dataset_id = getattr(self.params, 'dataset_id', None)
226
+ if dataset_id is None:
227
+ raise ValueError(
228
+ 'params.dataset_id is required for default get_dataset(). '
229
+ 'Either set dataset_id in your params model or override get_dataset().'
230
+ )
231
+ return self.client.get_data_collection(dataset_id)
232
+
233
+ def create_model(self, path: str, **kwargs: Any) -> dict[str, Any]:
234
+ """Upload trained model to backend.
235
+
236
+ Default implementation uploads via client.create_model().
237
+ Override for custom behavior (e.g., MLflow, S3).
238
+
239
+ Args:
240
+ path: Local path to model artifacts.
241
+ **kwargs: Additional fields for model creation.
242
+
243
+ Returns:
244
+ Created model metadata dictionary.
245
+
246
+ Raises:
247
+ RuntimeError: If no client in context.
248
+
249
+ Example:
250
+ >>> model = self.create_model('./model', name='my-model')
251
+ """
252
+ return self.client.create_model({
253
+ 'file': path,
254
+ **kwargs,
255
+ })
256
+
257
+ def get_model(self, model_id: int) -> dict[str, Any]:
258
+ """Retrieve existing model by ID.
259
+
260
+ Args:
261
+ model_id: Model identifier.
262
+
263
+ Returns:
264
+ Model metadata dictionary.
265
+
266
+ Raises:
267
+ RuntimeError: If no client in context.
268
+ """
269
+ return self.client.get_model(model_id)
270
+
271
+ def get_checkpoint(self) -> dict[str, Any] | None:
272
+ """Get checkpoint for training, either from context or by fetching from backend.
273
+
274
+ This method handles checkpoint resolution in the following order:
275
+ 1. If ctx.checkpoint is already set (remote mode), returns it directly
276
+ 2. If params has a 'checkpoint' field (model ID), fetches and extracts the model
277
+
278
+ The returned checkpoint dict contains:
279
+ - category: 'base' or fine-tuned model category
280
+ - path: Local path to the extracted model files
281
+
282
+ Returns:
283
+ Checkpoint dict with 'category' and 'path', or None if no checkpoint.
284
+
285
+ Raises:
286
+ RuntimeError: If no client in context and checkpoint ID provided.
287
+ FileNotFoundError: If model file cannot be downloaded/extracted.
288
+
289
+ Example:
290
+ >>> checkpoint = self.get_checkpoint()
291
+ >>> if checkpoint:
292
+ ... model_path = checkpoint['path']
293
+ ... is_base = checkpoint['category'] == 'base'
294
+ """
295
+ from synapse_sdk.utils.file import extract_archive, get_temp_path
296
+
297
+ # If checkpoint is already in context (remote mode), return it
298
+ if self.ctx.checkpoint is not None:
299
+ return self.ctx.checkpoint
300
+
301
+ # Check if params has a checkpoint field (model ID)
302
+ checkpoint_id = getattr(self.params, 'checkpoint', None)
303
+ if checkpoint_id is None:
304
+ return None
305
+
306
+ # Fetch model from backend
307
+ model = self.get_model(checkpoint_id)
308
+
309
+ # The model['file'] is downloaded by the client's url_conversion
310
+ model_file = Path(model['file'])
311
+
312
+ # Extract to temp path
313
+ output_path = get_temp_path(f'models/{model_file.stem}')
314
+ if not output_path.exists():
315
+ output_path.mkdir(parents=True, exist_ok=True)
316
+ extract_archive(model_file, output_path)
317
+
318
+ # Determine category - base models vs fine-tuned
319
+ category = model.get('category') or 'base'
320
+
321
+ return {
322
+ 'category': category,
323
+ 'path': output_path,
324
+ 'id': model.get('id'),
325
+ 'name': model.get('name'),
326
+ }
@@ -0,0 +1,57 @@
1
+ """Train context for sharing state between workflow steps."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from synapse_sdk.plugins.steps import BaseStepContext
9
+
10
+ if TYPE_CHECKING:
11
+ from synapse_sdk.clients.backend import BackendClient
12
+
13
+
14
+ @dataclass
15
+ class TrainContext(BaseStepContext):
16
+ """Shared context passed between training workflow steps.
17
+
18
+ Extends BaseStepContext with training-specific state fields.
19
+ Carries parameters and accumulated state as the workflow
20
+ progresses through steps.
21
+
22
+ Attributes:
23
+ params: Training parameters (from action params).
24
+ dataset: Loaded dataset (populated by dataset step).
25
+ model_path: Path to trained model (populated by training step).
26
+ model: Created model metadata (populated by upload step).
27
+
28
+ Example:
29
+ >>> context = TrainContext(
30
+ ... runtime_ctx=runtime_ctx,
31
+ ... params={'dataset_id': 1, 'epochs': 10},
32
+ ... )
33
+ >>> # Steps populate state as they execute
34
+ >>> context.dataset = loaded_dataset
35
+ """
36
+
37
+ # Training parameters
38
+ params: dict[str, Any] = field(default_factory=dict)
39
+
40
+ # Processing state (populated by steps)
41
+ dataset: Any | None = None
42
+ model_path: str | None = None
43
+ model: dict[str, Any] | None = None
44
+
45
+ @property
46
+ def client(self) -> BackendClient:
47
+ """Backend client from runtime context.
48
+
49
+ Returns:
50
+ BackendClient instance.
51
+
52
+ Raises:
53
+ RuntimeError: If no client in runtime context.
54
+ """
55
+ if self.runtime_ctx.client is None:
56
+ raise RuntimeError('No client in runtime context')
57
+ return self.runtime_ctx.client
@@ -0,0 +1,49 @@
1
+ """Upload action module with workflow step support.
2
+
3
+ Provides a full step-based workflow system for upload actions:
4
+ - BaseUploadAction: Base class for upload workflows
5
+ - UploadContext: Upload-specific context extending BaseStepContext
6
+ - UploadProgressCategories: Standard progress category names
7
+
8
+ For step infrastructure (BaseStep, StepRegistry, Orchestrator),
9
+ use the steps module:
10
+ from synapse_sdk.plugins.steps import BaseStep, StepRegistry
11
+
12
+ Example:
13
+ >>> from synapse_sdk.plugins.steps import BaseStep, StepResult
14
+ >>> from synapse_sdk.plugins.actions.upload import (
15
+ ... BaseUploadAction,
16
+ ... UploadContext,
17
+ ... )
18
+ >>>
19
+ >>> class InitStep(BaseStep[UploadContext]):
20
+ ... @property
21
+ ... def name(self) -> str:
22
+ ... return 'initialize'
23
+ ...
24
+ ... @property
25
+ ... def progress_weight(self) -> float:
26
+ ... return 0.1
27
+ ...
28
+ ... def execute(self, context: UploadContext) -> StepResult:
29
+ ... # Initialize storage, validate params
30
+ ... return StepResult(success=True)
31
+ >>>
32
+ >>> class MyUploadAction(BaseUploadAction[MyParams]):
33
+ ... def setup_steps(self, registry) -> None:
34
+ ... registry.register(InitStep())
35
+ """
36
+
37
+ from synapse_sdk.plugins.actions.upload.action import (
38
+ BaseUploadAction,
39
+ UploadProgressCategories,
40
+ )
41
+ from synapse_sdk.plugins.actions.upload.context import UploadContext
42
+
43
+ __all__ = [
44
+ # Action
45
+ 'BaseUploadAction',
46
+ 'UploadProgressCategories',
47
+ # Context
48
+ 'UploadContext',
49
+ ]
@@ -0,0 +1,165 @@
1
+ """Upload action base class with workflow step support."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any, TypeVar
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from synapse_sdk.plugins.action import BaseAction
10
+ from synapse_sdk.plugins.actions.upload.context import UploadContext
11
+ from synapse_sdk.plugins.enums import PluginCategory
12
+ from synapse_sdk.plugins.steps import Orchestrator, StepRegistry
13
+
14
+ P = TypeVar('P', bound=BaseModel)
15
+
16
+ if TYPE_CHECKING:
17
+ from synapse_sdk.clients.backend import BackendClient
18
+
19
+
20
+ class UploadProgressCategories:
21
+ """Standard progress category names for upload workflows.
22
+
23
+ .. deprecated::
24
+ With automatic category inference from step names (US2),
25
+ explicit category constants are less necessary. Step names
26
+ are now automatically used as progress/metrics categories.
27
+
28
+ Use these constants with set_progress() to track upload phases:
29
+ - INITIALIZE: Storage and path setup
30
+ - VALIDATE: File validation
31
+ - UPLOAD: File upload to storage
32
+ - CLEANUP: Post-upload cleanup
33
+
34
+ Example:
35
+ >>> self.set_progress(1, 4, self.progress.INITIALIZE)
36
+ """
37
+
38
+ INITIALIZE: str = 'initialize'
39
+ VALIDATE: str = 'validate'
40
+ UPLOAD: str = 'upload'
41
+ CLEANUP: str = 'cleanup'
42
+
43
+ def __init__(self) -> None:
44
+ """Initialize with deprecation warning."""
45
+ import warnings
46
+
47
+ warnings.warn(
48
+ 'UploadProgressCategories is deprecated. '
49
+ 'Step names are now automatically used as progress/metrics categories. '
50
+ 'Consider using step.name directly or omitting the category parameter.',
51
+ DeprecationWarning,
52
+ stacklevel=2,
53
+ )
54
+
55
+
56
+ class BaseUploadAction(BaseAction[P]):
57
+ """Base class for upload actions with workflow step support.
58
+
59
+ Provides a full step-based workflow system:
60
+ - Override setup_steps() to register custom steps
61
+ - Steps execute in order with automatic rollback on failure
62
+ - Progress tracked across all steps based on weights
63
+
64
+ Attributes:
65
+ category: Plugin category (defaults to UPLOAD).
66
+ progress: Standard progress category names.
67
+
68
+ Example:
69
+ >>> class MyUploadAction(BaseUploadAction[MyParams]):
70
+ ... action_name = 'upload'
71
+ ... params_model = MyParams
72
+ ...
73
+ ... def setup_steps(self, registry: StepRegistry) -> None:
74
+ ... registry.register(InitializeStep())
75
+ ... registry.register(ValidateStep())
76
+ ... registry.register(UploadFilesStep())
77
+ ... registry.register(CleanupStep())
78
+ >>>
79
+ >>> # Steps are executed in order with automatic rollback on failure
80
+ >>> # Progress is tracked based on step weights
81
+ """
82
+
83
+ category = PluginCategory.UPLOAD
84
+ progress = UploadProgressCategories()
85
+
86
+ @property
87
+ def client(self) -> BackendClient:
88
+ """Backend client from context.
89
+
90
+ Returns:
91
+ BackendClient instance.
92
+
93
+ Raises:
94
+ RuntimeError: If no client in context.
95
+ """
96
+ if self.ctx.client is None:
97
+ raise RuntimeError('No client in context. Provide a client via RuntimeContext.')
98
+ return self.ctx.client
99
+
100
+ def setup_steps(self, registry: StepRegistry[UploadContext]) -> None:
101
+ """Register workflow steps.
102
+
103
+ Override this method to register custom steps for your upload workflow.
104
+ Steps are executed in registration order.
105
+
106
+ Args:
107
+ registry: StepRegistry to register steps with.
108
+
109
+ Example:
110
+ >>> def setup_steps(self, registry: StepRegistry[UploadContext]) -> None:
111
+ ... registry.register(InitializeStep())
112
+ ... registry.register(ValidateStep())
113
+ ... registry.register(UploadFilesStep())
114
+ """
115
+ pass # Subclasses override to add steps
116
+
117
+ def create_context(self) -> UploadContext:
118
+ """Create upload context for the workflow.
119
+
120
+ Override to customize context creation or add additional state.
121
+
122
+ Returns:
123
+ UploadContext instance with params and runtime context.
124
+ """
125
+ params_dict = self.params.model_dump() if hasattr(self.params, 'model_dump') else dict(self.params)
126
+ return UploadContext(
127
+ params=params_dict,
128
+ runtime_ctx=self.ctx,
129
+ )
130
+
131
+ def execute(self) -> dict[str, Any]:
132
+ """Execute the upload workflow.
133
+
134
+ Creates registry, registers steps via setup_steps(), creates context,
135
+ and runs the orchestrator.
136
+
137
+ Returns:
138
+ Dict with success status and workflow results.
139
+
140
+ Raises:
141
+ RuntimeError: If no steps registered or a step fails.
142
+ """
143
+ # Setup
144
+ registry: StepRegistry[UploadContext] = StepRegistry()
145
+ self.setup_steps(registry)
146
+
147
+ if not registry:
148
+ raise RuntimeError('No steps registered. Override setup_steps() to register workflow steps.')
149
+
150
+ # Create context and orchestrator
151
+ context = self.create_context()
152
+ orchestrator: Orchestrator[UploadContext] = Orchestrator(
153
+ registry=registry,
154
+ context=context,
155
+ progress_callback=lambda curr, total: self.set_progress(curr, total),
156
+ )
157
+
158
+ # Execute workflow
159
+ result = orchestrator.execute()
160
+
161
+ # Add upload-specific result data
162
+ result['uploaded_files'] = len(context.uploaded_files)
163
+ result['data_units'] = len(context.data_units)
164
+
165
+ return result
@@ -0,0 +1,61 @@
1
+ """Upload context for sharing state between workflow steps."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from synapse_sdk.plugins.steps import BaseStepContext
9
+
10
+ if TYPE_CHECKING:
11
+ from synapse_sdk.clients.backend import BackendClient
12
+
13
+
14
+ @dataclass
15
+ class UploadContext(BaseStepContext):
16
+ """Shared context passed between upload workflow steps.
17
+
18
+ Extends BaseStepContext with upload-specific state fields.
19
+ Carries parameters and accumulated state as the workflow
20
+ progresses through steps.
21
+
22
+ Attributes:
23
+ params: Upload parameters (from action params).
24
+ storage: Storage configuration (populated by init step).
25
+ pathlib_cwd: Working directory path (populated by init step).
26
+ organized_files: Files organized for upload (populated by organize step).
27
+ uploaded_files: Successfully uploaded files (populated by upload step).
28
+ data_units: Created data units (populated by generate step).
29
+
30
+ Example:
31
+ >>> context = UploadContext(
32
+ ... runtime_ctx=runtime_ctx,
33
+ ... params={'storage': 1, 'path': '/data'},
34
+ ... )
35
+ >>> # Steps populate state as they execute
36
+ >>> context.organized_files.append({'path': 'file1.jpg'})
37
+ """
38
+
39
+ # Upload parameters
40
+ params: dict[str, Any] = field(default_factory=dict)
41
+
42
+ # Processing state (populated by steps)
43
+ storage: Any | None = None
44
+ pathlib_cwd: Any | None = None
45
+ organized_files: list[dict[str, Any]] = field(default_factory=list)
46
+ uploaded_files: list[dict[str, Any]] = field(default_factory=list)
47
+ data_units: list[dict[str, Any]] = field(default_factory=list)
48
+
49
+ @property
50
+ def client(self) -> BackendClient:
51
+ """Backend client from runtime context.
52
+
53
+ Returns:
54
+ BackendClient instance.
55
+
56
+ Raises:
57
+ RuntimeError: If no client in runtime context.
58
+ """
59
+ if self.runtime_ctx.client is None:
60
+ raise RuntimeError('No client in runtime context')
61
+ return self.runtime_ctx.client