synapse-sdk 1.0.0a11__py3-none-any.whl → 2026.1.1b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse-sdk might be problematic. Click here for more details.

Files changed (261) hide show
  1. synapse_sdk/__init__.py +24 -0
  2. synapse_sdk/cli/__init__.py +9 -8
  3. synapse_sdk/cli/agent/__init__.py +25 -0
  4. synapse_sdk/cli/agent/config.py +104 -0
  5. synapse_sdk/cli/agent/select.py +197 -0
  6. synapse_sdk/cli/auth.py +104 -0
  7. synapse_sdk/cli/main.py +1025 -0
  8. synapse_sdk/cli/plugin/__init__.py +58 -0
  9. synapse_sdk/cli/plugin/create.py +566 -0
  10. synapse_sdk/cli/plugin/job.py +196 -0
  11. synapse_sdk/cli/plugin/publish.py +322 -0
  12. synapse_sdk/cli/plugin/run.py +131 -0
  13. synapse_sdk/cli/plugin/test.py +200 -0
  14. synapse_sdk/clients/README.md +239 -0
  15. synapse_sdk/clients/__init__.py +5 -0
  16. synapse_sdk/clients/_template.py +266 -0
  17. synapse_sdk/clients/agent/__init__.py +84 -29
  18. synapse_sdk/clients/agent/async_ray.py +289 -0
  19. synapse_sdk/clients/agent/container.py +83 -0
  20. synapse_sdk/clients/agent/plugin.py +101 -0
  21. synapse_sdk/clients/agent/ray.py +296 -39
  22. synapse_sdk/clients/backend/__init__.py +152 -12
  23. synapse_sdk/clients/backend/annotation.py +164 -22
  24. synapse_sdk/clients/backend/core.py +101 -0
  25. synapse_sdk/clients/backend/data_collection.py +292 -0
  26. synapse_sdk/clients/backend/hitl.py +87 -0
  27. synapse_sdk/clients/backend/integration.py +374 -46
  28. synapse_sdk/clients/backend/ml.py +134 -22
  29. synapse_sdk/clients/backend/models.py +247 -0
  30. synapse_sdk/clients/base.py +538 -59
  31. synapse_sdk/clients/exceptions.py +35 -7
  32. synapse_sdk/clients/pipeline/__init__.py +5 -0
  33. synapse_sdk/clients/pipeline/client.py +636 -0
  34. synapse_sdk/clients/protocols.py +178 -0
  35. synapse_sdk/clients/utils.py +86 -8
  36. synapse_sdk/clients/validation.py +58 -0
  37. synapse_sdk/enums.py +76 -0
  38. synapse_sdk/exceptions.py +168 -0
  39. synapse_sdk/integrations/__init__.py +74 -0
  40. synapse_sdk/integrations/_base.py +119 -0
  41. synapse_sdk/integrations/_context.py +53 -0
  42. synapse_sdk/integrations/ultralytics/__init__.py +78 -0
  43. synapse_sdk/integrations/ultralytics/_callbacks.py +126 -0
  44. synapse_sdk/integrations/ultralytics/_patches.py +124 -0
  45. synapse_sdk/loggers.py +476 -95
  46. synapse_sdk/mcp/MCP.md +69 -0
  47. synapse_sdk/mcp/__init__.py +48 -0
  48. synapse_sdk/mcp/__main__.py +6 -0
  49. synapse_sdk/mcp/config.py +349 -0
  50. synapse_sdk/mcp/prompts/__init__.py +4 -0
  51. synapse_sdk/mcp/resources/__init__.py +4 -0
  52. synapse_sdk/mcp/server.py +1352 -0
  53. synapse_sdk/mcp/tools/__init__.py +6 -0
  54. synapse_sdk/plugins/__init__.py +133 -9
  55. synapse_sdk/plugins/action.py +229 -0
  56. synapse_sdk/plugins/actions/__init__.py +82 -0
  57. synapse_sdk/plugins/actions/dataset/__init__.py +37 -0
  58. synapse_sdk/plugins/actions/dataset/action.py +471 -0
  59. synapse_sdk/plugins/actions/export/__init__.py +55 -0
  60. synapse_sdk/plugins/actions/export/action.py +183 -0
  61. synapse_sdk/plugins/actions/export/context.py +59 -0
  62. synapse_sdk/plugins/actions/inference/__init__.py +84 -0
  63. synapse_sdk/plugins/actions/inference/action.py +285 -0
  64. synapse_sdk/plugins/actions/inference/context.py +81 -0
  65. synapse_sdk/plugins/actions/inference/deployment.py +322 -0
  66. synapse_sdk/plugins/actions/inference/serve.py +252 -0
  67. synapse_sdk/plugins/actions/train/__init__.py +54 -0
  68. synapse_sdk/plugins/actions/train/action.py +326 -0
  69. synapse_sdk/plugins/actions/train/context.py +57 -0
  70. synapse_sdk/plugins/actions/upload/__init__.py +49 -0
  71. synapse_sdk/plugins/actions/upload/action.py +165 -0
  72. synapse_sdk/plugins/actions/upload/context.py +61 -0
  73. synapse_sdk/plugins/config.py +98 -0
  74. synapse_sdk/plugins/context/__init__.py +109 -0
  75. synapse_sdk/plugins/context/env.py +113 -0
  76. synapse_sdk/plugins/datasets/__init__.py +113 -0
  77. synapse_sdk/plugins/datasets/converters/__init__.py +76 -0
  78. synapse_sdk/plugins/datasets/converters/base.py +347 -0
  79. synapse_sdk/plugins/datasets/converters/yolo/__init__.py +9 -0
  80. synapse_sdk/plugins/datasets/converters/yolo/from_dm.py +468 -0
  81. synapse_sdk/plugins/datasets/converters/yolo/to_dm.py +381 -0
  82. synapse_sdk/plugins/datasets/formats/__init__.py +82 -0
  83. synapse_sdk/plugins/datasets/formats/dm.py +351 -0
  84. synapse_sdk/plugins/datasets/formats/yolo.py +240 -0
  85. synapse_sdk/plugins/decorators.py +83 -0
  86. synapse_sdk/plugins/discovery.py +790 -0
  87. synapse_sdk/plugins/docs/ACTION_DEV_GUIDE.md +933 -0
  88. synapse_sdk/plugins/docs/ARCHITECTURE.md +1225 -0
  89. synapse_sdk/plugins/docs/LOGGING_SYSTEM.md +683 -0
  90. synapse_sdk/plugins/docs/OVERVIEW.md +531 -0
  91. synapse_sdk/plugins/docs/PIPELINE_GUIDE.md +145 -0
  92. synapse_sdk/plugins/docs/README.md +513 -0
  93. synapse_sdk/plugins/docs/STEP.md +656 -0
  94. synapse_sdk/plugins/enums.py +70 -10
  95. synapse_sdk/plugins/errors.py +92 -0
  96. synapse_sdk/plugins/executors/__init__.py +43 -0
  97. synapse_sdk/plugins/executors/local.py +99 -0
  98. synapse_sdk/plugins/executors/ray/__init__.py +18 -0
  99. synapse_sdk/plugins/executors/ray/base.py +282 -0
  100. synapse_sdk/plugins/executors/ray/job.py +298 -0
  101. synapse_sdk/plugins/executors/ray/jobs_api.py +511 -0
  102. synapse_sdk/plugins/executors/ray/packaging.py +137 -0
  103. synapse_sdk/plugins/executors/ray/pipeline.py +792 -0
  104. synapse_sdk/plugins/executors/ray/task.py +257 -0
  105. synapse_sdk/plugins/models/__init__.py +26 -0
  106. synapse_sdk/plugins/models/logger.py +173 -0
  107. synapse_sdk/plugins/models/pipeline.py +25 -0
  108. synapse_sdk/plugins/pipelines/__init__.py +81 -0
  109. synapse_sdk/plugins/pipelines/action_pipeline.py +417 -0
  110. synapse_sdk/plugins/pipelines/context.py +107 -0
  111. synapse_sdk/plugins/pipelines/display.py +311 -0
  112. synapse_sdk/plugins/runner.py +114 -0
  113. synapse_sdk/plugins/schemas/__init__.py +19 -0
  114. synapse_sdk/plugins/schemas/results.py +152 -0
  115. synapse_sdk/plugins/steps/__init__.py +63 -0
  116. synapse_sdk/plugins/steps/base.py +128 -0
  117. synapse_sdk/plugins/steps/context.py +90 -0
  118. synapse_sdk/plugins/steps/orchestrator.py +128 -0
  119. synapse_sdk/plugins/steps/registry.py +103 -0
  120. synapse_sdk/plugins/steps/utils/__init__.py +20 -0
  121. synapse_sdk/plugins/steps/utils/logging.py +85 -0
  122. synapse_sdk/plugins/steps/utils/timing.py +71 -0
  123. synapse_sdk/plugins/steps/utils/validation.py +68 -0
  124. synapse_sdk/plugins/templates/__init__.py +50 -0
  125. synapse_sdk/plugins/templates/base/.gitignore.j2 +26 -0
  126. synapse_sdk/plugins/templates/base/.synapseignore.j2 +11 -0
  127. synapse_sdk/plugins/templates/base/README.md.j2 +26 -0
  128. synapse_sdk/plugins/templates/base/plugin/__init__.py.j2 +1 -0
  129. synapse_sdk/plugins/templates/base/pyproject.toml.j2 +14 -0
  130. synapse_sdk/plugins/templates/base/requirements.txt.j2 +1 -0
  131. synapse_sdk/plugins/templates/custom/plugin/main.py.j2 +18 -0
  132. synapse_sdk/plugins/templates/data_validation/plugin/validate.py.j2 +32 -0
  133. synapse_sdk/plugins/templates/export/plugin/export.py.j2 +36 -0
  134. synapse_sdk/plugins/templates/neural_net/plugin/inference.py.j2 +36 -0
  135. synapse_sdk/plugins/templates/neural_net/plugin/train.py.j2 +33 -0
  136. synapse_sdk/plugins/templates/post_annotation/plugin/post_annotate.py.j2 +32 -0
  137. synapse_sdk/plugins/templates/pre_annotation/plugin/pre_annotate.py.j2 +32 -0
  138. synapse_sdk/plugins/templates/smart_tool/plugin/auto_label.py.j2 +44 -0
  139. synapse_sdk/plugins/templates/upload/plugin/upload.py.j2 +35 -0
  140. synapse_sdk/plugins/testing/__init__.py +25 -0
  141. synapse_sdk/plugins/testing/sample_actions.py +98 -0
  142. synapse_sdk/plugins/types.py +206 -0
  143. synapse_sdk/plugins/upload.py +595 -64
  144. synapse_sdk/plugins/utils.py +325 -37
  145. synapse_sdk/shared/__init__.py +25 -0
  146. synapse_sdk/utils/__init__.py +1 -0
  147. synapse_sdk/utils/auth.py +74 -0
  148. synapse_sdk/utils/file/__init__.py +58 -0
  149. synapse_sdk/utils/file/archive.py +449 -0
  150. synapse_sdk/utils/file/checksum.py +167 -0
  151. synapse_sdk/utils/file/download.py +286 -0
  152. synapse_sdk/utils/file/io.py +129 -0
  153. synapse_sdk/utils/file/requirements.py +36 -0
  154. synapse_sdk/utils/network.py +168 -0
  155. synapse_sdk/utils/storage/__init__.py +238 -0
  156. synapse_sdk/utils/storage/config.py +188 -0
  157. synapse_sdk/utils/storage/errors.py +52 -0
  158. synapse_sdk/utils/storage/providers/__init__.py +13 -0
  159. synapse_sdk/utils/storage/providers/base.py +76 -0
  160. synapse_sdk/utils/storage/providers/gcs.py +168 -0
  161. synapse_sdk/utils/storage/providers/http.py +250 -0
  162. synapse_sdk/utils/storage/providers/local.py +126 -0
  163. synapse_sdk/utils/storage/providers/s3.py +177 -0
  164. synapse_sdk/utils/storage/providers/sftp.py +208 -0
  165. synapse_sdk/utils/storage/registry.py +125 -0
  166. synapse_sdk/utils/websocket.py +99 -0
  167. synapse_sdk-2026.1.1b2.dist-info/METADATA +715 -0
  168. synapse_sdk-2026.1.1b2.dist-info/RECORD +172 -0
  169. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/WHEEL +1 -1
  170. synapse_sdk-2026.1.1b2.dist-info/licenses/LICENSE +201 -0
  171. locale/en/LC_MESSAGES/messages.mo +0 -0
  172. locale/en/LC_MESSAGES/messages.po +0 -39
  173. locale/ko/LC_MESSAGES/messages.mo +0 -0
  174. locale/ko/LC_MESSAGES/messages.po +0 -34
  175. synapse_sdk/cli/create_plugin.py +0 -10
  176. synapse_sdk/clients/agent/core.py +0 -7
  177. synapse_sdk/clients/agent/service.py +0 -15
  178. synapse_sdk/clients/backend/dataset.py +0 -51
  179. synapse_sdk/clients/ray/__init__.py +0 -6
  180. synapse_sdk/clients/ray/core.py +0 -22
  181. synapse_sdk/clients/ray/serve.py +0 -20
  182. synapse_sdk/i18n.py +0 -35
  183. synapse_sdk/plugins/categories/__init__.py +0 -0
  184. synapse_sdk/plugins/categories/base.py +0 -235
  185. synapse_sdk/plugins/categories/data_validation/__init__.py +0 -0
  186. synapse_sdk/plugins/categories/data_validation/actions/__init__.py +0 -0
  187. synapse_sdk/plugins/categories/data_validation/actions/validation.py +0 -10
  188. synapse_sdk/plugins/categories/data_validation/templates/config.yaml +0 -3
  189. synapse_sdk/plugins/categories/data_validation/templates/plugin/__init__.py +0 -0
  190. synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +0 -5
  191. synapse_sdk/plugins/categories/decorators.py +0 -13
  192. synapse_sdk/plugins/categories/export/__init__.py +0 -0
  193. synapse_sdk/plugins/categories/export/actions/__init__.py +0 -0
  194. synapse_sdk/plugins/categories/export/actions/export.py +0 -10
  195. synapse_sdk/plugins/categories/import/__init__.py +0 -0
  196. synapse_sdk/plugins/categories/import/actions/__init__.py +0 -0
  197. synapse_sdk/plugins/categories/import/actions/import.py +0 -10
  198. synapse_sdk/plugins/categories/neural_net/__init__.py +0 -0
  199. synapse_sdk/plugins/categories/neural_net/actions/__init__.py +0 -0
  200. synapse_sdk/plugins/categories/neural_net/actions/deployment.py +0 -45
  201. synapse_sdk/plugins/categories/neural_net/actions/inference.py +0 -18
  202. synapse_sdk/plugins/categories/neural_net/actions/test.py +0 -10
  203. synapse_sdk/plugins/categories/neural_net/actions/train.py +0 -143
  204. synapse_sdk/plugins/categories/neural_net/templates/config.yaml +0 -12
  205. synapse_sdk/plugins/categories/neural_net/templates/plugin/__init__.py +0 -0
  206. synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +0 -4
  207. synapse_sdk/plugins/categories/neural_net/templates/plugin/test.py +0 -2
  208. synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py +0 -14
  209. synapse_sdk/plugins/categories/post_annotation/__init__.py +0 -0
  210. synapse_sdk/plugins/categories/post_annotation/actions/__init__.py +0 -0
  211. synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py +0 -10
  212. synapse_sdk/plugins/categories/post_annotation/templates/config.yaml +0 -3
  213. synapse_sdk/plugins/categories/post_annotation/templates/plugin/__init__.py +0 -0
  214. synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.py +0 -3
  215. synapse_sdk/plugins/categories/pre_annotation/__init__.py +0 -0
  216. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +0 -0
  217. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py +0 -10
  218. synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +0 -3
  219. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py +0 -0
  220. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py +0 -3
  221. synapse_sdk/plugins/categories/registry.py +0 -16
  222. synapse_sdk/plugins/categories/smart_tool/__init__.py +0 -0
  223. synapse_sdk/plugins/categories/smart_tool/actions/__init__.py +0 -0
  224. synapse_sdk/plugins/categories/smart_tool/actions/auto_label.py +0 -37
  225. synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +0 -7
  226. synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py +0 -0
  227. synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py +0 -11
  228. synapse_sdk/plugins/categories/templates.py +0 -32
  229. synapse_sdk/plugins/cli/__init__.py +0 -21
  230. synapse_sdk/plugins/cli/publish.py +0 -37
  231. synapse_sdk/plugins/cli/run.py +0 -67
  232. synapse_sdk/plugins/exceptions.py +0 -22
  233. synapse_sdk/plugins/models.py +0 -121
  234. synapse_sdk/plugins/templates/cookiecutter.json +0 -11
  235. synapse_sdk/plugins/templates/hooks/post_gen_project.py +0 -3
  236. synapse_sdk/plugins/templates/hooks/pre_prompt.py +0 -21
  237. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
  238. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
  239. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.gitignore +0 -27
  240. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.pre-commit-config.yaml +0 -7
  241. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/README.md +0 -5
  242. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +0 -6
  243. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
  244. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/plugin/__init__.py +0 -0
  245. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml +0 -13
  246. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +0 -1
  247. synapse_sdk/shared/enums.py +0 -8
  248. synapse_sdk/utils/debug.py +0 -5
  249. synapse_sdk/utils/file.py +0 -87
  250. synapse_sdk/utils/module_loading.py +0 -29
  251. synapse_sdk/utils/pydantic/__init__.py +0 -0
  252. synapse_sdk/utils/pydantic/config.py +0 -4
  253. synapse_sdk/utils/pydantic/errors.py +0 -33
  254. synapse_sdk/utils/pydantic/validators.py +0 -7
  255. synapse_sdk/utils/storage.py +0 -91
  256. synapse_sdk/utils/string.py +0 -11
  257. synapse_sdk-1.0.0a11.dist-info/LICENSE +0 -21
  258. synapse_sdk-1.0.0a11.dist-info/METADATA +0 -43
  259. synapse_sdk-1.0.0a11.dist-info/RECORD +0 -111
  260. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/entry_points.txt +0 -0
  261. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,119 @@
