synth-ai 0.2.13.dev1__py3-none-any.whl → 0.2.14__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 (291) hide show
  1. examples/multi_step/configs/README_verilog_rl.md +77 -0
  2. examples/multi_step/configs/VERILOG_REWARDS.md +90 -0
  3. examples/multi_step/configs/VERILOG_RL_CHECKLIST.md +183 -0
  4. examples/multi_step/configs/crafter_eval_synth_qwen4b.toml +35 -0
  5. examples/multi_step/configs/crafter_eval_text_only_groq_qwen32b.toml +36 -0
  6. examples/multi_step/configs/crafter_rl_stepwise_hosted_judge.toml +17 -5
  7. examples/multi_step/configs/crafter_synth_backend.md +40 -0
  8. examples/multi_step/configs/verilog_eval_groq_qwen32b.toml +31 -0
  9. examples/multi_step/configs/verilog_eval_synth_qwen8b.toml +33 -0
  10. examples/multi_step/configs/verilog_rl_lora.toml +190 -0
  11. examples/multi_step/judges/crafter_backend_judge.py +220 -0
  12. examples/multi_step/judges/verilog_backend_judge.py +234 -0
  13. examples/multi_step/readme.md +48 -0
  14. examples/multi_step/verilog_rl_lora.md +218 -0
  15. examples/qwen_coder/configs/coder_lora_30b.toml +1 -1
  16. examples/sft/evaluate.py +2 -0
  17. examples/sft/generate_traces.py +2 -0
  18. examples/swe/task_app/grpo_swe_mini.py +56 -26
  19. examples/swe/task_app/hosted/rollout.py +42 -0
  20. examples/swe/task_app/hosted/test_service.py +5 -6
  21. examples/task_apps/IMAGE_ONLY_EVAL_QUICKSTART.md +258 -0
  22. examples/task_apps/TESTING.md +275 -0
  23. examples/task_apps/__init__.py +0 -0
  24. examples/task_apps/crafter/CREATE_SFT_DATASET.md +273 -0
  25. examples/task_apps/crafter/EVAL_IMAGE_ONLY_RESULTS.md +152 -0
  26. examples/task_apps/crafter/FILTER_COMMAND_STATUS.md +174 -0
  27. examples/task_apps/crafter/FILTER_COMMAND_SUCCESS.md +268 -0
  28. examples/task_apps/crafter/QUERY_EXAMPLES.md +203 -0
  29. examples/task_apps/crafter/README_IMAGE_ONLY_EVAL.md +316 -0
  30. examples/task_apps/crafter/__init__.py +0 -0
  31. examples/task_apps/crafter/eval_image_only_gpt4o.toml +28 -0
  32. examples/task_apps/crafter/eval_text_only_groq_llama.toml +36 -0
  33. examples/task_apps/crafter/filter_sft_dataset.toml +16 -0
  34. examples/task_apps/crafter/task_app/__init__.py +5 -0
  35. examples/{warming_up_to_rl → task_apps/crafter}/task_app/grpo_crafter.py +324 -21
  36. examples/{warming_up_to_rl → task_apps/crafter}/task_app/grpo_crafter_task_app.py +1 -1
  37. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/environment.py +10 -0
  38. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/policy.py +76 -7
  39. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/react_agent.py +17 -2
  40. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/inference/openai_client.py +25 -3
  41. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/policy_routes.py +77 -4
  42. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/rollout.py +117 -9
  43. examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/test_service.py +5 -6
  44. examples/task_apps/crafter/task_app/synth_envs_hosted/utils.py +218 -0
  45. examples/task_apps/dev/pokemon_emerald/__init__.py +2 -0
  46. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/README.md +811 -0
  47. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/__init__.py +120 -0
  48. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/action.py +160 -0
  49. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/memory.py +155 -0
  50. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/perception.py +69 -0
  51. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/planning.py +96 -0
  52. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/simple.py +1502 -0
  53. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/system_prompt.py +4 -0
  54. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/grab_map.py +68 -0
  55. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/manual.py +216 -0
  56. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/__init__.py +35 -0
  57. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emerald_utils.py +631 -0
  58. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emulator.py +1544 -0
  59. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/enums.py +1428 -0
  60. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/memory_reader.py +4848 -0
  61. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/types.py +41 -0
  62. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/utils.py +298 -0
  63. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pyproject.toml +95 -0
  64. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/run.py +204 -0
  65. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/__init__.py +0 -0
  66. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/app.py +2152 -0
  67. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/client.py +429 -0
  68. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/frame_server.py +155 -0
  69. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/README.md +78 -0
  70. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/__init__.py +0 -0
  71. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/run_tests.py +122 -0
  72. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_direct.py +76 -0
  73. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_prompts.py +413 -0
  74. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_battle_state_formatting.py +204 -0
  75. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection.py +133 -0
  76. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection_comprehensive.py +229 -0
  77. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_direct_agent_emulator.py +300 -0
  78. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_fps_adjustment_pytest.py +205 -0
  79. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_direct.py +200 -0
  80. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_transition.py +284 -0
  81. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_map_ground_truth_comparison.py +468 -0
  82. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_memory_map.py +575 -0
  83. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_server_map_validation.py +311 -0
  84. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_torchic_state.py +259 -0
  85. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/__init__.py +0 -0
  86. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/anticheat.py +372 -0
  87. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/checkpoint.py +296 -0
  88. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/error_handler.py +275 -0
  89. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/get_local_ip.py +22 -0
  90. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/helpers.py +44 -0
  91. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/llm_logger.py +514 -0
  92. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_formatter.py +415 -0
  93. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher.py +1763 -0
  94. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher_singleton.py +33 -0
  95. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_trimmer.py +106 -0
  96. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_visualizer.py +334 -0
  97. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/ocr_dialogue.py +1020 -0
  98. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/recording.py +188 -0
  99. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/state_formatter.py +1481 -0
  100. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/vlm.py +862 -0
  101. examples/task_apps/dev/pokemon_emerald/modal_app.py +114 -0
  102. examples/task_apps/dev/pokemon_emerald/task_app/README.md +81 -0
  103. examples/task_apps/dev/pokemon_emerald/task_app/__init__.py +6 -0
  104. examples/task_apps/dev/pokemon_emerald/task_app/pokemon_emerald.py +685 -0
  105. examples/task_apps/enron/__init__.py +1 -0
  106. examples/task_apps/enron/eval_groq_qwen32.toml +16 -0
  107. examples/task_apps/enron/filter_sft.toml +5 -0
  108. examples/task_apps/enron/task_app/README.md +14 -0
  109. examples/task_apps/enron/task_app/__init__.py +1 -0
  110. examples/task_apps/enron/task_app/grpo_enron.py +906 -0
  111. examples/task_apps/enron/task_app/grpo_enron_task_app.py +146 -0
  112. examples/task_apps/enron/tests/__init__.py +4 -0
  113. examples/task_apps/enron/tests/conftest.py +115 -0
  114. examples/task_apps/enron/tests/integration/__init__.py +4 -0
  115. examples/task_apps/enron/tests/integration/test_enron_eval.py +179 -0
  116. examples/task_apps/enron/tests/integration/test_enron_rollout.py +135 -0
  117. examples/task_apps/enron/tests/unit/__init__.py +4 -0
  118. examples/task_apps/enron/tests/unit/test_enron_environment.py +126 -0
  119. examples/task_apps/math/__init__.py +0 -0
  120. examples/{rl/task_app → task_apps/math}/math_single_step.py +19 -10
  121. examples/task_apps/pokemon_battle/__init__.py +2 -0
  122. examples/task_apps/pokemon_battle/modal_app.py +104 -0
  123. examples/task_apps/pokemon_battle/task_app/README.md +68 -0
  124. examples/task_apps/pokemon_battle/task_app/__init__.py +6 -0
  125. examples/task_apps/pokemon_battle/task_app/pokemon_showdown.py +932 -0
  126. examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_COMPLETE.md +283 -0
  127. examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_STATUS.md +155 -0
  128. examples/task_apps/pokemon_red/README.md +357 -0
  129. examples/task_apps/pokemon_red/README_IMAGE_ONLY_EVAL.md +415 -0
  130. examples/task_apps/pokemon_red/__init__.py +3 -0
  131. examples/task_apps/pokemon_red/eval_image_only_gpt4o.toml +29 -0
  132. examples/task_apps/pokemon_red/eval_pokemon_red_policy.py +225 -0
  133. examples/task_apps/pokemon_red/pallet_town_rl_config.toml +75 -0
  134. examples/task_apps/pokemon_red/task_app.py +799 -0
  135. examples/task_apps/pokemon_red/test_pallet_town_rewards.py +193 -0
  136. examples/task_apps/sokoban/README.md +307 -0
  137. examples/task_apps/sokoban/__init__.py +3 -0
  138. examples/task_apps/sokoban/eval_groq_qwen32.toml +16 -0
  139. examples/task_apps/sokoban/eval_openai_gpt5.toml +16 -0
  140. examples/task_apps/sokoban/filter_sft.toml +5 -0
  141. examples/task_apps/sokoban/task_app.py +1058 -0
  142. examples/task_apps/sokoban/tests/__init__.py +4 -0
  143. examples/task_apps/sokoban/tests/conftest.py +113 -0
  144. examples/task_apps/sokoban/tests/integration/__init__.py +4 -0
  145. examples/task_apps/sokoban/tests/integration/test_sokoban_eval.py +57 -0
  146. examples/task_apps/sokoban/tests/integration/test_sokoban_rollout.py +198 -0
  147. examples/task_apps/sokoban/tests/unit/__init__.py +4 -0
  148. examples/task_apps/sokoban/tests/unit/test_sokoban_environment.py +114 -0
  149. examples/task_apps/verilog/__init__.py +1 -0
  150. examples/task_apps/verilog/eval_groq_qwen32b.toml +24 -0
  151. examples/task_apps/verilog/filter_sft.toml +5 -0
  152. examples/task_apps/verilog/task_app/README.md +12 -0
  153. examples/task_apps/verilog/task_app/__init__.py +1 -0
  154. examples/task_apps/verilog/task_app/grpo_verilog.py +1166 -0
  155. examples/task_apps/verilog/task_app/grpo_verilog_task_app.py +145 -0
  156. examples/task_apps/verilog/tests/__init__.py +4 -0
  157. examples/task_apps/verilog/tests/conftest.py +115 -0
  158. examples/task_apps/verilog/tests/integration/__init__.py +4 -0
  159. examples/task_apps/verilog/tests/integration/test_verilog_eval.py +181 -0
  160. examples/task_apps/verilog/tests/integration/test_verilog_rollout.py +55 -0
  161. examples/task_apps/verilog/tests/unit/__init__.py +4 -0
  162. examples/task_apps/verilog/tests/unit/test_verilog_scoring.py +118 -0
  163. examples/vlm/crafter_openai_vlm_agent.py +4 -4
  164. examples/vlm/run_crafter_vlm_benchmark.py +4 -4
  165. examples/warming_up_to_rl/groq_test.py +2 -0
  166. examples/warming_up_to_rl/run_local_rollout.py +2 -0
  167. examples/warming_up_to_rl/run_local_rollout_modal.py +2 -0
  168. examples/warming_up_to_rl/run_local_rollout_parallel.py +2 -0
  169. examples/warming_up_to_rl/run_local_rollout_traced.py +2 -0
  170. examples/warming_up_to_rl/run_rollout_remote.py +2 -0
  171. examples/workflows/__init__.py +0 -0
  172. examples/workflows/math_rl/__init__.py +0 -0
  173. examples/workflows/math_rl/download_dataset.py +80 -0
  174. synth_ai/__init__.py +2 -2
  175. synth_ai/api/models/supported.py +1 -0
  176. synth_ai/api/train/builders.py +25 -11
  177. synth_ai/api/train/cli.py +12 -6
  178. synth_ai/api/train/configs/__init__.py +10 -10
  179. synth_ai/api/train/configs/rl.py +5 -4
  180. synth_ai/api/train/configs/sft.py +4 -3
  181. synth_ai/api/train/env_resolver.py +5 -2
  182. synth_ai/api/train/supported_algos.py +10 -5
  183. synth_ai/api/train/utils.py +7 -4
  184. synth_ai/cli/__init__.py +48 -59
  185. synth_ai/cli/_modal_wrapper.py +3 -2
  186. synth_ai/cli/_storage.py +4 -3
  187. synth_ai/cli/_validate_task_app.py +11 -0
  188. synth_ai/cli/balance.py +4 -3
  189. synth_ai/cli/calc.py +2 -2
  190. synth_ai/cli/demo.py +14 -7
  191. synth_ai/cli/legacy_root_backup.py +1 -1
  192. synth_ai/cli/recent.py +1 -1
  193. synth_ai/cli/rl_demo.py +8 -7
  194. synth_ai/cli/root.py +0 -97
  195. synth_ai/cli/status.py +1 -1
  196. synth_ai/cli/task_apps.py +1922 -190
  197. synth_ai/cli/traces.py +1 -1
  198. synth_ai/cli/tui.py +57 -0
  199. synth_ai/cli/turso.py +1 -1
  200. synth_ai/cli/watch.py +1 -1
  201. synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +29 -17
  202. synth_ai/environments/examples/crafter_classic/environment.py +1 -1
  203. synth_ai/environments/examples/enron/engine.py +7 -2
  204. synth_ai/environments/examples/enron/environment.py +68 -0
  205. synth_ai/environments/examples/red/engine.py +27 -0
  206. synth_ai/environments/examples/red/engine_helpers/memory_map.py +7 -0
  207. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_progression.py +477 -0
  208. synth_ai/environments/examples/red/engine_helpers/state_extraction.py +32 -0
  209. synth_ai/environments/examples/red/environment.py +60 -0
  210. synth_ai/environments/examples/sokoban/taskset.py +116 -0
  211. synth_ai/environments/examples/verilog/engine.py +104 -12
  212. synth_ai/evals/client.py +58 -61
  213. synth_ai/jobs/client.py +16 -4
  214. synth_ai/judge_schemas.py +9 -9
  215. synth_ai/py.typed +0 -0
  216. synth_ai/task/__init__.py +24 -5
  217. synth_ai/task/apps/__init__.py +1 -0
  218. synth_ai/task/config.py +257 -0
  219. synth_ai/task/contracts.py +138 -39
  220. synth_ai/task/proxy.py +48 -56
  221. synth_ai/task/rubrics/__init__.py +56 -0
  222. synth_ai/task/rubrics/loaders.py +152 -0
  223. synth_ai/task/rubrics/models.py +57 -0
  224. synth_ai/task/rubrics/scoring.py +116 -0
  225. synth_ai/{rubrics/validators.py → task/rubrics/strict.py} +53 -30
  226. synth_ai/task/server.py +8 -7
  227. synth_ai/task/trace_correlation_helpers.py +315 -0
  228. synth_ai/task/validators.py +413 -6
  229. synth_ai/tracing_v3/abstractions.py +3 -3
  230. synth_ai/tracing_v3/decorators.py +7 -3
  231. synth_ai/tracing_v3/llm_call_record_helpers.py +5 -5
  232. synth_ai/tracing_v3/replica_sync.py +4 -4
  233. synth_ai/tracing_v3/serialization.py +5 -5
  234. synth_ai/tracing_v3/session_tracer.py +16 -6
  235. synth_ai/tracing_v3/storage/base.py +29 -29
  236. synth_ai/tracing_v3/storage/config.py +3 -3
  237. synth_ai/tracing_v3/trace_utils.py +317 -0
  238. synth_ai/tracing_v3/turso/daemon.py +8 -7
  239. synth_ai/tracing_v3/turso/native_manager.py +66 -43
  240. synth_ai/tracing_v3/utils.py +3 -3
  241. synth_ai/tui/__init__.py +5 -0
  242. synth_ai/tui/__main__.py +13 -0
  243. synth_ai/tui/cli/__init__.py +1 -0
  244. synth_ai/tui/cli/query_experiments.py +164 -0
  245. synth_ai/tui/cli/query_experiments_v3.py +164 -0
  246. synth_ai/tui/dashboard.py +906 -0
  247. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/METADATA +4 -1
  248. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/RECORD +278 -126
  249. examples/agora_ex/README_MoE.md +0 -224
  250. examples/agora_ex/__init__.py +0 -7
  251. examples/agora_ex/agora_ex.py +0 -65
  252. examples/agora_ex/agora_ex_task_app.py +0 -590
  253. examples/agora_ex/configs/rl_lora_qwen3_moe_2xh200.toml +0 -121
  254. examples/agora_ex/reward_fn_grpo-human.py +0 -129
  255. examples/agora_ex/system_prompt_CURRENT.md +0 -63
  256. examples/agora_ex/task_app/agora_ex_task_app.py +0 -590
  257. examples/agora_ex/task_app/reward_fn_grpo-human.py +0 -129
  258. examples/agora_ex/task_app/system_prompt_CURRENT.md +0 -63
  259. examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +0 -62
  260. synth_ai/rubrics/__init__.py +0 -22
  261. synth_ai/task/rubrics.py +0 -219
  262. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/README.md +0 -0
  263. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/README.md +0 -0
  264. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/__init__.py +0 -0
  265. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/branching.py +0 -0
  266. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/environment_routes.py +0 -0
  267. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/__init__.py +0 -0
  268. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/__init__.py +0 -0
  269. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/app.py +0 -0
  270. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/shared.py +0 -0
  271. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/envs/crafter/tools.py +0 -0
  272. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/hosted_app.py +0 -0
  273. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/inference/__init__.py +0 -0
  274. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/main.py +0 -0
  275. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/registry.py +0 -0
  276. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/storage/__init__.py +0 -0
  277. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/storage/volume.py +0 -0
  278. /examples/{warming_up_to_rl → task_apps/crafter}/task_app/synth_envs_hosted/test_agents.py +0 -0
  279. /examples/{rl/task_app → task_apps/math}/README.md +0 -0
  280. /examples/{rl/task_app → task_apps/math}/math_task_app.py +0 -0
  281. /examples/{rl → workflows/math_rl}/configs/eval_base_qwen.toml +0 -0
  282. /examples/{rl → workflows/math_rl}/configs/eval_rl_qwen.toml +0 -0
  283. /examples/{rl → workflows/math_rl}/configs/rl_from_base_qwen.toml +0 -0
  284. /examples/{rl → workflows/math_rl}/configs/rl_from_base_qwen17.toml +0 -0
  285. /examples/{rl → workflows/math_rl}/configs/rl_from_ft_qwen.toml +0 -0
  286. /examples/{rl → workflows/math_rl}/run_eval.py +0 -0
  287. /examples/{rl → workflows/math_rl}/run_rl_and_save.py +0 -0
  288. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/WHEEL +0 -0
  289. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/entry_points.txt +0 -0
  290. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/licenses/LICENSE +0 -0
  291. {synth_ai-0.2.13.dev1.dist-info → synth_ai-0.2.14.dist-info}/top_level.txt +0 -0
