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,36 +1,37 @@
1
1
  from __future__ import annotations
2
2
 
3
- from pathlib import Path
4
3
  import json
5
- from typing import Any, Dict
6
- from urllib.parse import urlparse
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from synth_ai.learning.sft import SFTDataError, parse_jsonl_line
7
8
 
8
9
 
9
10
  def validate_training_jsonl(path: str | Path, *, sample_lines: int = 50) -> None:
10
11
  p = Path(path)
11
12
  if not p.exists():
12
13
  raise FileNotFoundError(str(p))
13
- lines = p.read_text().splitlines()
14
- if not lines:
14
+
15
+ max_samples = max(1, sample_lines)
16
+ non_empty_lines = 0
17
+
18
+ with p.open("r", encoding="utf-8") as fh:
19
+ for lineno, raw_line in enumerate(fh, start=1):
20
+ stripped = raw_line.strip()
21
+ if not stripped:
22
+ continue
23
+ non_empty_lines += 1
24
+ if non_empty_lines > max_samples:
25
+ break
26
+ try:
27
+ parse_jsonl_line(stripped, min_messages=2)
28
+ except json.JSONDecodeError as exc:
29
+ raise ValueError(f"invalid json on line {lineno}: {exc}") from exc
30
+ except SFTDataError as exc:
31
+ raise ValueError(f"line {lineno}: {exc}") from exc
32
+
33
+ if non_empty_lines == 0:
15
34
  raise ValueError("empty JSONL")
16
- for i, line in enumerate(lines[: max(1, sample_lines) ], start=1):
17
- if not line.strip():
18
- continue
19
- try:
20
- obj = json.loads(line)
21
- except Exception as e:
22
- raise ValueError(f"invalid json on line {i}: {e}") from e
23
- msgs = obj.get("messages")
24
- if not isinstance(msgs, list) or len(msgs) < 2:
25
- raise ValueError(f"line {i}: missing messages[] with at least 2 turns")
26
- roles = [m.get("role") for m in msgs if isinstance(m, dict)]
27
- if not roles or not isinstance(roles[0], str):
28
- raise ValueError(f"line {i}: missing first role")
29
- for m in msgs:
30
- if not isinstance(m, dict):
31
- raise ValueError(f"line {i}: non-dict message")
32
- if not isinstance(m.get("role"), str) or not isinstance(m.get("content"), str) or not m["content"].strip():
33
- raise ValueError(f"line {i}: invalid role/content")
34
35
 
35
36
 
36
37
  def validate_task_app_url(url: str, *, name: str = "TASK_APP_BASE_URL") -> None:
@@ -39,7 +40,7 @@ def validate_task_app_url(url: str, *, name: str = "TASK_APP_BASE_URL") -> None:
39
40
  _vt(url, name=name)
40
41
 
41
42
 
42
- def validate_trainer_cfg_rl(trainer: Dict[str, Any]) -> None:
43
+ def validate_trainer_cfg_rl(trainer: dict[str, Any]) -> None:
43
44
  bs = int(trainer.get("batch_size", 1))
44
45
  gs = int(trainer.get("group_size", 2))
45
46
  if bs < 1:
synth_ai/lm/__init__.py CHANGED
@@ -1,51 +1,25 @@
1
- """
2
- Synth AI Language Model Interface.
1
+ """Deprecated shim forwarding to synth_ai.v0.lm."""
3
2
 
4
- Provides a unified interface for multiple LLM providers including OpenAI and Synth.
5
- """
3
+ import importlib as _importlib
4
+ import pkgutil as _pkgutil
5
+ import sys as _sys
6
+ from pathlib import Path as _Path
6
7
 
7
- from .config import OpenAIConfig, SynthConfig
8
- from .core.main_v3 import LM
9
- from .unified_interface import (
10
- OpenAIProvider,
11
- SynthProvider,
12
- UnifiedLMClient,
13
- UnifiedLMProvider,
14
- create_provider,
15
- )
16
- from .vendors.synth_client import (
17
- AsyncSynthClient,
18
- SyncSynthClient,
19
- create_async_client,
20
- create_chat_completion_async,
21
- create_chat_completion_sync,
22
- create_sync_client,
23
- )
24
- from .warmup import get_warmup_status, warmup_synth_model
8
+ _TARGET_PREFIX = "synth_ai.v0.lm"
9
+ _ALIAS_PREFIX = __name__
25
10
 
