synapse-sdk 1.0.0a13__py3-none-any.whl → 2025.11.7__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 (339) hide show
  1. synapse_sdk/__init__.py +24 -0
  2. synapse_sdk/cli/__init__.py +310 -5
  3. synapse_sdk/cli/alias/__init__.py +22 -0
  4. synapse_sdk/cli/alias/create.py +36 -0
  5. synapse_sdk/cli/alias/dataclass.py +31 -0
  6. synapse_sdk/cli/alias/default.py +16 -0
  7. synapse_sdk/cli/alias/delete.py +15 -0
  8. synapse_sdk/cli/alias/list.py +19 -0
  9. synapse_sdk/cli/alias/read.py +15 -0
  10. synapse_sdk/cli/alias/update.py +17 -0
  11. synapse_sdk/cli/alias/utils.py +61 -0
  12. synapse_sdk/cli/code_server.py +687 -0
  13. synapse_sdk/cli/config.py +440 -0
  14. synapse_sdk/cli/devtools.py +90 -0
  15. synapse_sdk/cli/plugin/__init__.py +33 -0
  16. synapse_sdk/cli/{create_plugin.py → plugin/create.py} +2 -2
  17. synapse_sdk/cli/plugin/publish.py +45 -0
  18. synapse_sdk/{plugins/cli → cli/plugin}/run.py +12 -5
  19. synapse_sdk/clients/agent/__init__.py +9 -3
  20. synapse_sdk/clients/agent/container.py +133 -0
  21. synapse_sdk/clients/agent/core.py +19 -0
  22. synapse_sdk/clients/agent/ray.py +298 -9
  23. synapse_sdk/clients/backend/__init__.py +41 -12
  24. synapse_sdk/clients/backend/annotation.py +13 -5
  25. synapse_sdk/clients/backend/core.py +59 -0
  26. synapse_sdk/clients/backend/data_collection.py +186 -0
  27. synapse_sdk/clients/backend/hitl.py +17 -0
  28. synapse_sdk/clients/backend/integration.py +19 -4
  29. synapse_sdk/clients/backend/ml.py +10 -7
  30. synapse_sdk/clients/backend/models.py +78 -0
  31. synapse_sdk/clients/base.py +381 -34
  32. synapse_sdk/clients/ray/serve.py +2 -0
  33. synapse_sdk/clients/validators/collections.py +31 -0
  34. synapse_sdk/devtools/config.py +94 -0
  35. synapse_sdk/devtools/docs/.gitignore +20 -0
  36. synapse_sdk/devtools/docs/README.md +41 -0
  37. synapse_sdk/devtools/docs/blog/2019-05-28-first-blog-post.md +12 -0
  38. synapse_sdk/devtools/docs/blog/2019-05-29-long-blog-post.md +44 -0
  39. synapse_sdk/devtools/docs/blog/2021-08-01-mdx-blog-post.mdx +24 -0
  40. synapse_sdk/devtools/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
  41. synapse_sdk/devtools/docs/blog/2021-08-26-welcome/index.md +29 -0
  42. synapse_sdk/devtools/docs/blog/authors.yml +25 -0
  43. synapse_sdk/devtools/docs/blog/tags.yml +19 -0
  44. synapse_sdk/devtools/docs/docs/api/clients/agent.md +43 -0
  45. synapse_sdk/devtools/docs/docs/api/clients/annotation-mixin.md +378 -0
  46. synapse_sdk/devtools/docs/docs/api/clients/backend.md +420 -0
  47. synapse_sdk/devtools/docs/docs/api/clients/base.md +257 -0
  48. synapse_sdk/devtools/docs/docs/api/clients/core-mixin.md +477 -0
  49. synapse_sdk/devtools/docs/docs/api/clients/data-collection-mixin.md +422 -0
  50. synapse_sdk/devtools/docs/docs/api/clients/hitl-mixin.md +554 -0
  51. synapse_sdk/devtools/docs/docs/api/clients/index.md +391 -0
  52. synapse_sdk/devtools/docs/docs/api/clients/integration-mixin.md +571 -0
  53. synapse_sdk/devtools/docs/docs/api/clients/ml-mixin.md +578 -0
  54. synapse_sdk/devtools/docs/docs/api/clients/ray.md +342 -0
  55. synapse_sdk/devtools/docs/docs/api/index.md +52 -0
  56. synapse_sdk/devtools/docs/docs/api/plugins/categories.md +43 -0
  57. synapse_sdk/devtools/docs/docs/api/plugins/models.md +114 -0
  58. synapse_sdk/devtools/docs/docs/api/plugins/utils.md +328 -0
  59. synapse_sdk/devtools/docs/docs/categories.md +0 -0
  60. synapse_sdk/devtools/docs/docs/cli-usage.md +280 -0
  61. synapse_sdk/devtools/docs/docs/concepts/index.md +38 -0
  62. synapse_sdk/devtools/docs/docs/configuration.md +83 -0
  63. synapse_sdk/devtools/docs/docs/contributing.md +306 -0
  64. synapse_sdk/devtools/docs/docs/examples/index.md +29 -0
  65. synapse_sdk/devtools/docs/docs/faq.md +179 -0
  66. synapse_sdk/devtools/docs/docs/features/converters/index.md +455 -0
  67. synapse_sdk/devtools/docs/docs/features/index.md +24 -0
  68. synapse_sdk/devtools/docs/docs/features/utils/file.md +415 -0
  69. synapse_sdk/devtools/docs/docs/features/utils/network.md +378 -0
  70. synapse_sdk/devtools/docs/docs/features/utils/storage.md +57 -0
  71. synapse_sdk/devtools/docs/docs/features/utils/types.md +51 -0
  72. synapse_sdk/devtools/docs/docs/installation.md +94 -0
  73. synapse_sdk/devtools/docs/docs/introduction.md +47 -0
  74. synapse_sdk/devtools/docs/docs/plugins/categories/neural-net-plugins/train-action-overview.md +814 -0
  75. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  76. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  77. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  78. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  79. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-action.md +948 -0
  80. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-overview.md +544 -0
  81. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-template.md +766 -0
  82. synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +1092 -0
  83. synapse_sdk/devtools/docs/docs/plugins/plugins.md +852 -0
  84. synapse_sdk/devtools/docs/docs/quickstart.md +78 -0
  85. synapse_sdk/devtools/docs/docs/troubleshooting.md +519 -0
  86. synapse_sdk/devtools/docs/docs/tutorial-basics/_category_.json +8 -0
  87. synapse_sdk/devtools/docs/docs/tutorial-basics/congratulations.md +23 -0
  88. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-blog-post.md +34 -0
  89. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-document.md +57 -0
  90. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-page.md +43 -0
  91. synapse_sdk/devtools/docs/docs/tutorial-basics/deploy-your-site.md +31 -0
  92. synapse_sdk/devtools/docs/docs/tutorial-basics/markdown-features.mdx +152 -0
  93. synapse_sdk/devtools/docs/docs/tutorial-extras/_category_.json +7 -0
  94. synapse_sdk/devtools/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
  95. synapse_sdk/devtools/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
  96. synapse_sdk/devtools/docs/docs/tutorial-extras/manage-docs-versions.md +55 -0
  97. synapse_sdk/devtools/docs/docs/tutorial-extras/translate-your-site.md +88 -0
  98. synapse_sdk/devtools/docs/docusaurus.config.ts +148 -0
  99. synapse_sdk/devtools/docs/i18n/ko/code.json +325 -0
  100. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/agent.md +43 -0
  101. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/annotation-mixin.md +289 -0
  102. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/backend.md +420 -0
  103. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/base.md +257 -0
  104. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/core-mixin.md +417 -0
  105. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/data-collection-mixin.md +356 -0
  106. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/hitl-mixin.md +192 -0
  107. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/index.md +391 -0
  108. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/integration-mixin.md +479 -0
  109. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ml-mixin.md +284 -0
  110. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ray.md +342 -0
  111. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/index.md +52 -0
  112. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/plugins/models.md +114 -0
  113. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/categories.md +0 -0
  114. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/cli-usage.md +280 -0
  115. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/concepts/index.md +38 -0
  116. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/configuration.md +83 -0
  117. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/contributing.md +306 -0
  118. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/examples/index.md +29 -0
  119. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/faq.md +179 -0
  120. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/converters/index.md +30 -0
  121. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/index.md +24 -0
  122. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/file.md +415 -0
  123. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/network.md +378 -0
  124. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/storage.md +60 -0
  125. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/types.md +51 -0
  126. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/installation.md +94 -0
  127. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/introduction.md +47 -0
  128. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/neural-net-plugins/train-action-overview.md +815 -0
  129. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  130. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  131. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  132. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  133. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-action.md +948 -0
  134. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-overview.md +544 -0
  135. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-template.md +766 -0
  136. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +1092 -0
  137. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/plugins.md +117 -0
  138. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/quickstart.md +78 -0
  139. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/troubleshooting.md +519 -0
  140. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current.json +34 -0
  141. synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/footer.json +42 -0
  142. synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/navbar.json +18 -0
  143. synapse_sdk/devtools/docs/package-lock.json +18784 -0
  144. synapse_sdk/devtools/docs/package.json +48 -0
  145. synapse_sdk/devtools/docs/sidebars.ts +122 -0
  146. synapse_sdk/devtools/docs/src/components/HomepageFeatures/index.tsx +71 -0
  147. synapse_sdk/devtools/docs/src/components/HomepageFeatures/styles.module.css +11 -0
  148. synapse_sdk/devtools/docs/src/css/custom.css +30 -0
  149. synapse_sdk/devtools/docs/src/pages/index.module.css +23 -0
  150. synapse_sdk/devtools/docs/src/pages/index.tsx +21 -0
  151. synapse_sdk/devtools/docs/src/pages/markdown-page.md +7 -0
  152. synapse_sdk/devtools/docs/static/.nojekyll +0 -0
  153. synapse_sdk/devtools/docs/static/img/docusaurus-social-card.jpg +0 -0
  154. synapse_sdk/devtools/docs/static/img/docusaurus.png +0 -0
  155. synapse_sdk/devtools/docs/static/img/favicon.ico +0 -0
  156. synapse_sdk/devtools/docs/static/img/logo.png +0 -0
  157. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
  158. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_react.svg +170 -0
  159. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_tree.svg +40 -0
  160. synapse_sdk/devtools/docs/tsconfig.json +8 -0
  161. synapse_sdk/devtools/server.py +41 -0
  162. synapse_sdk/devtools/streamlit_app/__init__.py +5 -0
  163. synapse_sdk/devtools/streamlit_app/app.py +128 -0
  164. synapse_sdk/devtools/streamlit_app/services/__init__.py +11 -0
  165. synapse_sdk/devtools/streamlit_app/services/job_service.py +233 -0
  166. synapse_sdk/devtools/streamlit_app/services/plugin_service.py +236 -0
  167. synapse_sdk/devtools/streamlit_app/services/serve_service.py +95 -0
  168. synapse_sdk/devtools/streamlit_app/ui/__init__.py +15 -0
  169. synapse_sdk/devtools/streamlit_app/ui/config_tab.py +76 -0
  170. synapse_sdk/devtools/streamlit_app/ui/deployment_tab.py +66 -0
  171. synapse_sdk/devtools/streamlit_app/ui/http_tab.py +125 -0
  172. synapse_sdk/devtools/streamlit_app/ui/jobs_tab.py +573 -0
  173. synapse_sdk/devtools/streamlit_app/ui/serve_tab.py +346 -0
  174. synapse_sdk/devtools/streamlit_app/ui/status_bar.py +118 -0
  175. synapse_sdk/devtools/streamlit_app/utils/__init__.py +40 -0
  176. synapse_sdk/devtools/streamlit_app/utils/json_viewer.py +197 -0
  177. synapse_sdk/devtools/streamlit_app/utils/log_formatter.py +38 -0
  178. synapse_sdk/devtools/streamlit_app/utils/styles.py +241 -0
  179. synapse_sdk/devtools/streamlit_app/utils/ui_components.py +289 -0
  180. synapse_sdk/devtools/streamlit_app.py +10 -0
  181. synapse_sdk/loggers.py +74 -9
  182. synapse_sdk/plugins/README.md +1340 -0
  183. synapse_sdk/plugins/__init__.py +0 -13
  184. synapse_sdk/plugins/categories/base.py +145 -30
  185. synapse_sdk/plugins/categories/data_validation/actions/validation.py +72 -0
  186. synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +33 -5
  187. synapse_sdk/plugins/categories/export/actions/__init__.py +3 -0
  188. synapse_sdk/plugins/categories/export/actions/export/__init__.py +28 -0
  189. synapse_sdk/plugins/categories/export/actions/export/action.py +165 -0
  190. synapse_sdk/plugins/categories/export/actions/export/enums.py +113 -0
  191. synapse_sdk/plugins/categories/export/actions/export/exceptions.py +53 -0
  192. synapse_sdk/plugins/categories/export/actions/export/models.py +74 -0
  193. synapse_sdk/plugins/categories/export/actions/export/run.py +195 -0
  194. synapse_sdk/plugins/categories/export/actions/export/utils.py +187 -0
  195. synapse_sdk/plugins/categories/export/templates/config.yaml +21 -0
  196. synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +390 -0
  197. synapse_sdk/plugins/categories/export/templates/plugin/export.py +160 -0
  198. synapse_sdk/plugins/categories/neural_net/actions/deployment.py +29 -14
  199. synapse_sdk/plugins/categories/neural_net/actions/inference.py +13 -1
  200. synapse_sdk/plugins/categories/neural_net/actions/train.py +1084 -38
  201. synapse_sdk/plugins/categories/neural_net/actions/tune.py +534 -0
  202. synapse_sdk/plugins/categories/neural_net/base/__init__.py +0 -0
  203. synapse_sdk/plugins/categories/neural_net/base/inference.py +37 -0
  204. synapse_sdk/plugins/categories/neural_net/templates/config.yaml +30 -5
  205. synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +26 -10
  206. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
  207. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
  208. synapse_sdk/plugins/categories/{export/actions/export.py → pre_annotation/actions/pre_annotation/action.py} +4 -4
  209. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
  210. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +145 -0
  211. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
  212. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
  213. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
  214. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +97 -0
  215. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +250 -0
  216. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
  217. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
  218. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +287 -0
  219. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
  220. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
  221. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +87 -0
  222. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +127 -0
  223. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
  224. synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py +966 -0
  225. synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +19 -0
  226. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/to_task.py +40 -0
  227. synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +5 -2
  228. synapse_sdk/plugins/categories/upload/__init__.py +0 -0
  229. synapse_sdk/plugins/categories/upload/actions/__init__.py +0 -0
  230. synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +19 -0
  231. synapse_sdk/plugins/categories/upload/actions/upload/action.py +232 -0
  232. synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
  233. synapse_sdk/plugins/categories/upload/actions/upload/enums.py +471 -0
  234. synapse_sdk/plugins/categories/upload/actions/upload/exceptions.py +36 -0
  235. synapse_sdk/plugins/categories/upload/actions/upload/factory.py +138 -0
  236. synapse_sdk/plugins/categories/upload/actions/upload/models.py +203 -0
  237. synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +183 -0
  238. synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
  239. synapse_sdk/plugins/categories/upload/actions/upload/run.py +179 -0
  240. synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
  241. synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +107 -0
  242. synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
  243. synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +63 -0
  244. synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +84 -0
  245. synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +82 -0
  246. synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +235 -0
  247. synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +203 -0
  248. synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +97 -0
  249. synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +71 -0
  250. synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
  251. synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +82 -0
  252. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/__init__.py +1 -0
  253. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/batch.py +39 -0
  254. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/single.py +29 -0
  255. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/__init__.py +1 -0
  256. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +258 -0
  257. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +281 -0
  258. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/__init__.py +1 -0
  259. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/excel.py +174 -0
  260. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/none.py +16 -0
  261. synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/__init__.py +1 -0
  262. synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +84 -0
  263. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/__init__.py +1 -0
  264. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +60 -0
  265. synapse_sdk/plugins/categories/upload/actions/upload/utils.py +250 -0
  266. synapse_sdk/plugins/categories/upload/templates/README.md +470 -0
  267. synapse_sdk/plugins/categories/upload/templates/config.yaml +33 -0
  268. synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +294 -0
  269. synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +102 -0
  270. synapse_sdk/plugins/enums.py +3 -1
  271. synapse_sdk/plugins/models.py +140 -16
  272. synapse_sdk/plugins/templates/plugin-config-schema.json +406 -0
  273. synapse_sdk/plugins/templates/schema.json +491 -0
  274. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +1 -0
  275. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +1 -1
  276. synapse_sdk/plugins/utils/__init__.py +46 -0
  277. synapse_sdk/plugins/utils/actions.py +119 -0
  278. synapse_sdk/plugins/utils/config.py +203 -0
  279. synapse_sdk/plugins/utils/legacy.py +95 -0
  280. synapse_sdk/plugins/utils/ray_gcs.py +66 -0
  281. synapse_sdk/plugins/utils/registry.py +58 -0
  282. synapse_sdk/shared/__init__.py +25 -0
  283. synapse_sdk/shared/enums.py +93 -0
  284. synapse_sdk/types.py +19 -0
  285. synapse_sdk/utils/converters/__init__.py +240 -0
  286. synapse_sdk/utils/converters/coco/__init__.py +0 -0
  287. synapse_sdk/utils/converters/coco/from_dm.py +322 -0
  288. synapse_sdk/utils/converters/coco/to_dm.py +215 -0
  289. synapse_sdk/utils/converters/dm/__init__.py +56 -0
  290. synapse_sdk/utils/converters/dm/from_v1.py +627 -0
  291. synapse_sdk/utils/converters/dm/to_v1.py +367 -0
  292. synapse_sdk/utils/converters/pascal/__init__.py +0 -0
  293. synapse_sdk/utils/converters/pascal/from_dm.py +244 -0
  294. synapse_sdk/utils/converters/pascal/to_dm.py +214 -0
  295. synapse_sdk/utils/converters/yolo/__init__.py +0 -0
  296. synapse_sdk/utils/converters/yolo/from_dm.py +384 -0
  297. synapse_sdk/utils/converters/yolo/to_dm.py +267 -0
  298. synapse_sdk/utils/dataset.py +46 -0
  299. synapse_sdk/utils/encryption.py +158 -0
  300. synapse_sdk/utils/file/__init__.py +39 -0
  301. synapse_sdk/utils/file/archive.py +32 -0
  302. synapse_sdk/utils/file/checksum.py +56 -0
  303. synapse_sdk/utils/file/chunking.py +31 -0
  304. synapse_sdk/utils/file/download.py +385 -0
  305. synapse_sdk/utils/file/encoding.py +40 -0
  306. synapse_sdk/utils/file/io.py +22 -0
  307. synapse_sdk/utils/file/video/__init__.py +29 -0
  308. synapse_sdk/utils/file/video/transcode.py +307 -0
  309. synapse_sdk/utils/file.py.backup +301 -0
  310. synapse_sdk/utils/http.py +138 -0
  311. synapse_sdk/utils/network.py +309 -0
  312. synapse_sdk/utils/storage/__init__.py +72 -0
  313. synapse_sdk/utils/storage/providers/__init__.py +183 -0
  314. synapse_sdk/utils/storage/providers/file_system.py +134 -0
  315. synapse_sdk/utils/storage/providers/gcp.py +13 -0
  316. synapse_sdk/utils/storage/providers/http.py +190 -0
  317. synapse_sdk/utils/storage/providers/s3.py +91 -0
  318. synapse_sdk/utils/storage/providers/sftp.py +47 -0
  319. synapse_sdk/utils/storage/registry.py +17 -0
  320. synapse_sdk-2025.11.7.dist-info/METADATA +122 -0
  321. synapse_sdk-2025.11.7.dist-info/RECORD +386 -0
  322. {synapse_sdk-1.0.0a13.dist-info → synapse_sdk-2025.11.7.dist-info}/WHEEL +1 -1
  323. synapse_sdk/clients/backend/dataset.py +0 -51
  324. synapse_sdk/plugins/categories/import/actions/import.py +0 -10
  325. synapse_sdk/plugins/cli/__init__.py +0 -21
  326. synapse_sdk/plugins/cli/publish.py +0 -37
  327. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
  328. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
  329. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
  330. synapse_sdk/plugins/utils.py +0 -50
  331. synapse_sdk/utils/file.py +0 -87
  332. synapse_sdk/utils/storage.py +0 -91
  333. synapse_sdk-1.0.0a13.dist-info/METADATA +0 -43
  334. synapse_sdk-1.0.0a13.dist-info/RECORD +0 -111
  335. /synapse_sdk/{plugins/categories/import → clients/validators}/__init__.py +0 -0
  336. /synapse_sdk/{plugins/categories/import/actions → devtools}/__init__.py +0 -0
  337. {synapse_sdk-1.0.0a13.dist-info → synapse_sdk-2025.11.7.dist-info}/entry_points.txt +0 -0
  338. {synapse_sdk-1.0.0a13.dist-info → synapse_sdk-2025.11.7.dist-info/licenses}/LICENSE +0 -0
  339. {synapse_sdk-1.0.0a13.dist-info → synapse_sdk-2025.11.7.dist-info}/top_level.txt +0 -0
