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,183 @@
1
+ """Export action base class with optional 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.export.context import ExportContext
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 ExportProgressCategories:
21
+ """Standard progress category names for export workflows.
22
+
23
+ Use these constants with set_progress() to track export phases:
24
+ - DATASET_CONVERSION: Data conversion and file generation
25
+
26
+ Example:
27
+ >>> self.set_progress(50, 100, self.progress.DATASET_CONVERSION)
28
+ """
29
+
30
+ DATASET_CONVERSION: str = 'dataset_conversion'
31
+
32
+
33
+ class BaseExportAction(BaseAction[P]):
34
+ """Base class for export actions.
35
+
36
+ Provides helper methods for export workflows.
37
+ Override get_filtered_results() for your specific target type.
38
+
39
+ Supports two execution modes:
40
+ 1. Simple execute: Override execute() directly for simple workflows
41
+ 2. Step-based: Override setup_steps() to register workflow steps
42
+
43
+ If setup_steps() registers any steps, the step-based workflow
44
+ takes precedence and execute() is not called directly.
45
+
46
+ Attributes:
47
+ category: Plugin category (defaults to EXPORT).
48
+ progress: Standard progress category names.
49
+
50
+ Example (simple execute):
51
+ >>> class MyExportAction(BaseExportAction[MyParams]):
52
+ ... action_name = 'export'
53
+ ... params_model = MyParams
54
+ ...
55
+ ... def get_filtered_results(self, filters: dict) -> tuple[Any, int]:
56
+ ... return self.client.get_assignments(filters)
57
+ ...
58
+ ... def execute(self) -> dict[str, Any]:
59
+ ... results, count = self.get_filtered_results(self.params.filter)
60
+ ... self.set_progress(0, count, self.progress.DATASET_CONVERSION)
61
+ ... for i, item in enumerate(results, 1):
62
+ ... # Process and export item
63
+ ... self.set_progress(i, count, self.progress.DATASET_CONVERSION)
64
+ ... return {'exported': count}
65
+
66
+ Example (step-based):
67
+ >>> class MyExportAction(BaseExportAction[MyParams]):
68
+ ... def setup_steps(self, registry: StepRegistry[ExportContext]) -> None:
69
+ ... registry.register(FetchResultsStep())
70
+ ... registry.register(ProcessStep())
71
+ ... registry.register(FinalizeStep())
72
+ """
73
+
74
+ category = PluginCategory.EXPORT
75
+ progress = ExportProgressCategories()
76
+
77
+ @property
78
+ def client(self) -> BackendClient:
79
+ """Backend client from context.
80
+
81
+ Returns:
82
+ BackendClient instance.
83
+
84
+ Raises:
85
+ RuntimeError: If no client in context.
86
+ """
87
+ if self.ctx.client is None:
88
+ raise RuntimeError(
89
+ 'No client in context. Either provide a client via RuntimeContext or override get_filtered_results().'
90
+ )
91
+ return self.ctx.client
92
+
93
+ def setup_steps(self, registry: StepRegistry[ExportContext]) -> None:
94
+ """Register workflow steps for step-based execution.
95
+
96
+ Override this method to register custom steps for your export workflow.
97
+ If steps are registered, step-based execution takes precedence.
98
+
99
+ Args:
100
+ registry: StepRegistry to register steps with.
101
+
102
+ Example:
103
+ >>> def setup_steps(self, registry: StepRegistry[ExportContext]) -> None:
104
+ ... registry.register(FetchResultsStep())
105
+ ... registry.register(ProcessStep())
106
+ ... registry.register(FinalizeStep())
107
+ """
108
+ pass # Default: no steps, uses simple execute()
109
+
110
+ def create_context(self) -> ExportContext:
111
+ """Create export context for step-based workflow.
112
+
113
+ Override to customize context creation or add additional state.
114
+
115
+ Returns:
116
+ ExportContext instance with params and runtime context.
117
+ """
118
+ params_dict = self.params.model_dump() if hasattr(self.params, 'model_dump') else dict(self.params)
119
+ return ExportContext(
120
+ runtime_ctx=self.ctx,
121
+ params=params_dict,
122
+ )
123
+
124
+ def run(self) -> Any:
125
+ """Run the action, using steps if registered.
126
+
127
+ This method is called by executors. It checks if steps are
128
+ registered and uses step-based execution if so.
129
+
130
+ Returns:
131
+ Action result (dict or any return type).
132
+ """
133
+ # Check if steps are registered
134
+ registry: StepRegistry[ExportContext] = StepRegistry()
135
+ self.setup_steps(registry)
136
+
137
+ if registry:
138
+ # Step-based execution
139
+ context = self.create_context()
140
+ orchestrator: Orchestrator[ExportContext] = Orchestrator(
141
+ registry=registry,
142
+ context=context,
143
+ progress_callback=lambda curr, total: self.set_progress(curr, total),
144
+ )
145
+ result = orchestrator.execute()
146
+
147
+ # Add context data to result
148
+ result['exported_count'] = context.exported_count
149
+ if context.output_path:
150
+ result['output_path'] = context.output_path
151
+
152
+ return result
153
+
154
+ # Simple execute mode
155
+ return self.execute()
156
+
157
+ def get_filtered_results(self, filters: dict[str, Any]) -> tuple[Any, int]:
158
+ """Fetch filtered results for export.
159
+
160
+ Override this method for your specific target type
161
+ (assignments, ground_truth, tasks, or custom).
162
+
163
+ Args:
164
+ filters: Filter criteria dict.
165
+
166
+ Returns:
167
+ Tuple of (results_iterator, total_count).
168
+
169
+ Raises:
170
+ NotImplementedError: Must be overridden by subclass.
171
+
172
+ Example:
173
+ >>> # Override for assignments:
174
+ >>> def get_filtered_results(self, filters: dict) -> tuple[Any, int]:
175
+ ... return self.client.get_assignments(filters)
176
+ >>>
177
+ >>> # Override for ground truth:
178
+ >>> def get_filtered_results(self, filters: dict) -> tuple[Any, int]:
179
+ ... return self.client.get_ground_truth(filters)
180
+ """
181
+ raise NotImplementedError(
182
+ 'Override get_filtered_results() for your target type. Example: return self.client.get_assignments(filters)'
183
+ )
@@ -0,0 +1,59 @@
1
+ """Export 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 ExportContext(BaseStepContext):
16
+ """Shared context passed between export workflow steps.
17
+
18
+ Extends BaseStepContext with export-specific state fields.
19
+ Carries parameters and accumulated state as the workflow
20
+ progresses through steps.
21
+
22
+ Attributes:
23
+ params: Export parameters (from action params).
24
+ results: Fetched results to export (populated by fetch step).
25
+ total_count: Total number of items to export.
26
+ exported_count: Number of items successfully exported.
27
+ output_path: Path to export output file/directory.
28
+
29
+ Example:
30
+ >>> context = ExportContext(
31
+ ... runtime_ctx=runtime_ctx,
32
+ ... params={'format': 'coco', 'filter': {}},
33
+ ... )
34
+ >>> # Steps populate state as they execute
35
+ >>> context.results = fetched_data
36
+ """
37
+
38
+ # Export parameters
39
+ params: dict[str, Any] = field(default_factory=dict)
40
+
41
+ # Processing state (populated by steps)
42
+ results: Any | None = None
43
+ total_count: int = 0
44
+ exported_count: int = 0
45
+ output_path: str | None = None
46
+
47
+ @property
48
+ def client(self) -> BackendClient:
49
+ """Backend client from runtime context.
50
+
51
+ Returns:
52
+ BackendClient instance.
53
+
54
+ Raises:
55
+ RuntimeError: If no client in runtime context.
56
+ """
57
+ if self.runtime_ctx.client is None:
58
+ raise RuntimeError('No client in runtime context')
59
+ return self.runtime_ctx.client
@@ -0,0 +1,84 @@
1
+ """Inference action module with Ray Serve integration.
2
+
3
+ This module provides base classes for inference and deployment actions:
4
+
5
+ - **BaseInferenceAction**: For batch inference or REST API inference
6
+ - **BaseDeploymentAction**: For deploying models to Ray Serve
7
+ - **BaseServeDeployment**: Ray Serve deployment class for model serving
8
+ - **InferenceContext**: Step-based workflow context for inference
9
+ - **DeploymentContext**: Step-based workflow context for deployment
10
+
11
+ Example (Simple Inference):
12
+ >>> from synapse_sdk.plugins.actions.inference import BaseInferenceAction
13
+ >>>
14
+ >>> class MyInferenceAction(BaseInferenceAction[MyParams]):
15
+ ... action_name = 'inference'
16
+ ... category = 'neural_net'
17
+ ... params_model = MyParams
18
+ ...
19
+ ... def execute(self) -> dict:
20
+ ... model_info = self.load_model(self.params.model_id)
21
+ ... results = self.infer(model_info, self.params.inputs)
22
+ ... return {'results': results}
23
+
24
+ Example (Ray Serve Deployment):
25
+ >>> from synapse_sdk.plugins.actions.inference import (
26
+ ... BaseDeploymentAction,
27
+ ... BaseServeDeployment,
28
+ ... )
29
+ >>>
30
+ >>> class MyServeDeployment(BaseServeDeployment):
31
+ ... async def _get_model(self, model_info: dict) -> Any:
32
+ ... import torch
33
+ ... return torch.load(model_info['path'] / 'model.pt')
34
+ ...
35
+ ... async def infer(self, inputs: list[dict]) -> list[dict]:
36
+ ... model = await self.get_model()
37
+ ... return [{'pred': model(inp)} for inp in inputs]
38
+ >>>
39
+ >>> class MyDeploymentAction(BaseDeploymentAction[MyParams]):
40
+ ... action_name = 'deployment'
41
+ ... category = 'neural_net'
42
+ ... params_model = MyParams
43
+ ... entrypoint = MyServeDeployment
44
+ ...
45
+ ... def execute(self) -> dict:
46
+ ... self.ray_init()
47
+ ... self.deploy()
48
+ ... app_id = self.register_serve_application()
49
+ ... return {'serve_application': app_id}
50
+ """
51
+
52
+ from __future__ import annotations
53
+
54
+ from synapse_sdk.plugins.actions.inference.action import (
55
+ BaseInferenceAction,
56
+ InferenceProgressCategories,
57
+ )
58
+ from synapse_sdk.plugins.actions.inference.context import (
59
+ DeploymentContext,
60
+ InferenceContext,
61
+ )
62
+ from synapse_sdk.plugins.actions.inference.deployment import (
63
+ BaseDeploymentAction,
64
+ DeploymentProgressCategories,
65
+ )
66
+ from synapse_sdk.plugins.actions.inference.serve import (
67
+ BaseServeDeployment,
68
+ create_serve_multiplexed_model_id,
69
+ )
70
+
71
+ __all__ = [
72
+ # Actions
73
+ 'BaseInferenceAction',
74
+ 'BaseDeploymentAction',
75
+ # Serve
76
+ 'BaseServeDeployment',
77
+ 'create_serve_multiplexed_model_id',
78
+ # Contexts
79
+ 'InferenceContext',
80
+ 'DeploymentContext',
81
+ # Progress Categories
82
+ 'InferenceProgressCategories',
83
+ 'DeploymentProgressCategories',
84
+ ]
@@ -0,0 +1,285 @@
1
+ """Inference action base class with optional step support."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import tempfile
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING, Any, TypeVar
8
+
9
+ from pydantic import BaseModel
10
+
11
+ from synapse_sdk.plugins.action import BaseAction
12
+ from synapse_sdk.plugins.actions.inference.context import InferenceContext
13
+ from synapse_sdk.plugins.enums import PluginCategory
14
+ from synapse_sdk.plugins.steps import Orchestrator, StepRegistry
15
+ from synapse_sdk.utils.file.archive import extract_archive
16
+
17
+ P = TypeVar('P', bound=BaseModel)
18
+
19
+ if TYPE_CHECKING:
20
+ from synapse_sdk.clients.backend import BackendClient
21
+
22
+
23
+ class InferenceProgressCategories:
24
+ """Standard progress category names for inference workflows.
25
+
26
+ Use these constants with set_progress() to track inference phases:
27
+ - MODEL_LOAD: Model loading and initialization
28
+ - INFERENCE: Running inference on inputs
29
+ - POSTPROCESS: Post-processing results
30
+
31
+ Example:
32
+ >>> self.set_progress(1, 3, self.progress.MODEL_LOAD)
33
+ >>> self.set_progress(2, 3, self.progress.INFERENCE)
34
+ """
35
+
36
+ MODEL_LOAD: str = 'model_load'
37
+ INFERENCE: str = 'inference'
38
+ POSTPROCESS: str = 'postprocess'
39
+
40
+
41
+ class BaseInferenceAction(BaseAction[P]):
42
+ """Base class for inference actions.
43
+
44
+ Provides helper methods for model loading and inference workflows.
45
+ Supports both REST API-based inference (via Ray Serve) and batch
46
+ inference with step-based workflows.
47
+
48
+ Supports two execution modes:
49
+ 1. Simple execute: Override execute() directly for simple workflows
50
+ 2. Step-based: Override setup_steps() to register workflow steps
51
+
52
+ If setup_steps() registers any steps, the step-based workflow
53
+ takes precedence and execute() is not called directly.
54
+
55
+ Attributes:
56
+ category: Plugin category (defaults to NEURAL_NET).
57
+ progress: Standard progress category names.
58
+
59
+ Example (simple execute):
60
+ >>> class MyInferenceAction(BaseInferenceAction[MyParams]):
61
+ ... action_name = 'inference'
62
+ ... params_model = MyParams
63
+ ...
64
+ ... def execute(self) -> dict[str, Any]:
65
+ ... model = self.load_model(self.params.model_id)
66
+ ... self.set_progress(1, 3, self.progress.MODEL_LOAD)
67
+ ... results = self.infer(model, self.params.inputs)
68
+ ... self.set_progress(2, 3, self.progress.INFERENCE)
69
+ ... return {'results': results}
70
+
71
+ Example (step-based):
72
+ >>> class MyInferenceAction(BaseInferenceAction[MyParams]):
73
+ ... def setup_steps(self, registry: StepRegistry[InferenceContext]) -> None:
74
+ ... registry.register(LoadModelStep())
75
+ ... registry.register(InferenceStep())
76
+ ... registry.register(PostProcessStep())
77
+ """
78
+
79
+ category = PluginCategory.NEURAL_NET
80
+ progress = InferenceProgressCategories()
81
+
82
+ @property
83
+ def client(self) -> BackendClient:
84
+ """Backend client from context.
85
+
86
+ Returns:
87
+ BackendClient instance.
88
+
89
+ Raises:
90
+ RuntimeError: If no client in context.
91
+ """
92
+ if self.ctx.client is None:
93
+ raise RuntimeError(
94
+ 'No client in context. Either provide a client via RuntimeContext '
95
+ 'or override the helper methods (load_model, get_model).'
96
+ )
97
+ return self.ctx.client
98
+
99
+ def setup_steps(self, registry: StepRegistry[InferenceContext]) -> None:
100
+ """Register workflow steps for step-based execution.
101
+
102
+ Override this method to register custom steps for your inference workflow.
103
+ If steps are registered, step-based execution takes precedence.
104
+
105
+ Args:
106
+ registry: StepRegistry to register steps with.
107
+
108
+ Example:
109
+ >>> def setup_steps(self, registry: StepRegistry[InferenceContext]) -> None:
110
+ ... registry.register(LoadModelStep())
111
+ ... registry.register(InferenceStep())
112
+ ... registry.register(PostProcessStep())
113
+ """
114
+ pass # Default: no steps, uses simple execute()
115
+
116
+ def create_context(self) -> InferenceContext:
117
+ """Create inference context for step-based workflow.
118
+
119
+ Override to customize context creation or add additional state.
120
+
121
+ Returns:
122
+ InferenceContext instance with params and runtime context.
123
+ """
124
+ params_dict = self.params.model_dump() if hasattr(self.params, 'model_dump') else dict(self.params)
125
+ return InferenceContext(
126
+ runtime_ctx=self.ctx,
127
+ params=params_dict,
128
+ model_id=params_dict.get('model_id'),
129
+ )
130
+
131
+ def run(self) -> Any:
132
+ """Run the action, using steps if registered.
133
+
134
+ This method is called by executors. It checks if steps are
135
+ registered and uses step-based execution if so.
136
+
137
+ Returns:
138
+ Action result (dict or any return type).
139
+ """
140
+ # Check if steps are registered
141
+ registry: StepRegistry[InferenceContext] = StepRegistry()
142
+ self.setup_steps(registry)
143
+
144
+ if registry:
145
+ # Step-based execution
146
+ context = self.create_context()
147
+ orchestrator: Orchestrator[InferenceContext] = Orchestrator(
148
+ registry=registry,
149
+ context=context,
150
+ progress_callback=lambda curr, total: self.set_progress(curr, total),
151
+ )
152
+ result = orchestrator.execute()
153
+
154
+ # Add context data to result
155
+ result['processed_count'] = context.processed_count
156
+ if context.results:
157
+ result['results'] = context.results
158
+
159
+ return result
160
+
161
+ # Simple execute mode
162
+ return self.execute()
163
+
164
+ def get_model(self, model_id: int) -> dict[str, Any]:
165
+ """Retrieve model metadata by ID.
166
+
167
+ Args:
168
+ model_id: Model identifier.
169
+
170
+ Returns:
171
+ Model metadata dictionary including file URL.
172
+
173
+ Raises:
174
+ RuntimeError: If no client in context.
175
+
176
+ Example:
177
+ >>> model = self.get_model(123)
178
+ >>> print(model['name'], model['file'])
179
+ """
180
+ return self.client.get_model(model_id)
181
+
182
+ def download_model(
183
+ self,
184
+ model_id: int,
185
+ output_dir: str | Path | None = None,
186
+ ) -> Path:
187
+ """Download and extract model artifacts.
188
+
189
+ Fetches model metadata, downloads the model archive, and extracts
190
+ it to the specified directory (or a temp directory if not specified).
191
+
192
+ Args:
193
+ model_id: Model identifier.
194
+ output_dir: Directory to extract model to. If None, uses tempdir.
195
+
196
+ Returns:
197
+ Path to extracted model directory.
198
+
199
+ Raises:
200
+ RuntimeError: If no client in context.
201
+ ValueError: If model has no file URL.
202
+
203
+ Example:
204
+ >>> model_path = self.download_model(123)
205
+ >>> # Load model from model_path
206
+ """
207
+ model = self.get_model(model_id)
208
+
209
+ if not model.get('file'):
210
+ raise ValueError(f'Model {model_id} has no file URL')
211
+
212
+ # Determine output directory
213
+ if output_dir is None:
214
+ output_dir = Path(tempfile.mkdtemp(prefix='synapse_model_'))
215
+ else:
216
+ output_dir = Path(output_dir)
217
+ output_dir.mkdir(parents=True, exist_ok=True)
218
+
219
+ # Download and extract
220
+ from synapse_sdk.utils.file.download import download_file
221
+
222
+ archive_path = output_dir / 'model.zip'
223
+ download_file(model['file'], archive_path)
224
+ extract_archive(archive_path, output_dir)
225
+
226
+ # Remove archive after extraction
227
+ archive_path.unlink(missing_ok=True)
228
+
229
+ return output_dir
230
+
231
+ def load_model(self, model_id: int) -> dict[str, Any]:
232
+ """Load model for inference.
233
+
234
+ Downloads model artifacts and returns model info with local path.
235
+ Override this method for custom model loading (e.g., loading into
236
+ specific framework like PyTorch, TensorFlow).
237
+
238
+ Args:
239
+ model_id: Model identifier.
240
+
241
+ Returns:
242
+ Model metadata dict with 'path' key for local artifacts.
243
+
244
+ Example:
245
+ >>> model_info = self.load_model(123)
246
+ >>> model_path = model_info['path']
247
+ >>> # Load your model framework here:
248
+ >>> # model = torch.load(model_path / 'model.pt')
249
+ """
250
+ model = self.get_model(model_id)
251
+ model_path = self.download_model(model_id)
252
+ model['path'] = str(model_path)
253
+ return model
254
+
255
+ def infer(
256
+ self,
257
+ model: Any,
258
+ inputs: list[dict[str, Any]],
259
+ ) -> list[dict[str, Any]]:
260
+ """Run inference on inputs.
261
+
262
+ Override this method to implement your inference logic.
263
+ This is called by execute() in simple mode.
264
+
265
+ Args:
266
+ model: Loaded model (framework-specific).
267
+ inputs: List of input dictionaries.
268
+
269
+ Returns:
270
+ List of result dictionaries.
271
+
272
+ Raises:
273
+ NotImplementedError: Must be overridden by subclass.
274
+
275
+ Example:
276
+ >>> def infer(self, model, inputs):
277
+ ... results = []
278
+ ... for inp in inputs:
279
+ ... prediction = model.predict(inp['image'])
280
+ ... results.append({'prediction': prediction})
281
+ ... return results
282
+ """
283
+ raise NotImplementedError(
284
+ 'Override infer() to implement inference logic. Example: return model.predict(inputs)'
285
+ )
@@ -0,0 +1,81 @@
1
+ """Inference context for step-based workflows."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any
7
+
8
+ from synapse_sdk.plugins.steps import BaseStepContext
9
+
10
+
11
+ @dataclass
12
+ class InferenceContext(BaseStepContext):
13
+ """Context for inference action step-based workflows.
14
+
15
+ Extends BaseStepContext with inference-specific state including
16
+ model information, request/response tracking, and batch processing.
17
+
18
+ Attributes:
19
+ params: Action parameters dict.
20
+ model_id: ID of the model being used for inference.
21
+ model: Loaded model information from backend.
22
+ model_path: Local path to downloaded/extracted model.
23
+ requests: Input requests to process.
24
+ results: Inference results.
25
+ batch_size: Batch size for processing.
26
+ processed_count: Number of processed items.
27
+
28
+ Example:
29
+ >>> context = InferenceContext(
30
+ ... runtime_ctx=self.ctx,
31
+ ... params={'model_id': 123},
32
+ ... model_id=123,
33
+ ... )
34
+ >>> context.results.append({'prediction': 0.95})
35
+ """
36
+
37
+ params: dict[str, Any] = field(default_factory=dict)
38
+ model_id: int | None = None
39
+ model: dict[str, Any] | None = None
40
+ model_path: str | None = None
41
+ requests: list[dict[str, Any]] = field(default_factory=list)
42
+ results: list[dict[str, Any]] = field(default_factory=list)
43
+ batch_size: int = 1
44
+ processed_count: int = 0
45
+
46
+
47
+ @dataclass
48
+ class DeploymentContext(BaseStepContext):
49
+ """Context for deployment action step-based workflows.
50
+
51
+ Extends BaseStepContext with deployment-specific state including
52
+ model information, serve application configuration, and deployment status.
53
+
54
+ Attributes:
55
+ params: Action parameters dict.
56
+ model_id: ID of the model to deploy.
57
+ model: Model information from backend.
58
+ model_path: Local path to model artifacts.
59
+ serve_app_name: Name of the Ray Serve application.
60
+ serve_app_id: ID of the created serve application.
61
+ route_prefix: URL route prefix for the deployment.
62
+ ray_actor_options: Ray actor configuration options.
63
+ deployed: Whether deployment succeeded.
64
+
65
+ Example:
66
+ >>> context = DeploymentContext(
67
+ ... runtime_ctx=self.ctx,
68
+ ... params={'model_id': 123},
69
+ ... serve_app_name='my-model-v1',
70
+ ... )
71
+ """
72
+
73
+ params: dict[str, Any] = field(default_factory=dict)
74
+ model_id: int | None = None
75
+ model: dict[str, Any] | None = None
76
+ model_path: str | None = None
77
+ serve_app_name: str | None = None
78
+ serve_app_id: int | None = None
79
+ route_prefix: str | None = None
80
+ ray_actor_options: dict[str, Any] = field(default_factory=dict)
81
+ deployed: bool = False