26
- __all__ = [
27
- # Configuration
28
- "SynthConfig",
29
- "OpenAIConfig",
30
- # Warmup utilities
31
- "warmup_synth_model",
32
- "get_warmup_status",
33
- # Unified interface
34
- "UnifiedLMProvider",
35
- "OpenAIProvider",
36
- "SynthProvider",
37
- "UnifiedLMClient",
38
- "create_provider",
39
- # Synth client
40
- "AsyncSynthClient",
41
- "SyncSynthClient",
42
- "create_async_client",
43
- "create_sync_client",
44
- "create_chat_completion_async",
45
- "create_chat_completion_sync",
46
- # Core LM class
47
- "LM",
48
- ]
11
+ _alias_path = _Path(__file__).resolve().parents[1] / "v0" / "lm"
12
+ __path__ = [str(_alias_path)] # type: ignore[assignment]
49
13
 
50
- # Version info
51
- __version__ = "0.1.0"
14
+ _pkg = _importlib.import_module(_TARGET_PREFIX)
15
+ _sys.modules[_ALIAS_PREFIX] = _pkg
16
+
17
+ for _finder, _name, _ispkg in _pkgutil.walk_packages(_pkg.__path__, prefix=_TARGET_PREFIX + "."): # type: ignore[attr-defined]
18
+ try:
19
+ _module = _importlib.import_module(_name)
20
+ except Exception: # pragma: no cover - best effort
21
+ continue
22
+ _alias = _ALIAS_PREFIX + _name[len(_TARGET_PREFIX) :]
23
+ _sys.modules[_alias] = _module
24
+
25
+ del _finder, _name, _ispkg, _module, _alias, _TARGET_PREFIX, _ALIAS_PREFIX, _alias_path
synth_ai/task/__init__.py CHANGED
@@ -1,59 +1,58 @@
1
- from .validators import validate_task_app_url
2
- from .health import task_app_health
1
+ from .auth import (
2
+ is_api_key_header_authorized,
3
+ normalize_environment_api_key,
4
+ require_api_key_dependency,
5
+ )
6
+ from .client import TaskAppClient
3
7
  from .contracts import (
4
- TaskAppContract,
5
- TaskAppEndpoints,
6
8
  RolloutEnvSpec,
9
+ RolloutMetrics,
7
10
  RolloutPolicySpec,
8
11
  RolloutRecordConfig,
9
- RolloutSafetyConfig,
10
12
  RolloutRequest,
11
13
  RolloutResponse,
12
- RolloutTrajectory,
14
+ RolloutSafetyConfig,
13
15
  RolloutStep,
14
- RolloutMetrics,
16
+ RolloutTrajectory,
17
+ TaskAppContract,
18
+ TaskAppEndpoints,
15
19
  TaskInfo,
16
20
  )
21
+ from .datasets import TaskDatasetRegistry, TaskDatasetSpec
22
+ from .errors import error_payload, http_exception, json_error_response
23
+ from .health import task_app_health
17
24
  from .json import to_jsonable
18
- from .auth import (
19
- normalize_environment_api_key,
20
- is_api_key_header_authorized,
21
- require_api_key_dependency,
22
- )
23
- from .vendors import (
24
- normalize_vendor_keys,
25
- get_openai_key_or_503,
26
- get_groq_key_or_503,
27
- )
28
25
  from .proxy import (
29
26
  INTERACT_TOOL_SCHEMA,
30
- prepare_for_openai,
31
- prepare_for_groq,
32
- inject_system_hint,
33
27
  extract_message_text,
28
+ inject_system_hint,
34
29
  parse_tool_call_from_text,
30
+ prepare_for_groq,
31
+ prepare_for_openai,
35
32
  synthesize_tool_call_if_missing,
36
33
  )