@@ -1,18 +1,24 @@
1
+ from synapse_sdk.clients.agent.container import ContainerClientMixin
1
2
  from synapse_sdk.clients.agent.core import CoreClientMixin
2
3
  from synapse_sdk.clients.agent.ray import RayClientMixin
3
4
  from synapse_sdk.clients.agent.service import ServiceClientMixin
4
5
  from synapse_sdk.clients.exceptions import ClientError
5
6
 
6
7
 
7
- class AgentClient(CoreClientMixin, RayClientMixin, ServiceClientMixin):
8
+ class AgentClient(CoreClientMixin, RayClientMixin, ServiceClientMixin, ContainerClientMixin):
8
9
  name = 'Agent'
9
10
  agent_token = None
10
11
  user_token = None
11
12
  tenant = None
12
13
  long_poll_handler = None
13
14
 
14
- def __init__(self, base_url, agent_token, user_token=None, tenant=None, long_poll_handler=None):
15
- super().__init__(base_url)
15
+ def __init__(self, base_url, agent_token, user_token=None, tenant=None, long_poll_handler=None, timeout=None):
16
+ # Use shorter timeouts for agent connections for better UX
17
+ agent_timeout = timeout or {
18
+ 'connect': 3, # Connection timeout: 3 seconds
19
+ 'read': 10, # Read timeout: 10 seconds
20
+ }
21
+ super().__init__(base_url, timeout=agent_timeout)
16
22
  self.agent_token = agent_token
