synth-ai 0.2.8.dev2__py3-none-any.whl → 0.4.3__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.
Files changed (740) hide show
  1. synth_ai/__init__.py +44 -24
  2. synth_ai/__main__.py +30 -3
  3. synth_ai/cli/__init__.py +103 -48
  4. synth_ai/cli/__main__.py +42 -0
  5. synth_ai/cli/_internal/__init__.py +5 -0
  6. synth_ai/cli/_internal/modal_wrapper.py +31 -0
  7. synth_ai/cli/_internal/storage.py +20 -0
  8. synth_ai/cli/_internal/typer_patch.py +47 -0
  9. synth_ai/cli/_internal/validate_task_app.py +29 -0
  10. synth_ai/cli/agents/__init__.py +17 -0
  11. synth_ai/cli/agents/claude.py +77 -0
  12. synth_ai/cli/agents/codex.py +265 -0
  13. synth_ai/cli/agents/opencode.py +253 -0
  14. synth_ai/cli/commands/__init__.py +18 -0
  15. synth_ai/cli/commands/artifacts/__init__.py +13 -0
  16. synth_ai/cli/commands/artifacts/client.py +119 -0
  17. synth_ai/cli/commands/artifacts/config.py +57 -0
  18. synth_ai/cli/commands/artifacts/core.py +24 -0
  19. synth_ai/cli/commands/artifacts/download.py +188 -0
  20. synth_ai/cli/commands/artifacts/export.py +186 -0
  21. synth_ai/cli/commands/artifacts/list.py +156 -0
  22. synth_ai/cli/commands/artifacts/parsing.py +250 -0
  23. synth_ai/cli/commands/artifacts/show.py +336 -0
  24. synth_ai/cli/commands/demo/__init__.py +3 -0
  25. synth_ai/cli/commands/demo/core.py +153 -0
  26. synth_ai/cli/commands/eval/__init__.py +10 -0
  27. synth_ai/cli/commands/eval/config.py +338 -0
  28. synth_ai/cli/commands/eval/core.py +256 -0
  29. synth_ai/cli/commands/eval/runner.py +704 -0
  30. synth_ai/cli/commands/eval/validation.py +60 -0
  31. synth_ai/cli/commands/filter/__init__.py +12 -0
  32. synth_ai/cli/commands/filter/core.py +424 -0
  33. synth_ai/cli/commands/filter/errors.py +55 -0
  34. synth_ai/cli/commands/filter/validation.py +77 -0
  35. synth_ai/cli/commands/help/__init__.py +185 -0
  36. synth_ai/cli/commands/help/core.py +72 -0
  37. synth_ai/cli/commands/scan/__init__.py +19 -0
  38. synth_ai/cli/commands/scan/cloudflare_scanner.py +403 -0
  39. synth_ai/cli/commands/scan/core.py +344 -0
  40. synth_ai/cli/commands/scan/health_checker.py +242 -0
  41. synth_ai/cli/commands/scan/local_scanner.py +278 -0
  42. synth_ai/cli/commands/scan/models.py +83 -0
  43. synth_ai/cli/commands/smoke/__init__.py +7 -0
  44. synth_ai/cli/commands/smoke/core.py +1428 -0
  45. synth_ai/cli/commands/status/__init__.py +3 -0
  46. synth_ai/cli/commands/status/client.py +91 -0
  47. synth_ai/cli/commands/status/config.py +12 -0
  48. synth_ai/cli/commands/status/errors.py +11 -0
  49. synth_ai/cli/commands/status/subcommands/__init__.py +3 -0
  50. synth_ai/cli/commands/status/subcommands/config.py +13 -0
  51. synth_ai/cli/commands/status/subcommands/files.py +34 -0
  52. synth_ai/cli/commands/status/subcommands/jobs.py +51 -0
  53. synth_ai/cli/commands/status/subcommands/models.py +35 -0
  54. synth_ai/cli/commands/status/subcommands/runs.py +34 -0
  55. synth_ai/cli/commands/status/subcommands/session.py +77 -0
  56. synth_ai/cli/commands/status/subcommands/summary.py +39 -0
  57. synth_ai/cli/commands/status/subcommands/utils.py +41 -0
  58. synth_ai/cli/commands/status/utils.py +23 -0
  59. synth_ai/cli/commands/train/__init__.py +53 -0
  60. synth_ai/cli/commands/train/core.py +22 -0
  61. synth_ai/cli/commands/train/errors.py +117 -0
  62. synth_ai/cli/commands/train/judge_schemas.py +201 -0
  63. synth_ai/cli/commands/train/judge_validation.py +305 -0
  64. synth_ai/cli/commands/train/prompt_learning_validation.py +633 -0
  65. synth_ai/cli/commands/train/validation.py +392 -0
  66. synth_ai/cli/demo_apps/__init__.py +10 -0
  67. synth_ai/cli/demo_apps/core/__init__.py +28 -0
  68. synth_ai/{demos → cli/demo_apps}/core/cli.py +783 -441
  69. synth_ai/cli/demo_apps/crafter/__init__.py +1 -0
  70. synth_ai/cli/demo_apps/crafter/crafter_fft_4b.toml +55 -0
  71. synth_ai/cli/demo_apps/crafter/grpo_crafter_task_app.py +186 -0
  72. synth_ai/cli/demo_apps/crafter/rl_from_base_qwen4b.toml +74 -0
  73. synth_ai/cli/demo_apps/demo_registry.py +176 -0
  74. synth_ai/cli/demo_apps/demo_task_apps/__init__.py +7 -0
  75. synth_ai/{demos → cli/demo_apps}/demo_task_apps/core.py +75 -37
  76. synth_ai/cli/demo_apps/demo_task_apps/crafter/__init__.py +1 -0
  77. synth_ai/cli/demo_apps/demo_task_apps/crafter/configs/crafter_fft_4b.toml +53 -0
  78. synth_ai/cli/demo_apps/demo_task_apps/crafter/configs/rl_from_base_qwen4b.toml +73 -0
  79. synth_ai/cli/demo_apps/demo_task_apps/crafter/grpo_crafter_task_app.py +185 -0
  80. synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/_common.py +1 -2
  81. synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/app.py +2 -1
  82. synth_ai/cli/demo_apps/demo_task_apps/math/config.toml +73 -0
  83. synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/deploy_modal.py +3 -6
  84. synth_ai/cli/demo_apps/demo_task_apps/math/modal_task_app.py +738 -0
  85. synth_ai/cli/demo_apps/demo_task_apps/math/task_app_entry.py +39 -0
  86. synth_ai/cli/demo_apps/math/__init__.py +1 -0
  87. synth_ai/cli/demo_apps/math/_common.py +16 -0
  88. synth_ai/cli/demo_apps/math/app.py +38 -0
  89. synth_ai/cli/demo_apps/math/config.toml +75 -0
  90. synth_ai/cli/demo_apps/math/deploy_modal.py +54 -0
  91. synth_ai/cli/demo_apps/math/modal_task_app.py +698 -0
  92. synth_ai/cli/demo_apps/math/task_app_entry.py +53 -0
  93. synth_ai/cli/demo_apps/mipro/main.py +271 -0
  94. synth_ai/cli/demo_apps/mipro/task_app.py +922 -0
  95. synth_ai/cli/demo_apps/mipro/train_cfg.toml +92 -0
  96. synth_ai/cli/demos/__init__.py +12 -0
  97. synth_ai/cli/demos/demo.py +32 -0
  98. synth_ai/cli/demos/rl_demo.py +254 -0
  99. synth_ai/cli/deploy.py +216 -0
  100. synth_ai/cli/infra/__init__.py +14 -0
  101. synth_ai/cli/{balance.py → infra/balance.py} +16 -4
  102. synth_ai/cli/infra/mcp.py +35 -0
  103. synth_ai/cli/infra/modal_app.py +36 -0
  104. synth_ai/cli/infra/setup.py +69 -0
  105. synth_ai/cli/infra/status.py +16 -0
  106. synth_ai/cli/infra/turso.py +77 -0
  107. synth_ai/cli/lib/__init__.py +10 -0
  108. synth_ai/cli/lib/agents.py +76 -0
  109. synth_ai/cli/lib/apps/modal_app.py +101 -0
  110. synth_ai/cli/lib/apps/task_app.py +642 -0
  111. synth_ai/cli/lib/bin.py +39 -0
  112. synth_ai/cli/lib/env.py +375 -0
  113. synth_ai/cli/lib/errors.py +85 -0
  114. synth_ai/cli/lib/modal.py +315 -0
  115. synth_ai/cli/lib/plotting.py +126 -0
  116. synth_ai/cli/lib/prompt_args.py +39 -0
  117. synth_ai/cli/lib/prompts.py +284 -0
  118. synth_ai/cli/lib/sqld.py +122 -0
  119. synth_ai/cli/lib/task_app_discovery.py +884 -0
  120. synth_ai/cli/lib/task_app_env.py +295 -0
  121. synth_ai/cli/lib/train_cfgs.py +300 -0
  122. synth_ai/cli/lib/tunnel_records.py +207 -0
  123. synth_ai/cli/local/__init__.py +14 -0
  124. synth_ai/cli/local/experiment_queue/__init__.py +72 -0
  125. synth_ai/cli/local/experiment_queue/api_schemas.py +221 -0
  126. synth_ai/cli/local/experiment_queue/celery_app.py +208 -0
  127. synth_ai/cli/local/experiment_queue/config.py +128 -0
  128. synth_ai/cli/local/experiment_queue/config_utils.py +272 -0
  129. synth_ai/cli/local/experiment_queue/database.py +175 -0
  130. synth_ai/cli/local/experiment_queue/dispatcher.py +119 -0
  131. synth_ai/cli/local/experiment_queue/models.py +231 -0
  132. synth_ai/cli/local/experiment_queue/progress_info.py +160 -0
  133. synth_ai/cli/local/experiment_queue/results.py +373 -0
  134. synth_ai/cli/local/experiment_queue/schemas.py +131 -0
  135. synth_ai/cli/local/experiment_queue/service.py +344 -0
  136. synth_ai/cli/local/experiment_queue/status.py +372 -0
  137. synth_ai/cli/local/experiment_queue/status_tracker.py +360 -0
  138. synth_ai/cli/local/experiment_queue/tasks.py +1984 -0
  139. synth_ai/cli/local/experiment_queue/trace_storage.py +65 -0
  140. synth_ai/cli/local/experiment_queue/validation.py +157 -0
  141. synth_ai/cli/local/session/__init__.py +92 -0
  142. synth_ai/cli/local/session/client.py +383 -0
  143. synth_ai/cli/local/session/constants.py +63 -0
  144. synth_ai/cli/local/session/exceptions.py +105 -0
  145. synth_ai/cli/local/session/manager.py +139 -0
  146. synth_ai/cli/local/session/models.py +89 -0
  147. synth_ai/cli/local/session/query.py +110 -0
  148. synth_ai/cli/root.py +150 -108
  149. synth_ai/cli/task_apps/__init__.py +37 -0
  150. synth_ai/cli/task_apps/commands.py +3145 -0
  151. synth_ai/cli/task_apps/deploy.py +7 -0
  152. synth_ai/cli/task_apps/list.py +26 -0
  153. synth_ai/cli/task_apps/main.py +36 -0
  154. synth_ai/cli/task_apps/modal_serve.py +11 -0
  155. synth_ai/cli/task_apps/serve.py +11 -0
  156. synth_ai/cli/training/__init__.py +8 -0
  157. synth_ai/cli/training/train.py +5 -0
  158. synth_ai/cli/training/train_cfg.py +34 -0
  159. synth_ai/cli/{watch.py → training/watch.py} +13 -18
  160. synth_ai/cli/turso.py +52 -0
  161. synth_ai/cli/utils/__init__.py +8 -0
  162. synth_ai/cli/utils/experiments.py +235 -0
  163. synth_ai/cli/utils/queue.py +504 -0
  164. synth_ai/cli/{recent.py → utils/recent.py} +13 -7
  165. synth_ai/cli/{traces.py → utils/traces.py} +9 -5
  166. synth_ai/contracts/__init__.py +67 -0
  167. synth_ai/core/__init__.py +100 -0
  168. synth_ai/core/_utils/__init__.py +54 -0
  169. synth_ai/core/_utils/base_url.py +10 -0
  170. synth_ai/core/_utils/http.py +10 -0
  171. synth_ai/core/_utils/prompts.py +14 -0
  172. synth_ai/core/_utils/task_app_state.py +12 -0
  173. synth_ai/core/_utils/user_config.py +10 -0
  174. synth_ai/core/apps/common.py +116 -0
  175. synth_ai/core/auth.py +95 -0
  176. synth_ai/core/cfgs.py +240 -0
  177. synth_ai/core/config/__init__.py +16 -0
  178. synth_ai/core/config/base.py +168 -0
  179. synth_ai/core/config/resolver.py +89 -0
  180. synth_ai/core/env.py +231 -0
  181. synth_ai/core/errors.py +126 -0
  182. synth_ai/core/http.py +230 -0
  183. synth_ai/core/integrations/__init__.py +11 -0
  184. synth_ai/core/integrations/cloudflare.py +1710 -0
  185. synth_ai/core/integrations/mcp/__init__.py +6 -0
  186. synth_ai/core/integrations/mcp/__main__.py +8 -0
  187. synth_ai/core/integrations/mcp/claude.py +36 -0
  188. synth_ai/core/integrations/mcp/main.py +254 -0
  189. synth_ai/core/integrations/mcp/setup.py +100 -0
  190. synth_ai/core/integrations/modal.py +277 -0
  191. synth_ai/core/json.py +72 -0
  192. synth_ai/core/log_filter.py +99 -0
  193. synth_ai/core/logging.py +82 -0
  194. synth_ai/core/paths.py +107 -0
  195. synth_ai/core/pricing.py +109 -0
  196. synth_ai/core/process.py +233 -0
  197. synth_ai/core/ssl.py +25 -0
  198. synth_ai/core/storage/__init__.py +71 -0
  199. synth_ai/core/task_app_state.py +318 -0
  200. synth_ai/core/telemetry.py +282 -0
  201. synth_ai/{tracing_v3 → core/tracing_v3}/__init__.py +5 -1
  202. synth_ai/{tracing_v3 → core/tracing_v3}/abstractions.py +21 -4
  203. synth_ai/core/tracing_v3/config.py +229 -0
  204. synth_ai/core/tracing_v3/constants.py +21 -0
  205. synth_ai/{tracing_v3 → core/tracing_v3}/db_config.py +42 -29
  206. synth_ai/{tracing_v3 → core/tracing_v3}/decorators.py +80 -45
  207. synth_ai/{tracing_v3 → core/tracing_v3}/examples/basic_usage.py +15 -9
  208. synth_ai/{tracing_v3 → core/tracing_v3}/hooks.py +6 -4
  209. synth_ai/{tracing_v3 → core/tracing_v3}/llm_call_record_helpers.py +161 -61
  210. synth_ai/{tracing_v3 → core/tracing_v3}/migration_helper.py +1 -2
  211. synth_ai/{tracing_v3 → core/tracing_v3}/replica_sync.py +12 -7
  212. synth_ai/core/tracing_v3/serialization.py +130 -0
  213. synth_ai/{tracing_v3 → core/tracing_v3}/session_tracer.py +88 -21
  214. synth_ai/{tracing_v3 → core/tracing_v3}/storage/base.py +99 -12
  215. synth_ai/core/tracing_v3/storage/config.py +109 -0
  216. synth_ai/{tracing_v3 → core/tracing_v3}/storage/factory.py +11 -9
  217. synth_ai/{tracing_v3 → core/tracing_v3}/storage/utils.py +15 -11
  218. synth_ai/core/tracing_v3/trace_utils.py +326 -0
  219. synth_ai/core/tracing_v3/turso/__init__.py +12 -0
  220. synth_ai/core/tracing_v3/turso/daemon.py +278 -0
  221. synth_ai/{tracing_v3 → core/tracing_v3}/turso/models.py +7 -3
  222. synth_ai/core/tracing_v3/turso/native_manager.py +1385 -0
  223. synth_ai/{tracing_v3 → core/tracing_v3}/utils.py +5 -4
  224. synth_ai/core/urls.py +18 -0
  225. synth_ai/core/user_config.py +137 -0
  226. synth_ai/core/uvicorn.py +222 -0
  227. synth_ai/data/__init__.py +83 -0
  228. synth_ai/data/enums.py +123 -0
  229. synth_ai/data/rewards.py +152 -0
  230. synth_ai/data/traces.py +35 -0
  231. synth_ai/products/__init__.py +6 -0
  232. synth_ai/products/graph_evolve/__init__.py +46 -0
  233. synth_ai/products/graph_evolve/client.py +226 -0
  234. synth_ai/products/graph_evolve/config.py +591 -0
  235. synth_ai/products/graph_evolve/converters/__init__.py +42 -0
  236. synth_ai/products/graph_evolve/converters/openai_sft.py +484 -0
  237. synth_ai/products/graph_evolve/examples/hotpotqa/config.toml +109 -0
  238. synth_ai/products/graph_evolve/run.py +222 -0
  239. synth_ai/products/graph_gepa/__init__.py +23 -0
  240. synth_ai/products/graph_gepa/converters/__init__.py +19 -0
  241. synth_ai/products/graph_gepa/converters/openai_sft.py +29 -0
  242. synth_ai/sdk/__init__.py +123 -0
  243. synth_ai/sdk/api/__init__.py +1 -0
  244. synth_ai/sdk/api/models/supported.py +514 -0
  245. synth_ai/sdk/api/research_agent/__init__.py +296 -0
  246. synth_ai/sdk/api/train/__init__.py +85 -0
  247. synth_ai/sdk/api/train/builders.py +895 -0
  248. synth_ai/sdk/api/train/cli.py +2199 -0
  249. synth_ai/sdk/api/train/config_finder.py +267 -0
  250. synth_ai/sdk/api/train/configs/__init__.py +65 -0
  251. synth_ai/sdk/api/train/configs/prompt_learning.py +1706 -0
  252. synth_ai/sdk/api/train/configs/rl.py +187 -0
  253. synth_ai/sdk/api/train/configs/sft.py +99 -0
  254. synth_ai/sdk/api/train/configs/shared.py +81 -0
  255. synth_ai/sdk/api/train/context_learning.py +312 -0
  256. synth_ai/sdk/api/train/env_resolver.py +418 -0
  257. synth_ai/sdk/api/train/graph_validators.py +216 -0
  258. synth_ai/sdk/api/train/graphgen.py +984 -0
  259. synth_ai/sdk/api/train/graphgen_models.py +823 -0
  260. synth_ai/sdk/api/train/graphgen_validators.py +109 -0
  261. synth_ai/sdk/api/train/local_api.py +10 -0
  262. synth_ai/sdk/api/train/pollers.py +124 -0
  263. synth_ai/sdk/api/train/progress/__init__.py +97 -0
  264. synth_ai/sdk/api/train/progress/dataclasses.py +569 -0
  265. synth_ai/sdk/api/train/progress/events.py +326 -0
  266. synth_ai/sdk/api/train/progress/results.py +428 -0
  267. synth_ai/sdk/api/train/progress/tracker.py +641 -0
  268. synth_ai/sdk/api/train/prompt_learning.py +469 -0
  269. synth_ai/sdk/api/train/rl.py +441 -0
  270. synth_ai/sdk/api/train/sft.py +396 -0
  271. synth_ai/sdk/api/train/summary.py +522 -0
  272. synth_ai/sdk/api/train/supported_algos.py +147 -0
  273. synth_ai/sdk/api/train/task_app.py +351 -0
  274. synth_ai/sdk/api/train/utils.py +279 -0
  275. synth_ai/sdk/api/train/validators.py +2424 -0
  276. synth_ai/sdk/graphs/__init__.py +15 -0
  277. synth_ai/sdk/graphs/completions.py +570 -0
  278. synth_ai/{inference → sdk/inference}/__init__.py +0 -1
  279. synth_ai/sdk/inference/client.py +128 -0
  280. synth_ai/sdk/jobs/__init__.py +16 -0
  281. synth_ai/sdk/jobs/client.py +371 -0
  282. synth_ai/sdk/judging/__init__.py +14 -0
  283. synth_ai/sdk/judging/base.py +24 -0
  284. synth_ai/sdk/judging/client.py +40 -0
  285. synth_ai/sdk/judging/schemas.py +222 -0
  286. synth_ai/sdk/judging/types.py +42 -0
  287. synth_ai/sdk/learning/__init__.py +99 -0
  288. synth_ai/sdk/learning/algorithms.py +14 -0
  289. synth_ai/{learning → sdk/learning}/client.py +121 -30
  290. synth_ai/sdk/learning/config.py +5 -0
  291. synth_ai/{learning → sdk/learning}/constants.py +0 -2
  292. synth_ai/sdk/learning/context_learning_client.py +531 -0
  293. synth_ai/sdk/learning/context_learning_types.py +292 -0
  294. synth_ai/sdk/learning/ft_client.py +7 -0
  295. synth_ai/{learning → sdk/learning}/health.py +15 -9
  296. synth_ai/{learning → sdk/learning}/jobs.py +44 -47
  297. synth_ai/sdk/learning/prompt_extraction.py +334 -0
  298. synth_ai/sdk/learning/prompt_learning_client.py +455 -0
  299. synth_ai/sdk/learning/prompt_learning_types.py +186 -0
  300. synth_ai/{rl → sdk/learning/rl}/__init__.py +13 -8
  301. synth_ai/{learning/rl_client.py → sdk/learning/rl/client.py} +89 -77
  302. synth_ai/sdk/learning/rl/config.py +31 -0
  303. synth_ai/{rl → sdk/learning/rl}/contracts.py +5 -14
  304. synth_ai/{rl → sdk/learning/rl}/env_keys.py +45 -16
  305. synth_ai/sdk/learning/rl/secrets.py +13 -0
  306. synth_ai/sdk/learning/rl_client.py +5 -0
  307. synth_ai/sdk/learning/sft/__init__.py +29 -0
  308. synth_ai/sdk/learning/sft/client.py +95 -0
  309. synth_ai/sdk/learning/sft/config.py +270 -0
  310. synth_ai/sdk/learning/sft/data.py +698 -0
  311. synth_ai/sdk/learning/sse.py +57 -0
  312. synth_ai/sdk/learning/validators.py +52 -0
  313. synth_ai/sdk/localapi/__init__.py +40 -0
  314. synth_ai/sdk/localapi/apps/__init__.py +28 -0
  315. synth_ai/sdk/localapi/client.py +10 -0
  316. synth_ai/sdk/localapi/contracts.py +10 -0
  317. synth_ai/sdk/localapi/helpers.py +519 -0
  318. synth_ai/sdk/localapi/rollouts.py +87 -0
  319. synth_ai/sdk/localapi/server.py +29 -0
  320. synth_ai/sdk/localapi/template.py +70 -0
  321. synth_ai/sdk/streaming/__init__.py +35 -0
  322. synth_ai/sdk/streaming/config.py +94 -0
  323. synth_ai/sdk/streaming/handlers.py +1997 -0
  324. synth_ai/sdk/streaming/streamer.py +713 -0
  325. synth_ai/sdk/streaming/types.py +112 -0
  326. synth_ai/sdk/task/__init__.py +164 -0
  327. synth_ai/sdk/task/apps/__init__.py +169 -0
  328. synth_ai/sdk/task/auth.py +165 -0
  329. synth_ai/sdk/task/client.py +175 -0
  330. synth_ai/sdk/task/config.py +257 -0
  331. synth_ai/sdk/task/contracts.py +219 -0
  332. synth_ai/sdk/task/datasets.py +108 -0
  333. synth_ai/sdk/task/errors.py +50 -0
  334. synth_ai/sdk/task/health.py +34 -0
  335. synth_ai/sdk/task/in_process.py +1190 -0
  336. synth_ai/sdk/task/in_process_runner.py +314 -0
  337. synth_ai/sdk/task/inference_api.py +299 -0
  338. synth_ai/sdk/task/json.py +111 -0
  339. synth_ai/sdk/task/proxy.py +287 -0
  340. synth_ai/sdk/task/rubrics/__init__.py +55 -0
  341. synth_ai/sdk/task/rubrics/loaders.py +156 -0
  342. synth_ai/sdk/task/rubrics/models.py +57 -0
  343. synth_ai/sdk/task/rubrics/scoring.py +116 -0
  344. synth_ai/sdk/task/rubrics/strict.py +149 -0
  345. synth_ai/sdk/task/rubrics.py +219 -0
  346. synth_ai/sdk/task/server.py +631 -0
  347. synth_ai/sdk/task/trace_correlation_helpers.py +539 -0
  348. synth_ai/sdk/task/tracing_utils.py +95 -0
  349. synth_ai/sdk/task/validators.py +441 -0
  350. synth_ai/sdk/task/vendors.py +59 -0
  351. synth_ai/sdk/training/__init__.py +102 -0
  352. synth_ai/sdk/tunnels/__init__.py +83 -0
  353. synth_ai/sdk/tunnels/cleanup.py +83 -0
  354. synth_ai/sdk/tunnels/ports.py +120 -0
  355. synth_ai/utils/__init__.py +213 -0
  356. synth_ai-0.4.3.dist-info/METADATA +262 -0
  357. synth_ai-0.4.3.dist-info/RECORD +370 -0
  358. {synth_ai-0.2.8.dev2.dist-info → synth_ai-0.4.3.dist-info}/entry_points.txt +0 -1
  359. synth_ai/cli/calc.py +0 -69
  360. synth_ai/cli/demo.py +0 -144
  361. synth_ai/cli/legacy_root_backup.py +0 -470
  362. synth_ai/cli/man.py +0 -106
  363. synth_ai/cli/rl_demo.py +0 -202
  364. synth_ai/cli/status.py +0 -133
  365. synth_ai/config/base_url.py +0 -107
  366. synth_ai/core/experiment.py +0 -15
  367. synth_ai/core/system.py +0 -15
  368. synth_ai/demos/core/__init__.py +0 -1
  369. synth_ai/demos/demo_task_apps/__init__.py +0 -1
  370. synth_ai/demos/demo_task_apps/math/config.toml +0 -129
  371. synth_ai/demos/demo_task_apps/math/deploy_task_app.sh +0 -22
  372. synth_ai/demos/demo_task_apps/math/modal_task_app.py +0 -415
  373. synth_ai/environments/__init__.py +0 -31
  374. synth_ai/environments/environment/__init__.py +0 -1
  375. synth_ai/environments/environment/artifacts/__init__.py +0 -1
  376. synth_ai/environments/environment/artifacts/base.py +0 -52
  377. synth_ai/environments/environment/core.py +0 -67
  378. synth_ai/environments/environment/db/__init__.py +0 -1
  379. synth_ai/environments/environment/db/sqlite.py +0 -45
  380. synth_ai/environments/environment/registry.py +0 -233
  381. synth_ai/environments/environment/resources/sqlite.py +0 -45
  382. synth_ai/environments/environment/results.py +0 -1
  383. synth_ai/environments/environment/rewards/__init__.py +0 -1
  384. synth_ai/environments/environment/rewards/core.py +0 -29
  385. synth_ai/environments/environment/shared_engine.py +0 -26
  386. synth_ai/environments/environment/tools/__init__.py +0 -200
  387. synth_ai/environments/examples/__init__.py +0 -1
  388. synth_ai/environments/examples/bandit/__init__.py +0 -33
  389. synth_ai/environments/examples/bandit/engine.py +0 -294
  390. synth_ai/environments/examples/bandit/environment.py +0 -194
  391. synth_ai/environments/examples/bandit/taskset.py +0 -200
  392. synth_ai/environments/examples/crafter_classic/__init__.py +0 -8
  393. synth_ai/environments/examples/crafter_classic/agent_demos/analyze_semantic_words_markdown.py +0 -250
  394. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_comprehensive_evaluation.py +0 -59
  395. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_browser.py +0 -152
  396. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_config.toml +0 -24
  397. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_framework.py +0 -1194
  398. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/crafter_synth_config.toml +0 -56
  399. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_config_modal.toml +0 -32
  400. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_traces_sft_turso.py +0 -738
  401. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/kick_off_ft_modal.py +0 -384
  402. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_action_results.py +0 -53
  403. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_agent_actions.py +0 -178
  404. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_latest_run.py +0 -222
  405. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_lm_traces.py +0 -183
  406. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_no_rewards.py +0 -210
  407. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_trace_issue.py +0 -206
  408. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_db_schema.py +0 -49
  409. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_latest_results.py +0 -64
  410. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/debug_agent_responses.py +0 -88
  411. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/quick_trace_check.py +0 -77
  412. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/compare_experiments.py +0 -324
  413. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
  414. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/kick_off_ft_oai.py +0 -362
  415. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/multi_model_config.toml +0 -49
  416. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_enhanced_hooks.py +0 -332
  417. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_events.py +0 -97
  418. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_results.py +0 -217
  419. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_hook_storage.py +0 -87
  420. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_seeds.py +0 -88
  421. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/compare_seed_performance.py +0 -195
  422. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/custom_eval_pipelines.py +0 -400
  423. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/plot_hook_frequency.py +0 -195
  424. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/seed_analysis_summary.py +0 -56
  425. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/run_rollouts_for_models_and_compare_v3.py +0 -858
  426. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_quick_evaluation.py +0 -52
  427. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_react_agent.py +0 -874
  428. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_trace_evaluation.py +0 -1412
  429. synth_ai/environments/examples/crafter_classic/agent_demos/example_v3_usage.py +0 -216
  430. synth_ai/environments/examples/crafter_classic/agent_demos/old/compare_traces.py +0 -296
  431. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_comprehensive_evaluation.py +0 -58
  432. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_env_serialization.py +0 -464
  433. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_evaluation_browser.py +0 -152
  434. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_quick_evaluation.py +0 -51
  435. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_trace_evaluation.py +0 -1412
  436. synth_ai/environments/examples/crafter_classic/agent_demos/old/debug_player_loss.py +0 -112
  437. synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_service.py +0 -203
  438. synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_slowness.py +0 -305
  439. synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_by_difficulty.py +0 -126
  440. synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_example.py +0 -94
  441. synth_ai/environments/examples/crafter_classic/agent_demos/old/explore_saved_states.py +0 -142
  442. synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft.py +0 -26
  443. synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft_OLD.py +0 -984
  444. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_gemini.py +0 -724
  445. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_modal.py +0 -386
  446. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_metadata.py +0 -205
  447. synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_gemini.py +0 -150
  448. synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_modal.py +0 -283
  449. synth_ai/environments/examples/crafter_classic/agent_demos/old/prepare_vertex_ft.py +0 -280
  450. synth_ai/environments/examples/crafter_classic/agent_demos/old/profile_env_slowness.py +0 -456
  451. synth_ai/environments/examples/crafter_classic/agent_demos/old/replicate_issue.py +0 -166
  452. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_and_eval.py +0 -102
  453. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_comparison.py +0 -128
  454. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_qwen_rollouts.py +0 -655
  455. synth_ai/environments/examples/crafter_classic/agent_demos/old/trace_eval_OLD.py +0 -202
  456. synth_ai/environments/examples/crafter_classic/agent_demos/old/validate_openai_format.py +0 -166
  457. synth_ai/environments/examples/crafter_classic/config_logging.py +0 -111
  458. synth_ai/environments/examples/crafter_classic/debug_translation.py +0 -0
  459. synth_ai/environments/examples/crafter_classic/engine.py +0 -579
  460. synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +0 -64
  461. synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +0 -6
  462. synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +0 -75
  463. synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +0 -267
  464. synth_ai/environments/examples/crafter_classic/environment.py +0 -404
  465. synth_ai/environments/examples/crafter_classic/taskset.py +0 -233
  466. synth_ai/environments/examples/crafter_classic/trace_hooks_v3.py +0 -228
  467. synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +0 -299
  468. synth_ai/environments/examples/crafter_custom/__init__.py +0 -4
  469. synth_ai/environments/examples/crafter_custom/agent_demos/__init__.py +0 -1
  470. synth_ai/environments/examples/crafter_custom/agent_demos/trace_eval.py +0 -202
  471. synth_ai/environments/examples/crafter_custom/crafter/__init__.py +0 -7
  472. synth_ai/environments/examples/crafter_custom/crafter/config.py +0 -182
  473. synth_ai/environments/examples/crafter_custom/crafter/constants.py +0 -8
  474. synth_ai/environments/examples/crafter_custom/crafter/engine.py +0 -269
  475. synth_ai/environments/examples/crafter_custom/crafter/env.py +0 -262
  476. synth_ai/environments/examples/crafter_custom/crafter/objects.py +0 -417
  477. synth_ai/environments/examples/crafter_custom/crafter/recorder.py +0 -187
  478. synth_ai/environments/examples/crafter_custom/crafter/worldgen.py +0 -118
  479. synth_ai/environments/examples/crafter_custom/dataset_builder.py +0 -373
  480. synth_ai/environments/examples/crafter_custom/environment.py +0 -312
  481. synth_ai/environments/examples/crafter_custom/old/analyze_diamond_issue.py +0 -159
  482. synth_ai/environments/examples/crafter_custom/old/analyze_diamond_spawning.py +0 -158
  483. synth_ai/environments/examples/crafter_custom/old/compare_worlds.py +0 -71
  484. synth_ai/environments/examples/crafter_custom/old/dataset_stats.py +0 -105
  485. synth_ai/environments/examples/crafter_custom/old/diamond_spawning_summary.py +0 -119
  486. synth_ai/environments/examples/crafter_custom/old/example_dataset_usage.py +0 -52
  487. synth_ai/environments/examples/crafter_custom/run_dataset.py +0 -305
  488. synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +0 -156
  489. synth_ai/environments/examples/enron/art_helpers/local_email_db.py +0 -281
  490. synth_ai/environments/examples/enron/art_helpers/types_enron.py +0 -25
  491. synth_ai/environments/examples/enron/engine.py +0 -295
  492. synth_ai/environments/examples/enron/environment.py +0 -166
  493. synth_ai/environments/examples/enron/taskset.py +0 -112
  494. synth_ai/environments/examples/enron/units/keyword_stats.py +0 -112
  495. synth_ai/environments/examples/minigrid/__init__.py +0 -48
  496. synth_ai/environments/examples/minigrid/agent_demos/minigrid_evaluation_framework.py +0 -1188
  497. synth_ai/environments/examples/minigrid/agent_demos/minigrid_quick_evaluation.py +0 -48
  498. synth_ai/environments/examples/minigrid/agent_demos/minigrid_react_agent.py +0 -562
  499. synth_ai/environments/examples/minigrid/agent_demos/minigrid_trace_evaluation.py +0 -221
  500. synth_ai/environments/examples/minigrid/engine.py +0 -589
  501. synth_ai/environments/examples/minigrid/environment.py +0 -274
  502. synth_ai/environments/examples/minigrid/environment_mapping.py +0 -242
  503. synth_ai/environments/examples/minigrid/puzzle_loader.py +0 -417
  504. synth_ai/environments/examples/minigrid/taskset.py +0 -583
  505. synth_ai/environments/examples/nethack/__init__.py +0 -7
  506. synth_ai/environments/examples/nethack/achievements.py +0 -337
  507. synth_ai/environments/examples/nethack/agent_demos/nethack_evaluation_framework.py +0 -981
  508. synth_ai/environments/examples/nethack/agent_demos/nethack_quick_evaluation.py +0 -74
  509. synth_ai/environments/examples/nethack/agent_demos/nethack_react_agent.py +0 -831
  510. synth_ai/environments/examples/nethack/engine.py +0 -739
  511. synth_ai/environments/examples/nethack/environment.py +0 -256
  512. synth_ai/environments/examples/nethack/helpers/__init__.py +0 -41
  513. synth_ai/environments/examples/nethack/helpers/action_mapping.py +0 -301
  514. synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +0 -402
  515. synth_ai/environments/examples/nethack/helpers/observation_utils.py +0 -433
  516. synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +0 -200
  517. synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +0 -269
  518. synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +0 -308
  519. synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +0 -431
  520. synth_ai/environments/examples/nethack/taskset.py +0 -323
  521. synth_ai/environments/examples/red/__init__.py +0 -7
  522. synth_ai/environments/examples/red/agent_demos/__init__.py +0 -1
  523. synth_ai/environments/examples/red/config_logging.py +0 -110
  524. synth_ai/environments/examples/red/engine.py +0 -694
  525. synth_ai/environments/examples/red/engine_helpers/__init__.py +0 -1
  526. synth_ai/environments/examples/red/engine_helpers/memory_map.py +0 -28
  527. synth_ai/environments/examples/red/engine_helpers/reward_components.py +0 -276
  528. synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +0 -142
  529. synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +0 -57
  530. synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +0 -284
  531. synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +0 -150
  532. synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +0 -138
  533. synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +0 -57
  534. synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +0 -331
  535. synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +0 -121
  536. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +0 -559
  537. synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +0 -313
  538. synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +0 -148
  539. synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +0 -247
  540. synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +0 -368
  541. synth_ai/environments/examples/red/engine_helpers/state_extraction.py +0 -140
  542. synth_ai/environments/examples/red/environment.py +0 -238
  543. synth_ai/environments/examples/red/taskset.py +0 -79
  544. synth_ai/environments/examples/red/units/__init__.py +0 -1
  545. synth_ai/environments/examples/sokoban/__init__.py +0 -1
  546. synth_ai/environments/examples/sokoban/agent_demos/sokoban_full_eval.py +0 -899
  547. synth_ai/environments/examples/sokoban/engine.py +0 -678
  548. synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +0 -1
  549. synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +0 -657
  550. synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +0 -18
  551. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +0 -3
  552. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +0 -131
  553. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +0 -370
  554. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +0 -332
  555. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +0 -306
  556. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +0 -67
  557. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +0 -115
  558. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +0 -123
  559. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +0 -394
  560. synth_ai/environments/examples/sokoban/environment.py +0 -229
  561. synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +0 -440
  562. synth_ai/environments/examples/sokoban/puzzle_loader.py +0 -312
  563. synth_ai/environments/examples/sokoban/taskset.py +0 -428
  564. synth_ai/environments/examples/sokoban/units/astar_common.py +0 -95
  565. synth_ai/environments/examples/tictactoe/__init__.py +0 -1
  566. synth_ai/environments/examples/tictactoe/engine.py +0 -368
  567. synth_ai/environments/examples/tictactoe/environment.py +0 -240
  568. synth_ai/environments/examples/tictactoe/taskset.py +0 -215
  569. synth_ai/environments/examples/verilog/__init__.py +0 -10
  570. synth_ai/environments/examples/verilog/engine.py +0 -329
  571. synth_ai/environments/examples/verilog/environment.py +0 -350
  572. synth_ai/environments/examples/verilog/taskset.py +0 -420
  573. synth_ai/environments/examples/wordle/__init__.py +0 -29
  574. synth_ai/environments/examples/wordle/engine.py +0 -398
  575. synth_ai/environments/examples/wordle/environment.py +0 -159
  576. synth_ai/environments/examples/wordle/helpers/generate_instances_wordfreq.py +0 -75
  577. synth_ai/environments/examples/wordle/taskset.py +0 -230
  578. synth_ai/environments/reproducibility/core.py +0 -42
  579. synth_ai/environments/reproducibility/helpers.py +0 -0
  580. synth_ai/environments/reproducibility/tree.py +0 -364
  581. synth_ai/environments/service/app.py +0 -98
  582. synth_ai/environments/service/core_routes.py +0 -1020
  583. synth_ai/environments/service/external_registry.py +0 -56
  584. synth_ai/environments/service/registry.py +0 -9
  585. synth_ai/environments/stateful/__init__.py +0 -1
  586. synth_ai/environments/stateful/core.py +0 -163
  587. synth_ai/environments/stateful/engine.py +0 -21
  588. synth_ai/environments/stateful/state.py +0 -7
  589. synth_ai/environments/tasks/api.py +0 -19
  590. synth_ai/environments/tasks/core.py +0 -80
  591. synth_ai/environments/tasks/filters.py +0 -41
  592. synth_ai/environments/tasks/utils.py +0 -91
  593. synth_ai/environments/v0_observability/history.py +0 -3
  594. synth_ai/environments/v0_observability/log.py +0 -2
  595. synth_ai/evals/base.py +0 -15
  596. synth_ai/experimental/synth_oss.py +0 -446
  597. synth_ai/handshake.py +0 -63
  598. synth_ai/http.py +0 -26
  599. synth_ai/http_client.py +0 -104
  600. synth_ai/inference/client.py +0 -20
  601. synth_ai/install_sqld.sh +0 -40
  602. synth_ai/jobs/client.py +0 -246
  603. synth_ai/learning/__init__.py +0 -24
  604. synth_ai/learning/config.py +0 -43
  605. synth_ai/learning/filtering.py +0 -0
  606. synth_ai/learning/ft_client.py +0 -59
  607. synth_ai/learning/offline/dpo.py +0 -0
  608. synth_ai/learning/offline/providers.py +0 -7
  609. synth_ai/learning/offline/sft.py +0 -0
  610. synth_ai/learning/offline/shared.py +0 -0
  611. synth_ai/learning/online/grpo.py +0 -0
  612. synth_ai/learning/online/irft.py +0 -0
  613. synth_ai/learning/prompts/banking77_injection_eval.py +0 -168
  614. synth_ai/learning/prompts/gepa.py +0 -0
  615. synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +0 -213
  616. synth_ai/learning/prompts/mipro.py +0 -289
  617. synth_ai/learning/prompts/random_search.py +0 -246
  618. synth_ai/learning/prompts/run_mipro_banking77.py +0 -172
  619. synth_ai/learning/prompts/run_random_search_banking77.py +0 -324
  620. synth_ai/learning/sse.py +0 -58
  621. synth_ai/learning/validators.py +0 -48
  622. synth_ai/lm/__init__.py +0 -51
  623. synth_ai/lm/caching/constants.py +0 -6
  624. synth_ai/lm/caching/dbs.py +0 -0
  625. synth_ai/lm/caching/ephemeral.py +0 -102
  626. synth_ai/lm/caching/handler.py +0 -137
  627. synth_ai/lm/caching/initialize.py +0 -11
  628. synth_ai/lm/caching/persistent.py +0 -114
  629. synth_ai/lm/config.py +0 -110
  630. synth_ai/lm/constants.py +0 -32
  631. synth_ai/lm/core/__init__.py +0 -8
  632. synth_ai/lm/core/all.py +0 -73
  633. synth_ai/lm/core/exceptions.py +0 -7
  634. synth_ai/lm/core/main.py +0 -319
  635. synth_ai/lm/core/main_v3.py +0 -594
  636. synth_ai/lm/core/synth_models.py +0 -48
  637. synth_ai/lm/core/vendor_clients.py +0 -188
  638. synth_ai/lm/cost/__init__.py +0 -0
  639. synth_ai/lm/cost/monitor.py +0 -1
  640. synth_ai/lm/cost/statefulness.py +0 -1
  641. synth_ai/lm/injection.py +0 -80
  642. synth_ai/lm/overrides.py +0 -206
  643. synth_ai/lm/provider_support/__init__.py +0 -8
  644. synth_ai/lm/provider_support/anthropic.py +0 -972
  645. synth_ai/lm/provider_support/openai.py +0 -1139
  646. synth_ai/lm/provider_support/suppress_logging.py +0 -31
  647. synth_ai/lm/structured_outputs/__init__.py +0 -0
  648. synth_ai/lm/structured_outputs/handler.py +0 -440
  649. synth_ai/lm/structured_outputs/inject.py +0 -297
  650. synth_ai/lm/structured_outputs/rehabilitate.py +0 -185
  651. synth_ai/lm/tools/__init__.py +0 -3
  652. synth_ai/lm/tools/base.py +0 -172
  653. synth_ai/lm/unified_interface.py +0 -202
  654. synth_ai/lm/vendors/__init__.py +0 -0
  655. synth_ai/lm/vendors/base.py +0 -81
  656. synth_ai/lm/vendors/core/__init__.py +0 -0
  657. synth_ai/lm/vendors/core/anthropic_api.py +0 -387
  658. synth_ai/lm/vendors/core/gemini_api.py +0 -292
  659. synth_ai/lm/vendors/core/mistral_api.py +0 -322
  660. synth_ai/lm/vendors/core/openai_api.py +0 -225
  661. synth_ai/lm/vendors/core/synth_dev_api.py +0 -0
  662. synth_ai/lm/vendors/local/__init__.py +0 -0
  663. synth_ai/lm/vendors/local/ollama.py +0 -0
  664. synth_ai/lm/vendors/openai_standard.py +0 -780
  665. synth_ai/lm/vendors/openai_standard_responses.py +0 -256
  666. synth_ai/lm/vendors/retries.py +0 -22
  667. synth_ai/lm/vendors/supported/__init__.py +0 -0
  668. synth_ai/lm/vendors/supported/custom_endpoint.py +0 -417
  669. synth_ai/lm/vendors/supported/deepseek.py +0 -69
  670. synth_ai/lm/vendors/supported/grok.py +0 -75
  671. synth_ai/lm/vendors/supported/groq.py +0 -16
  672. synth_ai/lm/vendors/supported/ollama.py +0 -15
  673. synth_ai/lm/vendors/supported/openrouter.py +0 -74
  674. synth_ai/lm/vendors/supported/together.py +0 -11
  675. synth_ai/lm/vendors/synth_client.py +0 -808
  676. synth_ai/lm/warmup.py +0 -186
  677. synth_ai/rl/secrets.py +0 -19
  678. synth_ai/scripts/verify_rewards.py +0 -100
  679. synth_ai/task/__init__.py +0 -10
  680. synth_ai/task/contracts.py +0 -120
  681. synth_ai/task/health.py +0 -28
  682. synth_ai/task/validators.py +0 -12
  683. synth_ai/tracing/__init__.py +0 -30
  684. synth_ai/tracing_v1/__init__.py +0 -33
  685. synth_ai/tracing_v3/config.py +0 -84
  686. synth_ai/tracing_v3/storage/config.py +0 -62
  687. synth_ai/tracing_v3/turso/__init__.py +0 -25
  688. synth_ai/tracing_v3/turso/daemon.py +0 -144
  689. synth_ai/tracing_v3/turso/manager.py +0 -760
  690. synth_ai/v0/tracing/__init__.py +0 -0
  691. synth_ai/v0/tracing/abstractions.py +0 -224
  692. synth_ai/v0/tracing/base_client.py +0 -91
  693. synth_ai/v0/tracing/client_manager.py +0 -131
  694. synth_ai/v0/tracing/config.py +0 -142
  695. synth_ai/v0/tracing/context.py +0 -146
  696. synth_ai/v0/tracing/decorators.py +0 -682
  697. synth_ai/v0/tracing/events/__init__.py +0 -0
  698. synth_ai/v0/tracing/events/manage.py +0 -147
  699. synth_ai/v0/tracing/events/scope.py +0 -86
  700. synth_ai/v0/tracing/events/store.py +0 -228
  701. synth_ai/v0/tracing/immediate_client.py +0 -151
  702. synth_ai/v0/tracing/local.py +0 -18
  703. synth_ai/v0/tracing/log_client_base.py +0 -73
  704. synth_ai/v0/tracing/retry_queue.py +0 -186
  705. synth_ai/v0/tracing/trackers.py +0 -515
  706. synth_ai/v0/tracing/upload.py +0 -512
  707. synth_ai/v0/tracing/utils.py +0 -9
  708. synth_ai/v0/tracing_v1/__init__.py +0 -16
  709. synth_ai/v0/tracing_v1/abstractions.py +0 -224
  710. synth_ai/v0/tracing_v1/base_client.py +0 -91
  711. synth_ai/v0/tracing_v1/client_manager.py +0 -131
  712. synth_ai/v0/tracing_v1/config.py +0 -142
  713. synth_ai/v0/tracing_v1/context.py +0 -146
  714. synth_ai/v0/tracing_v1/decorators.py +0 -703
  715. synth_ai/v0/tracing_v1/events/__init__.py +0 -0
  716. synth_ai/v0/tracing_v1/events/manage.py +0 -147
  717. synth_ai/v0/tracing_v1/events/scope.py +0 -86
  718. synth_ai/v0/tracing_v1/events/store.py +0 -228
  719. synth_ai/v0/tracing_v1/immediate_client.py +0 -151
  720. synth_ai/v0/tracing_v1/local.py +0 -18
  721. synth_ai/v0/tracing_v1/log_client_base.py +0 -73
  722. synth_ai/v0/tracing_v1/retry_queue.py +0 -186
  723. synth_ai/v0/tracing_v1/trackers.py +0 -515
  724. synth_ai/v0/tracing_v1/upload.py +0 -527
  725. synth_ai/v0/tracing_v1/utils.py +0 -9
  726. synth_ai/zyk/__init__.py +0 -30
  727. synth_ai-0.2.8.dev2.dist-info/METADATA +0 -129
  728. synth_ai-0.2.8.dev2.dist-info/RECORD +0 -420
  729. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/__init__.py +0 -0
  730. /synth_ai/{lm/caching → core/apps}/__init__.py +0 -0
  731. /synth_ai/{tracing_v3 → core/tracing_v3}/lm_call_record_abstractions.py +0 -0
  732. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/__init__.py +0 -0
  733. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/exceptions.py +0 -0
  734. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/types.py +0 -0
  735. /synth_ai/{compound/cais.py → py.typed} +0 -0
  736. /synth_ai/{learning → sdk/learning}/core.py +0 -0
  737. /synth_ai/{learning → sdk/learning}/gateway.py +0 -0
  738. {synth_ai-0.2.8.dev2.dist-info → synth_ai-0.4.3.dist-info}/WHEEL +0 -0
  739. {synth_ai-0.2.8.dev2.dist-info → synth_ai-0.4.3.dist-info}/licenses/LICENSE +0 -0
  740. {synth_ai-0.2.8.dev2.dist-info → synth_ai-0.4.3.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Dict, List, Optional, Callable
4
- import os
5
3
  import time
4
+ from collections.abc import Callable
5
+ from contextlib import suppress
6
+ from typing import Any
6
7
 
7
- from ..http import AsyncHttpClient, HTTPError, sleep
8
+ from synth_ai.core._utils.http import AsyncHttpClient, HTTPError, sleep
9
+ from synth_ai.sdk.api.models.supported import (
10
+ UnsupportedModelError,
11
+ normalize_model_identifier,
12
+ )
8
13
 
9
14
 
10
15
  def _api_base(b: str) -> str:
@@ -13,12 +18,7 @@ def _api_base(b: str) -> str:
13
18
 
14
19
 
15
20
  class RlClient:
16
- """Lightweight RL client for provider-agnostic job control.
17
-
18
- Notes:
19
- - Uses learning/* for status/events/metrics and rl/* for creation/start.
20
- - Trainer endpoints are resolved server-side via trainer_id.
21
- """
21
+ """Lightweight RL client for provider-agnostic job control."""
22
22
 
23
23
  def __init__(self, base_url: str, api_key: str, *, timeout: float = 600.0) -> None:
24
24
  self._base_url = base_url.rstrip("/")
@@ -26,15 +26,24 @@ class RlClient:
26
26
  self._timeout = timeout
27
27
 
28
28
  async def resolve_trainer_start_url(self, trainer_id: str) -> str:
29
- """GET /api/rl/services/{id} → { training_start_url }"""
30
29
  path = f"/api/rl/services/{trainer_id}"
31
30
  async with AsyncHttpClient(self._base_url, self._api_key, timeout=30.0) as http:
32
31
  js = await http.get(path)
33
32
  if not isinstance(js, dict):
34
- raise HTTPError(status=500, url=path, message="invalid_service_response", body_snippet=str(js)[:200])
33
+ raise HTTPError(
34
+ status=500,
35
+ url=path,
36
+ message="invalid_service_response",
37
+ body_snippet=str(js)[:200],
38
+ )
35
39
  start_url = js.get("training_start_url")
36
40
  if not isinstance(start_url, str) or not start_url:
37
- raise HTTPError(status=500, url=path, message="missing_training_start_url", body_snippet=str(js)[:200])
41
+ raise HTTPError(
42
+ status=500,
43
+ url=path,
44
+ message="missing_training_start_url",
45
+ body_snippet=str(js)[:200],
46
+ )
38
47
  return start_url
39
48
 
40
49
  async def create_job(
@@ -42,15 +51,20 @@ class RlClient:
42
51
  *,
43
52
  model: str,
44
53
  task_app_url: str,
45
- trainer: Dict[str, Any],
46
- trainer_id: Optional[str] = None,
47
- job_config_id: Optional[str] = None,
48
- inline_config: Optional[Dict[str, Any]] = None,
49
- ) -> Dict[str, Any]:
54
+ trainer: dict[str, Any],
55
+ trainer_id: str | None = None,
56
+ job_config_id: str | None = None,
57
+ inline_config: dict[str, Any] | None = None,
58
+ ) -> dict[str, Any]:
59
+ try:
60
+ normalized_model = normalize_model_identifier(model)
61
+ except UnsupportedModelError as exc:
62
+ raise ValueError(str(exc)) from exc
63
+
50
64
  body = {
51
65
  "job_type": "rl",
52
66
  "data": {
53
- "model": model,
67
+ "model": normalized_model,
54
68
  "endpoint_base_url": task_app_url,
55
69
  **({"job_config_id": job_config_id} if job_config_id else {}),
56
70
  **({"config": inline_config} if inline_config else {}),
@@ -63,10 +77,15 @@ class RlClient:
63
77
  async with AsyncHttpClient(self._base_url, self._api_key, timeout=self._timeout) as http:
64
78
  js = await http.post_json(f"{_api_base(self._base_url)}/rl/jobs", json=body)
65
79
  if not isinstance(js, dict):
66
- raise HTTPError(status=500, url="/api/rl/jobs", message="invalid_create_response", body_snippet=str(js)[:200])
80
+ raise HTTPError(
81
+ status=500,
82
+ url="/api/rl/jobs",
83
+ message="invalid_create_response",
84
+ body_snippet=str(js)[:200],
85
+ )
67
86
  return js
68
87
 
69
- async def start_job_if_supported(self, job_id: str) -> Optional[Dict[str, Any]]:
88
+ async def start_job_if_supported(self, job_id: str) -> dict[str, Any] | None:
70
89
  path = f"{_api_base(self._base_url)}/rl/jobs/{job_id}/start"
71
90
  try:
72
91
  async with AsyncHttpClient(self._base_url, self._api_key, timeout=30.0) as http:
@@ -76,22 +95,26 @@ class RlClient:
76
95
  return None
77
96
  raise
78
97
 
79
- async def get_job(self, job_id: str) -> Dict[str, Any]:
98
+ async def get_job(self, job_id: str) -> dict[str, Any]:
80
99
  async with AsyncHttpClient(self._base_url, self._api_key, timeout=30.0) as http:
81
100
  return await http.get(f"{_api_base(self._base_url)}/learning/jobs/{job_id}")
82
101
 
83
- async def get_events(self, job_id: str, *, since_seq: int = 0, limit: int = 200) -> List[Dict[str, Any]]:
102
+ async def get_events(
103
+ self, job_id: str, *, since_seq: int = 0, limit: int = 200
104
+ ) -> list[dict[str, Any]]:
84
105
  params = {"since_seq": since_seq, "limit": limit}
85
106
  async with AsyncHttpClient(self._base_url, self._api_key, timeout=30.0) as http:
86
107
  try:
87
- js = await http.get(f"{_api_base(self._base_url)}/learning/jobs/{job_id}/events", params=params)
108
+ js = await http.get(
109
+ f"{_api_base(self._base_url)}/learning/jobs/{job_id}/events",
110
+ params=params,
111
+ headers={"accept": "application/json"},
112
+ )
88
113
  except HTTPError as he:
89
- try:
114
+ with suppress(Exception):
90
115
  print(
91
116
  f"[poll] events HTTPError status={he.status} url={he.url} since_seq={since_seq} body={(he.body_snippet or '')[:200]}"
92
117
  )
93
- except Exception:
94
- pass
95
118
  raise
96
119
  if isinstance(js, dict):
97
120
  evs = js.get("events") or js.get("data")
@@ -99,10 +122,14 @@ class RlClient:
99
122
  return evs
100
123
  return []
101
124
 
102
- async def get_metrics(self, job_id: str, *, after_step: int = -1, limit: int = 200) -> List[Dict[str, Any]]:
125
+ async def get_metrics(
126
+ self, job_id: str, *, after_step: int = -1, limit: int = 200
127
+ ) -> list[dict[str, Any]]:
103
128
  params = {"after_step": after_step, "limit": limit}
104
129
  async with AsyncHttpClient(self._base_url, self._api_key, timeout=30.0) as http:
105
- js = await http.get(f"{_api_base(self._base_url)}/learning/jobs/{job_id}/metrics", params=params)
130
+ js = await http.get(
131
+ f"{_api_base(self._base_url)}/learning/jobs/{job_id}/metrics", params=params
132
+ )
106
133
  if isinstance(js, dict) and isinstance(js.get("points"), list):
107
134
  return js["points"]
108
135
  return []
@@ -115,73 +142,65 @@ class RlClient:
115
142
  max_seconds: float | None = None,
116
143
  empty_polls_threshold: int = 5,
117
144
  startup_deadline_s: int = 45,
118
- on_event: Optional[Callable[[Dict[str, Any]], None]] = None,
119
- on_metric: Optional[Callable[[Dict[str, Any]], None]] = None,
120
- ) -> Dict[str, Any]:
121
- last_seq_by_stream: Dict[str, int] = {}
122
- events_job_id: Optional[str] = None
123
- last_status: Optional[str] = None
124
- last_step_by_name: Dict[str, int] = {}
145
+ on_event: Callable[[dict[str, Any]], None] | None = None,
146
+ on_metric: Callable[[dict[str, Any]], None] | None = None,
147
+ ) -> dict[str, Any]:
148
+ last_seq_by_stream: dict[str, int] = {}
149
+ events_job_id: str | None = None
150
+ last_status: str | None = None
151
+ last_step_by_name: dict[str, int] = {}
125
152
  empty_polls = 0
