synth-ai 0.2.9.dev7__py3-none-any.whl → 0.2.9.dev9__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 (327) hide show
  1. examples/__init__.py +16 -0
  2. examples/crafter_debug_render.py +8 -11
  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/run_eval.py +36 -37
  19. examples/rl/run_rl_and_save.py +5 -5
  20. examples/rl/task_app/math_single_step.py +65 -43
  21. examples/rl/task_app/math_task_app.py +3 -3
  22. examples/sft/README.md +139 -0
  23. examples/sft/configs/crafter_fft_qwen0p6b.toml +44 -0
  24. examples/sft/configs/crafter_lora_qwen0p6b.toml +45 -0
  25. examples/sft/evaluate.py +117 -0
  26. examples/sft/export_dataset.py +117 -0
  27. examples/sft/generate_traces.py +162 -0
  28. examples/swe/__init__.py +12 -0
  29. examples/swe/task_app/README.md +105 -0
  30. examples/swe/task_app/__init__.py +2 -0
  31. examples/swe/task_app/grpo_swe_mini.py +571 -0
  32. examples/swe/task_app/grpo_swe_mini_task_app.py +136 -0
  33. examples/swe/task_app/hosted/README.md +173 -0
  34. examples/swe/task_app/hosted/__init__.py +5 -0
  35. examples/swe/task_app/hosted/branching.py +143 -0
  36. examples/swe/task_app/hosted/environment_routes.py +1289 -0
  37. examples/swe/task_app/hosted/envs/__init__.py +1 -0
  38. examples/swe/task_app/hosted/envs/crafter/__init__.py +6 -0
  39. examples/swe/task_app/hosted/envs/crafter/app.py +1 -0
  40. examples/swe/task_app/hosted/envs/crafter/environment.py +522 -0
  41. examples/swe/task_app/hosted/envs/crafter/policy.py +478 -0
  42. examples/swe/task_app/hosted/envs/crafter/react_agent.py +108 -0
  43. examples/swe/task_app/hosted/envs/crafter/shared.py +305 -0
  44. examples/swe/task_app/hosted/envs/crafter/tools.py +47 -0
  45. examples/swe/task_app/hosted/envs/mini_swe/__init__.py +8 -0
  46. examples/swe/task_app/hosted/envs/mini_swe/environment.py +1164 -0
  47. examples/swe/task_app/hosted/envs/mini_swe/policy.py +355 -0
  48. examples/swe/task_app/hosted/envs/mini_swe/shared.py +83 -0
  49. examples/swe/task_app/hosted/envs/mini_swe/tools.py +96 -0
  50. examples/swe/task_app/hosted/hosted_app.py +204 -0
  51. examples/swe/task_app/hosted/inference/__init__.py +5 -0
  52. examples/swe/task_app/hosted/inference/openai_client.py +618 -0
  53. examples/swe/task_app/hosted/main.py +100 -0
  54. examples/swe/task_app/hosted/policy_routes.py +1079 -0
  55. examples/swe/task_app/hosted/registry.py +195 -0
  56. examples/swe/task_app/hosted/rollout.py +1869 -0
  57. examples/swe/task_app/hosted/storage/__init__.py +5 -0
  58. examples/swe/task_app/hosted/storage/volume.py +211 -0
  59. examples/swe/task_app/hosted/test_agents.py +161 -0
  60. examples/swe/task_app/hosted/test_service.py +137 -0
  61. examples/swe/task_app/hosted/utils.py +62 -0
  62. examples/vlm/README.md +68 -0
  63. examples/vlm/configs/crafter_vlm_gpt4o.toml +44 -0
  64. examples/vlm/crafter_image_only_agent.py +207 -0
  65. examples/vlm/crafter_openai_vlm_agent.py +277 -0
  66. examples/vlm/filter_image_rows.py +63 -0
  67. examples/vlm/run_crafter_vlm_benchmark.py +316 -0
  68. examples/warming_up_to_rl/analyze_trace_db.py +5 -5
  69. examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +11 -1
  70. examples/warming_up_to_rl/export_trace_sft.py +78 -21
  71. examples/warming_up_to_rl/groq_test.py +4 -4
  72. examples/warming_up_to_rl/manage_secrets.py +13 -18
  73. examples/warming_up_to_rl/run_eval.py +42 -44
  74. examples/warming_up_to_rl/run_fft_and_save.py +11 -16
  75. examples/warming_up_to_rl/run_local_rollout.py +1 -3
  76. examples/warming_up_to_rl/run_local_rollout_modal.py +2 -4
  77. examples/warming_up_to_rl/run_local_rollout_parallel.py +1 -4
  78. examples/warming_up_to_rl/run_local_rollout_traced.py +3 -5
  79. examples/warming_up_to_rl/run_rl_and_save.py +5 -6
  80. examples/warming_up_to_rl/run_rollout_remote.py +8 -10
  81. examples/warming_up_to_rl/task_app/README.md +6 -2
  82. examples/warming_up_to_rl/task_app/grpo_crafter.py +234 -35
  83. examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +2 -3
  84. examples/warming_up_to_rl/task_app/synth_envs_hosted/__init__.py +1 -1
  85. examples/warming_up_to_rl/task_app/synth_envs_hosted/branching.py +9 -11
  86. examples/warming_up_to_rl/task_app/synth_envs_hosted/environment_routes.py +131 -114
  87. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +101 -41
  88. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +73 -51
  89. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +14 -6
  90. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +16 -16
  91. examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +32 -34
  92. examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +94 -31
  93. examples/warming_up_to_rl/task_app/synth_envs_hosted/main.py +0 -2
  94. examples/warming_up_to_rl/task_app/synth_envs_hosted/policy_routes.py +303 -203
  95. examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py +21 -23
  96. examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py +328 -225
  97. examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +13 -13
  98. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py +1 -0
  99. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py +1 -0
  100. examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +4 -3
  101. synth/__init__.py +14 -0
  102. synth_ai/__init__.py +26 -4
  103. synth_ai/api/models/supported.py +376 -0
  104. synth_ai/api/train/builders.py +128 -21
  105. synth_ai/api/train/cli.py +80 -64
  106. synth_ai/api/train/config_finder.py +7 -2
  107. synth_ai/api/train/env_resolver.py +1 -1
  108. synth_ai/api/train/pollers.py +2 -1
  109. synth_ai/api/train/supported_algos.py +139 -0
  110. synth_ai/api/train/task_app.py +1 -2
  111. synth_ai/api/train/utils.py +13 -44
  112. synth_ai/cli/__init__.py +8 -0
  113. synth_ai/cli/_modal_wrapper.py +28 -0
  114. synth_ai/cli/_typer_patch.py +49 -0
  115. synth_ai/cli/balance.py +1 -2
  116. synth_ai/cli/calc.py +1 -1
  117. synth_ai/cli/demo.py +2 -1
  118. synth_ai/cli/recent.py +2 -2
  119. synth_ai/cli/rl_demo.py +2 -1
  120. synth_ai/cli/root.py +11 -13
  121. synth_ai/cli/status.py +2 -2
  122. synth_ai/cli/task_apps.py +529 -179
  123. synth_ai/cli/traces.py +6 -4
  124. synth_ai/cli/watch.py +12 -18
  125. synth_ai/demo_registry.py +1 -1
  126. synth_ai/demos/core/cli.py +36 -43
  127. synth_ai/demos/demo_task_apps/__init__.py +3 -3
  128. synth_ai/demos/demo_task_apps/core.py +17 -25
  129. synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +3 -4
  130. synth_ai/demos/demo_task_apps/math/app.py +2 -1
  131. synth_ai/demos/demo_task_apps/math/deploy_modal.py +3 -4
  132. synth_ai/demos/demo_task_apps/math/modal_task_app.py +16 -18
  133. synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -1
  134. synth_ai/environments/examples/crafter_classic/environment.py +76 -1
  135. synth_ai/environments/reproducibility/tree.py +2 -5
  136. synth_ai/environments/service/app.py +11 -12
  137. synth_ai/environments/service/core_routes.py +4 -7
  138. synth_ai/environments/stateful/engine.py +1 -1
  139. synth_ai/environments/tasks/core.py +1 -0
  140. synth_ai/environments/tasks/filters.py +5 -6
  141. synth_ai/environments/tasks/utils.py +4 -5
  142. synth_ai/handshake.py +9 -9
  143. synth_ai/http.py +1 -1
  144. synth_ai/http_client.py +18 -10
  145. synth_ai/inference/client.py +15 -5
  146. synth_ai/jobs/client.py +78 -83
  147. synth_ai/learning/__init__.py +41 -6
  148. synth_ai/learning/algorithms.py +14 -0
  149. synth_ai/learning/client.py +91 -24
  150. synth_ai/learning/config.py +2 -38
  151. synth_ai/learning/ft_client.py +4 -59
  152. synth_ai/learning/health.py +5 -6
  153. synth_ai/learning/jobs.py +31 -47
  154. synth_ai/{rl → learning/rl}/__init__.py +14 -4
  155. synth_ai/learning/rl/client.py +267 -0
  156. synth_ai/learning/rl/config.py +31 -0
  157. synth_ai/{rl → learning/rl}/contracts.py +5 -8
  158. synth_ai/{rl → learning/rl}/env_keys.py +39 -15
  159. synth_ai/learning/rl/secrets.py +13 -0
  160. synth_ai/learning/rl_client.py +2 -281
  161. synth_ai/learning/sft/__init__.py +29 -0
  162. synth_ai/learning/sft/client.py +68 -0
  163. synth_ai/learning/sft/config.py +270 -0
  164. synth_ai/learning/sft/data.py +295 -0
  165. synth_ai/learning/sse.py +25 -24
  166. synth_ai/learning/validators.py +25 -28
  167. synth_ai/lm/__init__.py +21 -47
  168. synth_ai/main.py +6 -0
  169. synth_ai/task/__init__.py +25 -27
  170. synth_ai/task/apps/__init__.py +7 -8
  171. synth_ai/task/auth.py +8 -8
  172. synth_ai/task/client.py +14 -14
  173. synth_ai/task/contracts.py +36 -35
  174. synth_ai/task/datasets.py +6 -5
  175. synth_ai/task/errors.py +10 -10
  176. synth_ai/task/health.py +17 -9
  177. synth_ai/task/json.py +58 -23
  178. synth_ai/task/proxy.py +13 -9
  179. synth_ai/task/rubrics.py +16 -15
  180. synth_ai/task/server.py +12 -12
  181. synth_ai/task/tracing_utils.py +4 -4
  182. synth_ai/task/vendors.py +5 -6
  183. synth_ai/tracing_v3/__init__.py +2 -0
  184. synth_ai/tracing_v3/abstractions.py +21 -4
  185. synth_ai/tracing_v3/decorators.py +18 -16
  186. synth_ai/tracing_v3/hooks.py +5 -5
  187. synth_ai/tracing_v3/llm_call_record_helpers.py +6 -6
  188. synth_ai/tracing_v3/session_tracer.py +40 -14
  189. synth_ai/tracing_v3/storage/base.py +85 -0
  190. synth_ai/tracing_v3/storage/config.py +21 -8
  191. synth_ai/tracing_v3/storage/factory.py +10 -7
  192. synth_ai/tracing_v3/storage/utils.py +4 -2
  193. synth_ai/tracing_v3/turso/daemon.py +7 -2
  194. synth_ai/tracing_v3/turso/models.py +2 -2
  195. synth_ai/tracing_v3/turso/native_manager.py +1173 -0
  196. synth_ai/tracing_v3/utils.py +4 -4
  197. synth_ai/v0/api/__init__.py +8 -0
  198. synth_ai/v0/api/models/__init__.py +8 -0
  199. synth_ai/v0/api/models/supported.py +8 -0
  200. synth_ai/v0/config/__init__.py +15 -0
  201. synth_ai/v0/config/base_url.py +12 -0
  202. synth_ai/v0/lm/__init__.py +51 -0
  203. synth_ai/{lm → v0/lm}/caching/ephemeral.py +2 -2
  204. synth_ai/{lm → v0/lm}/caching/handler.py +4 -4
  205. synth_ai/{lm → v0/lm}/caching/initialize.py +1 -1
  206. synth_ai/{lm → v0/lm}/caching/persistent.py +1 -1
  207. synth_ai/{lm → v0/lm}/config.py +6 -1
  208. synth_ai/{lm → v0/lm}/core/all.py +9 -9
  209. synth_ai/{lm → v0/lm}/core/main.py +6 -6
  210. synth_ai/{lm → v0/lm}/core/main_v3.py +10 -10
  211. synth_ai/{lm → v0/lm}/core/synth_models.py +2 -14
  212. synth_ai/{lm → v0/lm}/core/vendor_clients.py +2 -2
  213. synth_ai/{lm → v0/lm}/overrides.py +2 -2
  214. synth_ai/{lm → v0/lm}/provider_support/anthropic.py +4 -4
  215. synth_ai/{lm → v0/lm}/provider_support/openai.py +5 -5
  216. synth_ai/{lm → v0/lm}/structured_outputs/handler.py +5 -5
  217. synth_ai/{lm → v0/lm}/structured_outputs/rehabilitate.py +1 -1
  218. synth_ai/{lm → v0/lm}/vendors/core/anthropic_api.py +9 -9
  219. synth_ai/{lm → v0/lm}/vendors/core/gemini_api.py +5 -5
  220. synth_ai/{lm → v0/lm}/vendors/core/mistral_api.py +5 -5
  221. synth_ai/{lm → v0/lm}/vendors/core/openai_api.py +10 -10
  222. synth_ai/{lm → v0/lm}/vendors/openai_standard.py +8 -8
  223. synth_ai/{lm → v0/lm}/vendors/openai_standard_responses.py +2 -2
  224. synth_ai/{lm → v0/lm}/vendors/supported/custom_endpoint.py +3 -3
  225. synth_ai/{lm → v0/lm}/vendors/supported/deepseek.py +2 -2
  226. synth_ai/{lm → v0/lm}/vendors/supported/grok.py +2 -2
  227. synth_ai/{lm → v0/lm}/vendors/supported/groq.py +1 -1
  228. synth_ai/{lm → v0/lm}/vendors/supported/ollama.py +1 -1
  229. synth_ai/{lm → v0/lm}/vendors/supported/openrouter.py +3 -3
  230. synth_ai/{lm → v0/lm}/vendors/supported/together.py +1 -1
  231. synth_ai/{lm → v0/lm}/vendors/synth_client.py +1 -1
  232. synth_ai/v0/tracing_v3/__init__.py +10 -0
  233. synth_ai/v0/tracing_v3/abstractions.py +3 -0
  234. synth_ai/v0/tracing_v3/decorators.py +3 -0
  235. synth_ai/v0/tracing_v3/llm_call_record_helpers.py +3 -0
  236. synth_ai/v0/tracing_v3/session_tracer.py +3 -0
  237. synth_ai-0.2.9.dev9.dist-info/METADATA +191 -0
  238. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev9.dist-info}/RECORD +268 -238
  239. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev9.dist-info}/top_level.txt +1 -0
  240. examples/common_old/backend.py +0 -20
  241. examples/evals_old/README.md +0 -98
  242. examples/evals_old/__init__.py +0 -6
  243. examples/evals_old/compare_models.py +0 -1038
  244. examples/evals_old/example_log.md +0 -145
  245. examples/evals_old/run_demo.sh +0 -126
  246. examples/evals_old/trace_analysis.py +0 -270
  247. examples/finetuning_old/_backup_synth_qwen/config.toml +0 -29
  248. examples/finetuning_old/_backup_synth_qwen/example_log.md +0 -324
  249. examples/finetuning_old/_backup_synth_qwen/filter_traces.py +0 -60
  250. examples/finetuning_old/_backup_synth_qwen/filter_traces_achievements.py +0 -243
  251. examples/finetuning_old/_backup_synth_qwen/purge_v3_traces.py +0 -109
  252. examples/finetuning_old/_backup_synth_qwen/react_agent_lm.py +0 -1924
  253. examples/finetuning_old/_backup_synth_qwen/readme.md +0 -49
  254. examples/finetuning_old/_backup_synth_qwen/run_crafter_qwen4b.py +0 -114
  255. examples/finetuning_old/_backup_synth_qwen/run_demo.sh +0 -195
  256. examples/finetuning_old/_backup_synth_qwen/sft_kickoff.py +0 -119
  257. examples/finetuning_old/synth_qwen_v1/README.md +0 -68
  258. examples/finetuning_old/synth_qwen_v1/filter_traces.py +0 -60
  259. examples/finetuning_old/synth_qwen_v1/filter_traces_achievements.py +0 -243
  260. examples/finetuning_old/synth_qwen_v1/finetune.py +0 -46
  261. examples/finetuning_old/synth_qwen_v1/hello_ft_model.py +0 -71
  262. examples/finetuning_old/synth_qwen_v1/infer.py +0 -36
  263. examples/finetuning_old/synth_qwen_v1/poll.py +0 -46
  264. examples/finetuning_old/synth_qwen_v1/prepare_data.py +0 -35
  265. examples/finetuning_old/synth_qwen_v1/purge_v3_traces.py +0 -109
  266. examples/finetuning_old/synth_qwen_v1/react_agent_lm.py +0 -1933
  267. examples/finetuning_old/synth_qwen_v1/run_crafter_sft_job.py +0 -210
  268. examples/finetuning_old/synth_qwen_v1/run_ft_job.py +0 -237
  269. examples/finetuning_old/synth_qwen_v1/upload_data.py +0 -34
  270. examples/finetuning_old/synth_qwen_v1/util.py +0 -152
  271. examples/rl_old/task_app.py +0 -1131
  272. examples/warming_up_to_rl/old/event_rewards.md +0 -234
  273. examples/warming_up_to_rl/old/notes.md +0 -73
  274. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_traces_sft_turso.py +0 -738
  275. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
  276. synth_ai/experimental/synth_oss.py +0 -445
  277. synth_ai/learning/filtering.py +0 -0
  278. synth_ai/learning/offline/dpo.py +0 -0
  279. synth_ai/learning/offline/providers.py +0 -7
  280. synth_ai/learning/offline/sft.py +0 -0
  281. synth_ai/learning/offline/shared.py +0 -0
  282. synth_ai/learning/online/grpo.py +0 -0
  283. synth_ai/learning/online/irft.py +0 -0
  284. synth_ai/learning/prompts/banking77_injection_eval.py +0 -168
  285. synth_ai/learning/prompts/gepa.py +0 -0
  286. synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +0 -211
  287. synth_ai/learning/prompts/mipro.py +0 -289
  288. synth_ai/learning/prompts/random_search.py +0 -249
  289. synth_ai/learning/prompts/run_mipro_banking77.py +0 -172
  290. synth_ai/learning/prompts/run_random_search_banking77.py +0 -329
  291. synth_ai/rl/secrets.py +0 -19
  292. synth_ai/scripts/verify_rewards.py +0 -100
  293. synth_ai/tracing/__init__.py +0 -30
  294. synth_ai/tracing_v1/__init__.py +0 -33
  295. synth_ai/tracing_v3/turso/__init__.py +0 -25
  296. synth_ai/tracing_v3/turso/manager.py +0 -838
  297. synth_ai/zyk/__init__.py +0 -30
  298. synth_ai-0.2.9.dev7.dist-info/METADATA +0 -131
  299. /synth_ai/{lm → v0/lm}/caching/__init__.py +0 -0
  300. /synth_ai/{lm → v0/lm}/caching/constants.py +0 -0
  301. /synth_ai/{lm → v0/lm}/caching/dbs.py +0 -0
  302. /synth_ai/{lm → v0/lm}/constants.py +0 -0
  303. /synth_ai/{lm → v0/lm}/core/__init__.py +0 -0
  304. /synth_ai/{lm → v0/lm}/core/exceptions.py +0 -0
  305. /synth_ai/{lm → v0/lm}/cost/__init__.py +0 -0
  306. /synth_ai/{lm → v0/lm}/cost/monitor.py +0 -0
  307. /synth_ai/{lm → v0/lm}/cost/statefulness.py +0 -0
  308. /synth_ai/{lm → v0/lm}/injection.py +0 -0
  309. /synth_ai/{lm → v0/lm}/provider_support/__init__.py +0 -0
  310. /synth_ai/{lm → v0/lm}/provider_support/suppress_logging.py +0 -0
  311. /synth_ai/{lm → v0/lm}/structured_outputs/__init__.py +0 -0
  312. /synth_ai/{lm → v0/lm}/structured_outputs/inject.py +0 -0
  313. /synth_ai/{lm → v0/lm}/tools/__init__.py +0 -0
  314. /synth_ai/{lm → v0/lm}/tools/base.py +0 -0
  315. /synth_ai/{lm → v0/lm}/unified_interface.py +0 -0
  316. /synth_ai/{lm → v0/lm}/vendors/__init__.py +0 -0
  317. /synth_ai/{lm → v0/lm}/vendors/base.py +0 -0
  318. /synth_ai/{lm → v0/lm}/vendors/core/__init__.py +0 -0
  319. /synth_ai/{lm → v0/lm}/vendors/core/synth_dev_api.py +0 -0
  320. /synth_ai/{lm → v0/lm}/vendors/local/__init__.py +0 -0
  321. /synth_ai/{lm → v0/lm}/vendors/local/ollama.py +0 -0
  322. /synth_ai/{lm → v0/lm}/vendors/retries.py +0 -0
  323. /synth_ai/{lm → v0/lm}/vendors/supported/__init__.py +0 -0
  324. /synth_ai/{lm → v0/lm}/warmup.py +0 -0
  325. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev9.dist-info}/WHEEL +0 -0
  326. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev9.dist-info}/entry_points.txt +0 -0
  327. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev9.dist-info}/licenses/LICENSE +0 -0