17
23
  self.user_token = user_token
18
24
  self.tenant = tenant
@@ -0,0 +1,133 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any, Dict, Iterable, Optional, Union
5
+
6
+ from synapse_sdk.clients.base import BaseClient
7
+
8
+
9
+ class ContainerClientMixin(BaseClient):
10
+ """Client mixin exposing the agent container management API."""
11
+
12
+ def health_check(self):
13
+ """Perform a health check on Docker sock."""
14
+ path = 'health/'
15
+ return self._get(path)
16
+
17
+ def list_containers(self, params: Optional[Dict[str, Any]] = None, *, list_all: bool = False):
18
+ """List containers managed by the agent.
19
+
20
+ Args:
21
+ params: Optional query parameters (e.g. {'status': 'running'}).
22
+ list_all: When True, returns ``(generator, count)`` covering every page.
23
+
24
+ Returns:
25
+ dict | tuple: Standard paginated response or a tuple for ``list_all``.
26
+ """
27
+ path = 'containers/'
28
+ return self._list(path, params=params, list_all=list_all)
29
+
30
+ def get_container(self, container_id: Union[int, str]):
31
+ """Retrieve details for a specific container."""
32
+ path = f'containers/{container_id}/'
33
+ return self._get(path)
34
+
35
+ def delete_container(self, container_id: Union[int, str]):
36
+ """Stop and remove a container."""
37
+ path = f'containers/{container_id}/'
38
+ return self._delete(path)
39
+
40
+ def create_container(
41
+ self,
42
+ plugin_release: Optional[Union[str, Any]] = None,
43
+ *,
44
+ params: Optional[Dict[str, Any]] = None,
45
+ envs: Optional[Dict[str, str]] = None,
46
+ metadata: Optional[Dict[str, Any]] = None,
47
+ labels: Optional[Iterable[str]] = None,
48
+ plugin_file: Optional[Union[str, Path]] = None,
49
+ ):
50
+ """Create a Docker container running a plugin Gradio interface.
51
+
52
+ Args:
53
+ plugin_release: Plugin identifier. Accepts either ``synapse_sdk.plugins.models.PluginRelease``
54
+ instances or the ``"<plugin_code>@<version>"`` shorthand string.
55
+ params: Arbitrary parameters forwarded to ``plugin/gradio_interface.py``.
56
+ envs: Extra environment variables injected into the container.
57
+ metadata: Additional metadata stored with the container record.
58
+ labels: Optional container labels/tags for display or filtering.
59
+ plugin_file: Optional path to a packaged plugin release to upload directly.
60
+ The archive must contain ``plugin/gradio_interface.py``.
61
+
62
+ Returns:
63
+ dict: Container creation response that includes the exposed Gradio endpoint.
64
+
65
+ Raises:
66
+ FileNotFoundError: If ``plugin_file`` is provided but does not exist.
67
+ ValueError: If neither ``plugin_release`` nor ``plugin_file`` are provided.
68
+ """
69
+ if not plugin_release and not plugin_file:
70
+ raise ValueError('Either "plugin_release" or "plugin_file" must be provided to create a container.')
71
+
72
+ data: Dict[str, Any] = {}
73
+
74
+ if plugin_release:
75
+ data.update(self._serialize_plugin_release(plugin_release))
76
+
77
+ optional_payload = {
78
+ 'params': params if params is not None else None,
79
+ 'envs': envs or None,
80
+ 'metadata': metadata or None,
81
+ 'labels': list(labels) if labels else None,
82
+ }
83
+ data.update({key: value for key, value in optional_payload.items() if value is not None})
84
+
85
+ files = None
86
+ if plugin_file:
87
+ file_path = Path(plugin_file)
88
+ if not file_path.exists():
89
+ raise FileNotFoundError(f'Plugin release file not found: {file_path}')
90
+ files = {'file': file_path}
91
+ post_kwargs = {'data': data}
92
+ if files:
93
+ post_kwargs['files'] = files
94
+
95
+ return self._post('containers/', **post_kwargs)
96
+
97
+ @staticmethod
98
+ def _serialize_plugin_release(plugin_release: Union[str, Any]) -> Dict[str, Any]:
99
+ """Normalize plugin release data for API payloads."""
100
+ if hasattr(plugin_release, 'code') and hasattr(plugin_release, 'version'):
101
+ payload = {
102
+ 'plugin_release': plugin_release.code,
103
+ 'plugin': getattr(plugin_release, 'plugin', None),
104
+ 'version': plugin_release.version,
105
+ }
106
+
107
+ # Extract action and entrypoint from the first action in the config
108
+ if hasattr(plugin_release, 'config') and 'actions' in plugin_release.config:
109
+ actions = plugin_release.config['actions']
110
+ if actions:
111
+ # Get the first action (typically 'gradio')
112
+ action_name = next(iter(actions.keys()))
113
+ action_config = actions[action_name]
114
+ payload['action'] = action_name
115
+
116
+ # Convert entrypoint from dotted path to file path
117
+ if 'entrypoint' in action_config:
118
+ entrypoint = action_config['entrypoint']
119
+ # Convert 'plugin.gradio_interface.app' to 'plugin/gradio_interface.py'
120
+ file_path = entrypoint.rsplit('.', 1)[0].replace('.', '/') + '.py'
121
+ payload['entrypoint'] = file_path
122
+
123
+ return payload
124
+
125
+ if isinstance(plugin_release, str):
126
+ payload = {'plugin_release': plugin_release}
127
+ if '@' in plugin_release:
128
+ plugin, version = plugin_release.rsplit('@', 1)
129
+ payload.setdefault('plugin', plugin)
130
+ payload.setdefault('version', version)
131
+ return payload
132
+
133
+ raise TypeError('plugin_release must be a PluginRelease instance or a formatted string "code@version"')
@@ -5,3 +5,22 @@ class CoreClientMixin(BaseClient):
5
5
  def health_check(self):