37
- from .datasets import TaskDatasetSpec, TaskDatasetRegistry
38
34
  from .rubrics import (
39
35
  Criterion,
40
36
  Rubric,
41
- load_rubric,
42
37
  blend_rubrics,
38
+ load_rubric,
43
39
  score_events_against_rubric,
44
40
  score_outcome_against_rubric,
45
41
  )
46
- from .client import TaskAppClient
47
- from .errors import error_payload, http_exception, json_error_response
48
-
49
-
50
42
  from .server import (
51
- TaskAppConfig,
52
43
  ProxyConfig,
53
44
  RubricBundle,
45
+ TaskAppConfig,
54
46
  create_task_app,
55
47
  run_task_app,
56
48
  )
49
+ from .validators import validate_task_app_url
50
+ from .vendors import (
51
+ get_groq_key_or_503,
52
+ get_openai_key_or_503,
53
+ normalize_vendor_keys,
54
+ )
55
+
57
56
  __all__ = [
58
57
  "validate_task_app_url",
59
58
  "task_app_health",
@@ -1,13 +1,12 @@
1
- from __future__ import annotations
2
-
3
1
  """Registry for Task Apps exposed via the shared FastAPI harness."""
4
2
 
3
+ from __future__ import annotations
4
+
5
5
  import importlib
6
- import os
7
6
  import sys
7
+ from collections.abc import Callable, Iterable, Sequence
8
8
  from dataclasses import dataclass, field
9
9
  from pathlib import Path
10
- from typing import Callable, Dict, Iterable, List, Sequence
11
10
 
12
11
  from ..server import TaskAppConfig
13
12
 
@@ -45,8 +44,8 @@ class TaskAppRegistry:
45
44
  """In-memory registry of known task apps."""
46
45
 
47
46
  def __init__(self) -> None:
48
- self._entries: Dict[str, TaskAppEntry] = {}
49
- self._alias_to_id: Dict[str, str] = {}
47
+ self._entries: dict[str, TaskAppEntry] = {}
48
+ self._alias_to_id: dict[str, str] = {}
50
49
 
51
50
  def register(self, entry: TaskAppEntry) -> None:
52
51
  if entry.app_id in self._entries:
@@ -63,12 +62,12 @@ class TaskAppRegistry:
63
62
  raise KeyError(f"Unknown task app id: {app_id}")
64
63
  return self._entries[resolved]
65
64
 
66
- def list(self) -> List[TaskAppEntry]:
65
+ def list(self) -> list[TaskAppEntry]:
67
66
  return sorted(self._entries.values(), key=lambda entry: entry.app_id)
68
67
 
69
68
  def __iter__(self) -> Iterable[TaskAppEntry]:
70
69
  return iter(self.list())
71
-
70
+
72
71
  def clear(self) -> None:
73
72
  """Clear all registered task apps."""
74
73
  self._entries.clear()
@@ -85,42 +84,42 @@ def register_task_app(*, entry: TaskAppEntry) -> None:
85
84
  def discover_task_apps_from_cwd() -> None:
86
85
  """Discover and register task apps from the current working directory and subdirectories."""
87
86
  cwd = Path.cwd()
88
-
87
+
89
88
  # Look for task app files in common patterns
90
89
  patterns = [
91
90
  "**/task_app/*.py",
92
- "**/task_apps/*.py",
91
+ "**/task_apps/*.py",
93
92
  "**/*_task_app.py",
94
93
  "**/grpo_crafter.py",
95
94
  "**/math_single_step.py",
96
95
  ]
97
-
96
+
98
97
  discovered_files = []
99
98
  for pattern in patterns:
100
99
  discovered_files.extend(cwd.glob(pattern))
101
-
100
+
102
101
  # Add current directory to Python path temporarily
103
102
  original_path = sys.path.copy()
104
103
  try:
105
104
  sys.path.insert(0, str(cwd))
106
-
105
+
107
106
  for file_path in discovered_files:
108
- if file_path.name.startswith('__'):
107
+ if file_path.name.startswith("__"):
109
108
  continue
110
-
109
+
111
110
  # Convert file path to module name
112
111
  relative_path = file_path.relative_to(cwd)
113
112
  module_parts = list(relative_path.parts[:-1]) + [relative_path.stem]
114
- module_name = '.'.join(module_parts)
115
-
113
+ module_name = ".".join(module_parts)
114
+
116
115
  try:
117
116
  # Import the module to trigger registration
118
117
  importlib.import_module(module_name)
119
- except Exception as exc:
118
+ except Exception:
120
119
  # Silently skip modules that can't be imported
121
120
  # This allows for graceful handling of missing dependencies
122
121
  continue
123
-
122
+
124
123
  finally:
125
124
  sys.path[:] = original_path
126
125
 
synth_ai/task/auth.py CHANGED
@@ -1,9 +1,11 @@
1
- from __future__ import annotations
2
-
3
1
  """Authentication helpers shared by Task Apps."""
4
2
 
3
+ from __future__ import annotations
4
+
5
5
  import os
6
- from typing import Iterable, Optional, Any, Set
6
+ from collections.abc import Iterable
7
+ from contextlib import suppress
8
+ from typing import Any
7
9
 
8
10
  from .errors import http_exception
9
11
 
@@ -12,7 +14,9 @@ _DEV_API_KEY_ENVS = ("dev_environment_api_key", "DEV_ENVIRONMENT_API_KEY")
12
14
  _API_KEY_HEADER = "x-api-key"
13
15
  _API_KEYS_HEADER = "x-api-keys"
14
16
  _AUTH_HEADER = "authorization"
15
- _API_KEY_ALIASES_ENV = "ENVIRONMENT_API_KEY_ALIASES" # comma-separated list of additional valid keys
17
+ _API_KEY_ALIASES_ENV = (
18
+ "ENVIRONMENT_API_KEY_ALIASES" # comma-separated list of additional valid keys
19
+ )
16
20
 
17
21
 
18
22
  def _mask(value: str, *, prefix: int = 4) -> str:
@@ -22,7 +26,7 @@ def _mask(value: str, *, prefix: int = 4) -> str:
22
26
  return f"{visible}{'…' if len(value) > prefix else ''}"
23
27
 
24
28
 
25
- def normalize_environment_api_key() -> Optional[str]:
29
+ def normalize_environment_api_key() -> str | None:
26
30
  """Ensure `ENVIRONMENT_API_KEY` is populated from dev fallbacks.
27
31
 
28
32
  Returns the resolved key (if any) so callers can branch on configuration.
@@ -43,7 +47,7 @@ def normalize_environment_api_key() -> Optional[str]:
43
47
  return None
44
48
 
45
49
 
46
- def allowed_environment_api_keys() -> Set[str]:
50
+ def allowed_environment_api_keys() -> set[str]:
47
51
  """Return the set of valid environment API keys for this Task App.
48
52
 
49
53
  Includes:
@@ -120,7 +124,9 @@ def require_api_key_dependency(request: Any) -> None:
120
124
 
121
125
  allowed = allowed_environment_api_keys()
122
126
  if not allowed:
123
- raise http_exception(503, "missing_environment_api_key", "ENVIRONMENT_API_KEY is not configured")
127
+ raise http_exception(
128
+ 503, "missing_environment_api_key", "ENVIRONMENT_API_KEY is not configured"
129
+ )
124
130
  # Build candidate list for verbose diagnostics
125
131
  single = list(_header_values(request, _API_KEY_HEADER))
126
132
  multi = list(_header_values(request, _API_KEYS_HEADER))
@@ -131,23 +137,29 @@ def require_api_key_dependency(request: Any) -> None:
131
137
  bearer.append(a.split(" ", 1)[1].strip())
132
138
  candidates = _split_csv(single + multi + bearer)
133
139
  if not any(candidate in allowed for candidate in candidates):
134
- try:
135
- print({
136
- "task_auth_failed": True,
140
+ with suppress(Exception):
141
+ print(
142
+ {
143
+ "task_auth_failed": True,
144
+ "allowed_first15": [k[:15] for k in allowed],
145
+ "allowed_count": len(allowed),
146
+ "got_first15": [c[:15] for c in candidates],
147
+ "got_lens": [len(c) for c in candidates],
148
+ "have_x_api_key": bool(single),
149
+ "have_x_api_keys": bool(multi),
150
+ "have_authorization": bool(auths),
151
+ },
152
+ flush=True,
153
+ )
154
+ # Use 400 to make failures unmistakable during preflight
155
+ raise http_exception(
156
+ 400,
157
+ "unauthorised",
158
+ "API key missing or invalid",
159
+ extra={
137
160
  "allowed_first15": [k[:15] for k in allowed],
138
161
  "allowed_count": len(allowed),
139
162
  "got_first15": [c[:15] for c in candidates],
140
163
  "got_lens": [len(c) for c in candidates],
141
- "have_x_api_key": bool(single),
142
- "have_x_api_keys": bool(multi),
143
- "have_authorization": bool(auths),
144
- }, flush=True)
145
- except Exception:
146
- pass
147
- # Use 400 to make failures unmistakable during preflight
148
- raise http_exception(400, "unauthorised", "API key missing or invalid", extra={
149
- "allowed_first15": [k[:15] for k in allowed],
150
- "allowed_count": len(allowed),
151
- "got_first15": [c[:15] for c in candidates],
152
- "got_lens": [len(c) for c in candidates],
153
- })
164
+ },
165
+ )
synth_ai/task/client.py CHANGED
@@ -1,10 +1,10 @@
1
- from __future__ import annotations
2
-
3
1
  """Async HTTP client for interacting with Task Apps."""
4
2
 
3
+ from __future__ import annotations
4
+
5
5
  import asyncio
6
- from typing import Any, Dict, Iterable, List, Optional
7
6
  import os
7
+ from typing import Any
8
8
 
9
9
  import httpx
10
10
  from pydantic import BaseModel
@@ -37,7 +37,7 @@ class TaskAppClient:
37
37
  self._client: httpx.AsyncClient | None = None
38
38
  self.env = _TaskAppEnvironmentClient(self)
39
39
 
40
- async def __aenter__(self) -> "TaskAppClient":
40
+ async def __aenter__(self) -> TaskAppClient:
41
41
  await self._ensure_client()
42
42
  return self
43
43
 
@@ -53,8 +53,8 @@ class TaskAppClient:
53
53
  )
