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,531 @@
|
|
|
1
|
+
# Plugin System Overview
|
|
2
|
+
|
|
3
|
+
The Synapse SDK Plugin System is a comprehensive framework for building, discovering, and executing plugin actions. It provides a flexible architecture for creating reusable components that can run locally or distributed across Ray clusters.
|
|
4
|
+
|
|
5
|
+
## Target Audience
|
|
6
|
+
|
|
7
|
+
This documentation is for **plugin system developers** who need to:
|
|
8
|
+
- Create custom plugin actions for ML training, export, upload, inference, etc.
|
|
9
|
+
- Understand the plugin architecture for extension and customization
|
|
10
|
+
- Build step-based workflows with progress tracking and rollback support
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
- Python 3.12+
|
|
15
|
+
- Familiarity with Pydantic v2 for data validation
|
|
16
|
+
- Basic understanding of async/await patterns (for Ray execution)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Key Concepts
|
|
21
|
+
|
|
22
|
+
### Actions
|
|
23
|
+
|
|
24
|
+
Actions are the fundamental units of work in the plugin system. Each action:
|
|
25
|
+
- Receives typed parameters (Pydantic models)
|
|
26
|
+
- Has access to a runtime context (logger, environment, clients)
|
|
27
|
+
- Produces a result (optionally typed)
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from synapse_sdk.plugins import BaseAction
|
|
31
|
+
from pydantic import BaseModel
|
|
32
|
+
|
|
33
|
+
class TrainParams(BaseModel):
|
|
34
|
+
epochs: int = 10
|
|
35
|
+
learning_rate: float = 0.001
|
|
36
|
+
|
|
37
|
+
class TrainAction(BaseAction[TrainParams]):
|
|
38
|
+
def execute(self) -> dict:
|
|
39
|
+
for epoch in range(self.params.epochs):
|
|
40
|
+
self.set_progress(epoch + 1, self.params.epochs)
|
|
41
|
+
# Training logic here
|
|
42
|
+
return {'status': 'completed'}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Contexts
|
|
46
|
+
|
|
47
|
+
Contexts provide runtime services and shared state:
|
|
48
|
+
|
|
49
|
+
- **RuntimeContext**: Injected into all actions, provides logger, environment, job tracking
|
|
50
|
+
- **BaseStepContext**: Extended by step-based workflows to share state between steps
|
|
51
|
+
- **Specialized Contexts**: TrainContext, UploadContext, etc. for domain-specific state
|
|
52
|
+
|
|
53
|
+
### Steps
|
|
54
|
+
|
|
55
|
+
Steps are composable workflow building blocks for multi-phase operations:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from synapse_sdk.plugins.steps import BaseStep, StepResult
|
|
59
|
+
|
|
60
|
+
class LoadDataStep(BaseStep[MyContext]):
|
|
61
|
+
@property
|
|
62
|
+
def name(self) -> str:
|
|
63
|
+
return 'load_data'
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def progress_weight(self) -> float:
|
|
67
|
+
return 0.3 # 30% of total progress
|
|
68
|
+
|
|
69
|
+
def execute(self, context: MyContext) -> StepResult:
|
|
70
|
+
context.data = load_data()
|
|
71
|
+
return StepResult(success=True)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Executors
|
|
75
|
+
|
|
76
|
+
Executors determine where and how actions run:
|
|
77
|
+
|
|
78
|
+
| Executor | Use Case | Startup Time |
|
|
79
|
+
|----------|----------|--------------|
|
|
80
|
+
| `LocalExecutor` | Development, testing | Instant |
|
|
81
|
+
| `RayActorExecutor` | Light parallel tasks | <1 second |
|
|
82
|
+
| `RayJobExecutor` | Heavy workloads, isolation | ~30 seconds |
|
|
83
|
+
| `RayPipelineExecutor` | Multi-action workflows | Variable |
|
|
84
|
+
|
|
85
|
+
### Discovery
|
|
86
|
+
|
|
87
|
+
Plugin discovery loads actions from:
|
|
88
|
+
- **Config files**: `config.yaml` with action metadata
|
|
89
|
+
- **Python modules**: Scans for `@action` decorators and `BaseAction` subclasses
|
|
90
|
+
- **AST scanning**: Static analysis without import failures
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Tutorial: Creating Your First Plugin
|
|
95
|
+
|
|
96
|
+
This tutorial walks through creating a complete plugin from scratch.
|
|
97
|
+
|
|
98
|
+
### Step 1: Define Parameters Model
|
|
99
|
+
|
|
100
|
+
Create a Pydantic model for your action's input parameters:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# my_plugin/params.py
|
|
104
|
+
from pydantic import BaseModel, Field
|
|
105
|
+
|
|
106
|
+
class ProcessParams(BaseModel):
|
|
107
|
+
"""Parameters for the process action."""
|
|
108
|
+
|
|
109
|
+
input_path: str = Field(..., description='Path to input file')
|
|
110
|
+
output_path: str = Field(..., description='Path to output file')
|
|
111
|
+
batch_size: int = Field(default=32, ge=1, le=1024)
|
|
112
|
+
verbose: bool = False
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Step 2: Create Action Class
|
|
116
|
+
|
|
117
|
+
Implement your action by subclassing `BaseAction`:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
# my_plugin/actions.py
|
|
121
|
+
from synapse_sdk.plugins import BaseAction
|
|
122
|
+
from synapse_sdk.plugins.enums import PluginCategory
|
|
123
|
+
from my_plugin.params import ProcessParams
|
|
124
|
+
|
|
125
|
+
class ProcessAction(BaseAction[ProcessParams]):
|
|
126
|
+
"""Process files with progress tracking."""
|
|
127
|
+
|
|
128
|
+
action_name = 'process'
|
|
129
|
+
category = PluginCategory.CUSTOM
|
|
130
|
+
|
|
131
|
+
def execute(self) -> dict:
|
|
132
|
+
# Access validated parameters
|
|
133
|
+
input_path = self.params.input_path
|
|
134
|
+
output_path = self.params.output_path
|
|
135
|
+
|
|
136
|
+
# Log events
|
|
137
|
+
self.log('process_start', {'input': input_path})
|
|
138
|
+
|
|
139
|
+
# Simulate processing with progress
|
|
140
|
+
total_items = 100
|
|
141
|
+
for i in range(total_items):
|
|
142
|
+
# Update progress (current, total)
|
|
143
|
+
self.set_progress(i + 1, total_items)
|
|
144
|
+
|
|
145
|
+
if self.params.verbose:
|
|
146
|
+
self.log('item_processed', {'index': i})
|
|
147
|
+
|
|
148
|
+
# Log metrics
|
|
149
|
+
self.set_metrics({'items_processed': total_items}, category='process')
|
|
150
|
+
|
|
151
|
+
# Return result
|
|
152
|
+
return {
|
|
153
|
+
'status': 'completed',
|
|
154
|
+
'output_path': output_path,
|
|
155
|
+
'items_processed': total_items,
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Step 3: Write config.yaml
|
|
160
|
+
|
|
161
|
+
Create a configuration file for your plugin:
|
|
162
|
+
|
|
163
|
+
```yaml
|
|
164
|
+
# my_plugin/config.yaml
|
|
165
|
+
name: My Plugin
|
|
166
|
+
code: my_plugin
|
|
167
|
+
version: 0.1.0
|
|
168
|
+
category: custom
|
|
169
|
+
|
|
170
|
+
actions:
|
|
171
|
+
process:
|
|
172
|
+
name: Process Files
|
|
173
|
+
description: Process input files with batch processing
|
|
174
|
+
entrypoint: my_plugin.actions:ProcessAction
|
|
175
|
+
method: task
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Step 4: Run Locally
|
|
179
|
+
|
|
180
|
+
Execute your action using `run_plugin`:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
# run.py
|
|
184
|
+
from synapse_sdk.plugins import run_plugin
|
|
185
|
+
|
|
186
|
+
result = run_plugin(
|
|
187
|
+
plugin_code='my_plugin', # Module path
|
|
188
|
+
action='process',
|
|
189
|
+
params={
|
|
190
|
+
'input_path': '/data/input.csv',
|
|
191
|
+
'output_path': '/data/output.csv',
|
|
192
|
+
'batch_size': 64,
|
|
193
|
+
'verbose': True,
|
|
194
|
+
},
|
|
195
|
+
mode='local', # Run in current process
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
print(f"Result: {result}")
|
|
199
|
+
# Output: Result: {'status': 'completed', 'output_path': '/data/output.csv', 'items_processed': 100}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Step 5: Add Result Schema (Optional)
|
|
203
|
+
|
|
204
|
+
For typed results, create a result model:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
# my_plugin/results.py
|
|
208
|
+
from pydantic import BaseModel
|
|
209
|
+
|
|
210
|
+
class ProcessResult(BaseModel):
|
|
211
|
+
"""Typed result for process action."""
|
|
212
|
+
status: str
|
|
213
|
+
output_path: str
|
|
214
|
+
items_processed: int
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Then update your action:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
# my_plugin/actions.py
|
|
221
|
+
from my_plugin.results import ProcessResult
|
|
222
|
+
|
|
223
|
+
class ProcessAction(BaseAction[ProcessParams]):
|
|
224
|
+
result_model = ProcessResult # Enable result validation
|
|
225
|
+
|
|
226
|
+
def execute(self) -> ProcessResult:
|
|
227
|
+
# ... processing logic ...
|
|
228
|
+
return ProcessResult(
|
|
229
|
+
status='completed',
|
|
230
|
+
output_path=self.params.output_path,
|
|
231
|
+
items_processed=total_items,
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Two Ways to Define Actions
|
|
238
|
+
|
|
239
|
+
### Class-Based Actions (Recommended for Complex Actions)
|
|
240
|
+
|
|
241
|
+
Use `BaseAction` subclass for:
|
|
242
|
+
- Complex actions with multiple methods
|
|
243
|
+
- Actions that need class attributes (input_type, output_type)
|
|
244
|
+
- Step-based workflows
|
|
245
|
+
- Actions requiring autolog integration
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
from synapse_sdk.plugins import BaseAction
|
|
249
|
+
from synapse_sdk.plugins.enums import PluginCategory
|
|
250
|
+
from synapse_sdk.plugins.types import YOLODataset, ModelWeights
|
|
251
|
+
|
|
252
|
+
class TrainAction(BaseAction[TrainParams]):
|
|
253
|
+
"""Train a YOLO model with comprehensive features."""
|
|
254
|
+
|
|
255
|
+
# Optional class attributes
|
|
256
|
+
action_name = 'train'
|
|
257
|
+
category = PluginCategory.NEURAL_NET
|
|
258
|
+
input_type = YOLODataset # Semantic input type
|
|
259
|
+
output_type = ModelWeights # Semantic output type
|
|
260
|
+
result_model = TrainResult # Typed result schema
|
|
261
|
+
|
|
262
|
+
def execute(self) -> TrainResult:
|
|
263
|
+
# Enable automatic logging for Ultralytics
|
|
264
|
+
self.autolog('ultralytics')
|
|
265
|
+
|
|
266
|
+
# Access environment variables
|
|
267
|
+
api_key = self.ctx.env.get('API_KEY', '')
|
|
268
|
+
|
|
269
|
+
# Use the logger
|
|
270
|
+
self.logger.info('Starting training')
|
|
271
|
+
|
|
272
|
+
# Training implementation
|
|
273
|
+
model = train_model(self.params)
|
|
274
|
+
|
|
275
|
+
return TrainResult(
|
|
276
|
+
weights_path=model.path,
|
|
277
|
+
final_loss=model.loss,
|
|
278
|
+
)
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Function-Based Actions (Simple Actions)
|
|
282
|
+
|
|
283
|
+
Use `@action` decorator for:
|
|
284
|
+
- Simple, stateless operations
|
|
285
|
+
- Quick prototyping
|
|
286
|
+
- Actions without complex dependencies
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
from synapse_sdk.plugins import action
|
|
290
|
+
from synapse_sdk.plugins.context import RuntimeContext
|
|
291
|
+
from pydantic import BaseModel
|
|
292
|
+
|
|
293
|
+
class ConvertParams(BaseModel):
|
|
294
|
+
input_format: str
|
|
295
|
+
output_format: str
|
|
296
|
+
file_path: str
|
|
297
|
+
|
|
298
|
+
class ConvertResult(BaseModel):
|
|
299
|
+
output_path: str
|
|
300
|
+
converted: bool
|
|
301
|
+
|
|
302
|
+
@action(
|
|
303
|
+
name='convert',
|
|
304
|
+
description='Convert file between formats',
|
|
305
|
+
params=ConvertParams,
|
|
306
|
+
result=ConvertResult,
|
|
307
|
+
)
|
|
308
|
+
def convert(params: ConvertParams, context: RuntimeContext) -> ConvertResult:
|
|
309
|
+
"""Convert a file from one format to another."""
|
|
310
|
+
|
|
311
|
+
# Log progress
|
|
312
|
+
context.set_progress(0, 100)
|
|
313
|
+
|
|
314
|
+
# Conversion logic
|
|
315
|
+
output_path = convert_file(
|
|
316
|
+
params.file_path,
|
|
317
|
+
params.input_format,
|
|
318
|
+
params.output_format,
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
context.set_progress(100, 100)
|
|
322
|
+
|
|
323
|
+
return ConvertResult(
|
|
324
|
+
output_path=output_path,
|
|
325
|
+
converted=True,
|
|
326
|
+
)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Comparison: When to Use Each
|
|
330
|
+
|
|
331
|
+
| Aspect | Class-Based (`BaseAction`) | Function-Based (`@action`) |
|
|
332
|
+
|--------|---------------------------|---------------------------|
|
|
333
|
+
| Complexity | Complex, multi-method | Simple, single function |
|
|
334
|
+
| State | Can have instance state | Stateless |
|
|
335
|
+
| Type declarations | `input_type`, `output_type` | Not supported |
|
|
336
|
+
| Autolog | `self.autolog()` | Not available |
|
|
337
|
+
| Step workflows | Supported via mixins | Not supported |
|
|
338
|
+
| Testing | Easier mocking | Direct function calls |
|
|
339
|
+
| Config discovery | Full introspection | Limited metadata |
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Plugin Categories
|
|
344
|
+
|
|
345
|
+
Plugins are organized into categories for management and UI presentation:
|
|
346
|
+
|
|
347
|
+
| Category | Value | Description | Example Use Cases |
|
|
348
|
+
|----------|-------|-------------|-------------------|
|
|
349
|
+
| Neural Net | `neural_net` | ML model training | YOLO training, classification |
|
|
350
|
+
| Export | `export` | Model conversion/export | ONNX export, TensorRT |
|
|
351
|
+
| Upload | `upload` | Data/model uploads | S3 upload, model registry |
|
|
352
|
+
| Smart Tool | `smart_tool` | Interactive annotation | Auto-labeling, SAM |
|
|
353
|
+
| Pre-Annotation | `pre_annotation` | Before annotation | Data preprocessing |
|
|
354
|
+
| Post-Annotation | `post_annotation` | After annotation | QA checks, format conversion |
|
|
355
|
+
| Data Validation | `data_validation` | Data quality checks | Schema validation |
|
|
356
|
+
| Custom | `custom` | Custom functionality | Anything else |
|
|
357
|
+
|
|
358
|
+
Usage in actions:
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
from synapse_sdk.plugins.enums import PluginCategory
|
|
362
|
+
|
|
363
|
+
class MyAction(BaseAction[MyParams]):
|
|
364
|
+
category = PluginCategory.NEURAL_NET
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Execution Modes
|
|
370
|
+
|
|
371
|
+
### Local Execution
|
|
372
|
+
|
|
373
|
+
Best for development and testing. Runs in the current process:
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
from synapse_sdk.plugins import run_plugin
|
|
377
|
+
|
|
378
|
+
result = run_plugin(
|
|
379
|
+
plugin_code='my_plugin',
|
|
380
|
+
action='train',
|
|
381
|
+
params={'epochs': 10},
|
|
382
|
+
mode='local',
|
|
383
|
+
)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Or using the executor directly:
|
|
387
|
+
|
|
388
|
+
```python
|
|
389
|
+
from synapse_sdk.plugins.executors import LocalExecutor
|
|
390
|
+
|
|
391
|
+
executor = LocalExecutor(
|
|
392
|
+
env={'DEBUG': 'true'}, # Environment variables
|
|
393
|
+
job_id='test-123', # Optional job tracking ID
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
result = executor.execute(
|
|
397
|
+
action_cls=TrainAction,
|
|
398
|
+
params={'epochs': 10},
|
|
399
|
+
)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Ray Task Execution
|
|
403
|
+
|
|
404
|
+
For parallel tasks with fast startup. Uses Ray Actors:
|
|
405
|
+
|
|
406
|
+
```python
|
|
407
|
+
from synapse_sdk.plugins.executors.ray import RayActorExecutor
|
|
408
|
+
|
|
409
|
+
executor = RayActorExecutor(
|
|
410
|
+
working_dir='/path/to/plugin', # Plugin code directory
|
|
411
|
+
num_gpus=1, # GPU allocation
|
|
412
|
+
num_cpus=4, # CPU allocation
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
result = executor.execute(
|
|
416
|
+
action_cls=TrainAction,
|
|
417
|
+
params={'epochs': 10},
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
# Clean up when done
|
|
421
|
+
executor.shutdown()
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Ray Job Execution
|
|
425
|
+
|
|
426
|
+
For heavy workloads requiring full isolation:
|
|
427
|
+
|
|
428
|
+
```python
|
|
429
|
+
from synapse_sdk.plugins.executors.ray import RayJobExecutor
|
|
430
|
+
|
|
431
|
+
executor = RayJobExecutor(
|
|
432
|
+
dashboard_url='http://localhost:8265',
|
|
433
|
+
working_dir='/path/to/plugin',
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
# Submit job (async)
|
|
437
|
+
job_id = executor.submit('train', {'epochs': 100})
|
|
438
|
+
|
|
439
|
+
# Check status
|
|
440
|
+
status = executor.get_status(job_id)
|
|
441
|
+
print(f"Status: {status}") # PENDING, RUNNING, SUCCEEDED, FAILED
|
|
442
|
+
|
|
443
|
+
# Get logs
|
|
444
|
+
logs = executor.get_logs(job_id)
|
|
445
|
+
|
|
446
|
+
# Wait for completion
|
|
447
|
+
result = executor.wait(job_id, timeout_seconds=3600)
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Execution Mode Comparison
|
|
451
|
+
|
|
452
|
+
| Mode | Startup | Isolation | Best For |
|
|
453
|
+
|------|---------|-----------|----------|
|
|
454
|
+
| `local` | Instant | None | Development, testing |
|
|
455
|
+
| `task` | <1s | Process | Light parallel tasks |
|
|
456
|
+
| `job` | ~30s | Full | Production, heavy workloads |
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## RuntimeContext Reference
|
|
461
|
+
|
|
462
|
+
All actions receive a `RuntimeContext` with these capabilities:
|
|
463
|
+
|
|
464
|
+
```python
|
|
465
|
+
def execute(self) -> dict:
|
|
466
|
+
# Access the logger
|
|
467
|
+
self.ctx.logger.info('Processing started')
|
|
468
|
+
|
|
469
|
+
# Access environment variables
|
|
470
|
+
api_key = self.ctx.env.get('API_KEY')
|
|
471
|
+
debug = self.ctx.env.get('DEBUG', 'false') == 'true'
|
|
472
|
+
|
|
473
|
+
# Log structured events
|
|
474
|
+
self.ctx.log('event_name', {'key': 'value'})
|
|
475
|
+
|
|
476
|
+
# Track progress
|
|
477
|
+
self.ctx.set_progress(current=50, total=100, category='training')
|
|
478
|
+
|
|
479
|
+
# Record metrics
|
|
480
|
+
self.ctx.set_metrics({'loss': 0.05, 'accuracy': 0.95}, category='train')
|
|
481
|
+
|
|
482
|
+
# Log user-visible messages
|
|
483
|
+
self.ctx.log_message('Training complete!')
|
|
484
|
+
|
|
485
|
+
# Log developer debug events
|
|
486
|
+
self.ctx.log_dev_event('checkpoint_saved', {'path': '/model.pt'})
|
|
487
|
+
|
|
488
|
+
# Access job ID for tracking
|
|
489
|
+
job_id = self.ctx.job_id
|
|
490
|
+
|
|
491
|
+
# Access backend client (if available)
|
|
492
|
+
if self.ctx.client:
|
|
493
|
+
self.ctx.client.upload_file(...)
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## PluginEnvironment
|
|
499
|
+
|
|
500
|
+
Load configuration from environment variables or files:
|
|
501
|
+
|
|
502
|
+
```python
|
|
503
|
+
from synapse_sdk.plugins.context.env import PluginEnvironment
|
|
504
|
+
|
|
505
|
+
# From environment variables with prefix
|
|
506
|
+
env = PluginEnvironment.from_environ(prefix='PLUGIN_')
|
|
507
|
+
|
|
508
|
+
# From TOML file
|
|
509
|
+
env = PluginEnvironment.from_file('config.toml')
|
|
510
|
+
|
|
511
|
+
# Type-safe getters
|
|
512
|
+
api_key = env.get_str('API_KEY')
|
|
513
|
+
batch_size = env.get_int('BATCH_SIZE', default=32)
|
|
514
|
+
learning_rate = env.get_float('LEARNING_RATE', default=0.001)
|
|
515
|
+
debug = env.get_bool('DEBUG', default=False)
|
|
516
|
+
tags = env.get_list('TAGS', default=[])
|
|
517
|
+
|
|
518
|
+
# Merge multiple environments
|
|
519
|
+
merged = env.merge(another_env)
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Next Steps
|
|
525
|
+
|
|
526
|
+
- **[ACTION_DEV_GUIDE.md](ACTION_DEV_GUIDE.md)**: Complete action development guide
|
|
527
|
+
- **[ARCHITECTURE.md](ARCHITECTURE.md)**: Deep dive into system architecture
|
|
528
|
+
- **[STEP.md](STEP.md)**: Step implementations guide
|
|
529
|
+
- **[LOGGING_SYSTEM.md](LOGGING_SYSTEM.md)**: Logging and progress tracking
|
|
530
|
+
- **[README.md](README.md)**: Quick reference and extension guide
|
|
531
|
+
- **[PIPELINE_GUIDE.md](PIPELINE_GUIDE.md)**: Multi-action pipelines
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Remote Pipeline Execution
|
|
2
|
+
|
|
3
|
+
Multi-action pipeline execution on Ray clusters with progress tracking and checkpointing.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart LR
|
|
9
|
+
subgraph Local["SDK (local)"]
|
|
10
|
+
pipeline["ActionPipeline<br/>.submit()<br/>.wait()"]
|
|
11
|
+
executor["RayPipelineExecutor<br/>- get_progress()<br/>- get_result()"]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
subgraph Ray["Ray Cluster"]
|
|
15
|
+
actor["PipelineActor<br/>- run_pipeline<br/>- checkpoints"]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
subgraph Backend["Backend Service"]
|
|
19
|
+
devapi["Backend Service<br/>/api/v1/runs/<br/>/api/v1/progress/"]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
pipeline -->|"submit()"| actor
|
|
23
|
+
executor -->|"poll"| devapi
|
|
24
|
+
actor -->|"report"| devapi
|
|
25
|
+
devapi <-->|"HTTP"| executor
|
|
26
|
+
|
|
27
|
+
style Local fill:#e1f5fe
|
|
28
|
+
style Ray fill:#f3e5f5
|
|
29
|
+
style Backend fill:#fff3e0
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Key Design Decision:** Ray Workflows is deprecated. We use a single persistent Ray actor + custom orchestration via a backend service.
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from synapse_sdk.plugins.pipelines import ActionPipeline
|
|
38
|
+
from synapse_sdk.plugins.executors.ray import RayPipelineExecutor
|
|
39
|
+
|
|
40
|
+
pipeline = ActionPipeline([DownloadAction, ConvertAction, TrainAction])
|
|
41
|
+
|
|
42
|
+
executor = RayPipelineExecutor(
|
|
43
|
+
ray_address='auto',
|
|
44
|
+
working_dir='/path/to/plugin',
|
|
45
|
+
pipeline_service_url='http://localhost:8100',
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Remote execution
|
|
49
|
+
run_id = pipeline.submit({'dataset_id': 123}, executor)
|
|
50
|
+
progress = executor.get_progress(run_id)
|
|
51
|
+
result = pipeline.wait(run_id, executor)
|
|
52
|
+
|
|
53
|
+
# Stream progress with Rich display (sync)
|
|
54
|
+
from synapse_sdk.plugins.pipelines import display_progress
|
|
55
|
+
final = display_progress(executor.stream_progress(run_id))
|
|
56
|
+
|
|
57
|
+
# Stream progress with Rich display (async)
|
|
58
|
+
from synapse_sdk.plugins.pipelines import display_progress_async
|
|
59
|
+
final = await display_progress_async(executor.stream_progress_async(run_id))
|
|
60
|
+
|
|
61
|
+
# Resume from a failed run
|
|
62
|
+
new_run_id = pipeline.submit({'dataset_id': 123}, executor, resume_from=run_id)
|
|
63
|
+
|
|
64
|
+
# Local execution (unchanged)
|
|
65
|
+
result = pipeline.execute(params, ctx)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## File Structure
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
synapse_sdk/
|
|
72
|
+
├── plugins/pipelines/
|
|
73
|
+
│ ├── action_pipeline.py # ActionPipeline with submit()/wait()
|
|
74
|
+
│ ├── context.py # PipelineContext (shared working dir)
|
|
75
|
+
│ ├── display.py # Rich console progress display
|
|
76
|
+
│ └── models.py # PipelineProgress, ActionProgress, RunStatus
|
|
77
|
+
├── clients/pipeline/
|
|
78
|
+
│ └── client.py # PipelineServiceClient (backend client, SSE streaming)
|
|
79
|
+
└── plugins/executors/ray/
|
|
80
|
+
└── pipeline.py # RayPipelineExecutor, _PipelineExecutorActor
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## API Reference
|
|
84
|
+
|
|
85
|
+
### SDK Classes
|
|
86
|
+
|
|
87
|
+
| Class/Function | Location | Purpose |
|
|
88
|
+
|----------------|----------|---------|
|
|
89
|
+
| `ActionPipeline` | `plugins/pipelines/action_pipeline.py` | Chain actions, local or remote |
|
|
90
|
+
| `RayPipelineExecutor` | `plugins/executors/ray/pipeline.py` | Submit to Ray, track progress |
|
|
91
|
+
| `PipelineServiceClient` | `clients/pipeline/client.py` | Communicate with backend service |
|
|
92
|
+
| `PipelineContext` | `plugins/pipelines/context.py` | Shared working directory |
|
|
93
|
+
| `PipelineProgress` | `plugins/pipelines/models.py` | Progress state model |
|
|
94
|
+
| `display_progress()` | `plugins/pipelines/display.py` | Rich console progress (sync) |
|
|
95
|
+
| `display_progress_async()` | `plugins/pipelines/display.py` | Rich console progress (async) |
|
|
96
|
+
| `stream_progress()` | `RayPipelineExecutor` method | SSE progress generator (sync) |
|
|
97
|
+
| `stream_progress_async()` | `RayPipelineExecutor` method | SSE progress generator (async) |
|
|
98
|
+
|
|
99
|
+
## Design Decisions
|
|
100
|
+
|
|
101
|
+
| Decision | Choice | Rationale |
|
|
102
|
+
|----------|--------|-----------|
|
|
103
|
+
| Orchestration | Custom (not Ray Workflows) | Ray Workflows deprecated |
|
|
104
|
+
| Execution | Single persistent Ray actor | Shared filesystem, simpler state |
|
|
105
|
+
| Working dir | `/tmp/synapse_pipelines/{id}` | Ephemeral, auto-cleanup on reboot |
|
|
106
|
+
| Progress store | External backend service | Decoupled from Ray, queryable |
|
|
107
|
+
| Checkpointing | Yes | Enable resume on failure |
|
|
108
|
+
|
|
109
|
+
## Remaining Work
|
|
110
|
+
|
|
111
|
+
### Phase 2: Progress Streaming (Complete)
|
|
112
|
+
- [x] SSE endpoint: `GET /runs/{id}/progress/stream`
|
|
113
|
+
- [x] `executor.stream_progress()` generator
|
|
114
|
+
- [x] Rich console progress display (`display_progress()`)
|
|
115
|
+
|
|
116
|
+
### Phase 3: Checkpointing & Resume (Complete)
|
|
117
|
+
- [x] `submit(resume_from=run_id)` - Resume from latest checkpoint of a previous run
|
|
118
|
+
- [x] Skip completed actions on resume (marks them as SKIPPED)
|
|
119
|
+
- [x] Restore accumulated params from checkpoint's `params_snapshot`
|
|
120
|
+
|
|
121
|
+
### Phase 4: DAG Pipelines (Future)
|
|
122
|
+
- [ ] Parallel action branches
|
|
123
|
+
- [ ] Per-action resource requirements
|
|
124
|
+
- [ ] Dependency graph execution
|
|
125
|
+
|
|
126
|
+
## Troubleshooting
|
|
127
|
+
|
|
128
|
+
**Ray actor fails to import actions:**
|
|
129
|
+
- Ensure `working_dir` contains the plugin code
|
|
130
|
+
- Check `include_sdk=True` if using local SDK changes
|
|
131
|
+
- Actions must be in a proper module (not `__main__`), importable on the remote worker
|
|
132
|
+
|
|
133
|
+
**Remote cluster connectivity:**
|
|
134
|
+
- Use `actor_pipeline_service_url` parameter for the URL the actor should use
|
|
135
|
+
- The local SDK uses `pipeline_service_url` (e.g., `localhost:8100`)
|
|
136
|
+
- The remote actor uses `actor_pipeline_service_url` (e.g., internal network address)
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
executor = RayPipelineExecutor(
|
|
140
|
+
ray_address="ray://remote-cluster:10001",
|
|
141
|
+
pipeline_service_url="http://localhost:8100", # Local SDK access
|
|
142
|
+
actor_pipeline_service_url="http://internal-service:8100", # Actor access
|
|
143
|
+
include_sdk=True,
|
|
144
|
+
)
|
|
145
|
+
```
|