6
6
  path = 'health/'
7
7
  return self._get(path)
8
+
9
+ def get_metrics(self, panel):
10
+ path = f'metrics/{panel}/'
11
+ return self._get(path)
12
+
13
+ def get_code_server_info(self, workspace_path=None):
14
+ """Get code-server connection information from the agent.
15
+
16
+ Args:
17
+ workspace_path: Optional path to set as the workspace directory
18
+
19
+ Returns:
20
+ dict: Code-server connection information
21
+ """
22
+ path = 'code-server/info/'
23
+ params = {}
24
+ if workspace_path:
25
+ params['workspace'] = workspace_path
26
+ return self._get(path, params=params)
@@ -1,8 +1,86 @@
1
+ import weakref
2
+ from concurrent.futures import ThreadPoolExecutor
3
+
1
4
  from synapse_sdk.clients.base import BaseClient
2
5
  from synapse_sdk.clients.exceptions import ClientError
6
+ from synapse_sdk.utils.network import (
7
+ HTTPStreamManager,
8
+ StreamLimits,
9
+ WebSocketStreamManager,
10
+ http_to_websocket_url,
11
+ sanitize_error_message,
12
+ validate_resource_id,
13
+ validate_timeout,
14
+ )
3
15
 
4
16
 
5
17
  class RayClientMixin(BaseClient):