@@ -1,243 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Filter v3 Crafter traces into SFT JSONL requiring specific achievements.
4
-
5
- Environment:
6
- - CRAFTER_DB_URL (default: sqlite:///traces_v3_lm_synth/traces.db)
7
- - OUTPUT_JSONL (default: ft_data/qwen4b_crafter_sft_ach.jsonl)
8
- - REQUIRED_ACHIEVEMENTS (space-separated, default: collect_wood)
9
- - MIN_TOTAL_REWARD (float, default: 0.0)
10
- - MAX_COST (float, default: inf)
11
- - MAX_TOKENS (int, default: inf)
12
- - MODELS (optional, space-separated model names; default empty = all)
13
- - WINDOW_MODE=1 to emit per-turn user→assistant examples
14
- """
15
-
16
- import asyncio
17
- import json
18
- import math
19
- import os
20
- import tomllib
21
- from pathlib import Path
22
- from typing import Any
23
-
24
- try:
25
- # Preferred path (modal-specific)
26
- from synth_ai.environments.examples.crafter_classic.agent_demos.crafter_modal_ft.filter_traces_sft_turso import ( # type: ignore
27
- FinetuningDataExtractorV3,
28
- )
29
- except Exception: # pragma: no cover
30
- try:
31
- # Fallback path used in some dist builds
32
- from synth_ai.environments.examples.crafter_classic.agent_demos.crafter_openai_ft.filter_traces_sft_turso import ( # type: ignore
33
- FinetuningDataExtractorV3,
34
- )
35
- except Exception as _import_err: # pragma: no cover
36
- raise ImportError(
37
- "Could not import FinetuningDataExtractorV3 from synth_ai."
38
- ) from _import_err
39
-
40
-
41
- def env_list(name: str) -> list[str]:
42
- val = os.getenv(name, "").strip()
43
- return val.split() if val else []
44
-
45
-
46
- def normalize_db_url(raw: str) -> str:
47
- # Accept file path or sqlite URLs; ensure async driver prefix
48
- if raw.endswith(".db") and not raw.startswith("sqlite"):
49
- return f"sqlite+aiosqlite:///{raw}"
50
- if raw.startswith("sqlite+aiosqlite///"):
51
- return raw
52
- if raw.startswith("sqlite///") and raw.endswith(".db"):
53
- return raw.replace("sqlite///", "sqlite+aiosqlite///")
54
- return raw
55
-
56
-
57
- def build_filters() -> dict[str, Any]:
58
- cfg_default = Path(__file__).with_name("config.toml")
59
- cfg_path = os.getenv("CRAFTER_CONFIG", str(cfg_default))
60
- cfg: dict[str, Any] = {}
61
- if os.path.exists(cfg_path):
62
- with open(cfg_path, "rb") as f:
63
- cfg = tomllib.load(f)
64
- fcfg = cfg.get("filter", {})
65
- # Default: no required achievements gating unless provided via env/config
66
- req = set(env_list("REQUIRED_ACHIEVEMENTS") or fcfg.get("required_achievements", []))
67
- models = env_list("MODELS")
68
- # Default: allow zero reward unless overridden
69
- min_reward = float(os.getenv("MIN_TOTAL_REWARD", str(fcfg.get("min_total_reward", 0.0))))
70
- max_cost = float(os.getenv("MAX_COST", str(fcfg.get("max_cost", math.inf))))
71
- max_tokens = int(os.getenv("MAX_TOKENS", str(fcfg.get("max_tokens", 1_000_000_000))))
72
- return {
73
- "required_achievements": req,
74
- "models": models,
75
- "min_total_reward": min_reward,
76
- "max_cost": max_cost,
77
- "max_tokens": max_tokens,
78
- }
79
-
80
-
81
- async def main() -> None:
82
- cfg_default = Path(__file__).with_name("config.toml")
83
- cfg_path = os.getenv("CRAFTER_CONFIG", str(cfg_default))
84
- cfg: dict[str, Any] = {}
85
- if os.path.exists(cfg_path):
86
- with open(cfg_path, "rb") as f:
87
- cfg = tomllib.load(f)
88
- fcfg = cfg.get("filter", {})
89
- tcfg = cfg.get("traces", {})
90
-
91
- # Prefer env; else derive from config or repo-local v3 path
92
- raw_db_url = os.getenv("CRAFTER_DB_URL", "")
93
- if not raw_db_url:
94
- db_path = fcfg.get("db_path")
95
- if not db_path and tcfg.get("sqld_db_path"):
96
- # derive the internal data file path from the sqld dir
97
- db_path = str(Path(tcfg["sqld_db_path"]) / "dbs" / "default" / "data")
98
- if db_path:
99
- raw_db_url = f"sqlite+aiosqlite:///{db_path}"
100
- else:
101
- # Try repo-local default: traces/v3/synth_ai.db/dbs/default/data
102
- repo_root = Path(__file__).resolve().parents[3]
103
- candidate = repo_root / "traces" / "v3" / "synth_ai.db" / "dbs" / "default" / "data"
104
- raw_db_url = f"sqlite+aiosqlite:///{candidate}"
105
- db_url = normalize_db_url(raw_db_url)
106
- output_path = os.getenv(
107
- "OUTPUT_JSONL", fcfg.get("output_jsonl", "ft_data/qwen4b_crafter_sft_ach.jsonl")
108
- )
109
- filters = build_filters()
110
- # Default: require >1 achievements unless explicitly specified in config/env
111
- # If caller set REQUIRED_ACHIEVEMENTS or provided config 'required_achievements', we won't override.
112
- # Otherwise, enforce min achievements via MIN_ACHIEVEMENTS (default 2)
113
- if not filters.get("required_achievements"):
114
- try:
115
- min_ach = int(os.getenv("MIN_ACHIEVEMENTS", str(fcfg.get("min_achievements", 2))))
116
- except Exception:
117
- min_ach = 2
118
- filters["min_achievements"] = min_ach
119
-
120
- window_mode = os.getenv("WINDOW_MODE", "0") == "1"
121
-
122
- print("🤖 Modal/Synth FT Filter (achievements)")
123
- print("Using database:", db_url)
124
- print("Output file:", output_path)
125
- print(
126
- "Filters:",
127
- json.dumps(
128
- {k: (list(v) if isinstance(v, set) else v) for k, v in filters.items()}, indent=2
129
- ),
130
- )
131
- print("Window mode:", window_mode)
132
-
133
- # Print distributions (achievements and rewards) before filtering for visibility
134
- try:
135
- import numpy as _np
136
- from collections import Counter as _Counter
137
-
138
- async with FinetuningDataExtractorV3(db_url) as _ex:
139
- _sessions = await _ex.get_all_sessions()
140
- _ach_counts: _Counter[str] = _Counter()
141
- _rewards: list[float] = []
142
- for _, _row in _sessions.iterrows():
143
- _sid = _row["session_id"]
144
- _ach = await _ex.get_session_achievements(_sid) or []
145
- for _a in _ach:
146
- _ach_counts[_a] += 1
147
- _met = await _ex.get_session_metrics(_sid)
148
- try:
149
- _rewards.append(float(_met.get("total_reward", 0.0) or 0.0))
150
- except Exception:
151
- pass
152
- print(f"\nTotal sessions: {len(_sessions)}")
153
- if _ach_counts:
154
- print("\nAchievements by session (count):")
155
- for _name, _c in sorted(_ach_counts.items(), key=lambda x: (-x[1], x[0])):
156
- print(f" {_name}: {_c}")
157
- if _rewards:
158
- _r = _np.array(_rewards, dtype=float)
159
- print("\nReward stats:")
160
- print(
161
- f" min={_r.min():.2f} median={_np.median(_r):.2f} mean={_r.mean():.2f} max={_r.max():.2f}"
162
- )
163
- except Exception:
164
- pass
165
-
166
- required: set[str] = filters["required_achievements"]
167
- models: list[str] = filters["models"]
168
- min_reward: float = filters["min_total_reward"]
169
- max_cost: float = filters["max_cost"]
170
- max_tokens: int = filters["max_tokens"]
171
-
172
- stats: dict[str, Any] = {
173
- "total_sessions": 0,
174
- "kept_sessions": 0,
175
- "total_examples": 0,
176
- }
177
-
178
- async with FinetuningDataExtractorV3(db_url) as extractor:
179
- all_sessions = await extractor.get_all_sessions()
180
- stats["total_sessions"] = len(all_sessions)
181
-
182
- kept: list[str] = []
183
- for _, row in all_sessions.iterrows():
184
- session_id = row["session_id"]
185
- metrics = await extractor.get_session_metrics(session_id)
186
-
187
- if metrics["total_reward"] < min_reward:
188
- continue
189
- if metrics["total_cost"] > max_cost:
190
- continue
191
- if metrics["total_tokens"] > max_tokens:
192
- continue
193
-
194
- if models:
195
- model_query = """
196
- SELECT DISTINCT model_name
197
- FROM events
198
- WHERE session_id = :session_id
199
- AND event_type = 'cais'
200
- AND model_name IS NOT NULL
201
- """
202
- model_df = await extractor.db_manager.query_traces(
203
- model_query, {"session_id": session_id}
204
- )
205
- session_models = model_df["model_name"].tolist() if not model_df.empty else []
206
- if not any(m in models for m in session_models):
207
- continue
208
-
209
- # Respect either explicit required achievements OR min_achievements fallback
210
- min_ach = int(filters.get("min_achievements", 0))
211
- if required or min_ach > 0:
212
- achievements = await extractor.get_session_achievements(session_id)
213
- if not achievements:
214
- continue
215
- if required:
216
- if not (required & set(achievements)):
217
- continue
218
- else:
219
- if len(achievements) < min_ach:
220
- continue
221
-
222
- kept.append(session_id)
223
-
224
- stats["kept_sessions"] = len(kept)
225
-
226
- if window_mode:
227
- training_data = await extractor.extract_openai_window_format(kept)
228
- else:
229
- training_data = await extractor.extract_openai_format(kept)
230
-
231
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
232
- with open(output_path, "w") as f:
233
- for ex in training_data:
234
- f.write(json.dumps(ex) + "\n")
235
- stats["total_examples"] = len(training_data)
236
-
237
- print(
238
- "\n✅ Wrote", stats["total_examples"], "examples from", stats["kept_sessions"], "sessions"
239
- )
240
-
241
-
242
- if __name__ == "__main__":
243
- asyncio.run(main())
@@ -1,46 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import asyncio
4
-
5
- import sys
6
- import os
7
-
8
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
9
-
10
- from synth_ai.learning import FtClient
11
- from examples.finetuning.synth_qwen_v1.util import load_env, load_state, save_state, parse_args
12
-
13
-
14
- async def _run(mode: str | None) -> None:
15
- base, key = load_env(mode)
16
- client = FtClient(base_url=base, api_key=key)
17
-
18
- st = load_state()
19
- file_id = st.get("file_id")
20
- if not file_id:
21
- raise RuntimeError("state.json missing file_id; run upload_data.py first")
22
-
23
- # Qwen3 0.6B default
24
- resp = await client.create_sft_job(
25
- model="Qwen/Qwen3-0.6B",
26
- training_file_id=file_id,
27
- hyperparameters={"n_epochs": 1, "batch_size": 4},
28
- metadata={"upload_to_wasabi": True},
29
- )
30
- job_id = resp.get("job_id")
31
- if not job_id:
32
- raise RuntimeError(f"create_job missing job_id: {resp}")
33
- print(f"job_id={job_id}")
34
- save_state({"job_id": job_id})
35
-
36
- start = await client.start_job(job_id)
37
- print(f"start={start}")
38
-
39
-
40
- def main() -> None:
41
- args = parse_args()
42
- asyncio.run(_run(args.mode))
43
-
44
-
45
- if __name__ == "__main__":
46
- main()
@@ -1,71 +0,0 @@
1
- #!/usr/bin/env python3
2
- from __future__ import annotations
3
-
4
- import asyncio
5
- import json
6
- import os
7
- from pathlib import Path
8
-
9
- import sys
10
-
11
- # Ensure repo root on path
12
- ROOT = Path(__file__).parents[3]
13
- if str(ROOT) not in sys.path:
14
- sys.path.insert(0, str(ROOT))
15
-
16
- from examples.finetuning.synth_qwen_v1.util import load_env, load_state # type: ignore
17
- from synth_ai.inference import InferenceClient # type: ignore
18
-
19
-
20
- async def main() -> None:
21
- base_url, api_key = load_env(os.getenv("MODE") or os.getenv("ENV") or "local")
22
- st_path = Path(__file__).parent / "state.json"
23
- if not st_path.exists():
24
- raise FileNotFoundError(f"state.json not found at {st_path}")
25
- state = json.loads(st_path.read_text())
26
- model = state.get("fine_tuned_model")
27
- if not model:
28
- raise RuntimeError("fine_tuned_model missing in state.json")
29
-
30
- print(f"Backend: {base_url}")
31
- print(f"Model: {model}")
32
-
33
- ic = InferenceClient(base_url=base_url, api_key=api_key)
34
- try:
35
- resp = await ic.create_chat_completion(
36
- model=model,
37
- messages=[{"role": "user", "content": "Hello world!"}],
38
- max_tokens=64,
39
- temperature=0.2,
40
- stream=False,
41
- )
42
- print("\n===== Response =====")
43
- print(json.dumps(resp, indent=2))
44
- print("===== End Response =====\n")
45
- except Exception as e: # always print full failure context
46
- import traceback
47
-
48
- print("\n===== Inference Error =====")
49
- print(f"Type: {type(e).__name__}")
50
- print(f"Repr: {repr(e)}")
51
- print("Traceback:")
52
- print(traceback.format_exc())
53
- try:
54
- from synth_ai.http import HTTPError # type: ignore
55
-
56
- if isinstance(e, HTTPError):
57
- print("HTTPError details:")
58
- print(f" status={e.status}")
59
- print(f" url={e.url}")
60
- print(f" message={e.message}")
61
- if getattr(e, "detail", None) is not None:
62
- print(f" detail={e.detail}")
63
- if getattr(e, "body_snippet", None):
64
- print(f" body_snippet={e.body_snippet}")
65
- except Exception:
66
- pass
67
- print("===== End Inference Error =====\n")
68
-
69
-
70
- if __name__ == "__main__":
71
- asyncio.run(main())
@@ -1,36 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import asyncio
4
-
5
- import sys
6
- import os
7
-
8
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
9
-
10
- from synth_ai.inference import InferenceClient
11
- from examples.finetuning.synth_qwen_v1.util import load_env, load_state, parse_args
12
-
13
-
14
- async def _run(mode: str | None) -> None:
15
- base, key = load_env(mode)
16
- client = InferenceClient(base_url=base, api_key=key)
17
- st = load_state()
18
- model = st.get("fine_tuned_model") or "Qwen/Qwen2.5-0.5B"
19
- print(f"model={model}")
20
- resp = await client.create_chat_completion(
21
- model=model,
22
- messages=[{"role": "user", "content": "Give me a cheerful two-line greeting."}],
23
- max_tokens=128,
24
- temperature=0.7,
25
- stream=False,
26
- )
27
- print(resp)
28
-
29
-
30
- def main() -> None:
31
- args = parse_args()
32
- asyncio.run(_run(args.mode))
33
-
34
-
35
- if __name__ == "__main__":
36
- main()
@@ -1,46 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import asyncio
4
- from typing import Dict
5
-
6
- import sys
7
- import os
8
-
9
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
10
-
11
- from synth_ai.learning import JobHandle
12
- from examples.finetuning.synth_qwen_v1.util import load_env, load_state, save_state, parse_args
13
-
14
-
15
- def _print_event(e: Dict) -> None:
16
- try:
17
- print(f"event seq={e.get('seq')} type={e.get('type')} msg={e.get('message')}")
18
- except Exception:
19
- print(str(e))
20
-
21
-
22
- async def _run(mode: str | None) -> None:
23
- base, key = load_env(mode)
24
- st = load_state()
25
- job_id = st.get("job_id")
26
- if not job_id:
27
- raise RuntimeError("state.json missing job_id; run finetune.py first")
28
-
29
- # Use shared JobHandle poller abstraction (strict=True for FT)
30
- handle = JobHandle(base, key, job_id, strict=True)
31
- final = await handle.poll_until_terminal(
32
- interval_seconds=2.0, max_seconds=1800, on_event=_print_event
33
- )
34
- print(f"final_status={final.get('status')}")
35
- ft = final.get("fine_tuned_model")
36
- if ft:
37
- save_state({"fine_tuned_model": ft})
38
-
39
-
40
- def main() -> None:
41
- args = parse_args()
42
- asyncio.run(_run(args.mode))
43
-
44
-
45
- if __name__ == "__main__":
46
- main()
@@ -1,35 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import sys
5
- import os
6
- from pathlib import Path
7
-
8
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
9
-
10
- from examples.finetuning.synth_qwen_v1.util import validate_jsonl
11
-
12
-
13
- def main() -> None:
14
- out_dir = Path(__file__).parent / "data"
15
- out_dir.mkdir(parents=True, exist_ok=True)
16
- out_path = out_dir / "training.jsonl"
17
-
18
- # Minimal single-example JSONL
19
- lines = [
20
- json.dumps(
21
- {
22
- "messages": [
23
- {"role": "user", "content": "Write a short greeting."},
24
- {"role": "assistant", "content": "Hello there!"},
25
- ]
26
- }
27
- )
28
- ]
29
- out_path.write_text("\n".join(lines) + "\n")
30
- validate_jsonl(out_path)
31
- print(f"Wrote {out_path}")
32
-
33
-
34
- if __name__ == "__main__":
35
- main()
@@ -1,109 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Purge v3 trace databases:
4
- - Find all paths matching **/traces_v3_lm_synth/traces.db under the repo
5
- - If the DB is inside an `old/` path → delete the DB (and -wal/-shm) outright
6
- - Else → delete records older than 24 hours and VACUUM to reclaim space
7
-
8
- Run with: uvpm examples.finetuning.synth_qwen.purge_v3_traces
9
- """
10
-
11
- import contextlib
12
- import datetime
13
- import os
14
- import shutil
15
- import sqlite3
16
- from pathlib import Path
17
-
18
-
19
- def find_trace_dbs(repo_root: Path) -> list[Path]:
20
- return list(repo_root.rglob("traces_v3_lm_synth/traces.db"))
21
-
22
-
23
- def delete_db_files(db_path: Path) -> None:
24
- wal = db_path.with_suffix(".db-wal")
25
- shm = db_path.with_suffix(".db-shm")
26
- if db_path.exists():
27
- os.remove(db_path)
28
- if wal.exists():
29
- os.remove(wal)
30
- if shm.exists():
31
- os.remove(shm)
32
-
33
-
34
- def purge_older_than_24h(db_path: Path) -> None:
35
- cutoff = (datetime.datetime.utcnow() - datetime.timedelta(hours=24)).strftime(
36
- "%Y-%m-%d %H:%M:%S"
37
- )
38
- con = sqlite3.connect(str(db_path))
39
- cur = con.cursor()
40
-
41
- # Collect session_ids to purge
42
- cur.execute("SELECT session_id FROM session_traces WHERE created_at < ?", (cutoff,))
43
- session_ids = [row[0] for row in cur.fetchall()]
44
-
45
- if session_ids:
46
- placeholders = ",".join(["?"] * len(session_ids))
47
- cur.execute(f"DELETE FROM events WHERE session_id IN ({placeholders})", session_ids)
48
- cur.execute(f"DELETE FROM messages WHERE session_id IN ({placeholders})", session_ids)
49
- cur.execute(
50
- f"DELETE FROM session_timesteps WHERE session_id IN ({placeholders})", session_ids
51
- )
52
- cur.execute(
53
- f"DELETE FROM session_traces WHERE session_id IN ({placeholders}) AND created_at < ?",
54
- session_ids + [cutoff],
55
- )
56
-
57
- # Commit deletions before VACUUM
58
- con.commit()
59
- con.close()
60
-
61
- # Attempt VACUUM
62
- try:
63
- con2 = sqlite3.connect(str(db_path))
64
- cur2 = con2.cursor()
65
- cur2.execute("VACUUM")
66
- con2.commit()
67
- con2.close()
68
- return
69
- except sqlite3.OperationalError:
70
- with contextlib.suppress(Exception):
71
- con2.close()
72
-
73
- # Fallback: VACUUM INTO a temp path (e.g., /tmp) then replace atomically
74
- tmp_target = Path("/tmp") / f"{db_path.stem}_compacted.db"
75
- try:
76
- con3 = sqlite3.connect(str(db_path))
77
- cur3 = con3.cursor()
78
- cur3.execute(f"VACUUM INTO '{tmp_target.as_posix()}'")
79
- con3.commit()
80
- con3.close()
81
-
82
- # Replace original DB with compacted copy
83
- delete_db_files(db_path)
84
- shutil.move(str(tmp_target), str(db_path))
85
- finally:
86
- if tmp_target.exists():
87
- # Clean up if move failed
88
- with contextlib.suppress(Exception):
89
- os.remove(tmp_target)
90
-
91
-
92
- def main() -> None:
93
- repo_root = Path(__file__).resolve().parents[3]
94
- dbs = find_trace_dbs(repo_root)
95
- print(f"🔎 Found {len(dbs)} v3 trace DB(s)")
96
-
97
- for db in dbs:
98
- db_str = str(db)
99
- if "/old/" in db_str or db_str.endswith("/old/traces_v3_lm_synth/traces.db"):
100
- print(f"🗑️ Deleting DB under old/: {db_str}")
101
- delete_db_files(db)
102
- continue
103
- print(f"🧹 Purging records older than 24h: {db_str}")
104
- purge_older_than_24h(db)
105
- print(f"✅ Purged and compacted: {db_str}")
106
-
107
-
108
- if __name__ == "__main__":
109
- main()