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,311 @@
1
+ """Rich console progress display for pipeline execution.
2
+
3
+ Provides a real-time progress display using the Rich library for
4
+ monitoring pipeline execution in the terminal. Supports both sync and async.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from collections.abc import AsyncIterator, Iterator
13
+
14
+ from rich.panel import Panel
15
+
16
+ from synapse_sdk.plugins.models.logger import PipelineProgress
17
+
18
+
19
+ def _create_display_panel(
20
+ progress: 'PipelineProgress',
21
+ show_actions: bool = True,
22
+ ) -> 'Panel':
23
+ """Create the Rich display panel for progress."""
24
+ from rich.console import Group
25
+ from rich.panel import Panel
26
+ from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
27
+ from rich.table import Table
28
+
29
+ from synapse_sdk.plugins.models.pipeline import ActionStatus, RunStatus
30
+
31
+ # Main progress bar
32
+ main_progress = Progress(
33
+ SpinnerColumn(),
34
+ TextColumn('[bold blue]{task.description}'),
35
+ BarColumn(),
36
+ TextColumn('[progress.percentage]{task.percentage:>3.0f}%'),
37
+ )
38
+
39
+ # Calculate overall progress including current action progress
40
+ total_actions = len(progress.actions) if progress.actions else 1
41
+ completed_actions = sum(1 for a in (progress.actions or []) if a.status == ActionStatus.COMPLETED)
42
+
43
+ # Find current running action and its progress
44
+ current_action_progress = 0.0
45
+ if progress.actions:
46
+ for a in progress.actions:
47
+ if a.status == ActionStatus.RUNNING and a.progress:
48
+ current_action_progress = a.progress
49
+ break
50
+
51
+ if progress.status == RunStatus.COMPLETED:
52
+ percentage = 100.0
53
+ elif progress.status == RunStatus.FAILED:
54
+ percentage = (completed_actions / total_actions) * 100
55
+ else:
56
+ # Include current action's partial progress
57
+ base_progress = (completed_actions / total_actions) * 100
58
+ action_contribution = (current_action_progress / total_actions) * 100
59
+ percentage = base_progress + action_contribution
60
+
61
+ main_progress.add_task(
62
+ description=f'Pipeline: {progress.run_id[:8]}...',
63
+ total=100,
64
+ completed=percentage,
65
+ )
66
+
67
+ # Status text
68
+ status_colors = {
69
+ RunStatus.PENDING: 'yellow',
70
+ RunStatus.RUNNING: 'blue',
71
+ RunStatus.COMPLETED: 'green',
72
+ RunStatus.FAILED: 'red',
73
+ RunStatus.CANCELLED: 'orange3',
74
+ }
75
+ status_color = status_colors.get(progress.status, 'white')
76
+ status_text = f'[{status_color}]Status: {progress.status.value.upper()}[/]'
77
+
78
+ if progress.current_action:
79
+ status_text += f' | Current: [cyan]{progress.current_action}[/]'
80
+
81
+ # Find current action's detailed progress message
82
+ current_action_msg = None
83
+ if progress.actions:
84
+ for a in progress.actions:
85
+ if a.status == ActionStatus.RUNNING:
86
+ if a.message:
87
+ current_action_msg = a.message
88
+ elif a.progress_category and a.progress:
89
+ current_action_msg = f'{a.progress_category}: {a.progress * 100:.0f}%'
90
+ break
91
+
92
+ # Build content
93
+ content_parts: list = [main_progress, '', status_text]
94
+
95
+ # Add detailed progress message if available
96
+ if current_action_msg:
97
+ content_parts.append(f'[dim] {current_action_msg}[/]')
98
+
99
+ # Action table (if enabled and actions exist)
100
+ if show_actions and progress.actions:
101
+ action_table = Table(show_header=True, header_style='bold magenta')
102
+ action_table.add_column('#', style='dim', width=3)
103
+ action_table.add_column('Action', min_width=20)
104
+ action_table.add_column('Status', width=12)
105
+ action_table.add_column('Progress', width=15)
106
+
107
+ action_status_icons = {
108
+ ActionStatus.PENDING: '[dim]-[/]',
109
+ ActionStatus.RUNNING: '[blue]...[/]',
110
+ ActionStatus.COMPLETED: '[green]OK[/]',
111
+ ActionStatus.FAILED: '[red]FAIL[/]',
112
+ ActionStatus.SKIPPED: '[yellow]SKIP[/]',
113
+ }
114
+
115
+ for i, action in enumerate(progress.actions):
116
+ icon = action_status_icons.get(action.status, '?')
117
+ if action.message:
118
+ prog_text = action.message
119
+ elif action.progress:
120
+ prog_text = f'{action.progress * 100:.0f}%'
121
+ else:
122
+ prog_text = '-'
123
+ action_table.add_row(
124
+ str(i + 1),
125
+ action.name,
126
+ icon,
127
+ prog_text,
128
+ )
129
+
130
+ content_parts.extend(['', action_table])
131
+
132
+ # Error message (if any)
133
+ if progress.error:
134
+ content_parts.extend(['', f'[red]Error: {progress.error}[/]'])
135
+
136
+ return Panel(
137
+ Group(*content_parts),
138
+ title='[bold]Pipeline Progress[/]',
139
+ border_style='blue' if progress.status == RunStatus.RUNNING else 'green',
140
+ )
141
+
142
+
143
+ def display_progress(
144
+ progress_stream: 'Iterator[PipelineProgress]',
145
+ *,
146
+ show_actions: bool = True,
147
+ refresh_rate: float = 4.0,
148
+ ) -> 'PipelineProgress':
149
+ """Display pipeline progress in the console using Rich (sync version).
150
+
151
+ Creates a live-updating display showing:
152
+ - Overall pipeline status and progress bar
153
+ - Current action being executed
154
+ - Individual action statuses in a table
155
+
156
+ Args:
157
+ progress_stream: Iterator yielding PipelineProgress updates.
158
+ show_actions: If True, show individual action statuses.
159
+ refresh_rate: Refreshes per second for the live display.
160
+
161
+ Returns:
162
+ Final PipelineProgress after completion.
163
+
164
+ Example:
165
+ >>> from synapse_sdk.plugins.pipelines.display import display_progress
166
+ >>> run_id = executor.submit(pipeline, params)
167
+ >>> final = display_progress(executor.stream_progress(run_id))
168
+ >>> print(f"Completed with status: {final.status}")
169
+ """
170
+ try:
171
+ from rich.console import Console
172
+ from rich.live import Live
173
+ except ImportError as e:
174
+ raise ImportError('Rich library is required for progress display. Install it with: pip install rich') from e
175
+
176
+ console = Console()
177
+ last_progress: PipelineProgress | None = None
178
+
179
+ with Live(console=console, refresh_per_second=refresh_rate) as live:
180
+ for progress in progress_stream:
181
+ last_progress = progress
182
+ live.update(_create_display_panel(progress, show_actions))
183
+
184
+ if last_progress is None:
185
+ raise RuntimeError('No progress updates received')
186
+
187
+ return last_progress
188
+
189
+
190
+ async def display_progress_async(
191
+ progress_stream: 'AsyncIterator[PipelineProgress]',
192
+ *,
193
+ show_actions: bool = True,
194
+ refresh_rate: float = 4.0,
195
+ ) -> 'PipelineProgress':
196
+ """Display pipeline progress in the console using Rich (async version).
197
+
198
+ Creates a live-updating display showing:
199
+ - Overall pipeline status and progress bar
200
+ - Current action being executed
201
+ - Individual action statuses in a table
202
+
203
+ Args:
204
+ progress_stream: AsyncIterator yielding PipelineProgress updates.
205
+ show_actions: If True, show individual action statuses.
206
+ refresh_rate: Refreshes per second for the live display.
207
+
208
+ Returns:
209
+ Final PipelineProgress after completion.
210
+
211
+ Example:
212
+ >>> from synapse_sdk.plugins.pipelines.display import display_progress_async
213
+ >>> run_id = await executor.submit_async(pipeline, params)
214
+ >>> async for progress in executor.stream_progress_async(run_id):
215
+ ... # Process updates
216
+ >>> final = await display_progress_async(executor.stream_progress_async(run_id))
217
+ """
218
+ try:
219
+ from rich.console import Console
220
+ from rich.live import Live
221
+ except ImportError as e:
222
+ raise ImportError('Rich library is required for progress display. Install it with: pip install rich') from e
223
+
224
+ console = Console()
225
+ last_progress: PipelineProgress | None = None
226
+
227
+ with Live(console=console, refresh_per_second=refresh_rate) as live:
228
+ async for progress in progress_stream:
229
+ last_progress = progress
230
+ live.update(_create_display_panel(progress, show_actions))
231
+
232
+ if last_progress is None:
233
+ raise RuntimeError('No progress updates received')
234
+
235
+ return last_progress
236
+
237
+
238
+ def print_progress_summary(progress: 'PipelineProgress') -> None:
239
+ """Print a summary of pipeline execution.
240
+
241
+ Args:
242
+ progress: Final pipeline progress to summarize.
243
+ """
244
+ try:
245
+ from rich.console import Console
246
+ from rich.table import Table
247
+ except ImportError:
248
+ # Fallback to plain print
249
+ print(f'Pipeline {progress.run_id}: {progress.status.value}')
250
+ return
251
+
252
+ console = Console()
253
+ from synapse_sdk.plugins.models.pipeline import ActionStatus, RunStatus
254
+
255
+ # Status emoji
256
+ status_emoji = {
257
+ RunStatus.COMPLETED: '[green]OK[/]',
258
+ RunStatus.FAILED: '[red]FAILED[/]',
259
+ RunStatus.CANCELLED: '[yellow]CANCELLED[/]',
260
+ RunStatus.RUNNING: '[blue]RUNNING[/]',
261
+ RunStatus.PENDING: '[dim]PENDING[/]',
262
+ }
263
+
264
+ console.print()
265
+ console.print(f'[bold]Pipeline:[/] {progress.run_id}')
266
+ console.print(f'[bold]Status:[/] {status_emoji.get(progress.status, progress.status.value)}')
267
+
268
+ if progress.started_at:
269
+ console.print(f'[bold]Started:[/] {progress.started_at.isoformat()}')
270
+ if progress.completed_at:
271
+ console.print(f'[bold]Completed:[/] {progress.completed_at.isoformat()}')
272
+ if progress.started_at:
273
+ duration = progress.completed_at - progress.started_at
274
+ console.print(f'[bold]Duration:[/] {duration}')
275
+
276
+ if progress.actions:
277
+ console.print()
278
+ table = Table(title='Actions', show_header=True)
279
+ table.add_column('Action', style='cyan')
280
+ table.add_column('Status')
281
+ table.add_column('Duration')
282
+
283
+ action_status_style = {
284
+ ActionStatus.COMPLETED: '[green]COMPLETED[/]',
285
+ ActionStatus.FAILED: '[red]FAILED[/]',
286
+ ActionStatus.RUNNING: '[blue]RUNNING[/]',
287
+ ActionStatus.PENDING: '[dim]PENDING[/]',
288
+ ActionStatus.SKIPPED: '[yellow]SKIPPED[/]',
289
+ }
290
+
291
+ for action in progress.actions:
292
+ duration = '-'
293
+ if action.started_at and action.completed_at:
294
+ duration = str(action.completed_at - action.started_at)
295
+ elif action.started_at:
296
+ duration = 'running...'
297
+
298
+ table.add_row(
299
+ action.name,
300
+ action_status_style.get(action.status, str(action.status)),
301
+ duration,
302
+ )
303
+
304
+ console.print(table)
305
+
306
+ if progress.error:
307
+ console.print()
308
+ console.print(f'[red bold]Error:[/] {progress.error}')
309
+
310
+
311
+ __all__ = ['display_progress', 'display_progress_async', 'print_progress_summary']
@@ -0,0 +1,114 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib
4
+ from collections.abc import Callable
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING, Any, Literal
7
+
8
+ from synapse_sdk.plugins.discovery import PluginDiscovery
9
+ from synapse_sdk.plugins.executors.local import LocalExecutor
10
+ from synapse_sdk.plugins.executors.ray.job import RayJobExecutor
11
+ from synapse_sdk.plugins.executors.ray.task import RayActorExecutor
12
+
13
+ if TYPE_CHECKING:
14
+ from synapse_sdk.plugins.action import BaseAction
15
+
16
+
17
+ def _discover_action(plugin_code: str, action: str) -> type[BaseAction] | Callable:
18
+ """Discover action class from plugin code.
19
+
20
+ Args:
21
+ plugin_code: Either a module path ('my_plugins.yolov8') or
22
+ a filesystem path to config.yaml ('/path/to/plugin')
23
+ action: Action name to load
24
+
25
+ Returns:
26
+ Action class or decorated function
27
+ """
28
+ path = Path(plugin_code)
29
+
30
+ # Check if it's a filesystem path (config.yaml or directory)
31
+ if path.exists() or (path.parent.exists() and path.suffix == '.yaml'):
32
+ discovery = PluginDiscovery.from_path(path)
33
+ else:
34
+ # Treat as module path - import and introspect
35
+ module = importlib.import_module(plugin_code)
36
+ discovery = PluginDiscovery.from_module(module)
37
+
38
+ return discovery.get_action_class(action)
39
+
40
+
41
+ def run_plugin(
42
+ plugin_code: str,
43
+ action: str,
44
+ params: dict[str, Any] | None = None,
45
+ *,
46
+ mode: Literal['local', 'task', 'job'] = 'local',
47
+ **executor_kwargs: Any,
48
+ ) -> Any:
49
+ """Run a plugin action.
50
+
51
+ This is the main entry point for executing plugin actions. It handles
52
+ plugin discovery, parameter validation, and execution delegation to
53
+ the appropriate executor based on the mode.
54
+
55
+ Args:
56
+ plugin_code: Plugin identifier. Can be:
57
+ - Module path: 'my_plugins.yolov8' (discovers via @action decorators or BaseAction classes)
58
+ - Filesystem path: '/path/to/plugin' or '/path/to/config.yaml'
59
+ action: Action name to execute (e.g., 'train', 'infer', 'export').
60
+ params: Action parameters as a dictionary. Will be validated against
61
+ the action's params schema if defined.
62
+ mode: Execution mode:
63
+ - 'local': Run in the current process (default, good for dev).
64
+ - 'task': Run via Ray Actor pool (fast startup, <1s).
65
+ - 'job': Run via Ray Job API (for heavy/long-running workloads).
66
+ **executor_kwargs: Additional executor options:
67
+ - action_cls: Optional explicit action class (skips discovery).
68
+ - env: PluginEnvironment or dict for environment config.
69
+ - job_id: Optional job identifier for tracking.
70
+
71
+ Returns:
72
+ For 'local' and 'task' modes: Action result (type depends on the action).
73
+ For 'job' mode: Job ID string for tracking (async submission).
74
+
75
+ Raises:
76
+ ActionNotFoundError: If the action doesn't exist in the plugin.
77
+ ValidationError: If params fail schema validation.
78
+ ExecutionError: If action execution fails.
79
+
80
+ Example:
81
+ >>> from synapse_sdk.plugins.runner import run_plugin
82
+ >>>
83
+ >>> # Auto-discover from module path
84
+ >>> result = run_plugin('my_plugins.yolov8', 'train', {'epochs': 10})
85
+ >>>
86
+ >>> # Auto-discover from config.yaml path
87
+ >>> result = run_plugin('/path/to/plugin', 'train', {'epochs': 10})
88
+ >>>
89
+ >>> # Explicit action class (skips discovery)
90
+ >>> result = run_plugin('yolov8', 'train', {'epochs': 10}, action_cls=TrainAction)
91
+ """
92
+ params = params or {}
93
+
94
+ if mode == 'local':
95
+ action_cls = executor_kwargs.pop('action_cls', None)
96
+ if action_cls is None:
97
+ action_cls = _discover_action(plugin_code, action)
98
+ executor = LocalExecutor(**executor_kwargs)
99
+ return executor.execute(action_cls, params)
100
+
101
+ elif mode == 'task':
102
+ action_cls = executor_kwargs.pop('action_cls', None)
103
+ if action_cls is None:
104
+ action_cls = _discover_action(plugin_code, action)
105
+ executor = RayActorExecutor(**executor_kwargs)
106
+ return executor.execute(action_cls, params)
107
+
108
+ else: # mode == 'job'
109
+ executor = RayJobExecutor(**executor_kwargs)
110
+ # Job mode is async - submit and return job_id
111
+ return executor.submit(action, params)
112
+
113
+
114
+ __all__ = ['run_plugin']
@@ -0,0 +1,19 @@
1
+ """Common schema types for plugin actions."""
2
+
3
+ from synapse_sdk.plugins.schemas.results import (
4
+ ExportResult,
5
+ InferenceResult,
6
+ MetricsResult,
7
+ TrainResult,
8
+ UploadResult,
9
+ WeightsResult,
10
+ )
11
+
12
+ __all__ = [
13
+ 'ExportResult',
14
+ 'InferenceResult',
15
+ 'MetricsResult',
16
+ 'TrainResult',
17
+ 'UploadResult',
18
+ 'WeightsResult',
19
+ ]
@@ -0,0 +1,152 @@
1
+ """Common result types for plugin actions.
2
+
3
+ These provide standardized schemas for common action outputs.
4
+ Plugin developers can use these directly or extend them for
5
+ custom result types.
6
+
7
+ Example usage:
8
+ >>> from synapse_sdk.plugins import BaseTrainAction
9
+ >>> from synapse_sdk.plugins.schemas import TrainResult
10
+ >>>
11
+ >>> class MyTrainAction(BaseTrainAction[MyParams, TrainResult]):
12
+ ... def execute(self) -> TrainResult:
13
+ ... return TrainResult(
14
+ ... weights_path='/models/best.pt',
15
+ ... final_epoch=100,
16
+ ... train_metrics={'loss': 0.05},
17
+ ... val_metrics={'mAP50': 0.85},
18
+ ... )
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import Any
24
+
25
+ from pydantic import BaseModel, Field
26
+
27
+
28
+ class WeightsResult(BaseModel):
29
+ """Result type for actions that produce model weights.
30
+
31
+ Use this for actions that output trained model weights.
32
+
33
+ Example:
34
+ >>> class TrainAction(BaseAction[TrainParams, WeightsResult]):
35
+ ... def execute(self) -> WeightsResult:
36
+ ... return WeightsResult(
37
+ ... weights_path='/models/best.pt',
38
+ ... checkpoint_paths=['/models/epoch_10.pt'],
39
+ ... )
40
+ """
41
+
42
+ weights_path: str = Field(description='Path to the best/final model weights')
43
+ checkpoint_paths: list[str] = Field(default_factory=list, description='Paths to intermediate checkpoints')
44
+ format: str = Field(default='pt', description='Weights format (pt, onnx, safetensors, etc.)')
45
+
46
+
47
+ class MetricsResult(BaseModel):
48
+ """Result type for actions that produce metrics only.
49
+
50
+ Use this for evaluation/testing actions that output metrics.
51
+
52
+ Example:
53
+ >>> class EvalAction(BaseAction[EvalParams, MetricsResult]):
54
+ ... def execute(self) -> MetricsResult:
55
+ ... return MetricsResult(
56
+ ... metrics={'mAP50': 0.85, 'mAP50-95': 0.72},
57
+ ... category='validation',
58
+ ... )
59
+ """
60
+
61
+ metrics: dict[str, float] = Field(description='Metric name to value mapping')
62
+ category: str = Field(default='default', description='Metrics category (train, validation, test)')
63
+
64
+
65
+ class TrainResult(BaseModel):
66
+ """Combined result type for training actions.
67
+
68
+ Includes both weights and training metrics. Use this for
69
+ standard training workflows.
70
+
71
+ Example:
72
+ >>> class TrainAction(BaseTrainAction[TrainParams, TrainResult]):
73
+ ... def execute(self) -> TrainResult:
74
+ ... return TrainResult(
75
+ ... weights_path='/models/best.pt',
76
+ ... final_epoch=100,
77
+ ... best_epoch=85,
78
+ ... train_metrics={'loss': 0.05},
79
+ ... val_metrics={'mAP50': 0.85, 'mAP50-95': 0.72},
80
+ ... )
81
+ """
82
+
83
+ weights_path: str = Field(description='Path to trained model weights')
84
+ final_epoch: int = Field(description='Last completed epoch')
85
+ best_epoch: int | None = Field(default=None, description='Best epoch by validation metric')
86
+ train_metrics: dict[str, float] = Field(default_factory=dict, description='Final training metrics')
87
+ val_metrics: dict[str, float] = Field(default_factory=dict, description='Final validation metrics')
88
+
89
+
90
+ class InferenceResult(BaseModel):
91
+ """Result type for inference actions.
92
+
93
+ Generic container for inference outputs.
94
+
95
+ Example:
96
+ >>> class InferAction(BaseInferenceAction[InferParams, InferenceResult]):
97
+ ... def execute(self) -> InferenceResult:
98
+ ... return InferenceResult(
99
+ ... predictions=[{'class': 'dog', 'confidence': 0.95}],
100
+ ... processed_count=100,
101
+ ... )
102
+ """
103
+
104
+ predictions: list[dict[str, Any]] = Field(default_factory=list, description='List of prediction results')
105
+ processed_count: int = Field(default=0, description='Number of items processed')
106
+ output_path: str | None = Field(default=None, description='Path to output file if results were saved')
107
+
108
+
109
+ class ExportResult(BaseModel):
110
+ """Result type for export actions.
111
+
112
+ Example:
113
+ >>> class ExportAction(BaseExportAction[ExportParams, ExportResult]):
114
+ ... def execute(self) -> ExportResult:
115
+ ... return ExportResult(
116
+ ... output_path='/exports/dataset.zip',
117
+ ... exported_count=1000,
118
+ ... format='coco',
119
+ ... )
120
+ """
121
+
122
+ output_path: str = Field(description='Path to exported file/directory')
123
+ exported_count: int = Field(description='Number of items exported')
124
+ format: str = Field(description='Export format (coco, yolo, voc, csv, etc.)')
125
+ file_size_bytes: int | None = Field(default=None, description='Size of exported file in bytes')
126
+
127
+
128
+ class UploadResult(BaseModel):
129
+ """Result type for upload actions.
130
+
131
+ Example:
132
+ >>> class UploadAction(BaseUploadAction[UploadParams, UploadResult]):
133
+ ... def execute(self) -> UploadResult:
134
+ ... return UploadResult(
135
+ ... uploaded_count=500,
136
+ ... remote_path='s3://bucket/dataset/',
137
+ ... )
138
+ """
139
+
140
+ uploaded_count: int = Field(description='Number of items uploaded')
141
+ remote_path: str | None = Field(default=None, description='Remote path or URL where data was uploaded')
142
+ status: str = Field(default='completed', description='Upload status')
143
+
144
+
145
+ __all__ = [
146
+ 'ExportResult',
147
+ 'InferenceResult',
148
+ 'MetricsResult',
149
+ 'TrainResult',
150
+ 'UploadResult',
151
+ 'WeightsResult',
152
+ ]
@@ -0,0 +1,63 @@
1
+ """Step workflow module for Synapse SDK.
2
+
3
+ This module provides the core abstractions for building step-based workflows.
4
+ Classes here are not pipeline-specific and can be used standalone for any
5
+ action-based workflow.
6
+
7
+ Classes:
8
+ BaseStep: Abstract base class for implementing individual steps.
9
+ StepResult: Data class representing the result of a step execution.
10
+ BaseStepContext: Context shared between steps during execution.
11
+ StepRegistry: Registry for managing step registration and ordering.
12
+ Orchestrator: Executes steps in order and handles rollback on failure.
13
+
14
+ Utility Steps:
15
+ LoggingStep: Wrapper that adds logging to step execution.
16
+ TimingStep: Wrapper that adds timing measurement to step execution.
17
+ ValidationStep: Wrapper that adds pre-execution validation to steps.
18
+
19
+ Example:
20
+ >>> from synapse_sdk.plugins.steps import (
21
+ ... BaseStep,
22
+ ... BaseStepContext,
23
+ ... Orchestrator,
24
+ ... StepRegistry,
25
+ ... StepResult,
26
+ ... )
27
+ >>>
28
+ >>> @dataclass
29
+ ... class MyContext(BaseStepContext):
30
+ ... data: list[str] = field(default_factory=list)
31
+ >>>
32
+ >>> class LoadStep(BaseStep[MyContext]):
33
+ ... @property
34
+ ... def name(self) -> str:
35
+ ... return 'load'
36
+ ...
37
+ ... @property
38
+ ... def progress_weight(self) -> float:
39
+ ... return 0.3
40
+ ...
41
+ ... def execute(self, context: MyContext) -> StepResult:
42
+ ... context.data.append('loaded')
43
+ ... return StepResult(success=True)
44
+ """
45
+
46
+ from synapse_sdk.plugins.steps.base import BaseStep, StepResult
47
+ from synapse_sdk.plugins.steps.context import BaseStepContext
48
+ from synapse_sdk.plugins.steps.orchestrator import Orchestrator
49
+ from synapse_sdk.plugins.steps.registry import StepRegistry
50
+ from synapse_sdk.plugins.steps.utils import LoggingStep, TimingStep, ValidationStep
51
+
52
+ __all__ = [
53
+ # Core
54
+ 'BaseStep',
55
+ 'BaseStepContext',
56
+ 'Orchestrator',
57
+ 'StepRegistry',
58
+ 'StepResult',
59
+ # Utilities
60
+ 'LoggingStep',
61
+ 'TimingStep',
62
+ 'ValidationStep',
63
+ ]