126
153
  saw_any_event = False
127
154
  start_t = time.time()
128
155
  terminal = {"succeeded", "failed", "cancelled", "canceled", "error", "completed"}
129
156
 
130
157
  while True:
131
- status_data: Optional[Dict[str, Any]] = None
158
+ status_data: dict[str, Any] | None = None
132
159
  try:
133
160
  status_data = await self.get_job(job_id)
134
161
  except Exception:
135
162
  status_data = None
136
163
  if status_data is None:
137
- try:
164
+ with suppress(Exception):
138
165
  print(f"[poll] get_job returned None base={self._base_url} job_id={job_id}")
139
- except Exception:
140
- pass
141
166
  status = str((status_data or {}).get("status") or "").lower()
142
167
  if status_data:
143
168
  linked = status_data.get("linked_job_id")
144
169
  if isinstance(linked, str) and linked and linked != events_job_id:
145
170
  events_job_id = linked
146
- try:
171
+ with suppress(Exception):
147
172
  print(f"[poll] discovered linked_job_id stream={events_job_id}")
148
- except Exception:
149
- pass
150
173
  if status and status != last_status:
151
174
  last_status = status
152
- # Status transitions only to avoid log spam
153
175
  if on_event:
154
- try:
176
+ with suppress(Exception):
155
177
  on_event({"type": "rl.status", "message": status})