@@ -42,8 +42,10 @@ def build_rollout_request(
42
42
  trace_format=trace_format,
43
43
  return_trace=return_trace,
44
44
  )
45
+ from synth_ai.task.contracts import RolloutMode
45
46
  return RolloutRequest(
46
47
  run_id=run_id,
48
+ mode=RolloutMode.EVAL,
47
49
  env=RolloutEnvSpec(env_name="crafter", seed=seed, config={}),
48
50
  policy=RolloutPolicySpec(policy_name="crafter-react", config=policy_config),
49
51
  ops=ops,
@@ -33,12 +33,14 @@ def build_rollout_request(
33
33
  "Authorization": f"Bearer {api_key}",
34
34
  },
35
35
  }
36
+ from synth_ai.task.contracts import RolloutMode
36
37
  return RolloutRequest(
37
38
  run_id=run_id,
38
39
  env=RolloutEnvSpec(env_name="crafter", seed=seed, config={}),
39
40
  policy=RolloutPolicySpec(policy_name="crafter-react", config=policy_config),
40
41
  ops=ops,
41
42
  record=RolloutRecordConfig(trajectories=True),
43
+ mode=RolloutMode.EVAL,
42
44
  on_done="reset",
43
45
  safety=RolloutSafetyConfig(),
44
46
  )
