synth-ai 0.2.9.dev7__py3-none-any.whl → 0.2.9.dev8__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 +8 -11
- 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 +64 -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 +18 -0
- examples/qwen_coder/scripts/train_coder_30b.sh +21 -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 +38 -0
- examples/qwen_coder/validate_jsonl.py +59 -0
- examples/rl/run_eval.py +36 -37
- examples/rl/run_rl_and_save.py +5 -5
- examples/rl/task_app/math_single_step.py +65 -43
- examples/rl/task_app/math_task_app.py +3 -3
- 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/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 +5 -5
- examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +11 -1
- examples/warming_up_to_rl/export_trace_sft.py +78 -21
- examples/warming_up_to_rl/groq_test.py +4 -4
- examples/warming_up_to_rl/manage_secrets.py +13 -18
- examples/warming_up_to_rl/run_eval.py +42 -44
- examples/warming_up_to_rl/run_fft_and_save.py +11 -16
- examples/warming_up_to_rl/run_local_rollout.py +1 -3
- examples/warming_up_to_rl/run_local_rollout_modal.py +2 -4
- examples/warming_up_to_rl/run_local_rollout_parallel.py +1 -4
- examples/warming_up_to_rl/run_local_rollout_traced.py +3 -5
- examples/warming_up_to_rl/run_rl_and_save.py +5 -6
- examples/warming_up_to_rl/run_rollout_remote.py +8 -10
- examples/warming_up_to_rl/task_app/README.md +6 -2
- examples/warming_up_to_rl/task_app/grpo_crafter.py +234 -35
- examples/warming_up_to_rl/task_app/grpo_crafter_task_app.py +2 -3
- 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 +131 -114
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/environment.py +101 -41
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/policy.py +73 -51
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/react_agent.py +14 -6
- examples/warming_up_to_rl/task_app/synth_envs_hosted/envs/crafter/shared.py +16 -16
- examples/warming_up_to_rl/task_app/synth_envs_hosted/hosted_app.py +32 -34
- examples/warming_up_to_rl/task_app/synth_envs_hosted/inference/openai_client.py +94 -31
- 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 +303 -203
- 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 +328 -225
- examples/warming_up_to_rl/task_app/synth_envs_hosted/storage/volume.py +13 -13
- 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 +1 -0
- examples/warming_up_to_rl/task_app/synth_envs_hosted/utils.py +4 -3
- synth/__init__.py +14 -0
- synth_ai/__init__.py +26 -4
- synth_ai/api/models/supported.py +376 -0
- synth_ai/api/train/builders.py +128 -21
- synth_ai/api/train/cli.py +80 -64
- synth_ai/api/train/config_finder.py +7 -2
- synth_ai/api/train/env_resolver.py +1 -1
- synth_ai/api/train/pollers.py +2 -1
- synth_ai/api/train/supported_algos.py +139 -0
- synth_ai/api/train/task_app.py +1 -2
- synth_ai/api/train/utils.py +13 -44
- synth_ai/cli/__init__.py +8 -0
- synth_ai/cli/_modal_wrapper.py +28 -0
- synth_ai/cli/_typer_patch.py +49 -0
- synth_ai/cli/balance.py +1 -2
- synth_ai/cli/calc.py +1 -1
- synth_ai/cli/demo.py +2 -1
- synth_ai/cli/recent.py +2 -2
- synth_ai/cli/rl_demo.py +2 -1
- synth_ai/cli/root.py +11 -13
- synth_ai/cli/status.py +2 -2
- synth_ai/cli/task_apps.py +529 -179
- synth_ai/cli/traces.py +6 -4
- synth_ai/cli/watch.py +12 -18
- synth_ai/demo_registry.py +1 -1
- synth_ai/demos/core/cli.py +36 -43
- synth_ai/demos/demo_task_apps/__init__.py +3 -3
- synth_ai/demos/demo_task_apps/core.py +17 -25
- synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +3 -4
- synth_ai/demos/demo_task_apps/math/app.py +2 -1
- synth_ai/demos/demo_task_apps/math/deploy_modal.py +3 -4
- synth_ai/demos/demo_task_apps/math/modal_task_app.py +16 -18
- synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -1
- synth_ai/environments/examples/crafter_classic/environment.py +76 -1
- synth_ai/environments/reproducibility/tree.py +2 -5
- synth_ai/environments/service/app.py +11 -12
- synth_ai/environments/service/core_routes.py +4 -7
- 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/handshake.py +9 -9
- synth_ai/http.py +1 -1
- synth_ai/http_client.py +18 -10
- synth_ai/inference/client.py +15 -5
- synth_ai/jobs/client.py +78 -83
- synth_ai/learning/__init__.py +41 -6
- synth_ai/learning/algorithms.py +14 -0
- synth_ai/learning/client.py +91 -24
- synth_ai/learning/config.py +2 -38
- synth_ai/learning/ft_client.py +4 -59
- synth_ai/learning/health.py +5 -6
- synth_ai/learning/jobs.py +31 -47
- synth_ai/{rl → learning/rl}/__init__.py +14 -4
- synth_ai/learning/rl/client.py +267 -0
- synth_ai/learning/rl/config.py +31 -0
- synth_ai/{rl → learning/rl}/contracts.py +5 -8
- synth_ai/{rl → learning/rl}/env_keys.py +39 -15
- synth_ai/learning/rl/secrets.py +13 -0
- synth_ai/learning/rl_client.py +2 -281
- 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 -24
- synth_ai/learning/validators.py +25 -28
- synth_ai/lm/__init__.py +21 -47
- synth_ai/main.py +4 -0
- synth_ai/task/__init__.py +25 -27
- synth_ai/task/apps/__init__.py +7 -8
- synth_ai/task/auth.py +8 -8
- synth_ai/task/client.py +14 -14
- synth_ai/task/contracts.py +36 -35
- synth_ai/task/datasets.py +6 -5
- synth_ai/task/errors.py +10 -10
- synth_ai/task/health.py +17 -9
- synth_ai/task/json.py +58 -23
- synth_ai/task/proxy.py +13 -9
- synth_ai/task/rubrics.py +16 -15
- synth_ai/task/server.py +12 -12
- synth_ai/task/tracing_utils.py +4 -4
- synth_ai/task/vendors.py +5 -6
- synth_ai/tracing_v3/__init__.py +2 -0
- synth_ai/tracing_v3/abstractions.py +21 -4
- synth_ai/tracing_v3/decorators.py +18 -16
- synth_ai/tracing_v3/hooks.py +5 -5
- synth_ai/tracing_v3/llm_call_record_helpers.py +6 -6
- synth_ai/tracing_v3/session_tracer.py +40 -14
- synth_ai/tracing_v3/storage/base.py +85 -0
- synth_ai/tracing_v3/storage/config.py +21 -8
- synth_ai/tracing_v3/storage/factory.py +10 -7
- 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 +2 -2
- synth_ai/tracing_v3/turso/native_manager.py +1173 -0
- synth_ai/tracing_v3/utils.py +4 -4
- 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 +2 -2
- 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/main.py +6 -6
- synth_ai/{lm → v0/lm}/core/main_v3.py +10 -10
- synth_ai/{lm → v0/lm}/core/synth_models.py +2 -14
- synth_ai/{lm → v0/lm}/core/vendor_clients.py +2 -2
- synth_ai/{lm → v0/lm}/overrides.py +2 -2
- 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 +9 -9
- 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 +10 -10
- synth_ai/{lm → v0/lm}/vendors/openai_standard.py +8 -8
- synth_ai/{lm → v0/lm}/vendors/openai_standard_responses.py +2 -2
- synth_ai/{lm → v0/lm}/vendors/supported/custom_endpoint.py +3 -3
- 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 +1 -1
- 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.dev8.dist-info/METADATA +191 -0
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/RECORD +268 -238
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/top_level.txt +1 -0
- examples/common_old/backend.py +0 -20
- examples/evals_old/README.md +0 -98
- examples/evals_old/__init__.py +0 -6
- examples/evals_old/compare_models.py +0 -1038
- 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 -243
- 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 -119
- 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 -243
- 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 -36
- examples/finetuning_old/synth_qwen_v1/poll.py +0 -46
- 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 -1933
- examples/finetuning_old/synth_qwen_v1/run_crafter_sft_job.py +0 -210
- examples/finetuning_old/synth_qwen_v1/run_ft_job.py +0 -237
- examples/finetuning_old/synth_qwen_v1/upload_data.py +0 -34
- examples/finetuning_old/synth_qwen_v1/util.py +0 -152
- examples/rl_old/task_app.py +0 -1131
- examples/warming_up_to_rl/old/event_rewards.md +0 -234
- examples/warming_up_to_rl/old/notes.md +0 -73
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_traces_sft_turso.py +0 -738
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
- synth_ai/experimental/synth_oss.py +0 -445
- 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 -211
- synth_ai/learning/prompts/mipro.py +0 -289
- synth_ai/learning/prompts/random_search.py +0 -249
- synth_ai/learning/prompts/run_mipro_banking77.py +0 -172
- synth_ai/learning/prompts/run_random_search_banking77.py +0 -329
- 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 -838
- synth_ai/zyk/__init__.py +0 -30
- synth_ai-0.2.9.dev7.dist-info/METADATA +0 -131
- /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}/core/exceptions.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.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.9.dev7.dist-info → synth_ai-0.2.9.dev8.dist-info}/licenses/LICENSE +0 -0
synth_ai/cli/traces.py
CHANGED
|
@@ -26,7 +26,7 @@ def register(cli):
|
|
|
26
26
|
console = Console()
|
|
27
27
|
|
|
28
28
|
async def _run():
|
|
29
|
-
from synth_ai.tracing_v3.
|
|
29
|
+
from synth_ai.tracing_v3.storage.factory import StorageConfig, create_storage
|
|
30
30
|
|
|
31
31
|
# Discover DBs under ./synth_ai.db/dbs (or override via env)
|
|
32
32
|
root = os.getenv("SYNTH_TRACES_ROOT", "./synth_ai.db/dbs")
|
|
@@ -58,7 +58,7 @@ def register(cli):
|
|
|
58
58
|
|
|
59
59
|
async def db_counts(db_dir: str) -> tuple[int, dict[str, int], int, str | None, int]:
|
|
60
60
|
data_file = os.path.join(db_dir, "data")
|
|
61
|
-
mgr =
|
|
61
|
+
mgr = create_storage(StorageConfig(connection_string=f"sqlite+aiosqlite:///{data_file}"))
|
|
62
62
|
await mgr.initialize()
|
|
63
63
|
try:
|
|
64
64
|
traces_df = await mgr.query_traces("SELECT COUNT(*) AS c FROM session_traces")
|
|
@@ -74,9 +74,11 @@ def register(cli):
|
|
|
74
74
|
system_counts = (
|
|
75
75
|
{
|
|
76
76
|
str(r["system_type"] or "-"): int(r["c"] or 0)
|
|
77
|
-
for _, r in
|
|
77
|
+
for _, r in systems_df.iterrows()
|
|
78
78
|
}
|
|
79
|
-
if systems_df is not None
|
|
79
|
+
if systems_df is not None
|
|
80
|
+
and hasattr(systems_df, "iterrows")
|
|
81
|
+
and not systems_df.empty
|
|
80
82
|
else {}
|
|
81
83
|
)
|
|
82
84
|
except Exception:
|
synth_ai/cli/watch.py
CHANGED
|
@@ -16,6 +16,12 @@ from rich.console import Console, Group
|
|
|
16
16
|
from rich.panel import Panel
|
|
17
17
|
from rich.table import Table
|
|
18
18
|
|
|
19
|
+
from synth_ai.tracing_v3.storage.factory import StorageConfig, create_storage
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _open_db(db_url: str):
|
|
23
|
+
return create_storage(StorageConfig(connection_string=db_url))
|
|
24
|
+
|
|
19
25
|
|
|
20
26
|
class _State:
|
|
21
27
|
def __init__(self):
|
|
@@ -48,9 +54,7 @@ def _format_int(value: Any) -> str:
|
|
|
48
54
|
|
|
49
55
|
|
|
50
56
|
async def _fetch_experiments(db_url: str):
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
db = AsyncSQLTraceManager(db_url)
|
|
57
|
+
db = _open_db(db_url)
|
|
54
58
|
await db.initialize()
|
|
55
59
|
try:
|
|
56
60
|
df = await db.query_traces(
|
|
@@ -114,9 +118,7 @@ def _experiments_table(df, limit: int | None = None) -> Table:
|
|
|
114
118
|
|
|
115
119
|
|
|
116
120
|
async def _experiment_detail(db_url: str, experiment_id: str) -> dict[str, Any]:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
db = AsyncSQLTraceManager(db_url)
|
|
121
|
+
db = _open_db(db_url)
|
|
120
122
|
await db.initialize()
|
|
121
123
|
try:
|
|
122
124
|
exp_df = await db.query_traces(
|
|
@@ -253,9 +255,7 @@ def register(cli):
|
|
|
253
255
|
console = Console()
|
|
254
256
|
|
|
255
257
|
async def _run():
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
db = AsyncSQLTraceManager(db_url)
|
|
258
|
+
db = _open_db(db_url)
|
|
259
259
|
await db.initialize()
|
|
260
260
|
try:
|
|
261
261
|
df = await db.get_model_usage(model_name=model_name)
|
|
@@ -396,9 +396,7 @@ def _parse_hours(args: list[str]) -> float | None:
|
|
|
396
396
|
|
|
397
397
|
|
|
398
398
|
async def _usage_table(db_url: str, model_name: str | None):
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
db = AsyncSQLTraceManager(db_url)
|
|
399
|
+
db = _open_db(db_url)
|
|
402
400
|
await db.initialize()
|
|
403
401
|
try:
|
|
404
402
|
df = await db.get_model_usage(model_name=model_name)
|
|
@@ -418,9 +416,7 @@ async def _usage_table(db_url: str, model_name: str | None):
|
|
|
418
416
|
|
|
419
417
|
|
|
420
418
|
async def _traces_table(db_url: str, limit: int):
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
db = AsyncSQLTraceManager(db_url)
|
|
419
|
+
db = _open_db(db_url)
|
|
424
420
|
await db.initialize()
|
|
425
421
|
try:
|
|
426
422
|
df = await db.query_traces("SELECT * FROM session_summary ORDER BY created_at DESC")
|
|
@@ -453,10 +449,8 @@ async def _recent_table(db_url: str, hours: float, limit: int):
|
|
|
453
449
|
# Inline the recent query to avoid cross-module coupling
|
|
454
450
|
from datetime import timedelta
|
|
455
451
|
|
|
456
|
-
from synth_ai.tracing_v3.turso.manager import AsyncSQLTraceManager
|
|
457
|
-
|
|
458
452
|
start_time = datetime.now() - timedelta(hours=hours)
|
|
459
|
-
db =
|
|
453
|
+
db = _open_db(db_url)
|
|
460
454
|
await db.initialize()
|
|
461
455
|
try:
|
|
462
456
|
query = """
|
synth_ai/demo_registry.py
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import textwrap
|
|
6
|
+
from collections.abc import Callable, Iterable
|
|
6
7
|
from dataclasses import dataclass
|
|
7
8
|
from pathlib import Path
|
|
8
|
-
from typing import Callable, Iterable
|
|
9
9
|
|
|
10
10
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
11
11
|
|
synth_ai/demos/core/cli.py
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import contextlib
|
|
4
5
|
import json
|
|
5
6
|
import os
|
|
6
|
-
import sys
|
|
7
|
-
import time
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from typing import Any, Dict, Callable
|
|
10
7
|
import shutil
|
|
11
8
|
import stat
|
|
9
|
+
import sys
|
|
12
10
|
import textwrap
|
|
11
|
+
import time
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
13
15
|
|
|
14
|
-
from synth_ai.demos.demo_task_apps import core as demo_core
|
|
15
|
-
from synth_ai.demos.demo_task_apps.core import DemoEnv, DEFAULT_TASK_APP_SECRET_NAME
|
|
16
16
|
from synth_ai.demo_registry import (
|
|
17
|
-
CopySpec,
|
|
18
17
|
DemoTemplate,
|
|
19
18
|
get_demo_template,
|
|
20
19
|
list_demo_templates,
|
|
21
20
|
)
|
|
22
|
-
from synth_ai.
|
|
21
|
+
from synth_ai.demos.demo_task_apps import core as demo_core
|
|
22
|
+
from synth_ai.demos.demo_task_apps.core import DEFAULT_TASK_APP_SECRET_NAME, DemoEnv
|
|
23
|
+
from synth_ai.handshake import HandshakeError, run_handshake
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def _key_preview(value: str, label: str) -> str:
|
|
@@ -59,7 +60,6 @@ def cmd_setup(_args: argparse.Namespace) -> int:
|
|
|
59
60
|
try:
|
|
60
61
|
print("\n⏳ Connecting SDK to your browser session…")
|
|
61
62
|
res = run_handshake()
|
|
62
|
-
user = res.get("user") or {}
|
|
63
63
|
org = res.get("org") or {}
|
|
64
64
|
keys = res.get("keys") or {}
|
|
65
65
|
synth_key = str(keys.get("synth") or "").strip()
|
|
@@ -107,8 +107,8 @@ def cmd_setup(_args: argparse.Namespace) -> int:
|
|
|
107
107
|
demo_core.persist_env_file_path(dotenv_path)
|
|
108
108
|
|
|
109
109
|
# 2) Reload env after handshake to pick up values from .env (suppress env prints)
|
|
110
|
-
import io
|
|
111
110
|
import contextlib
|
|
111
|
+
import io
|
|
112
112
|
|
|
113
113
|
_buf = io.StringIO()
|
|
114
114
|
with contextlib.redirect_stdout(_buf):
|
|
@@ -126,9 +126,7 @@ def cmd_setup(_args: argparse.Namespace) -> int:
|
|
|
126
126
|
return
|
|
127
127
|
current = env.task_app_base_url
|
|
128
128
|
needs_lookup = False
|
|
129
|
-
if not current:
|
|
130
|
-
needs_lookup = True
|
|
131
|
-
elif not _is_modal_public_url(current):
|
|
129
|
+
if not current or not _is_modal_public_url(current):
|
|
132
130
|
needs_lookup = True
|
|
133
131
|
if not needs_lookup:
|
|
134
132
|
return
|
|
@@ -173,16 +171,14 @@ def cmd_setup(_args: argparse.Namespace) -> int:
|
|
|
173
171
|
|
|
174
172
|
_maybe_fix_task_url()
|
|
175
173
|
|
|
176
|
-
ok_backend = False
|
|
177
|
-
ok_task = False
|
|
178
174
|
if env.dev_backend_url:
|
|
179
175
|
api = env.dev_backend_url.rstrip("/") + (
|
|
180
176
|
"" if env.dev_backend_url.endswith("/api") else "/api"
|
|
181
177
|
)
|
|
182
|
-
|
|
178
|
+
demo_core.assert_http_ok(api + "/health", method="GET")
|
|
183
179
|
# Intentionally suppress backend health print for concise output
|
|
184
180
|
if env.task_app_base_url:
|
|
185
|
-
|
|
181
|
+
demo_core.assert_http_ok(
|
|
186
182
|
env.task_app_base_url.rstrip("/") + "/health", method="GET"
|
|
187
183
|
) or demo_core.assert_http_ok(env.task_app_base_url.rstrip("/"), method="GET")
|
|
188
184
|
# Intentionally suppress task app health print
|
|
@@ -723,7 +719,6 @@ def _ensure_task_app_ready(env: DemoEnv, synth_key: str, *, label: str) -> DemoE
|
|
|
723
719
|
if openai_key:
|
|
724
720
|
os.environ["OPENAI_API_KEY"] = openai_key
|
|
725
721
|
|
|
726
|
-
rollout_url = task_url.rstrip("/") + "/health/rollout"
|
|
727
722
|
print(f"[{label}] Verifying rollout health:")
|
|
728
723
|
try:
|
|
729
724
|
ek = (env_key or "").strip()
|
|
@@ -738,7 +733,6 @@ def _ensure_task_app_ready(env: DemoEnv, synth_key: str, *, label: str) -> DemoE
|
|
|
738
733
|
print(f"[{label}] GET", h)
|
|
739
734
|
rc, body = _http("GET", h, headers={"X-API-Key": env_key})
|
|
740
735
|
if rc == 200:
|
|
741
|
-
rollout_url = h
|
|
742
736
|
break
|
|
743
737
|
print(f"[{label}] status: {rc}")
|
|
744
738
|
try:
|
|
@@ -750,10 +744,8 @@ def _ensure_task_app_ready(env: DemoEnv, synth_key: str, *, label: str) -> DemoE
|
|
|
750
744
|
print(f"[{label}] body:", preview)
|
|
751
745
|
if rc != 200:
|
|
752
746
|
print(f"[{label}] Warning: rollout health check failed ({rc}). Response: {body}")
|
|
753
|
-
|
|
747
|
+
with contextlib.suppress(Exception):
|
|
754
748
|
print(f"[{label}] Sent header X-API-Key → {_key_preview(env_key, 'X-API-Key')}")
|
|
755
|
-
except Exception:
|
|
756
|
-
pass
|
|
757
749
|
else:
|
|
758
750
|
print(f"[{label}] Task app rollout health check OK.")
|
|
759
751
|
|
|
@@ -883,7 +875,7 @@ def cmd_deploy(args: argparse.Namespace) -> int:
|
|
|
883
875
|
env_key = None
|
|
884
876
|
|
|
885
877
|
if env_key is None:
|
|
886
|
-
from synth_ai.rl.secrets import mint_environment_api_key
|
|
878
|
+
from synth_ai.learning.rl.secrets import mint_environment_api_key
|
|
887
879
|
|
|
888
880
|
env_key = mint_environment_api_key()
|
|
889
881
|
demo_core.persist_env_api_key(env_key)
|
|
@@ -921,14 +913,14 @@ def cmd_deploy(args: argparse.Namespace) -> int:
|
|
|
921
913
|
if choice.startswith("y"):
|
|
922
914
|
try:
|
|
923
915
|
print(f"[deploy] Uploading ENVIRONMENT_API_KEY to {non_api_base} …")
|
|
924
|
-
from synth_ai.rl.env_keys import setup_environment_api_key
|
|
916
|
+
from synth_ai.learning.rl.env_keys import setup_environment_api_key
|
|
925
917
|
|
|
926
918
|
setup_environment_api_key(non_api_base, synth_key, token=env_key)
|
|
927
919
|
print("[deploy] Backend sealed-box upload complete.")
|
|
928
920
|
except Exception as upload_err:
|
|
929
921
|
print(f"[deploy] Failed to upload ENVIRONMENT_API_KEY: {upload_err}")
|
|
930
922
|
print(
|
|
931
|
-
'Hint: run `uvx python -c "from synth_ai.rl.env_keys import setup_environment_api_key as s;'
|
|
923
|
+
'Hint: run `uvx python -c "from synth_ai.learning.rl.env_keys import setup_environment_api_key as s;'
|
|
932
924
|
" s('<backend>', '<synth_api_key>')\"` once the backend is reachable."
|
|
933
925
|
)
|
|
934
926
|
|
|
@@ -1126,14 +1118,14 @@ def _ensure_modal_installed() -> None:
|
|
|
1126
1118
|
if auth_ok:
|
|
1127
1119
|
print(f"✓ Modal authenticated: {auth_msg}")
|
|
1128
1120
|
else:
|
|
1129
|
-
print(
|
|
1121
|
+
print("\n⚠️ Modal authentication required")
|
|
1130
1122
|
print(f" Status: {auth_msg}")
|
|
1131
|
-
print(
|
|
1132
|
-
print(
|
|
1133
|
-
print(
|
|
1134
|
-
print(
|
|
1135
|
-
print(
|
|
1136
|
-
print(
|
|
1123
|
+
print("\n To authenticate Modal, run:")
|
|
1124
|
+
print(" modal setup")
|
|
1125
|
+
print("\n Or set environment variables:")
|
|
1126
|
+
print(" export MODAL_TOKEN_ID=your-token-id")
|
|
1127
|
+
print(" export MODAL_TOKEN_SECRET=your-token-secret")
|
|
1128
|
+
print("\n You can deploy later after authenticating.\n")
|
|
1137
1129
|
|
|
1138
1130
|
|
|
1139
1131
|
def cmd_init(args: argparse.Namespace) -> int:
|
|
@@ -1289,7 +1281,7 @@ def cmd_init(args: argparse.Namespace) -> int:
|
|
|
1289
1281
|
should_write = True
|
|
1290
1282
|
if env_path.exists() and not directory_cleared:
|
|
1291
1283
|
try:
|
|
1292
|
-
response = input(
|
|
1284
|
+
response = input("File .env exists. Overwrite? [y/N]: ").strip().lower()
|
|
1293
1285
|
except (EOFError, KeyboardInterrupt):
|
|
1294
1286
|
print("\nCancelled.")
|
|
1295
1287
|
return 1
|
|
@@ -1353,9 +1345,12 @@ def cmd_init(args: argparse.Namespace) -> int:
|
|
|
1353
1345
|
|
|
1354
1346
|
|
|
1355
1347
|
def _http(
|
|
1356
|
-
method: str, url: str, headers:
|
|
1357
|
-
) -> tuple[int,
|
|
1358
|
-
import
|
|
1348
|
+
method: str, url: str, headers: dict[str, str] | None = None, body: dict[str, Any] | None = None
|
|
1349
|
+
) -> tuple[int, dict[str, Any] | str]:
|
|
1350
|
+
import json as _json
|
|
1351
|
+
import ssl
|
|
1352
|
+
import urllib.error
|
|
1353
|
+
import urllib.request
|
|
1359
1354
|
|
|
1360
1355
|
data = None
|
|
1361
1356
|
if body is not None:
|
|
@@ -1402,7 +1397,7 @@ def cmd_run(args: argparse.Namespace) -> int:
|
|
|
1402
1397
|
|
|
1403
1398
|
env = demo_core.load_env()
|
|
1404
1399
|
cwd_env_path = os.path.join(os.getcwd(), ".env")
|
|
1405
|
-
|
|
1400
|
+
demo_core.load_dotenv_file(cwd_env_path)
|
|
1406
1401
|
|
|
1407
1402
|
synth_key = (env.synth_api_key or "").strip()
|
|
1408
1403
|
if not synth_key:
|
|
@@ -1487,7 +1482,7 @@ def cmd_run(args: argparse.Namespace) -> int:
|
|
|
1487
1482
|
# Fallback: legacy jobs API flow
|
|
1488
1483
|
with open(cfg_path, "rb") as fh:
|
|
1489
1484
|
inline_cfg = tomllib.load(fh)
|
|
1490
|
-
with open(cfg_path
|
|
1485
|
+
with open(cfg_path) as fh2:
|
|
1491
1486
|
toml_text = fh2.read()
|
|
1492
1487
|
if args.batch_size is not None:
|
|
1493
1488
|
inline_cfg.setdefault("training", {})["batch_size"] = int(args.batch_size)
|
|
@@ -1498,13 +1493,11 @@ def cmd_run(args: argparse.Namespace) -> int:
|
|
|
1498
1493
|
# Print backend and key preview before request for clearer diagnostics
|
|
1499
1494
|
try:
|
|
1500
1495
|
sk = (env.synth_api_key or "").strip()
|
|
1501
|
-
sk_len = len(sk)
|
|
1502
|
-
sk_tail = sk[-5:] if sk_len >= 5 else sk
|
|
1503
1496
|
print(f"[run] Backend API: {api}")
|
|
1504
1497
|
print(f"[run] {_key_preview(sk, 'SYNTH_API_KEY')}")
|
|
1505
1498
|
except Exception:
|
|
1506
1499
|
pass
|
|
1507
|
-
data_fragment:
|
|
1500
|
+
data_fragment: dict[str, Any] = {
|
|
1508
1501
|
"model": model_name,
|
|
1509
1502
|
"endpoint_base_url": env.task_app_base_url,
|
|
1510
1503
|
"config": inline_cfg,
|
|
@@ -1529,7 +1522,7 @@ def cmd_run(args: argparse.Namespace) -> int:
|
|
|
1529
1522
|
if ":" in gshape:
|
|
1530
1523
|
t, c = gshape.split(":", 1)
|
|
1531
1524
|
compute = {"gpu_type": t.upper(), "gpu_count": int(c)}
|
|
1532
|
-
body:
|
|
1525
|
+
body: dict[str, Any] = {
|
|
1533
1526
|
"job_type": "rl",
|
|
1534
1527
|
"data": data_fragment,
|
|
1535
1528
|
}
|
|
@@ -1588,7 +1581,7 @@ def cmd_run(args: argparse.Namespace) -> int:
|
|
|
1588
1581
|
pass
|
|
1589
1582
|
try:
|
|
1590
1583
|
sent_keys = detail.get("sent_keys")
|
|
1591
|
-
if isinstance(sent_keys,
|
|
1584
|
+
if isinstance(sent_keys, list | tuple):
|
|
1592
1585
|
previews = []
|
|
1593
1586
|
for idx, val in enumerate(sent_keys):
|
|
1594
1587
|
if isinstance(val, str):
|
|
@@ -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
|
|
|
@@ -35,7 +32,7 @@ def _state_path() -> str:
|
|
|
35
32
|
return os.path.expanduser("~/.synth-ai/demo.json")
|
|
36
33
|
|
|
37
34
|
|
|
38
|
-
def _read_state() ->
|
|
35
|
+
def _read_state() -> dict[str, Any]:
|
|
39
36
|
try:
|
|
40
37
|
path = _state_path()
|
|
41
38
|
if os.path.isfile(path):
|
|
@@ -47,7 +44,7 @@ def _read_state() -> Dict[str, Any]:
|
|
|
47
44
|
return {}
|
|
48
45
|
|
|
49
46
|
|
|
50
|
-
def _write_state(data:
|
|
47
|
+
def _write_state(data: dict[str, Any]) -> None:
|
|
51
48
|
try:
|
|
52
49
|
path = _state_path()
|
|
53
50
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
@@ -57,8 +54,8 @@ def _write_state(data: Dict[str, Any]) -> None:
|
|
|
57
54
|
pass
|
|
58
55
|
|
|
59
56
|
|
|
60
|
-
def load_dotenv_file(path: str) ->
|
|
61
|
-
out:
|
|
57
|
+
def load_dotenv_file(path: str) -> dict[str, str]:
|
|
58
|
+
out: dict[str, str] = {}
|
|
62
59
|
try:
|
|
63
60
|
with open(path) as fh:
|
|
64
61
|
for raw in fh:
|
|
@@ -72,7 +69,7 @@ def load_dotenv_file(path: str) -> Dict[str, str]:
|
|
|
72
69
|
return out
|
|
73
70
|
|
|
74
71
|
|
|
75
|
-
def _persist_dotenv_values(path: str, values:
|
|
72
|
+
def _persist_dotenv_values(path: str, values: dict[str, str]) -> None:
|
|
76
73
|
"""Ensure ``values`` are present in ``path`` (.env style)."""
|
|
77
74
|
|
|
78
75
|
try:
|
|
@@ -82,7 +79,7 @@ def _persist_dotenv_values(path: str, values: Dict[str, str]) -> None:
|
|
|
82
79
|
existing_lines = fh.read().splitlines()
|
|
83
80
|
else:
|
|
84
81
|
os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
|
|
85
|
-
mapping:
|
|
82
|
+
mapping: dict[str, str] = {}
|
|
86
83
|
order: list[str] = []
|
|
87
84
|
for line in existing_lines:
|
|
88
85
|
if not line or line.startswith("#") or "=" not in line:
|
|
@@ -110,7 +107,7 @@ def _persist_dotenv_values(path: str, values: Dict[str, str]) -> None:
|
|
|
110
107
|
pass
|
|
111
108
|
|
|
112
109
|
|
|
113
|
-
def persist_dotenv_values(values:
|
|
110
|
+
def persist_dotenv_values(values: dict[str, str], *, cwd: str | None = None) -> str:
|
|
114
111
|
path = os.path.join(cwd or os.getcwd(), ".env")
|
|
115
112
|
_persist_dotenv_values(path, values)
|
|
116
113
|
return path
|
|
@@ -148,14 +145,15 @@ def load_env_file_path() -> str | None:
|
|
|
148
145
|
return data.get("ENV_FILE_PATH")
|
|
149
146
|
|
|
150
147
|
|
|
151
|
-
def modal_auth_status() ->
|
|
148
|
+
def modal_auth_status() -> tuple[bool, str]:
|
|
152
149
|
"""Return (ok, message) describing Modal CLI credential status."""
|
|
153
150
|
|
|
154
151
|
env_token_id = (os.environ.get("MODAL_TOKEN_ID") or "").strip()
|
|
155
152
|
env_token_secret = (os.environ.get("MODAL_TOKEN_SECRET") or "").strip()
|
|
156
153
|
|
|
157
154
|
try:
|
|
158
|
-
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
|
|
159
157
|
except Exception as exc: # pragma: no cover - modal optional in some envs
|
|
160
158
|
return False, f"Modal client unavailable ({exc})"
|
|
161
159
|
|
|
@@ -210,7 +208,7 @@ def load_env() -> DemoEnv:
|
|
|
210
208
|
"""
|
|
211
209
|
env = DemoEnv()
|
|
212
210
|
|
|
213
|
-
os_env:
|
|
211
|
+
os_env: dict[str, str] = dict(os.environ)
|
|
214
212
|
|
|
215
213
|
# CWD .env
|
|
216
214
|
cwd_env_path = os.path.join(os.getcwd(), ".env")
|
|
@@ -245,15 +243,12 @@ def load_env() -> DemoEnv:
|
|
|
245
243
|
or pkg_env.get("DEV_BACKEND_URL")
|
|
246
244
|
or ""
|
|
247
245
|
).strip()
|
|
248
|
-
use_dev = False
|
|
249
246
|
if backend_override:
|
|
250
247
|
dev_url = backend_override
|
|
251
|
-
use_dev = True
|
|
252
248
|
elif dev_env:
|
|
253
249
|
lower = dev_env.lower()
|
|
254
250
|
if "localhost" in lower or "127.0.0.1" in lower or lower.endswith(":8000"):
|
|
255
251
|
dev_url = dev_env
|
|
256
|
-
use_dev = True
|
|
257
252
|
else:
|
|
258
253
|
dev_url = prod_default
|
|
259
254
|
else:
|
|
@@ -426,16 +421,13 @@ def run_job(
|
|
|
426
421
|
env: DemoEnv,
|
|
427
422
|
config_toml_path: str,
|
|
428
423
|
*,
|
|
429
|
-
batch_size:
|
|
430
|
-
group_size:
|
|
431
|
-
model:
|
|
424
|
+
batch_size: int | None = None,
|
|
425
|
+
group_size: int | None = None,
|
|
426
|
+
model: str | None = None,
|
|
432
427
|
) -> None:
|
|
433
428
|
"""Create and stream a short RL job using the backend API (placeholder: prints cURL to execute)."""
|
|
434
429
|
backend = env.dev_backend_url.rstrip("/")
|
|
435
|
-
if backend.endswith("/api")
|
|
436
|
-
api_base = backend
|
|
437
|
-
else:
|
|
438
|
-
api_base = backend + "/api"
|
|
430
|
+
api_base = backend if backend.endswith("/api") else backend + "/api"
|
|
439
431
|
print("\nTo create an RL job, run:")
|
|
440
432
|
print(
|
|
441
433
|
'curl -s -X POST "' + api_base + '/rl/jobs" '
|
|
@@ -9,16 +9,15 @@ Prefer using `uvx synth-ai serve grpo-crafter` for local development and testing
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import argparse
|
|
12
|
+
import importlib.util
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
|
|
14
15
|
from fastapi.exceptions import RequestValidationError
|
|
15
16
|
from fastapi.responses import JSONResponse
|
|
16
17
|
from starlette.requests import Request
|
|
17
|
-
|
|
18
18
|
from synth_ai.task.apps import ModalDeploymentConfig, registry
|
|
19
19
|
from synth_ai.task.auth import is_api_key_header_authorized, normalize_environment_api_key
|
|
20
20
|
from synth_ai.task.server import TaskAppConfig, create_task_app, run_task_app
|
|
21
|
-
import importlib.util
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
def _load_build_config():
|
|
@@ -40,7 +39,7 @@ def _load_build_config():
|
|
|
40
39
|
raise ImportError(f"Could not load task app module at {module_path}")
|
|
41
40
|
module = importlib.util.module_from_spec(spec)
|
|
42
41
|
spec.loader.exec_module(module)
|
|
43
|
-
return
|
|
42
|
+
return module.build_config
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
build_config = _load_build_config()
|
|
@@ -130,7 +129,7 @@ def fastapi_app():
|
|
|
130
129
|
try:
|
|
131
130
|
hdr = request.headers
|
|
132
131
|
snapshot = {
|
|
133
|
-
"path": str(
|
|
132
|
+
"path": str(request.url.path),
|
|
134
133
|
"have_x_api_key": bool(hdr.get("x-api-key")),
|
|
135
134
|
"have_x_api_keys": bool(hdr.get("x-api-keys")),
|
|
136
135
|
"have_authorization": bool(hdr.get("authorization")),
|
|
@@ -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,4 +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
|
-
)
|
|
57
|
+
) from e
|