156
- except Exception:
157
- pass
158
178
 
159
- # Events
160
179
  stream_ids = [job_id]
161
180
  if events_job_id and events_job_id not in stream_ids:
162
181
  stream_ids.append(events_job_id)
163
- try:
164
- print(f"[poll] streams={stream_ids} intervals={interval_seconds}s since_map={last_seq_by_stream} empty_polls={empty_polls}")
165
- except Exception:
166
- pass
182
+ with suppress(Exception):
183
+ print(
184
+ f"[poll] streams={stream_ids} intervals={interval_seconds}s since_map={last_seq_by_stream} empty_polls={empty_polls}"
185
+ )
167
186
  total_events_this_cycle = 0
168
187
  terminal_event_seen = False
169
- terminal_event_status: Optional[str] = None
188
+ terminal_event_status: str | None = None
170
189
  for ev_id in stream_ids:
171
190
  since = last_seq_by_stream.get(ev_id, 0)
172
191
  try:
173
192
  events = await self.get_events(ev_id, since_seq=since, limit=200)
174
193
  except HTTPError as he:
175
- try:
176
- print(f"[poll] get_events error status={he.status} url={he.url} since={since} body={(he.body_snippet or '')[:200]}")
177
- except Exception:
178
- pass
194
+ with suppress(Exception):
195
+ print(
196
+ f"[poll] get_events error status={he.status} url={he.url} since={since} body={(he.body_snippet or '')[:200]}"
197
+ )
179
198
  events = []