1
+ """Base integration infrastructure for autolog."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abc import ABC, abstractmethod
6
+ from typing import TYPE_CHECKING, Callable
7
+
8
+ if TYPE_CHECKING:
9
+ from synapse_sdk.plugins.action import BaseAction
10
+
11
+
12
+ class BaseIntegration(ABC):
13
+ """Base class for framework integrations.
14
+
15
+ Subclasses implement framework-specific autologging by patching
16
+ the framework's training methods to automatically log metrics,
17
+ progress, and artifacts.
18
+
19
+ Example:
20
+ >>> @register_integration('my_framework')
21
+ ... class MyFrameworkIntegration(BaseIntegration):
22
+ ... name = 'my_framework'
23
+ ...
24
+ ... def enable(self, action):
25
+ ... # Patch framework methods
26
+ ... ...
27
+ ...
28
+ ... def disable(self):
29
+ ... # Restore original methods
30
+ ... ...
31
+ ...
32
+ ... def is_available(self):
33
+ ... try:
34
+ ... import my_framework
35
+ ... return True
36
+ ... except ImportError:
37
+ ... return False
38
+ """
39
+
40
+ name: str
41
+
42
+ @abstractmethod
43
+ def enable(self, action: BaseAction) -> None:
44
+ """Enable autologging for this framework.
45
+
46
+ Args:
47
+ action: The current action instance to log to.
48
+ """
49
+ ...
50
+
51
+ @abstractmethod
52
+ def disable(self) -> None:
53
+ """Disable autologging and restore original behavior."""
54
+ ...
55
+
56
+ @abstractmethod
57
+ def is_available(self) -> bool:
58
+ """Check if the framework is installed.
59
+
60
+ Returns:
61
+ True if framework is available, False otherwise.
62
+ """
63
+ ...
64
+
65
+
66
+ # Registry of available integrations
67
+ _integrations: dict[str, type[BaseIntegration]] = {}
68
+
69
+
70
+ def register_integration(name: str) -> Callable[[type[BaseIntegration]], type[BaseIntegration]]:
71
+ """Decorator to register an integration.
72
+
73
+ Args:
74
+ name: Integration name (e.g., 'ultralytics').
75
+
76
+ Returns:
77
+ Decorator function.
78
+
79
+ Example:
80
+ >>> @register_integration('ultralytics')
81
+ ... class UltralyticsIntegration(BaseIntegration):
82
+ ... ...
83
+ """
84
+
85
+ def decorator(cls: type[BaseIntegration]) -> type[BaseIntegration]:
86
+ _integrations[name] = cls
87
+ return cls
88
+
89
+ return decorator
90
+
91
+
92
+ def get_integration(name: str) -> BaseIntegration:
93
+ """Get integration instance by name.
94
+
95
+ Args:
96
+ name: Integration name (e.g., 'ultralytics').
97
+
98
+ Returns:
99
+ BaseIntegration instance.
100
+
101
+ Raises:
102
+ ValueError: If integration is not registered.
103
+ """
104
+ if name not in _integrations:
105
+ available = list(_integrations.keys()) or ['none']
106
+ raise ValueError(f"Unknown integration: '{name}'. Available: {available}")
107
+ return _integrations[name]()
108
+
109
+
110
+ def list_integrations() -> list[str]:
111
+ """List all registered integration names.
112
+
113
+ Returns:
114
+ List of integration names.
115
+ """
116
+ return list(_integrations.keys())
117
+
118
+
119
+ __all__ = ['BaseIntegration', 'register_integration', 'get_integration', 'list_integrations']
@@ -0,0 +1,53 @@
1
+ """Context management for autolog integrations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from contextvars import ContextVar
6
+ from dataclasses import dataclass, field
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ if TYPE_CHECKING:
10
+ from synapse_sdk.plugins.action import BaseAction
11
+
12
+
13
+ @dataclass
14
+ class AutologContext:
15
+ """Holds action context for autolog callbacks.
16
+
17
+ Attributes:
18
+ action: The current BaseAction instance.
19
+ total_epochs: Total epochs (auto-detected from train() kwargs).
20
+ extra: Additional framework-specific data.
21
+ """
22
+
23
+ action: BaseAction[Any]
24
+ total_epochs: int | None = None
25
+ extra: dict[str, Any] = field(default_factory=dict)
26
+
27
+
28
+ # Thread/async safe context storage
29
+ _autolog_context: ContextVar[AutologContext | None] = ContextVar(
30
+ 'synapse_autolog_context',
31
+ default=None,
32
+ )
33
+
34
+
35
+ def get_autolog_context() -> AutologContext | None:
36
+ """Get current autolog context.
37
+
38
+ Returns:
39
+ AutologContext if autolog is active, None otherwise.
40
+ """
41
+ return _autolog_context.get()
42
+
43
+
44
+ def set_autolog_context(ctx: AutologContext | None) -> None:
45
+ """Set autolog context.
46
+
47
+ Args:
48
+ ctx: AutologContext to set, or None to clear.
49
+ """
50
+ _autolog_context.set(ctx)
51
+
52
+
53
+ __all__ = ['AutologContext', 'get_autolog_context', 'set_autolog_context']
@@ -0,0 +1,78 @@
1
+ """Ultralytics YOLO autolog integration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from synapse_sdk.integrations._base import BaseIntegration, register_integration
8
+ from synapse_sdk.integrations._context import AutologContext, set_autolog_context
9
+
10
+ if TYPE_CHECKING:
11
+ from synapse_sdk.plugins.action import BaseAction
12
+
13
+
14
+ @register_integration('ultralytics')
15
+ class UltralyticsIntegration(BaseIntegration):
16
+ """Ultralytics YOLO autologging integration.
17
+
18
+ Automatically logs training progress, metrics, and artifacts
19
+ when using Ultralytics YOLO models.
20
+
21
+ Logged metrics:
22
+ - train: box_loss, cls_loss, dfl_loss (per epoch)
23
+ - validation: mAP50, mAP50_95 (per epoch)
24
+
25
+ Logged artifacts:
26
+ - validation_samples: Validation batch prediction images
27
+ - model_weights: best.pt weights file
28
+ - training_results: results.csv file
29
+
30
+ Example:
31
+ >>> class TrainAction(BaseTrainAction[TrainParams]):
32
+ ... def execute(self):
33
+ ... self.autolog('ultralytics')
34
+ ... model = YOLO('yolov8n.pt')
35
+ ... model.train(data='coco.yaml', epochs=100)
36
+ """
37
+
38
+ name = 'ultralytics'
39
+
40
+ def is_available(self) -> bool:
41
+ """Check if ultralytics is installed."""
42
+ try:
43
+ import ultralytics # noqa: F401
44
+
45
+ return True
46
+ except ImportError:
47
+ return False
48
+
49
+ def enable(self, action: BaseAction) -> None:
50
+ """Enable autologging for Ultralytics.
51
+
52
+ Args:
53
+ action: The action instance to log to.
54
+
55
+ Raises:
56
+ ImportError: If ultralytics is not installed.
57
+ """
58
+ if not self.is_available():
59
+ raise ImportError('ultralytics is not installed. Install with: pip install ultralytics')
60
+
61
+ # Set context for callbacks
62
+ set_autolog_context(AutologContext(action=action))
63
+
64
+ # Apply patches (idempotent)
65
+ from synapse_sdk.integrations.ultralytics._patches import patch_yolo
66
+
67
+ patch_yolo()
68
+
69
+ def disable(self) -> None:
70
+ """Disable autologging for Ultralytics.
71
+
72
+ Clears the context but keeps patches in place for efficiency.
73
+ Callbacks check context before logging.
74
+ """
75
+ set_autolog_context(None)
76
+
77
+
78
+ __all__ = ['UltralyticsIntegration']
@@ -0,0 +1,126 @@
1
+ """Ultralytics YOLO callback implementations for autolog."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from synapse_sdk.integrations._context import get_autolog_context
9
+
10
+
11
+ def on_train_epoch_end(trainer: Any) -> None:
12
+ """Log training metrics at end of each epoch.
13
+
14
+ Logs:
15
+ - Progress: epoch/total_epochs
16
+ - Metrics: box_loss, cls_loss, dfl_loss (category='train')
17
+
18
+ Args:
19
+ trainer: Ultralytics trainer instance.
20
+ """
21
+ ctx = get_autolog_context()
22
+ if ctx is None:
23
+ return
24
+
25
+ action = ctx.action
26
+ epoch = trainer.epoch + 1
27
+ total_epochs = ctx.total_epochs or getattr(trainer, 'epochs', 100)
28
+
29
+ # Update progress
30
+ action.set_progress(epoch, total_epochs, 'train')
31
+
32
+ # Log loss metrics
33
+ if hasattr(trainer, 'loss_items') and trainer.loss_items is not None:
34
+ loss_items = trainer.loss_items
35
+ if hasattr(loss_items, 'cpu'):
36
+ loss_items = loss_items.cpu().numpy()
37
+
38
+ action.set_metrics(
39
+ {
40
+ 'epoch': epoch,
41
+ 'box_loss': float(loss_items[0]),
42
+ 'cls_loss': float(loss_items[1]),
43
+ 'dfl_loss': float(loss_items[2]),
44
+ },
45
+ category='train',
46
+ )
47
+
48
+
49
+ def on_fit_epoch_end(trainer: Any) -> None:
50
+ """Log validation metrics after validation pass.
51
+
52
+ Logs:
53
+ - Metrics: mAP50, mAP50_95 (category='validation')
54
+ - Files: validation batch prediction images
55
+
56
+ Args:
57
+ trainer: Ultralytics trainer instance.
58
+ """
59
+ ctx = get_autolog_context()
60
+ if ctx is None:
61
+ return
62
+
63
+ action = ctx.action
64
+ epoch = trainer.epoch + 1
65
+ metrics = trainer.metrics
66
+
67
+ if metrics:
68
+ action.set_metrics(
69
+ {
70
+ 'epoch': epoch,
71
+ 'mAP50': metrics.get('metrics/mAP50(B)', 0),
72
+ 'mAP50_95': metrics.get('metrics/mAP50-95(B)', 0),
73
+ },
74
+ category='validation',
75
+ )
76
+
77
+ # Log validation sample images
78
+ save_dir = Path(trainer.save_dir)
79
+ for i in range(3):
80
+ img_path = save_dir / f'val_batch{i}_pred.jpg'
81
+ if img_path.exists():
82
+ action.log(
83
+ 'validation_samples',
84
+ {'group': epoch, 'index': i},
85
+ file=str(img_path),
86
+ )
87
+
88
+ # Ray Tune integration
89
+ is_tune = action.ctx.env.get_bool('IS_TUNE', default=False)
90
+ if is_tune and metrics:
91
+ try:
92
+ from ray import tune
93
+
94
+ tune.report(**metrics)
95
+ except ImportError:
96
+ pass
97
+
98
+
99
+ def on_train_end(trainer: Any) -> None:
100
+ """Log final artifacts when training completes.
101
+
102
+ Logs:
103
+ - Files: best.pt weights, results.csv
104
+
105
+ Args:
106
+ trainer: Ultralytics trainer instance.
107
+ """
108
+ ctx = get_autolog_context()
109
+ if ctx is None:
110
+ return
111
+
112
+ action = ctx.action
113
+ save_dir = Path(trainer.save_dir)
114
+
115
+ # Log final model weights
116
+ best_pt = save_dir / 'weights' / 'best.pt'
117
+ if best_pt.exists():
118
+ action.log('model_weights', {'type': 'best'}, file=str(best_pt))
119
+
120
+ # Log training results CSV
121
+ results_csv = save_dir / 'results.csv'
122
+ if results_csv.exists():
123
+ action.log('training_results', {}, file=str(results_csv))
124
+
125
+
126
+ __all__ = ['on_train_epoch_end', 'on_fit_epoch_end', 'on_train_end']
@@ -0,0 +1,124 @@
1
+ """Monkey patches for Ultralytics YOLO autolog."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ from typing import Any
7
+
8
+ from synapse_sdk.integrations._context import get_autolog_context
9
+ from synapse_sdk.integrations.ultralytics._callbacks import (
10
+ on_fit_epoch_end,
11
+ on_train_end,
12
+ on_train_epoch_end,
13
+ )
14
+
15
+ # Store original methods to avoid re-patching
16
+ _original_yolo_init: Any = None
17
+ _original_yolo_train: Any = None
18
+ _patched = False
19
+
20
+
21
+ def patch_yolo() -> None:
22
+ """Apply all YOLO patches.
23
+
24
+ Patches:
25
+ - YOLO.__init__: Auto-attach callbacks when model is created
26
+ - YOLO.train: Capture epochs from kwargs
27
+
28
+ This function is idempotent - calling it multiple times has no effect.
29
+ """
30
+ global _patched
31
+ if _patched:
32
+ return
33
+
34
+ _patch_yolo_init()
35
+ _patch_yolo_train()
36
+ _patched = True
37
+
38
+
39
+ def _patch_yolo_init() -> None:
40
+ """Patch YOLO.__init__ to auto-attach callbacks."""
41
+ global _original_yolo_init
42
+
43
+ from ultralytics import YOLO
44
+
45
+ if _original_yolo_init is not None:
46
+ return # Already patched
47
+
48
+ _original_yolo_init = YOLO.__init__
49
+
50
+ @functools.wraps(_original_yolo_init)
51
+ def patched_init(self: Any, *args: Any, **kwargs: Any) -> None:
52
+ result = _original_yolo_init(self, *args, **kwargs)
53
+
54
+ # Check if autolog is active
55
+ ctx = get_autolog_context()
56
+ if ctx is not None:
57
+ # Attach Synapse callbacks
58
+ self.add_callback('on_train_epoch_end', on_train_epoch_end)
59
+ self.add_callback('on_fit_epoch_end', on_fit_epoch_end)
60
+ self.add_callback('on_train_end', on_train_end)
61
+
62
+ return result
63
+
64
+ YOLO.__init__ = patched_init
65
+
66
+
67
+ def _patch_yolo_train() -> None:
68
+ """Patch YOLO.train to capture epochs from kwargs."""
69
+ global _original_yolo_train
70
+
71
+ from ultralytics import YOLO
72
+
73
+ if _original_yolo_train is not None:
74
+ return # Already patched
75
+
76
+ _original_yolo_train = YOLO.train
77
+
78
+ @functools.wraps(_original_yolo_train)
79
+ def patched_train(self: Any, *args: Any, **kwargs: Any) -> Any:
80
+ ctx = get_autolog_context()
81
+ if ctx is not None:
82
+ # Auto-detect epochs from train() kwargs
83
+ epochs = kwargs.get('epochs')
84
+ if epochs is None:
85
+ # Check data config for epochs
86
+ data = kwargs.get('data')
87
+ if isinstance(data, dict):
88
+ epochs = data.get('epochs')
89
+
90
+ # Fall back to ultralytics default
91
+ if epochs is None:
92
+ epochs = 100
93
+
94
+ ctx.total_epochs = epochs
95
+
96
+ return _original_yolo_train(self, *args, **kwargs)
97
+
98
+ YOLO.train = patched_train
99
+
100
+
101
+ def unpatch_yolo() -> None:
102
+ """Restore original YOLO methods.
103
+
104
+ Used for testing or cleanup.
105
+ """
106
+ global _original_yolo_init, _original_yolo_train, _patched
107
+
108
+ if not _patched:
109
+ return
110
+
111
+ from ultralytics import YOLO
112
+
113
+ if _original_yolo_init is not None:
114
+ YOLO.__init__ = _original_yolo_init
115
+ _original_yolo_init = None
116
+
117
+ if _original_yolo_train is not None:
118
+ YOLO.train = _original_yolo_train
119
+ _original_yolo_train = None
120
+
121
+ _patched = False
122
+
123
+
124
+ __all__ = ['patch_yolo', 'unpatch_yolo']