synth-ai 0.2.9.dev5__py3-none-any.whl → 0.2.9.dev6__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 synth-ai might be problematic. Click here for more details.

Files changed (351) hide show
  1. examples/__init__.py +16 -0
  2. examples/crafter_debug_render.py +23 -17
  3. examples/qwen_coder/README.md +102 -0
  4. examples/qwen_coder/_shared.py +113 -0
  5. examples/qwen_coder/configs/coder_lora_30b.toml +61 -0
  6. examples/qwen_coder/configs/coder_lora_4b.toml +57 -0
  7. examples/qwen_coder/configs/coder_lora_small.toml +58 -0
  8. examples/qwen_coder/generate_dataset.py +98 -0
  9. examples/qwen_coder/infer_ft_smoke.py +64 -0
  10. examples/qwen_coder/infer_prod_proxy.py +73 -0
  11. examples/qwen_coder/infer_via_synth.py +87 -0
  12. examples/qwen_coder/scripts/infer_coder.sh +18 -0
  13. examples/qwen_coder/scripts/train_coder_30b.sh +21 -0
  14. examples/qwen_coder/sft_full_17b.py +103 -0
  15. examples/qwen_coder/sft_lora_30b.py +110 -0
  16. examples/qwen_coder/subset_jsonl.py +38 -0
  17. examples/qwen_coder/validate_jsonl.py +59 -0
  18. examples/rl/configs/eval_base_qwen.toml +1 -1
  19. examples/rl/configs/rl_from_base_qwen17.toml +1 -1
  20. examples/rl/download_dataset.py +26 -10
  21. examples/rl/run_eval.py +53 -52
  22. examples/rl/run_rl_and_save.py +29 -12
  23. examples/rl/task_app/math_single_step.py +180 -41
  24. examples/rl/task_app/math_task_app.py +14 -6
  25. examples/sft/README.md +139 -0
  26. examples/sft/configs/crafter_fft_qwen0p6b.toml +44 -0
  27. examples/sft/configs/crafter_lora_qwen0p6b.toml +45 -0
  28. examples/sft/evaluate.py +117 -0
  29. examples/sft/export_dataset.py +117 -0
  30. examples/sft/generate_traces.py +162 -0
  31. examples/swe/__init__.py +12 -0
  32. examples/swe/task_app/README.md +105 -0
  33. examples/swe/task_app/__init__.py +2 -0
  34. examples/swe/task_app/grpo_swe_mini.py +571 -0
  35. examples/swe/task_app/grpo_swe_mini_task_app.py +136 -0
  36. examples/swe/task_app/hosted/README.md +173 -0
  37. examples/swe/task_app/hosted/__init__.py +5 -0
  38. examples/swe/task_app/hosted/branching.py +143 -0
  39. examples/swe/task_app/hosted/environment_routes.py +1289 -0
  40. examples/swe/task_app/hosted/envs/__init__.py +1 -0
  41. examples/swe/task_app/hosted/envs/crafter/__init__.py +6 -0
  42. examples/swe/task_app/hosted/envs/crafter/app.py +1 -0
  43. examples/swe/task_app/hosted/envs/crafter/environment.py +522 -0
  44. examples/swe/task_app/hosted/envs/crafter/policy.py +478 -0
  45. examples/swe/task_app/hosted/envs/crafter/react_agent.py +108 -0
  46. examples/swe/task_app/hosted/envs/crafter/shared.py +305 -0
  47. examples/swe/task_app/hosted/envs/crafter/tools.py +47 -0
  48. examples/swe/task_app/hosted/envs/mini_swe/__init__.py +8 -0
  49. examples/swe/task_app/hosted/envs/mini_swe/environment.py +1164 -0
  50. examples/swe/task_app/hosted/envs/mini_swe/policy.py +355 -0
  51. examples/swe/task_app/hosted/envs/mini_swe/shared.py +83 -0
  52. examples/swe/task_app/hosted/envs/mini_swe/tools.py +96 -0
  53. examples/swe/task_app/hosted/hosted_app.py +204 -0
  54. examples/swe/task_app/hosted/inference/__init__.py +5 -0
  55. examples/swe/task_app/hosted/inference/openai_client.py +618 -0
  56. examples/swe/task_app/hosted/main.py +100 -0
  57. examples/swe/task_app/hosted/policy_routes.py +1079 -0
  58. examples/swe/task_app/hosted/registry.py +195 -0
  59. examples/swe/task_app/hosted/rollout.py +1869 -0
  60. examples/swe/task_app/hosted/storage/__init__.py +5 -0
  61. examples/swe/task_app/hosted/storage/volume.py +211 -0
  62. examples/swe/task_app/hosted/test_agents.py +161 -0
  63. examples/swe/task_app/hosted/test_service.py +137 -0
  64. examples/swe/task_app/hosted/utils.py +62 -0
  65. examples/vlm/README.md +68 -0
  66. examples/vlm/configs/crafter_vlm_gpt4o.toml +44 -0
  67. examples/vlm/crafter_image_only_agent.py +207 -0
  68. examples/vlm/crafter_openai_vlm_agent.py +277 -0
  69. examples/vlm/filter_image_rows.py +63 -0
  70. examples/vlm/run_crafter_vlm_benchmark.py +316 -0
  71. examples/warming_up_to_rl/analyze_trace_db.py +12 -10
  72. examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +11 -1
  73. examples/warming_up_to_rl/export_trace_sft.py +218 -36
  74. examples/warming_up_to_rl/groq_test.py +15 -8
  75. examples/warming_up_to_rl/manage_secrets.py +29 -25
  76. examples/warming_up_to_rl/readme.md +9 -2
  77. examples/warming_up_to_rl/run_eval.py +137 -61
  78. examples/warming_up_to_rl/run_fft_and_save.py +131 -60
  79. examples/warming_up_to_rl/run_local_rollout.py +88 -39
  80. examples/warming_up_to_rl/run_local_rollout_modal.py +114 -28
  81. examples/warming_up_to_rl/run_local_rollout_parallel.py +81 -20
  82. examples/warming_up_to_rl/run_local_rollout_traced.py +126 -23
  83. examples/warming_up_to_rl/run_rl_and_save.py +35 -12
  84. examples/warming_up_to_rl/run_rollout_remote.py +44 -19
  85. examples/warming_up_to_rl/task_app/README.md +6 -2
  86. examples/warming_up_to_rl/task_app/grpo_crafter.py +319 -57
  87. examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +11 -30
  88. examples/warming_up_to_rl/task_app/synth_envs_hosted/__init__.py +1 -1
  89. examples/warming_up_to_rl/task_app/synth_envs_hosted/branching.py +9 -11
  90. examples/warming_up_to_rl/task_app/synth_envs_hosted/environment_routes.py +137 -182
  91. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/__init__.py +1 -1
  92. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/__init__.py +1 -1
  93. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/app.py +1 -1
  94. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +150 -57
  95. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +105 -69
  96. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +19 -7
  97. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +45 -42
  98. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/tools.py +1 -1
  99. examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +47 -45
  100. examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/__init__.py +1 -1
  101. examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +198 -92
  102. examples/warming_up_to_rl/task_app/synth_envs_hosted/main.py +0 -2
  103. examples/warming_up_to_rl/task_app/synth_envs_hosted/policy_routes.py +361 -263
  104. examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py +21 -23
  105. examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py +394 -274
  106. examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/__init__.py +1 -1
  107. examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +56 -62
  108. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py +1 -0
  109. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py +6 -15
  110. examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +4 -3
  111. synth/__init__.py +14 -0
  112. synth_ai/__init__.py +20 -4
  113. synth_ai/api/models/supported.py +376 -0
  114. synth_ai/api/train/builders.py +157 -26
  115. synth_ai/api/train/cli.py +213 -57
  116. synth_ai/api/train/config_finder.py +65 -5
  117. synth_ai/api/train/env_resolver.py +33 -15
  118. synth_ai/api/train/pollers.py +13 -4
  119. synth_ai/api/train/supported_algos.py +139 -0
  120. synth_ai/api/train/task_app.py +5 -3
  121. synth_ai/api/train/utils.py +33 -48
  122. synth_ai/cli/__init__.py +19 -4
  123. synth_ai/cli/_modal_wrapper.py +28 -0
  124. synth_ai/cli/_typer_patch.py +49 -0
  125. synth_ai/cli/balance.py +2 -3
  126. synth_ai/cli/calc.py +1 -1
  127. synth_ai/cli/demo.py +21 -6
  128. synth_ai/cli/recent.py +2 -2
  129. synth_ai/cli/rl_demo.py +77 -17
  130. synth_ai/cli/root.py +116 -39
  131. synth_ai/cli/status.py +2 -2
  132. synth_ai/cli/task_apps.py +1699 -259
  133. synth_ai/cli/traces.py +7 -4
  134. synth_ai/cli/turso.py +73 -0
  135. synth_ai/cli/watch.py +12 -18
  136. synth_ai/core/experiment.py +0 -2
  137. synth_ai/demo_registry.py +68 -31
  138. synth_ai/demos/core/cli.py +516 -194
  139. synth_ai/demos/demo_task_apps/__init__.py +3 -3
  140. synth_ai/demos/demo_task_apps/core.py +64 -28
  141. synth_ai/demos/demo_task_apps/crafter/configs/crafter_fft_4b.toml +2 -3
  142. synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +37 -30
  143. synth_ai/demos/demo_task_apps/math/_common.py +1 -2
  144. synth_ai/demos/demo_task_apps/math/app.py +2 -1
  145. synth_ai/demos/demo_task_apps/math/deploy_modal.py +3 -6
  146. synth_ai/demos/demo_task_apps/math/modal_task_app.py +183 -82
  147. synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -2
  148. synth_ai/environments/examples/bandit/engine.py +12 -4
  149. synth_ai/environments/examples/bandit/taskset.py +4 -4
  150. synth_ai/environments/examples/crafter_classic/environment.py +76 -1
  151. synth_ai/environments/reproducibility/tree.py +5 -6
  152. synth_ai/environments/service/app.py +11 -12
  153. synth_ai/environments/service/core_routes.py +10 -9
  154. synth_ai/environments/stateful/engine.py +1 -1
  155. synth_ai/environments/tasks/core.py +1 -0
  156. synth_ai/environments/tasks/filters.py +5 -6
  157. synth_ai/environments/tasks/utils.py +4 -5
  158. synth_ai/evals/base.py +0 -2
  159. synth_ai/handshake.py +11 -9
  160. synth_ai/http.py +1 -1
  161. synth_ai/http_client.py +43 -11
  162. synth_ai/inference/__init__.py +0 -2
  163. synth_ai/inference/client.py +20 -6
  164. synth_ai/jobs/client.py +103 -78
  165. synth_ai/learning/__init__.py +41 -6
  166. synth_ai/learning/algorithms.py +14 -0
  167. synth_ai/learning/client.py +121 -29
  168. synth_ai/learning/config.py +2 -40
  169. synth_ai/learning/constants.py +0 -2
  170. synth_ai/learning/ft_client.py +4 -56
  171. synth_ai/learning/health.py +13 -7
  172. synth_ai/learning/jobs.py +43 -47
  173. synth_ai/{rl → learning/rl}/__init__.py +14 -5
  174. synth_ai/learning/rl/client.py +267 -0
  175. synth_ai/learning/rl/config.py +31 -0
  176. synth_ai/{rl → learning/rl}/contracts.py +5 -10
  177. synth_ai/{rl → learning/rl}/env_keys.py +45 -16
  178. synth_ai/learning/rl/secrets.py +13 -0
  179. synth_ai/learning/rl_client.py +2 -253
  180. synth_ai/learning/sft/__init__.py +29 -0
  181. synth_ai/learning/sft/client.py +68 -0
  182. synth_ai/learning/sft/config.py +270 -0
  183. synth_ai/learning/sft/data.py +295 -0
  184. synth_ai/learning/sse.py +25 -26
  185. synth_ai/learning/validators.py +25 -24
  186. synth_ai/lm/__init__.py +21 -47
  187. synth_ai/task/__init__.py +26 -27
  188. synth_ai/task/apps/__init__.py +18 -19
  189. synth_ai/task/auth.py +35 -23
  190. synth_ai/task/client.py +15 -13
  191. synth_ai/task/contracts.py +37 -35
  192. synth_ai/task/datasets.py +9 -6
  193. synth_ai/task/errors.py +11 -10
  194. synth_ai/task/health.py +17 -11
  195. synth_ai/task/json.py +58 -24
  196. synth_ai/task/proxy.py +15 -14
  197. synth_ai/task/rubrics.py +22 -15
  198. synth_ai/task/server.py +43 -17
  199. synth_ai/task/tracing_utils.py +12 -7
  200. synth_ai/task/validators.py +0 -1
  201. synth_ai/task/vendors.py +5 -7
  202. synth_ai/tracing_v3/__init__.py +2 -0
  203. synth_ai/tracing_v3/abstractions.py +21 -4
  204. synth_ai/tracing_v3/db_config.py +26 -1
  205. synth_ai/tracing_v3/decorators.py +18 -15
  206. synth_ai/tracing_v3/examples/basic_usage.py +3 -2
  207. synth_ai/tracing_v3/hooks.py +6 -4
  208. synth_ai/tracing_v3/llm_call_record_helpers.py +6 -6
  209. synth_ai/tracing_v3/replica_sync.py +1 -0
  210. synth_ai/tracing_v3/session_tracer.py +63 -16
  211. synth_ai/tracing_v3/storage/base.py +89 -1
  212. synth_ai/tracing_v3/storage/config.py +21 -8
  213. synth_ai/tracing_v3/storage/factory.py +10 -8
  214. synth_ai/tracing_v3/storage/utils.py +4 -2
  215. synth_ai/tracing_v3/turso/daemon.py +7 -2
  216. synth_ai/tracing_v3/turso/models.py +5 -2
  217. synth_ai/tracing_v3/turso/native_manager.py +1173 -0
  218. synth_ai/tracing_v3/utils.py +4 -3
  219. synth_ai/v0/api/__init__.py +8 -0
  220. synth_ai/v0/api/models/__init__.py +8 -0
  221. synth_ai/v0/api/models/supported.py +8 -0
  222. synth_ai/v0/config/__init__.py +15 -0
  223. synth_ai/v0/config/base_url.py +12 -0
  224. synth_ai/v0/lm/__init__.py +51 -0
  225. synth_ai/{lm → v0/lm}/caching/ephemeral.py +3 -5
  226. synth_ai/{lm → v0/lm}/caching/handler.py +4 -4
  227. synth_ai/{lm → v0/lm}/caching/initialize.py +1 -1
  228. synth_ai/{lm → v0/lm}/caching/persistent.py +1 -1
  229. synth_ai/{lm → v0/lm}/config.py +6 -1
  230. synth_ai/{lm → v0/lm}/core/all.py +9 -9
  231. synth_ai/{lm → v0/lm}/core/exceptions.py +0 -2
  232. synth_ai/{lm → v0/lm}/core/main.py +19 -7
  233. synth_ai/{lm → v0/lm}/core/main_v3.py +10 -10
  234. synth_ai/{lm → v0/lm}/core/synth_models.py +2 -15
  235. synth_ai/{lm → v0/lm}/core/vendor_clients.py +6 -4
  236. synth_ai/{lm → v0/lm}/overrides.py +4 -4
  237. synth_ai/{lm → v0/lm}/provider_support/anthropic.py +4 -4
  238. synth_ai/{lm → v0/lm}/provider_support/openai.py +5 -5
  239. synth_ai/{lm → v0/lm}/structured_outputs/handler.py +5 -5
  240. synth_ai/{lm → v0/lm}/structured_outputs/rehabilitate.py +1 -1
  241. synth_ai/{lm → v0/lm}/vendors/core/anthropic_api.py +16 -16
  242. synth_ai/{lm → v0/lm}/vendors/core/gemini_api.py +5 -5
  243. synth_ai/{lm → v0/lm}/vendors/core/mistral_api.py +5 -5
  244. synth_ai/{lm → v0/lm}/vendors/core/openai_api.py +12 -10
  245. synth_ai/{lm → v0/lm}/vendors/openai_standard.py +11 -9
  246. synth_ai/{lm → v0/lm}/vendors/openai_standard_responses.py +8 -5
  247. synth_ai/{lm → v0/lm}/vendors/supported/custom_endpoint.py +4 -6
  248. synth_ai/{lm → v0/lm}/vendors/supported/deepseek.py +2 -2
  249. synth_ai/{lm → v0/lm}/vendors/supported/grok.py +2 -2
  250. synth_ai/{lm → v0/lm}/vendors/supported/groq.py +1 -1
  251. synth_ai/{lm → v0/lm}/vendors/supported/ollama.py +1 -1
  252. synth_ai/{lm → v0/lm}/vendors/supported/openrouter.py +3 -3
  253. synth_ai/{lm → v0/lm}/vendors/supported/together.py +1 -1
  254. synth_ai/{lm → v0/lm}/vendors/synth_client.py +38 -11
  255. synth_ai/v0/tracing/upload.py +32 -135
  256. synth_ai/v0/tracing_v3/__init__.py +10 -0
  257. synth_ai/v0/tracing_v3/abstractions.py +3 -0
  258. synth_ai/v0/tracing_v3/decorators.py +3 -0
  259. synth_ai/v0/tracing_v3/llm_call_record_helpers.py +3 -0
  260. synth_ai/v0/tracing_v3/session_tracer.py +3 -0
  261. synth_ai-0.2.9.dev6.dist-info/METADATA +191 -0
  262. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/RECORD +291 -262
  263. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/top_level.txt +1 -0
  264. examples/common_old/backend.py +0 -21
  265. examples/evals_old/README.md +0 -98
  266. examples/evals_old/__init__.py +0 -6
  267. examples/evals_old/compare_models.py +0 -1037
  268. examples/evals_old/example_log.md +0 -145
  269. examples/evals_old/run_demo.sh +0 -126
  270. examples/evals_old/trace_analysis.py +0 -270
  271. examples/finetuning_old/_backup_synth_qwen/config.toml +0 -29
  272. examples/finetuning_old/_backup_synth_qwen/example_log.md +0 -324
  273. examples/finetuning_old/_backup_synth_qwen/filter_traces.py +0 -60
  274. examples/finetuning_old/_backup_synth_qwen/filter_traces_achievements.py +0 -239
  275. examples/finetuning_old/_backup_synth_qwen/purge_v3_traces.py +0 -109
  276. examples/finetuning_old/_backup_synth_qwen/react_agent_lm.py +0 -1924
  277. examples/finetuning_old/_backup_synth_qwen/readme.md +0 -49
  278. examples/finetuning_old/_backup_synth_qwen/run_crafter_qwen4b.py +0 -114
  279. examples/finetuning_old/_backup_synth_qwen/run_demo.sh +0 -195
  280. examples/finetuning_old/_backup_synth_qwen/sft_kickoff.py +0 -118
  281. examples/finetuning_old/synth_qwen_v1/README.md +0 -68
  282. examples/finetuning_old/synth_qwen_v1/filter_traces.py +0 -60
  283. examples/finetuning_old/synth_qwen_v1/filter_traces_achievements.py +0 -239
  284. examples/finetuning_old/synth_qwen_v1/finetune.py +0 -46
  285. examples/finetuning_old/synth_qwen_v1/hello_ft_model.py +0 -71
  286. examples/finetuning_old/synth_qwen_v1/infer.py +0 -37
  287. examples/finetuning_old/synth_qwen_v1/poll.py +0 -44
  288. examples/finetuning_old/synth_qwen_v1/prepare_data.py +0 -35
  289. examples/finetuning_old/synth_qwen_v1/purge_v3_traces.py +0 -109
  290. examples/finetuning_old/synth_qwen_v1/react_agent_lm.py +0 -1932
  291. examples/finetuning_old/synth_qwen_v1/run_crafter_sft_job.py +0 -207
  292. examples/finetuning_old/synth_qwen_v1/run_ft_job.py +0 -232
  293. examples/finetuning_old/synth_qwen_v1/upload_data.py +0 -34
  294. examples/finetuning_old/synth_qwen_v1/util.py +0 -147
  295. examples/rl_old/task_app.py +0 -962
  296. examples/warming_up_to_rl/old/event_rewards.md +0 -234
  297. examples/warming_up_to_rl/old/notes.md +0 -73
  298. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_traces_sft_turso.py +0 -738
  299. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
  300. synth_ai/experimental/synth_oss.py +0 -446
  301. synth_ai/install_sqld.sh +0 -40
  302. synth_ai/learning/filtering.py +0 -0
  303. synth_ai/learning/offline/dpo.py +0 -0
  304. synth_ai/learning/offline/providers.py +0 -7
  305. synth_ai/learning/offline/sft.py +0 -0
  306. synth_ai/learning/offline/shared.py +0 -0
  307. synth_ai/learning/online/grpo.py +0 -0
  308. synth_ai/learning/online/irft.py +0 -0
  309. synth_ai/learning/prompts/banking77_injection_eval.py +0 -168
  310. synth_ai/learning/prompts/gepa.py +0 -0
  311. synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +0 -213
  312. synth_ai/learning/prompts/mipro.py +0 -289
  313. synth_ai/learning/prompts/random_search.py +0 -246
  314. synth_ai/learning/prompts/run_mipro_banking77.py +0 -172
  315. synth_ai/learning/prompts/run_random_search_banking77.py +0 -324
  316. synth_ai/rl/secrets.py +0 -19
  317. synth_ai/scripts/verify_rewards.py +0 -100
  318. synth_ai/tracing/__init__.py +0 -30
  319. synth_ai/tracing_v1/__init__.py +0 -33
  320. synth_ai/tracing_v3/turso/__init__.py +0 -25
  321. synth_ai/tracing_v3/turso/manager.py +0 -774
  322. synth_ai/zyk/__init__.py +0 -30
  323. synth_ai-0.2.9.dev5.dist-info/METADATA +0 -131
  324. /synth_ai/{lm → v0/lm}/caching/__init__.py +0 -0
  325. /synth_ai/{lm → v0/lm}/caching/constants.py +0 -0
  326. /synth_ai/{lm → v0/lm}/caching/dbs.py +0 -0
  327. /synth_ai/{lm → v0/lm}/constants.py +0 -0
  328. /synth_ai/{lm → v0/lm}/core/__init__.py +0 -0
  329. /synth_ai/{lm → v0/lm}/cost/__init__.py +0 -0
  330. /synth_ai/{lm → v0/lm}/cost/monitor.py +0 -0
  331. /synth_ai/{lm → v0/lm}/cost/statefulness.py +0 -0
  332. /synth_ai/{lm → v0/lm}/injection.py +0 -0
  333. /synth_ai/{lm → v0/lm}/provider_support/__init__.py +0 -0
  334. /synth_ai/{lm → v0/lm}/provider_support/suppress_logging.py +0 -0
  335. /synth_ai/{lm → v0/lm}/structured_outputs/__init__.py +0 -0
  336. /synth_ai/{lm → v0/lm}/structured_outputs/inject.py +0 -0
  337. /synth_ai/{lm → v0/lm}/tools/__init__.py +0 -0
  338. /synth_ai/{lm → v0/lm}/tools/base.py +0 -0
  339. /synth_ai/{lm → v0/lm}/unified_interface.py +0 -0
  340. /synth_ai/{lm → v0/lm}/vendors/__init__.py +0 -0
  341. /synth_ai/{lm → v0/lm}/vendors/base.py +0 -0
  342. /synth_ai/{lm → v0/lm}/vendors/core/__init__.py +0 -0
  343. /synth_ai/{lm → v0/lm}/vendors/core/synth_dev_api.py +0 -0
  344. /synth_ai/{lm → v0/lm}/vendors/local/__init__.py +0 -0
  345. /synth_ai/{lm → v0/lm}/vendors/local/ollama.py +0 -0
  346. /synth_ai/{lm → v0/lm}/vendors/retries.py +0 -0
  347. /synth_ai/{lm → v0/lm}/vendors/supported/__init__.py +0 -0
  348. /synth_ai/{lm → v0/lm}/warmup.py +0 -0
  349. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/WHEEL +0 -0
  350. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/entry_points.txt +0 -0
  351. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.9.dev6.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Mapping