180
199
  except Exception as e:
181
- try:
182
- print(f"[poll] get_events unexpected error ev_id={ev_id} since={since} err={type(e).__name__}: {e}")
183
- except Exception:
184
- pass
200
+ with suppress(Exception):
201
+ print(
202
+ f"[poll] get_events unexpected error ev_id={ev_id} since={since} err={type(e).__name__}: {e}"
203
+ )
185
204
  events = []
186
205
  total_events_this_cycle += len(events)
187
206
  if events:
@@ -192,10 +211,8 @@ class RlClient:
192
211
  continue
193
212
  last_seq_by_stream[ev_id] = seq_val
194
213
  if on_event:
195
- try:
214
+ with suppress(Exception):
196
215
  on_event(e)
197
- except Exception:
198
- pass
199
216
  et = str(e.get("type") or e.get("event_type") or "").lower()
200
217
  if et in ("rl.job.completed", "workflow.completed", "rl.train.completed"):
201
218
  terminal_event_seen = True
@@ -204,7 +221,6 @@ class RlClient:
204
221
  terminal_event_seen = True
205
222
  terminal_event_status = "failed"
206
223
 
207
- # Metrics
208
224
  try:
209
225
  after = max(last_step_by_name.values()) if last_step_by_name else -1
210
226
  points = await self.get_metrics(job_id, after_step=after, limit=200)
