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
@@ -1,63 +1,391 @@
1
- from synapse_sdk.clients.base import BaseClient
1
+ """Integration client mixin for plugin, job, and storage operations."""
2
2
 
3
+ from __future__ import annotations
3
4
 
4
- class IntegrationClientMixin(BaseClient):
5
- def health_check_agent(self, token):
6
- path = f'agents/{token}/connect/'
7
- return self._post(path)
5
+ from collections.abc import Generator
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING, Any
8
8
 
9
- def get_plugin(self, pk):
10
- path = f'plugins/{pk}/'
11
- return self._get(path)
9
+ from synapse_sdk.clients.backend.models import (
10
+ Agent,
11
+ PluginReleaseCreateRequest,
12
+ PluginRunRequest,
13
+ ServeApplicationCreateRequest,
14
+ Storage,
15
+ UpdateJobRequest,
16
+ )
17
+ from synapse_sdk.utils.file.io import convert_file_to_base64
12
18
 
13
- def create_plugin(self, data):
14
- path = 'plugins/'
15
- return self._post(path, data=data)
19
+ if TYPE_CHECKING:
20
+ from synapse_sdk.clients.protocols import ClientProtocol
16
21
 
17
- def update_plugin(self, pk, data):
18
- path = f'plugins/{pk}/'
19
- return self._put(path, data=data)
20
22
 
21
- def run_plugin(self, pk, data):
22
- path = f'plugins/{pk}/run/'
23
- return self._post(path, data=data)
23
+ class IntegrationClientMixin:
24
+ """Mixin for integration-related API endpoints.
24
25
 
25
- def get_plugin_release(self, pk, params=None):
26
- path = f'plugin_releases/{pk}/'
27
- return self._get(path, params=params)
26
+ Provides methods for managing plugins, jobs, logs, and serve applications.
27
+ """
28
28
 
29
- def create_plugin_release(self, data):
30
- path = 'plugin_releases/'
31
- files = {'file': data.pop('file')}
32
- return self._post(path, data=data, files=files)
29
+ # -------------------------------------------------------------------------
30
+ # Agent Operations
31
+ # -------------------------------------------------------------------------
33
32
 
34
- def get_job(self, pk, params=None):
35
- path = f'jobs/{pk}/'
36
- return self._get(path, params=params)
33
+ def list_agents(
34
+ self: ClientProtocol,
35
+ params: dict[str, Any] | None = None,
36
+ ) -> list[Agent]:
37
+ """List available agents.
37
38
 
38
- def list_jobs(self, params=None):
39
- path = 'jobs/'
40
- return self._get(path, params=params)
39
+ Args:
40
+ params: Optional query parameters for filtering.
41
41
 
42
- def update_job(self, pk, data):
43
- path = f'jobs/{pk}/'
44
- return self._patch(path, data=data)
42
+ Returns:
43
+ List of Agent objects.
44
+ """
45
+ response = self._get('agents/', params=params)
46
+ results = response.get('results', [])
47
+ agents = []
48
+ for item in results:
49
+ agent = Agent.model_validate(item)
50
+ # Extract token from node_install_script if not set
51
+ if not agent.token:
52
+ agent.token = agent.extract_token()
53
+ agents.append(agent)
54
+ return agents
45
55
 