18
+ """Mixin class providing Ray cluster management and monitoring functionality.
19
+
20
+ This mixin extends BaseClient with Ray-specific operations for interacting with
21
+ Apache Ray distributed computing clusters. It provides comprehensive job management,
22
+ node monitoring, task tracking, and Ray Serve application control capabilities.
23
+
24
+ Key Features:
25
+ - Job lifecycle management (list, get, monitor)
26
+ - Real-time log streaming via WebSocket and HTTP protocols
27
+ - Node and task monitoring
28
+ - Ray Serve application deployment and management
29
+ - Robust error handling with input validation
30
+ - Resource management with automatic cleanup
31
+
32
+ Streaming Capabilities:
33
+ - WebSocket streaming for real-time log tailing
34
+ - HTTP streaming as fallback protocol
35
+ - Configurable timeouts and stream limits
36
+ - Automatic protocol validation and error recovery
37
+
38
+ Resource Management:
39
+ - Thread pool for concurrent operations (5 workers)
40
+ - WeakSet for tracking active connections
41
+ - Automatic cleanup on object destruction
42
+ - Stream limits to prevent resource exhaustion
43
+
44
+ Usage Examples:
45
+ Basic job operations:
46
+ >>> client = RayClient(base_url="http://ray-head:8265")
47
+ >>> jobs = client.list_jobs()
48
+ >>> job = client.get_job('job-12345')
49
+
50
+ Real-time log streaming:
51
+ >>> # WebSocket streaming (preferred)
52
+ >>> for log_line in client.tail_job_logs('job-12345', protocol='websocket'):
53
+ ... print(log_line)
54
+
55
+ >>> # HTTP streaming (fallback)
56
+ >>> for log_line in client.tail_job_logs('job-12345', protocol='stream'):
57
+ ... print(log_line)
58
+
59
+ Node and task monitoring:
60
+ >>> nodes = client.list_nodes()
61
+ >>> tasks = client.list_tasks()
62
+ >>> node_details = client.get_node('node-id')
63
+
64
+ Ray Serve management:
65
+ >>> apps = client.list_serve_applications()
66
+ >>> client.delete_serve_application('app-id')
67
+
68
+ Note:
69
+ This class is designed as a mixin and should be combined with other
70
+ client classes that provide authentication and base functionality.
71
+ It requires the BaseClient foundation for HTTP operations.
72
+ """
73
+
74
+ def __init__(self, *args, **kwargs):
75
+ super().__init__(*args, **kwargs)
76
+ self._thread_pool = ThreadPoolExecutor(max_workers=5, thread_name_prefix='ray_client_')
77
+ self._active_connections = weakref.WeakSet()
78
+
79
+ # Initialize stream managers
80
+ stream_limits = StreamLimits()
81
+ self._websocket_manager = WebSocketStreamManager(self._thread_pool, stream_limits)
82
+ self._http_manager = HTTPStreamManager(self.requests_session, stream_limits)
83
+
6
84
  def get_job(self, pk):
