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,298 @@
1
+ """Ray Job executor for plugin actions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING, Any, Literal
7
+
8
+ from synapse_sdk.plugins.context import PluginEnvironment
9
+ from synapse_sdk.plugins.enums import PackageManager
10
+ from synapse_sdk.plugins.errors import ExecutionError
11
+ from synapse_sdk.plugins.executors.ray.base import BaseRayExecutor
12
+
13
+ if TYPE_CHECKING:
14
+ from synapse_sdk.plugins.action import BaseAction
15
+
16
+
17
+ class RayJobExecutor(BaseRayExecutor):
18
+ """Ray Job based asynchronous execution.
19
+
20
+ Submits actions as detached Ray tasks. Best for heavy/long-running
21
+ workloads that don't need immediate results.
22
+
23
+ Example:
24
+ >>> executor = RayJobExecutor(
25
+ ... ray_address='auto',
26
+ ... working_dir='/path/to/plugin',
27
+ ... )
28
+ >>> job_id = executor.submit(TrainAction, {'epochs': 100})
29
+ >>> status = executor.get_status(job_id)
30
+ >>> result = executor.get_result(job_id)
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ env: PluginEnvironment | dict[str, Any] | None = None,
36
+ *,
37
+ ray_address: str = 'auto',
38
+ runtime_env: dict[str, Any] | None = None,
39
+ working_dir: str | Path | None = None,
40
+ requirements_file: str | Path | None = None,
41
+ package_manager: PackageManager | Literal['pip', 'uv'] = PackageManager.PIP,
42
+ package_manager_options: list[str] | None = None,
43
+ wheels_dir: str = 'wheels',
44
+ num_cpus: int | None = None,
45
+ num_gpus: int | None = None,
46
+ include_sdk: bool = False,
47
+ job_id: str | None = None,
48
+ ) -> None:
49
+ """Initialize Ray job executor.
50
+
51
+ Args:
52
+ env: Environment config for the action. If None, loads from os.environ.
53
+ ray_address: Ray cluster address. Defaults to 'auto'.
54
+ runtime_env: Ray runtime environment config.
55
+ working_dir: Plugin working directory.
56
+ requirements_file: Path to requirements.txt.
57
+ package_manager: Package manager to use ('pip' or 'uv').
58
+ package_manager_options: Additional options for the package manager.
59
+ wheels_dir: Directory containing .whl files relative to working_dir.
60
+ num_cpus: Number of CPUs to request.
61
+ num_gpus: Number of GPUs to request.
62
+ include_sdk: If True, bundle local SDK with upload (for development).
63
+ job_id: Optional job identifier for tracking.
64
+ """
65
+ super().__init__(
66
+ env=env,
67
+ runtime_env=runtime_env,
68
+ working_dir=working_dir,
69
+ requirements_file=requirements_file,
70
+ package_manager=package_manager,
71
+ package_manager_options=package_manager_options,
72
+ wheels_dir=wheels_dir,
73
+ ray_address=ray_address,
74
+ include_sdk=include_sdk,
75
+ )
76
+ self._num_cpus = num_cpus
77
+ self._num_gpus = num_gpus
78
+ self._job_id = job_id
79
+ self._submitted_refs: dict[str, Any] = {} # job_id -> ObjectRef
80
+
81
+ def submit(
82
+ self,
83
+ action_cls: type[BaseAction] | str,
84
+ params: dict[str, Any],
85
+ *,
86
+ job_id: str | None = None,
87
+ ) -> str:
88
+ """Submit action as a Ray task (non-blocking).
89
+
90
+ Args:
91
+ action_cls: BaseAction subclass or entrypoint string.
92
+ params: Parameters dict for the action.
93
+ job_id: Optional job identifier. If None, generates one.
94
+
95
+ Returns:
96
+ Job ID for tracking.
97
+ """
98
+ import uuid
99
+
100
+ import ray
101
+
102
+ self._ray_init()
103
+
104
+ # Convert class to entrypoint string
105
+ if isinstance(action_cls, str):
106
+ entrypoint = action_cls
107
+ else:
108
+ entrypoint = f'{action_cls.__module__}.{action_cls.__name__}'
109
+
110
+ # Generate job_id if not provided
111
+ job_id = job_id or self._job_id or str(uuid.uuid4())[:8]
112
+
113
+ # Build remote options
114
+ remote_options: dict[str, Any] = {'runtime_env': self._build_runtime_env()}
115
+ if self._num_cpus is not None:
116
+ remote_options['num_cpus'] = self._num_cpus
117
+ if self._num_gpus is not None:
118
+ remote_options['num_gpus'] = self._num_gpus
119
+
120
+ # Create actor and submit (actor pattern works with remote clusters)
121
+ JobActor = ray.remote(**remote_options)(_JobExecutorActor)
122
+ actor = JobActor.remote(job_id)
123
+ ref = actor.run_action.remote(entrypoint, params)
124
+
125
+ self._submitted_refs[job_id] = ref
126
+ return job_id
127
+
128
+ def get_status(self, job_id: str) -> str:
129
+ """Get job status.
130
+
131
+ Args:
132
+ job_id: Job ID from submit().
133
+
134
+ Returns:
135
+ 'PENDING', 'RUNNING', 'SUCCEEDED', or 'FAILED'.
136
+ """
137
+ import ray
138
+
139
+ ref = self._submitted_refs.get(job_id)
140
+ if ref is None:
141
+ return 'UNKNOWN'
142
+
143
+ ready, _ = ray.wait([ref], timeout=0)
144
+ if ready:
145
+ try:
146
+ ray.get(ref)
147
+ return 'SUCCEEDED'
148
+ except Exception:
149
+ return 'FAILED'
150
+ return 'RUNNING'
151
+
152
+ def get_result(self, job_id: str, timeout: float | None = None) -> Any:
153
+ """Get job result (blocks until complete).
154
+
155
+ Args:
156
+ job_id: Job ID from submit().
157
+ timeout: Optional timeout in seconds.
158
+
159
+ Returns:
160
+ Action result.
161
+
162
+ Raises:
163
+ ExecutionError: If job failed or not found.
164
+ """
165
+ import ray
166
+
167
+ ref = self._submitted_refs.get(job_id)
168
+ if ref is None:
169
+ raise ExecutionError(f'Job {job_id} not found')
170
+
171
+ try:
172
+ return ray.get(ref, timeout=timeout)
173
+ except Exception as e:
174
+ raise ExecutionError(f'Job {job_id} failed: {e}') from e
175
+
176
+ def wait(self, job_id: str, timeout_seconds: float = 300) -> str:
177
+ """Wait for job to complete.
178
+
179
+ Args:
180
+ job_id: Job ID from submit().
181
+ timeout_seconds: Maximum time to wait.
182
+
183
+ Returns:
184
+ Final job status.
185
+
186
+ Raises:
187
+ ExecutionError: If job fails or times out.
188
+ """
189
+ import ray
190
+
191
+ ref = self._submitted_refs.get(job_id)
192
+ if ref is None:
193
+ raise ExecutionError(f'Job {job_id} not found')
194
+
195
+ try:
196
+ ray.get(ref, timeout=timeout_seconds)
197
+ return 'SUCCEEDED'
198
+ except ray.exceptions.GetTimeoutError:
199
+ raise ExecutionError(f'Job {job_id} timed out after {timeout_seconds}s')
200
+ except Exception as e:
201
+ raise ExecutionError(f'Job {job_id} failed: {e}') from e
202
+
203
+ def get_logs(self, job_id: str) -> str:
204
+ """Get job logs (not available for ray.remote tasks)."""
205
+ return ''
206
+
207
+
208
+ class _JobExecutorActor:
209
+ """Ray Actor that executes plugin actions for job mode.
210
+
211
+ Each job gets its own actor instance (not reused like task mode).
212
+ """
213
+
214
+ def __init__(self, job_id: str | None = None) -> None:
215
+ """Initialize the actor.
216
+
217
+ Args:
218
+ job_id: Optional job identifier for tracking.
219
+ """
220
+ self._job_id = job_id
221
+
222
+ def run_action(
223
+ self,
224
+ entrypoint: str,
225
+ params: dict[str, Any],
226
+ ) -> Any:
227
+ """Execute an action within this actor.
228
+
229
+ Args:
230
+ entrypoint: Action entrypoint string (e.g., 'plugin.test.TestAction').
231
+ params: Parameters dict to validate and pass.
232
+
233
+ Returns:
234
+ Action result from execute().
235
+ """
236
+ import importlib
237
+ import logging
238
+ import os
239
+ import sys
240
+
241
+ # Configure logging to ensure ConsoleLogger output is visible
242
+ # This is needed because Ray workers don't have logging configured by default
243
+ logging.basicConfig(
244
+ level=logging.INFO,
245
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
246
+ force=True, # Override any existing config
247
+ )
248
+
249
+ from synapse_sdk.loggers import ConsoleLogger
250
+ from synapse_sdk.plugins.context import RuntimeContext
251
+ from synapse_sdk.plugins.errors import ExecutionError, ValidationError
252
+
253
+ # Ensure working directory is in sys.path
254
+ cwd = os.getcwd()
255
+ if cwd not in sys.path:
256
+ sys.path.insert(0, cwd)
257
+
258
+ # Dynamically import action class
259
+ try:
260
+ module_path, class_name = entrypoint.rsplit('.', 1)
261
+ module = importlib.import_module(module_path)
262
+ action_cls = getattr(module, class_name)
263
+ except Exception as e:
264
+ raise ExecutionError(f'Failed to import action {entrypoint}: {e}') from e
265
+
266
+ # Validate params
267
+ try:
268
+ validated_params = action_cls.params_model.model_validate(params)
269
+ except Exception as e:
270
+ raise ValidationError(f'Parameter validation failed: {e}') from e
271
+
272
+ # Try to create BackendClient from environment/credentials
273
+ from synapse_sdk.utils.auth import create_backend_client
274
+
275
+ client = create_backend_client()
276
+
277
+ # Build context
278
+ logger = ConsoleLogger()
279
+ ctx = RuntimeContext(
280
+ logger=logger,
281
+ env=dict(os.environ),
282
+ job_id=self._job_id,
283
+ client=client,
284
+ )
285
+
286
+ # Execute
287
+ action = action_cls(validated_params, ctx)
288
+ try:
289
+ result = action.execute()
290
+ except Exception as e:
291
+ logger.finish()
292
+ raise ExecutionError(f'Action execution failed: {e}') from e
293
+
294
+ logger.finish()
295
+ return result
296
+
297
+
298
+ __all__ = ['RayJobExecutor']