46
- def list_job_console_logs(self, pk):
47
- path = f'jobs/{pk}/console_logs/'
48
- return self._get(path)
56
+ def health_check_agent(self: ClientProtocol, agent_token: str) -> dict[str, Any]:
57
+ """Check agent health and connectivity.
49
58
 
50
- def tail_job_console_logs(self, pk):
51
- path = f'jobs/{pk}/tail_console_logs/'
59
+ Args:
60
+ agent_token: Agent authentication token.
52
61
 
53
- url = self._get_url(path)
62
+ Returns:
63
+ Agent health status and metadata.
64
+ """
65
+ return self._post(f'agents/{agent_token}/connect/')
66
+
67
+ # -------------------------------------------------------------------------
68
+ # Plugin Operations
69
+ # -------------------------------------------------------------------------
70
+
71
+ def get_plugin(self: ClientProtocol, plugin_id: int) -> dict[str, Any]:
72
+ """Get plugin details by ID.
73
+
74
+ Args:
75
+ plugin_id: Plugin ID.
76
+
77
+ Returns:
78
+ Plugin data including configuration and releases.
79
+ """
80
+ return self._get(f'plugins/{plugin_id}/')
81
+
82
+ def create_plugin(self: ClientProtocol, data: dict[str, Any]) -> dict[str, Any]:
83
+ """Create a new plugin.
84
+
85
+ Args:
86
+ data: Plugin creation data (name, category, etc.).
87
+
88
+ Returns:
89
+ Created plugin data.
90
+ """
91
+ return self._post('plugins/', data=data)
92
+
93
+ def update_plugin(
94
+ self: ClientProtocol,
95
+ plugin_id: int,
96
+ data: dict[str, Any],
97
+ ) -> dict[str, Any]:
98
+ """Update an existing plugin.
99
+
100
+ Args:
101
+ plugin_id: Plugin ID to update.
102
+ data: Fields to update.
103
+
104
+ Returns:
105
+ Updated plugin data.
106
+ """
107
+ return self._put(f'plugins/{plugin_id}/', data=data)
108
+
109
+ def run_plugin(
110
+ self: ClientProtocol,
111
+ plugin: int | str,
112
+ data: dict[str, Any],
113
+ ) -> dict[str, Any]:
114
+ """Run a plugin action.
115
+
116
+ Args:
117
+ plugin: Plugin ID or code.
118
+ data: Run parameters including action, agent, and params.
119
+
120
+ Returns:
121
+ Job data or direct result.
122
+
123
+ Example:
124
+ >>> client.run_plugin('yolov8', {
125
+ ... 'agent': 1,
126
+ ... 'action': 'deployment',
127
+ ... 'params': {'num_cpus': 8},
128
+ ... })
129
+ """
130
+ return self._post(
131
+ f'plugins/{plugin}/run/',
132
+ request_model=PluginRunRequest,
133
+ data=data,
134
+ )
135
+
136
+ # -------------------------------------------------------------------------
137
+ # Plugin Release Operations
138
+ # -------------------------------------------------------------------------
139
+
140
+ def get_plugin_release(
141
+ self: ClientProtocol,
142
+ release_id: int,
143
+ *,
144
+ params: dict[str, Any] | None = None,
145
+ ) -> dict[str, Any]:
146
+ """Get plugin release details by ID.
147
+
148
+ Args:
149
+ release_id: Plugin release ID.
150
+ params: Optional query parameters.
151
+
152
+ Returns:
153
+ Plugin release data including config and requirements.
154
+ """
155
+ return self._get(f'plugin_releases/{release_id}/', params=params)
156
+
157
+ def create_plugin_release(
158
+ self: ClientProtocol,
159
+ data: dict[str, Any],
160
+ *,
161
+ file: str | Path | None = None,
162
+ ) -> dict[str, Any]:
163
+ """Create a new plugin release.
164
+
165
+ Args:
166
+ data: Release data (plugin, version, config, requirements).
167
+ file: Optional plugin archive file to upload.
168
+
169
+ Returns:
170
+ Created plugin release data.
171
+
172
+ Example:
173
+ >>> client.create_plugin_release(
174
+ ... {'plugin': 123, 'version': '1.0.0'},
175
+ ... file='/path/to/plugin.zip'
176
+ ... )
177
+ """
178
+ files = None
179
+ if file is not None:
180
+ files = {'file': file}
181
+
182
+ return self._post(
183
+ 'plugin_releases/',
184
+ request_model=PluginReleaseCreateRequest,
185
+ data=data,
186
+ files=files,
187
+ )
188
+
189
+ # -------------------------------------------------------------------------
190
+ # Job Operations
191
+ # -------------------------------------------------------------------------
192
+
193
+ def get_job(
194
+ self: ClientProtocol,
195
+ job_id: int | str,
196
+ *,
197
+ params: dict[str, Any] | None = None,
198
+ ) -> dict[str, Any]:
199
+ """Get job details by ID.
200
+
201
+ Args:
202
+ job_id: Job ID (integer or UUID string).
203
+ params: Optional query parameters.
204
+
205
+ Returns:
206
+ Job data including status and progress.
207
+ """
208
+ return self._get(f'jobs/{job_id}/', params=params)
209
+
210
+ def list_jobs(
211
+ self: ClientProtocol,
212
+ params: dict[str, Any] | None = None,
213
+ ) -> dict[str, Any]:
214
+ """List jobs with optional filtering.
215
+
216
+ Args:
217
+ params: Query parameters (status, plugin, etc.).
218
+
219
+ Returns:
220
+ Paginated job list.
221
+ """
222
+ return self._get('jobs/', params=params)
223
+
224
+ def update_job(
225
+ self: ClientProtocol,
226
+ job_id: int,
227
+ data: dict[str, Any],
228
+ ) -> dict[str, Any]:
229
+ """Update job status and data.
230
+
231
+ Args:
232
+ job_id: Job ID to update.
233
+ data: Update payload (status, progress_record, metrics_record, etc.).
234
+
235
+ Returns:
236
+ Updated job data.
237
+
238
+ Example:
239
+ >>> client.update_job(123, {
240
+ ... 'status': 'running',
241
+ ... 'progress_record': {'step': 5, 'total': 100}
242
+ ... })
243
+ """
244
+ return self._patch(
245
+ f'jobs/{job_id}/',
246
+ request_model=UpdateJobRequest,
247
+ data=data,
248
+ )
249
+
250
+ def list_job_console_logs(self: ClientProtocol, job_id: int) -> dict[str, Any]:
251
+ """Get console logs for a job.
252
+
253
+ Args:
254
+ job_id: Job ID.
255
+
256
+ Returns:
257
+ Console log entries.
258
+ """
259
+ return self._get(f'jobs/{job_id}/console_logs/')
260
+
261
+ def tail_job_console_logs(
262
+ self: ClientProtocol,
263
+ job_id: int | str,
264
+ ) -> Generator[str, None, None]:
265
+ """Stream console logs for a running job.
266
+
267
+ Yields log lines as they become available.
268
+
269
+ Args:
270
+ job_id: Job ID (integer or UUID string) to tail.
271
+
272
+ Yields:
273
+ Log lines as strings.
274
+
275
+ Example:
276
+ >>> for line in client.tail_job_console_logs('abc-123'):
277
+ ... print(line)
278
+ """
279
+ # Use async endpoint for streaming
280
+ # The async endpoint is at /async/jobs/{id}/tail_console_logs/
281
+ base = self.base_url.rstrip('/')
282
+ url = f'{base}/async/jobs/{job_id}/tail_console_logs/'
54
283
  headers = self._get_headers()