54
54
  return self._client
55
55
 
56
- def _headers(self) -> Dict[str, str]:
57
- headers: Dict[str, str] = {}
56
+ def _headers(self) -> dict[str, str]:
57
+ headers: dict[str, str] = {}
58
58
  # Primary key
59
59
  primary = (self.api_key or "").strip()
60
60
  if primary:
@@ -85,7 +85,7 @@ class TaskAppClient:
85
85
  method: str,
86
86
  path: str,
87
87
  *,
88
- params: Optional[Dict[str, Any] | List[tuple[str, Any]]] = None,
88
+ params: dict[str, Any] | list[tuple[str, Any]] | None = None,
89
89
  json_payload: Any = None,
90
90
  ) -> httpx.Response:
91
91
  client = await self._ensure_client()
@@ -118,16 +118,16 @@ class TaskAppClient:
118
118
  raise last_exc
119
119
  raise RuntimeError("Unreachable code in TaskAppClient._request")
120
120
 
121
- async def health(self) -> Dict[str, Any]:
121
+ async def health(self) -> dict[str, Any]:
122
122
  response = await self._request("GET", "/health")
123
123
  return response.json()
124
124
 
125
- async def info(self) -> Dict[str, Any]:
125
+ async def info(self) -> dict[str, Any]:
126
126
  response = await self._request("GET", "/info")