7
85
  path = f'jobs/{pk}/'
8
86
  return self._get(path)
@@ -15,19 +93,180 @@ class RayClientMixin(BaseClient):
15
93
  path = f'jobs/{pk}/logs/'
16
94
  return self._get(path)
17
95
 
18
- def tail_job_logs(self, pk):
19
- if self.long_poll_handler:
20
- raise ClientError(400, '"tail_job_logs" does not support long polling')
96
+ def websocket_tail_job_logs(self, pk, stream_timeout=10):
97
+ """Stream job logs in real-time using WebSocket protocol.
98
+
99
+ Establishes a WebSocket connection to stream job logs as they are generated.
100
+ This method provides the lowest latency for real-time log monitoring and is
101
+ the preferred protocol when available.
102
+
103
+ Args:
104
+ pk (str): Job primary key or identifier. Must be alphanumeric with
105
+ optional hyphens/underscores, max 100 characters.
106
+ stream_timeout (float, optional): Maximum time in seconds to wait for
107
+ log data. Defaults to 10. Must be positive
108
+ and cannot exceed 300 seconds.
109
+
110
+ Returns:
111
+ Generator[str, None, None]: A generator yielding log lines as strings.
112
+ Each line includes a newline character.
113
+
114
+ Raises:
115
+ ClientError:
116
+ - 400: If long polling is enabled (incompatible)
117
+ - 400: If pk is empty, contains invalid characters, or too long
118
+ - 400: If stream_timeout is not positive or exceeds maximum
119
+ - 500: If WebSocket library is unavailable
120
+ - 503: If connection to Ray cluster fails
121
+ - 408: If connection timeout occurs
122
+ - 429: If stream limits are exceeded (lines, size, messages)
123
+
124
+ Usage:
125
+ >>> # Basic log streaming
126
+ >>> for log_line in client.websocket_tail_job_logs('job-12345'):
127
+ ... print(log_line.strip())
128
+
129
+ >>> # With custom timeout
130
+ >>> for log_line in client.websocket_tail_job_logs('job-12345', stream_timeout=30):
131
+ ... if 'ERROR' in log_line:
132
+ ... break
133
+
134
+ Technical Notes:
135
+ - Uses WebSocketStreamManager for connection management
136
+ - Automatic input validation and sanitization
137
+ - Resource cleanup handled by WeakSet tracking
138
+ - Stream limits prevent memory exhaustion
139
+ - Thread pool manages WebSocket operations
140
+
141
+ See Also:
142
+ stream_tail_job_logs: HTTP-based alternative
143
+ tail_job_logs: Protocol-agnostic wrapper method
144
+ """
145
+ if hasattr(self, 'long_poll_handler') and self.long_poll_handler:
146
+ raise ClientError(400, '"websocket_tail_job_logs" does not support long polling')
147
+
148
+ # Validate inputs using network utilities
149
+ validated_pk = validate_resource_id(pk, 'job')
150
+ validated_timeout = validate_timeout(stream_timeout)
151
+
152
+ # Build WebSocket URL
153
+ path = f'ray/jobs/{validated_pk}/logs/ws/'
154
+ url = self._get_url(path, trailing_slash=True)
155
+ ws_url = http_to_websocket_url(url)
156
+
157
+ # Get headers and use WebSocket manager
158
+ headers = self._get_headers()
159
+ headers['Agent-Token'] = f'Token {self.agent_token}'
160
+ context = f'job {validated_pk}'
161
+
162
+ return self._websocket_manager.stream_logs(ws_url, headers, validated_timeout, context)
163
+
164
+ def stream_tail_job_logs(self, pk, stream_timeout=10):
165
+ """Stream job logs in real-time using HTTP chunked transfer encoding.
166
+
167
+ Establishes an HTTP connection with chunked transfer encoding to stream
168
+ job logs as they are generated. This method serves as a reliable fallback
169
+ when WebSocket connections are not available or suitable.
170
+
171
+ Args:
172
+ pk (str): Job primary key or identifier. Must be alphanumeric with
173
+ optional hyphens/underscores, max 100 characters.
174
+ stream_timeout (float, optional): Maximum time in seconds to wait for
175
+ log data. Defaults to 10. Must be positive
176
+ and cannot exceed 300 seconds.
177
+
178
+ Returns:
179
+ Generator[str, None, None]: A generator yielding log lines as strings.
180
+ Each line includes a newline character.
181
+
182
+ Raises:
183
+ ClientError:
184
+ - 400: If long polling is enabled (incompatible)
185
+ - 400: If pk is empty, contains invalid characters, or too long
186
+ - 400: If stream_timeout is not positive or exceeds maximum
187
+ - 503: If connection to Ray cluster fails
188
+ - 408: If connection or read timeout occurs
189
+ - 404: If job is not found
190
+ - 429: If stream limits are exceeded (lines, size, messages)
191
+ - 500: If unexpected streaming error occurs
192
+
193
+ Usage:
194
+ >>> # Basic HTTP log streaming
195
+ >>> for log_line in client.stream_tail_job_logs('job-12345'):
196
+ ... print(log_line.strip())
21
197
 
22
- path = f'jobs/{pk}/tail_logs/'
198
+ >>> # With error handling and custom timeout
199
+ >>> try:
200
+ ... for log_line in client.stream_tail_job_logs('job-12345', stream_timeout=60):
201
+ ... if 'COMPLETED' in log_line:
202
+ ... break
203
+ ... except ClientError as e:
204
+ ... print(f"Streaming failed: {e}")
23
205
 
24
- url = self._get_url(path)
206
+ Technical Notes:
207
+ - Uses HTTPStreamManager for connection management
208
+ - Automatic input validation and sanitization
209
+ - Proper HTTP response cleanup on completion/error
210
+ - Stream limits prevent memory exhaustion
211
+ - Filters out oversized lines (>10KB) automatically
212
+ - Connection reuse through requests session
213
+
214
+ See Also:
215
+ websocket_tail_job_logs: WebSocket-based alternative (preferred)
216
+ tail_job_logs: Protocol-agnostic wrapper method
217
+ """
218
+ if hasattr(self, 'long_poll_handler') and self.long_poll_handler:
219
+ raise ClientError(400, '"stream_tail_job_logs" does not support long polling')
220
+
221
+ # Validate inputs using network utilities
222
+ validated_pk = validate_resource_id(pk, 'job')
223
+ validated_timeout = validate_timeout(stream_timeout)
224
+
225
+ # Build HTTP URL and prepare request
226
+ path = f'ray/jobs/{validated_pk}/logs/stream/'
227
+ url = self._get_url(path, trailing_slash=True)
25
228
  headers = self._get_headers()