3
4
  from dataclasses import dataclass
4
- from typing import Any, Mapping
5
+ from datetime import datetime
6
+ from typing import Any
5
7
 
6
8
  import click
7
9
 
@@ -15,7 +17,9 @@ class PollOutcome:
15
17
 
16
18
 
17
19
  class JobPoller:
18
- def __init__(self, base_url: str, api_key: str, *, interval: float = 5.0, timeout: float = 3600.0) -> None:
20
+ def __init__(
21
+ self, base_url: str, api_key: str, *, interval: float = 5.0, timeout: float = 3600.0
22
+ ) -> None:
19
23
  self.base_url = ensure_api_base(base_url)
20
24
  self.api_key = api_key
21
25
  self.interval = interval
@@ -35,9 +39,14 @@ class JobPoller:
35
39
  while elapsed <= self.timeout:
36
40
  try:
37
41
  resp = http_get(f"{self.base_url}{path}", headers=self._headers())
38
- info = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
42
+ info = (
43
+ resp.json()
44
+ if resp.headers.get("content-type", "").startswith("application/json")
45
+ else {}
46
+ )
39
47
  status = (info.get("status") or info.get("state") or "").lower()
40
- click.echo(f"[poll] {elapsed:.0f}s status={status}")
48
+ timestamp = datetime.now().strftime("%H:%M:%S")
49
+ click.echo(f"[poll] {timestamp} {elapsed:.0f}s status={status}")
41
50
  if status in {"succeeded", "failed", "cancelled", "canceled", "completed"}:
