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,257 @@
|
|
|
1
|
+
"""Ray Actor 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, read_requirements
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from synapse_sdk.plugins.action import BaseAction
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RayActorExecutor(BaseRayExecutor):
|
|
18
|
+
"""Ray Actor based synchronous task execution.
|
|
19
|
+
|
|
20
|
+
Executes actions using a persistent Ray Actor. Best for fast startup
|
|
21
|
+
with pre-warmed workers. The actor maintains state across executions
|
|
22
|
+
and methods are executed serially within each actor.
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
>>> executor = RayActorExecutor(
|
|
26
|
+
... ray_address='auto',
|
|
27
|
+
... working_dir='/path/to/plugin', # Auto-reads requirements.txt
|
|
28
|
+
... )
|
|
29
|
+
>>> result = executor.execute(TrainAction, {'epochs': 10})
|
|
30
|
+
>>> # Reuse the same actor for subsequent executions
|
|
31
|
+
>>> result2 = executor.execute(InferAction, {'batch_size': 32})
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
env: PluginEnvironment | dict[str, Any] | None = None,
|
|
37
|
+
job_id: str | None = None,
|
|
38
|
+
*,
|
|
39
|
+
ray_address: str = 'auto',
|
|
40
|
+
runtime_env: dict[str, Any] | None = None,
|
|
41
|
+
working_dir: str | Path | None = None,
|
|
42
|
+
requirements_file: str | Path | None = None,
|
|
43
|
+
package_manager: PackageManager | Literal['pip', 'uv'] = PackageManager.PIP,
|
|
44
|
+
package_manager_options: list[str] | None = None,
|
|
45
|
+
wheels_dir: str = 'wheels',
|
|
46
|
+
num_cpus: int | None = None,
|
|
47
|
+
num_gpus: int | None = None,
|
|
48
|
+
include_sdk: bool = False,
|
|
49
|
+
) -> None:
|
|
50
|
+
"""Initialize Ray actor executor.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
env: Environment config for the action. If None, loads from os.environ.
|
|
54
|
+
job_id: Optional job identifier for tracking.
|
|
55
|
+
ray_address: Ray cluster address. Defaults to 'auto'.
|
|
56
|
+
runtime_env: Ray runtime environment config (pip packages, working_dir, env_vars).
|
|
57
|
+
working_dir: Plugin working directory. Sets runtime_env['working_dir'] and
|
|
58
|
+
auto-reads requirements.txt if requirements_file is not specified.
|
|
59
|
+
requirements_file: Path to requirements.txt. If None and working_dir is set,
|
|
60
|
+
looks for requirements.txt in working_dir.
|
|
61
|
+
package_manager: Package manager to use ('pip' or 'uv'). Defaults to 'pip'.
|
|
62
|
+
package_manager_options: Additional options for the package manager.
|
|
63
|
+
For uv: defaults to ['--no-cache']. For pip: defaults to ['--upgrade'].
|
|
64
|
+
wheels_dir: Directory containing .whl files relative to working_dir (default: 'wheels').
|
|
65
|
+
num_cpus: Number of CPUs to request for the actor.
|
|
66
|
+
num_gpus: Number of GPUs to request for the actor.
|
|
67
|
+
include_sdk: If True, bundle local SDK with upload (for development).
|
|
68
|
+
"""
|
|
69
|
+
super().__init__(
|
|
70
|
+
env=env,
|
|
71
|
+
runtime_env=runtime_env,
|
|
72
|
+
working_dir=working_dir,
|
|
73
|
+
requirements_file=requirements_file,
|
|
74
|
+
package_manager=package_manager,
|
|
75
|
+
package_manager_options=package_manager_options,
|
|
76
|
+
wheels_dir=wheels_dir,
|
|
77
|
+
ray_address=ray_address,
|
|
78
|
+
include_sdk=include_sdk,
|
|
79
|
+
)
|
|
80
|
+
self._job_id = job_id
|
|
81
|
+
self._num_cpus = num_cpus
|
|
82
|
+
self._num_gpus = num_gpus
|
|
83
|
+
self._actor: Any | None = None
|
|
84
|
+
|
|
85
|
+
def _get_or_create_actor(self) -> Any:
|
|
86
|
+
"""Get existing actor or create a new one."""
|
|
87
|
+
import ray
|
|
88
|
+
|
|
89
|
+
if self._actor is not None:
|
|
90
|
+
return self._actor
|
|
91
|
+
|
|
92
|
+
self._ray_init()
|
|
93
|
+
|
|
94
|
+
# Build remote options
|
|
95
|
+
remote_options: dict[str, Any] = {'runtime_env': self._build_runtime_env()}
|
|
96
|
+
if self._num_cpus is not None:
|
|
97
|
+
remote_options['num_cpus'] = self._num_cpus
|
|
98
|
+
if self._num_gpus is not None:
|
|
99
|
+
remote_options['num_gpus'] = self._num_gpus
|
|
100
|
+
|
|
101
|
+
# Create the actor class dynamically with ray.remote
|
|
102
|
+
ActionExecutorActor = ray.remote(**remote_options)(_ActionExecutorActor)
|
|
103
|
+
self._actor = ActionExecutorActor.remote(self._job_id)
|
|
104
|
+
return self._actor
|
|
105
|
+
|
|
106
|
+
def execute(
|
|
107
|
+
self,
|
|
108
|
+
action_cls: type[BaseAction] | str,
|
|
109
|
+
params: dict[str, Any],
|
|
110
|
+
**kwargs: Any,
|
|
111
|
+
) -> Any:
|
|
112
|
+
"""Execute action using the Ray actor.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
action_cls: BaseAction subclass or entrypoint string (e.g., 'plugin.test.TestAction').
|
|
116
|
+
params: Parameters dict to validate and pass.
|
|
117
|
+
**kwargs: Ignored (for protocol compatibility).
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Action result from execute().
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
ValidationError: If params fail validation.
|
|
124
|
+
ExecutionError: If action execution fails.
|
|
125
|
+
"""
|
|
126
|
+
import ray
|
|
127
|
+
from ray.exceptions import RayActorError, RayTaskError
|
|
128
|
+
|
|
129
|
+
# Convert class to entrypoint string for remote import
|
|
130
|
+
if isinstance(action_cls, str):
|
|
131
|
+
entrypoint = action_cls
|
|
132
|
+
else:
|
|
133
|
+
entrypoint = f'{action_cls.__module__}.{action_cls.__name__}'
|
|
134
|
+
|
|
135
|
+
actor = self._get_or_create_actor()
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
return ray.get(actor.run_action.remote(entrypoint, params))
|
|
139
|
+
except (RayTaskError, RayActorError) as e:
|
|
140
|
+
# Actor may have died, reset it for next call
|
|
141
|
+
self._actor = None
|
|
142
|
+
cause = getattr(e, 'cause', e)
|
|
143
|
+
raise ExecutionError(f'Ray actor execution failed: {cause}') from e
|
|
144
|
+
|
|
145
|
+
def shutdown(self) -> None:
|
|
146
|
+
"""Shutdown the actor."""
|
|
147
|
+
import ray
|
|
148
|
+
|
|
149
|
+
if self._actor is not None:
|
|
150
|
+
ray.kill(self._actor)
|
|
151
|
+
self._actor = None
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class _ActionExecutorActor:
|
|
155
|
+
"""Ray Actor that executes plugin actions.
|
|
156
|
+
|
|
157
|
+
This actor maintains state across executions and provides
|
|
158
|
+
serial execution guarantees for methods called on it.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
def __init__(self, job_id: str | None = None) -> None:
|
|
162
|
+
"""Initialize the actor.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
job_id: Optional job identifier for tracking.
|
|
166
|
+
"""
|
|
167
|
+
self._job_id = job_id
|
|
168
|
+
|
|
169
|
+
def run_action(
|
|
170
|
+
self,
|
|
171
|
+
entrypoint: str,
|
|
172
|
+
params: dict[str, Any],
|
|
173
|
+
) -> Any:
|
|
174
|
+
"""Execute an action within this actor.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
entrypoint: Action entrypoint string (e.g., 'plugin.test.TestAction').
|
|
178
|
+
params: Parameters dict to validate and pass.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
Action result from execute().
|
|
182
|
+
|
|
183
|
+
Raises:
|
|
184
|
+
ValidationError: If params fail validation.
|
|
185
|
+
ExecutionError: If action execution fails.
|
|
186
|
+
"""
|
|
187
|
+
import importlib
|
|
188
|
+
import logging
|
|
189
|
+
import os
|
|
190
|
+
import sys
|
|
191
|
+
|
|
192
|
+
# Configure logging to ensure ConsoleLogger output is visible
|
|
193
|
+
# This is needed because Ray workers don't have logging configured by default
|
|
194
|
+
logging.basicConfig(
|
|
195
|
+
level=logging.INFO,
|
|
196
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
197
|
+
force=True, # Override any existing config
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
from synapse_sdk.loggers import ConsoleLogger
|
|
201
|
+
from synapse_sdk.plugins.action import NoResult, validate_result
|
|
202
|
+
from synapse_sdk.plugins.context import RuntimeContext
|
|
203
|
+
from synapse_sdk.plugins.errors import ExecutionError, ValidationError
|
|
204
|
+
from synapse_sdk.utils.auth import create_backend_client
|
|
205
|
+
|
|
206
|
+
# Dynamically import action class from entrypoint
|
|
207
|
+
try:
|
|
208
|
+
# Ensure working directory is in sys.path (Ray should do this, but be explicit)
|
|
209
|
+
cwd = os.getcwd()
|
|
210
|
+
if cwd not in sys.path:
|
|
211
|
+
sys.path.insert(0, cwd)
|
|
212
|
+
|
|
213
|
+
module_path, class_name = entrypoint.rsplit('.', 1)
|
|
214
|
+
module = importlib.import_module(module_path)
|
|
215
|
+
action_cls = getattr(module, class_name)
|
|
216
|
+
except Exception as e:
|
|
217
|
+
raise ExecutionError(f'Failed to import action {entrypoint}: {e}') from e
|
|
218
|
+
|
|
219
|
+
# Validate params
|
|
220
|
+
try:
|
|
221
|
+
validated_params = action_cls.params_model.model_validate(params)
|
|
222
|
+
except Exception as e:
|
|
223
|
+
raise ValidationError(f'Parameter validation failed: {e}') from e
|
|
224
|
+
|
|
225
|
+
# Try to create BackendClient from environment/credentials
|
|
226
|
+
client = create_backend_client()
|
|
227
|
+
|
|
228
|
+
# Build context (inside actor)
|
|
229
|
+
logger = ConsoleLogger()
|
|
230
|
+
ctx = RuntimeContext(
|
|
231
|
+
logger=logger,
|
|
232
|
+
env=dict(os.environ),
|
|
233
|
+
job_id=self._job_id,
|
|
234
|
+
client=client,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
# Execute
|
|
238
|
+
action = action_cls(validated_params, ctx)
|
|
239
|
+
try:
|
|
240
|
+
result = action.execute()
|
|
241
|
+
except Exception as e:
|
|
242
|
+
logger.finish()
|
|
243
|
+
raise ExecutionError(f'Action execution failed: {e}') from e
|
|
244
|
+
|
|
245
|
+
# Validate result with warning-only mode
|
|
246
|
+
result_model = getattr(action_cls, 'result_model', NoResult)
|
|
247
|
+
if result_model is not NoResult:
|
|
248
|
+
result = validate_result(result, result_model, logger)
|
|
249
|
+
|
|
250
|
+
logger.finish()
|
|
251
|
+
return result
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
# Keep old name as alias for backwards compatibility
|
|
255
|
+
RayTaskExecutor = RayActorExecutor
|
|
256
|
+
|
|
257
|
+
__all__ = ['RayActorExecutor', 'RayTaskExecutor', 'read_requirements']
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Plugin models module."""
|
|
2
|
+
|
|
3
|
+
from synapse_sdk.plugins.models.logger import (
|
|
4
|
+
ActionProgress,
|
|
5
|
+
Checkpoint,
|
|
6
|
+
LogEntry,
|
|
7
|
+
LoggerBackend,
|
|
8
|
+
LogLevel,
|
|
9
|
+
PipelineProgress,
|
|
10
|
+
ProgressData,
|
|
11
|
+
)
|
|
12
|
+
from synapse_sdk.plugins.models.pipeline import ActionStatus, RunStatus
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
# pipeline.py
|
|
16
|
+
'RunStatus',
|
|
17
|
+
'ActionStatus',
|
|
18
|
+
# logger.py
|
|
19
|
+
'LogLevel',
|
|
20
|
+
'ProgressData',
|
|
21
|
+
'LogEntry',
|
|
22
|
+
'LoggerBackend',
|
|
23
|
+
'ActionProgress',
|
|
24
|
+
'PipelineProgress',
|
|
25
|
+
'Checkpoint',
|
|
26
|
+
]
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Logger models and enums.
|
|
2
|
+
|
|
3
|
+
This module re-exports core logger types from synapse_sdk.loggers
|
|
4
|
+
and defines additional logger-related models.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
# Re-export core logger types from loggers.py to avoid circular imports
|
|
15
|
+
from synapse_sdk.loggers import LogEntry, LoggerBackend, ProgressData
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from synapse_sdk.plugins.models.pipeline import ActionStatus
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
'LogLevel',
|
|
22
|
+
'ProgressData',
|
|
23
|
+
'LogEntry',
|
|
24
|
+
'LoggerBackend',
|
|
25
|
+
'ActionProgress',
|
|
26
|
+
'PipelineProgress',
|
|
27
|
+
'Checkpoint',
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class LogLevel(str, Enum):
|
|
32
|
+
"""Log level for logger."""
|
|
33
|
+
|
|
34
|
+
DEBUG = 'debug'
|
|
35
|
+
INFO = 'info'
|
|
36
|
+
WARNING = 'warning'
|
|
37
|
+
ERROR = 'error'
|
|
38
|
+
CRITICAL = 'critical'
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class ActionProgress:
|
|
43
|
+
"""Progress state for a single action."""
|
|
44
|
+
|
|
45
|
+
name: str
|
|
46
|
+
status: ActionStatus = None # type: ignore[assignment]
|
|
47
|
+
progress: float = 0.0
|
|
48
|
+
progress_category: str | None = None
|
|
49
|
+
message: str | None = None
|
|
50
|
+
metrics: dict[str, Any] = field(default_factory=dict)
|
|
51
|
+
started_at: datetime | None = None
|
|
52
|
+
completed_at: datetime | None = None
|
|
53
|
+
error: str | None = None
|
|
54
|
+
|
|
55
|
+
def __post_init__(self) -> None:
|
|
56
|
+
# Lazy import to avoid circular imports
|
|
57
|
+
if self.status is None:
|
|
58
|
+
from synapse_sdk.plugins.models.pipeline import ActionStatus
|
|
59
|
+
|
|
60
|
+
self.status = ActionStatus.PENDING
|
|
61
|
+
|
|
62
|
+
def to_dict(self) -> dict[str, Any]:
|
|
63
|
+
"""Convert to dictionary for API serialization."""
|
|
64
|
+
return {
|
|
65
|
+
'name': self.name,
|
|
66
|
+
'status': self.status.value,
|
|
67
|
+
'progress': self.progress,
|
|
68
|
+
'progress_category': self.progress_category,
|
|
69
|
+
'message': self.message,
|
|
70
|
+
'metrics': self.metrics,
|
|
71
|
+
'started_at': self.started_at.isoformat() if self.started_at else None,
|
|
72
|
+
'completed_at': self.completed_at.isoformat() if self.completed_at else None,
|
|
73
|
+
'error': self.error,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_dict(cls, data: dict[str, Any]) -> ActionProgress:
|
|
78
|
+
"""Create from dictionary."""
|
|
79
|
+
from synapse_sdk.plugins.models.pipeline import ActionStatus
|
|
80
|
+
|
|
81
|
+
return cls(
|
|
82
|
+
name=data['name'],
|
|
83
|
+
status=ActionStatus(data['status']),
|
|
84
|
+
progress=data.get('progress', 0.0),
|
|
85
|
+
progress_category=data.get('progress_category'),
|
|
86
|
+
message=data.get('message'),
|
|
87
|
+
metrics=data.get('metrics', {}),
|
|
88
|
+
started_at=datetime.fromisoformat(data['started_at']) if data.get('started_at') else None,
|
|
89
|
+
completed_at=datetime.fromisoformat(data['completed_at']) if data.get('completed_at') else None,
|
|
90
|
+
error=data.get('error'),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dataclass
|
|
95
|
+
class PipelineProgress:
|
|
96
|
+
"""Overall pipeline progress state."""
|
|
97
|
+
|
|
98
|
+
run_id: str
|
|
99
|
+
status: Any = None # RunStatus, but lazy loaded
|
|
100
|
+
actions: dict[str, ActionProgress] = field(default_factory=dict)
|
|
101
|
+
current_action: str | None = None
|
|
102
|
+
started_at: datetime | None = None
|
|
103
|
+
completed_at: datetime | None = None
|
|
104
|
+
error: str | None = None
|
|
105
|
+
|
|
106
|
+
def __post_init__(self) -> None:
|
|
107
|
+
if self.status is None:
|
|
108
|
+
from synapse_sdk.plugins.models.pipeline import RunStatus
|
|
109
|
+
|
|
110
|
+
self.status = RunStatus.PENDING
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def overall_progress(self) -> float:
|
|
114
|
+
"""Calculate overall progress across all actions."""
|
|
115
|
+
if not self.actions:
|
|
116
|
+
return 0.0
|
|
117
|
+
return sum(a.progress for a in self.actions.values()) / len(self.actions)
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def completed_actions(self) -> int:
|
|
121
|
+
"""Count completed actions."""
|
|
122
|
+
from synapse_sdk.plugins.models.pipeline import ActionStatus
|
|
123
|
+
|
|
124
|
+
return sum(1 for a in self.actions.values() if a.status == ActionStatus.COMPLETED)
|
|
125
|
+
|
|
126
|
+
def to_dict(self) -> dict[str, Any]:
|
|
127
|
+
"""Convert to dictionary for API serialization."""
|
|
128
|
+
return {
|
|
129
|
+
'run_id': self.run_id,
|
|
130
|
+
'status': self.status.value,
|
|
131
|
+
'actions': {k: v.to_dict() for k, v in self.actions.items()},
|
|
132
|
+
'current_action': self.current_action,
|
|
133
|
+
'overall_progress': self.overall_progress,
|
|
134
|
+
'completed_actions': self.completed_actions,
|
|
135
|
+
'total_actions': len(self.actions),
|
|
136
|
+
'started_at': self.started_at.isoformat() if self.started_at else None,
|
|
137
|
+
'completed_at': self.completed_at.isoformat() if self.completed_at else None,
|
|
138
|
+
'error': self.error,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def from_dict(cls, data: dict[str, Any]) -> PipelineProgress:
|
|
143
|
+
"""Create from dictionary."""
|
|
144
|
+
from synapse_sdk.plugins.models.pipeline import RunStatus
|
|
145
|
+
|
|
146
|
+
return cls(
|
|
147
|
+
run_id=data['run_id'],
|
|
148
|
+
status=RunStatus(data['status']),
|
|
149
|
+
actions={k: ActionProgress.from_dict(v) for k, v in data.get('actions', {}).items()},
|
|
150
|
+
current_action=data.get('current_action'),
|
|
151
|
+
started_at=datetime.fromisoformat(data['started_at']) if data.get('started_at') else None,
|
|
152
|
+
completed_at=datetime.fromisoformat(data['completed_at']) if data.get('completed_at') else None,
|
|
153
|
+
error=data.get('error'),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@dataclass
|
|
158
|
+
class Checkpoint:
|
|
159
|
+
"""Checkpoint for pipeline state persistence."""
|
|
160
|
+
|
|
161
|
+
run_id: str
|
|
162
|
+
action_name: str
|
|
163
|
+
result: Any
|
|
164
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
165
|
+
|
|
166
|
+
def to_dict(self) -> dict[str, Any]:
|
|
167
|
+
"""Convert to dictionary for serialization."""
|
|
168
|
+
return {
|
|
169
|
+
'run_id': self.run_id,
|
|
170
|
+
'action_name': self.action_name,
|
|
171
|
+
'result': self.result,
|
|
172
|
+
'created_at': self.created_at.isoformat(),
|
|
173
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Pipeline status enums."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
__all__ = ['RunStatus', 'ActionStatus']
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RunStatus(str, Enum):
|
|
9
|
+
"""Status of a pipeline run."""
|
|
10
|
+
|
|
11
|
+
PENDING = 'pending'
|
|
12
|
+
RUNNING = 'running'
|
|
13
|
+
COMPLETED = 'completed'
|
|
14
|
+
FAILED = 'failed'
|
|
15
|
+
CANCELLED = 'cancelled'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ActionStatus(str, Enum):
|
|
19
|
+
"""Status of an individual action."""
|
|
20
|
+
|
|
21
|
+
PENDING = 'pending'
|
|
22
|
+
RUNNING = 'running'
|
|
23
|
+
COMPLETED = 'completed'
|
|
24
|
+
FAILED = 'failed'
|
|
25
|
+
SKIPPED = 'skipped'
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Pipeline patterns for Synapse SDK.
|
|
2
|
+
|
|
3
|
+
This module provides various pipeline execution patterns:
|
|
4
|
+
- ActionPipeline: Chain actions with input/output schema validation
|
|
5
|
+
- PipelineContext: Shared working directory for pipeline actions
|
|
6
|
+
- Progress models: Track pipeline and action progress
|
|
7
|
+
- steps: Sequential step-based workflows with rollback support (for internal use)
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
>>> from synapse_sdk.plugins.pipelines import ActionPipeline, PipelineContext
|
|
11
|
+
>>>
|
|
12
|
+
>>> # Unix pipe style: Download | Convert | Train
|
|
13
|
+
>>> pipeline = ActionPipeline([
|
|
14
|
+
... DownloadDatasetAction,
|
|
15
|
+
... ConvertDatasetAction,
|
|
16
|
+
... TrainAction,
|
|
17
|
+
... ])
|
|
18
|
+
>>>
|
|
19
|
+
>>> result = pipeline.execute(params, ctx)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from synapse_sdk.plugins.models.logger import (
|
|
23
|
+
ActionProgress,
|
|
24
|
+
Checkpoint,
|
|
25
|
+
LogEntry,
|
|
26
|
+
LogLevel,
|
|
27
|
+
PipelineProgress,
|
|
28
|
+
)
|
|
29
|
+
from synapse_sdk.plugins.models.pipeline import ActionStatus, RunStatus
|
|
30
|
+
from synapse_sdk.plugins.pipelines.action_pipeline import (
|
|
31
|
+
ActionPipeline,
|
|
32
|
+
SchemaIncompatibleError,
|
|
33
|
+
)
|
|
34
|
+
from synapse_sdk.plugins.pipelines.context import PipelineContext
|
|
35
|
+
from synapse_sdk.plugins.pipelines.display import (
|
|
36
|
+
display_progress,
|
|
37
|
+
display_progress_async,
|
|
38
|
+
print_progress_summary,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Import from new canonical location (not deprecated pipelines.steps)
|
|
42
|
+
from synapse_sdk.plugins.steps import (
|
|
43
|
+
BaseStep,
|
|
44
|
+
BaseStepContext,
|
|
45
|
+
LoggingStep,
|
|
46
|
+
Orchestrator,
|
|
47
|
+
StepRegistry,
|
|
48
|
+
StepResult,
|
|
49
|
+
TimingStep,
|
|
50
|
+
ValidationStep,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
# Action Pipeline (recommended)
|
|
55
|
+
'ActionPipeline',
|
|
56
|
+
'SchemaIncompatibleError',
|
|
57
|
+
# Pipeline Context
|
|
58
|
+
'PipelineContext',
|
|
59
|
+
# Display Utilities
|
|
60
|
+
'display_progress',
|
|
61
|
+
'display_progress_async',
|
|
62
|
+
'print_progress_summary',
|
|
63
|
+
# Progress Models
|
|
64
|
+
'ActionProgress',
|
|
65
|
+
'ActionStatus',
|
|
66
|
+
'Checkpoint',
|
|
67
|
+
'LogEntry',
|
|
68
|
+
'LogLevel',
|
|
69
|
+
'PipelineProgress',
|
|
70
|
+
'RunStatus',
|
|
71
|
+
# Steps - Core (internal)
|
|
72
|
+
'BaseStep',
|
|
73
|
+
'BaseStepContext',
|
|
74
|
+
'Orchestrator',
|
|
75
|
+
'StepRegistry',
|
|
76
|
+
'StepResult',
|
|
77
|
+
# Steps - Utilities
|
|
78
|
+
'LoggingStep',
|
|
79
|
+
'TimingStep',
|
|
80
|
+
'ValidationStep',
|
|
81
|
+
]
|