synth-ai 0.2.9.dev7__py3-none-any.whl → 0.2.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synth-ai might be problematic. Click here for more details.

Files changed (323) hide show
  1. examples/__init__.py +16 -0
  2. examples/crafter_debug_render.py +8 -11
  3. examples/dev/qwen3_32b_qlora_4xh100.toml +40 -0
  4. examples/multi_step/crafter_rl_lora.md +29 -0
  5. examples/qwen_coder/README.md +102 -0
  6. examples/qwen_coder/_shared.py +113 -0
  7. examples/qwen_coder/configs/coder_lora_30b.toml +61 -0
  8. examples/qwen_coder/configs/coder_lora_4b.toml +57 -0
  9. examples/qwen_coder/configs/coder_lora_small.toml +58 -0
  10. examples/qwen_coder/generate_dataset.py +98 -0
  11. examples/qwen_coder/infer_ft_smoke.py +65 -0
  12. examples/qwen_coder/infer_prod_proxy.py +73 -0
  13. examples/qwen_coder/infer_via_synth.py +87 -0
  14. examples/qwen_coder/scripts/infer_coder.sh +19 -0
  15. examples/qwen_coder/scripts/train_coder_30b.sh +22 -0
  16. examples/qwen_coder/sft_full_17b.py +103 -0
  17. examples/qwen_coder/sft_lora_30b.py +110 -0
  18. examples/qwen_coder/subset_jsonl.py +39 -0
  19. examples/qwen_coder/todos.md +38 -0
  20. examples/qwen_coder/validate_jsonl.py +60 -0
  21. examples/rl/run_eval.py +36 -37
  22. examples/rl/run_rl_and_save.py +5 -5
  23. examples/rl/task_app/math_single_step.py +65 -43
  24. examples/rl/task_app/math_task_app.py +3 -3
  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/PROPOSAL.md +53 -0
  66. examples/vlm/README.md +68 -0
  67. examples/vlm/configs/crafter_vlm_gpt4o.toml +44 -0
  68. examples/vlm/crafter_image_only_agent.py +207 -0
  69. examples/vlm/crafter_openai_vlm_agent.py +277 -0
  70. examples/vlm/filter_image_rows.py +63 -0
  71. examples/vlm/run_crafter_vlm_benchmark.py +316 -0
  72. examples/warming_up_to_rl/analyze_trace_db.py +5 -5
  73. examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +11 -1
  74. examples/warming_up_to_rl/export_trace_sft.py +78 -21
  75. examples/warming_up_to_rl/groq_test.py +4 -4
  76. examples/warming_up_to_rl/manage_secrets.py +13 -18
  77. examples/warming_up_to_rl/run_eval.py +42 -44
  78. examples/warming_up_to_rl/run_fft_and_save.py +11 -16
  79. examples/warming_up_to_rl/run_local_rollout.py +1 -3
  80. examples/warming_up_to_rl/run_local_rollout_modal.py +2 -4
  81. examples/warming_up_to_rl/run_local_rollout_parallel.py +1 -4
  82. examples/warming_up_to_rl/run_local_rollout_traced.py +3 -5
  83. examples/warming_up_to_rl/run_rl_and_save.py +5 -6
  84. examples/warming_up_to_rl/run_rollout_remote.py +8 -10
  85. examples/warming_up_to_rl/task_app/README.md +6 -2
  86. examples/warming_up_to_rl/task_app/grpo_crafter.py +234 -35
  87. examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +2 -3
  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 +131 -114
  91. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +101 -41
  92. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +73 -51
  93. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +14 -6
  94. examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +16 -16
  95. examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +32 -34
  96. examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +94 -31
  97. examples/warming_up_to_rl/task_app/synth_envs_hosted/main.py +0 -2
  98. examples/warming_up_to_rl/task_app/synth_envs_hosted/policy_routes.py +303 -203
  99. examples/warming_up_to_rl/task_app/synth_envs_hosted/registry.py +21 -23
  100. examples/warming_up_to_rl/task_app/synth_envs_hosted/rollout.py +328 -225
  101. examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +13 -13
  102. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_agents.py +1 -0
  103. examples/warming_up_to_rl/task_app/synth_envs_hosted/test_service.py +1 -0
  104. examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +4 -3
  105. synth_ai/api/models/supported.py +376 -0
  106. synth_ai/api/train/builders.py +128 -21
  107. synth_ai/api/train/cli.py +80 -64
  108. synth_ai/api/train/config_finder.py +7 -2
  109. synth_ai/api/train/env_resolver.py +1 -1
  110. synth_ai/api/train/pollers.py +2 -1
  111. synth_ai/api/train/supported_algos.py +139 -0
  112. synth_ai/api/train/task_app.py +1 -2
  113. synth_ai/api/train/utils.py +13 -44
  114. synth_ai/cli/__init__.py +8 -0
  115. synth_ai/cli/_modal_wrapper.py +28 -0
  116. synth_ai/cli/_typer_patch.py +49 -0
  117. synth_ai/cli/balance.py +1 -2
  118. synth_ai/cli/calc.py +1 -1
  119. synth_ai/cli/demo.py +2 -1
  120. synth_ai/cli/recent.py +2 -2
  121. synth_ai/cli/rl_demo.py +2 -1
  122. synth_ai/cli/root.py +11 -13
  123. synth_ai/cli/status.py +2 -2
  124. synth_ai/cli/task_apps.py +529 -179
  125. synth_ai/cli/traces.py +6 -4
  126. synth_ai/cli/watch.py +12 -18
  127. synth_ai/demo_registry.py +1 -1
  128. synth_ai/demos/core/cli.py +36 -43
  129. synth_ai/demos/demo_task_apps/__init__.py +3 -3
  130. synth_ai/demos/demo_task_apps/core.py +17 -25
  131. synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +3 -4
  132. synth_ai/demos/demo_task_apps/math/app.py +2 -1
  133. synth_ai/demos/demo_task_apps/math/deploy_modal.py +3 -4
  134. synth_ai/demos/demo_task_apps/math/modal_task_app.py +16 -18
  135. synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -1
  136. synth_ai/environments/examples/crafter_classic/environment.py +76 -1
  137. synth_ai/environments/reproducibility/tree.py +2 -5
  138. synth_ai/environments/service/app.py +11 -12
  139. synth_ai/environments/service/core_routes.py +4 -7
  140. synth_ai/environments/stateful/engine.py +1 -1
  141. synth_ai/environments/tasks/core.py +1 -0
  142. synth_ai/environments/tasks/filters.py +5 -6
  143. synth_ai/environments/tasks/utils.py +4 -5
  144. synth_ai/handshake.py +9 -9
  145. synth_ai/http.py +1 -1
  146. synth_ai/http_client.py +18 -10
  147. synth_ai/inference/client.py +15 -5
  148. synth_ai/jobs/client.py +78 -83
  149. synth_ai/learning/__init__.py +41 -6
  150. synth_ai/learning/algorithms.py +14 -0
  151. synth_ai/learning/client.py +91 -24
  152. synth_ai/learning/config.py +2 -38
  153. synth_ai/learning/ft_client.py +4 -59
  154. synth_ai/learning/health.py +5 -6
  155. synth_ai/learning/jobs.py +31 -47
  156. synth_ai/{rl → learning/rl}/__init__.py +14 -4
  157. synth_ai/learning/rl/client.py +267 -0
  158. synth_ai/learning/rl/config.py +31 -0
  159. synth_ai/{rl → learning/rl}/contracts.py +5 -8
  160. synth_ai/{rl → learning/rl}/env_keys.py +39 -15
  161. synth_ai/learning/rl/secrets.py +13 -0
  162. synth_ai/learning/rl_client.py +2 -281
  163. synth_ai/learning/sft/__init__.py +29 -0
  164. synth_ai/learning/sft/client.py +68 -0
  165. synth_ai/learning/sft/config.py +270 -0
  166. synth_ai/learning/sft/data.py +295 -0
  167. synth_ai/learning/sse.py +25 -24
  168. synth_ai/learning/validators.py +25 -28
  169. synth_ai/lm/__init__.py +21 -47
  170. synth_ai/task/__init__.py +25 -27
  171. synth_ai/task/apps/__init__.py +7 -8
  172. synth_ai/task/auth.py +8 -8
  173. synth_ai/task/client.py +14 -14
  174. synth_ai/task/contracts.py +36 -35
  175. synth_ai/task/datasets.py +6 -5
  176. synth_ai/task/errors.py +10 -10
  177. synth_ai/task/health.py +17 -9
  178. synth_ai/task/json.py +58 -23
  179. synth_ai/task/proxy.py +13 -9
  180. synth_ai/task/rubrics.py +16 -15
  181. synth_ai/task/server.py +12 -12
  182. synth_ai/task/tracing_utils.py +4 -4
  183. synth_ai/task/vendors.py +5 -6
  184. synth_ai/tracing_v3/__init__.py +2 -0
  185. synth_ai/tracing_v3/abstractions.py +21 -4
  186. synth_ai/tracing_v3/decorators.py +18 -16
  187. synth_ai/tracing_v3/hooks.py +5 -5
  188. synth_ai/tracing_v3/llm_call_record_helpers.py +6 -6
  189. synth_ai/tracing_v3/session_tracer.py +40 -14
  190. synth_ai/tracing_v3/storage/base.py +85 -0
  191. synth_ai/tracing_v3/storage/config.py +21 -8
  192. synth_ai/tracing_v3/storage/factory.py +10 -7
  193. synth_ai/tracing_v3/storage/utils.py +4 -2
  194. synth_ai/tracing_v3/turso/daemon.py +7 -2
  195. synth_ai/tracing_v3/turso/models.py +2 -2
  196. synth_ai/tracing_v3/turso/native_manager.py +1173 -0
  197. synth_ai/tracing_v3/utils.py +4 -4
  198. synth_ai/v0/api/__init__.py +8 -0
  199. synth_ai/v0/api/models/__init__.py +8 -0
  200. synth_ai/v0/api/models/supported.py +8 -0
  201. synth_ai/v0/config/__init__.py +15 -0
  202. synth_ai/v0/config/base_url.py +12 -0
  203. synth_ai/v0/lm/__init__.py +51 -0
  204. synth_ai/{lm → v0/lm}/caching/ephemeral.py +2 -2
  205. synth_ai/{lm → v0/lm}/caching/handler.py +4 -4
  206. synth_ai/{lm → v0/lm}/caching/initialize.py +1 -1
  207. synth_ai/{lm → v0/lm}/caching/persistent.py +1 -1
  208. synth_ai/{lm → v0/lm}/config.py +6 -1
  209. synth_ai/{lm → v0/lm}/core/all.py +9 -9
  210. synth_ai/{lm → v0/lm}/core/main.py +6 -6
  211. synth_ai/{lm → v0/lm}/core/main_v3.py +10 -10
  212. synth_ai/{lm → v0/lm}/core/synth_models.py +2 -14
  213. synth_ai/{lm → v0/lm}/core/vendor_clients.py +2 -2
  214. synth_ai/{lm → v0/lm}/overrides.py +2 -2
  215. synth_ai/{lm → v0/lm}/provider_support/anthropic.py +4 -4
  216. synth_ai/{lm → v0/lm}/provider_support/openai.py +5 -5
  217. synth_ai/{lm → v0/lm}/structured_outputs/handler.py +5 -5
  218. synth_ai/{lm → v0/lm}/structured_outputs/rehabilitate.py +1 -1
  219. synth_ai/{lm → v0/lm}/vendors/core/anthropic_api.py +9 -9
  220. synth_ai/{lm → v0/lm}/vendors/core/gemini_api.py +5 -5
  221. synth_ai/{lm → v0/lm}/vendors/core/mistral_api.py +5 -5
  222. synth_ai/{lm → v0/lm}/vendors/core/openai_api.py +10 -10
  223. synth_ai/{lm → v0/lm}/vendors/openai_standard.py +8 -8
  224. synth_ai/{lm → v0/lm}/vendors/openai_standard_responses.py +2 -2
  225. synth_ai/{lm → v0/lm}/vendors/supported/custom_endpoint.py +3 -3
  226. synth_ai/{lm → v0/lm}/vendors/supported/deepseek.py +2 -2
  227. synth_ai/{lm → v0/lm}/vendors/supported/grok.py +2 -2
  228. synth_ai/{lm → v0/lm}/vendors/supported/groq.py +1 -1
  229. synth_ai/{lm → v0/lm}/vendors/supported/ollama.py +1 -1
  230. synth_ai/{lm → v0/lm}/vendors/supported/openrouter.py +3 -3
  231. synth_ai/{lm → v0/lm}/vendors/supported/together.py +1 -1
  232. synth_ai/{lm → v0/lm}/vendors/synth_client.py +1 -1
  233. synth_ai/v0/tracing_v3/__init__.py +10 -0
  234. synth_ai/v0/tracing_v3/abstractions.py +3 -0
  235. synth_ai/v0/tracing_v3/decorators.py +3 -0
  236. synth_ai/v0/tracing_v3/llm_call_record_helpers.py +3 -0
  237. synth_ai/v0/tracing_v3/session_tracer.py +3 -0
  238. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.10.dist-info}/METADATA +10 -7
  239. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.10.dist-info}/RECORD +269 -233
  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. synth_ai/experimental/synth_oss.py +0 -445
  273. synth_ai/learning/filtering.py +0 -0
  274. synth_ai/learning/offline/dpo.py +0 -0
  275. synth_ai/learning/offline/providers.py +0 -7
  276. synth_ai/learning/offline/sft.py +0 -0
  277. synth_ai/learning/offline/shared.py +0 -0
  278. synth_ai/learning/online/grpo.py +0 -0
  279. synth_ai/learning/online/irft.py +0 -0
  280. synth_ai/learning/prompts/banking77_injection_eval.py +0 -168
  281. synth_ai/learning/prompts/gepa.py +0 -0
  282. synth_ai/learning/prompts/hello_world_in_context_injection_ex.py +0 -211
  283. synth_ai/learning/prompts/mipro.py +0 -289
  284. synth_ai/learning/prompts/random_search.py +0 -249
  285. synth_ai/learning/prompts/run_mipro_banking77.py +0 -172
  286. synth_ai/learning/prompts/run_random_search_banking77.py +0 -329
  287. synth_ai/rl/secrets.py +0 -19
  288. synth_ai/scripts/verify_rewards.py +0 -100
  289. synth_ai/tracing/__init__.py +0 -30
  290. synth_ai/tracing_v1/__init__.py +0 -33
  291. synth_ai/tracing_v3/turso/__init__.py +0 -25
  292. synth_ai/tracing_v3/turso/manager.py +0 -838
  293. synth_ai/zyk/__init__.py +0 -30
  294. /synth_ai/{lm → v0/lm}/caching/__init__.py +0 -0
  295. /synth_ai/{lm → v0/lm}/caching/constants.py +0 -0
  296. /synth_ai/{lm → v0/lm}/caching/dbs.py +0 -0
  297. /synth_ai/{lm → v0/lm}/constants.py +0 -0
  298. /synth_ai/{lm → v0/lm}/core/__init__.py +0 -0
  299. /synth_ai/{lm → v0/lm}/core/exceptions.py +0 -0
  300. /synth_ai/{lm → v0/lm}/cost/__init__.py +0 -0
  301. /synth_ai/{lm → v0/lm}/cost/monitor.py +0 -0
  302. /synth_ai/{lm → v0/lm}/cost/statefulness.py +0 -0
  303. /synth_ai/{lm → v0/lm}/injection.py +0 -0
  304. /synth_ai/{lm → v0/lm}/provider_support/__init__.py +0 -0
  305. /synth_ai/{lm → v0/lm}/provider_support/suppress_logging.py +0 -0
  306. /synth_ai/{lm → v0/lm}/structured_outputs/__init__.py +0 -0
  307. /synth_ai/{lm → v0/lm}/structured_outputs/inject.py +0 -0
  308. /synth_ai/{lm → v0/lm}/tools/__init__.py +0 -0
  309. /synth_ai/{lm → v0/lm}/tools/base.py +0 -0
  310. /synth_ai/{lm → v0/lm}/unified_interface.py +0 -0
  311. /synth_ai/{lm → v0/lm}/vendors/__init__.py +0 -0
  312. /synth_ai/{lm → v0/lm}/vendors/base.py +0 -0
  313. /synth_ai/{lm → v0/lm}/vendors/core/__init__.py +0 -0
  314. /synth_ai/{lm → v0/lm}/vendors/core/synth_dev_api.py +0 -0
  315. /synth_ai/{lm → v0/lm}/vendors/local/__init__.py +0 -0
  316. /synth_ai/{lm → v0/lm}/vendors/local/ollama.py +0 -0
  317. /synth_ai/{lm → v0/lm}/vendors/retries.py +0 -0
  318. /synth_ai/{lm → v0/lm}/vendors/supported/__init__.py +0 -0
  319. /synth_ai/{lm → v0/lm}/warmup.py +0 -0
  320. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.10.dist-info}/WHEEL +0 -0
  321. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.10.dist-info}/entry_points.txt +0 -0
  322. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.10.dist-info}/licenses/LICENSE +0 -0
  323. {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.10.dist-info}/top_level.txt +0 -0