42
51
  break
43
52
  except Exception as exc: # pragma: no cover - network failures
@@ -0,0 +1,139 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from dataclasses import dataclass
5
+
6
+ from synth_ai.api.models.supported import (
7
+ RL_SUPPORTED_MODELS,
8
+ SFT_SUPPORTED_MODELS,
9
+ training_modes_for_model,
10
+ )
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class AlgorithmSpec:
15
+ algo_type: str
16
+ method: str
17
+ variety: str
18
+ label: str # Human readable identifier (e.g. "RL / GSPO")
19
+ required_training_mode: str # Expected training mode on the model record (e.g. "rl", "sft")
20
+
21
+
22
+ def _normalize(value: object) -> str:
23
+ if value is None:
24
+ return ""
25
+ return str(value).strip().lower()
26
+
27
+ RL_ALGORITHM_MODEL_IDS: tuple[str, ...] = tuple(sorted(RL_SUPPORTED_MODELS))
28
+ RL_ALGORITHM_MODEL_SET: frozenset[str] = frozenset(RL_ALGORITHM_MODEL_IDS)
29
+
30
+ SFT_ALGORITHM_MODEL_IDS: tuple[str, ...] = tuple(sorted(SFT_SUPPORTED_MODELS))
31
+ SFT_ALGORITHM_MODEL_SET: frozenset[str] = frozenset(SFT_ALGORITHM_MODEL_IDS)
32
+
33
+
34
+ SUPPORTED_ALGORITHMS: tuple[AlgorithmSpec, ...] = (
35
+ AlgorithmSpec(
36
+ "online", "policy_gradient", "gspo", "online policy_gradient / gspo", "rl"
37
+ ),
38
+ AlgorithmSpec(
39
+ "offline", "supervised_finetune", "fft", "offline supervised_finetune / fft", "sft"
40
+ ),
41
+ AlgorithmSpec("offline", "sft", "fft", "offline sft / fft", "sft"),
42
+ # Accept explicit LoRA variety for SFT as a first-class alias of FFT SFT.
43
+ # This allows configs to declare intent with variety="lora" while still
44
+ # using SFT training mode; actual adapter selection is driven by [training].
45
+ AlgorithmSpec("offline", "sft", "lora", "offline sft / lora", "sft"),
46
+ )
47
+
48
+ _SUPPORTED_LOOKUP = {
49
+ (spec.algo_type, spec.method, spec.variety): spec for spec in SUPPORTED_ALGORITHMS
50
+ }
51
+
52
+
53
+ class AlgorithmValidationError(ValueError):
54
+ """Raised when an algorithm block contains unsupported combinations."""
55
+
56
+
57
+ def validate_algorithm_config(
58
+ algorithm_block: Mapping[str, object] | None,
59
+ *,
60
+ expected_family: str | None = None,
61
+ ) -> AlgorithmSpec:
62
+ """Validate the [algorithm] section of a training config.
63
+
64
+ Args:
65
+ algorithm_block: Parsed mapping from the TOML config.
66
+ expected_family: Optional expected family label ("rl" or "sft").
67
+
68
+ Returns:
69
+ The matched AlgorithmSpec describing the supported combination.
70
+
71
+ Raises:
72
+ AlgorithmValidationError: if the combination is missing or unsupported.
73
+ """
74
+
75
+ if algorithm_block is None:
76
+ raise AlgorithmValidationError("Missing required [algorithm] section in config.")
77
+ if not isinstance(algorithm_block, Mapping):
78
+ raise AlgorithmValidationError("[algorithm] section must be a mapping/object.")
79
+
80
+ algo_type = _normalize(algorithm_block.get("type"))
81
+ method = _normalize(algorithm_block.get("method"))
82
+ variety = _normalize(algorithm_block.get("variety"))
83
+
84
+ key = (algo_type, method, variety)
85
+ spec = _SUPPORTED_LOOKUP.get(key)
86
+ if spec is None:
87
+ supported = "; ".join(
88
+ f"type='{entry.algo_type}', method='{entry.method}', variety='{entry.variety}'"
89
+ for entry in SUPPORTED_ALGORITHMS
90
+ )
91
+ raise AlgorithmValidationError(
92
+ "Unsupported algorithm configuration:\n"
93
+ f" type={algo_type!r}, method={method!r}, variety={variety!r}\n"
94
+ f"Supported combinations are: {supported}"
95
+ )
96
+
97
+ if expected_family:
98
+ expected_family = expected_family.lower()
99
+ family_map = {
100
+ ("online", "policy_gradient", "gspo"): "rl",
101
+ ("offline", "supervised_finetune", "fft"): "sft",
102
+ ("offline", "sft", "fft"): "sft",
103
+ ("offline", "sft", "lora"): "sft",
104
+ }
105
+ family = family_map.get(key)
106
+ if family != expected_family:
107
+ raise AlgorithmValidationError(
108
+ f"Config contains algorithm {spec.label!r}, "
109
+ f"but the current command expects {expected_family.upper()}."
110
+ )
111
+
112
+ return spec
113
+
114
+
115
+ def ensure_model_supported_for_algorithm(model_id: str, spec: AlgorithmSpec) -> None:
116
+ """Ensure that the given model supports the training mode required by *spec*."""
117
+
118
+ modes = {mode.lower() for mode in training_modes_for_model(model_id)}
119
+ required = spec.required_training_mode.lower()
120
+ if required not in modes:
121
+ if required == "rl":
122
+ allowed = ", ".join(RL_ALGORITHM_MODEL_IDS)
123
+ else:
124
+ allowed = ", ".join(SFT_ALGORITHM_MODEL_IDS)
125
+ raise AlgorithmValidationError(
126
+ f"Model '{model_id}' does not support {spec.label} workloads "
127
+ f"(missing training mode '{required}'). Supported model IDs: {allowed}"
128
+ )
129
+
130
+
131
+ __all__ = [
132
+ "AlgorithmSpec",
133
+ "AlgorithmValidationError",
134
+ "RL_ALGORITHM_MODEL_IDS",
135
+ "SFT_ALGORITHM_MODEL_IDS",
136
+ "SUPPORTED_ALGORITHMS",
137
+ "validate_algorithm_config",
138
+ "ensure_model_supported_for_algorithm",
139
+ ]
@@ -1,8 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
3
+ from collections.abc import Iterable
4
4
  from dataclasses import dataclass