229
+ headers['Agent-Token'] = f'Token {self.agent_token}'
230
+ timeout = (self.timeout['connect'], validated_timeout)
231
+ context = f'job {validated_pk}'
232
+
233
+ return self._http_manager.stream_logs(url, headers, timeout, context)
234
+
235
+ def tail_job_logs(self, pk, stream_timeout=10, protocol='stream'):
236
+ """Tail job logs using either WebSocket or HTTP streaming.
237
+
238
+ Args:
239
+ pk: Job primary key
240
+ stream_timeout: Timeout for streaming operations
241
+ protocol: 'websocket' or 'stream' (default: 'stream')
242
+ """
243
+ # Validate protocol first
244
+ if protocol not in ('websocket', 'stream'):
245
+ raise ClientError(400, f'Unsupported protocol: {protocol}. Use "websocket" or "stream"')
26
246
 
27
- response = self.requests_session.get(url, headers=headers, stream=True)
28
- for line in response.iter_lines(decode_unicode=True):
29
- if line:
30
- yield f'{line}\n'
247
+ # Pre-validate common inputs using network utilities
248
+ validate_resource_id(pk, 'job')
249
+ validate_timeout(stream_timeout)
250
+
251
+ try:
252
+ if protocol == 'websocket':
253
+ return self.websocket_tail_job_logs(pk, stream_timeout)
254
+ else: # protocol == 'stream'
255
+ return self.stream_tail_job_logs(pk, stream_timeout)
256
+ except ClientError:
257
+ raise
258
+ except Exception as e:
259
+ # Fallback error handling using network utility
260
+ sanitized_error = sanitize_error_message(str(e), f'job {pk}')
261
+ raise ClientError(500, f'Protocol {protocol} failed: {sanitized_error}')
262
+
263
+ def __del__(self):
264
+ """Cleanup resources when object is destroyed."""
265
+ try:
266
+ if hasattr(self, '_thread_pool'):
267
+ self._thread_pool.shutdown(wait=False)
268
+ except Exception:
269
+ pass # Ignore cleanup errors during destruction
31
270
 
32
271
  def get_node(self, pk):
33
272
  path = f'nodes/{pk}/'
@@ -56,3 +295,53 @@ class RayClientMixin(BaseClient):
56
295
  def delete_serve_application(self, pk):
57
296
  path = f'serve_applications/{pk}/'
58
297
  return self._delete(path)
298
+
299
+ def stop_job(self, pk):
300
+ """Stop a running job gracefully.
301
+
302
+ Uses Ray's stop_job() API to request graceful termination of the job.
303
+ This preserves job state and allows for potential resubmission later.
304
+
305
+ Args:
306
+ pk (str): Job primary key or identifier. Must be alphanumeric with
307
+ optional hyphens/underscores, max 100 characters.
308
+
309
+ Returns:
310
+ dict: Response containing job status and stop details.
311
+
312
+ Raises:
313
+ ClientError:
314
+ - 400: If pk is empty, contains invalid characters, or too long
315
+ - 400: If job is already in terminal state (STOPPED, FAILED, etc.)
316
+ - 404: If job is not found
317
+ - 503: If connection to Ray cluster fails
318
+ - 500: If unexpected error occurs during stop
319
+
320
+ Usage:
321
+ >>> # Stop a running job
322
+ >>> result = client.stop_job('job-12345')
323
+ >>> print(result['status']) # Should show 'STOPPING' or similar
324
+
325
+ >>> # Handle stop errors
326
+ >>> try:
327
+ ... client.stop_job('job-12345')
328
+ ... except ClientError as e:
329
+ ... print(f"Stop failed: {e}")
330
+
331
+ Technical Notes:
332
+ - Uses Ray's stop_job() API for graceful termination
333
+ - Validates job state before attempting stop
334
+ - Maintains consistency with existing SDK patterns
335
+ - Provides detailed error messages for debugging
336
+
337
+ See Also:
338
+ resume_job: Method for restarting stopped jobs
339
+ """
340
+ # Validate inputs using network utilities
341
+ validated_pk = validate_resource_id(pk, 'job')
342
+
343
+ # Build API path for job stop
344
+ path = f'jobs/{validated_pk}/stop/'
345
+
346
+ # Use _post method with empty data to match Ray's API pattern
347
+ return self._post(path)
@@ -1,23 +1,52 @@
1
1
  from synapse_sdk.clients.backend.annotation import AnnotationClientMixin
2
- from synapse_sdk.clients.backend.dataset import DatasetClientMixin
2
+ from synapse_sdk.clients.backend.core import CoreClientMixin
3
+ from synapse_sdk.clients.backend.data_collection import DataCollectionClientMixin
4
+ from synapse_sdk.clients.backend.hitl import HITLClientMixin
3
5
  from synapse_sdk.clients.backend.integration import IntegrationClientMixin