127
127
  return response.json()
128
128
 
129
129
  async def task_info(self, seeds: list[int] | None = None) -> TaskInfo | list[TaskInfo]:
130
- params: Optional[List[tuple[str, Any]]] = None
130
+ params: list[tuple[str, Any]] | None = None
131
131
  if seeds:
132
132
  params = [("seed", seed) for seed in seeds]
133
133
  response = await self._request("GET", "/task_info", params=params)
@@ -146,19 +146,21 @@ class _TaskAppEnvironmentClient:
146
146
  def __init__(self, client: TaskAppClient) -> None:
147
147
  self._client = client
148
148
 
149
- async def initialize(self, env_name: str, payload: Dict[str, Any]) -> Dict[str, Any]:
149
+ async def initialize(self, env_name: str, payload: dict[str, Any]) -> dict[str, Any]:
150
150
  response = await self._client._request(
151
151
  "POST", f"/env/{env_name}/initialize", json_payload=payload
152
152
  )
153
153
  return response.json()
154
154
 
155
- async def step(self, env_name: str, payload: Dict[str, Any]) -> Dict[str, Any]:
155
+ async def step(self, env_name: str, payload: dict[str, Any]) -> dict[str, Any]:
156
156
  response = await self._client._request(
157
157
  "POST", f"/env/{env_name}/step", json_payload=payload
158
158
  )
