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