@@ -1,324 +0,0 @@
1
- ### Quickstart (using config.toml)
2
-
3
- The defaults come from `examples/finetuning/synth_qwen/config.toml`. Override with env vars only when needed.
4
-
5
- #### 1) Rollouts → v3 traces
6
- ```bash
7
- set -a; source .env 2>/dev/null || true; set +a
8
- uvpm examples.finetuning.synth_qwen.run_crafter_qwen4b
9
- ```
10
-
11
- Notes:
12
- - Model, episodes, steps, difficulty, temperature, tool choice, etc. are taken from `config.toml`.
13
- - Only API key and v3 db path are specified here.
14
-
15
- Example output (abridged):
16
- ```text
17
- āœ… Crafter service is healthy
18
- šŸš€ Running 10 episodes (concurrency=5)...
19
- āœ… Completed 10 episodes in ~366s
20
- šŸ“Š EVALUATION RESULTS
21
- Episodes completed: 10/10
22
- Average reward per episode: 1.10
23
- Average steps per episode: 87.00
24
- šŸ’¾ Results: traces/v3/synth_ai.db
25
- ```
26
-
27
- #### 2) Filter traces → SFT JSONL
28
- ```bash
29
- uvpm examples.finetuning.synth_qwen.filter_traces_achievements
30
- ```
31
-
32
- Notes:
33
- - Filter settings (achievements, thresholds, output path) are defined in `config.toml`.
34
-
35
- Example output:
36
- ```text
37
- Using database: sqlite+aiosqlite:///$PWD/traces/v3/synth_ai.db/dbs/default/data
38
- Output file: ft_data/qwen4b_crafter_sft_collect_wood.jsonl
39
- āœ… Wrote 13 examples from 13 sessions
40
- ```
41
-
42
- #### 3) Kick off SFT (prod)
43
- ```bash
44
- set -a; source .env 2>/dev/null || true; set +a
45
- uvpm examples.finetuning.synth_qwen.sft_kickoff
46
- ```
47
-
48
- Notes:
49
- - Base model and training JSONL path come from `config.toml`.
50
-
51
- Example output (abridged):
52
- ```text
53
- šŸš€ Starting Qwen 4B SFT
54
- ā³ poll ...
55
- 🟢 Qwen4B SFT fine-tune succeeded → ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-22
56
- ```
57
-
58
- #### 4) Rollouts with fine-tuned model
59
- ```bash
60
- set -a; source .env 2>/dev/null || true; set +a
61
- CRAFTER_MODEL="ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-22" uvpm examples.finetuning.synth_qwen.run_crafter_qwen4b
62
- ```
63
-
64
- Notes:
65
- - Replace `ftjob-22` with the job id printed by your SFT step.
66
- - If you see 401 Invalid API key, export the prod key: `export SYNTH_API_KEY="$SYNTH_API_KEY_PROD"`.
67
-
68
- Example output (abridged):
69
- ```text
70
- āœ… Model warmed up successfully!
71
- šŸš€ Running 10 episodes (concurrency=5)...
72
- āœ… Completed 10 episodes in ~480s
73
- šŸ“Š EVALUATION RESULTS
74
- Episodes completed: 10/10
75
- Average reward per episode: 1.60
76
- Average steps per episode: 90.80
77
- Achievements: collect_wood in 6/10 episodes
78
- šŸ’¾ Results: traces/v3/synth_ai.db
79
- ```
80
-
81
-
82
-
83
- ```
84
- joshuapurtell@Mac synth-ai % bash examples/finetuning/synth_qwen/run_demo.sh
85
- Synth Qwen4B finetuning demo (Crafter)
86
-
87
- Run rollouts to generate v3 traces now? [Y/n]: Y
88
- Using config defaults from examples/finetuning/synth_qwen/config.toml (override below if desired).
89
- Model id [Enter=use config]:
90
- Episodes [Enter=use config]: 5
91
- Max steps [Enter=use config]: 5
92
- Difficulty [Enter=use config]:
93
- Enable think mode? (1/0) [Enter=0]:
94
-
95
- Running rollouts (v3 tracing)...
96
- Detected SYNTH_API_KEY (sk_liv...ac95). Use this key? [Y/n]: N
97
- Use SYNTH_API_KEY_PROD (sk_liv...a2a4)? [y/N]: y
98
- [PATCH] Attempting to apply Crafter deterministic patch...
99
- [PATCH] Patching crafter.Env._balance_object...
100
- [PATCH] crafter.Env._balance_object patched.
101
- [PATCH] Attempting to apply Crafter serialization patch v3...
102
- [PATCH] Adding enhanced save/load methods to crafter.Env...
103
- [PATCH] crafter.Env.save() and load() methods added (v3).
104
- [PATCH] Crafter serialization patch v3 complete.
105
- [PATCH] Attempting to apply simplified Crafter world configuration patch...
106
- [PATCH] Simplified Crafter world configuration patch complete.
107
- [PATCH] Available configs: easy, normal, hard, peaceful
108
- šŸ”§ Using Synth base URL = https://agent-learning.onrender.com/api
109
- šŸ”‡ Quiet mode enabled - suppressing verbose logs
110
- āœ… Crafter service is healthy: {'status': 'ok', 'supported_environments': ['CrafterClassic', 'CrafterCustom']}
111
-
112
- šŸ”„ Warming up Qwen/Qwen3-4B-Instruct-2507 on Synth backend...
113
- āœ… Warmed Qwen/Qwen3-4B-Instruct-2507 in 3s arming elapsed=0s
114
- āœ… Model warmed up successfully!
115
-
116
- šŸš€ Starting sqld daemon for v3 tracing...
117
- āœ… sqld daemon started
118
-
119
- šŸ“Š V3 Tracing enabled. Traces will be saved to: traces/v3/synth_ai.db
120
- Experiment: crafter_lm_synth_Qwen/Qwen3-4B-Instruct-2507_20250808_165304
121
-
122
- šŸš€ Running 5 episodes (concurrency=5)...
123
-
124
- šŸ“¤ Starting episodes...
125
- Episode 1: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:18<00:00, 3.71s/it, tc=1, act=3, tok=78, in=860, tps=22.4]
126
- Episode 0: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:19<00:00, 3.89s/it, tc=1, act=3, tok=94, in=861, tps=22.79]
127
- Episode 2: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:18<00:00, 3.74s/it, tc=1, act=2, tok=73, in=832, tps=21.06]
128
- Episode 4: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:19<00:00, 3.90s/it, tc=1, act=3, tok=91, in=818, tps=17.34]
129
- Episode 3: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:20<00:00, 4.15s/it, tc=1, act=2, tok=86, in=859, tps=21.96]
130
-
131
- āœ… Completed 5 episodes in 23.57 seconds
132
-
133
- ==================================================
134
- šŸ“Š EVALUATION RESULTS
135
- ==================================================
136
- Episodes completed: 5/5
137
- Failed episodes: 0
138
- Total reward: 1.00
139
- Average reward per episode: 0.20
140
- Total steps: 68
141
- Average steps per episode: 13.60
142
-
143
- Seeds used:
144
- Episode 0: seed 1
145
- Episode 1: seed 2
146
- Episode 2: seed 3
147
- Episode 3: seed 4
148
- Episode 4: seed 5
149
- Unique achievements unlocked: 1
150
-
151
- Achievements unlocked:
152
- - collect_sapling: 1 episodes (20.0%)
153
-
154
- Action counts (total: 68):
155
- - move_right: 25 (36.8%)
156
- - do: 19 (27.9%)
157
- - move_down: 10 (14.7%)
158
- - move_left: 5 (7.4%)
159
- - place_stone: 3 (4.4%)
160
- - move_up: 3 (4.4%)
161
- - make_wood_sword: 1 (1.5%)
162
- - make_stone_pickaxe: 1 (1.5%)
163
- - make_wood_pickaxe: 1 (1.5%)
164
-
165
- šŸ’¾ Results available in Turso database: traces/v3/synth_ai.db
166
- Experiment ID: exp_a0b091fd12c6
167
- Use the filter_traces_sft_turso.py script to extract fine-tuning data
168
-
169
- Markdown row:
170
- | Qwen/Qwen3-4B-Instruct-2507 | 5 | 0.20 | 0.020 | 0.001 | 68.000 | 13.600 |
171
-
172
- āœ… Stopped sqld daemon
173
-
174
- Filter v3 traces into SFT JSONL now? [Y/n]: Y
175
- Using DB: sqlite+aiosqlite:////Users/joshuapurtell/Documents/GitHub/synth-ai/traces/v3/synth_ai.db/dbs/default/data
176
- You can override filter options; Enter to use config defaults.
177
- Required achievements (space-separated) [Enter=config]:
178
- Restrict to models (space-separated) [Enter=all]:
179
- Output JSONL path [Enter=config]:
180
- Min total reward [Enter=config]: 1
181
- Max total cost [Enter=config]:
182
- Max total tokens [Enter=config]:
183
-
184
- Filtering traces to SFT JSONL...
185
- [PATCH] Attempting to apply Crafter deterministic patch...
186
- [PATCH] Patching crafter.Env._balance_object...
187
- [PATCH] crafter.Env._balance_object patched.
188
- [PATCH] Attempting to apply Crafter serialization patch v3...
189
- [PATCH] Adding enhanced save/load methods to crafter.Env...
190
- [PATCH] crafter.Env.save() and load() methods added (v3).
191
- [PATCH] Crafter serialization patch v3 complete.
192
- [PATCH] Attempting to apply simplified Crafter world configuration patch...
193
- [PATCH] Simplified Crafter world configuration patch complete.
194
- [PATCH] Available configs: easy, normal, hard, peaceful
195
- šŸ¤– Modal/Synth FT Filter (achievements)
196
- Using database: sqlite+aiosqlite:////Users/joshuapurtell/Documents/GitHub/synth-ai/traces/v3/synth_ai.db/dbs/default/data
197
- Output file: ft_data/qwen4b_crafter_sft.jsonl
198
- Filters: {
199
- "required_achievements": [
200
- "collect_wood"
201
- ],
202
- "models": [
203
- "Qwen/Qwen3-4B-Instruct-2507"
204
- ],
205
- "min_total_reward": 1.0,
206
- "max_cost": 10.0,
207
- "max_tokens": 100000
208
- }
209
-
210
- āœ… Wrote 23 examples from 23 sessions
211
-
212
- Kick off SFT training job now? [Y/n]: Y
213
- Enter overrides for training job; Enter to use config.
214
- Base model [Enter=config]:
215
- Training JSONL path [Enter=config]:
216
-
217
- Starting SFT job...
218
- Detected SYNTH_API_KEY (sk_liv...a2a4). Use this key? [Y/n]: n
219
- Use SYNTH_API_KEY_PROD (sk_liv...a2a4)? [y/N]: Y
220
- šŸš€ Starting Qwen 4B SFT
221
- ā³ poll 1/20 – status = queued
222
- ā³ poll 2/20 – status = queued
223
- ā³ poll 3/20 – status = queued
224
- ā³ poll 4/20 – status = queued
225
- ā³ poll 5/20 – status = queued
226
- ā³ poll 6/20 – status = queued
227
- ā³ poll 7/20 – status = queued
228
- ā³ poll 8/20 – status = queued
229
- ā³ poll 9/20 – status = running
230
- ā³ poll 10/20 – status = queued
231
- ā³ poll 11/20 – status = queued
232
- ā³ poll 12/20 – status = succeeded
233
- 🟢 Qwen4B SFT fine-tune succeeded → ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace
234
- ā±ļø wall-clock: 249.3s | trained_tokens: 41777
235
- Captured fine-tuned model id: ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace
236
- SFT logs saved to: logs/sft_kickoff_20250808_165436.log
237
-
238
- Roll out fine-tuned model 'ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace' in Crafter now? [y/N]: Y
239
- Episodes [Enter=config]: 5
240
- Max steps [Enter=config]: 5
241
- Difficulty [Enter=config]:
242
- Enable think mode? (1/0) [Enter=0]:
243
-
244
- Running rollouts with fine-tuned model...
245
- [PATCH] Attempting to apply Crafter deterministic patch...
246
- [PATCH] Patching crafter.Env._balance_object...
247
- [PATCH] crafter.Env._balance_object patched.
248
- [PATCH] Attempting to apply Crafter serialization patch v3...
249
- [PATCH] Adding enhanced save/load methods to crafter.Env...
250
- [PATCH] crafter.Env.save() and load() methods added (v3).
251
- [PATCH] Crafter serialization patch v3 complete.
252
- [PATCH] Attempting to apply simplified Crafter world configuration patch...
253
- [PATCH] Simplified Crafter world configuration patch complete.
254
- [PATCH] Available configs: easy, normal, hard, peaceful
255
- šŸ”§ Using Synth base URL = https://agent-learning.onrender.com/api
256
- šŸ”‡ Quiet mode enabled - suppressing verbose logs
257
- āœ… Crafter service is healthy: {'status': 'ok', 'supported_environments': ['CrafterClassic', 'CrafterCustom']}
258
-
259
- šŸ”„ Warming up ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace on Synth backend...
260
- ā³ Warming ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace [|] status=timeout elapsed=10ā³ Warming ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace [/] status=timeout elapsed=21āœ… Warmed ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace in 22s
261
- āœ… Model warmed up successfully!
262
-
263
- šŸš€ Starting sqld daemon for v3 tracing...
264
- āœ… sqld daemon started
265
-
266
- šŸ“Š V3 Tracing enabled. Traces will be saved to: traces/v3/synth_ai.db
267
- Experiment: crafter_lm_synth_ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace_20250808_165943
268
-
269
- šŸš€ Running 5 episodes (concurrency=5)...
270
-
271
- šŸ“¤ Starting episodes...
272
- Episode 2: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:48<00:00, 9.80s/it, tc=1, act=3, tok=75, in=833, tps=15.24]
273
- Episode 1: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:52<00:00, 10.48s/it, tc=1, act=3, tok=73, in=840, tps=10.74]
274
- Episode 3: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:54<00:00, 10.88s/it, tc=1, act=3, tok=79, in=834, tps=15.59]
275
- Episode 4: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:54<00:00, 10.90s/it, tc=1, act=3, tok=75, in=817, tps=11.93]
276
- Episode 0: 100%|ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ| 5/5 [00:56<00:00, 11.38s/it, tc=1, act=2, tok=91, in=850, tps=5.53]
277
-
278
- āœ… Completed 5 episodes in 58.29 seconds
279
-
280
- ==================================================
281
- šŸ“Š EVALUATION RESULTS
282
- ==================================================
283
- Episodes completed: 5/5
284
- Failed episodes: 0
285
- Total reward: 3.00
286
- Average reward per episode: 0.60
287
- Total steps: 72
288
- Average steps per episode: 14.40
289
-
290
- Seeds used:
291
- Episode 0: seed 1
292
- Episode 1: seed 2
293
- Episode 2: seed 3
294
- Episode 3: seed 4
295
- Episode 4: seed 5
296
- Unique achievements unlocked: 2
297
-
298
- Achievements unlocked:
299
- - collect_sapling: 2 episodes (40.0%)
300
- - collect_wood: 1 episodes (20.0%)
301
-
302
- Action counts (total: 72):
303
- - move_right: 25 (34.7%)
304
- - do: 19 (26.4%)
305
- - move_down: 8 (11.1%)
306
- - move_left: 8 (11.1%)
307
- - move_up: 6 (8.3%)
308
- - place_stone: 2 (2.8%)
309
- - place_table: 2 (2.8%)
310
- - make_wood_pickaxe: 1 (1.4%)
311
- - place_plant: 1 (1.4%)
312
-
313
- šŸ’¾ Results available in Turso database: traces/v3/synth_ai.db
314
- Experiment ID: exp_56d8e29cbf5a
315
- Use the filter_traces_sft_turso.py script to extract fine-tuning data
316
-
317
- Markdown row:
318
- | ft:Qwen/Qwen3-4B-Instruct-2507:ftjob-6cedf721e0ca4c80968834b71e2bdace | 5 | 0.60 | 0.240 | 0.012 | 72.000 | 14.400 |
319
-
320
- āœ… Stopped sqld daemon
321
-
322
- Done. You can re-run this script to repeat steps as needed.
323
- joshuapurtell@Mac synth-ai %
324
- ```
@@ -1,60 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Filter v3 Crafter traces into an SFT-ready JSONL using the maintained
4
- Modal/Synth filter logic (no CLI needed). Intended to be run after
5
- collecting trajectories with the Crafter runner.
6
-
7
- Environment:
8
- - CRAFTER_DB_URL (default: sqlite:///traces_v3_lm_synth/traces.db)
9
- - OUTPUT_JSONL (default: ft_data/qwen4b_crafter_sft.jsonl)
10
- - MIN_TOTAL_REWARD (float, default: 1.0)
11
- - MIN_ACHIEVEMENTS (int, default: 0)
12
- - MAX_COST (float, default: 10.0)
13
- - MAX_TOKENS (int, default: 100000)
14
- - MODELS (optional, space-separated model names; default empty = all)
15
- """
16
-
17
- import asyncio
18
- import json
19
- import os
20
- from typing import Any
21
-
22
- # Reuse the existing filtering implementation
23
- from synth_ai.environments.examples.crafter_classic.agent_demos.crafter_modal_ft.filter_traces_sft_turso import (
24
- filter_traces_from_turso,
25
- )
26
-
27
-
28
- def build_config() -> dict[str, Any]:
29
- models_env = os.getenv("MODELS", "").strip()
30
- models: list[str] = models_env.split() if models_env else []
31
- return {
32
- "mode": "trajectory",
33
- "filters": {
34
- "min_total_reward": float(os.getenv("MIN_TOTAL_REWARD", "1.0")),
35
- "min_achievements": int(os.getenv("MIN_ACHIEVEMENTS", "0")),
36
- "max_cost": float(os.getenv("MAX_COST", "10.0")),
37
- "max_tokens": int(os.getenv("MAX_TOKENS", "100000")),
38
- "models": models,
39
- },
40
- }
41
-
42
-
43
- async def main() -> None:
44
- db_url = os.getenv("CRAFTER_DB_URL", "sqlite:///traces_v3_lm_synth/traces.db")
45
- output_path = os.getenv("OUTPUT_JSONL", "ft_data/qwen4b_crafter_sft.jsonl")
46
- config = build_config()
47
-
48
- print("šŸ¤– Modal/Synth Fine-Tuning Data Filter (v3)")
49
- print("Using database:", db_url)
50
- print("Output file:", output_path)
51
- print("Config:", json.dumps(config, indent=2))
52
-
53
- num_examples, stats = await filter_traces_from_turso(db_url, output_path, config)
54
-
55
- print("\nāœ… Wrote", num_examples, "training examples to", output_path)
56
- print("šŸ“Š Stats keys:", list(stats.keys()))
57
-
58
-
59
- if __name__ == "__main__":
60
- asyncio.run(main())
@@ -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())