55
284
 
56
- response = self.requests_session.get(url, headers=headers, stream=True)
57
- for line in response.iter_lines(decode_unicode=True):
58
- if line:
59
- yield f'{line}\n'
285
+ response = self.requests_session.get(
286
+ url,
287
+ headers=headers,
288
+ stream=True,
289
+ timeout=(self.timeout['connect'], None), # No read timeout for streaming
290
+ )
291
+ response.raise_for_status()
292
+
293
+ yield from response.iter_lines(decode_unicode=True)
294
+
295
+ # -------------------------------------------------------------------------
296
+ # Log Operations
297
+ # -------------------------------------------------------------------------
298
+
299
+ def create_logs(
300
+ self: ClientProtocol,
301
+ data: dict[str, Any] | list[dict[str, Any]],
302
+ ) -> dict[str, Any]:
303
+ """Create log entries with optional file attachments.
304
+
305
+ File fields are automatically converted to base64 data URIs.
306
+
307
+ Args:
308
+ data: Single log entry or list of entries.
309
+
310
+ Returns:
311
+ Created log entries response.
312
+
313
+ Example:
314
+ >>> client.create_logs({
315
+ ... 'message': 'Training complete',
316
+ ... 'level': 'info',
317
+ ... 'file': '/path/to/result.png' # Auto-converted to base64
318
+ ... })
319
+ """
320
+ # Normalize to list
321
+ items = data if isinstance(data, list) else [data]
322
+
323
+ # Convert file fields to base64
324
+ for item in items:
325
+ if 'file' in item and item['file']:
326
+ file_path = item['file']
327
+ if not isinstance(file_path, str) or not file_path.startswith('data:'):
328
+ item['file'] = convert_file_to_base64(file_path)
329
+
330
+ return self._post('logs/', data=items if len(items) > 1 else items[0])
331
+
332
+ # -------------------------------------------------------------------------
333
+ # Serve Application Operations
334
+ # -------------------------------------------------------------------------
335
+
336
+ def create_serve_application(
337
+ self: ClientProtocol,
338
+ data: dict[str, Any],
339
+ ) -> dict[str, Any]:
340
+ """Create a Ray Serve application.
341
+
342
+ Args:
343
+ data: Application config (name, plugin_release, action, params).
344
+
345
+ Returns:
346
+ Created serve application data.
347
+ """
348
+ return self._post(
349
+ 'serve_applications/',
350
+ request_model=ServeApplicationCreateRequest,
351
+ data=data,
352
+ )
353
+
354
+ def list_serve_applications(
355
+ self: ClientProtocol,
356
+ params: dict[str, Any] | None = None,
357
+ *,
358
+ list_all: bool = False,
359
+ ) -> dict[str, Any] | tuple[Any, int]:
360
+ """List Ray Serve applications.
361
+
362
+ Args:
363
+ params: Query parameters for filtering.
364
+ list_all: If True, returns (generator, count).
365
+
366
+ Returns:
367
+ Paginated list or (generator, count).
368
+ """
369
+ return self._list('serve_applications/', params=params, list_all=list_all)
370
+
371
+ # -------------------------------------------------------------------------
372
+ # Storage Operations
373
+ # -------------------------------------------------------------------------
374
+
375
+ def get_storage(self: ClientProtocol, storage_id: int) -> Storage:
376
+ """Get storage configuration by ID.
377
+
378
+ Args:
379
+ storage_id: Storage ID.
380
+
381
+ Returns:
382
+ Storage model with provider configuration.
383
+ """
384
+ response = self._get(
385
+ f'storages/{storage_id}/',
386
+ params={'with_configuration': 'true'},
387
+ )
388
+ return Storage.model_validate(response)
389
+
60
390
 
