synth-ai 0.2.9.dev5__py3-none-any.whl → 0.2.10__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 (349) hide show
  1. examples/__init__.py +16 -0
  2. examples/crafter_debug_render.py +23 -17
  3. examples/dev/qwen3_32b_qlora_4xh100.toml +40 -0
  4. examples/multi_step/crafter_rl_lora.md +29 -0
  5. examples/qwen_coder/README.md +102 -0
  6. examples/qwen_coder/_shared.py +113 -0
  7. examples/qwen_coder/configs/coder_lora_30b.toml +61 -0
  8. examples/qwen_coder/configs/coder_lora_4b.toml +57 -0
  9. examples/qwen_coder/configs/coder_lora_small.toml +58 -0
  10. examples/qwen_coder/generate_dataset.py +98 -0
  11. examples/qwen_coder/infer_ft_smoke.py +65 -0
  12. examples/qwen_coder/infer_prod_proxy.py +73 -0
  13. examples/qwen_coder/infer_via_synth.py +87 -0
  14. examples/qwen_coder/scripts/infer_coder.sh +19 -0
  15. examples/qwen_coder/scripts/train_coder_30b.sh +22 -0
  16. examples/qwen_coder/sft_full_17b.py +103 -0
  17. examples/qwen_coder/sft_lora_30b.py +110 -0
  18. examples/qwen_coder/subset_jsonl.py +39 -0
  19. examples/qwen_coder/todos.md +38 -0
  20. examples/qwen_coder/validate_jsonl.py +60 -0
  21. examples/rl/configs/eval_base_qwen.toml +1 -1
  22. examples/rl/configs/rl_from_base_qwen17.toml +1 -1
  23. examples/rl/download_dataset.py +26 -10
  24. examples/rl/run_eval.py +53 -52
  25. examples/rl/run_rl_and_save.py +29 -12
  26. examples/rl/task_app/math_single_step.py +180 -41
  27. examples/rl/task_app/math_task_app.py +14 -6
  28. examples/sft/README.md +139 -0
  29. examples/sft/configs/crafter_fft_qwen0p6b.toml +44 -0
  30. examples/sft/configs/crafter_lora_qwen0p6b.toml +45 -0
  31. examples/sft/evaluate.py +117 -0
  32. examples/sft/export_dataset.py +117 -0
  33. examples/sft/generate_traces.py +162 -0
  34. examples/swe/__init__.py +12 -0
  35. examples/swe/task_app/README.md +105 -0
  36. examples/swe/task_app/__init__.py +2 -0
  37. examples/swe/task_app/grpo_swe_mini.py +571 -0
  38. examples/swe/task_app/grpo_swe_mini_task_app.py +136 -0
  39. examples/swe/task_app/hosted/README.md +173 -0
  40. examples/swe/task_app/hosted/__init__.py +5 -0
  41. examples/swe/task_app/hosted/branching.py +143 -0
  42. examples/swe/task_app/hosted/environment_routes.py +1289 -0
  43. examples/swe/task_app/hosted/envs/__init__.py +1 -0
  44. examples/swe/task_app/hosted/envs/crafter/__init__.py +6 -0
  45. examples/swe/task_app/hosted/envs/crafter/app.py +1 -0
  46. examples/swe/task_app/hosted/envs/crafter/environment.py +522 -0
  47. examples/swe/task_app/hosted/envs/crafter/policy.py +478 -0
  48. examples/swe/task_app/hosted/envs/crafter/react_agent.py +108 -0
  49. examples/swe/task_app/hosted/envs/crafter/shared.py +305 -0
  50. examples/swe/task_app/hosted/envs/crafter/tools.py +47 -0
  51. examples/swe/task_app/hosted/envs/mini_swe/__init__.py +8 -0
  52. examples/swe/task_app/hosted/envs/mini_swe/environment.py +1164 -0
  53. examples/swe/task_app/hosted/envs/mini_swe/policy.py +355 -0
  54. examples/swe/task_app/hosted/envs/mini_swe/shared.py +83 -0
  55. examples/swe/task_app/hosted/envs/mini_swe/tools.py +96 -0
  56. examples/swe/task_app/hosted/hosted_app.py +204 -0
  57. examples/swe/task_app/hosted/inference/__init__.py +5 -0
  58. examples/swe/task_app/hosted/inference/openai_client.py +618 -0
  59. examples/swe/task_app/hosted/main.py +100 -0
  60. examples/swe/task_app/hosted/policy_routes.py +1079 -0
  61. examples/swe/task_app/hosted/registry.py +195 -0
  62. examples/swe/task_app/hosted/rollout.py +1869 -0
  63. examples/swe/task_app/hosted/storage/__init__.py +5 -0
  64. examples/swe/task_app/hosted/storage/volume.py +211 -0
  65. examples/swe/task_app/hosted/test_agents.py +161 -0
  66. examples/swe/task_app/hosted/test_service.py +137 -0
  67. examples/swe/task_app/hosted/utils.py +62 -0
  68. examples/vlm/PROPOSAL.md +53 -0
  69. examples/vlm/README.md +68 -0
  70. examples/vlm/configs/crafter_vlm_gpt4o.toml +44 -0
  71. examples/vlm/crafter_image_only_agent.py +207 -0
  72. examples/vlm/crafter_openai_vlm_agent.py +277 -0
  73. examples/vlm/filter_image_rows.py +63 -0
  74. examples/vlm/run_crafter_vlm_benchmark.py +316 -0
  75. examples/warming_up_to_rl/analyze_trace_db.py +12 -10
  76. examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +11 -1
  77. examples/warming_up_to_rl/export_trace_sft.py +218 -36
  78. examples/warming_up_to_rl/groq_test.py +15 -8
  79. examples/warming_up_to_rl/manage_secrets.py +29 -25
  80. examples/warming_up_to_rl/readme.md +9 -2
  81. examples/warming_up_to_rl/run_eval.py +137 -61
  82. examples/warming_up_to_rl/run_fft_and_save.py +131 -60
  83. examples/warming_up_to_rl/run_local_rollout.py +88 -39
  84. examples/warming_up_to_rl/run_local_rollout_modal.py +114 -28
  85. examples/warming_up_to_rl/run_local_rollout_parallel.py +81 -20
  86. examples/warming_up_to_rl/run_local_rollout_traced.py +126 -23
  87. examples/warming_up_to_rl/run_rl_and_save.py +35 -12
  88. examples/warming_up_to_rl/run_rollout_remote.py +44 -19
  89. examples/warming_up_to_rl/task_app/README.md +6 -2
  90. examples/warming_up_to_rl/task_app/grpo_crafter.py +319 -57
  91. examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +11 -30
  92. examples/warming_up_to_rl/task_app/synth_envs_hosted/__init__.py +1 -1
  93. examples/warming_up_to_rl/task_app/synth_envs_hosted/branching.py +9 -11
  94. examples/warming_up_to_rl/task_app/synth_envs_hosted/environment_routes.py +137 -182
  95. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/__init__.py +1 -1
  96. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/__init__.py +1 -1
  97. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/app.py +1 -1
  98. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +150 -57
  99. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +105 -69
  100. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +19 -7
  101. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +45 -42
  102. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/tools.py +1 -1
  103. examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +47 -45
  104. examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/__init__.py +1 -1
  105. examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +198 -92
  106. examples/warming_up_to_rl/task_app/synth_envs_hosted/main.py +0 -2
  107. examples/warming_up_to_rl/task_app/synth_envs_hosted/policy_routes.py +361 -263
  108. examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py +21 -23
  109. examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py +394 -274
  110. examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/__init__.py +1 -1
  111. examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +56 -62
  112. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py +1 -0
  113. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py +6 -15
  114. examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +4 -3
  115. synth_ai/__init__.py +1 -0
  116. synth_ai/api/models/supported.py +376 -0
  117. synth_ai/api/train/builders.py +157 -26
  118. synth_ai/api/train/cli.py +213 -57
  119. synth_ai/api/train/config_finder.py +65 -5
  120. synth_ai/api/train/env_resolver.py +33 -15
  121. synth_ai/api/train/pollers.py +13 -4
  122. synth_ai/api/train/supported_algos.py +139 -0
  123. synth_ai/api/train/task_app.py +5 -3
  124. synth_ai/api/train/utils.py +33 -48
  125. synth_ai/cli/__init__.py +19 -4
  126. synth_ai/cli/_modal_wrapper.py +28 -0
  127. synth_ai/cli/_typer_patch.py +49 -0
  128. synth_ai/cli/balance.py +2 -3
  129. synth_ai/cli/calc.py +1 -1
  130. synth_ai/cli/demo.py +21 -6
  131. synth_ai/cli/recent.py +2 -2
  132. synth_ai/cli/rl_demo.py +77 -17
  133. synth_ai/cli/root.py +116 -39
  134. synth_ai/cli/status.py +2 -2
  135. synth_ai/cli/task_apps.py +1699 -259
  136. synth_ai/cli/traces.py +7 -4
  137. synth_ai/cli/turso.py +73 -0
  138. synth_ai/cli/watch.py +12 -18
  139. synth_ai/core/experiment.py +0 -2
  140. synth_ai/demo_registry.py +68 -31
  141. synth_ai/demos/core/cli.py +516 -194
  142. synth_ai/demos/demo_task_apps/__init__.py +3 -3
  143. synth_ai/demos/demo_task_apps/core.py +64 -28
  144. synth_ai/demos/demo_task_apps/crafter/configs/crafter_fft_4b.toml +2 -3
  145. synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +37 -30
  146. synth_ai/demos/demo_task_apps/math/_common.py +1 -2
  147. synth_ai/demos/demo_task_apps/math/app.py +2 -1
  148. synth_ai/demos/demo_task_apps/math/deploy_modal.py +3 -6
  149. synth_ai/demos/demo_task_apps/math/modal_task_app.py +183 -82
  150. synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -2
  151. synth_ai/environments/examples/bandit/engine.py +12 -4
  152. synth_ai/environments/examples/bandit/taskset.py +4 -4
  153. synth_ai/environments/examples/crafter_classic/environment.py +76 -1
  154. synth_ai/environments/reproducibility/tree.py +5 -6
  155. synth_ai/environments/service/app.py +11 -12
  156. synth_ai/environments/service/core_routes.py +10 -9
  157. synth_ai/environments/stateful/engine.py +1 -1
  158. synth_ai/environments/tasks/core.py +1 -0
  159. synth_ai/environments/tasks/filters.py +5 -6
  160. synth_ai/environments/tasks/utils.py +4 -5
  161. synth_ai/evals/base.py +0 -2
  162. synth_ai/handshake.py +11 -9
  163. synth_ai/http.py +1 -1
  164. synth_ai/http_client.py +43 -11
  165. synth_ai/inference/__init__.py +0 -2
  166. synth_ai/inference/client.py +20 -6
  167. synth_ai/jobs/client.py +103 -78
  168. synth_ai/learning/__init__.py +41 -6
  169. synth_ai/learning/algorithms.py +14 -0
  170. synth_ai/learning/client.py +121 -29
  171. synth_ai/learning/config.py +2 -40
  172. synth_ai/learning/constants.py +0 -2
  173. synth_ai/learning/ft_client.py +4 -56
  174. synth_ai/learning/health.py +13 -7
  175. synth_ai/learning/jobs.py +43 -47
  176. synth_ai/{rl → learning/rl}/__init__.py +14 -5
  177. synth_ai/learning/rl/client.py +267 -0
  178. synth_ai/learning/rl/config.py +31 -0
  179. synth_ai/{rl → learning/rl}/contracts.py +5 -10
  180. synth_ai/{rl → learning/rl}/env_keys.py +45 -16
  181. synth_ai/learning/rl/secrets.py +13 -0
  182. synth_ai/learning/rl_client.py +2 -253
  183. synth_ai/learning/sft/__init__.py +29 -0
  184. synth_ai/learning/sft/client.py +68 -0
  185. synth_ai/learning/sft/config.py +270 -0
  186. synth_ai/learning/sft/data.py +295 -0
  187. synth_ai/learning/sse.py +25 -26
  188. synth_ai/learning/validators.py +25 -24
  189. synth_ai/lm/__init__.py +21 -47
  190. synth_ai/task/__init__.py +26 -27
  191. synth_ai/task/apps/__init__.py +18 -19
  192. synth_ai/task/auth.py +35 -23
  193. synth_ai/task/client.py +15 -13
  194. synth_ai/task/contracts.py +37 -35
  195. synth_ai/task/datasets.py +9 -6
  196. synth_ai/task/errors.py +11 -10
  197. synth_ai/task/health.py +17 -11
  198. synth_ai/task/json.py +58 -24
  199. synth_ai/task/proxy.py +15 -14
  200. synth_ai/task/rubrics.py +22 -15
  201. synth_ai/task/server.py +43 -17
  202. synth_ai/task/tracing_utils.py +12 -7
  203. synth_ai/task/validators.py +0 -1
  204. synth_ai/task/vendors.py +5 -7
  205. synth_ai/tracing_v3/__init__.py +2 -0
  206. synth_ai/tracing_v3/abstractions.py +21 -4
  207. synth_ai/tracing_v3/db_config.py +26 -1
  208. synth_ai/tracing_v3/decorators.py +18 -15
  209. synth_ai/tracing_v3/examples/basic_usage.py +3 -2
  210. synth_ai/tracing_v3/hooks.py +6 -4
  211. synth_ai/tracing_v3/llm_call_record_helpers.py +6 -6
  212. synth_ai/tracing_v3/replica_sync.py +1 -0
  213. synth_ai/tracing_v3/session_tracer.py +63 -16
  214. synth_ai/tracing_v3/storage/base.py +89 -1
  215. synth_ai/tracing_v3/storage/config.py +21 -8
  216. synth_ai/tracing_v3/storage/factory.py +10 -8
  217. synth_ai/tracing_v3/storage/utils.py +4 -2
  218. synth_ai/tracing_v3/turso/daemon.py +7 -2
  219. synth_ai/tracing_v3/turso/models.py +5 -2
  220. synth_ai/tracing_v3/turso/native_manager.py +1173 -0
  221. synth_ai/tracing_v3/utils.py +4 -3
  222. synth_ai/v0/api/__init__.py +8 -0
  223. synth_ai/v0/api/models/__init__.py +8 -0
  224. synth_ai/v0/api/models/supported.py +8 -0
  225. synth_ai/v0/config/__init__.py +15 -0
  226. synth_ai/v0/config/base_url.py +12 -0
  227. synth_ai/v0/lm/__init__.py +51 -0
  228. synth_ai/{lm → v0/lm}/caching/ephemeral.py +3 -5
  229. synth_ai/{lm → v0/lm}/caching/handler.py +4 -4
  230. synth_ai/{lm → v0/lm}/caching/initialize.py +1 -1
  231. synth_ai/{lm → v0/lm}/caching/persistent.py +1 -1
  232. synth_ai/{lm → v0/lm}/config.py +6 -1
  233. synth_ai/{lm → v0/lm}/core/all.py +9 -9
  234. synth_ai/{lm → v0/lm}/core/exceptions.py +0 -2
  235. synth_ai/{lm → v0/lm}/core/main.py +19 -7
  236. synth_ai/{lm → v0/lm}/core/main_v3.py +10 -10
  237. synth_ai/{lm → v0/lm}/core/synth_models.py +2 -15
  238. synth_ai/{lm → v0/lm}/core/vendor_clients.py +6 -4
  239. synth_ai/{lm → v0/lm}/overrides.py +4 -4
  240. synth_ai/{lm → v0/lm}/provider_support/anthropic.py +4 -4
  241. synth_ai/{lm → v0/lm}/provider_support/openai.py +5 -5
  242. synth_ai/{lm → v0/lm}/structured_outputs/handler.py +5 -5
  243. synth_ai/{lm → v0/lm}/structured_outputs/rehabilitate.py +1 -1
  244. synth_ai/{lm → v0/lm}/vendors/core/anthropic_api.py +16 -16
  245. synth_ai/{lm → v0/lm}/vendors/core/gemini_api.py +5 -5
  246. synth_ai/{lm → v0/lm}/vendors/core/mistral_api.py +5 -5
  247. synth_ai/{lm → v0/lm}/vendors/core/openai_api.py +12 -10
  248. synth_ai/{lm → v0/lm}/vendors/openai_standard.py +11 -9
  249. synth_ai/{lm → v0/lm}/vendors/openai_standard_responses.py +8 -5
  250. synth_ai/{lm → v0/lm}/vendors/supported/custom_endpoint.py +4 -6
  251. synth_ai/{lm → v0/lm}/vendors/supported/deepseek.py +2 -2
  252. synth_ai/{lm → v0/lm}/vendors/supported/grok.py +2 -2
  253. synth_ai/{lm → v0/lm}/vendors/supported/groq.py +1 -1
  254. synth_ai/{lm → v0/lm}/vendors/supported/ollama.py +1 -1
  255. synth_ai/{lm → v0/lm}/vendors/supported/openrouter.py +3 -3
  256. synth_ai/{lm → v0/lm}/vendors/supported/together.py +1 -1
  257. synth_ai/{lm → v0/lm}/vendors/synth_client.py +38 -11
  258. synth_ai/v0/tracing/upload.py +32 -135
  259. synth_ai/v0/tracing_v3/__init__.py +10 -0
  260. synth_ai/v0/tracing_v3/abstractions.py +3 -0
  261. synth_ai/v0/tracing_v3/decorators.py +3 -0
  262. synth_ai/v0/tracing_v3/llm_call_record_helpers.py +3 -0
  263. synth_ai/v0/tracing_v3/session_tracer.py +3 -0
  264. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/METADATA +10 -7
  265. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/RECORD +294 -258
  266. examples/common_old/backend.py +0 -21
  267. examples/evals_old/README.md +0 -98
  268. examples/evals_old/__init__.py +0 -6
  269. examples/evals_old/compare_models.py +0 -1037
  270. examples/evals_old/example_log.md +0 -145
  271. examples/evals_old/run_demo.sh +0 -126
  272. examples/evals_old/trace_analysis.py +0 -270
  273. examples/finetuning_old/_backup_synth_qwen/config.toml +0 -29
  274. examples/finetuning_old/_backup_synth_qwen/example_log.md +0 -324
  275. examples/finetuning_old/_backup_synth_qwen/filter_traces.py +0 -60
  276. examples/finetuning_old/_backup_synth_qwen/filter_traces_achievements.py +0 -239
  277. examples/finetuning_old/_backup_synth_qwen/purge_v3_traces.py +0 -109
  278. examples/finetuning_old/_backup_synth_qwen/react_agent_lm.py +0 -1924
  279. examples/finetuning_old/_backup_synth_qwen/readme.md +0 -49
  280. examples/finetuning_old/_backup_synth_qwen/run_crafter_qwen4b.py +0 -114
  281. examples/finetuning_old/_backup_synth_qwen/run_demo.sh +0 -195
  282. examples/finetuning_old/_backup_synth_qwen/sft_kickoff.py +0 -118
  283. examples/finetuning_old/synth_qwen_v1/README.md +0 -68
  284. examples/finetuning_old/synth_qwen_v1/filter_traces.py +0 -60
  285. examples/finetuning_old/synth_qwen_v1/filter_traces_achievements.py +0 -239
  286. examples/finetuning_old/synth_qwen_v1/finetune.py +0 -46
  287. examples/finetuning_old/synth_qwen_v1/hello_ft_model.py +0 -71
  288. examples/finetuning_old/synth_qwen_v1/infer.py +0 -37
  289. examples/finetuning_old/synth_qwen_v1/poll.py +0 -44
  290. examples/finetuning_old/synth_qwen_v1/prepare_data.py +0 -35
  291. examples/finetuning_old/synth_qwen_v1/purge_v3_traces.py +0 -109
  292. examples/finetuning_old/synth_qwen_v1/react_agent_lm.py +0 -1932
  293. examples/finetuning_old/synth_qwen_v1/run_crafter_sft_job.py +0 -207
  294. examples/finetuning_old/synth_qwen_v1/run_ft_job.py +0 -232
  295. examples/finetuning_old/synth_qwen_v1/upload_data.py +0 -34
  296. examples/finetuning_old/synth_qwen_v1/util.py +0 -147
  297. examples/rl_old/task_app.py +0 -962
  298. synth_ai/experimental/synth_oss.py +0 -446
  299. synth_ai/install_sqld.sh +0 -40
  300. synth_ai/learning/filtering.py +0 -0
  301. synth_ai/learning/offline/dpo.py +0 -0
  302. synth_ai/learning/offline/providers.py +0 -7
  303. synth_ai/learning/offline/sft.py +0 -0
  304. synth_ai/learning/offline/shared.py +0 -0
  305. synth_ai/learning/online/grpo.py +0 -0
  306. synth_ai/learning/online/irft.py +0 -0
  307. synth_ai/learning/prompts/banking77_injection_eval.py +0 -168
  308. synth_ai/learning/prompts/gepa.py +0 -0
  309. synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +0 -213
  310. synth_ai/learning/prompts/mipro.py +0 -289
  311. synth_ai/learning/prompts/random_search.py +0 -246
  312. synth_ai/learning/prompts/run_mipro_banking77.py +0 -172
  313. synth_ai/learning/prompts/run_random_search_banking77.py +0 -324
  314. synth_ai/rl/secrets.py +0 -19
  315. synth_ai/scripts/verify_rewards.py +0 -100
  316. synth_ai/tracing/__init__.py +0 -30
  317. synth_ai/tracing_v1/__init__.py +0 -33
  318. synth_ai/tracing_v3/turso/__init__.py +0 -25
  319. synth_ai/tracing_v3/turso/manager.py +0 -774
  320. synth_ai/zyk/__init__.py +0 -30
  321. /synth_ai/{lm → v0/lm}/caching/__init__.py +0 -0
  322. /synth_ai/{lm → v0/lm}/caching/constants.py +0 -0
  323. /synth_ai/{lm → v0/lm}/caching/dbs.py +0 -0
  324. /synth_ai/{lm → v0/lm}/constants.py +0 -0
  325. /synth_ai/{lm → v0/lm}/core/__init__.py +0 -0
  326. /synth_ai/{lm → v0/lm}/cost/__init__.py +0 -0
  327. /synth_ai/{lm → v0/lm}/cost/monitor.py +0 -0
  328. /synth_ai/{lm → v0/lm}/cost/statefulness.py +0 -0
  329. /synth_ai/{lm → v0/lm}/injection.py +0 -0
  330. /synth_ai/{lm → v0/lm}/provider_support/__init__.py +0 -0
  331. /synth_ai/{lm → v0/lm}/provider_support/suppress_logging.py +0 -0
  332. /synth_ai/{lm → v0/lm}/structured_outputs/__init__.py +0 -0
  333. /synth_ai/{lm → v0/lm}/structured_outputs/inject.py +0 -0
  334. /synth_ai/{lm → v0/lm}/tools/__init__.py +0 -0
  335. /synth_ai/{lm → v0/lm}/tools/base.py +0 -0
  336. /synth_ai/{lm → v0/lm}/unified_interface.py +0 -0
  337. /synth_ai/{lm → v0/lm}/vendors/__init__.py +0 -0
  338. /synth_ai/{lm → v0/lm}/vendors/base.py +0 -0
  339. /synth_ai/{lm → v0/lm}/vendors/core/__init__.py +0 -0
  340. /synth_ai/{lm → v0/lm}/vendors/core/synth_dev_api.py +0 -0
  341. /synth_ai/{lm → v0/lm}/vendors/local/__init__.py +0 -0
  342. /synth_ai/{lm → v0/lm}/vendors/local/ollama.py +0 -0
  343. /synth_ai/{lm → v0/lm}/vendors/retries.py +0 -0
  344. /synth_ai/{lm → v0/lm}/vendors/supported/__init__.py +0 -0
  345. /synth_ai/{lm → v0/lm}/warmup.py +0 -0
  346. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/WHEEL +0 -0
  347. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/entry_points.txt +0 -0
  348. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/licenses/LICENSE +0 -0
  349. {synth_ai-0.2.9.dev5.dist-info → synth_ai-0.2.10.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  """Namespace for demo task apps (math, etc.)."""
2
2
 
3
+ import contextlib
4
+
3
5
  # Ensure registry entries are loaded for CLI discovery.
4
- try: # pragma: no cover - optional on downstream installs
6
+ with contextlib.suppress(Exception): # pragma: no cover - optional on downstream installs
5
7
  from .math import task_app_entry # noqa: F401
6
- except Exception:
7
- pass
@@ -3,15 +3,12 @@ from __future__ import annotations
3
3
  import json
4
4
  import os
5
5
  import subprocess
6
- import sys
7
- from dataclasses import dataclass
8
- from typing import Any, Dict, Optional, Tuple
9
-
10
6
  import urllib.request
7
+ from dataclasses import dataclass
8
+ from typing import Any
11
9
 
12
10
  from synth_ai.config.base_url import PROD_BASE_URL_DEFAULT
13
11
 
14
-
15
12
  DEFAULT_TASK_APP_SECRET_NAME = "hendrycks-math-task-app-secret"
16
13
 
17
14
 
@@ -24,6 +21,7 @@ class DemoEnv:
24
21
  task_app_name: str = ""
25
22
  task_app_secret_name: str = DEFAULT_TASK_APP_SECRET_NAME
26
23
 
24
+
27
25
  def _mask(value: str, keep: int = 4) -> str:
28
26
  if not value:
29
27
  return ""
@@ -34,7 +32,7 @@ def _state_path() -> str:
34
32
  return os.path.expanduser("~/.synth-ai/demo.json")
35
33
 
36
34
 
37
- def _read_state() -> Dict[str, Any]:
35
+ def _read_state() -> dict[str, Any]:
38
36
  try:
39
37
  path = _state_path()
40
38
  if os.path.isfile(path):
@@ -46,7 +44,7 @@ def _read_state() -> Dict[str, Any]:
46
44
  return {}
47
45
 
48
46
 
49
- def _write_state(data: Dict[str, Any]) -> None:
47
+ def _write_state(data: dict[str, Any]) -> None:
50
48
  try:
51
49
  path = _state_path()
52
50
  os.makedirs(os.path.dirname(path), exist_ok=True)
@@ -56,8 +54,8 @@ def _write_state(data: Dict[str, Any]) -> None:
56
54
  pass
57
55
 
58
56
 
59
- def load_dotenv_file(path: str) -> Dict[str, str]:
60
- out: Dict[str, str] = {}
57
+ def load_dotenv_file(path: str) -> dict[str, str]:
58
+ out: dict[str, str] = {}
61
59
  try:
62
60
  with open(path) as fh:
63
61
  for raw in fh:
@@ -71,7 +69,7 @@ def load_dotenv_file(path: str) -> Dict[str, str]:
71
69
  return out
72
70
 
73
71
 
74
- def _persist_dotenv_values(path: str, values: Dict[str, str]) -> None:
72
+ def _persist_dotenv_values(path: str, values: dict[str, str]) -> None:
75
73
  """Ensure ``values`` are present in ``path`` (.env style)."""
76
74
 
77
75
  try:
@@ -81,7 +79,7 @@ def _persist_dotenv_values(path: str, values: Dict[str, str]) -> None:
81
79
  existing_lines = fh.read().splitlines()
82
80
  else:
83
81
  os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
84
- mapping: Dict[str, str] = {}
82
+ mapping: dict[str, str] = {}
85
83
  order: list[str] = []
86
84
  for line in existing_lines:
87
85
  if not line or line.startswith("#") or "=" not in line:
@@ -109,7 +107,7 @@ def _persist_dotenv_values(path: str, values: Dict[str, str]) -> None:
109
107
  pass
110
108
 
111
109
 
112
- def persist_dotenv_values(values: Dict[str, str], *, cwd: str | None = None) -> str:
110
+ def persist_dotenv_values(values: dict[str, str], *, cwd: str | None = None) -> str:
113
111
  path = os.path.join(cwd or os.getcwd(), ".env")
114
112
  _persist_dotenv_values(path, values)
115
113
  return path
@@ -121,14 +119,41 @@ def persist_env_api_key(key: str) -> None:
121
119
  _write_state(data)
122
120
 
123
121
 
124
- def modal_auth_status() -> Tuple[bool, str]:
122
+ def persist_demo_dir(demo_dir: str) -> None:
123
+ """Store the demo directory path for subsequent commands."""
124
+ data = _read_state()
125
+ data["DEMO_DIR"] = demo_dir
126
+ _write_state(data)
127
+
128
+
129
+ def load_demo_dir() -> str | None:
130
+ """Load the stored demo directory path, if any."""
131
+ data = _read_state()
132
+ return data.get("DEMO_DIR")
133
+
134
+
135
+ def persist_env_file_path(env_path: str) -> None:
136
+ """Store the .env file path for subsequent commands."""
137
+ data = _read_state()
138
+ data["ENV_FILE_PATH"] = env_path
139
+ _write_state(data)
140
+
141
+
142
+ def load_env_file_path() -> str | None:
143
+ """Load the stored .env file path, if any."""
144
+ data = _read_state()
145
+ return data.get("ENV_FILE_PATH")
146
+
147
+
148
+ def modal_auth_status() -> tuple[bool, str]:
125
149
  """Return (ok, message) describing Modal CLI credential status."""
126
150
 
127
151
  env_token_id = (os.environ.get("MODAL_TOKEN_ID") or "").strip()
128
152
  env_token_secret = (os.environ.get("MODAL_TOKEN_SECRET") or "").strip()
129
153
 
130
154
  try:
131
- from modal.config import config as modal_config, user_config_path
155
+ from modal.config import config as modal_config
156
+ from modal.config import user_config_path
132
157
  except Exception as exc: # pragma: no cover - modal optional in some envs
133
158
  return False, f"Modal client unavailable ({exc})"
134
159
 
@@ -183,7 +208,7 @@ def load_env() -> DemoEnv:
183
208
  """
184
209
  env = DemoEnv()
185
210
 
186
- os_env: Dict[str, str] = dict(os.environ)
211
+ os_env: dict[str, str] = dict(os.environ)
187
212
 
188
213
  # CWD .env
189
214
  cwd_env_path = os.path.join(os.getcwd(), ".env")
@@ -192,7 +217,9 @@ def load_env() -> DemoEnv:
192
217
  # Repo/package .envs (fallbacks)
193
218
  repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../.."))
194
219
  repo_env = load_dotenv_file(os.path.join(repo_root, ".env"))
195
- pkg_env = load_dotenv_file(os.path.join(repo_root, "synth_ai", "demos", "demo_task_apps", "math", ".env"))
220
+ pkg_env = load_dotenv_file(
221
+ os.path.join(repo_root, "synth_ai", "demos", "demo_task_apps", "math", ".env")
222
+ )
196
223
  examples_env = load_dotenv_file(os.path.join(repo_root, "examples", "rl", ".env"))
197
224
 
198
225
  state = _read_state()
@@ -216,15 +243,12 @@ def load_env() -> DemoEnv:
216
243
  or pkg_env.get("DEV_BACKEND_URL")
217
244
  or ""
218
245
  ).strip()
219
- use_dev = False
220
246
  if backend_override:
221
247
  dev_url = backend_override
222
- use_dev = True
223
248
  elif dev_env:
224
249
  lower = dev_env.lower()
225
250
  if "localhost" in lower or "127.0.0.1" in lower or lower.endswith(":8000"):
226
251
  dev_url = dev_env
227
- use_dev = True
228
252
  else:
229
253
  dev_url = prod_default
230
254
  else:
@@ -241,7 +265,11 @@ def load_env() -> DemoEnv:
241
265
  or str(state.get("SYNTH_API_KEY") or "")
242
266
  )
243
267
  if not synth_api_key:
244
- mode = "prod" if default_root in dev_url else ("local" if ("localhost" in dev_url or "127.0.0.1" in dev_url) else "dev")
268
+ mode = (
269
+ "prod"
270
+ if default_root in dev_url
271
+ else ("local" if ("localhost" in dev_url or "127.0.0.1" in dev_url) else "dev")
272
+ )
245
273
  if mode == "prod":
246
274
  synth_api_key = (
247
275
  os_env.get("PROD_SYNTH_API_KEY")
@@ -310,7 +338,9 @@ def load_env() -> DemoEnv:
310
338
  return env
311
339
 
312
340
 
313
- def assert_http_ok(url: str, method: str = "GET", allow_redirects: bool = True, timeout: float = 10.0) -> bool:
341
+ def assert_http_ok(
342
+ url: str, method: str = "GET", allow_redirects: bool = True, timeout: float = 10.0
343
+ ) -> bool:
314
344
  try:
315
345
  import ssl
316
346
 
@@ -387,18 +417,24 @@ def persist_api_key(key: str) -> None:
387
417
  _write_state(data)
388
418
 
389
419
 
390
- def run_job(env: DemoEnv, config_toml_path: str, *, batch_size: Optional[int] = None, group_size: Optional[int] = None, model: Optional[str] = None) -> None:
420
+ def run_job(
421
+ env: DemoEnv,
422
+ config_toml_path: str,
423
+ *,
424
+ batch_size: int | None = None,
425
+ group_size: int | None = None,
426
+ model: str | None = None,
427
+ ) -> None:
391
428
  """Create and stream a short RL job using the backend API (placeholder: prints cURL to execute)."""
392
429
  backend = env.dev_backend_url.rstrip("/")
393
- if backend.endswith("/api"):
394
- api_base = backend
395
- else:
396
- api_base = backend + "/api"
430
+ api_base = backend if backend.endswith("/api") else backend + "/api"
397
431
  print("\nTo create an RL job, run:")
398
432
  print(
399
- "curl -s -X POST \"" + api_base + "/rl/jobs\" "
433
+ 'curl -s -X POST "' + api_base + '/rl/jobs" '
400
434
  "-H 'Content-Type: application/json' "
401
435
  f"-H 'Authorization: Bearer {env.synth_api_key}' "
402
436
  "-d '{" # intentionally not fully formed here for brevity in this scaffold
403
437
  )
404
- print(" NOTE: CLI implementation will build the full JSON body with inline TOML config and stream events.")
438
+ print(
439
+ " NOTE: CLI implementation will build the full JSON body with inline TOML config and stream events."
440
+ )
@@ -8,8 +8,7 @@ variety = "fft"
8
8
 
9
9
  [job]
10
10
  model = "Qwen/Qwen3-4B"
11
- # Limit training to the first 100 conversations (export a 100-row JSONL and point to it here)
12
- # data = "../ft_data/qwen3_32b_ach_ge3_raw_filtered.head100.jsonl"
11
+ data = "ft_data/crafter_traces.jsonl"
13
12
 
14
13
  [compute]
15
14
  # Adjust as needed for your quota
@@ -23,7 +22,7 @@ topology = {}
23
22
 
24
23
  # Optional local validation dataset path (JSONL). If set, the client will upload
25
24
  # this file and wire up validation so the frontend can display val.loss.
26
- validation_path = "../ft_data/qwen3_32b_ach_ge3_raw_filtered.tokens_1000000_seed_123.val_2000.jsonl"
25
+ # validation_path = "../ft_data/crafter_validation.jsonl"
27
26
 
28
27
  [training]
29
28
  mode = "sft_offline"
@@ -1,51 +1,57 @@
1
-
2
1
  """Compatibility wrapper for the GRPO Crafter task app.
3
2
 
4
- This module now delegates to the shared TaskAppConfig defined in
5
- `synth_ai.task.apps.grpo_crafter`. It is kept for legacy usage (running the
6
- file directly or targeting `fastapi_app` from external tooling). Prefer using
7
- `uvx synth-ai serve grpo-crafter` for local development and testing.
3
+ This module now delegates to the TaskAppConfig defined in the local example at
4
+ `examples/warming_up_to_rl/task_app/grpo_crafter.py`. It is kept for legacy usage
5
+ (running the file directly or targeting `fastapi_app` from external tooling).
6
+ Prefer using `uvx synth-ai serve grpo-crafter` for local development and testing.
8
7
  """
9
8
 
10
9
  from __future__ import annotations
11
10
 
12
11
  import argparse
12
+ import importlib.util
13
13
  from pathlib import Path
14
14
 
15
15
  from fastapi.exceptions import RequestValidationError
16
16
  from fastapi.responses import JSONResponse
17
17
  from starlette.requests import Request
18
-
19
18
  from synth_ai.task.apps import ModalDeploymentConfig, registry
20
- from synth_ai.task.apps.grpo_crafter import build_config
21
19
  from synth_ai.task.auth import is_api_key_header_authorized, normalize_environment_api_key
22
20
  from synth_ai.task.server import TaskAppConfig, create_task_app, run_task_app
23
21
 
24
22
 
23
+ def _load_build_config():
24
+ # Find synth_ai package location to locate examples/
25
+ import synth_ai
26
+
27
+ synth_ai_path = Path(synth_ai.__file__).resolve().parent.parent
28
+ module_path = synth_ai_path / "examples" / "warming_up_to_rl" / "task_app" / "grpo_crafter.py"
29
+
30
+ if not module_path.exists():
31
+ raise ImportError(
32
+ f"Could not find task app module at {module_path}. Make sure you're running from the synth-ai repository."
33
+ )
34
+
35
+ spec = importlib.util.spec_from_file_location(
36
+ "warming_up_to_rl.task_app.grpo_crafter", module_path
37
+ )
38
+ if spec is None or spec.loader is None:
39
+ raise ImportError(f"Could not load task app module at {module_path}")
40
+ module = importlib.util.module_from_spec(spec)
41
+ spec.loader.exec_module(module)
42
+ return module.build_config
43
+
44
+
45
+ build_config = _load_build_config()
46
+
47
+
25
48
  APP_ID = "grpo-crafter"
26
49
 
27
50
 
28
- _BASE_CONFIG = build_config()
29
- TASK_APP_CONFIG = TaskAppConfig(
30
- app_id="grpo-crafter",
31
- name=_BASE_CONFIG.name,
32
- description=_BASE_CONFIG.description,
33
- base_task_info=_BASE_CONFIG.base_task_info,
34
- describe_taskset=_BASE_CONFIG.describe_taskset,
35
- provide_task_instances=_BASE_CONFIG.provide_task_instances,
36
- rollout=_BASE_CONFIG.rollout,
37
- dataset_registry=_BASE_CONFIG.dataset_registry,
38
- rubrics=_BASE_CONFIG.rubrics,
39
- proxy=_BASE_CONFIG.proxy,
40
- routers=_BASE_CONFIG.routers,
41
- middleware=_BASE_CONFIG.middleware,
42
- app_state=_BASE_CONFIG.app_state,
43
- require_api_key=_BASE_CONFIG.require_api_key,
44
- expose_debug_env=_BASE_CONFIG.expose_debug_env,
45
- cors_origins=_BASE_CONFIG.cors_origins,
46
- startup_hooks=_BASE_CONFIG.startup_hooks,
47
- shutdown_hooks=_BASE_CONFIG.shutdown_hooks,
48
- )
51
+ def _build_base_config() -> TaskAppConfig:
52
+ # Lazily construct the base config to avoid heavy work at import time
53
+ return build_config()
54
+
49
55
 
50
56
  try:
51
57
  _REGISTERED_ENTRY = registry.get(APP_ID)
@@ -60,7 +66,8 @@ else:
60
66
  def build_task_app_config() -> TaskAppConfig:
61
67
  """Return a fresh TaskAppConfig for this wrapper."""
62
68
 
63
- return TASK_APP_CONFIG.clone()
69
+ base = _build_base_config()
70
+ return base.clone()
64
71
 
65
72
 
66
73
  def fastapi_app():
@@ -122,7 +129,7 @@ def fastapi_app():
122
129
  try:
123
130
  hdr = request.headers
124
131
  snapshot = {
125
- "path": str(getattr(request, "url").path),
132
+ "path": str(request.url.path),
126
133
  "have_x_api_key": bool(hdr.get("x-api-key")),
127
134
  "have_x_api_keys": bool(hdr.get("x-api-keys")),
128
135
  "have_authorization": bool(hdr.get("authorization")),
@@ -6,6 +6,7 @@ This module provides a local fallback for install_problem_bank_into_shared so
6
6
  the modal task app can import it without requiring an external math_rl package.
7
7
  """
8
8
 
9
+
9
10
  def install_problem_bank_into_shared() -> None:
10
11
  """No-op placeholder for installing the Hendrycks MATH problem bank.
11
12
 
@@ -13,5 +14,3 @@ def install_problem_bank_into_shared() -> None:
13
14
  into a shared directory. For the demo scaffold, it is a no-op.
14
15
  """
15
16
  return None
16
-
17
-
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import os
4
+
4
5
  from fastapi import FastAPI
5
6
  from starlette.middleware.cors import CORSMiddleware
6
7
 
@@ -11,7 +12,7 @@ except Exception: # fallback path when imported from repo root
11
12
  try:
12
13
  from examples.rl.task_app import make_app as make_rl_app # type: ignore
13
14
  except Exception as e: # pragma: no cover
14
- raise ImportError(f"Unable to import RL task app: {e}")
15
+ raise ImportError(f"Unable to import RL task app: {e}") from e
15
16
 
16
17
 
17
18
  def create_app() -> FastAPI:
@@ -2,10 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
  import subprocess
5
- from typing import Optional
6
5
 
7
6
 
8
- def _parse_public_url_from_log(log_path: str) -> Optional[str]:
7
+ def _parse_public_url_from_log(log_path: str) -> str | None:
9
8
  try:
10
9
  with open(log_path) as fh:
11
10
  for line in fh:
@@ -16,7 +15,7 @@ def _parse_public_url_from_log(log_path: str) -> Optional[str]:
16
15
  return None
17
16
 
18
17
 
19
- def deploy(script_path: Optional[str] = None, *, env_api_key: Optional[str] = None) -> str:
18
+ def deploy(script_path: str | None = None, *, env_api_key: str | None = None) -> str:
20
19
  """
21
20
  Deploy the Math Task App to Modal and return the public URL.
22
21
 
@@ -55,6 +54,4 @@ def deploy(script_path: Optional[str] = None, *, env_api_key: Optional[str] = No
55
54
  raise RuntimeError(
56
55
  f"No deploy script provided and Python-based deploy failed: {e}. "
57
56
  "Pass --script /path/to/deploy_task_app.sh to demo.deploy."
58
- )
59
-
60
-
57
+ ) from e