@@ -215,10 +231,8 @@ class RlClient:
215
231
  continue
216
232
  last_step_by_name[name] = step
217
233
  if on_metric:
218
- try:
234
+ with suppress(Exception):
219
235
  on_metric(p)
220
- except Exception:
221
- pass
222
236
  except Exception:
223
237
  pass
224
238
 
@@ -232,25 +246,23 @@ class RlClient:
232
246
  else:
233
247
  empty_polls = 0
234
248
  if empty_polls >= max(1, int(empty_polls_threshold)):
235
- try:
249
+ with suppress(Exception):
236
250
  print(
237
251
  f"[poll] threshold hit: empty_polls={empty_polls} >= {empty_polls_threshold} streams={stream_ids} last_seq_map={last_seq_by_stream}"
238
252
  )
239
- except Exception:
240
- pass
241
- raise AssertionError(f"No new events detected for {empty_polls_threshold} consecutive polls. Check event ingestion.")
253
+ raise AssertionError(
254
+ f"No new events detected for {empty_polls_threshold} consecutive polls. Check event ingestion."
255
+ )
242
256
 
243
257
  if not saw_any_event and (time.time() - start_t) > int(startup_deadline_s):
244
- try:
258
+ with suppress(Exception):
245
259
  print(
246
260
  f"[poll] startup window exceeded: {startup_deadline_s}s base={self._base_url} job={job_id} streams={stream_ids} last_seq_map={last_seq_by_stream}"
247
261
  )