5
- from typing import Iterable
6
5
 
7
6
  import click
8
7
  import requests
@@ -42,6 +41,7 @@ def _health_response_ok(resp: requests.Response | None) -> tuple[bool, str]:
42
41
  def check_task_app_health(base_url: str, api_key: str, *, timeout: float = 10.0) -> TaskAppHealth:
43
42
  # Send ALL known environment keys so the server can authorize any valid one
44
43
  import os
44
+
45
45
  headers = {"X-API-Key": api_key}
46
46
  aliases = (os.getenv("ENVIRONMENT_API_KEY_ALIASES") or "").strip()
47
47
  keys: list[str] = [api_key]
@@ -146,7 +146,9 @@ def list_modal_secrets(pattern: str | None = None) -> list[str]:
146
146
  def get_modal_secret_value(name: str) -> str:
147
147
  result = _run_modal(["secret", "get", name])
148
148
  if result.code != 0:
149
- raise click.ClickException(f"modal secret get {name} failed: {result.stderr or result.stdout}")
149
+ raise click.ClickException(
150
+ f"modal secret get {name} failed: {result.stderr or result.stdout}"
151
+ )
150
152
  value = result.stdout.strip()
151
153
  if not value:
152
154
  raise click.ClickException(f"Secret {name} is empty")
