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,1225 @@
|
|
|
1
|
+
# Plugin System Architecture
|
|
2
|
+
|
|
3
|
+
This document provides a detailed technical overview of the Synapse SDK plugin system architecture, covering all major components, their interactions, and extension points.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## System Architecture
|
|
8
|
+
|
|
9
|
+
### High-Level Overview
|
|
10
|
+
|
|
11
|
+
```mermaid
|
|
12
|
+
flowchart TB
|
|
13
|
+
subgraph UserCode["User Code"]
|
|
14
|
+
decorator["@action decorator"]
|
|
15
|
+
baseaction["BaseAction subclass"]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
subgraph PluginFramework["Plugin Framework"]
|
|
19
|
+
discovery["PluginDiscovery<br/>- from_path()<br/>- from_module()<br/>- get_action_class()"]
|
|
20
|
+
actionclass["Action Class<br/>- params_model<br/>- result_model<br/>- execute()"]
|
|
21
|
+
context["RuntimeContext<br/>- logger<br/>- env<br/>- job_id"]
|
|
22
|
+
executor["Executor<br/>- LocalExecutor<br/>- RayActorExecutor<br/>- RayJobExecutor"]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
subgraph Config["Configuration"]
|
|
26
|
+
configyaml["config.yaml<br/>- actions<br/>- method"]
|
|
27
|
+
pluginenv["PluginEnvironment<br/>- from_environ()<br/>- from_file()"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
decorator -->|discover| discovery
|
|
31
|
+
baseaction -->|discover| discovery
|
|
32
|
+
discovery -->|load| actionclass
|
|
33
|
+
actionclass -->|instantiate| context
|
|
34
|
+
pluginenv -->|inject| context
|
|
35
|
+
context -->|execute via| executor
|
|
36
|
+
|
|
37
|
+
style UserCode fill:#e1f5fe
|
|
38
|
+
style PluginFramework fill:#f3e5f5
|
|
39
|
+
style Config fill:#fff3e0
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Component Interaction Flow
|
|
43
|
+
|
|
44
|
+
```mermaid
|
|
45
|
+
flowchart TD
|
|
46
|
+
A["run_plugin(plugin_code, action, params, mode)"] --> B["_discover_action"]
|
|
47
|
+
B --> C["PluginDiscovery.get_action_class()"]
|
|
48
|
+
C --> D{"Select Executor"}
|
|
49
|
+
|
|
50
|
+
D -->|"mode='local'"| E1["LocalExecutor"]
|
|
51
|
+
D -->|"mode='task'"| E2["RayActorExecutor"]
|
|
52
|
+
D -->|"mode='job'"| E3["RayJobExecutor"]
|
|
53
|
+
|
|
54
|
+
E1 --> F["executor.execute()"]
|
|
55
|
+
E2 --> F
|
|
56
|
+
E3 --> F
|
|
57
|
+
|
|
58
|
+
F --> G["1. Validate params<br/>(Pydantic)"]
|
|
59
|
+
G --> H["2. Create RuntimeContext<br/>(logger, env)"]
|
|
60
|
+
H --> I["3. Instantiate action<br/>action_cls(params, ctx)"]
|
|
61
|
+
I --> J["4. Call execute()<br/>(user's method)"]
|
|
62
|
+
J --> K["5. Validate result<br/>(optional schema)"]
|
|
63
|
+
K --> L["Result"]
|
|
64
|
+
|
|
65
|
+
style A fill:#e8f5e9
|
|
66
|
+
style L fill:#e8f5e9
|
|
67
|
+
style D fill:#fff9c4
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Core Components
|
|
73
|
+
|
|
74
|
+
### BaseAction[P] - Action Base Class
|
|
75
|
+
|
|
76
|
+
Location: `synapse_sdk/plugins/action.py`
|
|
77
|
+
|
|
78
|
+
The `BaseAction` class is a generic abstract base class parameterized by a Pydantic model type `P` representing the action's parameters.
|
|
79
|
+
|
|
80
|
+
#### Class Definition
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from abc import ABC, abstractmethod
|
|
84
|
+
from typing import Generic, TypeVar
|
|
85
|
+
from pydantic import BaseModel
|
|
86
|
+
|
|
87
|
+
P = TypeVar('P', bound=BaseModel)
|
|
88
|
+
|
|
89
|
+
class BaseAction(ABC, Generic[P]):
|
|
90
|
+
# Class attributes (optional, can be injected from config)
|
|
91
|
+
action_name: str | None = None
|
|
92
|
+
category: PluginCategory | None = None
|
|
93
|
+
|
|
94
|
+
# Semantic type declarations for pipeline validation
|
|
95
|
+
input_type: type[DataType] | None = None
|
|
96
|
+
output_type: type[DataType] | None = None
|
|
97
|
+
|
|
98
|
+
# Auto-extracted from generic parameter
|
|
99
|
+
params_model: type[P]
|
|
100
|
+
|
|
101
|
+
# Optional result schema for validation
|
|
102
|
+
result_model: type[BaseModel] | type[NoResult] = NoResult
|
|
103
|
+
|
|
104
|
+
# Instance attributes (set in __init__)
|
|
105
|
+
params: P
|
|
106
|
+
ctx: RuntimeContext
|
|
107
|
+
|
|
108
|
+
@abstractmethod
|
|
109
|
+
def execute(self) -> Any:
|
|
110
|
+
"""Execute the action logic."""
|
|
111
|
+
...
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### Generic Parameter Extraction
|
|
115
|
+
|
|
116
|
+
The `params_model` is automatically extracted from the generic type parameter via `__init_subclass__`:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
class TrainParams(BaseModel):
|
|
120
|
+
epochs: int = 10
|
|
121
|
+
|
|
122
|
+
class TrainAction(BaseAction[TrainParams]): # P = TrainParams
|
|
123
|
+
pass
|
|
124
|
+
|
|
125
|
+
# After class creation:
|
|
126
|
+
TrainAction.params_model # == TrainParams (auto-extracted)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Complete Implementation Example
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from synapse_sdk.plugins import BaseAction
|
|
133
|
+
from synapse_sdk.plugins.enums import PluginCategory
|
|
134
|
+
from synapse_sdk.plugins.types import YOLODataset, ModelWeights
|
|
135
|
+
from pydantic import BaseModel, Field
|
|
136
|
+
|
|
137
|
+
class TrainParams(BaseModel):
|
|
138
|
+
"""Training parameters."""
|
|
139
|
+
epochs: int = Field(default=100, ge=1, le=1000)
|
|
140
|
+
batch_size: int = Field(default=16, ge=1, le=256)
|
|
141
|
+
learning_rate: float = Field(default=0.001, gt=0)
|
|
142
|
+
model_size: str = Field(default='n', pattern='^[nsmlx]$')
|
|
143
|
+
|
|
144
|
+
class TrainResult(BaseModel):
|
|
145
|
+
"""Training result."""
|
|
146
|
+
weights_path: str
|
|
147
|
+
final_loss: float
|
|
148
|
+
best_map: float
|
|
149
|
+
|
|
150
|
+
class YOLOTrainAction(BaseAction[TrainParams]):
|
|
151
|
+
"""Train a YOLO model on a dataset."""
|
|
152
|
+
|
|
153
|
+
# Metadata (optional, can come from config.yaml)
|
|
154
|
+
action_name = 'train'
|
|
155
|
+
category = PluginCategory.NEURAL_NET
|
|
156
|
+
|
|
157
|
+
# Semantic types for pipeline compatibility
|
|
158
|
+
input_type = YOLODataset
|
|
159
|
+
output_type = ModelWeights
|
|
160
|
+
|
|
161
|
+
# Enable result validation
|
|
162
|
+
result_model = TrainResult
|
|
163
|
+
|
|
164
|
+
def execute(self) -> TrainResult:
|
|
165
|
+
# Enable automatic framework logging
|
|
166
|
+
self.autolog('ultralytics')
|
|
167
|
+
|
|
168
|
+
# Access parameters
|
|
169
|
+
epochs = self.params.epochs
|
|
170
|
+
batch_size = self.params.batch_size
|
|
171
|
+
|
|
172
|
+
# Log start event
|
|
173
|
+
self.log('train_start', {
|
|
174
|
+
'epochs': epochs,
|
|
175
|
+
'batch_size': batch_size,
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
# Training loop with progress tracking
|
|
179
|
+
model = self._create_model()
|
|
180
|
+
|
|
181
|
+
for epoch in range(epochs):
|
|
182
|
+
loss = self._train_epoch(model, epoch)
|
|
183
|
+
self.set_progress(epoch + 1, epochs, category='train')
|
|
184
|
+
self.set_metrics({'loss': loss}, category='epoch')
|
|
185
|
+
|
|
186
|
+
# Save model
|
|
187
|
+
weights_path = self._save_model(model)
|
|
188
|
+
|
|
189
|
+
# Log completion
|
|
190
|
+
self.log('train_complete', {'weights_path': weights_path})
|
|
191
|
+
|
|
192
|
+
return TrainResult(
|
|
193
|
+
weights_path=weights_path,
|
|
194
|
+
final_loss=model.final_loss,
|
|
195
|
+
best_map=model.best_map,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
def _create_model(self):
|
|
199
|
+
# Model creation logic
|
|
200
|
+
...
|
|
201
|
+
|
|
202
|
+
def _train_epoch(self, model, epoch):
|
|
203
|
+
# Training epoch logic
|
|
204
|
+
...
|
|
205
|
+
|
|
206
|
+
def _save_model(self, model):
|
|
207
|
+
# Model saving logic
|
|
208
|
+
...
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### Method Reference
|
|
212
|
+
|
|
213
|
+
| Method | Description |
|
|
214
|
+
|--------|-------------|
|
|
215
|
+
| `execute()` | Abstract. Implement your action logic here. |
|
|
216
|
+
| `log(event, data, file=None)` | Log a structured event. |
|
|
217
|
+
| `set_progress(current, total, category=None)` | Update progress tracking. |
|
|
218
|
+
| `set_metrics(value, category)` | Record metrics for a category. |
|
|
219
|
+
| `autolog(framework)` | Enable automatic logging for ML frameworks. |
|
|
220
|
+
|
|
221
|
+
| Property | Description |
|
|
222
|
+
|----------|-------------|
|
|
223
|
+
| `logger` | Access the logger from context. |
|
|
224
|
+
| `params` | Validated parameters (Pydantic model instance). |
|
|
225
|
+
| `ctx` | RuntimeContext with services. |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### RuntimeContext - Dependency Injection Container
|
|
230
|
+
|
|
231
|
+
Location: `synapse_sdk/plugins/context/__init__.py`
|
|
232
|
+
|
|
233
|
+
The `RuntimeContext` provides runtime services to actions.
|
|
234
|
+
|
|
235
|
+
#### Structure
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
from dataclasses import dataclass
|
|
239
|
+
from typing import Any
|
|
240
|
+
|
|
241
|
+
@dataclass
|
|
242
|
+
class RuntimeContext:
|
|
243
|
+
"""Runtime context for action execution."""
|
|
244
|
+
|
|
245
|
+
logger: BaseLogger # Logging interface
|
|
246
|
+
env: dict[str, Any] # Environment variables
|
|
247
|
+
job_id: str | None = None # Job tracking ID
|
|
248
|
+
client: BackendClient | None = None # API client
|
|
249
|
+
agent_client: AgentClient | None = None # Ray operations
|
|
250
|
+
checkpoint: dict | None = None # Pretrained model info
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Usage Patterns
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
def execute(self) -> dict:
|
|
257
|
+
# Logging
|
|
258
|
+
self.ctx.logger.info('Starting execution')
|
|
259
|
+
self.ctx.logger.warning('Rate limit approaching')
|
|
260
|
+
self.ctx.logger.error('Failed to connect')
|
|
261
|
+
|
|
262
|
+
# Environment access
|
|
263
|
+
api_key = self.ctx.env.get('API_KEY', '')
|
|
264
|
+
debug_mode = self.ctx.env.get('DEBUG', 'false') == 'true'
|
|
265
|
+
|
|
266
|
+
# Structured logging
|
|
267
|
+
self.ctx.log('process_start', {'input_size': 1000})
|
|
268
|
+
|
|
269
|
+
# Progress tracking (with optional category)
|
|
270
|
+
self.ctx.set_progress(50, 100) # 50% complete
|
|
271
|
+
self.ctx.set_progress(5, 10, category='download') # Category-specific
|
|
272
|
+
|
|
273
|
+
# Metrics recording
|
|
274
|
+
self.ctx.set_metrics({'loss': 0.05}, category='train')
|
|
275
|
+
self.ctx.set_metrics({'accuracy': 0.95}, category='eval')
|
|
276
|
+
|
|
277
|
+
# User-visible messages
|
|
278
|
+
self.ctx.log_message('Model training complete!')
|
|
279
|
+
|
|
280
|
+
# Developer debug events
|
|
281
|
+
self.ctx.log_dev_event('checkpoint_saved', {'epoch': 10})
|
|
282
|
+
|
|
283
|
+
# Finalize logging
|
|
284
|
+
self.ctx.end_log()
|
|
285
|
+
|
|
286
|
+
return {'status': 'done'}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
### PluginEnvironment - Configuration Management
|
|
292
|
+
|
|
293
|
+
Location: `synapse_sdk/plugins/context/env.py`
|
|
294
|
+
|
|
295
|
+
Type-safe configuration loading from environment or files.
|
|
296
|
+
|
|
297
|
+
#### Loading Methods
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
from synapse_sdk.plugins.context.env import PluginEnvironment
|
|
301
|
+
|
|
302
|
+
# From environment variables with prefix
|
|
303
|
+
# PLUGIN_API_KEY=xxx, PLUGIN_BATCH_SIZE=32, etc.
|
|
304
|
+
env = PluginEnvironment.from_environ(prefix='PLUGIN_')
|
|
305
|
+
|
|
306
|
+
# From TOML file
|
|
307
|
+
env = PluginEnvironment.from_file('config.toml')
|
|
308
|
+
|
|
309
|
+
# From explicit dictionary
|
|
310
|
+
env = PluginEnvironment({'API_KEY': 'xxx', 'BATCH_SIZE': 32})
|
|
311
|
+
|
|
312
|
+
# Merge environments (later values override)
|
|
313
|
+
merged = env1.merge(env2)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### Type-Safe Getters
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
# String (required - raises if missing)
|
|
320
|
+
api_key = env.get_str('API_KEY')
|
|
321
|
+
|
|
322
|
+
# String with default
|
|
323
|
+
mode = env.get_str('MODE', default='production')
|
|
324
|
+
|
|
325
|
+
# Integer
|
|
326
|
+
batch_size = env.get_int('BATCH_SIZE', default=32)
|
|
327
|
+
|
|
328
|
+
# Float
|
|
329
|
+
learning_rate = env.get_float('LEARNING_RATE', default=0.001)
|
|
330
|
+
|
|
331
|
+
# Boolean (true/false, 1/0, yes/no)
|
|
332
|
+
debug = env.get_bool('DEBUG', default=False)
|
|
333
|
+
|
|
334
|
+
# List (comma-separated string or actual list)
|
|
335
|
+
tags = env.get_list('TAGS', default=[])
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
### PluginConfig & ActionConfig
|
|
341
|
+
|
|
342
|
+
Location: `synapse_sdk/plugins/config.py`
|
|
343
|
+
|
|
344
|
+
Configuration models for plugin metadata.
|
|
345
|
+
|
|
346
|
+
#### ActionConfig
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
from pydantic import BaseModel
|
|
350
|
+
from synapse_sdk.plugins.enums import RunMethod
|
|
351
|
+
|
|
352
|
+
class ActionConfig(BaseModel):
|
|
353
|
+
name: str # Display name
|
|
354
|
+
description: str = '' # Human-readable description
|
|
355
|
+
entrypoint: str # Module path (module:Class or module.Class)
|
|
356
|
+
method: RunMethod = RunMethod.TASK # Execution method
|
|
357
|
+
params_schema: type[BaseModel] | None = None # Parameter schema
|
|
358
|
+
input_type: str | None = None # Semantic input type name
|
|
359
|
+
output_type: str | None = None # Semantic output type name
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
#### PluginConfig
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
class PluginConfig(BaseModel):
|
|
366
|
+
name: str # Plugin display name
|
|
367
|
+
code: str # Unique identifier
|
|
368
|
+
version: str = '0.1.0' # Semantic version
|
|
369
|
+
category: PluginCategory # Plugin category
|
|
370
|
+
|
|
371
|
+
# Package management
|
|
372
|
+
package_manager: PackageManager = PackageManager.PIP
|
|
373
|
+
package_manager_options: list[str] = []
|
|
374
|
+
wheels_dir: str = 'wheels'
|
|
375
|
+
|
|
376
|
+
# Runtime configuration
|
|
377
|
+
env: dict[str, Any] = {} # Default environment
|
|
378
|
+
runtime_env: dict[str, Any] = {} # Ray runtime_env
|
|
379
|
+
|
|
380
|
+
# Data type configuration
|
|
381
|
+
data_type: DataType | None = None # IMAGE, TEXT, VIDEO, etc.
|
|
382
|
+
tasks: list[str] = [] # Supported annotation tasks
|
|
383
|
+
|
|
384
|
+
# Smart tool configuration
|
|
385
|
+
annotation_category: AnnotationCategory | None = None
|
|
386
|
+
annotation_type: AnnotationType | None = None
|
|
387
|
+
smart_tool: SmartToolType | None = None
|
|
388
|
+
|
|
389
|
+
# Actions
|
|
390
|
+
actions: dict[str, ActionConfig] = {}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
#### config.yaml Example
|
|
394
|
+
|
|
395
|
+
```yaml
|
|
396
|
+
name: YOLO Training Plugin
|
|
397
|
+
code: yolo_train
|
|
398
|
+
version: 1.0.0
|
|
399
|
+
category: neural_net
|
|
400
|
+
data_type: image
|
|
401
|
+
package_manager: uv
|
|
402
|
+
|
|
403
|
+
env:
|
|
404
|
+
DEFAULT_MODEL: yolov8n.pt
|
|
405
|
+
MAX_EPOCHS: 300
|
|
406
|
+
|
|
407
|
+
runtime_env:
|
|
408
|
+
pip:
|
|
409
|
+
- ultralytics>=8.0.0
|
|
410
|
+
- torch>=2.0.0
|
|
411
|
+
|
|
412
|
+
actions:
|
|
413
|
+
train:
|
|
414
|
+
name: Train YOLO Model
|
|
415
|
+
description: Train a YOLO model on a labeled dataset
|
|
416
|
+
entrypoint: yolo_plugin.actions:TrainAction
|
|
417
|
+
method: job
|
|
418
|
+
input_type: YOLODataset
|
|
419
|
+
output_type: ModelWeights
|
|
420
|
+
|
|
421
|
+
export:
|
|
422
|
+
name: Export Model
|
|
423
|
+
description: Export trained model to ONNX format
|
|
424
|
+
entrypoint: yolo_plugin.actions:ExportAction
|
|
425
|
+
method: task
|
|
426
|
+
input_type: ModelWeights
|
|
427
|
+
output_type: ONNXModel
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Step-Based Workflow System
|
|
433
|
+
|
|
434
|
+
For complex multi-phase operations, use the step-based workflow system.
|
|
435
|
+
|
|
436
|
+
### BaseStep[C] - Step Base Class
|
|
437
|
+
|
|
438
|
+
Location: `synapse_sdk/plugins/steps/base.py`
|
|
439
|
+
|
|
440
|
+
```python
|
|
441
|
+
from abc import ABC, abstractmethod
|
|
442
|
+
|
|
443
|
+
class BaseStep[C: BaseStepContext](ABC):
|
|
444
|
+
"""Abstract base for workflow steps."""
|
|
445
|
+
|
|
446
|
+
@property
|
|
447
|
+
@abstractmethod
|
|
448
|
+
def name(self) -> str:
|
|
449
|
+
"""Unique step identifier."""
|
|
450
|
+
...
|
|
451
|
+
|
|
452
|
+
@property
|
|
453
|
+
@abstractmethod
|
|
454
|
+
def progress_weight(self) -> float:
|
|
455
|
+
"""Weight for progress calculation (0.0-1.0)."""
|
|
456
|
+
...
|
|
457
|
+
|
|
458
|
+
@abstractmethod
|
|
459
|
+
def execute(self, context: C) -> StepResult:
|
|
460
|
+
"""Execute the step."""
|
|
461
|
+
...
|
|
462
|
+
|
|
463
|
+
def can_skip(self, context: C) -> bool:
|
|
464
|
+
"""Optional skip condition."""
|
|
465
|
+
return False
|
|
466
|
+
|
|
467
|
+
def rollback(self, context: C, result: StepResult) -> None:
|
|
468
|
+
"""Optional cleanup on workflow failure."""
|
|
469
|
+
pass
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### StepResult - Step Outcome
|
|
473
|
+
|
|
474
|
+
```python
|
|
475
|
+
from dataclasses import dataclass, field
|
|
476
|
+
from datetime import datetime
|
|
477
|
+
from typing import Any
|
|
478
|
+
|
|
479
|
+
@dataclass
|
|
480
|
+
class StepResult:
|
|
481
|
+
success: bool = True
|
|
482
|
+
data: dict[str, Any] = field(default_factory=dict)
|
|
483
|
+
error: str | None = None
|
|
484
|
+
rollback_data: dict[str, Any] = field(default_factory=dict)
|
|
485
|
+
skipped: bool = False
|
|
486
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Creating Custom Steps
|
|
490
|
+
|
|
491
|
+
```python
|
|
492
|
+
from synapse_sdk.plugins.steps import BaseStep, StepResult, BaseStepContext
|
|
493
|
+
from dataclasses import dataclass, field
|
|
494
|
+
|
|
495
|
+
# 1. Define context with shared state
|
|
496
|
+
@dataclass
|
|
497
|
+
class UploadContext(BaseStepContext):
|
|
498
|
+
"""Context for upload workflow."""
|
|
499
|
+
files: list[str] = field(default_factory=list)
|
|
500
|
+
uploaded_urls: list[str] = field(default_factory=list)
|
|
501
|
+
total_bytes: int = 0
|
|
502
|
+
|
|
503
|
+
# 2. Implement steps
|
|
504
|
+
class ValidateFilesStep(BaseStep[UploadContext]):
|
|
505
|
+
@property
|
|
506
|
+
def name(self) -> str:
|
|
507
|
+
return 'validate_files'
|
|
508
|
+
|
|
509
|
+
@property
|
|
510
|
+
def progress_weight(self) -> float:
|
|
511
|
+
return 0.1 # 10% of workflow
|
|
512
|
+
|
|
513
|
+
def execute(self, context: UploadContext) -> StepResult:
|
|
514
|
+
# Validate each file exists
|
|
515
|
+
missing = []
|
|
516
|
+
for path in context.files:
|
|
517
|
+
if not os.path.exists(path):
|
|
518
|
+
missing.append(path)
|
|
519
|
+
|
|
520
|
+
if missing:
|
|
521
|
+
return StepResult(
|
|
522
|
+
success=False,
|
|
523
|
+
error=f"Missing files: {missing}",
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
# Calculate total size
|
|
527
|
+
context.total_bytes = sum(
|
|
528
|
+
os.path.getsize(f) for f in context.files
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
return StepResult(
|
|
532
|
+
success=True,
|
|
533
|
+
data={'total_bytes': context.total_bytes},
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
class UploadFilesStep(BaseStep[UploadContext]):
|
|
538
|
+
@property
|
|
539
|
+
def name(self) -> str:
|
|
540
|
+
return 'upload_files'
|
|
541
|
+
|
|
542
|
+
@property
|
|
543
|
+
def progress_weight(self) -> float:
|
|
544
|
+
return 0.8 # 80% of workflow
|
|
545
|
+
|
|
546
|
+
def execute(self, context: UploadContext) -> StepResult:
|
|
547
|
+
uploaded = []
|
|
548
|
+
|
|
549
|
+
for i, path in enumerate(context.files):
|
|
550
|
+
# Report per-file progress
|
|
551
|
+
context.set_progress(i, len(context.files))
|
|
552
|
+
|
|
553
|
+
url = upload_to_storage(path)
|
|
554
|
+
uploaded.append(url)
|
|
555
|
+
context.uploaded_urls.append(url)
|
|
556
|
+
|
|
557
|
+
return StepResult(
|
|
558
|
+
success=True,
|
|
559
|
+
data={'urls': uploaded},
|
|
560
|
+
rollback_data={'urls': uploaded}, # For cleanup
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
def rollback(self, context: UploadContext, result: StepResult) -> None:
|
|
564
|
+
# Clean up uploaded files on failure
|
|
565
|
+
for url in result.rollback_data.get('urls', []):
|
|
566
|
+
try:
|
|
567
|
+
delete_from_storage(url)
|
|
568
|
+
except Exception:
|
|
569
|
+
context.errors.append(f"Failed to delete: {url}")
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
class FinalizeStep(BaseStep[UploadContext]):
|
|
573
|
+
@property
|
|
574
|
+
def name(self) -> str:
|
|
575
|
+
return 'finalize'
|
|
576
|
+
|
|
577
|
+
@property
|
|
578
|
+
def progress_weight(self) -> float:
|
|
579
|
+
return 0.1 # 10% of workflow
|
|
580
|
+
|
|
581
|
+
def can_skip(self, context: UploadContext) -> bool:
|
|
582
|
+
# Skip if nothing was uploaded
|
|
583
|
+
return len(context.uploaded_urls) == 0
|
|
584
|
+
|
|
585
|
+
def execute(self, context: UploadContext) -> StepResult:
|
|
586
|
+
# Register uploads in database
|
|
587
|
+
register_uploads(context.uploaded_urls)
|
|
588
|
+
|
|
589
|
+
return StepResult(
|
|
590
|
+
success=True,
|
|
591
|
+
data={'finalized': True},
|
|
592
|
+
)
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
### StepRegistry - Step Management
|
|
596
|
+
|
|
597
|
+
Location: `synapse_sdk/plugins/steps/registry.py`
|
|
598
|
+
|
|
599
|
+
```python
|
|
600
|
+
from synapse_sdk.plugins.steps import StepRegistry
|
|
601
|
+
|
|
602
|
+
# Create registry
|
|
603
|
+
registry = StepRegistry[UploadContext]()
|
|
604
|
+
|
|
605
|
+
# Register steps in order
|
|
606
|
+
registry.register(ValidateFilesStep())
|
|
607
|
+
registry.register(UploadFilesStep())
|
|
608
|
+
registry.register(FinalizeStep())
|
|
609
|
+
|
|
610
|
+
# Dynamic insertion
|
|
611
|
+
registry.insert_after('validate_files', CompressionStep())
|
|
612
|
+
registry.insert_before('finalize', VerifyStep())
|
|
613
|
+
|
|
614
|
+
# Remove step
|
|
615
|
+
registry.unregister('compression')
|
|
616
|
+
|
|
617
|
+
# Access steps
|
|
618
|
+
steps = registry.get_steps() # Returns copy of step list
|
|
619
|
+
total = registry.total_weight # Sum of all progress weights
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Orchestrator - Step Execution
|
|
623
|
+
|
|
624
|
+
Location: `synapse_sdk/plugins/steps/orchestrator.py`
|
|
625
|
+
|
|
626
|
+
```python
|
|
627
|
+
from synapse_sdk.plugins.steps import Orchestrator, StepRegistry
|
|
628
|
+
|
|
629
|
+
# Setup
|
|
630
|
+
registry = StepRegistry[UploadContext]()
|
|
631
|
+
registry.register(ValidateFilesStep())
|
|
632
|
+
registry.register(UploadFilesStep())
|
|
633
|
+
registry.register(FinalizeStep())
|
|
634
|
+
|
|
635
|
+
# Create context
|
|
636
|
+
context = UploadContext(
|
|
637
|
+
runtime_ctx=runtime_ctx,
|
|
638
|
+
files=['/data/file1.jpg', '/data/file2.jpg'],
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
# Optional progress callback
|
|
642
|
+
def on_progress(current: int, total: int):
|
|
643
|
+
print(f"Progress: {current}/{total}%")
|
|
644
|
+
|
|
645
|
+
# Execute workflow
|
|
646
|
+
orchestrator = Orchestrator(
|
|
647
|
+
registry=registry,
|
|
648
|
+
context=context,
|
|
649
|
+
progress_callback=on_progress,
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
try:
|
|
653
|
+
result = orchestrator.execute()
|
|
654
|
+
# {'success': True, 'steps_executed': 3, 'steps_total': 3}
|
|
655
|
+
print(f"Uploaded: {context.uploaded_urls}")
|
|
656
|
+
except RuntimeError as e:
|
|
657
|
+
print(f"Workflow failed: {e}")
|
|
658
|
+
# Rollback already performed automatically
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Orchestrator Execution Flow
|
|
662
|
+
|
|
663
|
+
```mermaid
|
|
664
|
+
flowchart TD
|
|
665
|
+
A["orchestrator.execute()"] --> B["For each step in registry"]
|
|
666
|
+
B --> C["Set context.current_step = step.name"]
|
|
667
|
+
C --> D{"step.can_skip(context)?"}
|
|
668
|
+
|
|
669
|
+
D -->|Yes| E["Create skipped StepResult"]
|
|
670
|
+
D -->|No| F["Try: result = step.execute(context)"]
|
|
671
|
+
|
|
672
|
+
F -->|Exception| G["result = StepResult(success=False, error)"]
|
|
673
|
+
F -->|Success| H["result from execute()"]
|
|
674
|
+
|
|
675
|
+
E --> I["Append result to context.step_results"]
|
|
676
|
+
G --> I
|
|
677
|
+
H --> I
|
|
678
|
+
|
|
679
|
+
I --> J{"result.success?"}
|
|
680
|
+
|
|
681
|
+
J -->|No| K["_rollback() in reverse order"]
|
|
682
|
+
K --> L["Raise RuntimeError"]
|
|
683
|
+
|
|
684
|
+
J -->|Yes| M["Update progress via callback"]
|
|
685
|
+
M --> N{"More steps?"}
|
|
686
|
+
|
|
687
|
+
N -->|Yes| B
|
|
688
|
+
N -->|No| O["Clear context.current_step"]
|
|
689
|
+
O --> P["Return success summary"]
|
|
690
|
+
|
|
691
|
+
style A fill:#e8f5e9
|
|
692
|
+
style P fill:#e8f5e9
|
|
693
|
+
style L fill:#ffcdd2
|
|
694
|
+
style D fill:#fff9c4
|
|
695
|
+
style J fill:#fff9c4
|
|
696
|
+
style N fill:#fff9c4
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
### Utility Steps
|
|
700
|
+
|
|
701
|
+
#### LoggingStep - Execution Logging
|
|
702
|
+
|
|
703
|
+
```python
|
|
704
|
+
from synapse_sdk.plugins.steps.utils import LoggingStep
|
|
705
|
+
|
|
706
|
+
# Wrap any step with logging
|
|
707
|
+
logged_upload = LoggingStep(UploadFilesStep())
|
|
708
|
+
|
|
709
|
+
# Will log:
|
|
710
|
+
# - step_start: {step: 'logged_upload_files'}
|
|
711
|
+
# - step_end: {step: 'logged_upload_files', elapsed: 1.23, success: True}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
#### TimingStep - Execution Timing
|
|
715
|
+
|
|
716
|
+
```python
|
|
717
|
+
from synapse_sdk.plugins.steps.utils import TimingStep
|
|
718
|
+
|
|
719
|
+
# Wrap any step with timing
|
|
720
|
+
timed_upload = TimingStep(UploadFilesStep())
|
|
721
|
+
|
|
722
|
+
# Result will include:
|
|
723
|
+
# result.data['duration_seconds'] = 1.234567
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
#### ValidationStep - Context Validation
|
|
727
|
+
|
|
728
|
+
```python
|
|
729
|
+
from synapse_sdk.plugins.steps.utils import ValidationStep
|
|
730
|
+
|
|
731
|
+
def validate_files_exist(context: UploadContext) -> tuple[bool, str | None]:
|
|
732
|
+
if not context.files:
|
|
733
|
+
return False, "No files provided"
|
|
734
|
+
return True, None
|
|
735
|
+
|
|
736
|
+
# Create validation step
|
|
737
|
+
validate_step = ValidationStep(
|
|
738
|
+
validator=validate_files_exist,
|
|
739
|
+
name='validate_input',
|
|
740
|
+
progress_weight=0.05,
|
|
741
|
+
)
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
## Action Specializations
|
|
747
|
+
|
|
748
|
+
### BaseTrainAction
|
|
749
|
+
|
|
750
|
+
Location: `synapse_sdk/plugins/actions/train/`
|
|
751
|
+
|
|
752
|
+
Base class for ML training actions with step-based workflow support.
|
|
753
|
+
|
|
754
|
+
```python
|
|
755
|
+
from synapse_sdk.plugins.actions.train import BaseTrainAction, TrainContext
|
|
756
|
+
from synapse_sdk.plugins.steps import StepRegistry
|
|
757
|
+
|
|
758
|
+
class MyTrainAction(BaseTrainAction[TrainParams]):
|
|
759
|
+
def setup_steps(self, registry: StepRegistry[TrainContext]) -> None:
|
|
760
|
+
"""Override to register training steps."""
|
|
761
|
+
registry.register(PrepareDatasetStep())
|
|
762
|
+
registry.register(InitModelStep())
|
|
763
|
+
registry.register(TrainStep())
|
|
764
|
+
registry.register(SaveModelStep())
|
|
765
|
+
|
|
766
|
+
def execute(self) -> dict:
|
|
767
|
+
# Base class handles step orchestration
|
|
768
|
+
return super().execute()
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
TrainContext provides:
|
|
772
|
+
- `dataset`: Loaded dataset reference
|
|
773
|
+
- `model_path`: Path to model weights
|
|
774
|
+
- `model`: Model instance
|
|
775
|
+
- Progress categories: `DATASET`, `TRAIN`, `MODEL_UPLOAD`
|
|
776
|
+
|
|
777
|
+
### BaseExportAction
|
|
778
|
+
|
|
779
|
+
Location: `synapse_sdk/plugins/actions/export/`
|
|
780
|
+
|
|
781
|
+
```python
|
|
782
|
+
from synapse_sdk.plugins.actions.export import BaseExportAction, ExportContext
|
|
783
|
+
|
|
784
|
+
class ONNXExportAction(BaseExportAction[ExportParams]):
|
|
785
|
+
def execute(self) -> dict:
|
|
786
|
+
# Load model
|
|
787
|
+
model = load_model(self.params.model_path)
|
|
788
|
+
|
|
789
|
+
# Export to ONNX
|
|
790
|
+
self.set_progress(0, 100, category='export')
|
|
791
|
+
output_path = export_to_onnx(model, self.params.output_path)
|
|
792
|
+
self.set_progress(100, 100, category='export')
|
|
793
|
+
|
|
794
|
+
return {'output_path': output_path}
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### BaseUploadAction
|
|
798
|
+
|
|
799
|
+
Location: `synapse_sdk/plugins/actions/upload/`
|
|
800
|
+
|
|
801
|
+
```python
|
|
802
|
+
from synapse_sdk.plugins.actions.upload import BaseUploadAction, UploadContext
|
|
803
|
+
|
|
804
|
+
class S3UploadAction(BaseUploadAction[UploadParams]):
|
|
805
|
+
def setup_steps(self, registry: StepRegistry[UploadContext]) -> None:
|
|
806
|
+
registry.register(ValidateFilesStep())
|
|
807
|
+
registry.register(UploadToS3Step())
|
|
808
|
+
registry.register(VerifyUploadStep())
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
UploadContext provides:
|
|
812
|
+
- `organized_files`: Files prepared for upload
|
|
813
|
+
- `uploaded_files`: Successfully uploaded file references
|
|
814
|
+
- `data_units`: Data unit tracking
|
|
815
|
+
- Progress categories: `VALIDATION`, `UPLOAD`, `FINALIZATION`
|
|
816
|
+
|
|
817
|
+
### BaseInferenceAction & BaseDeploymentAction
|
|
818
|
+
|
|
819
|
+
Location: `synapse_sdk/plugins/actions/inference/`
|
|
820
|
+
|
|
821
|
+
```python
|
|
822
|
+
from synapse_sdk.plugins.actions.inference import (
|
|
823
|
+
BaseInferenceAction,
|
|
824
|
+
BaseDeploymentAction,
|
|
825
|
+
InferenceContext,
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
class YOLOInferenceAction(BaseInferenceAction[InferenceParams]):
|
|
829
|
+
def execute(self) -> dict:
|
|
830
|
+
# Load model
|
|
831
|
+
self.set_progress(0, 100, category='model_download')
|
|
832
|
+
model = load_model(self.params.model_path)
|
|
833
|
+
self.set_progress(100, 100, category='model_download')
|
|
834
|
+
|
|
835
|
+
# Run inference
|
|
836
|
+
results = []
|
|
837
|
+
images = self.params.images
|
|
838
|
+
for i, image in enumerate(images):
|
|
839
|
+
self.set_progress(i, len(images), category='inference')
|
|
840
|
+
result = model.predict(image)
|
|
841
|
+
results.append(result)
|
|
842
|
+
|
|
843
|
+
return {'predictions': results}
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
---
|
|
847
|
+
|
|
848
|
+
## Executor System
|
|
849
|
+
|
|
850
|
+
### LocalExecutor
|
|
851
|
+
|
|
852
|
+
Location: `synapse_sdk/plugins/executors/local.py`
|
|
853
|
+
|
|
854
|
+
Synchronous, in-process execution for development.
|
|
855
|
+
|
|
856
|
+
```python
|
|
857
|
+
from synapse_sdk.plugins.executors import LocalExecutor
|
|
858
|
+
|
|
859
|
+
executor = LocalExecutor(
|
|
860
|
+
env={'DEBUG': 'true', 'API_KEY': 'xxx'},
|
|
861
|
+
job_id='local-test-001',
|
|
862
|
+
)
|
|
863
|
+
|
|
864
|
+
result = executor.execute(
|
|
865
|
+
action_cls=TrainAction,
|
|
866
|
+
params={'epochs': 10, 'batch_size': 32},
|
|
867
|
+
)
|
|
868
|
+
|
|
869
|
+
# Result is returned directly
|
|
870
|
+
print(result)
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
### RayActorExecutor
|
|
874
|
+
|
|
875
|
+
Location: `synapse_sdk/plugins/executors/ray/task.py`
|
|
876
|
+
|
|
877
|
+
Persistent Ray Actor for serial task execution.
|
|
878
|
+
|
|
879
|
+
```python
|
|
880
|
+
from synapse_sdk.plugins.executors.ray import RayActorExecutor
|
|
881
|
+
|
|
882
|
+
executor = RayActorExecutor(
|
|
883
|
+
working_dir='/path/to/plugin', # Plugin source code
|
|
884
|
+
num_gpus=1, # GPU allocation per task
|
|
885
|
+
num_cpus=4, # CPU allocation per task
|
|
886
|
+
runtime_env={ # Additional Ray runtime_env
|
|
887
|
+
'pip': ['torch>=2.0'],
|
|
888
|
+
},
|
|
889
|
+
)
|
|
890
|
+
|
|
891
|
+
# Execute action on Ray cluster
|
|
892
|
+
result = executor.execute(
|
|
893
|
+
action_cls=TrainAction,
|
|
894
|
+
params={'epochs': 100},
|
|
895
|
+
)
|
|
896
|
+
|
|
897
|
+
# Cleanup actor
|
|
898
|
+
executor.shutdown()
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
### RayJobExecutor
|
|
902
|
+
|
|
903
|
+
Location: `synapse_sdk/plugins/executors/ray/job.py`
|
|
904
|
+
|
|
905
|
+
Full job isolation via Ray Job API.
|
|
906
|
+
|
|
907
|
+
```python
|
|
908
|
+
from synapse_sdk.plugins.executors.ray import RayJobExecutor
|
|
909
|
+
|
|
910
|
+
executor = RayJobExecutor(
|
|
911
|
+
dashboard_url='http://ray-head:8265',
|
|
912
|
+
working_dir='/path/to/plugin',
|
|
913
|
+
runtime_env={
|
|
914
|
+
'pip': ['ultralytics>=8.0'],
|
|
915
|
+
'env_vars': {'CUDA_VISIBLE_DEVICES': '0'},
|
|
916
|
+
},
|
|
917
|
+
)
|
|
918
|
+
|
|
919
|
+
# Submit job (returns immediately)
|
|
920
|
+
job_id = executor.submit(
|
|
921
|
+
action_name='train',
|
|
922
|
+
params={'epochs': 100},
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
# Monitor status
|
|
926
|
+
status = executor.get_status(job_id)
|
|
927
|
+
# Returns: 'PENDING', 'RUNNING', 'SUCCEEDED', 'FAILED', 'STOPPED'
|
|
928
|
+
|
|
929
|
+
# Stream logs
|
|
930
|
+
for line in executor.stream_logs(job_id):
|
|
931
|
+
print(line)
|
|
932
|
+
|
|
933
|
+
# Wait for completion with timeout
|
|
934
|
+
result = executor.wait(job_id, timeout_seconds=3600)
|
|
935
|
+
|
|
936
|
+
# Or get logs after completion
|
|
937
|
+
logs = executor.get_logs(job_id)
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
### RayPipelineExecutor
|
|
941
|
+
|
|
942
|
+
Location: `synapse_sdk/plugins/executors/ray/pipeline.py`
|
|
943
|
+
|
|
944
|
+
Multi-action workflow execution. See [PIPELINE_GUIDE.md](PIPELINE_GUIDE.md) for details.
|
|
945
|
+
|
|
946
|
+
```python
|
|
947
|
+
from synapse_sdk.plugins.pipelines import ActionPipeline
|
|
948
|
+
from synapse_sdk.plugins.executors.ray import RayPipelineExecutor
|
|
949
|
+
|
|
950
|
+
# Define pipeline
|
|
951
|
+
pipeline = ActionPipeline([
|
|
952
|
+
DownloadAction,
|
|
953
|
+
PreprocessAction,
|
|
954
|
+
TrainAction,
|
|
955
|
+
ExportAction,
|
|
956
|
+
])
|
|
957
|
+
|
|
958
|
+
# Create executor
|
|
959
|
+
executor = RayPipelineExecutor(
|
|
960
|
+
ray_address='auto',
|
|
961
|
+
working_dir='/path/to/plugin',
|
|
962
|
+
pipeline_service_url='http://localhost:8100',
|
|
963
|
+
)
|
|
964
|
+
|
|
965
|
+
# Submit pipeline
|
|
966
|
+
run_id = pipeline.submit({'dataset_id': 123}, executor)
|
|
967
|
+
|
|
968
|
+
# Monitor progress
|
|
969
|
+
progress = executor.get_progress(run_id)
|
|
970
|
+
|
|
971
|
+
# Wait for result
|
|
972
|
+
result = pipeline.wait(run_id, executor)
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
---
|
|
976
|
+
|
|
977
|
+
## Plugin Discovery System
|
|
978
|
+
|
|
979
|
+
Location: `synapse_sdk/plugins/discovery.py`
|
|
980
|
+
|
|
981
|
+
### PluginDiscovery Class
|
|
982
|
+
|
|
983
|
+
```python
|
|
984
|
+
from synapse_sdk.plugins.discovery import PluginDiscovery
|
|
985
|
+
|
|
986
|
+
# Load from config file
|
|
987
|
+
discovery = PluginDiscovery.from_path('/path/to/plugin')
|
|
988
|
+
|
|
989
|
+
# Load from Python module
|
|
990
|
+
discovery = PluginDiscovery.from_module('my_plugin')
|
|
991
|
+
|
|
992
|
+
# List available actions
|
|
993
|
+
actions = discovery.list_actions()
|
|
994
|
+
# ['train', 'export', 'inference']
|
|
995
|
+
|
|
996
|
+
# Get action class with metadata injection
|
|
997
|
+
action_cls = discovery.get_action_class('train')
|
|
998
|
+
# action_cls.action_name == 'train' (injected from config)
|
|
999
|
+
# action_cls.category == PluginCategory.NEURAL_NET
|
|
1000
|
+
|
|
1001
|
+
# Get params model for validation
|
|
1002
|
+
params_model = discovery.get_action_params_model('train')
|
|
1003
|
+
|
|
1004
|
+
# Get result model
|
|
1005
|
+
result_model = discovery.get_action_result_model('train')
|
|
1006
|
+
|
|
1007
|
+
# Get semantic types
|
|
1008
|
+
input_type = discovery.get_action_input_type('train') # YOLODataset
|
|
1009
|
+
output_type = discovery.get_action_output_type('train') # ModelWeights
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
### UI Schema Generation
|
|
1013
|
+
|
|
1014
|
+
Generate FormKit UI schemas from Pydantic models:
|
|
1015
|
+
|
|
1016
|
+
```python
|
|
1017
|
+
# Get UI schema for action params
|
|
1018
|
+
ui_schema = discovery.get_action_ui_schema('train')
|
|
1019
|
+
|
|
1020
|
+
# Returns FormKit-compatible schema:
|
|
1021
|
+
# {
|
|
1022
|
+
# '$formkit': 'group',
|
|
1023
|
+
# 'children': [
|
|
1024
|
+
# {
|
|
1025
|
+
# '$formkit': 'number',
|
|
1026
|
+
# 'name': 'epochs',
|
|
1027
|
+
# 'label': 'Epochs',
|
|
1028
|
+
# 'value': 10,
|
|
1029
|
+
# 'validation': 'required|min:1|max:1000',
|
|
1030
|
+
# },
|
|
1031
|
+
# ...
|
|
1032
|
+
# ]
|
|
1033
|
+
# }
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
### Config Synchronization
|
|
1037
|
+
|
|
1038
|
+
Update config.yaml from discovered code:
|
|
1039
|
+
|
|
1040
|
+
```python
|
|
1041
|
+
# Discover actions and update config file
|
|
1042
|
+
PluginDiscovery.sync_config_file('/path/to/plugin/config.yaml')
|
|
1043
|
+
|
|
1044
|
+
# This will:
|
|
1045
|
+
# 1. Scan Python files for BaseAction subclasses
|
|
1046
|
+
# 2. Extract entrypoints, input_type, output_type
|
|
1047
|
+
# 3. Add new actions to config.yaml
|
|
1048
|
+
# 4. Update existing action entrypoints
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
### Static Discovery (AST-Based)
|
|
1052
|
+
|
|
1053
|
+
Discover actions without importing (safer for broken modules):
|
|
1054
|
+
|
|
1055
|
+
```python
|
|
1056
|
+
# Returns list of discovered action info
|
|
1057
|
+
actions = PluginDiscovery.discover_actions('/path/to/plugin')
|
|
1058
|
+
|
|
1059
|
+
# Each action contains:
|
|
1060
|
+
# {
|
|
1061
|
+
# 'name': 'train',
|
|
1062
|
+
# 'entrypoint': 'my_plugin.actions:TrainAction',
|
|
1063
|
+
# 'input_type': 'YOLODataset',
|
|
1064
|
+
# 'output_type': 'ModelWeights',
|
|
1065
|
+
# }
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
---
|
|
1069
|
+
|
|
1070
|
+
## Type System
|
|
1071
|
+
|
|
1072
|
+
Location: `synapse_sdk/plugins/types.py`
|
|
1073
|
+
|
|
1074
|
+
### DataType Hierarchy
|
|
1075
|
+
|
|
1076
|
+
```python
|
|
1077
|
+
class DataType:
|
|
1078
|
+
"""Base class for semantic data types."""
|
|
1079
|
+
name: ClassVar[str]
|
|
1080
|
+
format: ClassVar[str | None] = None
|
|
1081
|
+
description: ClassVar[str] = ''
|
|
1082
|
+
|
|
1083
|
+
@classmethod
|
|
1084
|
+
def is_compatible_with(cls, other: type[DataType]) -> bool:
|
|
1085
|
+
"""Check if this type is compatible with another."""
|
|
1086
|
+
return issubclass(cls, other) or issubclass(other, cls)
|
|
1087
|
+
|
|
1088
|
+
# Built-in types
|
|
1089
|
+
class Dataset(DataType):
|
|
1090
|
+
name = 'dataset'
|
|
1091
|
+
|
|
1092
|
+
class YOLODataset(Dataset):
|
|
1093
|
+
name = 'yolo_dataset'
|
|
1094
|
+
format = 'yolo'
|
|
1095
|
+
|
|
1096
|
+
class COCODataset(Dataset):
|
|
1097
|
+
name = 'coco_dataset'
|
|
1098
|
+
format = 'coco'
|
|
1099
|
+
|
|
1100
|
+
class Model(DataType):
|
|
1101
|
+
name = 'model'
|
|
1102
|
+
|
|
1103
|
+
class ModelWeights(Model):
|
|
1104
|
+
name = 'model_weights'
|
|
1105
|
+
|
|
1106
|
+
class ONNXModel(Model):
|
|
1107
|
+
name = 'onnx_model'
|
|
1108
|
+
format = 'onnx'
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
### Creating Custom Types
|
|
1112
|
+
|
|
1113
|
+
```python
|
|
1114
|
+
from synapse_sdk.plugins.types import DataType
|
|
1115
|
+
|
|
1116
|
+
class CustomDataset(DataType):
|
|
1117
|
+
name = 'custom_dataset'
|
|
1118
|
+
format = 'custom'
|
|
1119
|
+
description = 'My custom dataset format'
|
|
1120
|
+
|
|
1121
|
+
class CustomModel(DataType):
|
|
1122
|
+
name = 'custom_model'
|
|
1123
|
+
format = 'custom'
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
### Pipeline Compatibility
|
|
1127
|
+
|
|
1128
|
+
Types enable automatic pipeline validation:
|
|
1129
|
+
|
|
1130
|
+
```python
|
|
1131
|
+
from synapse_sdk.plugins.pipelines import ActionPipeline
|
|
1132
|
+
|
|
1133
|
+
# This validates that:
|
|
1134
|
+
# - Action1.output_type is compatible with Action2.input_type
|
|
1135
|
+
# - etc.
|
|
1136
|
+
pipeline = ActionPipeline([Action1, Action2, Action3])
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
---
|
|
1140
|
+
|
|
1141
|
+
## Directory Structure
|
|
1142
|
+
|
|
1143
|
+
```
|
|
1144
|
+
synapse_sdk/plugins/
|
|
1145
|
+
├── __init__.py # Public API exports (136 items)
|
|
1146
|
+
├── action.py # BaseAction[P], NoResult, validate_result
|
|
1147
|
+
├── decorators.py # @action decorator
|
|
1148
|
+
├── config.py # PluginConfig, ActionConfig
|
|
1149
|
+
├── discovery.py # PluginDiscovery class
|
|
1150
|
+
├── runner.py # run_plugin() entry point
|
|
1151
|
+
├── types.py # DataType hierarchy
|
|
1152
|
+
├── enums.py # PluginCategory, RunMethod, etc.
|
|
1153
|
+
├── errors.py # Exception hierarchy
|
|
1154
|
+
├── utils.py # Utility functions
|
|
1155
|
+
│
|
|
1156
|
+
├── context/
|
|
1157
|
+
│ ├── __init__.py # RuntimeContext
|
|
1158
|
+
│ └── env.py # PluginEnvironment
|
|
1159
|
+
│
|
|
1160
|
+
├── steps/
|
|
1161
|
+
│ ├── __init__.py # Step exports
|
|
1162
|
+
│ ├── base.py # BaseStep[C], StepResult
|
|
1163
|
+
│ ├── context.py # BaseStepContext
|
|
1164
|
+
│ ├── registry.py # StepRegistry[C]
|
|
1165
|
+
│ ├── orchestrator.py # Orchestrator[C]
|
|
1166
|
+
│ └── utils/
|
|
1167
|
+
│ ├── __init__.py
|
|
1168
|
+
│ ├── logging.py # LoggingStep
|
|
1169
|
+
│ ├── timing.py # TimingStep
|
|
1170
|
+
│ └── validation.py # ValidationStep
|
|
1171
|
+
│
|
|
1172
|
+
├── actions/
|
|
1173
|
+
│ ├── __init__.py # Action exports
|
|
1174
|
+
│ ├── train/ # BaseTrainAction, TrainContext
|
|
1175
|
+
│ ├── export/ # BaseExportAction, ExportContext
|
|
1176
|
+
│ ├── upload/ # BaseUploadAction, UploadContext
|
|
1177
|
+
│ ├── inference/ # BaseInferenceAction, BaseDeploymentAction
|
|
1178
|
+
│ └── dataset/ # DatasetAction
|
|
1179
|
+
│
|
|
1180
|
+
├── executors/
|
|
1181
|
+
│ ├── __init__.py # ExecutorProtocol, LocalExecutor
|
|
1182
|
+
│ ├── local.py # LocalExecutor
|
|
1183
|
+
│ └── ray/
|
|
1184
|
+
│ ├── __init__.py # Ray executor exports
|
|
1185
|
+
│ ├── base.py # BaseRayExecutor
|
|
1186
|
+
│ ├── task.py # RayTaskExecutor, RayActorExecutor
|
|
1187
|
+
│ ├── job.py # RayJobExecutor
|
|
1188
|
+
│ ├── pipeline.py # RayPipelineExecutor
|
|
1189
|
+
│ └── packaging.py # Dependency packaging
|
|
1190
|
+
│
|
|
1191
|
+
├── pipelines/
|
|
1192
|
+
│ ├── __init__.py # Pipeline exports
|
|
1193
|
+
│ ├── action_pipeline.py # ActionPipeline
|
|
1194
|
+
│ ├── context.py # PipelineContext
|
|
1195
|
+
│ ├── display.py # Progress display utilities
|
|
1196
|
+
│ └── (see docs/PIPELINE_GUIDE.md)
|
|
1197
|
+
│
|
|
1198
|
+
├── models/
|
|
1199
|
+
│ ├── logger.py # LogLevel, ActionProgress, PipelineProgress
|
|
1200
|
+
│ └── pipeline.py # RunStatus, ActionStatus
|
|
1201
|
+
│
|
|
1202
|
+
├── schemas/
|
|
1203
|
+
│ └── results.py # WeightsResult, TrainResult, etc.
|
|
1204
|
+
│
|
|
1205
|
+
├── datasets/
|
|
1206
|
+
│ ├── formats/ # Format definitions (DM, YOLO)
|
|
1207
|
+
│ └── converters/ # Format converters
|
|
1208
|
+
│
|
|
1209
|
+
├── templates/ # Plugin generation templates
|
|
1210
|
+
│ └── base/ # Base plugin templates
|
|
1211
|
+
│
|
|
1212
|
+
└── testing/
|
|
1213
|
+
└── sample_actions.py # Test fixtures
|
|
1214
|
+
```
|
|
1215
|
+
|
|
1216
|
+
---
|
|
1217
|
+
|
|
1218
|
+
## Next Steps
|
|
1219
|
+
|
|
1220
|
+
- **[OVERVIEW.md](OVERVIEW.md)**: Quick start and tutorials
|
|
1221
|
+
- **[ACTION_DEV_GUIDE.md](ACTION_DEV_GUIDE.md)**: Action development guide
|
|
1222
|
+
- **[STEP.md](STEP.md)**: Step implementations guide
|
|
1223
|
+
- **[LOGGING_SYSTEM.md](LOGGING_SYSTEM.md)**: Logging and progress tracking
|
|
1224
|
+
- **[README.md](README.md)**: Extension guide and best practices
|
|
1225
|
+
- **[PIPELINE_GUIDE.md](PIPELINE_GUIDE.md)**: Multi-action pipelines
|