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.
- synapse_sdk/__init__.py +24 -0
- synapse_sdk/cli/__init__.py +9 -8
- synapse_sdk/cli/agent/__init__.py +25 -0
- synapse_sdk/cli/agent/config.py +104 -0
- synapse_sdk/cli/agent/select.py +197 -0
- synapse_sdk/cli/auth.py +104 -0
- synapse_sdk/cli/main.py +1025 -0
- synapse_sdk/cli/plugin/__init__.py +58 -0
- synapse_sdk/cli/plugin/create.py +566 -0
- synapse_sdk/cli/plugin/job.py +196 -0
- synapse_sdk/cli/plugin/publish.py +322 -0
- synapse_sdk/cli/plugin/run.py +131 -0
- synapse_sdk/cli/plugin/test.py +200 -0
- synapse_sdk/clients/README.md +239 -0
- synapse_sdk/clients/__init__.py +5 -0
- synapse_sdk/clients/_template.py +266 -0
- synapse_sdk/clients/agent/__init__.py +84 -29
- synapse_sdk/clients/agent/async_ray.py +289 -0
- synapse_sdk/clients/agent/container.py +83 -0
- synapse_sdk/clients/agent/plugin.py +101 -0
- synapse_sdk/clients/agent/ray.py +296 -39
- synapse_sdk/clients/backend/__init__.py +152 -12
- synapse_sdk/clients/backend/annotation.py +164 -22
- synapse_sdk/clients/backend/core.py +101 -0
- synapse_sdk/clients/backend/data_collection.py +292 -0
- synapse_sdk/clients/backend/hitl.py +87 -0
- synapse_sdk/clients/backend/integration.py +374 -46
- synapse_sdk/clients/backend/ml.py +134 -22
- synapse_sdk/clients/backend/models.py +247 -0
- synapse_sdk/clients/base.py +538 -59
- synapse_sdk/clients/exceptions.py +35 -7
- synapse_sdk/clients/pipeline/__init__.py +5 -0
- synapse_sdk/clients/pipeline/client.py +636 -0
- synapse_sdk/clients/protocols.py +178 -0
- synapse_sdk/clients/utils.py +86 -8
- synapse_sdk/clients/validation.py +58 -0
- synapse_sdk/enums.py +76 -0
- synapse_sdk/exceptions.py +168 -0
- synapse_sdk/integrations/__init__.py +74 -0
- synapse_sdk/integrations/_base.py +119 -0
- synapse_sdk/integrations/_context.py +53 -0
- synapse_sdk/integrations/ultralytics/__init__.py +78 -0
- synapse_sdk/integrations/ultralytics/_callbacks.py +126 -0
- synapse_sdk/integrations/ultralytics/_patches.py +124 -0
- synapse_sdk/loggers.py +476 -95
- synapse_sdk/mcp/MCP.md +69 -0
- synapse_sdk/mcp/__init__.py +48 -0
- synapse_sdk/mcp/__main__.py +6 -0
- synapse_sdk/mcp/config.py +349 -0
- synapse_sdk/mcp/prompts/__init__.py +4 -0
- synapse_sdk/mcp/resources/__init__.py +4 -0
- synapse_sdk/mcp/server.py +1352 -0
- synapse_sdk/mcp/tools/__init__.py +6 -0
- synapse_sdk/plugins/__init__.py +133 -9
- synapse_sdk/plugins/action.py +229 -0
- synapse_sdk/plugins/actions/__init__.py +82 -0
- synapse_sdk/plugins/actions/dataset/__init__.py +37 -0
- synapse_sdk/plugins/actions/dataset/action.py +471 -0
- synapse_sdk/plugins/actions/export/__init__.py +55 -0
- synapse_sdk/plugins/actions/export/action.py +183 -0
- synapse_sdk/plugins/actions/export/context.py +59 -0
- synapse_sdk/plugins/actions/inference/__init__.py +84 -0
- synapse_sdk/plugins/actions/inference/action.py +285 -0
- synapse_sdk/plugins/actions/inference/context.py +81 -0
- synapse_sdk/plugins/actions/inference/deployment.py +322 -0
- synapse_sdk/plugins/actions/inference/serve.py +252 -0
- synapse_sdk/plugins/actions/train/__init__.py +54 -0
- synapse_sdk/plugins/actions/train/action.py +326 -0
- synapse_sdk/plugins/actions/train/context.py +57 -0
- synapse_sdk/plugins/actions/upload/__init__.py +49 -0
- synapse_sdk/plugins/actions/upload/action.py +165 -0
- synapse_sdk/plugins/actions/upload/context.py +61 -0
- synapse_sdk/plugins/config.py +98 -0
- synapse_sdk/plugins/context/__init__.py +109 -0
- synapse_sdk/plugins/context/env.py +113 -0
- synapse_sdk/plugins/datasets/__init__.py +113 -0
- synapse_sdk/plugins/datasets/converters/__init__.py +76 -0
- synapse_sdk/plugins/datasets/converters/base.py +347 -0
- synapse_sdk/plugins/datasets/converters/yolo/__init__.py +9 -0
- synapse_sdk/plugins/datasets/converters/yolo/from_dm.py +468 -0
- synapse_sdk/plugins/datasets/converters/yolo/to_dm.py +381 -0
- synapse_sdk/plugins/datasets/formats/__init__.py +82 -0
- synapse_sdk/plugins/datasets/formats/dm.py +351 -0
- synapse_sdk/plugins/datasets/formats/yolo.py +240 -0
- synapse_sdk/plugins/decorators.py +83 -0
- synapse_sdk/plugins/discovery.py +790 -0
- synapse_sdk/plugins/docs/ACTION_DEV_GUIDE.md +933 -0
- synapse_sdk/plugins/docs/ARCHITECTURE.md +1225 -0
- synapse_sdk/plugins/docs/LOGGING_SYSTEM.md +683 -0
- synapse_sdk/plugins/docs/OVERVIEW.md +531 -0
- synapse_sdk/plugins/docs/PIPELINE_GUIDE.md +145 -0
- synapse_sdk/plugins/docs/README.md +513 -0
- synapse_sdk/plugins/docs/STEP.md +656 -0
- synapse_sdk/plugins/enums.py +70 -10
- synapse_sdk/plugins/errors.py +92 -0
- synapse_sdk/plugins/executors/__init__.py +43 -0
- synapse_sdk/plugins/executors/local.py +99 -0
- synapse_sdk/plugins/executors/ray/__init__.py +18 -0
- synapse_sdk/plugins/executors/ray/base.py +282 -0
- synapse_sdk/plugins/executors/ray/job.py +298 -0
- synapse_sdk/plugins/executors/ray/jobs_api.py +511 -0
- synapse_sdk/plugins/executors/ray/packaging.py +137 -0
- synapse_sdk/plugins/executors/ray/pipeline.py +792 -0
- synapse_sdk/plugins/executors/ray/task.py +257 -0
- synapse_sdk/plugins/models/__init__.py +26 -0
- synapse_sdk/plugins/models/logger.py +173 -0
- synapse_sdk/plugins/models/pipeline.py +25 -0
- synapse_sdk/plugins/pipelines/__init__.py +81 -0
- synapse_sdk/plugins/pipelines/action_pipeline.py +417 -0
- synapse_sdk/plugins/pipelines/context.py +107 -0
- synapse_sdk/plugins/pipelines/display.py +311 -0
- synapse_sdk/plugins/runner.py +114 -0
- synapse_sdk/plugins/schemas/__init__.py +19 -0
- synapse_sdk/plugins/schemas/results.py +152 -0
- synapse_sdk/plugins/steps/__init__.py +63 -0
- synapse_sdk/plugins/steps/base.py +128 -0
- synapse_sdk/plugins/steps/context.py +90 -0
- synapse_sdk/plugins/steps/orchestrator.py +128 -0
- synapse_sdk/plugins/steps/registry.py +103 -0
- synapse_sdk/plugins/steps/utils/__init__.py +20 -0
- synapse_sdk/plugins/steps/utils/logging.py +85 -0
- synapse_sdk/plugins/steps/utils/timing.py +71 -0
- synapse_sdk/plugins/steps/utils/validation.py +68 -0
- synapse_sdk/plugins/templates/__init__.py +50 -0
- synapse_sdk/plugins/templates/base/.gitignore.j2 +26 -0
- synapse_sdk/plugins/templates/base/.synapseignore.j2 +11 -0
- synapse_sdk/plugins/templates/base/README.md.j2 +26 -0
- synapse_sdk/plugins/templates/base/plugin/__init__.py.j2 +1 -0
- synapse_sdk/plugins/templates/base/pyproject.toml.j2 +14 -0
- synapse_sdk/plugins/templates/base/requirements.txt.j2 +1 -0
- synapse_sdk/plugins/templates/custom/plugin/main.py.j2 +18 -0
- synapse_sdk/plugins/templates/data_validation/plugin/validate.py.j2 +32 -0
- synapse_sdk/plugins/templates/export/plugin/export.py.j2 +36 -0
- synapse_sdk/plugins/templates/neural_net/plugin/inference.py.j2 +36 -0
- synapse_sdk/plugins/templates/neural_net/plugin/train.py.j2 +33 -0
- synapse_sdk/plugins/templates/post_annotation/plugin/post_annotate.py.j2 +32 -0
- synapse_sdk/plugins/templates/pre_annotation/plugin/pre_annotate.py.j2 +32 -0
- synapse_sdk/plugins/templates/smart_tool/plugin/auto_label.py.j2 +44 -0
- synapse_sdk/plugins/templates/upload/plugin/upload.py.j2 +35 -0
- synapse_sdk/plugins/testing/__init__.py +25 -0
- synapse_sdk/plugins/testing/sample_actions.py +98 -0
- synapse_sdk/plugins/types.py +206 -0
- synapse_sdk/plugins/upload.py +595 -64
- synapse_sdk/plugins/utils.py +325 -37
- synapse_sdk/shared/__init__.py +25 -0
- synapse_sdk/utils/__init__.py +1 -0
- synapse_sdk/utils/auth.py +74 -0
- synapse_sdk/utils/file/__init__.py +58 -0
- synapse_sdk/utils/file/archive.py +449 -0
- synapse_sdk/utils/file/checksum.py +167 -0
- synapse_sdk/utils/file/download.py +286 -0
- synapse_sdk/utils/file/io.py +129 -0
- synapse_sdk/utils/file/requirements.py +36 -0
- synapse_sdk/utils/network.py +168 -0
- synapse_sdk/utils/storage/__init__.py +238 -0
- synapse_sdk/utils/storage/config.py +188 -0
- synapse_sdk/utils/storage/errors.py +52 -0
- synapse_sdk/utils/storage/providers/__init__.py +13 -0
- synapse_sdk/utils/storage/providers/base.py +76 -0
- synapse_sdk/utils/storage/providers/gcs.py +168 -0
- synapse_sdk/utils/storage/providers/http.py +250 -0
- synapse_sdk/utils/storage/providers/local.py +126 -0
- synapse_sdk/utils/storage/providers/s3.py +177 -0
- synapse_sdk/utils/storage/providers/sftp.py +208 -0
- synapse_sdk/utils/storage/registry.py +125 -0
- synapse_sdk/utils/websocket.py +99 -0
- synapse_sdk-2026.1.1b2.dist-info/METADATA +715 -0
- synapse_sdk-2026.1.1b2.dist-info/RECORD +172 -0
- {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/WHEEL +1 -1
- synapse_sdk-2026.1.1b2.dist-info/licenses/LICENSE +201 -0
- locale/en/LC_MESSAGES/messages.mo +0 -0
- locale/en/LC_MESSAGES/messages.po +0 -39
- locale/ko/LC_MESSAGES/messages.mo +0 -0
- locale/ko/LC_MESSAGES/messages.po +0 -34
- synapse_sdk/cli/create_plugin.py +0 -10
- synapse_sdk/clients/agent/core.py +0 -7
- synapse_sdk/clients/agent/service.py +0 -15
- synapse_sdk/clients/backend/dataset.py +0 -51
- synapse_sdk/clients/ray/__init__.py +0 -6
- synapse_sdk/clients/ray/core.py +0 -22
- synapse_sdk/clients/ray/serve.py +0 -20
- synapse_sdk/i18n.py +0 -35
- synapse_sdk/plugins/categories/__init__.py +0 -0
- synapse_sdk/plugins/categories/base.py +0 -235
- synapse_sdk/plugins/categories/data_validation/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/actions/validation.py +0 -10
- synapse_sdk/plugins/categories/data_validation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/data_validation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +0 -5
- synapse_sdk/plugins/categories/decorators.py +0 -13
- synapse_sdk/plugins/categories/export/__init__.py +0 -0
- synapse_sdk/plugins/categories/export/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/export/actions/export.py +0 -10
- synapse_sdk/plugins/categories/import/__init__.py +0 -0
- synapse_sdk/plugins/categories/import/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/import/actions/import.py +0 -10
- synapse_sdk/plugins/categories/neural_net/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/actions/deployment.py +0 -45
- synapse_sdk/plugins/categories/neural_net/actions/inference.py +0 -18
- synapse_sdk/plugins/categories/neural_net/actions/test.py +0 -10
- synapse_sdk/plugins/categories/neural_net/actions/train.py +0 -143
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +0 -12
- synapse_sdk/plugins/categories/neural_net/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +0 -4
- synapse_sdk/plugins/categories/neural_net/templates/plugin/test.py +0 -2
- synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py +0 -14
- synapse_sdk/plugins/categories/post_annotation/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py +0 -10
- synapse_sdk/plugins/categories/post_annotation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/post_annotation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.py +0 -3
- synapse_sdk/plugins/categories/pre_annotation/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py +0 -10
- synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py +0 -3
- synapse_sdk/plugins/categories/registry.py +0 -16
- synapse_sdk/plugins/categories/smart_tool/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/actions/auto_label.py +0 -37
- synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +0 -7
- synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py +0 -11
- synapse_sdk/plugins/categories/templates.py +0 -32
- synapse_sdk/plugins/cli/__init__.py +0 -21
- synapse_sdk/plugins/cli/publish.py +0 -37
- synapse_sdk/plugins/cli/run.py +0 -67
- synapse_sdk/plugins/exceptions.py +0 -22
- synapse_sdk/plugins/models.py +0 -121
- synapse_sdk/plugins/templates/cookiecutter.json +0 -11
- synapse_sdk/plugins/templates/hooks/post_gen_project.py +0 -3
- synapse_sdk/plugins/templates/hooks/pre_prompt.py +0 -21
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.gitignore +0 -27
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.pre-commit-config.yaml +0 -7
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/README.md +0 -5
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +0 -6
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/plugin/__init__.py +0 -0
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml +0 -13
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +0 -1
- synapse_sdk/shared/enums.py +0 -8
- synapse_sdk/utils/debug.py +0 -5
- synapse_sdk/utils/file.py +0 -87
- synapse_sdk/utils/module_loading.py +0 -29
- synapse_sdk/utils/pydantic/__init__.py +0 -0
- synapse_sdk/utils/pydantic/config.py +0 -4
- synapse_sdk/utils/pydantic/errors.py +0 -33
- synapse_sdk/utils/pydantic/validators.py +0 -7
- synapse_sdk/utils/storage.py +0 -91
- synapse_sdk/utils/string.py +0 -11
- synapse_sdk-1.0.0a11.dist-info/LICENSE +0 -21
- synapse_sdk-1.0.0a11.dist-info/METADATA +0 -43
- synapse_sdk-1.0.0a11.dist-info/RECORD +0 -111
- {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/entry_points.txt +0 -0
- {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']
|