159
159
  return response.json()
160
160
 
161
- async def terminate(self, env_name: str, payload: Dict[str, Any] | None = None) -> Dict[str, Any]:
161
+ async def terminate(
162
+ self, env_name: str, payload: dict[str, Any] | None = None
163
+ ) -> dict[str, Any]:
162
164
  response = await self._client._request(
163
165
  "POST", f"/env/{env_name}/terminate", json_payload=payload or {}
164
166
  )
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import Optional, Any, Dict, List, Literal
4
+ from typing import Any, Literal
5
+
5
6
  from pydantic import BaseModel, Field
6
7
 
7
8
 
@@ -40,23 +41,24 @@ class TaskAppContract:
40
41
  """
41
42
 
42
43
  base_url: str
43
- env_name: Optional[str] = None
44
+ env_name: str | None = None
44
45
  requires_api_key_header: bool = True
45
46
 
46
47
 
47
48
  # --- Unified rollout schema used by Task App services and SDK utilities ---
48
49
 
50
+
49
51
  class RolloutEnvSpec(BaseModel):
50
- env_id: Optional[str] = None
51
- env_name: Optional[str] = None
52
- config: Dict[str, Any] = {}
53
- seed: Optional[int] = None
52
+ env_id: str | None = None
53
+ env_name: str | None = None
54
+ config: dict[str, Any] = Field(default_factory=dict)
55
+ seed: int | None = None
54
56
 
55
57
 
56
58
  class RolloutPolicySpec(BaseModel):
57
- policy_id: Optional[str] = None
58
- policy_name: Optional[str] = None
59
- config: Dict[str, Any] = {}
59
+ policy_id: str | None = None
60
+ policy_name: str | None = None
61
+ config: dict[str, Any] = Field(default_factory=dict)
60
62
 
61
63
 
62
64
  class RolloutRecordConfig(BaseModel):
@@ -76,60 +78,60 @@ class RolloutRequest(BaseModel):
76
78
  run_id: str
77
79
  env: RolloutEnvSpec
78
80
  policy: RolloutPolicySpec
79
- ops: List[Dict[str, Any]] | List[str]
81
+ ops: list[dict[str, Any]] | list[str]
80
82
  record: RolloutRecordConfig = RolloutRecordConfig()
81
83
  on_done: str = "reset"
82
84
  safety: RolloutSafetyConfig = RolloutSafetyConfig()
83
- training_session_id: Optional[str] = None
84
- synth_base_url: Optional[str] = None
85
+ training_session_id: str | None = None
86
+ synth_base_url: str | None = None
85
87
 
86
88
 
87
89
  class RolloutStep(BaseModel):
88
- obs: Dict[str, Any]
89
- tool_calls: List[Dict[str, Any]]
90
- reward: Optional[float] = None
90
+ obs: dict[str, Any]
91
+ tool_calls: list[dict[str, Any]]
92
+ reward: float | None = None
91
93
  done: bool = False
92
- truncated: Optional[bool] = None
93
- info: Optional[Dict[str, Any]] = None
94
+ truncated: bool | None = None
95
+ info: dict[str, Any] | None = None
94
96
 
95
97
 
96
98
  class RolloutTrajectory(BaseModel):
97
99
  env_id: str
98
100
  policy_id: str
99
- steps: List[RolloutStep]
100
- final: Optional[Dict[str, Any]] = None
101
+ steps: list[RolloutStep]
102
+ final: dict[str, Any] | None = None
101
103
  length: int
102
104
 
103
105
 
104
106
  class RolloutMetrics(BaseModel):
105
- episode_returns: List[float]
107
+ episode_returns: list[float]
106
108
  mean_return: float
107
109
  num_steps: int
108
110
  num_episodes: int = 0
109
- outcome_score: Optional[float] = None
110
- events_score: Optional[float] = None
111
- details: Dict[str, Any] = Field(default_factory=dict)
111
+ outcome_score: float | None = None
112
+ events_score: float | None = None
113
+ details: dict[str, Any] = Field(default_factory=dict)
112
114
 
113
115
 
114
116
  class RolloutResponse(BaseModel):
115
117
  run_id: str
116
- trajectories: List[RolloutTrajectory]
117
- branches: Dict[str, List[str]] = {}
118
+ trajectories: list[RolloutTrajectory]
119
+ branches: dict[str, list[str]] = Field(default_factory=dict)
118
120
  metrics: RolloutMetrics
119
121
  aborted: bool = False
120
122
  ops_executed: int = 0
121
- trace: Dict[str, Any] | None = None
123
+ trace: dict[str, Any] | None = None
122
124
 
123
125
 
124
126
  class TaskInfo(BaseModel):
125
127
  """Static metadata describing the capabilities of a Task App task."""
126
128
 
127
- task: Dict[str, Any]
128
- environments: List[str]
129
- action_space: Dict[str, Any]
130
- observation: Dict[str, Any]
131
- dataset: Dict[str, Any]
132
- rubric: Dict[str, Any]
133
- inference: Dict[str, Any]
134
- capabilities: Dict[str, Any]
135
- limits: Dict[str, Any]
129
+ task: dict[str, Any]
130
+ environments: list[str]
131
+ action_space: dict[str, Any]
132
+ observation: dict[str, Any]
133
+ dataset: dict[str, Any]
134
+ rubric: dict[str, Any]
135
+ inference: dict[str, Any]
136
+ capabilities: dict[str, Any]
137
+ limits: dict[str, Any]
synth_ai/task/datasets.py CHANGED
@@ -1,8 +1,9 @@
1
- from __future__ import annotations
2
-
3
1
  """Dataset registry and helpers shared by Task Apps."""
4
2
 
5
- from typing import Any, Callable, Dict, Hashable, Tuple
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable, Hashable
6
+ from typing import Any
6
7
 
7
8
  from pydantic import BaseModel, Field, field_validator
8
9
 
@@ -34,10 +35,12 @@ class TaskDatasetRegistry:
34
35
  """Lightweight registry mapping dataset specs to loader callables."""
35
36
 
36
37
  def __init__(self) -> None:
37
- self._entries: Dict[str, Tuple[TaskDatasetSpec, RegistryLoader, bool]] = {}
38
- self._cache: Dict[Hashable, Any] = {}
38
+ self._entries: dict[str, tuple[TaskDatasetSpec, RegistryLoader, bool]] = {}
39
+ self._cache: dict[Hashable, Any] = {}
39
40
 
40
- def register(self, spec: TaskDatasetSpec, loader: RegistryLoader, *, cache: bool = True) -> None:
41
+ def register(
42
+ self, spec: TaskDatasetSpec, loader: RegistryLoader, *, cache: bool = True
43
+ ) -> None:
41
44
  """Register a dataset loader and its metadata."""
42
45
 
43
46
  self._entries[spec.id] = (spec, loader, cache)