248
- except Exception:
249
- pass
250
- raise AssertionError(f"No events observed within startup window ({startup_deadline_s}s). Investigate event streaming.")
262
+ raise AssertionError(
263
+ f"No events observed within startup window ({startup_deadline_s}s). Investigate event streaming."
264
+ )
251
265
 
252
266
  await sleep(interval_seconds)
253
267
  if max_seconds is not None and (time.time() - start_t) >= max_seconds:
254
268
  raise TimeoutError(f"Polling timed out after {max_seconds}s for job {job_id}")
255
-
256
-
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+
7
+ def _ensure_positive(value: Any, *, name: str) -> int:
8
+ try:
9
+ ivalue = int(value)
10
+ except (TypeError, ValueError) as exc:
11
+ raise ValueError(f"{name} must be an integer") from exc
12
+ if ivalue < 1:
13
+ raise ValueError(f"{name} must be >= 1")
14
+ return ivalue
15
+
16
+
17
+ @dataclass(slots=True)
18
+ class RLJobConfig:
19
+ model: str
20
+ task_app_url: str
21
+ trainer_id: str
22
+ batch_size: int = 1
23
+ group_size: int = 2
24
+ job_config_id: str | None = None
25
+ inline_config: dict[str, Any] | None = None
26
+
27
+ def trainer_dict(self) -> dict[str, Any]:
28
+ return {
29
+ "batch_size": _ensure_positive(self.batch_size, name="trainer.batch_size"),
30
+ "group_size": _ensure_positive(self.group_size, name="trainer.group_size"),
31
+ }
@@ -1,20 +1,15 @@
1
- from __future__ import annotations
1
+ """Compatibility re-export for rollout contracts used by RL tooling."""
2
2
 