@@ -46,12 +46,14 @@ def build_rollout_request(
46
46
  trace_format=trace_format,
47
47
  return_trace=return_trace,
48
48
  )
49
+ from synth_ai.task.contracts import RolloutMode
49
50
  return RolloutRequest(
50
51
  run_id=run_id,
51
52
  env=RolloutEnvSpec(env_name="crafter", seed=seed, config={}),
52
53
  policy=RolloutPolicySpec(policy_name="crafter-react", config=policy_config),
53
54
  ops=ops,
54
55
  record=record_cfg,
56
+ mode=RolloutMode.EVAL,
55
57
  on_done="reset",
56
58
  safety=RolloutSafetyConfig(),
57
59
  )
@@ -53,12 +53,14 @@ def build_rollout_request(
53
53
  trace_format=trace_format,
54
54
  )
55
55
 
56
+ from synth_ai.task.contracts import RolloutMode
56
57
  return RolloutRequest(
57
58
  run_id=run_id,
58
59
  env=RolloutEnvSpec(env_name="crafter", seed=seed, config={}),
59
60
  policy=RolloutPolicySpec(policy_name="crafter-react", config=policy_config),
60
61
  ops=ops,
61
62
  record=record,
63
+ mode=RolloutMode.EVAL,
62
64
  on_done="reset",
63
65
  safety=RolloutSafetyConfig(),
64
66
  )