4
6
  from synapse_sdk.clients.backend.ml import MLClientMixin
5
7
 
6
8
 
7
- class BackendClient(AnnotationClientMixin, DatasetClientMixin, IntegrationClientMixin, MLClientMixin):
9
+ class BackendClient(
10
+ AnnotationClientMixin,
11
+ CoreClientMixin,
12
+ DataCollectionClientMixin,
13
+ IntegrationClientMixin,
14
+ MLClientMixin,
15
+ HITLClientMixin,
16
+ ):
17
+ """BackendClient is a client for the synapse backend API.
18
+
19
+ * Access token overrides authorization token and tenant token.
20
+
21
+ Attrs:
22
+ access_token (str): The synapse access token for the synapse backend API.
23
+ authorization_token (str): The authorization token for the synapse backend API.
24
+ tenant_token (str): The tenant token for the synapse backend API.
25
+ agent_token (str): The agent token for the backend API.
26
+ timeout (Dict): Set reasonable default timeouts for better UX. It can receive keys called 'connect' and 'read'.
27
+ """
28
+
8
29
  name = 'Backend'
9
- token = None
10
- tenant = None
30
+ access_token = None
31
+ authorization_token = None
32
+ tenant_token = None
33
+ agent_token = None
11
34
 
12
- def __init__(self, base_url, token=None, tenant=None):
13
- super().__init__(base_url)
14
- self.token = token
15
- self.tenant = tenant
35
+ def __init__(self, base_url, access_token=None, token=None, tenant=None, agent_token=None, timeout=None, **kwargs):
36
+ super().__init__(base_url, timeout=timeout)
37
+ self.access_token = access_token
38
+ self.authorization_token = token
39
+ self.tenant_token = tenant
40
+ self.agent_token = agent_token
16
41
 
17
42
  def _get_headers(self):
18
43
  headers = {}
19
- if self.token:
20
- headers = {'Authorization': f'Token {self.token}'}
21
- if self.tenant:
22
- headers['SYNAPSE-Tenant'] = f'Token {self.tenant}'
44
+ if self.access_token:
45
+ headers['Synapse-Access-Token'] = f'Token {self.access_token}'
46
+ if self.authorization_token:
47
+ headers['Authorization'] = f'Token {self.authorization_token}'
48
+ if self.tenant_token:
49
+ headers['Synapse-Tenant'] = f'Token {self.tenant_token}'
50
+ if self.agent_token:
51
+ headers['SYNAPSE-Agent'] = f'Token {self.agent_token}'
23
52
  return headers
@@ -7,18 +7,26 @@ class AnnotationClientMixin(BaseClient):
7
7
  path = f'projects/{pk}/'
8
8
  return self._get(path)
9
9
 
10
+ def get_task(self, pk, params):
11
+ path = f'tasks/{pk}/'
12
+ return self._get(path, params=params)
13
+
14
+ def annotate_task_data(self, pk, data):
15
+ path = f'tasks/{pk}/annotate_task_data/'
16
+ return self._put(path, data=data)
17
+
10
18
  def get_task_tag(self, pk):
11
19
  path = f'task_tags/{pk}/'
12
20
  return self._get(path)
13
21
 
14
- def list_task_tags(self, data):
22
+ def list_task_tags(self, params):
15
23
  path = 'task_tags/'
16
- return self._list(path, data=data)
24
+ return self._list(path, params=params)
17
25
 
18
- def list_tasks(self, data, url_conversion=None, list_all=False):
19
- path = 'tasks/'
26
+ def list_tasks(self, params=None, url_conversion=None, list_all=False):
27
+ path = 'sdk/tasks/'
20
28
  url_conversion = get_default_url_conversion(url_conversion, files_fields=['files'])
21
- return self._list(path, data=data, url_conversion=url_conversion, list_all=list_all)
29
+ return self._list(path, params=params, url_conversion=url_conversion, list_all=list_all)
22
30
 
23
31
  def create_tasks(self, data):
24
32
  path = 'tasks/'
@@ -0,0 +1,59 @@
1
+ import hashlib
2
+ import os
3
+ from pathlib import Path
4
+
5
+ from synapse_sdk.clients.base import BaseClient
6
+ from synapse_sdk.utils.file import read_file_in_chunks
7
+
8
+
9
+ class CoreClientMixin(BaseClient):
10
+ def create_chunked_upload(self, file_path):
11
+ """
12
+ Upload a file using chunked upload for efficient handling of large files.
13
+
14
+ This method breaks the file into chunks and uploads them sequentially to the server.
15
+ It calculates an MD5 hash of the entire file to ensure data integrity during upload.
16
+
17
+ Args:
18
+ file_path (str | Path): Path to the file to upload
19
+
20
+ Returns:
21
+ dict: Response from the server after successful upload completion,
22
+ typically containing upload confirmation and file metadata
23
+
24
+ Raises:
25
+ FileNotFoundError: If the specified file doesn't exist
26
+ PermissionError: If the file can't be read due to permissions
27
+ ClientError: If there's an error during the upload process
28
+ OSError: If there's an OS-level error accessing the file
29
+
30
+ Example:
31
+ ```python
32
+ client = CoreClientMixin(base_url='https://api.example.com')
33
+ result = client.create_chunked_upload('/path/to/large_file.zip')
34
+ print(f"Upload completed: {result}")
35
+ ```
36
+
37
+ Note:
38
+ - Uses 50MB chunks by default for optimal upload performance
39
+ - Automatically resumes from the last successfully uploaded chunk
40
+ - Verifies upload integrity using MD5 checksum
41
+ """
42
+ file_path = Path(file_path)
43
+ size = os.path.getsize(file_path)
44
+ hash_md5 = hashlib.md5()
45
+
46
+ url = 'chunked_upload/'
47
+ offset = 0
48
+ for chunk in read_file_in_chunks(file_path):
49
+ hash_md5.update(chunk)
50
+ data = self._put(
51
+ url,
52
+ data={'filename': file_path.name},
53
+ files={'file': chunk},
54
+ headers={'Content-Range': f'bytes {offset}-{offset + len(chunk) - 1}/{size}'},
55
+ )
56
+ offset = data['offset']
57
+ url = data['url']
58
+
59
+ return self._post(url, data={'md5': hash_md5.hexdigest()})