61
- def create_logs(self, data):
62
- path = 'logs/'
63
- return self._post(path, data=data)
391
+ __all__ = ['IntegrationClientMixin']
@@ -1,29 +1,141 @@
1
- from synapse_sdk.clients.base import BaseClient
2
- from synapse_sdk.clients.utils import get_default_url_conversion
1
+ """ML client mixin for model and ground truth operations."""
3
2
 
3
+ from __future__ import annotations
4
4
 
5
- class MLClientMixin(BaseClient):
6
- def list_models(self, params=None):
7
- path = 'models/'
8
- return self._get(path, params=params)
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING, Any
9
7
 
10
- def get_model(self, pk, params=None, url_conversion=None):
11
- path = f'models/{pk}/'
12
- url_conversion = get_default_url_conversion(
13
- url_conversion, files_fields=['files', 'parent.files'], is_list=False
8
+ from synapse_sdk.clients.backend.models import ModelCreateRequest
9
+
10
+ if TYPE_CHECKING:
11
+ from synapse_sdk.clients.protocols import ClientProtocol
12
+
13
+
14
+ class MLClientMixin:
15
+ """Mixin for ML-related API endpoints.
16
+
17
+ Provides methods for managing models and ground truth data.
18
+ """
19
+
20
+ def list_models(
21
+ self: ClientProtocol,
22
+ params: dict[str, Any] | None = None,
23
+ ) -> dict[str, Any]:
24
+ """List models with optional filtering.
25
+
26
+ Args:
27
+ params: Query parameters for filtering.
28
+
29
+ Returns:
30
+ Paginated model list.
31
+ """
32
+ return self._get('models/', params=params)
33
+
34
+ def get_model(
35
+ self: ClientProtocol,
36
+ model_id: int,
37
+ *,
38
+ params: dict[str, Any] | None = None,
39
+ url_conversion: dict[str, Any] | None = None,
40
+ ) -> dict[str, Any]:
41
+ """Get model details by ID.
42
+
43
+ Args:
44
+ model_id: Model ID.
45
+ params: Optional query parameters.
46
+ url_conversion: URL-to-path conversion config.
47
+
48
+ Returns:
49
+ Model data including file URL and metadata.
50
+ """
51
+ if url_conversion is None:
52
+ url_conversion = {'files_fields': ['file'], 'is_list': False}
53
+
54
+ return self._get(
55
+ f'models/{model_id}/',
56
+ params=params,
57
+ url_conversion=url_conversion,
58
+ )
59
+
60
+ def create_model(
61
+ self: ClientProtocol,
62
+ data: dict[str, Any],
63
+ *,
64
+ file: str | Path | None = None,
65
+ ) -> dict[str, Any]:
66
+ """Create a new model with file upload.
67
+
68
+ Large files are automatically uploaded using chunked upload.
69
+
70
+ Args:
71
+ data: Model metadata (name, plugin, version, etc.).
72
+ file: Model file to upload (uses chunked upload).
73
+
74
+ Returns:
75
+ Created model data.
76
+
77
+ Example:
78
+ >>> client.create_model(
79
+ ... {'name': 'My Model', 'plugin': 123},
80
+ ... file='/path/to/model.pt'
81
+ ... )
82
+ """
83
+ # Handle file upload via chunked upload
84
+ if file is not None:
85
+ path = Path(file)
86
+ if not path.exists():
87
+ raise FileNotFoundError(f'Model file not found: {path}')
88
+
89
+ # Upload file in chunks
90
+ upload_result = self.create_chunked_upload(path)
91
+ data['chunked_upload'] = upload_result['id']
92
+
93
+ return self._post(
94
+ 'models/',
95
+ request_model=ModelCreateRequest,
96
+ data=data,
14
97
  )
15
- return self._get(path, params=params, url_conversion=url_conversion)
16
98
 
17
- def create_model(self, data):
18
- path = 'models/'
19
- files = {'file': data.pop('file')}
20
- return self._post(path, data=data, files=files)
99
+ def list_ground_truth_events(
100
+ self: ClientProtocol,
101
+ params: dict[str, Any] | None = None,
102
+ *,
103
+ url_conversion: dict[str, Any] | None = None,
104
+ list_all: bool = False,
105
+ ) -> dict[str, Any] | tuple[Any, int]:
106
+ """List ground truth events.
107
+
108
+ Args:
109
+ params: Query parameters for filtering.
110
+ url_conversion: URL-to-path conversion config.
111
+ list_all: If True, returns (generator, count).
112
+
113
+ Returns:
114
+ Paginated list or (generator, count).
115
+ """
116
+ if url_conversion is None:
117
+ url_conversion = {'files_fields': ['files']}
118
+
119
+ return self._list(
120
+ 'sdk/ground_truth_events/',
121
+ params=params,
122
+ url_conversion=url_conversion,
123
+ list_all=list_all,
124
+ )
125
+
126
+ def get_ground_truth_version(
127
+ self: ClientProtocol,
128
+ version_id: int,
129
+ ) -> dict[str, Any]:
130
+ """Get ground truth dataset version by ID.
131
+
132
+ Args:
133
+ version_id: Version ID.
134
+
135
+ Returns:
136
+ Version data including file manifest.
137
+ """
138
+ return self._get(f'ground_truth_dataset_versions/{version_id}/')
21
139
 
22
- def create_serve_application(self, data):
23
- path = 'serve_applications/'
24
- return self._post(path, data=data)
25
140
 
26
- def list_ground_truth_events(self, params=None, url_conversion=None, list_all=False):
27
- path = 'ground_truth_events/'
28
- url_conversion = get_default_url_conversion(url_conversion, files_fields=['files'])
29
- return self._list(path, params=params, url_conversion=url_conversion, list_all=list_all)
141
+ __all__ = ['MLClientMixin']