@@ -4,15 +4,16 @@ import json
4
4
  import os
5
5
  import re
6
6
  import subprocess
7
- import sys
8
7
  import tempfile
9
8
  import time
9
+ import tomllib
10
+ from collections.abc import Iterable, Mapping
10
11
  from dataclasses import dataclass
11
12
  from pathlib import Path
12
- from typing import Any, Iterable, Mapping
13
+ from typing import Any
13
14
 
14
15
  import requests
15
- import tomllib
16
+ from synth_ai.learning.sft import collect_sft_jsonl_errors
16
17
 
17
18
  REPO_ROOT = Path(__file__).resolve().parents[3]
18
19
 
@@ -83,7 +84,13 @@ class CLIResult:
83
84
  stderr: str
84
85
 
85
86
 
86
- def run_cli(args: Iterable[str], *, cwd: Path | None = None, env: Mapping[str, str] | None = None, timeout: float | None = None) -> CLIResult:
87
+ def run_cli(
88
+ args: Iterable[str],
89
+ *,
90
+ cwd: Path | None = None,
91
+ env: Mapping[str, str] | None = None,
92
+ timeout: float | None = None,
93
+ ) -> CLIResult:
87
94
  proc = subprocess.run(
88
95
  list(args),
89
96
  cwd=cwd,
@@ -95,17 +102,27 @@ def run_cli(args: Iterable[str], *, cwd: Path | None = None, env: Mapping[str, s
95
102
  return CLIResult(code=proc.returncode, stdout=proc.stdout.strip(), stderr=proc.stderr.strip())
96
103
 
97
104
 
98
- def http_post(url: str, *, headers: Mapping[str, str] | None = None, json_body: Any | None = None, timeout: float = 60.0) -> requests.Response:
105
+ def http_post(
106
+ url: str,
107
+ *,
108
+ headers: Mapping[str, str] | None = None,
109
+ json_body: Any | None = None,
110
+ timeout: float = 60.0,
111
+ ) -> requests.Response:
99
112
  resp = requests.post(url, headers=dict(headers or {}), json=json_body, timeout=timeout)
100
113
  return resp
101
114
 
102
115
 
103
- def http_get(url: str, *, headers: Mapping[str, str] | None = None, timeout: float = 30.0) -> requests.Response:
116
+ def http_get(
117
+ url: str, *, headers: Mapping[str, str] | None = None, timeout: float = 30.0
118
+ ) -> requests.Response:
104
119
  resp = requests.get(url, headers=dict(headers or {}), timeout=timeout)
105
120
  return resp
106
121
 
107
122
 
108
- def post_multipart(url: str, *, api_key: str, file_field: str, file_path: Path, purpose: str = "fine-tune") -> requests.Response:
123
+ def post_multipart(
124
+ url: str, *, api_key: str, file_field: str, file_path: Path, purpose: str = "fine-tune"
125
+ ) -> requests.Response:
109
126
  headers = {"Authorization": f"Bearer {api_key}"}
110
127
  files = {file_field: (file_path.name, file_path.read_bytes(), "application/jsonl")}
111
128
  data = {"purpose": purpose}
@@ -123,49 +140,17 @@ def fmt_duration(seconds: float) -> str:
123
140
 
124
141
 
125
142
  def validate_sft_jsonl(path: Path, *, max_errors: int = 20) -> None:
126
- errors: list[str] = []
127
- try:
128
- fh = path.open("r", encoding="utf-8")
129
- except FileNotFoundError as exc: # pragma: no cover - upstream ensures existence
130
- raise TrainError(f"Dataset not found: {path}") from exc
131
-
132
- with fh:
133
- for idx, line in enumerate(fh, start=1):
134
- stripped = line.strip()
135
- if not stripped:
136
- continue
137
- try:
138
- record = json.loads(stripped)
139
- except json.JSONDecodeError as exc:
140
- errors.append(f"Line {idx}: invalid JSON ({exc.msg})")
141
- if len(errors) >= max_errors:
142
- break
143
- continue
144
-
145
- messages = record.get("messages")
146
- if not isinstance(messages, list) or not messages:
147
- errors.append(f"Line {idx}: missing or empty 'messages' list")
148
- if len(errors) >= max_errors:
149
- break
150
- continue
143
+ if not path.exists():
144
+ raise TrainError(f"Dataset not found: {path}")
151
145
 
152
- for msg_idx, msg in enumerate(messages):
153
- if not isinstance(msg, dict):
154
- errors.append(f"Line {idx}: message {msg_idx} is not an object")
155
- break
156
- if "role" not in msg or "content" not in msg:
157
- errors.append(f"Line {idx}: message {msg_idx} missing 'role' or 'content'")
158
- break
159
- if not isinstance(msg["role"], str) or not isinstance(msg["content"], str):
160
- errors.append(f"Line {idx}: message {msg_idx} has non-string role/content")
161
- break
162
- if len(errors) >= max_errors:
163
- break
146
+ issues = collect_sft_jsonl_errors(path, min_messages=1, max_errors=max_errors)
147
+ if not issues:
148
+ return
164
149
 
165
- if errors:
166
- suffix = "" if len(errors) < max_errors else f" (showing first {max_errors} issues)"
167
- details = "\n - ".join(errors)
168
- raise TrainError(f"Dataset validation failed{suffix}:\n - {details}")
150
+ truncated = max_errors is not None and len(issues) >= max_errors
151
+ suffix = "" if not truncated else f" (showing first {max_errors} issues)"
152
+ details = "\n - ".join(issues)
153
+ raise TrainError(f"{path}: Dataset validation failed{suffix}:\n - {details}")
169
154
 
170
155
 
171
156
  def limit_jsonl_examples(src: Path, limit: int) -> Path:
synth_ai/cli/__init__.py CHANGED
@@ -17,6 +17,13 @@ except Exception:
17
17
  # dotenv is optional at runtime; proceed if unavailable
18
18
  pass
19
19
 
20
+ try:
21
+ from ._typer_patch import patch_typer_make_metavar
22
+
23
+ patch_typer_make_metavar()
24
+ except Exception:
25
+ pass
26
+
20
27
 
21
28
  from .root import cli # new canonical CLI entrypoint
22
29
 
@@ -69,6 +76,12 @@ try:
69
76
  _demo.register(cli)
70
77
  except Exception:
71
78
  pass
79
+ try:
80
+ from . import turso as _turso
81
+
82
+ _turso.register(cli)
83
+ except Exception:
84
+ pass
72
85
  try:
73
86
  from . import rl_demo as _rl_demo
74
87
 
@@ -83,18 +96,20 @@ except Exception:
83
96
  pass
84
97
 
85
98
 
86
-
87
99
  from .task_apps import task_app_group
100
+
88
101
  cli.add_command(task_app_group, name="task-app")
89
102
 
90
103
 
91
104
  try:
92
105
  from . import task_apps as _task_apps
106
+
93
107
  _task_apps.register(cli)
94
108
  except Exception:
95
109
  pass
96
110
 
97
- cli.add_command(task_app_group.commands['serve'], name='serve')
98
- cli.add_command(task_app_group.commands['deploy'], name='deploy')
111
+ cli.add_command(task_app_group.commands["serve"], name="serve")
112
+ cli.add_command(task_app_group.commands["deploy"], name="deploy")
99
113
 
100
- cli.add_command(task_app_group.commands['modal-serve'], name='modal-serve')
114
+ cli.add_command(task_app_group.commands["modal-serve"], name="modal-serve")
115
+ cli.add_command(task_app_group.commands["info"], name="info")
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+
6
+ def main() -> int:
7
+ # Apply Typer compatibility patch before Modal CLI bootstraps Click/Typer internals.
8
+ try:
9
+ from ._typer_patch import patch_typer_make_metavar
10
+
11
+ patch_typer_make_metavar()
12
+ except Exception:
13
+ pass
14
+
15
+ from modal.__main__ import main as modal_main
16
+
17
+ # Present ourselves as the upstream `modal` CLI so Typer/Click parsing stays intact.
18
+ if sys.argv:
19
+ sys.argv[0] = "modal"
20
+ else:
21
+ sys.argv = ["modal"]
22
+
23
+ return modal_main()
24
+
25
+
26
+ if __name__ == "__main__":
27
+ sys.exit(main())
28
+
@@ -0,0 +1,49 @@
1
+ from __future__ import annotations
2
+
3
+ from click import Parameter
4
+
5
+
6
+ def patch_typer_make_metavar() -> None:
7
+ try:
8
+ from typer.main import TyperArgument, TyperOption
9
+ except Exception:
10
+ return
11
+
12
+ def _call_get_metavar(param_type: object, param: Parameter) -> str | None:
13
+ getter = getattr(param_type, "get_metavar", None)
14
+ if getter is None:
15
+ return None
16
+ try:
17
+ return getter(param)
18
+ except TypeError:
19
+ try:
20
+ return getter(param, None)
21
+ except TypeError:
22
+ return None
23
+
24
+ def _patched_argument_make_metavar(self, ctx=None) -> str:
25
+ if self.metavar is not None:
26
+ return self.metavar
27
+ var = (self.name or "").upper()
28
+ if not self.required:
29
+ var = f"[{var}]"
30
+ type_var = _call_get_metavar(self.type, self)
31
+ if type_var:
32
+ var += f":{type_var}"
33
+ if self.nargs != 1:
34
+ var += "..."
35
+ return var
36
+
37
+ def _patched_option_make_metavar(self, ctx=None) -> str:
38
+ if self.metavar is not None:
39
+ return self.metavar
40
+ metavar = _call_get_metavar(self.type, self)
41
+ if not metavar:
42
+ name = getattr(self.type, "name", "") or ""
43
+ metavar = name.upper()
44
+ if self.nargs != 1:
45
+ metavar += "..."
46
+ return metavar
47
+
48
+ TyperArgument.make_metavar = _patched_argument_make_metavar # type: ignore[assignment]
49
+ TyperOption.make_metavar = _patched_option_make_metavar # type: ignore[assignment]
synth_ai/cli/balance.py CHANGED
@@ -6,7 +6,6 @@ CLI: check remaining credit balance from Synth backend.
6
6
  from __future__ import annotations
7
7
 
8
8
  import os
9
- from urllib.parse import urlparse
10
9
 
11
10
  import click
12
11
  import requests
@@ -15,7 +14,7 @@ from rich import box
15
14
  from rich.console import Console
16
15
  from rich.table import Table
17
16
 
18
- from synth_ai.config.base_url import get_backend_from_env, PROD_BASE_URL_DEFAULT
17
+ from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT, get_backend_from_env
19
18
 
20
19
  PROD_BACKEND_BASE = f"{PROD_BASE_URL_DEFAULT.rstrip('/')}/api/v1"
21
20
 
@@ -29,7 +28,7 @@ def _get_default_base_url() -> str:
29
28
  base, _ = get_backend_from_env()
30
29
  base = base.rstrip("/")
31
30
  if base.endswith("/api"):
32
- base = base[:-len("/api")]
31
+ base = base[: -len("/api")]
33
32
  return f"{base}/api/v1"
34
33
 
35
34
 
synth_ai/cli/calc.py CHANGED
@@ -30,7 +30,7 @@ def _safe_eval(expr: str) -> float:
30
30
  def _eval(n):
31
31
  if isinstance(n, ast.Expression):
32
32
  return _eval(n.body)
33
- if isinstance(n, ast.Num): # 3.8 and earlier
33
+ if hasattr(ast, "Num") and isinstance(n, ast.Num): # 3.8 and earlier
34
34
  return n.n
35
35
  if isinstance(n, ast.Constant): # 3.8+
36
36
  if isinstance(n.value, int | float):
synth_ai/cli/demo.py CHANGED
@@ -23,6 +23,7 @@ def _find_demo_scripts(root: Path) -> list[Path]:
23
23
 
24
24
  def _forward_to_new(args: list[str]) -> None:
25
25
  import sys
26
+
26
27
  try:
27
28
  from synth_ai.demos.core import cli as demo_cli # type: ignore
28
29
  except Exception as e: # pragma: no cover
@@ -35,7 +36,9 @@ def _forward_to_new(args: list[str]) -> None:
35
36
 
36
37
  def register(cli):
37
38
  @cli.group("demo", invoke_without_command=True)
38
- @click.option("--force", is_flag=True, help="Overwrite existing files in CWD when initializing demo")
39
+ @click.option(
40
+ "--force", is_flag=True, help="Overwrite existing files in CWD when initializing demo"
41
+ )
39
42
  @click.option("--list", "list_only", is_flag=True, help="List available legacy demos and exit")
40
43
  @click.option("-f", "filter_term", default="", help="Filter legacy demos by substring")
41
44
  @click.pass_context
@@ -98,14 +101,26 @@ def register(cli):
98
101
  # (prepare command removed; configure now prepares baseline TOML)
99
102
 
100
103
  # Help pyright understand dynamic Click group attributes
101
- from typing import Any, cast as _cast
104
+ from typing import Any
105
+ from typing import cast as _cast
106
+
102
107
  _dg = _cast(Any, demo)
103
108
 
104
109
  @_dg.command("deploy")
105
110
  @click.option("--local", is_flag=True, help="Run local FastAPI instead of Modal deploy")
106
- @click.option("--app", type=click.Path(), default=None, help="Path to Modal app.py for uv run modal deploy")
111
+ @click.option(
112
+ "--app",
113
+ type=click.Path(),
114
+ default=None,
115
+ help="Path to Modal app.py for uv run modal deploy",
116
+ )
107
117
  @click.option("--name", type=str, default="synth-math-demo", help="Modal app name")
108
- @click.option("--script", type=click.Path(), default=None, help="Path to deploy_task_app.sh (optional legacy)")
118
+ @click.option(
119
+ "--script",
120
+ type=click.Path(),
121
+ default=None,
122
+ help="Path to deploy_task_app.sh (optional legacy)",
123
+ )
109
124
  def demo_deploy(local: bool, app: str | None, name: str, script: str | None):
110
125
  args: list[str] = ["rl_demo.deploy"]
111
126
  if local:
@@ -120,11 +135,11 @@ def register(cli):
120
135
 
121
136
  @_dg.command("configure")
122
137
  def demo_configure():
123
- _forward_to_new(["rl_demo.configure"])
138
+ _forward_to_new(["rl_demo.configure"])
124
139
 
125
140
  @_dg.command("setup")
126
141
  def demo_setup():
127
- _forward_to_new(["rl_demo.setup"])
142
+ _forward_to_new(["rl_demo.setup"])
128
143
 
129
144
  @_dg.command("run")
130
145
  @click.option("--batch-size", type=int, default=None)
synth_ai/cli/recent.py CHANGED
@@ -34,11 +34,11 @@ def _fmt_time(v) -> str:
34
34
 
35
35
 
36
36
  async def _fetch_recent(db_url: str, hours: float):
37
- from synth_ai.tracing_v3.turso.manager import AsyncSQLTraceManager
37
+ from synth_ai.tracing_v3.storage.factory import create_storage, StorageConfig
38
38
 
39
39
  start_time = datetime.now() - timedelta(hours=hours)
40
40
 
41
- db = AsyncSQLTraceManager(db_url)
41
+ db = create_storage(StorageConfig(connection_string=db_url))
42
42
  await db.initialize()
43
43
  try:
44
44
  query = """