3
- """
4
- Compatibility layer: re-export Task App rollout contracts from synth_ai.task.contracts
5
- so existing imports continue to work while consolidating under synth_ai.task.
6
- """
3
+ from __future__ import annotations
7
4
 
8
- from synth_ai.task.contracts import (
5
+ from synth_ai.sdk.task.contracts import (
9
6
  RolloutEnvSpec,
7
+ RolloutMetrics,
10
8
  RolloutPolicySpec,
11
9
  RolloutRecordConfig,
12
- RolloutSafetyConfig,
13
10
  RolloutRequest,
14
- RolloutStep,
15
- RolloutTrajectory,
16
- RolloutMetrics,
17
11
  RolloutResponse,
12
+ RolloutSafetyConfig,
18
13
  )
19
14
 
20
15
  __all__ = [
@@ -23,10 +18,6 @@ __all__ = [
23
18
  "RolloutRecordConfig",
24
19
  "RolloutSafetyConfig",
25
20
  "RolloutRequest",
26
- "RolloutStep",
27
- "RolloutTrajectory",
28
21
  "RolloutMetrics",
29
22
  "RolloutResponse",
30
23
  ]
31
-
32
-
@@ -1,12 +1,12 @@
1
- from __future__ import annotations
1
+ """Helpers for uploading Environment credentials to the backend."""
2
2
 
3
- """Helpers for uploading RL environment credentials to the backend."""
3
+ from __future__ import annotations
4
4
 
5
5
  import base64
6
6
  import binascii
7
7
  import json
8
- from typing import Any, Dict
9
8
  import os
9
+ from typing import Any
10
10
 
11
11
  import requests
12
12
  from nacl.public import PublicKey, SealedBox
@@ -18,14 +18,12 @@ _ALGORITHM = "libsodium.sealedbox.v1"
18
18
 
19
19
 
20
20
  def encrypt_for_backend(pubkey_b64: str, secret: str | bytes) -> str:
21
- """Encrypt ``secret`` for storage by the backend using libsodium sealed boxes."""
22
-
23
21
  if not isinstance(pubkey_b64, str) or not pubkey_b64.strip():
24
22
  raise ValueError("public key must be a non-empty base64 string")
25
23
 
26
24
  try:
27
25
  key_bytes = base64.b64decode(pubkey_b64, validate=True)
28
- except binascii.Error as exc: # pragma: no cover - defensive guard
26
+ except binascii.Error as exc:
29
27
  raise ValueError("public key must be base64-encoded") from exc
30
28
 
31
29
  if len(key_bytes) != 32:
@@ -35,7 +33,7 @@ def encrypt_for_backend(pubkey_b64: str, secret: str | bytes) -> str:
35
33
  secret_bytes = secret.encode("utf-8")
36
34
  elif isinstance(secret, bytes):
37
35
  secret_bytes = secret
38
- else: # pragma: no cover - type guard
36
+ else:
39
37
  raise TypeError("secret must be str or bytes")
40
38
 
41
39
  if not secret_bytes:
@@ -52,20 +50,17 @@ def setup_environment_api_key(
52
50
  token: str | None = None,
53
51
  *,
54
52
  timeout: float = 15.0,
55
- ) -> Dict[str, Any]:
56
- """Upload an ENVIRONMENT_API_KEY to the backend."""
57
-
53
+ ) -> dict[str, Any]:
58
54
  backend = backend_base.rstrip("/")
59
55
  if not backend:
60
56
  raise ValueError("backend_base must be provided")
61
57
  if not synth_api_key:
62
58
  raise ValueError("synth_api_key must be provided")
63
59
 
64
- # Require caller-provided plaintext. If not provided, read from ENVIRONMENT_API_KEY.
65
60
  plaintext = token if token is not None else os.getenv("ENVIRONMENT_API_KEY", "").strip()
66
61
  if not plaintext:
67
62
  raise ValueError("ENVIRONMENT_API_KEY must be set (or pass token=...) to upload")
68
- if not isinstance(plaintext, str): # pragma: no cover - defensive guard
63
+ if not isinstance(plaintext, str):
69
64
  raise TypeError("token must be a string")
70
65
 
71
66
  token_bytes = plaintext.encode("utf-8")
@@ -81,7 +76,7 @@ def setup_environment_api_key(
81
76
 
82
77
  try:
83
78
  doc = response.json()
84
- except ValueError as exc: # pragma: no cover - backend invariant
79
+ except ValueError as exc:
85
80
  raise RuntimeError("backend returned invalid JSON for public key") from exc
86
81
 
87
82
  if not isinstance(doc, dict):
@@ -91,17 +86,51 @@ def setup_environment_api_key(
91
86
  if not isinstance(pubkey, str) or not pubkey:
92
87
  raise RuntimeError("backend response missing public_key")
93
88
 
94
- # The backend currently returns a single algorithm identifier; keep a guard in
95
- # case future versions change the value and we need to surface that to callers.
96
89
  alg = doc.get("alg")
97
90
  if alg is not None and alg != _ALGORITHM:
98
91
  raise RuntimeError(f"unsupported sealed box algorithm: {alg}")
99
92
 
93
+ # Diagnostics: safe previews and hashes to correlate with backend logs
94
+ try:
95
+ import hashlib as _hash
96
+
97
+ pk_bytes = base64.b64decode(pubkey, validate=True)
98
+ pk_sha256 = _hash.sha256(pk_bytes).hexdigest()
99
+ print(
100
+ f"[env-keys] public_key: b64_len={len(pubkey)} sha256={pk_sha256} head={pubkey[:16]} tail={pubkey[-16:]}"
101
+ )
102
+ _plen = len(plaintext)
103
+ _ppref = (plaintext[:6] + "…") if _plen > 10 else plaintext
104
+ _psuf = ("…" + plaintext[-4:]) if _plen > 10 else ""
105
+ _has_ws = any(ch.isspace() for ch in plaintext)
106
+ print(
107
+ f"[env-keys] plaintext: len={_plen} preview={_ppref}{_psuf} has_ws={bool(_has_ws)}"
108
+ )
109
+ except Exception:
110
+ pass
111
+
100
112
  ciphertext_b64 = encrypt_for_backend(pubkey, token_bytes)
101
113
 
102
114
  body = {"name": "ENVIRONMENT_API_KEY", "ciphertext_b64": ciphertext_b64}
103
115
  post_url = f"{backend}/api/v1/env-keys"
104
- response2 = requests.post(post_url, headers={**headers, "Content-Type": "application/json"}, json=body, timeout=timeout)
116
+ # Ciphertext diagnostics
117
+ try:
118
+ import hashlib as _hash
119
+
120
+ _ct_bytes = base64.b64decode(ciphertext_b64, validate=True)
121
+ _ct_sha = _hash.sha256(_ct_bytes).hexdigest()
122
+ print(
123
+ f"[env-keys] ciphertext: b64_len={len(ciphertext_b64)} sha256={_ct_sha} head={ciphertext_b64[:16]} tail={ciphertext_b64[-16:]}"
124
+ )
125
+ except Exception:
126
+ pass
127
+
128
+ response2 = requests.post(
129
+ post_url,
130
+ headers={**headers, "Content-Type": "application/json"},
131
+ json=body,
132
+ timeout=timeout,
133
+ )
105
134
  _raise_with_detail(response2)
106
135
 
107
136
  try:
@@ -0,0 +1,13 @@
1
+ """Helpers for generating Environment credentials."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import secrets
6
+
7
+ __all__ = ["mint_environment_api_key"]
8
+
9
+
10
+ def mint_environment_api_key() -> str:
11
+ """Mint a random ENVIRONMENT_API_KEY value."""
12
+
13
+ return secrets.token_hex(32)
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from .rl.client import RlClient
4
+
5
+ __all__ = ["RlClient"]
@@ -0,0 +1,29 @@
1
+ from .client import FtClient
2
+ from .data import (
3
+ SFTDataError,
4
+ SFTExample,
5
+ SFTMessage,
6
+ SFTToolCall,
7
+ SFTToolDefinition,
8
+ coerce_example,
9
+ collect_sft_jsonl_errors,
10
+ iter_sft_examples,
11
+ load_jsonl,
12
+ parse_jsonl_line,
13
+ validate_jsonl_or_raise,
14
+ )
15
+
16
+ __all__ = [
17
+ "FtClient",
18
+ "SFTDataError",
19
+ "SFTExample",
20
+ "SFTMessage",
21
+ "SFTToolCall",
22
+ "SFTToolDefinition",
23
+ "collect_sft_jsonl_errors",
24
+ "coerce_example",
25
+ "iter_sft_examples",
26
+ "load_jsonl",
27
+ "parse_jsonl_line",
28
+ "validate_jsonl_or_raise",
29
+ ]
@@ -0,0 +1,95 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from synth_ai.core._utils.http import AsyncHttpClient, HTTPError
7
+
8
+ from .config import prepare_sft_job_payload
9
+ from .data import validate_jsonl_or_raise
10
+
11
+
12
+ class FtClient:
13
+ def __init__(self, base_url: str, api_key: str, *, timeout: float = 30.0) -> None:
14
+ self._base_url = base_url.rstrip("/")
15
+ self._api_key = api_key
16
+ self._timeout = timeout
17
+
18
+ async def upload_training_file(self, path: str | Path, *, purpose: str = "fine-tune") -> str:
19
+ p = Path(path)
20
+ if p.suffix.lower() == ".jsonl" and purpose == "fine-tune":
21
+ validate_jsonl_or_raise(p, min_messages=2)
22
+ content = p.read_bytes()
23
+ async with AsyncHttpClient(self._base_url, self._api_key, timeout=self._timeout) as http:
24
+ data = {"purpose": purpose}
25
+ files = {"file": (p.name, content, _infer_content_type(p.name))}
26
+ js = await http.post_multipart("/api/learning/files", data=data, files=files)
27
+ if not isinstance(js, dict) or "id" not in js:
28
+ raise HTTPError(
29
+ status=500,
30
+ url="/api/learning/files",
31
+ message="invalid_upload_response",
32
+ body_snippet=str(js)[:200],
33
+ )
34
+ return str(js["id"])
35
+
36
+ async def create_sft_job(
37
+ self,
38
+ *,
39
+ model: str,
40
+ training_file_id: str,
41
+ hyperparameters: dict[str, Any],
42
+ metadata: dict[str, Any] | None = None,
43
+ ) -> dict[str, Any]:
44
+ body = prepare_sft_job_payload(
45
+ model=model,
46
+ training_file=training_file_id,
47
+ hyperparameters=hyperparameters,
48
+ metadata=metadata,
49
+ training_type="sft_offline",
50
+ training_file_field="training_file_id",
51
+ require_training_file=True,
52
+ )
53
+ async with AsyncHttpClient(self._base_url, self._api_key, timeout=self._timeout) as http:
54
+ return await http.post_json("/api/learning/jobs", json=body)
55
+
56
+ async def start_job(self, job_id: str) -> dict[str, Any]:
57
+ async with AsyncHttpClient(self._base_url, self._api_key, timeout=self._timeout) as http:
58
+ return await http.post_json(f"/api/learning/jobs/{job_id}/start", json={})
59
+
60
+ async def get_job_status(self, job_id: str) -> dict[str, Any]:
61
+ """Get the status and details of an SFT job.
62
+
63
+ Args:
64
+ job_id: The job ID to check
65
+
66
+ Returns:
67
+ Job details including status, progress, etc.
68
+ """
69
+ async with AsyncHttpClient(self._base_url, self._api_key, timeout=self._timeout) as http:
70
+ return await http.get(f"/api/learning/jobs/{job_id}")
71
+
72
+ async def list_jobs(self, *, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]:
73
+ """List SFT jobs.
74
+
75
+ Args:
76
+ limit: Max number of jobs to return
77
+ offset: Pagination offset
78
+
79
+ Returns:
80
+ List of job objects
81
+ """
82
+ async with AsyncHttpClient(self._base_url, self._api_key, timeout=self._timeout) as http:
83
+ result = await http.get(f"/api/learning/jobs?limit={limit}&offset={offset}")
84
+ return result if isinstance(result, list) else result.get("jobs", [])
85
+
86
+
87
+ def _infer_content_type(filename: str) -> str:
88
+ name = filename.lower()
89
+ if name.endswith(".jsonl"):
90
+ return "application/jsonl"
91
+ if name.endswith(".json"):
92
+ return "application/json"
93
+ if name.endswith(".txt"):
94
+ return "text/plain"
95
+ return "application/octet-stream"