@@ -60,12 +60,14 @@ def build_request(
60
60
  for _ in range(max(llm_calls, 1)):
61
61
  ops.extend(["agent", "env"])
62
62
 
63
+ from synth_ai.task.contracts import RolloutMode
63
64
  return RolloutRequest(
64
65
  run_id=run_id,
65
66
  env=RolloutEnvSpec(env_name="crafter", seed=seed, config={}),
66
67
  policy=RolloutPolicySpec(policy_name="crafter-react", config=policy_config),
67
68
  ops=ops,
68
69
  record=RolloutRecordConfig(trajectories=True),
70
+ mode=RolloutMode.EVAL,
69
71
  on_done="reset",
70
72
  safety=RolloutSafetyConfig(),
71
73
  )
File without changes
File without changes
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env python3
2
+ """Download subsets of the MATH dataset to local JSONL files."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from datasets import load_dataset
12
+
13
+
14
+ def extract_examples(dataset: Any, *, limit: int | None) -> list[dict[str, str]]:
15
+ if limit is not None:
16
+ dataset = dataset.select(range(min(limit, len(dataset))))
17
+ examples: list[dict[str, str]] = []
18
+ for item in dataset:
19
+ problem = (item.get("problem") or "").strip()
20
+ solution = item.get("solution") or ""
21
+ if isinstance(solution, list):
22
+ solution = "\n".join(str(part) for part in solution)
23
+ examples.append(
24
+ {
25
+ "problem": problem,
26
+ "solution": solution,
27
+ }
28
+ )
29
+ return examples
30
+
31
+
32
+ def write_jsonl(path: Path, rows: list[dict[str, str]]) -> None:
33
+ path.parent.mkdir(parents=True, exist_ok=True)
34
+ with path.open("w", encoding="utf-8") as fh:
35
+ for row in rows:
36
+ fh.write(json.dumps(row, ensure_ascii=False) + "\n")
37
+
38
+
39
+ def main() -> None:
40
+ parser = argparse.ArgumentParser(
41
+ description="Download MATH dataset splits to JSONL for offline use"
42
+ )
43
+ parser.add_argument(
44
+ "--output-dir", default="examples/rl/data", help="Directory to write <split>.jsonl files"
45
+ )
46
+ parser.add_argument(
47
+ "--dataset",
48
+ default="nlile/hendrycks-MATH-benchmark",
49
+ help="Hugging Face dataset identifier",
50
+ )
51
+ parser.add_argument(
52
+ "--config", default="algebra", help="Hugging Face dataset config (if required)"
53
+ )
54
+ parser.add_argument(
55
+ "--splits", nargs="*", default=["train", "validation", "test"], help="Splits to download"
56
+ )
57
+ parser.add_argument(
58
+ "--limit", type=int, default=None, help="Optional cap on examples per split"
59
+ )
60
+ args = parser.parse_args()
61
+
62
+ output_dir = Path(args.output_dir).expanduser()
63
+ output_dir.mkdir(parents=True, exist_ok=True)
64
+
65
+ for split in args.splits:
66
+ print(f"[INFO] Downloading {args.dataset} ({args.config}) split={split}")
67
+ if args.config:
68
+ dataset = load_dataset(args.dataset, args.config, split=split)
69
+ else:
70
+ dataset = load_dataset(args.dataset, split=split)
71
+ rows = extract_examples(dataset, limit=args.limit)
72
+ out_path = output_dir / f"{split}.jsonl"
73
+ write_jsonl(out_path, rows)
74
+ print(f"[INFO] Wrote {len(rows)} examples to {out_path}")
75
+
76
+ print("Done. Set MATH_DATASET_LOCAL_DIR to the output directory when serving the task app.")
77
+
78
+
79
+ if __name__ == "__main__":
80
+ main()
synth_ai/__init__.py CHANGED
@@ -45,13 +45,13 @@ except Exception:
45
45
 
46
46
  # Judge API contract schemas
47
47
  from synth_ai.judge_schemas import (
48
+ CriterionScorePayload,
49
+ JudgeOptions,
48
50
  JudgeScoreRequest,
49
51
  JudgeScoreResponse,
50
- JudgeOptions,
51
52
  JudgeTaskApp,
52
53
  JudgeTracePayload,
53
54
  ReviewPayload,
54
- CriterionScorePayload,
55
55
  )
56
56
 
57
57
  # Legacy tracing v1 is not required for v3 usage and can be unavailable in minimal envs.
@@ -36,6 +36,7 @@ QWEN3_CODER_MODELS: list[str] = [
36
36
  # Training support sets
37
37
  RL_SUPPORTED_MODELS: frozenset[str] = frozenset(
38
38
  {
39
+ "Qwen/Qwen3-0.6B",
39
40
  "Qwen/Qwen3-1.7B",
40
41
  "Qwen/Qwen3-4B",
41
42
  "Qwen/Qwen3-4B-Thinking-2507",
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import importlib
4
+ from collections.abc import Callable
4
5
  from dataclasses import dataclass
5
6
  from pathlib import Path
6
7
  from typing import Any, cast
@@ -9,25 +10,36 @@ import click
9
10
  from pydantic import ValidationError
10
11
 
11
12
  try:
12
- _models_module = importlib.import_module("synth_ai.api.models.supported")
13
- UnsupportedModelError = _models_module.UnsupportedModelError
14
- ensure_allowed_model = _models_module.ensure_allowed_model
15
- normalize_model_identifier = _models_module.normalize_model_identifier
13
+ _models_module = cast(
14
+ Any, importlib.import_module("synth_ai.api.models.supported")
15
+ )
16
+ UnsupportedModelError = cast(type[Exception], _models_module.UnsupportedModelError)
17
+ ensure_allowed_model = cast(
18
+ Callable[..., None], _models_module.ensure_allowed_model
19
+ )
20
+ normalize_model_identifier = cast(
21
+ Callable[[str], str], _models_module.normalize_model_identifier
22
+ )
16
23
  except Exception as exc: # pragma: no cover - critical dependency
17
24
  raise RuntimeError("Unable to load supported model helpers") from exc
18
25
 
19
26
  try:
20
- prepare_sft_job_payload = importlib.import_module("synth_ai.learning.sft.config").prepare_sft_job_payload
27
+ _sft_module = cast(
28
+ Any, importlib.import_module("synth_ai.learning.sft.config")
29
+ )
30
+ prepare_sft_job_payload = cast(
31
+ Callable[..., dict[str, Any]], _sft_module.prepare_sft_job_payload
32
+ )
21
33
  except Exception as exc: # pragma: no cover - critical dependency
22
34
  raise RuntimeError("Unable to load SFT payload helpers") from exc
23
35
 
36
+ from .configs import RLConfig, SFTConfig
24
37
  from .supported_algos import (
25
38
  AlgorithmValidationError,
26
39
  ensure_model_supported_for_algorithm,
27
40
  validate_algorithm_config,
28
41
  )
29
42
  from .utils import TrainError, ensure_api_base
30
- from .configs import RLConfig, SFTConfig
31
43
 
32
44
 
33
45
  @dataclass(slots=True)
@@ -125,7 +137,7 @@ def build_rl_payload(
125
137
  if model_source:
126
138
  model_source = normalize_model_identifier(model_source)
127
139
  if model_base:
128
- model_base = normalize_model_identifier(model_base, allow_finetuned_prefixes=False)
140
+ model_base = normalize_model_identifier(model_base)
129
141
  except UnsupportedModelError as exc:
130
142
  raise click.ClickException(str(exc)) from exc
131
143
 
@@ -304,10 +316,12 @@ def build_sft_payload(
304
316
  )
305
317
  except UnsupportedModelError as exc:
306
318
  raise TrainError(str(exc)) from exc
307
- try:
308
- ensure_model_supported_for_algorithm(base_model, spec)
309
- except AlgorithmValidationError as exc:
310
- raise TrainError(str(exc)) from exc
319
+
320
+ if base_model:
321
+ try:
322
+ ensure_model_supported_for_algorithm(base_model, spec)
323
+ except AlgorithmValidationError as exc:
324
+ raise TrainError(str(exc)) from exc
311
325
 
312
326
  try:
313
327
  payload = prepare_sft_job_payload(
synth_ai/api/train/cli.py CHANGED
@@ -2,15 +2,17 @@ from __future__ import annotations
2
2
 
3
3
  import importlib
4
4
  import os
5
- from collections.abc import Mapping
5
+ from collections.abc import Callable, Mapping
6
6
  from pathlib import Path
7
- from typing import Any
7
+ from typing import Any, cast
8
8
 
9
9
  import click
10
10
 
11
11
  try:
12
- _config_module = importlib.import_module("synth_ai.config.base_url")
13
- get_backend_from_env = _config_module.get_backend_from_env
12
+ _config_module = cast(
13
+ Any, importlib.import_module("synth_ai.config.base_url")
14
+ )
15
+ get_backend_from_env = cast(Callable[[], str], _config_module.get_backend_from_env)
14
16
  except Exception as exc: # pragma: no cover - critical dependency
15
17
  raise RuntimeError("Unable to load backend configuration helpers") from exc
16
18
 
@@ -238,8 +240,12 @@ def train_command(
238
240
  ]
239
241
  if missing_keys:
240
242
  try:
241
- _task_apps_module = importlib.import_module("synth_ai.cli.task_apps")
242
- _interactive_fill_env = _task_apps_module._interactive_fill_env
243
+ _task_apps_module = cast(
244
+ Any, importlib.import_module("synth_ai.cli.task_apps")
245
+ )
246
+ _interactive_fill_env = cast(
247
+ Callable[[Path], Path | None], _task_apps_module._interactive_fill_env
248
+ )
243
249
  except Exception as exc: # pragma: no cover - protective fallback
244
250
  raise click.ClickException(f"Unable to prompt for env values: {exc}") from exc
245
251
 
@@ -1,15 +1,5 @@
1
1
  """Typed training config loaders for RL and SFT jobs."""
2
2
 
3
- from .shared import AlgorithmConfig, ComputeConfig
4
- from .sft import (
5
- HyperparametersConfig,
6
- HyperparametersParallelism,
7
- JobConfig,
8
- SFTConfig,
9
- SFTDataConfig,
10
- TrainingConfig,
11
- TrainingValidationConfig,
12
- )
13
3
  from .rl import (
14
4
  EvaluationConfig,
15
5
  JudgeConfig,
@@ -21,6 +11,16 @@ from .rl import (
21
11
  RolloutConfig,
22
12
  WeightSyncConfig,
23
13
  )
14
+ from .sft import (
15
+ HyperparametersConfig,
16
+ HyperparametersParallelism,
17
+ JobConfig,
18
+ SFTConfig,
19
+ SFTDataConfig,
20
+ TrainingConfig,
21
+ TrainingValidationConfig,
22
+ )
23
+ from .shared import AlgorithmConfig, ComputeConfig
24
24
 
25
25
  __all__ = [
26
26
  "AlgorithmConfig",
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Mapping
3
4
  from pathlib import Path
4
- from typing import Any, Mapping
5
+ from typing import Any
5
6
 
6
7
  from pydantic import model_validator
7
8
 
@@ -21,7 +22,7 @@ class ModelConfig(ExtraModel):
21
22
  label: str
22
23
 
23
24
  @model_validator(mode="after")
24
- def _ensure_exactly_one_source_or_base(self) -> "ModelConfig":
25
+ def _ensure_exactly_one_source_or_base(self) -> ModelConfig:
25
26
  if bool(self.source) == bool(self.base):
26
27
  raise ValueError("Config must set exactly one of [model].source or [model].base")
27
28
  return self
@@ -111,11 +112,11 @@ class RLConfig(ExtraModel):
111
112
  return self.model_dump(mode="python", exclude_none=True)
112
113
 
113
114
  @classmethod
114
- def from_mapping(cls, data: Mapping[str, Any]) -> "RLConfig":
115
+ def from_mapping(cls, data: Mapping[str, Any]) -> RLConfig:
115
116
  return cls.model_validate(dict(data))
116
117
 
117
118
  @classmethod
118
- def from_path(cls, path: Path) -> "RLConfig":
119
+ def from_path(cls, path: Path) -> RLConfig:
119
120
  content = load_toml(path)
120
121
  return cls.from_mapping(content)
121
122
 
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Mapping
3
4
  from pathlib import Path
4
- from typing import Any, Mapping
5
+ from typing import Any
5
6
 
6
7
  from pydantic import Field
7
8
 
@@ -74,11 +75,11 @@ class SFTConfig(ExtraModel):
74
75
  return self.model_dump(mode="python", exclude_none=True)
75
76
 
76
77
  @classmethod
77
- def from_mapping(cls, data: Mapping[str, Any]) -> "SFTConfig":
78
+ def from_mapping(cls, data: Mapping[str, Any]) -> SFTConfig:
78
79
  return cls.model_validate(dict(data))
79
80
 
80
81
  @classmethod
81
- def from_path(cls, path: Path) -> "SFTConfig":
82
+ def from_path(cls, path: Path) -> SFTConfig:
82
83
  content = load_toml(path)
83
84
  return cls.from_mapping(content)
84
85
 
@@ -5,6 +5,7 @@ import os
5
5
  from collections.abc import Callable, Iterable, MutableMapping
6
6
  from dataclasses import dataclass
7
7
  from pathlib import Path
8
+ from typing import Any, cast
8
9
 
9
10
  import click
10
11
 
@@ -14,8 +15,10 @@ from .utils import REPO_ROOT, mask_value, read_env_file, write_env_value
14
15
 
15
16
  def _load_saved_env_path() -> Path | None:
16
17
  try:
17
- module = importlib.import_module("synth_ai.demos.demo_task_apps.core")
18
- loader = module.load_env_file_path
18
+ module = cast(
19
+ Any, importlib.import_module("synth_ai.demos.demo_task_apps.core")
20
+ )
21
+ loader = cast(Callable[[], str | None], module.load_env_file_path)
19
22
  saved_path = loader()
20
23
  if saved_path:
21
24
  return Path(saved_path)
@@ -1,14 +1,19 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import importlib
4
- from collections.abc import Mapping
4
+ from collections.abc import Callable, Mapping
5
5
  from dataclasses import dataclass
6
+ from typing import Any, cast
6
7
 
7
8
  try:
8
- _models_module = importlib.import_module("synth_ai.api.models.supported")
9
- RL_SUPPORTED_MODELS = _models_module.RL_SUPPORTED_MODELS
10
- SFT_SUPPORTED_MODELS = _models_module.SFT_SUPPORTED_MODELS
11
- training_modes_for_model = _models_module.training_modes_for_model
9
+ _models_module = cast(
10
+ Any, importlib.import_module("synth_ai.api.models.supported")
11
+ )
12
+ RL_SUPPORTED_MODELS = cast(tuple[str, ...], _models_module.RL_SUPPORTED_MODELS)
13
+ SFT_SUPPORTED_MODELS = cast(tuple[str, ...], _models_module.SFT_SUPPORTED_MODELS)
14
+ training_modes_for_model = cast(
15
+ Callable[[str], tuple[str, ...]], _models_module.training_modes_for_model
16
+ )
12
17
  except Exception as exc: # pragma: no cover - critical dependency
13
18
  raise RuntimeError("Unable to load supported model metadata") from exc
14
19
 
@@ -8,15 +8,18 @@ import subprocess
8
8
  import tempfile
9
9
  import time
10
10
  import tomllib
11
- from collections.abc import Iterable, Mapping
11
+ from collections.abc import Callable, Iterable, Mapping
12
12
  from dataclasses import dataclass
13
13
  from pathlib import Path
14
- from typing import Any
14
+ from typing import Any, cast
15
15
 
16
16
  import requests
17
17
 
18
18
  try:
19
- collect_sft_jsonl_errors = importlib.import_module("synth_ai.learning.sft").collect_sft_jsonl_errors
19
+ sft_module = cast(Any, importlib.import_module("synth_ai.learning.sft"))
20
+ collect_sft_jsonl_errors = cast(
21
+ Callable[..., list[dict[str, Any]]], sft_module.collect_sft_jsonl_errors
22
+ )
20
23
  except Exception as exc: # pragma: no cover - critical dependency
21
24
  raise RuntimeError("Unable to load SFT JSONL helpers") from exc
22
25
 
@@ -154,7 +157,7 @@ def validate_sft_jsonl(path: Path, *, max_errors: int = 20) -> None:
154
157
 
155
158
  truncated = max_errors is not None and len(issues) >= max_errors
156
159
  suffix = "" if not truncated else f" (showing first {max_errors} issues)"
157
- details = "\n - ".join(issues)
160
+ details = "\n - ".join(cast("list[str]", issues))
158
161
  raise TrainError(f"{path}: Dataset validation failed{suffix}:\n - {details}")
159
162
 
160
163
 
synth_ai/cli/__init__.py CHANGED
@@ -8,6 +8,8 @@ pyproject entry point `synth_ai.cli:cli`.
8
8
  from __future__ import annotations
9
9
 
10
10
  import importlib
11
+ from collections.abc import Callable
12
+ from typing import Any, cast
11
13
 
12
14
  # Load environment variables from a local .env if present (repo root)
13
15
  try:
@@ -20,98 +22,85 @@ except Exception:
20
22
  pass
21
23
 
22
24
  try:
23
- from ._typer_patch import patch_typer_make_metavar
25
+ from synth_ai.cli._typer_patch import patch_typer_make_metavar
24
26
 
25
27
  patch_typer_make_metavar()
26
28
  except Exception:
27
29
  pass
28
30
 
29
31
 
30
- from .root import cli # new canonical CLI entrypoint
32
+ from synth_ai.cli.root import cli # new canonical CLI entrypoint
31
33
 
32
34
  # Register subcommands from this package onto the group
35
+ # Deprecated/legacy commands intentionally not registered: watch/experiments, balance, calc,
36
+ # man, recent, status, traces
33
37
  try:
34
- from . import watch as _watch
38
+ from synth_ai.cli import demo as _demo
35
39
 
36
- _watch.register(cli)
40
+ _demo.register(cli)
37
41
  except Exception:
38
42
  pass
39
43
  try:
40
- from . import balance as _balance
44
+ from synth_ai.cli import turso as _turso
41
45
 
42
- _balance.register(cli)
46
+ _turso.register(cli)
43
47
  except Exception:
44
48
  pass
45
49
  try:
46
- from . import man as _man
47
-
48
- _man.register(cli)
50
+ _train_module = cast(Any, importlib.import_module("synth_ai.api.train"))
51
+ _train_register = cast(Callable[[Any], None], _train_module.register)
52
+ _train_register(cli)
49
53
  except Exception:
50
54
  pass
51
- try:
52
- from . import traces as _traces
53
55
 
54
- _traces.register(cli)
55
- except Exception:
56
- pass
57
- try:
58
- from . import recent as _recent
59
56
 
60
- _recent.register(cli)
61
- except Exception:
62
- pass
57
+ # Import task_app_group conditionally
63
58
  try:
64
- from . import calc as _calc
65
-
66
- _calc.register(cli)
59
+ from synth_ai.cli.task_apps import task_app_group
60
+ cli.add_command(task_app_group, name="task-app")
67
61
  except Exception:
62
+ # Task app functionality not available
68
63
  pass
69
- try:
70
- from . import status as _status
71
64
 
72
- _status.register(cli)
73
- except Exception:
74
- pass
75
- try:
76
- from . import demo as _demo
77
65
 
78
- _demo.register(cli)
79
- except Exception:
80
- pass
81
66
  try:
82
- from . import turso as _turso
83
-
84
- _turso.register(cli)
85
- except Exception:
67
+ # Make task_apps import more robust to handle missing optional dependencies
68
+ import importlib
69
+ task_apps_module = importlib.import_module('synth_ai.cli.task_apps')
70
+ task_apps_module.register(cli)
71
+ except (ImportError, ModuleNotFoundError, TypeError, RuntimeError) as e:
72
+ # Task apps module not available (missing optional dependencies)
73
+ # This is expected - silently skip
86
74
  pass
87
- try:
88
- from . import rl_demo as _rl_demo
89
75
 
90
- _rl_demo.register(cli)
91
- except Exception:
92
- pass
76
+ # Register TUI command - make import completely isolated
77
+ def _register_tui_command():
78
+ """Register TUI command only when called, not during CLI startup."""
79
+ try:
80
+ # Import TUI only when the command is actually used
81
+ from synth_ai.cli.tui import register as tui_register
82
+ tui_register(cli)
83
+ except Exception:
84
+ # TUI not available - this is expected if dependencies are missing
85
+ pass
86
+
87
+ # Add TUI command as a lazy-registered command
93
88
  try:
94
- _train_module = importlib.import_module("synth_ai.api.train")
95
- _train_register = _train_module.register
96
- _train_register(cli)
89
+ # Try to import and register immediately for normal cases
90
+ from synth_ai.cli.tui import register as tui_register
91
+ tui_register(cli)
97
92
  except Exception:
93
+ # If that fails, add a lazy registration that will only happen when called
94
+ # For now, just skip - the command won't be available but CLI won't crash
98
95
  pass
99
96
 
100
-
101
- from .task_apps import task_app_group
102
-
103
- cli.add_command(task_app_group, name="task-app")
104
-
105
-
97
+ # Add task app commands if available
106
98
  try:
107
- from . import task_apps as _task_apps
108
-
109
- _task_apps.register(cli)
99
+ if 'task_app_group' in locals() and hasattr(task_app_group, 'commands'):
100
+ cli.add_command(task_app_group.commands["serve"], name="serve")
101
+ cli.add_command(task_app_group.commands["deploy"], name="deploy")
102
+ cli.add_command(task_app_group.commands["modal-serve"], name="modal-serve")
110
103
  except Exception:
104
+ # Task app commands not available
111
105
  pass
112
-
113
- cli.add_command(task_app_group.commands["serve"], name="serve")
114
- cli.add_command(task_app_group.commands["deploy"], name="deploy")
115
-
116
- cli.add_command(task_app_group.commands["modal-serve"], name="modal-serve")
117
- cli.add_command(task_app_group.commands["info"], name="info")
106
+ # Top-level 'info' alias removed; use `synth-ai task-app info` instead
@@ -6,7 +6,7 @@ import sys
6
6
  def main() -> int:
7
7
  # Apply Typer compatibility patch before Modal CLI bootstraps Click/Typer internals.
8
8
  try:
9
- from ._typer_patch import patch_typer_make_metavar
9
+ from synth_ai.cli._typer_patch import patch_typer_make_metavar
10
10
 
11
11
  patch_typer_make_metavar()
12
12
  except Exception:
@@ -20,7 +20,8 @@ def main() -> int:
20
20
  else:
21
21
  sys.argv = ["modal"]
22
22
 
23
- return modal_main()
23
+ result = modal_main()
24
+ return result if result is not None else 0
24
25
 
25
26
 
26
27
  if __name__ == "__main__":
synth_ai/cli/_storage.py CHANGED
@@ -8,12 +8,13 @@ allowing type checkers to resolve the symbols dynamically.
8
8
  from __future__ import annotations
9
9
 
10
10
  import importlib
11
- from typing import Any
11
+ from collections.abc import Callable
12
+ from typing import Any, cast
12
13
 
13
14
 
14
15
  def load_storage() -> tuple[Any, Any]:
15
16
  """Return (create_storage, StorageConfig) from tracing_v3.storage."""
16
- storage_module = importlib.import_module("synth_ai.tracing_v3.storage")
17
- create_storage = storage_module.create_storage
17
+ storage_module = cast(Any, importlib.import_module("synth_ai.tracing_v3.storage"))
18
+ create_storage = cast(Callable[..., Any], storage_module.create_storage)
18
19
  storage_config = storage_module.StorageConfig
19
20
  return create_storage, storage_config