synth-ai 0.2.14__py3-none-any.whl → 0.4.1__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.
- synth_ai/__init__.py +19 -40
- synth_ai/__main__.py +30 -3
- synth_ai/cli/__init__.py +105 -70
- synth_ai/cli/__main__.py +42 -0
- synth_ai/cli/_internal/__init__.py +5 -0
- synth_ai/cli/_internal/modal_wrapper.py +31 -0
- synth_ai/cli/_internal/storage.py +20 -0
- synth_ai/cli/_internal/typer_patch.py +47 -0
- synth_ai/cli/_internal/validate_task_app.py +29 -0
- synth_ai/cli/agents/__init__.py +17 -0
- synth_ai/cli/agents/claude.py +77 -0
- synth_ai/cli/agents/codex.py +265 -0
- synth_ai/cli/agents/opencode.py +253 -0
- synth_ai/cli/commands/__init__.py +18 -0
- synth_ai/cli/commands/artifacts/__init__.py +13 -0
- synth_ai/cli/commands/artifacts/client.py +119 -0
- synth_ai/cli/commands/artifacts/config.py +57 -0
- synth_ai/cli/commands/artifacts/core.py +24 -0
- synth_ai/cli/commands/artifacts/download.py +188 -0
- synth_ai/cli/commands/artifacts/export.py +186 -0
- synth_ai/cli/commands/artifacts/list.py +156 -0
- synth_ai/cli/commands/artifacts/parsing.py +250 -0
- synth_ai/cli/commands/artifacts/show.py +336 -0
- synth_ai/cli/commands/baseline/__init__.py +12 -0
- synth_ai/cli/commands/baseline/core.py +636 -0
- synth_ai/cli/commands/baseline/list.py +94 -0
- synth_ai/cli/commands/demo/__init__.py +3 -0
- synth_ai/cli/commands/demo/core.py +153 -0
- synth_ai/cli/commands/eval/__init__.py +19 -0
- synth_ai/cli/commands/eval/core.py +1113 -0
- synth_ai/cli/commands/eval/errors.py +81 -0
- synth_ai/cli/commands/eval/validation.py +133 -0
- synth_ai/cli/commands/filter/__init__.py +12 -0
- synth_ai/cli/commands/filter/core.py +424 -0
- synth_ai/cli/commands/filter/errors.py +55 -0
- synth_ai/cli/commands/filter/validation.py +77 -0
- synth_ai/cli/commands/help/__init__.py +185 -0
- synth_ai/cli/commands/help/core.py +72 -0
- synth_ai/cli/commands/scan/__init__.py +19 -0
- synth_ai/cli/commands/scan/cloudflare_scanner.py +403 -0
- synth_ai/cli/commands/scan/core.py +344 -0
- synth_ai/cli/commands/scan/health_checker.py +242 -0
- synth_ai/cli/commands/scan/local_scanner.py +278 -0
- synth_ai/cli/commands/scan/models.py +83 -0
- synth_ai/cli/commands/smoke/__init__.py +7 -0
- synth_ai/cli/commands/smoke/core.py +1438 -0
- synth_ai/cli/commands/status/__init__.py +66 -0
- synth_ai/cli/commands/status/client.py +192 -0
- synth_ai/cli/commands/status/config.py +92 -0
- synth_ai/cli/commands/status/errors.py +20 -0
- synth_ai/cli/commands/status/formatters.py +164 -0
- synth_ai/cli/commands/status/subcommands/__init__.py +9 -0
- synth_ai/cli/commands/status/subcommands/files.py +79 -0
- synth_ai/cli/commands/status/subcommands/jobs.py +334 -0
- synth_ai/cli/commands/status/subcommands/models.py +79 -0
- synth_ai/cli/commands/status/subcommands/pricing.py +23 -0
- synth_ai/cli/commands/status/subcommands/runs.py +81 -0
- synth_ai/cli/commands/status/subcommands/session.py +182 -0
- synth_ai/cli/commands/status/subcommands/summary.py +47 -0
- synth_ai/cli/commands/status/subcommands/usage.py +203 -0
- synth_ai/cli/commands/status/utils.py +114 -0
- synth_ai/cli/commands/train/__init__.py +53 -0
- synth_ai/cli/commands/train/core.py +22 -0
- synth_ai/cli/commands/train/errors.py +117 -0
- synth_ai/cli/commands/train/judge_schemas.py +201 -0
- synth_ai/cli/commands/train/judge_validation.py +305 -0
- synth_ai/cli/commands/train/prompt_learning_validation.py +633 -0
- synth_ai/cli/commands/train/validation.py +392 -0
- synth_ai/cli/demo_apps/__init__.py +10 -0
- synth_ai/cli/demo_apps/core/__init__.py +28 -0
- synth_ai/cli/demo_apps/core/cli.py +1735 -0
- synth_ai/cli/demo_apps/crafter/crafter_fft_4b.toml +55 -0
- synth_ai/cli/demo_apps/crafter/grpo_crafter_task_app.py +186 -0
- synth_ai/cli/demo_apps/crafter/rl_from_base_qwen4b.toml +74 -0
- synth_ai/cli/demo_apps/demo_registry.py +176 -0
- synth_ai/cli/demo_apps/demo_task_apps/core.py +440 -0
- synth_ai/cli/demo_apps/demo_task_apps/crafter/__init__.py +1 -0
- synth_ai/cli/demo_apps/demo_task_apps/crafter/grpo_crafter_task_app.py +185 -0
- synth_ai/cli/demo_apps/demo_task_apps/math/modal_task_app.py +742 -0
- synth_ai/cli/demo_apps/demo_task_apps/math/task_app_entry.py +39 -0
- synth_ai/cli/demo_apps/math/__init__.py +1 -0
- synth_ai/cli/demo_apps/math/_common.py +16 -0
- synth_ai/cli/demo_apps/math/app.py +38 -0
- synth_ai/cli/demo_apps/math/config.toml +76 -0
- synth_ai/cli/demo_apps/math/deploy_modal.py +54 -0
- synth_ai/cli/demo_apps/math/modal_task_app.py +702 -0
- synth_ai/cli/demo_apps/math/task_app_entry.py +53 -0
- synth_ai/cli/demo_apps/mipro/main.py +271 -0
- synth_ai/cli/demo_apps/mipro/task_app.py +933 -0
- synth_ai/cli/demo_apps/mipro/train_cfg.toml +92 -0
- synth_ai/cli/demos/__init__.py +12 -0
- synth_ai/cli/demos/demo.py +32 -0
- synth_ai/cli/demos/rl_demo.py +254 -0
- synth_ai/cli/deploy.py +216 -0
- synth_ai/cli/infra/__init__.py +14 -0
- synth_ai/cli/infra/balance.py +216 -0
- synth_ai/cli/infra/mcp.py +35 -0
- synth_ai/cli/infra/modal_app.py +36 -0
- synth_ai/cli/infra/setup.py +69 -0
- synth_ai/cli/infra/status.py +16 -0
- synth_ai/cli/infra/turso.py +77 -0
- synth_ai/cli/lib/__init__.py +10 -0
- synth_ai/cli/lib/agents.py +76 -0
- synth_ai/cli/lib/apps/modal_app.py +101 -0
- synth_ai/cli/lib/apps/task_app.py +643 -0
- synth_ai/cli/lib/bin.py +39 -0
- synth_ai/cli/lib/env.py +375 -0
- synth_ai/cli/lib/errors.py +85 -0
- synth_ai/cli/lib/modal.py +315 -0
- synth_ai/cli/lib/plotting.py +126 -0
- synth_ai/cli/lib/prompt_args.py +39 -0
- synth_ai/cli/lib/prompts.py +284 -0
- synth_ai/cli/lib/sqld.py +122 -0
- synth_ai/cli/lib/task_app_discovery.py +884 -0
- synth_ai/cli/lib/task_app_env.py +295 -0
- synth_ai/cli/lib/train_cfgs.py +300 -0
- synth_ai/cli/lib/tunnel_records.py +207 -0
- synth_ai/cli/local/__init__.py +14 -0
- synth_ai/cli/local/experiment_queue/__init__.py +72 -0
- synth_ai/cli/local/experiment_queue/api_schemas.py +221 -0
- synth_ai/cli/local/experiment_queue/celery_app.py +208 -0
- synth_ai/cli/local/experiment_queue/config.py +128 -0
- synth_ai/cli/local/experiment_queue/config_utils.py +272 -0
- synth_ai/cli/local/experiment_queue/database.py +175 -0
- synth_ai/cli/local/experiment_queue/dispatcher.py +119 -0
- synth_ai/cli/local/experiment_queue/models.py +231 -0
- synth_ai/cli/local/experiment_queue/progress_info.py +160 -0
- synth_ai/cli/local/experiment_queue/results.py +373 -0
- synth_ai/cli/local/experiment_queue/schemas.py +131 -0
- synth_ai/cli/local/experiment_queue/service.py +344 -0
- synth_ai/cli/local/experiment_queue/status.py +372 -0
- synth_ai/cli/local/experiment_queue/status_tracker.py +360 -0
- synth_ai/cli/local/experiment_queue/tasks.py +1984 -0
- synth_ai/cli/local/experiment_queue/trace_storage.py +65 -0
- synth_ai/cli/local/experiment_queue/validation.py +157 -0
- synth_ai/cli/local/session/__init__.py +92 -0
- synth_ai/cli/local/session/client.py +383 -0
- synth_ai/cli/local/session/constants.py +63 -0
- synth_ai/cli/local/session/exceptions.py +105 -0
- synth_ai/cli/local/session/manager.py +139 -0
- synth_ai/cli/local/session/models.py +89 -0
- synth_ai/cli/local/session/query.py +110 -0
- synth_ai/cli/root.py +30 -6
- synth_ai/cli/task_apps/__init__.py +26 -0
- synth_ai/cli/task_apps/commands.py +3153 -0
- synth_ai/cli/task_apps/deploy.py +7 -0
- synth_ai/cli/task_apps/list.py +26 -0
- synth_ai/cli/task_apps/main.py +36 -0
- synth_ai/cli/task_apps/modal_serve.py +11 -0
- synth_ai/cli/task_apps/serve.py +11 -0
- synth_ai/cli/training/__init__.py +8 -0
- synth_ai/cli/training/train.py +5 -0
- synth_ai/cli/training/train_cfg.py +34 -0
- synth_ai/cli/training/watch.py +506 -0
- synth_ai/cli/turso.py +34 -55
- synth_ai/cli/usage.py +159 -0
- synth_ai/cli/utils/__init__.py +8 -0
- synth_ai/cli/utils/experiments.py +235 -0
- synth_ai/cli/utils/queue.py +504 -0
- synth_ai/cli/utils/recent.py +133 -0
- synth_ai/cli/utils/traces.py +164 -0
- synth_ai/contracts/__init__.py +67 -0
- synth_ai/core/__init__.py +100 -0
- synth_ai/core/_utils/__init__.py +54 -0
- synth_ai/core/_utils/base_url.py +10 -0
- synth_ai/core/_utils/http.py +10 -0
- synth_ai/core/_utils/prompts.py +14 -0
- synth_ai/core/_utils/task_app_state.py +12 -0
- synth_ai/core/_utils/user_config.py +10 -0
- synth_ai/core/apps/common.py +116 -0
- synth_ai/core/auth.py +95 -0
- synth_ai/core/cfgs.py +240 -0
- synth_ai/core/config/__init__.py +16 -0
- synth_ai/core/config/base.py +168 -0
- synth_ai/core/config/resolver.py +89 -0
- synth_ai/core/env.py +220 -0
- synth_ai/core/errors.py +126 -0
- synth_ai/core/http.py +230 -0
- synth_ai/core/integrations/__init__.py +11 -0
- synth_ai/core/integrations/cloudflare.py +1710 -0
- synth_ai/core/integrations/mcp/__init__.py +6 -0
- synth_ai/core/integrations/mcp/__main__.py +8 -0
- synth_ai/core/integrations/mcp/claude.py +36 -0
- synth_ai/core/integrations/mcp/main.py +254 -0
- synth_ai/core/integrations/mcp/setup.py +100 -0
- synth_ai/core/integrations/modal.py +277 -0
- synth_ai/core/json.py +72 -0
- synth_ai/core/log_filter.py +99 -0
- synth_ai/core/logging.py +82 -0
- synth_ai/core/paths.py +107 -0
- synth_ai/core/pricing.py +109 -0
- synth_ai/core/process.py +233 -0
- synth_ai/core/ssl.py +25 -0
- synth_ai/core/storage/__init__.py +71 -0
- synth_ai/core/task_app_state.py +318 -0
- synth_ai/core/telemetry.py +282 -0
- synth_ai/core/tracing_v3/__init__.py +99 -0
- synth_ai/core/tracing_v3/abstractions.py +302 -0
- synth_ai/core/tracing_v3/config.py +229 -0
- synth_ai/core/tracing_v3/constants.py +21 -0
- synth_ai/core/tracing_v3/db_config.py +182 -0
- synth_ai/core/tracing_v3/decorators.py +401 -0
- synth_ai/core/tracing_v3/llm_call_record_helpers.py +437 -0
- synth_ai/core/tracing_v3/migration_helper.py +119 -0
- synth_ai/core/tracing_v3/session_tracer.py +542 -0
- synth_ai/core/tracing_v3/storage/base.py +211 -0
- synth_ai/core/tracing_v3/storage/config.py +109 -0
- synth_ai/core/tracing_v3/storage/factory.py +39 -0
- synth_ai/core/tracing_v3/trace_utils.py +326 -0
- synth_ai/core/tracing_v3/turso/daemon.py +278 -0
- synth_ai/core/tracing_v3/turso/models.py +470 -0
- synth_ai/core/tracing_v3/turso/native_manager.py +1385 -0
- synth_ai/core/tracing_v3/utils.py +108 -0
- synth_ai/core/urls.py +18 -0
- synth_ai/core/user_config.py +137 -0
- synth_ai/core/uvicorn.py +222 -0
- synth_ai/data/__init__.py +110 -0
- synth_ai/data/enums.py +141 -0
- synth_ai/data/rewards.py +152 -0
- synth_ai/data/specs.py +36 -0
- synth_ai/data/traces.py +35 -0
- synth_ai/products/__init__.py +6 -0
- synth_ai/products/graph_evolve/__init__.py +46 -0
- synth_ai/products/graph_evolve/client.py +226 -0
- synth_ai/products/graph_evolve/config.py +591 -0
- synth_ai/products/graph_evolve/converters/__init__.py +42 -0
- synth_ai/products/graph_evolve/converters/openai_sft.py +484 -0
- synth_ai/products/graph_evolve/examples/hotpotqa/config.toml +109 -0
- synth_ai/products/graph_evolve/run.py +222 -0
- synth_ai/sdk/__init__.py +119 -0
- synth_ai/sdk/api/__init__.py +1 -0
- synth_ai/sdk/api/models/supported.py +514 -0
- synth_ai/sdk/api/research_agent/__init__.py +86 -0
- synth_ai/sdk/api/research_agent/cli.py +428 -0
- synth_ai/sdk/api/research_agent/config.py +357 -0
- synth_ai/sdk/api/research_agent/job.py +717 -0
- synth_ai/sdk/api/train/__init__.py +85 -0
- synth_ai/sdk/api/train/builders.py +895 -0
- synth_ai/sdk/api/train/cli.py +2188 -0
- synth_ai/sdk/api/train/config_finder.py +267 -0
- synth_ai/sdk/api/train/configs/__init__.py +65 -0
- synth_ai/sdk/api/train/configs/prompt_learning.py +1706 -0
- synth_ai/sdk/api/train/configs/rl.py +188 -0
- synth_ai/sdk/api/train/configs/sft.py +99 -0
- synth_ai/sdk/api/train/configs/shared.py +81 -0
- synth_ai/sdk/api/train/context_learning.py +312 -0
- synth_ai/sdk/api/train/env_resolver.py +418 -0
- synth_ai/sdk/api/train/graph_validators.py +216 -0
- synth_ai/sdk/api/train/graphgen.py +984 -0
- synth_ai/sdk/api/train/graphgen_models.py +823 -0
- synth_ai/sdk/api/train/graphgen_validators.py +109 -0
- synth_ai/sdk/api/train/pollers.py +124 -0
- synth_ai/sdk/api/train/progress/__init__.py +97 -0
- synth_ai/sdk/api/train/progress/dataclasses.py +569 -0
- synth_ai/sdk/api/train/progress/events.py +326 -0
- synth_ai/sdk/api/train/progress/results.py +428 -0
- synth_ai/sdk/api/train/progress/tracker.py +641 -0
- synth_ai/sdk/api/train/prompt_learning.py +470 -0
- synth_ai/sdk/api/train/rl.py +442 -0
- synth_ai/sdk/api/train/sft.py +396 -0
- synth_ai/sdk/api/train/summary.py +522 -0
- synth_ai/sdk/api/train/supported_algos.py +147 -0
- synth_ai/sdk/api/train/task_app.py +331 -0
- synth_ai/sdk/api/train/utils.py +279 -0
- synth_ai/sdk/api/train/validators.py +2424 -0
- synth_ai/sdk/baseline/__init__.py +25 -0
- synth_ai/sdk/baseline/config.py +209 -0
- synth_ai/sdk/baseline/discovery.py +216 -0
- synth_ai/sdk/baseline/execution.py +154 -0
- synth_ai/sdk/graphs/__init__.py +15 -0
- synth_ai/sdk/graphs/completions.py +570 -0
- synth_ai/sdk/inference/__init__.py +6 -0
- synth_ai/sdk/inference/client.py +128 -0
- synth_ai/sdk/jobs/__init__.py +16 -0
- synth_ai/sdk/jobs/client.py +371 -0
- synth_ai/sdk/judging/__init__.py +15 -0
- synth_ai/sdk/judging/base.py +24 -0
- synth_ai/sdk/judging/client.py +191 -0
- synth_ai/sdk/judging/schemas.py +222 -0
- synth_ai/sdk/learning/__init__.py +69 -0
- synth_ai/sdk/learning/client.py +240 -0
- synth_ai/sdk/learning/ft_client.py +7 -0
- synth_ai/sdk/learning/health.py +49 -0
- synth_ai/sdk/learning/jobs.py +202 -0
- synth_ai/sdk/learning/prompt_extraction.py +334 -0
- synth_ai/sdk/learning/prompt_learning_client.py +455 -0
- synth_ai/sdk/learning/prompt_learning_types.py +185 -0
- synth_ai/sdk/learning/rl/client.py +268 -0
- synth_ai/sdk/learning/rl/contracts.py +27 -0
- synth_ai/sdk/learning/rl/env_keys.py +166 -0
- synth_ai/sdk/learning/rl/secrets.py +13 -0
- synth_ai/sdk/learning/sft/client.py +95 -0
- synth_ai/sdk/learning/sft/config.py +270 -0
- synth_ai/sdk/learning/sft/data.py +698 -0
- synth_ai/sdk/learning/validators.py +52 -0
- synth_ai/sdk/research_agent/__init__.py +34 -0
- synth_ai/sdk/research_agent/container_builder.py +328 -0
- synth_ai/sdk/research_agent/container_spec.py +198 -0
- synth_ai/sdk/research_agent/defaults.py +34 -0
- synth_ai/sdk/research_agent/results_collector.py +69 -0
- synth_ai/sdk/specs/__init__.py +46 -0
- synth_ai/sdk/specs/dataclasses.py +149 -0
- synth_ai/sdk/specs/loader.py +144 -0
- synth_ai/sdk/specs/serializer.py +199 -0
- synth_ai/sdk/specs/validation.py +250 -0
- synth_ai/sdk/streaming/__init__.py +35 -0
- synth_ai/sdk/streaming/config.py +94 -0
- synth_ai/sdk/streaming/handlers.py +1997 -0
- synth_ai/sdk/streaming/streamer.py +704 -0
- synth_ai/sdk/streaming/types.py +112 -0
- synth_ai/sdk/task/__init__.py +151 -0
- synth_ai/sdk/task/apps/__init__.py +133 -0
- synth_ai/sdk/task/config.py +261 -0
- synth_ai/sdk/task/contracts.py +298 -0
- synth_ai/sdk/task/datasets.py +108 -0
- synth_ai/sdk/task/in_process.py +1190 -0
- synth_ai/sdk/task/in_process_runner.py +309 -0
- synth_ai/sdk/task/inference_api.py +299 -0
- synth_ai/sdk/task/proxy.py +287 -0
- synth_ai/sdk/task/rubrics/__init__.py +55 -0
- synth_ai/sdk/task/rubrics/loaders.py +156 -0
- synth_ai/sdk/task/rubrics.py +219 -0
- synth_ai/sdk/task/server.py +580 -0
- synth_ai/sdk/task/trace_correlation_helpers.py +506 -0
- synth_ai/sdk/task/tracing_utils.py +95 -0
- synth_ai/sdk/task/validators.py +456 -0
- synth_ai/sdk/tracing/__init__.py +39 -0
- synth_ai/sdk/training/__init__.py +102 -0
- synth_ai/sdk/usage/__init__.py +37 -0
- synth_ai/sdk/usage/client.py +171 -0
- synth_ai/sdk/usage/models.py +261 -0
- synth_ai/utils/__init__.py +213 -0
- synth_ai-0.4.1.dist-info/METADATA +195 -0
- synth_ai-0.4.1.dist-info/RECORD +379 -0
- synth_ai-0.4.1.dist-info/top_level.txt +1 -0
- examples/__init__.py +0 -16
- examples/analyze_semantic_words.sh +0 -17
- examples/crafter_debug_render.py +0 -186
- examples/dev/qwen3_32b_qlora_4xh100.toml +0 -40
- examples/multi_step/configs/README_verilog_rl.md +0 -77
- examples/multi_step/configs/VERILOG_REWARDS.md +0 -90
- examples/multi_step/configs/VERILOG_RL_CHECKLIST.md +0 -183
- examples/multi_step/configs/crafter_eval_synth_qwen4b.toml +0 -35
- examples/multi_step/configs/crafter_eval_text_only_groq_qwen32b.toml +0 -36
- examples/multi_step/configs/crafter_rl_outcome.toml +0 -74
- examples/multi_step/configs/crafter_rl_stepwise_hosted_judge.toml +0 -187
- examples/multi_step/configs/crafter_rl_stepwise_shaped.toml +0 -83
- examples/multi_step/configs/crafter_rl_stepwise_simple.toml +0 -78
- examples/multi_step/configs/crafter_synth_backend.md +0 -40
- examples/multi_step/configs/verilog_eval_groq_qwen32b.toml +0 -31
- examples/multi_step/configs/verilog_eval_synth_qwen8b.toml +0 -33
- examples/multi_step/configs/verilog_rl_lora.toml +0 -190
- examples/multi_step/crafter_rl_lora.md +0 -70
- examples/multi_step/judges/crafter_backend_judge.py +0 -220
- examples/multi_step/judges/verilog_backend_judge.py +0 -234
- examples/multi_step/readme.md +0 -48
- examples/multi_step/sse_metrics_streaming_notes.md +0 -357
- examples/multi_step/task_app_config_notes.md +0 -494
- examples/multi_step/verilog_rl_lora.md +0 -218
- examples/qwen_coder/README.md +0 -102
- examples/qwen_coder/_shared.py +0 -113
- examples/qwen_coder/configs/coder_lora_30b.toml +0 -61
- examples/qwen_coder/configs/coder_lora_4b.toml +0 -57
- examples/qwen_coder/configs/coder_lora_small.toml +0 -58
- examples/qwen_coder/generate_dataset.py +0 -98
- examples/qwen_coder/infer_ft_smoke.py +0 -65
- examples/qwen_coder/infer_prod_proxy.py +0 -73
- examples/qwen_coder/infer_via_synth.py +0 -87
- examples/qwen_coder/scripts/infer_coder.sh +0 -19
- examples/qwen_coder/scripts/train_coder_30b.sh +0 -22
- examples/qwen_coder/sft_full_17b.py +0 -103
- examples/qwen_coder/sft_lora_30b.py +0 -110
- examples/qwen_coder/subset_jsonl.py +0 -39
- examples/qwen_coder/todos.md +0 -38
- examples/qwen_coder/validate_jsonl.py +0 -60
- examples/rl/README.md +0 -169
- examples/rl/download_dataset.py +0 -80
- examples/run_crafter_demo.sh +0 -10
- examples/sft/README.md +0 -139
- examples/sft/configs/crafter_fft_qwen0p6b.toml +0 -44
- examples/sft/configs/crafter_lora_qwen0p6b.toml +0 -45
- examples/sft/evaluate.py +0 -119
- examples/sft/export_dataset.py +0 -117
- examples/sft/generate_traces.py +0 -164
- examples/swe/__init__.py +0 -12
- examples/swe/task_app/README.md +0 -105
- examples/swe/task_app/__init__.py +0 -2
- examples/swe/task_app/grpo_swe_mini.py +0 -601
- examples/swe/task_app/grpo_swe_mini_task_app.py +0 -136
- examples/swe/task_app/hosted/README.md +0 -173
- examples/swe/task_app/hosted/__init__.py +0 -5
- examples/swe/task_app/hosted/branching.py +0 -143
- examples/swe/task_app/hosted/environment_routes.py +0 -1289
- examples/swe/task_app/hosted/envs/__init__.py +0 -1
- examples/swe/task_app/hosted/envs/crafter/__init__.py +0 -6
- examples/swe/task_app/hosted/envs/crafter/app.py +0 -1
- examples/swe/task_app/hosted/envs/crafter/environment.py +0 -522
- examples/swe/task_app/hosted/envs/crafter/policy.py +0 -478
- examples/swe/task_app/hosted/envs/crafter/react_agent.py +0 -108
- examples/swe/task_app/hosted/envs/crafter/shared.py +0 -305
- examples/swe/task_app/hosted/envs/crafter/tools.py +0 -47
- examples/swe/task_app/hosted/envs/mini_swe/__init__.py +0 -8
- examples/swe/task_app/hosted/envs/mini_swe/environment.py +0 -1164
- examples/swe/task_app/hosted/envs/mini_swe/policy.py +0 -355
- examples/swe/task_app/hosted/envs/mini_swe/shared.py +0 -83
- examples/swe/task_app/hosted/envs/mini_swe/tools.py +0 -96
- examples/swe/task_app/hosted/hosted_app.py +0 -204
- examples/swe/task_app/hosted/inference/__init__.py +0 -5
- examples/swe/task_app/hosted/inference/openai_client.py +0 -618
- examples/swe/task_app/hosted/main.py +0 -100
- examples/swe/task_app/hosted/policy_routes.py +0 -1079
- examples/swe/task_app/hosted/registry.py +0 -195
- examples/swe/task_app/hosted/rollout.py +0 -1911
- examples/swe/task_app/hosted/storage/__init__.py +0 -5
- examples/swe/task_app/hosted/storage/volume.py +0 -211
- examples/swe/task_app/hosted/test_agents.py +0 -161
- examples/swe/task_app/hosted/test_service.py +0 -136
- examples/swe/task_app/hosted/utils.py +0 -62
- examples/task_apps/IMAGE_ONLY_EVAL_QUICKSTART.md +0 -258
- examples/task_apps/TESTING.md +0 -275
- examples/task_apps/crafter/CREATE_SFT_DATASET.md +0 -273
- examples/task_apps/crafter/EVAL_IMAGE_ONLY_RESULTS.md +0 -152
- examples/task_apps/crafter/FILTER_COMMAND_STATUS.md +0 -174
- examples/task_apps/crafter/FILTER_COMMAND_SUCCESS.md +0 -268
- examples/task_apps/crafter/QUERY_EXAMPLES.md +0 -203
- examples/task_apps/crafter/README_IMAGE_ONLY_EVAL.md +0 -316
- examples/task_apps/crafter/__init__.py +0 -0
- examples/task_apps/crafter/eval_image_only_gpt4o.toml +0 -28
- examples/task_apps/crafter/eval_text_only_groq_llama.toml +0 -36
- examples/task_apps/crafter/filter_sft_dataset.toml +0 -16
- examples/task_apps/crafter/task_app/README.md +0 -42
- examples/task_apps/crafter/task_app/__init__.py +0 -5
- examples/task_apps/crafter/task_app/grpo_crafter.py +0 -973
- examples/task_apps/crafter/task_app/grpo_crafter_task_app.py +0 -146
- examples/task_apps/crafter/task_app/synth_envs_hosted/README.md +0 -173
- examples/task_apps/crafter/task_app/synth_envs_hosted/__init__.py +0 -5
- examples/task_apps/crafter/task_app/synth_envs_hosted/branching.py +0 -143
- examples/task_apps/crafter/task_app/synth_envs_hosted/environment_routes.py +0 -1226
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/__init__.py +0 -1
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/__init__.py +0 -6
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/app.py +0 -1
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/environment.py +0 -532
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/policy.py +0 -547
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/react_agent.py +0 -123
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/shared.py +0 -305
- examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/tools.py +0 -47
- examples/task_apps/crafter/task_app/synth_envs_hosted/hosted_app.py +0 -204
- examples/task_apps/crafter/task_app/synth_envs_hosted/inference/__init__.py +0 -5
- examples/task_apps/crafter/task_app/synth_envs_hosted/inference/openai_client.py +0 -704
- examples/task_apps/crafter/task_app/synth_envs_hosted/main.py +0 -100
- examples/task_apps/crafter/task_app/synth_envs_hosted/policy_routes.py +0 -1152
- examples/task_apps/crafter/task_app/synth_envs_hosted/registry.py +0 -195
- examples/task_apps/crafter/task_app/synth_envs_hosted/rollout.py +0 -2160
- examples/task_apps/crafter/task_app/synth_envs_hosted/storage/__init__.py +0 -5
- examples/task_apps/crafter/task_app/synth_envs_hosted/storage/volume.py +0 -211
- examples/task_apps/crafter/task_app/synth_envs_hosted/test_agents.py +0 -161
- examples/task_apps/crafter/task_app/synth_envs_hosted/test_service.py +0 -136
- examples/task_apps/crafter/task_app/synth_envs_hosted/utils.py +0 -218
- examples/task_apps/dev/pokemon_emerald/__init__.py +0 -2
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/README.md +0 -811
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/__init__.py +0 -120
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/action.py +0 -160
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/memory.py +0 -155
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/perception.py +0 -69
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/planning.py +0 -96
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/simple.py +0 -1502
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/system_prompt.py +0 -4
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/grab_map.py +0 -68
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/manual.py +0 -216
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/__init__.py +0 -35
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emerald_utils.py +0 -631
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emulator.py +0 -1544
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/enums.py +0 -1428
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/memory_reader.py +0 -4848
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/types.py +0 -41
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/utils.py +0 -298
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pyproject.toml +0 -95
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/run.py +0 -204
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/__init__.py +0 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/app.py +0 -2152
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/client.py +0 -429
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/frame_server.py +0 -155
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/README.md +0 -78
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/__init__.py +0 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/run_tests.py +0 -122
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_direct.py +0 -76
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_prompts.py +0 -413
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_battle_state_formatting.py +0 -204
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection.py +0 -133
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection_comprehensive.py +0 -229
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_direct_agent_emulator.py +0 -300
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_fps_adjustment_pytest.py +0 -205
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_direct.py +0 -200
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_transition.py +0 -284
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_map_ground_truth_comparison.py +0 -468
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_memory_map.py +0 -575
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_server_map_validation.py +0 -311
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_torchic_state.py +0 -259
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/__init__.py +0 -0
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/anticheat.py +0 -372
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/checkpoint.py +0 -296
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/error_handler.py +0 -275
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/get_local_ip.py +0 -22
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/helpers.py +0 -44
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/llm_logger.py +0 -514
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_formatter.py +0 -415
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher.py +0 -1763
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher_singleton.py +0 -33
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_trimmer.py +0 -106
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_visualizer.py +0 -334
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/ocr_dialogue.py +0 -1020
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/recording.py +0 -188
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/state_formatter.py +0 -1481
- examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/vlm.py +0 -862
- examples/task_apps/dev/pokemon_emerald/modal_app.py +0 -114
- examples/task_apps/dev/pokemon_emerald/task_app/README.md +0 -81
- examples/task_apps/dev/pokemon_emerald/task_app/__init__.py +0 -6
- examples/task_apps/dev/pokemon_emerald/task_app/pokemon_emerald.py +0 -685
- examples/task_apps/enron/__init__.py +0 -1
- examples/task_apps/enron/eval_groq_qwen32.toml +0 -16
- examples/task_apps/enron/filter_sft.toml +0 -5
- examples/task_apps/enron/task_app/README.md +0 -14
- examples/task_apps/enron/task_app/__init__.py +0 -1
- examples/task_apps/enron/task_app/grpo_enron.py +0 -906
- examples/task_apps/enron/task_app/grpo_enron_task_app.py +0 -146
- examples/task_apps/enron/tests/__init__.py +0 -4
- examples/task_apps/enron/tests/conftest.py +0 -115
- examples/task_apps/enron/tests/integration/__init__.py +0 -4
- examples/task_apps/enron/tests/integration/test_enron_eval.py +0 -179
- examples/task_apps/enron/tests/integration/test_enron_rollout.py +0 -135
- examples/task_apps/enron/tests/unit/__init__.py +0 -4
- examples/task_apps/enron/tests/unit/test_enron_environment.py +0 -126
- examples/task_apps/math/README.md +0 -22
- examples/task_apps/math/__init__.py +0 -0
- examples/task_apps/math/math_single_step.py +0 -1000
- examples/task_apps/math/math_task_app.py +0 -115
- examples/task_apps/pokemon_battle/__init__.py +0 -2
- examples/task_apps/pokemon_battle/modal_app.py +0 -104
- examples/task_apps/pokemon_battle/task_app/README.md +0 -68
- examples/task_apps/pokemon_battle/task_app/__init__.py +0 -6
- examples/task_apps/pokemon_battle/task_app/pokemon_showdown.py +0 -932
- examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_COMPLETE.md +0 -283
- examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_STATUS.md +0 -155
- examples/task_apps/pokemon_red/README.md +0 -357
- examples/task_apps/pokemon_red/README_IMAGE_ONLY_EVAL.md +0 -415
- examples/task_apps/pokemon_red/__init__.py +0 -3
- examples/task_apps/pokemon_red/eval_image_only_gpt4o.toml +0 -29
- examples/task_apps/pokemon_red/eval_pokemon_red_policy.py +0 -225
- examples/task_apps/pokemon_red/pallet_town_rl_config.toml +0 -75
- examples/task_apps/pokemon_red/task_app.py +0 -799
- examples/task_apps/pokemon_red/test_pallet_town_rewards.py +0 -193
- examples/task_apps/sokoban/README.md +0 -307
- examples/task_apps/sokoban/__init__.py +0 -3
- examples/task_apps/sokoban/eval_groq_qwen32.toml +0 -16
- examples/task_apps/sokoban/eval_openai_gpt5.toml +0 -16
- examples/task_apps/sokoban/filter_sft.toml +0 -5
- examples/task_apps/sokoban/task_app.py +0 -1058
- examples/task_apps/sokoban/tests/__init__.py +0 -4
- examples/task_apps/sokoban/tests/conftest.py +0 -113
- examples/task_apps/sokoban/tests/integration/__init__.py +0 -4
- examples/task_apps/sokoban/tests/integration/test_sokoban_eval.py +0 -57
- examples/task_apps/sokoban/tests/integration/test_sokoban_rollout.py +0 -198
- examples/task_apps/sokoban/tests/unit/__init__.py +0 -4
- examples/task_apps/sokoban/tests/unit/test_sokoban_environment.py +0 -114
- examples/task_apps/verilog/__init__.py +0 -1
- examples/task_apps/verilog/eval_groq_qwen32b.toml +0 -24
- examples/task_apps/verilog/filter_sft.toml +0 -5
- examples/task_apps/verilog/task_app/README.md +0 -12
- examples/task_apps/verilog/task_app/__init__.py +0 -1
- examples/task_apps/verilog/task_app/grpo_verilog.py +0 -1166
- examples/task_apps/verilog/task_app/grpo_verilog_task_app.py +0 -145
- examples/task_apps/verilog/tests/__init__.py +0 -4
- examples/task_apps/verilog/tests/conftest.py +0 -115
- examples/task_apps/verilog/tests/integration/__init__.py +0 -4
- examples/task_apps/verilog/tests/integration/test_verilog_eval.py +0 -181
- examples/task_apps/verilog/tests/integration/test_verilog_rollout.py +0 -55
- examples/task_apps/verilog/tests/unit/__init__.py +0 -4
- examples/task_apps/verilog/tests/unit/test_verilog_scoring.py +0 -118
- examples/vlm/PROPOSAL.md +0 -53
- examples/vlm/README.md +0 -68
- examples/vlm/configs/crafter_vlm_gpt4o.toml +0 -44
- examples/vlm/crafter_image_only_agent.py +0 -207
- examples/vlm/crafter_openai_vlm_agent.py +0 -277
- examples/vlm/filter_image_rows.py +0 -63
- examples/vlm/run_crafter_vlm_benchmark.py +0 -316
- examples/warming_up_to_rl/analyze_trace_db.py +0 -422
- examples/warming_up_to_rl/configs/crafter_fft.toml +0 -48
- examples/warming_up_to_rl/configs/crafter_fft_4b.toml +0 -54
- examples/warming_up_to_rl/configs/eval_fft_qwen4b.toml +0 -20
- examples/warming_up_to_rl/configs/eval_groq_qwen32b.toml +0 -13
- examples/warming_up_to_rl/configs/eval_modal_qwen4b.toml +0 -23
- examples/warming_up_to_rl/configs/eval_stepwise_complex.toml +0 -35
- examples/warming_up_to_rl/configs/eval_stepwise_consistent.toml +0 -26
- examples/warming_up_to_rl/configs/eval_stepwise_per_achievement.toml +0 -36
- examples/warming_up_to_rl/configs/eval_stepwise_simple.toml +0 -32
- examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +0 -83
- examples/warming_up_to_rl/configs/rl_from_ft.toml +0 -56
- examples/warming_up_to_rl/export_trace_sft.py +0 -723
- examples/warming_up_to_rl/groq_test.py +0 -97
- examples/warming_up_to_rl/manage_secrets.py +0 -131
- examples/warming_up_to_rl/old/event_rewards.md +0 -234
- examples/warming_up_to_rl/old/notes.md +0 -73
- examples/warming_up_to_rl/readme.md +0 -179
- examples/warming_up_to_rl/run_eval.py +0 -736
- examples/warming_up_to_rl/run_fft_and_save.py +0 -380
- examples/warming_up_to_rl/run_local_rollout.py +0 -239
- examples/warming_up_to_rl/run_local_rollout_modal.py +0 -248
- examples/warming_up_to_rl/run_local_rollout_parallel.py +0 -405
- examples/warming_up_to_rl/run_local_rollout_traced.py +0 -477
- examples/warming_up_to_rl/run_rl_and_save.py +0 -124
- examples/warming_up_to_rl/run_rollout_remote.py +0 -156
- examples/workflows/__init__.py +0 -0
- examples/workflows/math_rl/__init__.py +0 -0
- examples/workflows/math_rl/configs/eval_base_qwen.toml +0 -15
- examples/workflows/math_rl/configs/eval_rl_qwen.toml +0 -11
- examples/workflows/math_rl/configs/rl_from_base_qwen.toml +0 -35
- examples/workflows/math_rl/configs/rl_from_base_qwen17.toml +0 -74
- examples/workflows/math_rl/configs/rl_from_ft_qwen.toml +0 -35
- examples/workflows/math_rl/download_dataset.py +0 -80
- examples/workflows/math_rl/run_eval.py +0 -436
- examples/workflows/math_rl/run_rl_and_save.py +0 -111
- synth_ai/api/models/supported.py +0 -377
- synth_ai/api/train/__init__.py +0 -5
- synth_ai/api/train/builders.py +0 -351
- synth_ai/api/train/cli.py +0 -635
- synth_ai/api/train/config_finder.py +0 -228
- synth_ai/api/train/configs/__init__.py +0 -44
- synth_ai/api/train/configs/rl.py +0 -134
- synth_ai/api/train/configs/sft.py +0 -95
- synth_ai/api/train/configs/shared.py +0 -24
- synth_ai/api/train/env_resolver.py +0 -349
- synth_ai/api/train/pollers.py +0 -75
- synth_ai/api/train/supported_algos.py +0 -147
- synth_ai/api/train/task_app.py +0 -195
- synth_ai/api/train/utils.py +0 -225
- synth_ai/cli/_modal_wrapper.py +0 -29
- synth_ai/cli/_storage.py +0 -20
- synth_ai/cli/_typer_patch.py +0 -49
- synth_ai/cli/_validate_task_app.py +0 -11
- synth_ai/cli/balance.py +0 -216
- synth_ai/cli/calc.py +0 -84
- synth_ai/cli/demo.py +0 -165
- synth_ai/cli/legacy_root_backup.py +0 -468
- synth_ai/cli/man.py +0 -106
- synth_ai/cli/recent.py +0 -132
- synth_ai/cli/rl_demo.py +0 -254
- synth_ai/cli/status.py +0 -134
- synth_ai/cli/task_apps.py +0 -4523
- synth_ai/cli/traces.py +0 -164
- synth_ai/cli/tui.py +0 -57
- synth_ai/cli/watch.py +0 -506
- synth_ai/compound/cais.py +0 -0
- synth_ai/config/base_url.py +0 -107
- synth_ai/core/experiment.py +0 -13
- synth_ai/core/system.py +0 -15
- synth_ai/demo_registry.py +0 -295
- synth_ai/demos/core/__init__.py +0 -1
- synth_ai/demos/core/cli.py +0 -1718
- synth_ai/demos/demo_task_apps/core.py +0 -440
- synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +0 -184
- synth_ai/demos/demo_task_apps/math/deploy_task_app.sh +0 -22
- synth_ai/demos/demo_task_apps/math/modal_task_app.py +0 -739
- synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -37
- synth_ai/environments/__init__.py +0 -31
- synth_ai/environments/environment/__init__.py +0 -1
- synth_ai/environments/environment/artifacts/__init__.py +0 -1
- synth_ai/environments/environment/artifacts/base.py +0 -52
- synth_ai/environments/environment/core.py +0 -67
- synth_ai/environments/environment/db/__init__.py +0 -1
- synth_ai/environments/environment/db/sqlite.py +0 -45
- synth_ai/environments/environment/registry.py +0 -233
- synth_ai/environments/environment/resources/sqlite.py +0 -45
- synth_ai/environments/environment/results.py +0 -1
- synth_ai/environments/environment/rewards/__init__.py +0 -1
- synth_ai/environments/environment/rewards/core.py +0 -29
- synth_ai/environments/environment/shared_engine.py +0 -26
- synth_ai/environments/environment/tools/__init__.py +0 -200
- synth_ai/environments/examples/__init__.py +0 -1
- synth_ai/environments/examples/bandit/__init__.py +0 -33
- synth_ai/environments/examples/bandit/engine.py +0 -302
- synth_ai/environments/examples/bandit/environment.py +0 -194
- synth_ai/environments/examples/bandit/taskset.py +0 -200
- synth_ai/environments/examples/crafter_classic/__init__.py +0 -8
- synth_ai/environments/examples/crafter_classic/agent_demos/analyze_semantic_words_markdown.py +0 -250
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_comprehensive_evaluation.py +0 -59
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_browser.py +0 -152
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_config.toml +0 -24
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_framework.py +0 -1194
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/crafter_synth_config.toml +0 -56
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_config_modal.toml +0 -32
- 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_modal_ft/kick_off_ft_modal.py +0 -384
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_action_results.py +0 -53
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_agent_actions.py +0 -178
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_latest_run.py +0 -222
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_lm_traces.py +0 -183
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_no_rewards.py +0 -210
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_trace_issue.py +0 -206
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_db_schema.py +0 -49
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_latest_results.py +0 -64
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/debug_agent_responses.py +0 -88
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/quick_trace_check.py +0 -77
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/compare_experiments.py +0 -324
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/kick_off_ft_oai.py +0 -362
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/multi_model_config.toml +0 -49
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_enhanced_hooks.py +0 -332
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_events.py +0 -97
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_results.py +0 -217
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_hook_storage.py +0 -87
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_seeds.py +0 -88
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/compare_seed_performance.py +0 -195
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/custom_eval_pipelines.py +0 -400
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/plot_hook_frequency.py +0 -195
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/seed_analysis_summary.py +0 -56
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/run_rollouts_for_models_and_compare_v3.py +0 -858
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_quick_evaluation.py +0 -52
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_react_agent.py +0 -874
- synth_ai/environments/examples/crafter_classic/agent_demos/crafter_trace_evaluation.py +0 -1412
- synth_ai/environments/examples/crafter_classic/agent_demos/example_v3_usage.py +0 -216
- synth_ai/environments/examples/crafter_classic/agent_demos/old/compare_traces.py +0 -296
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_comprehensive_evaluation.py +0 -58
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_env_serialization.py +0 -464
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_evaluation_browser.py +0 -152
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_quick_evaluation.py +0 -51
- synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_trace_evaluation.py +0 -1412
- synth_ai/environments/examples/crafter_classic/agent_demos/old/debug_player_loss.py +0 -112
- synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_service.py +0 -203
- synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_slowness.py +0 -305
- synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_by_difficulty.py +0 -126
- synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_example.py +0 -94
- synth_ai/environments/examples/crafter_classic/agent_demos/old/explore_saved_states.py +0 -142
- synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft.py +0 -26
- synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft_OLD.py +0 -984
- synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_gemini.py +0 -724
- synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_modal.py +0 -386
- synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_metadata.py +0 -205
- synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_gemini.py +0 -150
- synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_modal.py +0 -283
- synth_ai/environments/examples/crafter_classic/agent_demos/old/prepare_vertex_ft.py +0 -280
- synth_ai/environments/examples/crafter_classic/agent_demos/old/profile_env_slowness.py +0 -456
- synth_ai/environments/examples/crafter_classic/agent_demos/old/replicate_issue.py +0 -166
- synth_ai/environments/examples/crafter_classic/agent_demos/old/run_and_eval.py +0 -102
- synth_ai/environments/examples/crafter_classic/agent_demos/old/run_comparison.py +0 -128
- synth_ai/environments/examples/crafter_classic/agent_demos/old/run_qwen_rollouts.py +0 -655
- synth_ai/environments/examples/crafter_classic/agent_demos/old/trace_eval_OLD.py +0 -202
- synth_ai/environments/examples/crafter_classic/agent_demos/old/validate_openai_format.py +0 -166
- synth_ai/environments/examples/crafter_classic/config_logging.py +0 -111
- synth_ai/environments/examples/crafter_classic/debug_translation.py +0 -0
- synth_ai/environments/examples/crafter_classic/engine.py +0 -579
- synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +0 -64
- synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +0 -6
- synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +0 -75
- synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +0 -267
- synth_ai/environments/examples/crafter_classic/environment.py +0 -495
- synth_ai/environments/examples/crafter_classic/taskset.py +0 -233
- synth_ai/environments/examples/crafter_classic/trace_hooks_v3.py +0 -228
- synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +0 -299
- synth_ai/environments/examples/crafter_custom/__init__.py +0 -4
- synth_ai/environments/examples/crafter_custom/agent_demos/__init__.py +0 -1
- synth_ai/environments/examples/crafter_custom/agent_demos/trace_eval.py +0 -202
- synth_ai/environments/examples/crafter_custom/crafter/__init__.py +0 -7
- synth_ai/environments/examples/crafter_custom/crafter/config.py +0 -182
- synth_ai/environments/examples/crafter_custom/crafter/constants.py +0 -8
- synth_ai/environments/examples/crafter_custom/crafter/engine.py +0 -269
- synth_ai/environments/examples/crafter_custom/crafter/env.py +0 -262
- synth_ai/environments/examples/crafter_custom/crafter/objects.py +0 -417
- synth_ai/environments/examples/crafter_custom/crafter/recorder.py +0 -187
- synth_ai/environments/examples/crafter_custom/crafter/worldgen.py +0 -118
- synth_ai/environments/examples/crafter_custom/dataset_builder.py +0 -373
- synth_ai/environments/examples/crafter_custom/environment.py +0 -312
- synth_ai/environments/examples/crafter_custom/old/analyze_diamond_issue.py +0 -159
- synth_ai/environments/examples/crafter_custom/old/analyze_diamond_spawning.py +0 -158
- synth_ai/environments/examples/crafter_custom/old/compare_worlds.py +0 -71
- synth_ai/environments/examples/crafter_custom/old/dataset_stats.py +0 -105
- synth_ai/environments/examples/crafter_custom/old/diamond_spawning_summary.py +0 -119
- synth_ai/environments/examples/crafter_custom/old/example_dataset_usage.py +0 -52
- synth_ai/environments/examples/crafter_custom/run_dataset.py +0 -305
- synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +0 -156
- synth_ai/environments/examples/enron/art_helpers/local_email_db.py +0 -281
- synth_ai/environments/examples/enron/art_helpers/types_enron.py +0 -25
- synth_ai/environments/examples/enron/engine.py +0 -300
- synth_ai/environments/examples/enron/environment.py +0 -234
- synth_ai/environments/examples/enron/taskset.py +0 -112
- synth_ai/environments/examples/enron/units/keyword_stats.py +0 -112
- synth_ai/environments/examples/minigrid/__init__.py +0 -48
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_evaluation_framework.py +0 -1188
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_quick_evaluation.py +0 -48
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_react_agent.py +0 -562
- synth_ai/environments/examples/minigrid/agent_demos/minigrid_trace_evaluation.py +0 -221
- synth_ai/environments/examples/minigrid/engine.py +0 -589
- synth_ai/environments/examples/minigrid/environment.py +0 -274
- synth_ai/environments/examples/minigrid/environment_mapping.py +0 -242
- synth_ai/environments/examples/minigrid/puzzle_loader.py +0 -417
- synth_ai/environments/examples/minigrid/taskset.py +0 -583
- synth_ai/environments/examples/nethack/__init__.py +0 -7
- synth_ai/environments/examples/nethack/achievements.py +0 -337
- synth_ai/environments/examples/nethack/agent_demos/nethack_evaluation_framework.py +0 -981
- synth_ai/environments/examples/nethack/agent_demos/nethack_quick_evaluation.py +0 -74
- synth_ai/environments/examples/nethack/agent_demos/nethack_react_agent.py +0 -831
- synth_ai/environments/examples/nethack/engine.py +0 -739
- synth_ai/environments/examples/nethack/environment.py +0 -256
- synth_ai/environments/examples/nethack/helpers/__init__.py +0 -41
- synth_ai/environments/examples/nethack/helpers/action_mapping.py +0 -301
- synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +0 -402
- synth_ai/environments/examples/nethack/helpers/observation_utils.py +0 -433
- synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +0 -200
- synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +0 -269
- synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +0 -308
- synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +0 -431
- synth_ai/environments/examples/nethack/taskset.py +0 -323
- synth_ai/environments/examples/red/__init__.py +0 -7
- synth_ai/environments/examples/red/agent_demos/__init__.py +0 -1
- synth_ai/environments/examples/red/config_logging.py +0 -110
- synth_ai/environments/examples/red/engine.py +0 -721
- synth_ai/environments/examples/red/engine_helpers/__init__.py +0 -1
- synth_ai/environments/examples/red/engine_helpers/memory_map.py +0 -35
- synth_ai/environments/examples/red/engine_helpers/reward_components.py +0 -276
- synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +0 -142
- synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +0 -57
- synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +0 -284
- synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +0 -150
- synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +0 -138
- synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +0 -57
- synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +0 -331
- synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +0 -121
- synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_progression.py +0 -477
- synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +0 -559
- synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +0 -313
- synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +0 -148
- synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +0 -247
- synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +0 -368
- synth_ai/environments/examples/red/engine_helpers/state_extraction.py +0 -172
- synth_ai/environments/examples/red/environment.py +0 -298
- synth_ai/environments/examples/red/taskset.py +0 -79
- synth_ai/environments/examples/red/units/__init__.py +0 -1
- synth_ai/environments/examples/sokoban/__init__.py +0 -1
- synth_ai/environments/examples/sokoban/agent_demos/sokoban_full_eval.py +0 -899
- synth_ai/environments/examples/sokoban/engine.py +0 -678
- synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +0 -1
- synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +0 -657
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +0 -18
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +0 -3
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +0 -131
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +0 -370
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +0 -332
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +0 -306
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +0 -67
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +0 -115
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +0 -123
- synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +0 -394
- synth_ai/environments/examples/sokoban/environment.py +0 -229
- synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +0 -440
- synth_ai/environments/examples/sokoban/puzzle_loader.py +0 -312
- synth_ai/environments/examples/sokoban/taskset.py +0 -544
- synth_ai/environments/examples/tictactoe/__init__.py +0 -1
- synth_ai/environments/examples/tictactoe/engine.py +0 -368
- synth_ai/environments/examples/tictactoe/environment.py +0 -240
- synth_ai/environments/examples/tictactoe/taskset.py +0 -215
- synth_ai/environments/examples/verilog/__init__.py +0 -10
- synth_ai/environments/examples/verilog/engine.py +0 -421
- synth_ai/environments/examples/verilog/environment.py +0 -350
- synth_ai/environments/examples/verilog/taskset.py +0 -420
- synth_ai/environments/examples/wordle/__init__.py +0 -29
- synth_ai/environments/examples/wordle/engine.py +0 -398
- synth_ai/environments/examples/wordle/environment.py +0 -159
- synth_ai/environments/examples/wordle/helpers/generate_instances_wordfreq.py +0 -75
- synth_ai/environments/examples/wordle/taskset.py +0 -230
- synth_ai/environments/reproducibility/core.py +0 -42
- synth_ai/environments/reproducibility/helpers.py +0 -0
- synth_ai/environments/reproducibility/tree.py +0 -363
- synth_ai/environments/service/app.py +0 -97
- synth_ai/environments/service/core_routes.py +0 -1021
- synth_ai/environments/service/external_registry.py +0 -56
- synth_ai/environments/service/registry.py +0 -9
- synth_ai/environments/stateful/__init__.py +0 -1
- synth_ai/environments/stateful/core.py +0 -163
- synth_ai/environments/stateful/engine.py +0 -21
- synth_ai/environments/stateful/state.py +0 -7
- synth_ai/environments/tasks/api.py +0 -19
- synth_ai/environments/tasks/core.py +0 -81
- synth_ai/environments/tasks/filters.py +0 -40
- synth_ai/environments/tasks/utils.py +0 -90
- synth_ai/environments/v0_observability/history.py +0 -3
- synth_ai/environments/v0_observability/log.py +0 -2
- synth_ai/evals/__init__.py +0 -15
- synth_ai/evals/base.py +0 -13
- synth_ai/evals/client.py +0 -82
- synth_ai/handshake.py +0 -109
- synth_ai/http.py +0 -26
- synth_ai/http_client.py +0 -136
- synth_ai/inference/__init__.py +0 -5
- synth_ai/inference/client.py +0 -34
- synth_ai/jobs/client.py +0 -295
- synth_ai/judge_schemas.py +0 -127
- synth_ai/learning/__init__.py +0 -59
- synth_ai/learning/client.py +0 -241
- synth_ai/learning/ft_client.py +0 -7
- synth_ai/learning/health.py +0 -49
- synth_ai/learning/jobs.py +0 -201
- synth_ai/learning/rl/client.py +0 -267
- synth_ai/learning/rl/contracts.py +0 -27
- synth_ai/learning/rl/env_keys.py +0 -166
- synth_ai/learning/rl/secrets.py +0 -13
- synth_ai/learning/sft/client.py +0 -68
- synth_ai/learning/sft/config.py +0 -270
- synth_ai/learning/sft/data.py +0 -295
- synth_ai/learning/validators.py +0 -49
- synth_ai/lm/__init__.py +0 -25
- synth_ai/task/__init__.py +0 -121
- synth_ai/task/apps/__init__.py +0 -129
- synth_ai/task/config.py +0 -257
- synth_ai/task/contracts.py +0 -236
- synth_ai/task/datasets.py +0 -108
- synth_ai/task/proxy.py +0 -251
- synth_ai/task/rubrics/__init__.py +0 -56
- synth_ai/task/rubrics/loaders.py +0 -152
- synth_ai/task/server.py +0 -432
- synth_ai/task/trace_correlation_helpers.py +0 -315
- synth_ai/task/tracing_utils.py +0 -84
- synth_ai/task/validators.py +0 -418
- synth_ai/tracing_v3/__init__.py +0 -97
- synth_ai/tracing_v3/abstractions.py +0 -302
- synth_ai/tracing_v3/config.py +0 -84
- synth_ai/tracing_v3/db_config.py +0 -194
- synth_ai/tracing_v3/decorators.py +0 -398
- synth_ai/tracing_v3/llm_call_record_helpers.py +0 -391
- synth_ai/tracing_v3/migration_helper.py +0 -120
- synth_ai/tracing_v3/session_tracer.py +0 -540
- synth_ai/tracing_v3/storage/base.py +0 -210
- synth_ai/tracing_v3/storage/config.py +0 -75
- synth_ai/tracing_v3/storage/factory.py +0 -39
- synth_ai/tracing_v3/trace_utils.py +0 -317
- synth_ai/tracing_v3/turso/daemon.py +0 -151
- synth_ai/tracing_v3/turso/models.py +0 -469
- synth_ai/tracing_v3/turso/native_manager.py +0 -1209
- synth_ai/tracing_v3/utils.py +0 -108
- synth_ai/tui/__init__.py +0 -5
- synth_ai/tui/__main__.py +0 -13
- synth_ai/tui/cli/__init__.py +0 -1
- synth_ai/tui/cli/query_experiments.py +0 -164
- synth_ai/tui/cli/query_experiments_v3.py +0 -164
- synth_ai/tui/dashboard.py +0 -906
- synth_ai/v0/api/__init__.py +0 -8
- synth_ai/v0/api/models/__init__.py +0 -8
- synth_ai/v0/api/models/supported.py +0 -8
- synth_ai/v0/config/__init__.py +0 -15
- synth_ai/v0/config/base_url.py +0 -12
- synth_ai/v0/lm/__init__.py +0 -51
- synth_ai/v0/lm/caching/__init__.py +0 -0
- synth_ai/v0/lm/caching/constants.py +0 -6
- synth_ai/v0/lm/caching/dbs.py +0 -0
- synth_ai/v0/lm/caching/ephemeral.py +0 -100
- synth_ai/v0/lm/caching/handler.py +0 -137
- synth_ai/v0/lm/caching/initialize.py +0 -11
- synth_ai/v0/lm/caching/persistent.py +0 -114
- synth_ai/v0/lm/config.py +0 -115
- synth_ai/v0/lm/constants.py +0 -32
- synth_ai/v0/lm/core/__init__.py +0 -8
- synth_ai/v0/lm/core/all.py +0 -73
- synth_ai/v0/lm/core/exceptions.py +0 -5
- synth_ai/v0/lm/core/main.py +0 -331
- synth_ai/v0/lm/core/main_v3.py +0 -594
- synth_ai/v0/lm/core/synth_models.py +0 -35
- synth_ai/v0/lm/core/vendor_clients.py +0 -190
- synth_ai/v0/lm/cost/__init__.py +0 -0
- synth_ai/v0/lm/cost/monitor.py +0 -1
- synth_ai/v0/lm/cost/statefulness.py +0 -1
- synth_ai/v0/lm/injection.py +0 -80
- synth_ai/v0/lm/overrides.py +0 -206
- synth_ai/v0/lm/provider_support/__init__.py +0 -8
- synth_ai/v0/lm/provider_support/anthropic.py +0 -972
- synth_ai/v0/lm/provider_support/openai.py +0 -1139
- synth_ai/v0/lm/provider_support/suppress_logging.py +0 -31
- synth_ai/v0/lm/structured_outputs/__init__.py +0 -0
- synth_ai/v0/lm/structured_outputs/handler.py +0 -440
- synth_ai/v0/lm/structured_outputs/inject.py +0 -297
- synth_ai/v0/lm/structured_outputs/rehabilitate.py +0 -185
- synth_ai/v0/lm/tools/__init__.py +0 -3
- synth_ai/v0/lm/tools/base.py +0 -172
- synth_ai/v0/lm/unified_interface.py +0 -202
- synth_ai/v0/lm/vendors/__init__.py +0 -0
- synth_ai/v0/lm/vendors/base.py +0 -81
- synth_ai/v0/lm/vendors/core/__init__.py +0 -0
- synth_ai/v0/lm/vendors/core/anthropic_api.py +0 -387
- synth_ai/v0/lm/vendors/core/gemini_api.py +0 -292
- synth_ai/v0/lm/vendors/core/mistral_api.py +0 -322
- synth_ai/v0/lm/vendors/core/openai_api.py +0 -227
- synth_ai/v0/lm/vendors/core/synth_dev_api.py +0 -0
- synth_ai/v0/lm/vendors/local/__init__.py +0 -0
- synth_ai/v0/lm/vendors/local/ollama.py +0 -0
- synth_ai/v0/lm/vendors/openai_standard.py +0 -782
- synth_ai/v0/lm/vendors/openai_standard_responses.py +0 -259
- synth_ai/v0/lm/vendors/retries.py +0 -22
- synth_ai/v0/lm/vendors/supported/__init__.py +0 -0
- synth_ai/v0/lm/vendors/supported/custom_endpoint.py +0 -415
- synth_ai/v0/lm/vendors/supported/deepseek.py +0 -69
- synth_ai/v0/lm/vendors/supported/grok.py +0 -75
- synth_ai/v0/lm/vendors/supported/groq.py +0 -16
- synth_ai/v0/lm/vendors/supported/ollama.py +0 -15
- synth_ai/v0/lm/vendors/supported/openrouter.py +0 -74
- synth_ai/v0/lm/vendors/supported/together.py +0 -11
- synth_ai/v0/lm/vendors/synth_client.py +0 -835
- synth_ai/v0/lm/warmup.py +0 -186
- synth_ai/v0/tracing/__init__.py +0 -0
- synth_ai/v0/tracing/abstractions.py +0 -224
- synth_ai/v0/tracing/base_client.py +0 -91
- synth_ai/v0/tracing/client_manager.py +0 -131
- synth_ai/v0/tracing/config.py +0 -142
- synth_ai/v0/tracing/context.py +0 -146
- synth_ai/v0/tracing/decorators.py +0 -682
- synth_ai/v0/tracing/events/__init__.py +0 -0
- synth_ai/v0/tracing/events/manage.py +0 -147
- synth_ai/v0/tracing/events/scope.py +0 -86
- synth_ai/v0/tracing/events/store.py +0 -228
- synth_ai/v0/tracing/immediate_client.py +0 -151
- synth_ai/v0/tracing/local.py +0 -18
- synth_ai/v0/tracing/log_client_base.py +0 -73
- synth_ai/v0/tracing/retry_queue.py +0 -186
- synth_ai/v0/tracing/trackers.py +0 -515
- synth_ai/v0/tracing/upload.py +0 -409
- synth_ai/v0/tracing/utils.py +0 -9
- synth_ai/v0/tracing_v1/__init__.py +0 -16
- synth_ai/v0/tracing_v1/abstractions.py +0 -224
- synth_ai/v0/tracing_v1/base_client.py +0 -91
- synth_ai/v0/tracing_v1/client_manager.py +0 -131
- synth_ai/v0/tracing_v1/config.py +0 -142
- synth_ai/v0/tracing_v1/context.py +0 -146
- synth_ai/v0/tracing_v1/decorators.py +0 -703
- synth_ai/v0/tracing_v1/events/__init__.py +0 -0
- synth_ai/v0/tracing_v1/events/manage.py +0 -147
- synth_ai/v0/tracing_v1/events/scope.py +0 -86
- synth_ai/v0/tracing_v1/events/store.py +0 -228
- synth_ai/v0/tracing_v1/immediate_client.py +0 -151
- synth_ai/v0/tracing_v1/local.py +0 -18
- synth_ai/v0/tracing_v1/log_client_base.py +0 -73
- synth_ai/v0/tracing_v1/retry_queue.py +0 -186
- synth_ai/v0/tracing_v1/trackers.py +0 -515
- synth_ai/v0/tracing_v1/upload.py +0 -527
- synth_ai/v0/tracing_v1/utils.py +0 -9
- synth_ai/v0/tracing_v3/__init__.py +0 -10
- synth_ai/v0/tracing_v3/abstractions.py +0 -3
- synth_ai/v0/tracing_v3/decorators.py +0 -3
- synth_ai/v0/tracing_v3/llm_call_record_helpers.py +0 -3
- synth_ai/v0/tracing_v3/session_tracer.py +0 -3
- synth_ai-0.2.14.dist-info/METADATA +0 -139
- synth_ai-0.2.14.dist-info/RECORD +0 -762
- synth_ai-0.2.14.dist-info/top_level.txt +0 -2
- /synth_ai/{demos/demo_task_apps → cli/demo_apps}/crafter/__init__.py +0 -0
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/__init__.py +0 -0
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/crafter/configs/crafter_fft_4b.toml +0 -0
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/crafter/configs/rl_from_base_qwen4b.toml +0 -0
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/__init__.py +0 -0
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/_common.py +0 -0
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/app.py +0 -0
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/config.toml +0 -0
- /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/deploy_modal.py +0 -0
- {examples/task_apps → synth_ai/core/apps}/__init__.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/examples/basic_usage.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/hooks.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/lm_call_record_abstractions.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/replica_sync.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/serialization.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/storage/__init__.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/storage/exceptions.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/storage/types.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/storage/utils.py +0 -0
- /synth_ai/{tracing_v3 → core/tracing_v3}/turso/__init__.py +0 -0
- /synth_ai/{evals → sdk/judging}/types.py +0 -0
- /synth_ai/{learning → sdk/learning}/algorithms.py +0 -0
- /synth_ai/{learning → sdk/learning}/config.py +0 -0
- /synth_ai/{learning → sdk/learning}/constants.py +0 -0
- /synth_ai/{learning → sdk/learning}/core.py +0 -0
- /synth_ai/{learning → sdk/learning}/gateway.py +0 -0
- /synth_ai/{learning → sdk/learning}/rl/__init__.py +0 -0
- /synth_ai/{learning → sdk/learning}/rl/config.py +0 -0
- /synth_ai/{learning → sdk/learning}/rl_client.py +0 -0
- /synth_ai/{learning → sdk/learning}/sft/__init__.py +0 -0
- /synth_ai/{learning → sdk/learning}/sse.py +0 -0
- /synth_ai/{task → sdk/task}/auth.py +0 -0
- /synth_ai/{task → sdk/task}/client.py +0 -0
- /synth_ai/{task → sdk/task}/errors.py +0 -0
- /synth_ai/{task → sdk/task}/health.py +0 -0
- /synth_ai/{task → sdk/task}/json.py +0 -0
- /synth_ai/{task → sdk/task}/rubrics/models.py +0 -0
- /synth_ai/{task → sdk/task}/rubrics/scoring.py +0 -0
- /synth_ai/{task → sdk/task}/rubrics/strict.py +0 -0
- /synth_ai/{task → sdk/task}/vendors.py +0 -0
- {synth_ai-0.2.14.dist-info → synth_ai-0.4.1.dist-info}/WHEEL +0 -0
- {synth_ai-0.2.14.dist-info → synth_ai-0.4.1.dist-info}/entry_points.txt +0 -0
- {synth_ai-0.2.14.dist-info → synth_ai-0.4.1.dist-info}/licenses/LICENSE +0 -0
synth_ai/demos/core/cli.py
DELETED
|
@@ -1,1718 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import contextlib
|
|
4
|
-
import json
|
|
5
|
-
import os
|
|
6
|
-
import shutil
|
|
7
|
-
import stat
|
|
8
|
-
import sys
|
|
9
|
-
import textwrap
|
|
10
|
-
import time
|
|
11
|
-
from collections.abc import Callable
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from typing import Any
|
|
14
|
-
|
|
15
|
-
from synth_ai.demo_registry import (
|
|
16
|
-
DemoTemplate,
|
|
17
|
-
get_demo_template,
|
|
18
|
-
list_demo_templates,
|
|
19
|
-
)
|
|
20
|
-
from synth_ai.demos.demo_task_apps import core as demo_core
|
|
21
|
-
from synth_ai.demos.demo_task_apps.core import DEFAULT_TASK_APP_SECRET_NAME, DemoEnv
|
|
22
|
-
from synth_ai.handshake import HandshakeError, run_handshake
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def _key_preview(value: str, label: str) -> str:
|
|
26
|
-
"""Return a short descriptor for a secret without leaking the full value."""
|
|
27
|
-
try:
|
|
28
|
-
text = value or ""
|
|
29
|
-
length = len(text)
|
|
30
|
-
prefix = text[:6] if length >= 6 else text
|
|
31
|
-
suffix = text[-5:] if length >= 5 else text
|
|
32
|
-
return f"{label} len={length} prefix={prefix} last5={suffix}"
|
|
33
|
-
except Exception:
|
|
34
|
-
return f"{label} len=0"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def _is_modal_public_url(u: str) -> bool:
|
|
38
|
-
try:
|
|
39
|
-
s = (u or "").strip().lower()
|
|
40
|
-
if not (s.startswith("http://") or s.startswith("https://")):
|
|
41
|
-
return False
|
|
42
|
-
return (".modal.run" in s) and ("modal.local" not in s) and ("pypi-mirror" not in s)
|
|
43
|
-
except Exception:
|
|
44
|
-
return False
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def setup() -> int:
|
|
48
|
-
# Change to demo directory if stored
|
|
49
|
-
demo_dir = demo_core.load_demo_dir()
|
|
50
|
-
if demo_dir and os.path.isdir(demo_dir):
|
|
51
|
-
os.chdir(demo_dir)
|
|
52
|
-
print(f"Using demo directory: {demo_dir}")
|
|
53
|
-
|
|
54
|
-
# 1) Try to fetch keys from frontend; fall back to manual input if fetch fails
|
|
55
|
-
synth_key = ""
|
|
56
|
-
rl_env_key = ""
|
|
57
|
-
org_name = "this organization"
|
|
58
|
-
|
|
59
|
-
try:
|
|
60
|
-
print("\n⏳ Connecting SDK to your browser session…")
|
|
61
|
-
res = run_handshake()
|
|
62
|
-
org = res.get("org") or {}
|
|
63
|
-
keys = res.get("keys") or {}
|
|
64
|
-
synth_key = str(keys.get("synth") or "").strip()
|
|
65
|
-
rl_env_key = str(keys.get("rl_env") or "").strip()
|
|
66
|
-
org_name = org.get("name") or "this organization"
|
|
67
|
-
print(f"✅ Connected to {org_name}!")
|
|
68
|
-
except (HandshakeError, Exception) as e:
|
|
69
|
-
print(f"⚠️ Failed to fetch keys from frontend: {e}")
|
|
70
|
-
print("Falling back to manual entry...")
|
|
71
|
-
|
|
72
|
-
# Prompt for manual input if any key is missing
|
|
73
|
-
if not synth_key:
|
|
74
|
-
try:
|
|
75
|
-
synth_key = input(
|
|
76
|
-
"Failed to fetch your Synth API key. Please enter your Synth API key here:\n> "
|
|
77
|
-
).strip()
|
|
78
|
-
except (EOFError, KeyboardInterrupt):
|
|
79
|
-
print("\nSetup cancelled.")
|
|
80
|
-
return 1
|
|
81
|
-
if not synth_key:
|
|
82
|
-
print("Synth API key is required.")
|
|
83
|
-
return 1
|
|
84
|
-
|
|
85
|
-
if not rl_env_key:
|
|
86
|
-
try:
|
|
87
|
-
rl_env_key = input(
|
|
88
|
-
"Failed to fetch your RL Environment API key. Please enter your RL Environment API key here:\n> "
|
|
89
|
-
).strip()
|
|
90
|
-
except (EOFError, KeyboardInterrupt):
|
|
91
|
-
print("\nSetup cancelled.")
|
|
92
|
-
return 1
|
|
93
|
-
if not rl_env_key:
|
|
94
|
-
print("RL Environment API key is required.")
|
|
95
|
-
return 1
|
|
96
|
-
|
|
97
|
-
# Persist both keys to .env
|
|
98
|
-
dotenv_path = demo_core.persist_dotenv_values(
|
|
99
|
-
{
|
|
100
|
-
"SYNTH_API_KEY": synth_key,
|
|
101
|
-
"ENVIRONMENT_API_KEY": rl_env_key,
|
|
102
|
-
}
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
# Store .env path for subsequent commands
|
|
106
|
-
demo_core.persist_env_file_path(dotenv_path)
|
|
107
|
-
|
|
108
|
-
# 2) Reload env after handshake to pick up values from .env (suppress env prints)
|
|
109
|
-
import contextlib
|
|
110
|
-
import io
|
|
111
|
-
|
|
112
|
-
_buf = io.StringIO()
|
|
113
|
-
with contextlib.redirect_stdout(_buf):
|
|
114
|
-
env = demo_core.load_env()
|
|
115
|
-
cwd_env_path = os.path.join(os.getcwd(), ".env")
|
|
116
|
-
local_env = demo_core.load_dotenv_file(cwd_env_path)
|
|
117
|
-
|
|
118
|
-
def _refresh_env() -> None:
|
|
119
|
-
nonlocal env, local_env
|
|
120
|
-
env = demo_core.load_env()
|
|
121
|
-
local_env = demo_core.load_dotenv_file(cwd_env_path)
|
|
122
|
-
|
|
123
|
-
def _maybe_fix_task_url() -> None:
|
|
124
|
-
if not env.task_app_name:
|
|
125
|
-
return
|
|
126
|
-
current = env.task_app_base_url
|
|
127
|
-
needs_lookup = False
|
|
128
|
-
if not current or not _is_modal_public_url(current):
|
|
129
|
-
needs_lookup = True
|
|
130
|
-
if not needs_lookup:
|
|
131
|
-
return
|
|
132
|
-
code, out = _popen_capture(
|
|
133
|
-
[
|
|
134
|
-
"uv",
|
|
135
|
-
"run",
|
|
136
|
-
"python",
|
|
137
|
-
"-m",
|
|
138
|
-
"modal",
|
|
139
|
-
"app",
|
|
140
|
-
"url",
|
|
141
|
-
env.task_app_name,
|
|
142
|
-
]
|
|
143
|
-
)
|
|
144
|
-
if code != 0 or not out:
|
|
145
|
-
return
|
|
146
|
-
new_url = ""
|
|
147
|
-
for token in out.split():
|
|
148
|
-
if _is_modal_public_url(token):
|
|
149
|
-
new_url = token.strip().rstrip("/")
|
|
150
|
-
break
|
|
151
|
-
if new_url and new_url != current:
|
|
152
|
-
print(f"Updating TASK_APP_BASE_URL from Modal CLI → {new_url}")
|
|
153
|
-
demo_core.persist_task_url(new_url, name=env.task_app_name)
|
|
154
|
-
dotenv_values = {
|
|
155
|
-
"TASK_APP_BASE_URL": new_url,
|
|
156
|
-
"TASK_APP_NAME": env.task_app_name,
|
|
157
|
-
}
|
|
158
|
-
demo_core.persist_dotenv_values(dotenv_values)
|
|
159
|
-
os.environ["TASK_APP_BASE_URL"] = new_url
|
|
160
|
-
_refresh_env()
|
|
161
|
-
|
|
162
|
-
# Keys have been written already via handshake; avoid any interactive prompts
|
|
163
|
-
synth_key = env.synth_api_key.strip()
|
|
164
|
-
if not local_env.get("SYNTH_API_KEY") and synth_key:
|
|
165
|
-
demo_core.persist_dotenv_values({"SYNTH_API_KEY": synth_key})
|
|
166
|
-
_refresh_env()
|
|
167
|
-
|
|
168
|
-
# Check Modal auth silently to avoid noisy output
|
|
169
|
-
modal_ok, modal_msg = demo_core.modal_auth_status()
|
|
170
|
-
|
|
171
|
-
_maybe_fix_task_url()
|
|
172
|
-
|
|
173
|
-
if env.dev_backend_url:
|
|
174
|
-
api = env.dev_backend_url.rstrip("/") + (
|
|
175
|
-
"" if env.dev_backend_url.endswith("/api") else "/api"
|
|
176
|
-
)
|
|
177
|
-
demo_core.assert_http_ok(api + "/health", method="GET")
|
|
178
|
-
# Intentionally suppress backend health print for concise output
|
|
179
|
-
if env.task_app_base_url:
|
|
180
|
-
demo_core.assert_http_ok(
|
|
181
|
-
env.task_app_base_url.rstrip("/") + "/health", method="GET"
|
|
182
|
-
) or demo_core.assert_http_ok(env.task_app_base_url.rstrip("/"), method="GET")
|
|
183
|
-
# Intentionally suppress task app health print
|
|
184
|
-
else:
|
|
185
|
-
print("\nSet your task app URL by running:\nuvx synth-ai rl_demo deploy\n")
|
|
186
|
-
|
|
187
|
-
# Omit uv version print to keep output concise
|
|
188
|
-
|
|
189
|
-
# Keep exit code neutral; not all checks are critical for pairing
|
|
190
|
-
print(f"\nKeys saved to: {dotenv_path}")
|
|
191
|
-
return 0
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
def _popen_capture(
|
|
195
|
-
cmd: list[str], cwd: str | None = None, env: dict | None = None
|
|
196
|
-
) -> tuple[int, str]:
|
|
197
|
-
import subprocess
|
|
198
|
-
|
|
199
|
-
try:
|
|
200
|
-
proc = subprocess.Popen(
|
|
201
|
-
cmd, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
|
|
202
|
-
)
|
|
203
|
-
out, _ = proc.communicate()
|
|
204
|
-
return int(proc.returncode or 0), out or ""
|
|
205
|
-
except Exception as e:
|
|
206
|
-
return 1, str(e)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def _popen_stream(cmd: list[str], cwd: str | None = None, env: dict | None = None) -> int:
|
|
210
|
-
"""Stream subprocess output line-by-line to stdout for real-time feedback."""
|
|
211
|
-
|
|
212
|
-
import subprocess
|
|
213
|
-
import threading
|
|
214
|
-
|
|
215
|
-
try:
|
|
216
|
-
proc = subprocess.Popen(
|
|
217
|
-
cmd,
|
|
218
|
-
cwd=cwd,
|
|
219
|
-
env=env,
|
|
220
|
-
stdout=subprocess.PIPE,
|
|
221
|
-
stderr=subprocess.STDOUT,
|
|
222
|
-
text=True,
|
|
223
|
-
bufsize=1,
|
|
224
|
-
)
|
|
225
|
-
except Exception as exc:
|
|
226
|
-
print(f"Failed to launch {' '.join(cmd)}: {exc}")
|
|
227
|
-
return 1
|
|
228
|
-
|
|
229
|
-
def _pump(stdout) -> None:
|
|
230
|
-
try:
|
|
231
|
-
for line in stdout:
|
|
232
|
-
print(line.rstrip())
|
|
233
|
-
except Exception:
|
|
234
|
-
pass
|
|
235
|
-
|
|
236
|
-
if proc.stdout is not None:
|
|
237
|
-
t = threading.Thread(target=_pump, args=(proc.stdout,), daemon=True)
|
|
238
|
-
t.start()
|
|
239
|
-
proc.wait()
|
|
240
|
-
t.join(timeout=1.0)
|
|
241
|
-
else:
|
|
242
|
-
proc.wait()
|
|
243
|
-
return int(proc.returncode or 0)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
def _popen_stream_capture(
|
|
247
|
-
cmd: list[str], cwd: str | None = None, env: dict | None = None
|
|
248
|
-
) -> tuple[int, str]:
|
|
249
|
-
"""Stream subprocess output to stdout and also capture it into a buffer."""
|
|
250
|
-
import subprocess
|
|
251
|
-
import threading
|
|
252
|
-
|
|
253
|
-
buf_lines: list[str] = []
|
|
254
|
-
try:
|
|
255
|
-
proc = subprocess.Popen(
|
|
256
|
-
cmd,
|
|
257
|
-
cwd=cwd,
|
|
258
|
-
env=env,
|
|
259
|
-
stdout=subprocess.PIPE,
|
|
260
|
-
stderr=subprocess.STDOUT,
|
|
261
|
-
text=True,
|
|
262
|
-
bufsize=1,
|
|
263
|
-
)
|
|
264
|
-
except Exception as exc:
|
|
265
|
-
print(f"Failed to launch {' '.join(cmd)}: {exc}")
|
|
266
|
-
return 1, ""
|
|
267
|
-
|
|
268
|
-
def _pump(stdout) -> None:
|
|
269
|
-
try:
|
|
270
|
-
for line in stdout:
|
|
271
|
-
line = line.rstrip()
|
|
272
|
-
print(line)
|
|
273
|
-
buf_lines.append(line)
|
|
274
|
-
except Exception:
|
|
275
|
-
pass
|
|
276
|
-
|
|
277
|
-
if proc.stdout is not None:
|
|
278
|
-
t = threading.Thread(target=_pump, args=(proc.stdout,), daemon=True)
|
|
279
|
-
t.start()
|
|
280
|
-
proc.wait()
|
|
281
|
-
t.join(timeout=1.0)
|
|
282
|
-
else:
|
|
283
|
-
proc.wait()
|
|
284
|
-
return int(proc.returncode or 0), "\n".join(buf_lines)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
def _fmt_float(value: float) -> str:
|
|
288
|
-
return f"{value:.10g}"
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
def _find_asgi_apps(root: Path) -> list[Path]:
|
|
292
|
-
"""Recursively search for Python files that declare a Modal ASGI app.
|
|
293
|
-
|
|
294
|
-
A file is considered a Modal task app candidate if it contains one of:
|
|
295
|
-
- "@asgi_app()"
|
|
296
|
-
- "@modal.asgi_app()"
|
|
297
|
-
"""
|
|
298
|
-
results: list[Path] = []
|
|
299
|
-
skip_dirs = {
|
|
300
|
-
".git",
|
|
301
|
-
".hg",
|
|
302
|
-
".svn",
|
|
303
|
-
"node_modules",
|
|
304
|
-
"dist",
|
|
305
|
-
"build",
|
|
306
|
-
"__pycache__",
|
|
307
|
-
".ruff_cache",
|
|
308
|
-
".mypy_cache",
|
|
309
|
-
"venv",
|
|
310
|
-
".venv",
|
|
311
|
-
}
|
|
312
|
-
for dirpath, dirnames, filenames in os.walk(root):
|
|
313
|
-
dirnames[:] = [d for d in dirnames if d not in skip_dirs]
|
|
314
|
-
for name in filenames:
|
|
315
|
-
if not name.endswith(".py"):
|
|
316
|
-
continue
|
|
317
|
-
path = Path(dirpath) / name
|
|
318
|
-
try:
|
|
319
|
-
with path.open("r", encoding="utf-8", errors="ignore") as fh:
|
|
320
|
-
txt = fh.read()
|
|
321
|
-
if ("@asgi_app()" in txt) or ("@modal.asgi_app()" in txt):
|
|
322
|
-
results.append(path)
|
|
323
|
-
except Exception:
|
|
324
|
-
continue
|
|
325
|
-
|
|
326
|
-
# Stable order: prioritize files under synth_demo/ first, then alphabetical
|
|
327
|
-
def _priority(p: Path) -> tuple[int, str]:
|
|
328
|
-
rel = str(p.resolve())
|
|
329
|
-
in_demo = "/synth_demo/" in rel or rel.endswith("/synth_demo/task_app.py")
|
|
330
|
-
return (0 if in_demo else 1, rel)
|
|
331
|
-
|
|
332
|
-
results.sort(key=_priority)
|
|
333
|
-
return results
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
def _prompt_value(
|
|
337
|
-
label: str, default: str | int | float, cast: Callable[[str], Any] | None = None
|
|
338
|
-
) -> Any:
|
|
339
|
-
prompt = f"{label} [{default}]: "
|
|
340
|
-
try:
|
|
341
|
-
raw = input(prompt).strip()
|
|
342
|
-
except Exception:
|
|
343
|
-
raw = ""
|
|
344
|
-
if not raw:
|
|
345
|
-
return default
|
|
346
|
-
if cast is None:
|
|
347
|
-
return raw
|
|
348
|
-
try:
|
|
349
|
-
return cast(raw)
|
|
350
|
-
except Exception:
|
|
351
|
-
print(f"Invalid value; keeping default {default}")
|
|
352
|
-
return default
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
def _find_vllm_tomls(root: Path) -> list[Path]:
|
|
356
|
-
results: list[Path] = []
|
|
357
|
-
skip_dirs = {
|
|
358
|
-
".git",
|
|
359
|
-
".hg",
|
|
360
|
-
".svn",
|
|
361
|
-
"node_modules",
|
|
362
|
-
"dist",
|
|
363
|
-
"build",
|
|
364
|
-
"__pycache__",
|
|
365
|
-
".ruff_cache",
|
|
366
|
-
".mypy_cache",
|
|
367
|
-
"venv",
|
|
368
|
-
".venv",
|
|
369
|
-
}
|
|
370
|
-
for dirpath, dirnames, filenames in os.walk(root):
|
|
371
|
-
dirnames[:] = [d for d in dirnames if d not in skip_dirs]
|
|
372
|
-
for name in filenames:
|
|
373
|
-
if not name.endswith(".toml"):
|
|
374
|
-
continue
|
|
375
|
-
path = Path(dirpath) / name
|
|
376
|
-
try:
|
|
377
|
-
with path.open("r", encoding="utf-8", errors="ignore") as fh:
|
|
378
|
-
if "[vllm]" in fh.read().lower():
|
|
379
|
-
results.append(path)
|
|
380
|
-
except Exception:
|
|
381
|
-
continue
|
|
382
|
-
return results
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
def _create_new_config(env: DemoEnv) -> str:
|
|
386
|
-
default_path = os.path.join(os.getcwd(), "demo_config.toml")
|
|
387
|
-
while True:
|
|
388
|
-
try:
|
|
389
|
-
destination = (
|
|
390
|
-
input(f"Path to save new config [{default_path}]: ").strip() or default_path
|
|
391
|
-
)
|
|
392
|
-
except Exception:
|
|
393
|
-
destination = default_path
|
|
394
|
-
destination = os.path.abspath(destination)
|
|
395
|
-
if os.path.isdir(destination):
|
|
396
|
-
print("Path points to a directory; provide a file path.")
|
|
397
|
-
continue
|
|
398
|
-
if os.path.exists(destination):
|
|
399
|
-
try:
|
|
400
|
-
overwrite = (
|
|
401
|
-
input(f"{destination} exists. Overwrite? [y/N]: ").strip().lower() or "n"
|
|
402
|
-
)
|
|
403
|
-
except Exception:
|
|
404
|
-
overwrite = "n"
|
|
405
|
-
if not overwrite.startswith("y"):
|
|
406
|
-
continue
|
|
407
|
-
break
|
|
408
|
-
|
|
409
|
-
env_name = _prompt_value("Environment name", "Crafter")
|
|
410
|
-
policy_name = _prompt_value("Policy name", "crafter-react")
|
|
411
|
-
model_name = _prompt_value("Model name", "Qwen/Qwen3-0.6B")
|
|
412
|
-
compute_gpu_type = _prompt_value("Compute GPU type", "H100")
|
|
413
|
-
compute_gpu_count = _prompt_value("Compute GPU count", 4, int)
|
|
414
|
-
topology_gpu_type = _prompt_value(
|
|
415
|
-
"Topology GPU type", f"{compute_gpu_type}:{compute_gpu_count}"
|
|
416
|
-
)
|
|
417
|
-
gpus_for_vllm = _prompt_value("Topology gpus_for_vllm", 2, int)
|
|
418
|
-
gpus_for_training = _prompt_value("Topology gpus_for_training", 1, int)
|
|
419
|
-
tensor_parallel = _prompt_value("Topology tensor_parallel", 2, int)
|
|
420
|
-
gpus_for_ref = _prompt_value("Topology gpus_for_ref", 1, int)
|
|
421
|
-
vllm_tp_size = _prompt_value("vLLM tensor parallel size", tensor_parallel, int)
|
|
422
|
-
vllm_max_model_len = _prompt_value("vLLM max_model_len", 8192, int)
|
|
423
|
-
vllm_max_num_seqs = _prompt_value("vLLM max_num_seqs", 32, int)
|
|
424
|
-
vllm_gpu_mem_util = _prompt_value("vLLM gpu_memory_utilization", 0.9, float)
|
|
425
|
-
vllm_max_parallel = _prompt_value("vLLM max_parallel_generations", 4, int)
|
|
426
|
-
training_num_epochs = _prompt_value("Training num_epochs", 1, int)
|
|
427
|
-
training_iters = _prompt_value("Training iterations_per_epoch", 2, int)
|
|
428
|
-
training_batch = _prompt_value("Training batch_size", 1, int)
|
|
429
|
-
training_group = _prompt_value("Training group_size", 8, int)
|
|
430
|
-
training_lr = _prompt_value("Training learning_rate", 5e-6, float)
|
|
431
|
-
task_url_default = env.task_app_base_url or ""
|
|
432
|
-
services_task_url = _prompt_value("services.task_url", task_url_default)
|
|
433
|
-
|
|
434
|
-
template = (
|
|
435
|
-
textwrap.dedent(
|
|
436
|
-
f"""\
|
|
437
|
-
# Crafter online RL training configuration (research local copy)
|
|
438
|
-
|
|
439
|
-
[model]
|
|
440
|
-
#name = \"fft:Qwen/Qwen3-4B:job_7243b8aa76fe4b59\"
|
|
441
|
-
name = \"{model_name}\"
|
|
442
|
-
dtype = \"bfloat16\"
|
|
443
|
-
seed = 42
|
|
444
|
-
trainer_mode = \"full\"
|
|
445
|
-
|
|
446
|
-
[lora]
|
|
447
|
-
r = 16
|
|
448
|
-
alpha = 32
|
|
449
|
-
dropout = 0.05
|
|
450
|
-
target_modules = [
|
|
451
|
-
\"q_proj\", \"k_proj\", \"v_proj\", \"o_proj\",
|
|
452
|
-
\"gate_proj\", \"up_proj\", \"down_proj\",
|
|
453
|
-
]
|
|
454
|
-
|
|
455
|
-
[rdma]
|
|
456
|
-
enabled = false
|
|
457
|
-
ifname = \"eth0\"
|
|
458
|
-
ip_type = \"ipv4\"
|
|
459
|
-
p2p_disable = 0
|
|
460
|
-
shm_disable = 0
|
|
461
|
-
fast_nccl = false
|
|
462
|
-
|
|
463
|
-
gid_index = 3
|
|
464
|
-
cross_nic = 0
|
|
465
|
-
collnet_enable = 0
|
|
466
|
-
net_gdr_level = 2
|
|
467
|
-
|
|
468
|
-
nsocks_perthread = 4
|
|
469
|
-
socket_nthreads = 2
|
|
470
|
-
|
|
471
|
-
algo = \"Ring\"
|
|
472
|
-
proto = \"Simple\"
|
|
473
|
-
p2p_level = \"SYS\"
|
|
474
|
-
debug = \"INFO\"
|
|
475
|
-
|
|
476
|
-
[compute]
|
|
477
|
-
gpu_type = \"{compute_gpu_type}\"
|
|
478
|
-
gpu_count = {compute_gpu_count}
|
|
479
|
-
|
|
480
|
-
[topology]
|
|
481
|
-
type = \"single_node_split\"
|
|
482
|
-
gpu_type = \"{topology_gpu_type}\"
|
|
483
|
-
use_rdma = false
|
|
484
|
-
gpus_for_vllm = {gpus_for_vllm}
|
|
485
|
-
gpus_for_training = {gpus_for_training}
|
|
486
|
-
tensor_parallel = {tensor_parallel}
|
|
487
|
-
gpus_for_ref = {gpus_for_ref}
|
|
488
|
-
|
|
489
|
-
[vllm]
|
|
490
|
-
tensor_parallel_size = {vllm_tp_size}
|
|
491
|
-
gpu_memory_utilization = {_fmt_float(vllm_gpu_mem_util)}
|
|
492
|
-
max_model_len = {vllm_max_model_len}
|
|
493
|
-
max_num_seqs = {vllm_max_num_seqs}
|
|
494
|
-
enforce_eager = false
|
|
495
|
-
max_parallel_generations = {vllm_max_parallel}
|
|
496
|
-
|
|
497
|
-
# Reference scoring server (dedicated GPU)
|
|
498
|
-
[reference]
|
|
499
|
-
placement = \"dedicated\"
|
|
500
|
-
gpu_index = 1
|
|
501
|
-
port = 8002
|
|
502
|
-
tp = 1
|
|
503
|
-
health_max_wait_s = 180
|
|
504
|
-
health_interval_ms = 300
|
|
505
|
-
|
|
506
|
-
[training]
|
|
507
|
-
num_epochs = {training_num_epochs}
|
|
508
|
-
iterations_per_epoch = {training_iters}
|
|
509
|
-
batch_size = {training_batch}
|
|
510
|
-
group_size = {training_group}
|
|
511
|
-
learning_rate = {_fmt_float(training_lr)}
|
|
512
|
-
max_grad_norm = 0.5
|
|
513
|
-
log_interval = 1
|
|
514
|
-
update_reference_interval = 0
|
|
515
|
-
weight_sync_interval = 1
|
|
516
|
-
|
|
517
|
-
[training.weight_sync]
|
|
518
|
-
enable = true
|
|
519
|
-
targets = [\"policy\"]
|
|
520
|
-
|
|
521
|
-
[rollout]
|
|
522
|
-
env_name = \"{env_name}\"
|
|
523
|
-
policy_name = \"{policy_name}\"
|
|
524
|
-
env_config = {{}}
|
|
525
|
-
max_steps_per_episode = 5
|
|
526
|
-
sampling_temperature = 0.3
|
|
527
|
-
sampling_top_p = 0.95
|
|
528
|
-
max_tokens = 1024
|
|
529
|
-
max_concurrent_rollouts = 4
|
|
530
|
-
ops_per_rollout = 14
|
|
531
|
-
on_done = \"reset\"
|
|
532
|
-
thinking_mode = \"think\"
|
|
533
|
-
thinking_budget = 512
|
|
534
|
-
|
|
535
|
-
[policy]
|
|
536
|
-
config = {{}}
|
|
537
|
-
|
|
538
|
-
[evaluation]
|
|
539
|
-
seeds = [0, 1, 2, 3, 4, 5, 6, 7]
|
|
540
|
-
rollouts_per_seed = 1
|
|
541
|
-
instances = 0
|
|
542
|
-
max_concurrent_rollouts = 4
|
|
543
|
-
thinking_mode = \"think\"
|
|
544
|
-
every_n_iters = 5
|
|
545
|
-
|
|
546
|
-
[hyperparams]
|
|
547
|
-
epsilon_low = 0.1
|
|
548
|
-
epsilon_high = 0.3
|
|
549
|
-
delta = 5.0
|
|
550
|
-
beta = 0.01
|
|
551
|
-
kl_penalty = 0.01
|
|
552
|
-
advantage_normalization = true
|
|
553
|
-
group_normalization = true
|
|
554
|
-
num_inner_steps = 1
|
|
555
|
-
clip_epsilon = 0.2
|
|
556
|
-
completion_only = false
|
|
557
|
-
|
|
558
|
-
[step_rewards]
|
|
559
|
-
enabled = false
|
|
560
|
-
mode = \"off\"
|
|
561
|
-
step_beta = 0.0
|
|
562
|
-
indicator_lambda = 0.0
|
|
563
|
-
|
|
564
|
-
[trainer]
|
|
565
|
-
allow_ref_fallback = false
|
|
566
|
-
|
|
567
|
-
[checkpoint]
|
|
568
|
-
interval = 10
|
|
569
|
-
directory = \"/checkpoints\"
|
|
570
|
-
keep_last_n = 3
|
|
571
|
-
save_optimizer = true
|
|
572
|
-
save_scheduler = true
|
|
573
|
-
enabled = true
|
|
574
|
-
|
|
575
|
-
[services]
|
|
576
|
-
task_url = \"{services_task_url}\"
|
|
577
|
-
"""
|
|
578
|
-
).strip()
|
|
579
|
-
+ "\n"
|
|
580
|
-
)
|
|
581
|
-
|
|
582
|
-
with open(destination, "w", encoding="utf-8") as fh:
|
|
583
|
-
fh.write(template)
|
|
584
|
-
print(f"Wrote config to {destination}")
|
|
585
|
-
return destination
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
def _select_or_create_config(explicit: str | None, env: DemoEnv) -> str:
|
|
589
|
-
if explicit:
|
|
590
|
-
path = os.path.abspath(explicit)
|
|
591
|
-
if not os.path.isfile(path):
|
|
592
|
-
raise FileNotFoundError(f"Config not found: {path}")
|
|
593
|
-
return path
|
|
594
|
-
|
|
595
|
-
search_root = Path(os.getcwd())
|
|
596
|
-
discovered = _find_vllm_tomls(search_root)
|
|
597
|
-
|
|
598
|
-
extras: list[Path] = []
|
|
599
|
-
packaged = Path(
|
|
600
|
-
os.path.abspath(
|
|
601
|
-
os.path.join(os.path.dirname(__file__), "..", "demo_task_apps", "math", "config.toml")
|
|
602
|
-
)
|
|
603
|
-
)
|
|
604
|
-
extras.append(packaged)
|
|
605
|
-
home_cfg = Path(os.path.expanduser("~/.synth-ai/demo_config.toml"))
|
|
606
|
-
extras.append(home_cfg)
|
|
607
|
-
|
|
608
|
-
all_paths: list[Path] = []
|
|
609
|
-
seen: set[str] = set()
|
|
610
|
-
for candidate in discovered + extras:
|
|
611
|
-
if candidate.is_file():
|
|
612
|
-
resolved = str(candidate.resolve())
|
|
613
|
-
if resolved not in seen:
|
|
614
|
-
seen.add(resolved)
|
|
615
|
-
all_paths.append(candidate)
|
|
616
|
-
|
|
617
|
-
if not all_paths:
|
|
618
|
-
print("No existing RL TOML configs with [vllm] found; creating a new one.")
|
|
619
|
-
return _create_new_config(env)
|
|
620
|
-
|
|
621
|
-
print("Select a TOML config (found [vllm] section):")
|
|
622
|
-
for idx, path in enumerate(all_paths, 1):
|
|
623
|
-
rel = os.path.relpath(str(path), os.getcwd())
|
|
624
|
-
print(f" [{idx}] {rel}")
|
|
625
|
-
create_idx = len(all_paths) + 1
|
|
626
|
-
print(f" [{create_idx}] Create new config")
|
|
627
|
-
try:
|
|
628
|
-
sel = input(f"Enter choice [1-{create_idx}] (default 1): ").strip() or "1"
|
|
629
|
-
except Exception:
|
|
630
|
-
sel = "1"
|
|
631
|
-
try:
|
|
632
|
-
choice = int(sel)
|
|
633
|
-
except Exception:
|
|
634
|
-
choice = 1
|
|
635
|
-
if choice == create_idx:
|
|
636
|
-
return _create_new_config(env)
|
|
637
|
-
choice = max(1, min(choice, len(all_paths)))
|
|
638
|
-
selected = os.path.abspath(all_paths[choice - 1])
|
|
639
|
-
print(f"Using config: {selected}")
|
|
640
|
-
return selected
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
def _ensure_task_app_ready(env: DemoEnv, synth_key: str, *, label: str) -> DemoEnv:
|
|
644
|
-
cwd_env_path = os.path.join(os.getcwd(), ".env")
|
|
645
|
-
local_env = demo_core.load_dotenv_file(cwd_env_path)
|
|
646
|
-
|
|
647
|
-
env_key = (env.env_api_key or "").strip()
|
|
648
|
-
if not env_key:
|
|
649
|
-
raise RuntimeError(
|
|
650
|
-
f"[{label}] ENVIRONMENT_API_KEY missing. Run `uvx synth-ai rl_demo deploy` first."
|
|
651
|
-
)
|
|
652
|
-
|
|
653
|
-
task_url = env.task_app_base_url
|
|
654
|
-
if not task_url or not _is_modal_public_url(task_url):
|
|
655
|
-
resolved = ""
|
|
656
|
-
if env.task_app_name:
|
|
657
|
-
try:
|
|
658
|
-
choice = (
|
|
659
|
-
input(f"Resolve URL from Modal for app '{env.task_app_name}'? [Y/n]: ")
|
|
660
|
-
.strip()
|
|
661
|
-
.lower()
|
|
662
|
-
or "y"
|
|
663
|
-
)
|
|
664
|
-
except Exception:
|
|
665
|
-
choice = "y"
|
|
666
|
-
if choice.startswith("y"):
|
|
667
|
-
code, out = _popen_capture(
|
|
668
|
-
[
|
|
669
|
-
"uv",
|
|
670
|
-
"run",
|
|
671
|
-
"python",
|
|
672
|
-
"-m",
|
|
673
|
-
"modal",
|
|
674
|
-
"app",
|
|
675
|
-
"url",
|
|
676
|
-
env.task_app_name,
|
|
677
|
-
]
|
|
678
|
-
)
|
|
679
|
-
if code == 0 and out:
|
|
680
|
-
for tok in out.split():
|
|
681
|
-
if _is_modal_public_url(tok):
|
|
682
|
-
resolved = tok.strip().rstrip("/")
|
|
683
|
-
break
|
|
684
|
-
if not resolved:
|
|
685
|
-
print(f"[{label}] Task app URL not configured or not a valid Modal public URL.")
|
|
686
|
-
print("Examples: https://<app-name>-fastapi-app.modal.run")
|
|
687
|
-
entered = input(
|
|
688
|
-
"Enter Task App base URL (must contain '.modal.run'), or press Enter to abort: "
|
|
689
|
-
).strip()
|
|
690
|
-
if not entered or not _is_modal_public_url(entered):
|
|
691
|
-
raise RuntimeError(f"[{label}] Valid Task App URL is required.")
|
|
692
|
-
task_url = entered.rstrip("/")
|
|
693
|
-
else:
|
|
694
|
-
task_url = resolved
|
|
695
|
-
demo_core.persist_task_url(task_url, name=(env.task_app_name or None))
|
|
696
|
-
|
|
697
|
-
app_name = env.task_app_name.strip()
|
|
698
|
-
if not app_name:
|
|
699
|
-
fallback = input("Enter Modal app name for the task app (required): ").strip()
|
|
700
|
-
if not fallback:
|
|
701
|
-
raise RuntimeError(f"[{label}] Task app name is required.")
|
|
702
|
-
app_name = fallback
|
|
703
|
-
demo_core.persist_task_url(task_url, name=app_name)
|
|
704
|
-
|
|
705
|
-
demo_core.persist_task_url(task_url, name=app_name)
|
|
706
|
-
demo_core.persist_dotenv_values(
|
|
707
|
-
{
|
|
708
|
-
"TASK_APP_BASE_URL": task_url,
|
|
709
|
-
"TASK_APP_NAME": app_name,
|
|
710
|
-
"TASK_APP_SECRET_NAME": DEFAULT_TASK_APP_SECRET_NAME,
|
|
711
|
-
}
|
|
712
|
-
)
|
|
713
|
-
|
|
714
|
-
if synth_key:
|
|
715
|
-
os.environ["SYNTH_API_KEY"] = synth_key
|
|
716
|
-
|
|
717
|
-
openai_key = (os.environ.get("OPENAI_API_KEY") or local_env.get("OPENAI_API_KEY") or "").strip()
|
|
718
|
-
if openai_key:
|
|
719
|
-
os.environ["OPENAI_API_KEY"] = openai_key
|
|
720
|
-
|
|
721
|
-
print(f"[{label}] Verifying rollout health:")
|
|
722
|
-
try:
|
|
723
|
-
ek = (env_key or "").strip()
|
|
724
|
-
print(f"[{label}] {_key_preview(ek, 'ENVIRONMENT_API_KEY')}")
|
|
725
|
-
except Exception:
|
|
726
|
-
pass
|
|
727
|
-
health_base = task_url.rstrip("/")
|
|
728
|
-
health_urls = [f"{health_base}/health/rollout", f"{health_base}/health"]
|
|
729
|
-
rc = 0
|
|
730
|
-
body: Any = ""
|
|
731
|
-
for h in health_urls:
|
|
732
|
-
print(f"[{label}] GET", h)
|
|
733
|
-
rc, body = _http("GET", h, headers={"X-API-Key": env_key})
|
|
734
|
-
if rc == 200:
|
|
735
|
-
break
|
|
736
|
-
print(f"[{label}] status: {rc}")
|
|
737
|
-
try:
|
|
738
|
-
import json as _json
|
|
739
|
-
|
|
740
|
-
preview = _json.dumps(body)[:800] if isinstance(body, dict) else str(body)[:800]
|
|
741
|
-
except Exception:
|
|
742
|
-
preview = str(body)[:800]
|
|
743
|
-
print(f"[{label}] body:", preview)
|
|
744
|
-
if rc != 200:
|
|
745
|
-
print(f"[{label}] Warning: rollout health check failed ({rc}). Response: {body}")
|
|
746
|
-
with contextlib.suppress(Exception):
|
|
747
|
-
print(f"[{label}] Sent header X-API-Key → {_key_preview(env_key, 'X-API-Key')}")
|
|
748
|
-
else:
|
|
749
|
-
print(f"[{label}] Task app rollout health check OK.")
|
|
750
|
-
|
|
751
|
-
os.environ["TASK_APP_BASE_URL"] = task_url
|
|
752
|
-
os.environ["ENVIRONMENT_API_KEY"] = env_key
|
|
753
|
-
os.environ["TASK_APP_SECRET_NAME"] = DEFAULT_TASK_APP_SECRET_NAME
|
|
754
|
-
updated_env = demo_core.load_env()
|
|
755
|
-
updated_env.env_api_key = env_key
|
|
756
|
-
updated_env.task_app_base_url = task_url
|
|
757
|
-
updated_env.task_app_name = app_name
|
|
758
|
-
updated_env.task_app_secret_name = DEFAULT_TASK_APP_SECRET_NAME
|
|
759
|
-
return updated_env
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
def deploy(
|
|
763
|
-
local: bool = False, app: str | None = None, name: str | None = None, script: str | None = None
|
|
764
|
-
) -> int:
|
|
765
|
-
# Change to demo directory if stored
|
|
766
|
-
demo_dir = demo_core.load_demo_dir()
|
|
767
|
-
if demo_dir and os.path.isdir(demo_dir):
|
|
768
|
-
os.chdir(demo_dir)
|
|
769
|
-
print(f"Using demo directory: {demo_dir}")
|
|
770
|
-
|
|
771
|
-
env = demo_core.load_env()
|
|
772
|
-
os.environ["TASK_APP_SECRET_NAME"] = DEFAULT_TASK_APP_SECRET_NAME
|
|
773
|
-
cwd_env_path = os.path.join(os.getcwd(), ".env")
|
|
774
|
-
local_env = demo_core.load_dotenv_file(cwd_env_path)
|
|
775
|
-
url = ""
|
|
776
|
-
app_name = env.task_app_name or ""
|
|
777
|
-
try:
|
|
778
|
-
if local:
|
|
779
|
-
print("Starting local Task App…")
|
|
780
|
-
import subprocess
|
|
781
|
-
|
|
782
|
-
subprocess.Popen(
|
|
783
|
-
[
|
|
784
|
-
sys.executable,
|
|
785
|
-
"-c",
|
|
786
|
-
"from synth_ai.demos.demo_task_apps.math.app import run; run()",
|
|
787
|
-
],
|
|
788
|
-
stdout=sys.stdout,
|
|
789
|
-
stderr=sys.stderr,
|
|
790
|
-
)
|
|
791
|
-
target = "http://127.0.0.1:8080"
|
|
792
|
-
app_name = ""
|
|
793
|
-
for _ in range(30):
|
|
794
|
-
if demo_core.assert_http_ok(
|
|
795
|
-
target + "/health", method="GET"
|
|
796
|
-
) or demo_core.assert_http_ok(target, method="GET"):
|
|
797
|
-
url = target
|
|
798
|
-
break
|
|
799
|
-
time.sleep(1)
|
|
800
|
-
else:
|
|
801
|
-
# Auto-detect app path if not supplied; prompt interactively from discovered ASGI apps
|
|
802
|
-
app_path = os.path.abspath(app) if app else None
|
|
803
|
-
if not app_path or not os.path.isfile(app_path):
|
|
804
|
-
# First pass: look for known common filenames
|
|
805
|
-
candidates = [
|
|
806
|
-
os.path.abspath(os.path.join(os.getcwd(), "synth_demo", "task_app.py")),
|
|
807
|
-
os.path.abspath(os.path.join(os.getcwd(), "task_app.py")),
|
|
808
|
-
os.path.abspath(os.path.join(os.getcwd(), "app.py")),
|
|
809
|
-
os.path.abspath(os.path.join(os.getcwd(), "math_task_app.py")),
|
|
810
|
-
]
|
|
811
|
-
app_path = next((p for p in candidates if os.path.isfile(p)), None)
|
|
812
|
-
# If still not found, scan for any file containing @asgi_app()
|
|
813
|
-
if not app_path:
|
|
814
|
-
found = _find_asgi_apps(Path(os.getcwd()))
|
|
815
|
-
if found:
|
|
816
|
-
print("Select a Modal ASGI app to deploy:")
|
|
817
|
-
for idx, pth in enumerate(found, 1):
|
|
818
|
-
rel = os.path.relpath(str(pth), os.getcwd())
|
|
819
|
-
print(f" [{idx}] {rel}")
|
|
820
|
-
try:
|
|
821
|
-
sel = (
|
|
822
|
-
input(f"Enter choice [1-{len(found)}] (default 1): ").strip() or "1"
|
|
823
|
-
)
|
|
824
|
-
except Exception:
|
|
825
|
-
sel = "1"
|
|
826
|
-
try:
|
|
827
|
-
choice = int(sel)
|
|
828
|
-
except Exception:
|
|
829
|
-
choice = 1
|
|
830
|
-
choice = max(1, min(choice, len(found)))
|
|
831
|
-
app_path = str(found[choice - 1].resolve())
|
|
832
|
-
if not app_path and script:
|
|
833
|
-
# Legacy script fallback if user supplied --script explicitly
|
|
834
|
-
from synth_ai.demos.demo_task_apps.math.deploy_modal import deploy as modal_deploy
|
|
835
|
-
|
|
836
|
-
url = modal_deploy(script_path=script, env_api_key=env.env_api_key)
|
|
837
|
-
if name:
|
|
838
|
-
app_name = name
|
|
839
|
-
else:
|
|
840
|
-
if not app_path:
|
|
841
|
-
entered = input("Path to Modal app.py (e.g., ./task_app.py): ").strip()
|
|
842
|
-
if not entered:
|
|
843
|
-
raise FileNotFoundError("No app.py path provided and auto-detect failed")
|
|
844
|
-
app_path = os.path.abspath(entered)
|
|
845
|
-
if not os.path.isfile(app_path):
|
|
846
|
-
raise FileNotFoundError(f"App file not found: {app_path}")
|
|
847
|
-
# Surface the app path before asking for the name
|
|
848
|
-
print(f"Using task app: {app_path}")
|
|
849
|
-
existing_name = (name or env.task_app_name or "").strip()
|
|
850
|
-
if not existing_name:
|
|
851
|
-
existing_name = f"synth-{os.path.splitext(os.path.basename(app_path))[0]}"
|
|
852
|
-
suggested_name = existing_name
|
|
853
|
-
name_in = input(f"Modal app name [{suggested_name}]: ").strip() or suggested_name
|
|
854
|
-
app_name = name_in
|
|
855
|
-
print("\nAbout to deploy with:")
|
|
856
|
-
print(f" app.py: {app_path}")
|
|
857
|
-
print(f" name: {name_in}")
|
|
858
|
-
proceed = (input("Proceed? [Y/n]: ").strip().lower() or "y").startswith("y")
|
|
859
|
-
if not proceed:
|
|
860
|
-
print("Aborted by user.")
|
|
861
|
-
return 1
|
|
862
|
-
|
|
863
|
-
existing_env_key = (env.env_api_key or "").strip()
|
|
864
|
-
env_key: str | None = existing_env_key or None
|
|
865
|
-
if existing_env_key:
|
|
866
|
-
try:
|
|
867
|
-
reuse_choice = (
|
|
868
|
-
input("Use existing ENVIRONMENT_API_KEY from state/.env? [Y/n]: ")
|
|
869
|
-
.strip()
|
|
870
|
-
.lower()
|
|
871
|
-
or "y"
|
|
872
|
-
)
|
|
873
|
-
except Exception:
|
|
874
|
-
reuse_choice = "y"
|
|
875
|
-
if not reuse_choice.startswith("y"):
|
|
876
|
-
env_key = None
|
|
877
|
-
|
|
878
|
-
if env_key is None:
|
|
879
|
-
from synth_ai.learning.rl.secrets import mint_environment_api_key
|
|
880
|
-
|
|
881
|
-
env_key = mint_environment_api_key()
|
|
882
|
-
demo_core.persist_env_api_key(env_key)
|
|
883
|
-
demo_core.persist_dotenv_values({"ENVIRONMENT_API_KEY": env_key})
|
|
884
|
-
os.environ["ENVIRONMENT_API_KEY"] = env_key
|
|
885
|
-
env.env_api_key = env_key
|
|
886
|
-
local_env["ENVIRONMENT_API_KEY"] = env_key
|
|
887
|
-
print("[deploy] Minted new ENVIRONMENT_API_KEY")
|
|
888
|
-
elif env_key:
|
|
889
|
-
os.environ["ENVIRONMENT_API_KEY"] = env_key
|
|
890
|
-
|
|
891
|
-
# Optionally upload the new key to the backend using sealed box helper
|
|
892
|
-
backend_base = (env.dev_backend_url or "").rstrip("/")
|
|
893
|
-
synth_key = (
|
|
894
|
-
env.synth_api_key
|
|
895
|
-
or os.environ.get("SYNTH_API_KEY")
|
|
896
|
-
or local_env.get("SYNTH_API_KEY")
|
|
897
|
-
or ""
|
|
898
|
-
).strip()
|
|
899
|
-
if backend_base and synth_key:
|
|
900
|
-
# Pass a base WITHOUT trailing /api to setup_environment_api_key,
|
|
901
|
-
# since it appends /api/v1/... internally.
|
|
902
|
-
non_api_base = (
|
|
903
|
-
backend_base[:-4] if backend_base.endswith("/api") else backend_base
|
|
904
|
-
)
|
|
905
|
-
try:
|
|
906
|
-
choice = (
|
|
907
|
-
input(f"Upload ENVIRONMENT_API_KEY to backend {non_api_base}? [Y/n]: ")
|
|
908
|
-
.strip()
|
|
909
|
-
.lower()
|
|
910
|
-
or "y"
|
|
911
|
-
)
|
|
912
|
-
except Exception:
|
|
913
|
-
choice = "y"
|
|
914
|
-
if choice.startswith("y"):
|
|
915
|
-
try:
|
|
916
|
-
print(f"[deploy] Uploading ENVIRONMENT_API_KEY to {non_api_base} …")
|
|
917
|
-
from synth_ai.learning.rl.env_keys import setup_environment_api_key
|
|
918
|
-
|
|
919
|
-
setup_environment_api_key(non_api_base, synth_key, token=env_key)
|
|
920
|
-
print("[deploy] Backend sealed-box upload complete.")
|
|
921
|
-
except Exception as upload_err:
|
|
922
|
-
print(f"[deploy] Failed to upload ENVIRONMENT_API_KEY: {upload_err}")
|
|
923
|
-
print(
|
|
924
|
-
'Hint: run `uvx python -c "from synth_ai.learning.rl.env_keys import setup_environment_api_key as s;'
|
|
925
|
-
" s('<backend>', '<synth_api_key>')\"` once the backend is reachable."
|
|
926
|
-
)
|
|
927
|
-
|
|
928
|
-
synth_key = (
|
|
929
|
-
env.synth_api_key
|
|
930
|
-
or os.environ.get("SYNTH_API_KEY")
|
|
931
|
-
or local_env.get("SYNTH_API_KEY")
|
|
932
|
-
or ""
|
|
933
|
-
).strip()
|
|
934
|
-
if not synth_key:
|
|
935
|
-
synth_key = input("Enter SYNTH_API_KEY for deployment (required): ").strip()
|
|
936
|
-
if not synth_key:
|
|
937
|
-
print("SYNTH_API_KEY is required for deployment.")
|
|
938
|
-
return 1
|
|
939
|
-
demo_core.persist_api_key(synth_key)
|
|
940
|
-
demo_core.persist_dotenv_values({"SYNTH_API_KEY": synth_key})
|
|
941
|
-
env.synth_api_key = synth_key
|
|
942
|
-
os.environ["SYNTH_API_KEY"] = synth_key
|
|
943
|
-
|
|
944
|
-
openai_key = (
|
|
945
|
-
os.environ.get("OPENAI_API_KEY") or local_env.get("OPENAI_API_KEY") or ""
|
|
946
|
-
).strip()
|
|
947
|
-
if not openai_key:
|
|
948
|
-
openai_key = input(
|
|
949
|
-
"Enter your OpenAI API key, found at https://platform.openai.com/api-keys\n> "
|
|
950
|
-
).strip()
|
|
951
|
-
if not openai_key:
|
|
952
|
-
print("OPENAI_API_KEY is required for deployment.")
|
|
953
|
-
return 1
|
|
954
|
-
demo_core.persist_dotenv_values({"OPENAI_API_KEY": openai_key})
|
|
955
|
-
local_env["OPENAI_API_KEY"] = openai_key
|
|
956
|
-
os.environ["OPENAI_API_KEY"] = openai_key
|
|
957
|
-
|
|
958
|
-
deploy_cmd = [
|
|
959
|
-
"uv",
|
|
960
|
-
"run",
|
|
961
|
-
"python",
|
|
962
|
-
"-m",
|
|
963
|
-
"modal",
|
|
964
|
-
"deploy",
|
|
965
|
-
"--name",
|
|
966
|
-
name_in,
|
|
967
|
-
app_path,
|
|
968
|
-
]
|
|
969
|
-
print(
|
|
970
|
-
"\nStreaming Modal build/deploy logs (this can take several minutes on first run)…\n"
|
|
971
|
-
)
|
|
972
|
-
code, deploy_logs = _popen_stream_capture(deploy_cmd)
|
|
973
|
-
if code != 0:
|
|
974
|
-
raise RuntimeError(f"modal deploy failed (exit {code})")
|
|
975
|
-
# Try to parse URL directly from streamed logs
|
|
976
|
-
if not url:
|
|
977
|
-
try:
|
|
978
|
-
import re as _re
|
|
979
|
-
|
|
980
|
-
m_all = _re.findall(r"https?://[^\s]+\.modal\.run", deploy_logs or "")
|
|
981
|
-
if m_all:
|
|
982
|
-
url = m_all[-1].strip().rstrip("/")
|
|
983
|
-
except Exception:
|
|
984
|
-
pass
|
|
985
|
-
url_cmd = ["uv", "run", "python", "-m", "modal", "app", "url", name_in]
|
|
986
|
-
code2, out2 = _popen_capture(url_cmd)
|
|
987
|
-
if code2 == 0:
|
|
988
|
-
for token in out2.split():
|
|
989
|
-
if _is_modal_public_url(token):
|
|
990
|
-
url = token.strip().rstrip("/")
|
|
991
|
-
break
|
|
992
|
-
# Fallback: try reading recent Modal logs for the app to find a URL line
|
|
993
|
-
if not url:
|
|
994
|
-
code3, out3 = _popen_capture(
|
|
995
|
-
["uv", "run", "python", "-m", "modal", "app", "list"]
|
|
996
|
-
)
|
|
997
|
-
if code3 == 0 and out3:
|
|
998
|
-
for line in out3.splitlines():
|
|
999
|
-
if name_in in line:
|
|
1000
|
-
for token in line.split():
|
|
1001
|
-
if _is_modal_public_url(token):
|
|
1002
|
-
url = token.strip().rstrip("/")
|
|
1003
|
-
break
|
|
1004
|
-
if url:
|
|
1005
|
-
break
|
|
1006
|
-
# Prompt user if still no valid URL
|
|
1007
|
-
if not url:
|
|
1008
|
-
print("\nCould not auto-detect a public Modal URL for the app.")
|
|
1009
|
-
entered = input(
|
|
1010
|
-
"Enter the Modal public URL (must contain '.modal.run'), or press Enter to abort: "
|
|
1011
|
-
).strip()
|
|
1012
|
-
if entered and _is_modal_public_url(entered):
|
|
1013
|
-
url = entered.rstrip("/")
|
|
1014
|
-
if not url:
|
|
1015
|
-
raise RuntimeError("Failed to resolve public URL from modal CLI output")
|
|
1016
|
-
if not url:
|
|
1017
|
-
print("Failed to determine Task App URL")
|
|
1018
|
-
return 2
|
|
1019
|
-
demo_core.persist_task_url(url, name=app_name or None)
|
|
1020
|
-
dotenv_values = {"TASK_APP_BASE_URL": url}
|
|
1021
|
-
if app_name:
|
|
1022
|
-
dotenv_values["TASK_APP_NAME"] = app_name
|
|
1023
|
-
dotenv_values["TASK_APP_SECRET_NAME"] = DEFAULT_TASK_APP_SECRET_NAME
|
|
1024
|
-
dotenv_path = demo_core.persist_dotenv_values(dotenv_values)
|
|
1025
|
-
print(f"TASK_APP_BASE_URL={url}")
|
|
1026
|
-
if app_name:
|
|
1027
|
-
print(f"TASK_APP_NAME={app_name}")
|
|
1028
|
-
print("Export for this shell:")
|
|
1029
|
-
print(f" export TASK_APP_BASE_URL={url}")
|
|
1030
|
-
if app_name:
|
|
1031
|
-
print(f" export TASK_APP_NAME={app_name}")
|
|
1032
|
-
print(f"Persisted to {dotenv_path}")
|
|
1033
|
-
print("\nNext step:\n$ uvx synth-ai run")
|
|
1034
|
-
return 0
|
|
1035
|
-
except Exception as e:
|
|
1036
|
-
print(f"Deploy error: {e}")
|
|
1037
|
-
return 2
|
|
1038
|
-
|
|
1039
|
-
print(
|
|
1040
|
-
"`rl_demo configure` prepares environment and secrets; `synth-ai run` now handles launches."
|
|
1041
|
-
)
|
|
1042
|
-
env = demo_core.load_env()
|
|
1043
|
-
synth_key = (env.synth_api_key or "").strip()
|
|
1044
|
-
if not synth_key:
|
|
1045
|
-
entered = input("Enter SYNTH_API_KEY (required): ").strip()
|
|
1046
|
-
if not entered:
|
|
1047
|
-
print("SYNTH_API_KEY is required.")
|
|
1048
|
-
return 1
|
|
1049
|
-
os.environ["SYNTH_API_KEY"] = entered
|
|
1050
|
-
demo_core.persist_api_key(entered)
|
|
1051
|
-
demo_core.persist_dotenv_values({"SYNTH_API_KEY": entered})
|
|
1052
|
-
env = demo_core.load_env()
|
|
1053
|
-
synth_key = (env.synth_api_key or "").strip()
|
|
1054
|
-
if not env.dev_backend_url:
|
|
1055
|
-
print("Backend URL missing. Set DEV_BACKEND_URL or BACKEND_OVERRIDE.")
|
|
1056
|
-
return 1
|
|
1057
|
-
try:
|
|
1058
|
-
env = _ensure_task_app_ready(env, synth_key, label="configure")
|
|
1059
|
-
except RuntimeError as exc:
|
|
1060
|
-
print(exc)
|
|
1061
|
-
return 1
|
|
1062
|
-
os.environ["ENVIRONMENT_API_KEY"] = env.env_api_key
|
|
1063
|
-
try:
|
|
1064
|
-
review = input("Review or create an RL config now? [Y/n]: ").strip().lower() or "y"
|
|
1065
|
-
except Exception:
|
|
1066
|
-
review = "y"
|
|
1067
|
-
if review.startswith("y"):
|
|
1068
|
-
_select_or_create_config(None, env)
|
|
1069
|
-
print("Environment ready. Use `uvx synth-ai run` to launch an RL job.")
|
|
1070
|
-
return 0
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
def _ensure_modal_installed() -> None:
|
|
1074
|
-
"""Install the modal package if it is not already available and check authentication."""
|
|
1075
|
-
|
|
1076
|
-
# Check if modal is installed
|
|
1077
|
-
modal_installed = False
|
|
1078
|
-
try:
|
|
1079
|
-
import importlib.util as _iu
|
|
1080
|
-
|
|
1081
|
-
if _iu.find_spec("modal") is not None:
|
|
1082
|
-
modal_installed = True
|
|
1083
|
-
except Exception:
|
|
1084
|
-
pass
|
|
1085
|
-
|
|
1086
|
-
# Install modal if needed
|
|
1087
|
-
if not modal_installed:
|
|
1088
|
-
print("modal not found; installing…")
|
|
1089
|
-
try:
|
|
1090
|
-
if shutil.which("uv"):
|
|
1091
|
-
code, out = _popen_capture(["uv", "pip", "install", "modal>=1.1.4"])
|
|
1092
|
-
else:
|
|
1093
|
-
code, out = _popen_capture([sys.executable, "-m", "pip", "install", "modal>=1.1.4"])
|
|
1094
|
-
if code != 0:
|
|
1095
|
-
print(out)
|
|
1096
|
-
print("Failed to install modal; continuing may fail.")
|
|
1097
|
-
return
|
|
1098
|
-
else:
|
|
1099
|
-
print("✓ modal installed successfully")
|
|
1100
|
-
modal_installed = True
|
|
1101
|
-
except Exception as exc:
|
|
1102
|
-
print(f"modal install error: {exc}")
|
|
1103
|
-
return
|
|
1104
|
-
|
|
1105
|
-
# Verify modal is importable
|
|
1106
|
-
if modal_installed:
|
|
1107
|
-
try:
|
|
1108
|
-
import importlib.util as _iu
|
|
1109
|
-
|
|
1110
|
-
if _iu.find_spec("modal") is None:
|
|
1111
|
-
print("Warning: modal is still not importable after install attempt.")
|
|
1112
|
-
return
|
|
1113
|
-
except Exception:
|
|
1114
|
-
print("Warning: unable to verify modal installation.")
|
|
1115
|
-
return
|
|
1116
|
-
|
|
1117
|
-
# Check modal authentication status
|
|
1118
|
-
auth_ok, auth_msg = demo_core.modal_auth_status()
|
|
1119
|
-
if auth_ok:
|
|
1120
|
-
print(f"✓ Modal authenticated: {auth_msg}")
|
|
1121
|
-
else:
|
|
1122
|
-
print("\n⚠️ Modal authentication required")
|
|
1123
|
-
print(f" Status: {auth_msg}")
|
|
1124
|
-
print("\n To authenticate Modal, run:")
|
|
1125
|
-
print(" modal setup")
|
|
1126
|
-
print("\n Or set environment variables:")
|
|
1127
|
-
print(" export MODAL_TOKEN_ID=your-token-id")
|
|
1128
|
-
print(" export MODAL_TOKEN_SECRET=your-token-secret")
|
|
1129
|
-
print("\n You can deploy later after authenticating.\n")
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
def init(template: str | None = None, dest: str | None = None, force: bool = False) -> int:
|
|
1133
|
-
"""Materialise a demo task app template into the current directory."""
|
|
1134
|
-
|
|
1135
|
-
templates = list(list_demo_templates())
|
|
1136
|
-
if not templates:
|
|
1137
|
-
print("No demo templates registered. Update synth_ai/demo_registry.py to add entries.")
|
|
1138
|
-
return 1
|
|
1139
|
-
|
|
1140
|
-
selected: DemoTemplate | None = None
|
|
1141
|
-
if template:
|
|
1142
|
-
selected = get_demo_template(template)
|
|
1143
|
-
if selected is None:
|
|
1144
|
-
available = ", ".join(t.template_id for t in templates)
|
|
1145
|
-
print(f"Unknown template '{template}'. Available: {available}")
|
|
1146
|
-
return 1
|
|
1147
|
-
else:
|
|
1148
|
-
if force:
|
|
1149
|
-
selected = templates[0]
|
|
1150
|
-
print(
|
|
1151
|
-
f"Using default template: {selected.name} ({selected.template_id}) "
|
|
1152
|
-
f"(pass --template to choose another)"
|
|
1153
|
-
)
|
|
1154
|
-
else:
|
|
1155
|
-
print("Select a demo template:" + "\n")
|
|
1156
|
-
for idx, tpl in enumerate(templates, start=1):
|
|
1157
|
-
print(f" [{idx}] {tpl.name} ({tpl.template_id})")
|
|
1158
|
-
print(f" {tpl.description}")
|
|
1159
|
-
try:
|
|
1160
|
-
choice_raw = input(f"Enter choice [1-{len(templates)}] (default 1): ").strip() or "1"
|
|
1161
|
-
except Exception:
|
|
1162
|
-
choice_raw = "1"
|
|
1163
|
-
if not choice_raw.isdigit():
|
|
1164
|
-
print("Selection must be a number.")
|
|
1165
|
-
return 1
|
|
1166
|
-
choice_idx = int(choice_raw)
|
|
1167
|
-
if not 1 <= choice_idx <= len(templates):
|
|
1168
|
-
print("Selection out of range.")
|
|
1169
|
-
return 1
|
|
1170
|
-
selected = templates[choice_idx - 1]
|
|
1171
|
-
|
|
1172
|
-
assert selected is not None
|
|
1173
|
-
|
|
1174
|
-
default_subdir = selected.default_subdir or selected.template_id
|
|
1175
|
-
|
|
1176
|
-
# Check if default destination is already occupied and switch to local_demos/ if needed
|
|
1177
|
-
if dest:
|
|
1178
|
-
default_dest = Path(dest).expanduser().resolve()
|
|
1179
|
-
else:
|
|
1180
|
-
primary_dest = Path.cwd() / default_subdir
|
|
1181
|
-
if primary_dest.exists() and any(primary_dest.iterdir()):
|
|
1182
|
-
# Switch to local_demos/ automatically if primary location is occupied
|
|
1183
|
-
default_dest = (Path.cwd() / "local_demos" / default_subdir).resolve()
|
|
1184
|
-
else:
|
|
1185
|
-
default_dest = primary_dest.resolve()
|
|
1186
|
-
|
|
1187
|
-
if force:
|
|
1188
|
-
dest_input = ""
|
|
1189
|
-
else:
|
|
1190
|
-
try:
|
|
1191
|
-
dest_input = input(f"Destination directory [{default_dest}]: ").strip()
|
|
1192
|
-
except Exception:
|
|
1193
|
-
dest_input = ""
|
|
1194
|
-
destination = Path(dest_input).expanduser().resolve() if dest_input else default_dest
|
|
1195
|
-
|
|
1196
|
-
# Track whether we should skip individual file prompts (if we already cleared the directory)
|
|
1197
|
-
directory_cleared = False
|
|
1198
|
-
|
|
1199
|
-
if destination.exists():
|
|
1200
|
-
if destination.is_file():
|
|
1201
|
-
print(f"Destination {destination} is a file. Provide a directory path.")
|
|
1202
|
-
return 1
|
|
1203
|
-
if any(destination.iterdir()):
|
|
1204
|
-
if force:
|
|
1205
|
-
response = "y"
|
|
1206
|
-
else:
|
|
1207
|
-
try:
|
|
1208
|
-
response = (
|
|
1209
|
-
input(f"Destination {destination} is not empty. Overwrite? [y/N]: ")
|
|
1210
|
-
.strip()
|
|
1211
|
-
.lower()
|
|
1212
|
-
)
|
|
1213
|
-
except (EOFError, KeyboardInterrupt):
|
|
1214
|
-
print("\nCancelled.")
|
|
1215
|
-
return 1
|
|
1216
|
-
if response not in ("y", "yes"):
|
|
1217
|
-
print("Cancelled. Choose another directory or delete the existing one.")
|
|
1218
|
-
return 1
|
|
1219
|
-
# User agreed to overwrite - clear the entire directory including hidden files
|
|
1220
|
-
print(f"Clearing {destination}...")
|
|
1221
|
-
try:
|
|
1222
|
-
# Remove all contents including hidden files (.env, .git, etc.)
|
|
1223
|
-
shutil.rmtree(destination)
|
|
1224
|
-
except Exception as e:
|
|
1225
|
-
print(f"Error clearing directory: {e}")
|
|
1226
|
-
print("Please manually remove the directory and try again.")
|
|
1227
|
-
return 1
|
|
1228
|
-
# Recreate empty directory
|
|
1229
|
-
destination.mkdir(parents=True, exist_ok=True)
|
|
1230
|
-
# Verify it's actually empty
|
|
1231
|
-
if any(destination.iterdir()):
|
|
1232
|
-
print(f"Warning: Directory {destination} still contains files after clearing.")
|
|
1233
|
-
print("Some files may not have been removed. Please check manually.")
|
|
1234
|
-
return 1
|
|
1235
|
-
directory_cleared = True
|
|
1236
|
-
else:
|
|
1237
|
-
destination.mkdir(parents=True, exist_ok=True)
|
|
1238
|
-
|
|
1239
|
-
if selected.requires_modal:
|
|
1240
|
-
_ensure_modal_installed()
|
|
1241
|
-
|
|
1242
|
-
try:
|
|
1243
|
-
for spec in selected.iter_copy_specs():
|
|
1244
|
-
src_path = spec.absolute_source()
|
|
1245
|
-
if not src_path.exists():
|
|
1246
|
-
print(f"Template source missing: {src_path}")
|
|
1247
|
-
return 1
|
|
1248
|
-
dest_path = (destination / spec.destination).resolve()
|
|
1249
|
-
|
|
1250
|
-
# Handle directory copying
|
|
1251
|
-
if src_path.is_dir():
|
|
1252
|
-
if dest_path.exists() and not directory_cleared:
|
|
1253
|
-
if force:
|
|
1254
|
-
response = "y"
|
|
1255
|
-
else:
|
|
1256
|
-
try:
|
|
1257
|
-
response = (
|
|
1258
|
-
input(f"Directory {dest_path.name} exists. Overwrite? [y/N]: ")
|
|
1259
|
-
.strip()
|
|
1260
|
-
.lower()
|
|
1261
|
-
)
|
|
1262
|
-
except (EOFError, KeyboardInterrupt):
|
|
1263
|
-
print("\nCancelled.")
|
|
1264
|
-
return 1
|
|
1265
|
-
if response not in ("y", "yes"):
|
|
1266
|
-
print(f"Skipping {dest_path.name}")
|
|
1267
|
-
continue
|
|
1268
|
-
shutil.rmtree(dest_path)
|
|
1269
|
-
elif dest_path.exists() and directory_cleared:
|
|
1270
|
-
shutil.rmtree(dest_path)
|
|
1271
|
-
shutil.copytree(src_path, dest_path)
|
|
1272
|
-
else:
|
|
1273
|
-
# Handle file copying
|
|
1274
|
-
dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1275
|
-
if dest_path.exists() and not directory_cleared:
|
|
1276
|
-
if force:
|
|
1277
|
-
response = "y"
|
|
1278
|
-
else:
|
|
1279
|
-
try:
|
|
1280
|
-
response = (
|
|
1281
|
-
input(f"File {dest_path.name} exists. Overwrite? [y/N]: ")
|
|
1282
|
-
.strip()
|
|
1283
|
-
.lower()
|
|
1284
|
-
)
|
|
1285
|
-
except (EOFError, KeyboardInterrupt):
|
|
1286
|
-
print("\nCancelled.")
|
|
1287
|
-
return 1
|
|
1288
|
-
if response not in ("y", "yes"):
|
|
1289
|
-
print(f"Skipping {dest_path.name}")
|
|
1290
|
-
continue
|
|
1291
|
-
shutil.copy2(src_path, dest_path)
|
|
1292
|
-
if spec.make_executable:
|
|
1293
|
-
try:
|
|
1294
|
-
st = os.stat(dest_path)
|
|
1295
|
-
os.chmod(dest_path, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
1296
|
-
except Exception:
|
|
1297
|
-
pass
|
|
1298
|
-
|
|
1299
|
-
if selected.env_lines:
|
|
1300
|
-
env_path = destination / ".env"
|
|
1301
|
-
should_write = True
|
|
1302
|
-
if env_path.exists() and not directory_cleared:
|
|
1303
|
-
if force:
|
|
1304
|
-
response = "y"
|
|
1305
|
-
else:
|
|
1306
|
-
try:
|
|
1307
|
-
response = input("File .env exists. Overwrite? [y/N]: ").strip().lower()
|
|
1308
|
-
except (EOFError, KeyboardInterrupt):
|
|
1309
|
-
print("\nCancelled.")
|
|
1310
|
-
return 1
|
|
1311
|
-
should_write = response in ("y", "yes")
|
|
1312
|
-
if should_write:
|
|
1313
|
-
_write_text(env_path, "\n".join(selected.env_lines) + "\n")
|
|
1314
|
-
elif not directory_cleared:
|
|
1315
|
-
print("Skipping .env")
|
|
1316
|
-
|
|
1317
|
-
config_src = selected.config_source_path()
|
|
1318
|
-
if config_src and config_src.exists():
|
|
1319
|
-
cfg_dst = (destination / selected.config_destination).resolve()
|
|
1320
|
-
should_copy = True
|
|
1321
|
-
if cfg_dst.exists() and not directory_cleared:
|
|
1322
|
-
if force:
|
|
1323
|
-
response = "y"
|
|
1324
|
-
else:
|
|
1325
|
-
try:
|
|
1326
|
-
response = (
|
|
1327
|
-
input(f"File {cfg_dst.name} exists. Overwrite? [y/N]: ").strip().lower()
|
|
1328
|
-
)
|
|
1329
|
-
except (EOFError, KeyboardInterrupt):
|
|
1330
|
-
print("\nCancelled.")
|
|
1331
|
-
return 1
|
|
1332
|
-
should_copy = response in ("y", "yes")
|
|
1333
|
-
if should_copy:
|
|
1334
|
-
cfg_dst.parent.mkdir(parents=True, exist_ok=True)
|
|
1335
|
-
shutil.copy2(config_src, cfg_dst)
|
|
1336
|
-
elif not directory_cleared:
|
|
1337
|
-
print(f"Skipping {cfg_dst.name}")
|
|
1338
|
-
|
|
1339
|
-
if selected.post_copy is not None:
|
|
1340
|
-
try:
|
|
1341
|
-
selected.post_copy(destination)
|
|
1342
|
-
except Exception as post_exc:
|
|
1343
|
-
print(f"Post-processing failed: {post_exc}")
|
|
1344
|
-
return 1
|
|
1345
|
-
|
|
1346
|
-
# Store demo directory for subsequent commands
|
|
1347
|
-
demo_core.persist_demo_dir(str(destination))
|
|
1348
|
-
|
|
1349
|
-
# Store .env path if it was created
|
|
1350
|
-
env_file = destination / ".env"
|
|
1351
|
-
if env_file.exists():
|
|
1352
|
-
demo_core.persist_env_file_path(str(env_file))
|
|
1353
|
-
|
|
1354
|
-
print(f"Demo template '{selected.name}' materialised at {destination}.")
|
|
1355
|
-
print("Files created:")
|
|
1356
|
-
for spec in selected.iter_copy_specs():
|
|
1357
|
-
print(f" - {spec.destination}")
|
|
1358
|
-
if selected.env_lines:
|
|
1359
|
-
print(" - .env")
|
|
1360
|
-
if selected.config_source_path():
|
|
1361
|
-
print(f" - {selected.config_destination}")
|
|
1362
|
-
print("\nDemo directory stored. Subsequent commands will use this directory automatically.")
|
|
1363
|
-
print("Review the files, edit .env, and run any provided deploy scripts when ready.")
|
|
1364
|
-
return 0
|
|
1365
|
-
except KeyboardInterrupt:
|
|
1366
|
-
print("Aborted")
|
|
1367
|
-
return 1
|
|
1368
|
-
except Exception as exc:
|
|
1369
|
-
print(f"Init failed: {exc}")
|
|
1370
|
-
return 1
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
def _http(
|
|
1374
|
-
method: str, url: str, headers: dict[str, str] | None = None, body: dict[str, Any] | None = None
|
|
1375
|
-
) -> tuple[int, dict[str, Any] | str]:
|
|
1376
|
-
import json as _json
|
|
1377
|
-
import ssl
|
|
1378
|
-
import urllib.error
|
|
1379
|
-
import urllib.request
|
|
1380
|
-
|
|
1381
|
-
data = None
|
|
1382
|
-
if body is not None:
|
|
1383
|
-
data = _json.dumps(body).encode("utf-8")
|
|
1384
|
-
req = urllib.request.Request(url, method=method, headers=headers or {}, data=data)
|
|
1385
|
-
try:
|
|
1386
|
-
# Default: disable SSL verification for local/dev convenience.
|
|
1387
|
-
# Set SYNTH_SSL_VERIFY=1 to enable verification.
|
|
1388
|
-
ctx = ssl._create_unverified_context() # nosec: disabled by default for dev
|
|
1389
|
-
if os.getenv("SYNTH_SSL_VERIFY", "0") == "1":
|
|
1390
|
-
ctx = None
|
|
1391
|
-
with urllib.request.urlopen(req, timeout=60, context=ctx) as resp:
|
|
1392
|
-
code = getattr(resp, "status", 200)
|
|
1393
|
-
txt = resp.read().decode("utf-8", errors="ignore")
|
|
1394
|
-
try:
|
|
1395
|
-
return int(code), _json.loads(txt)
|
|
1396
|
-
except Exception:
|
|
1397
|
-
return int(code), txt
|
|
1398
|
-
except urllib.error.HTTPError as he: # Capture 4xx/5xx bodies
|
|
1399
|
-
txt = he.read().decode("utf-8", errors="ignore")
|
|
1400
|
-
try:
|
|
1401
|
-
return int(he.code or 0), _json.loads(txt)
|
|
1402
|
-
except Exception:
|
|
1403
|
-
return int(he.code or 0), txt
|
|
1404
|
-
except Exception as e:
|
|
1405
|
-
return 0, str(e)
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
def _write_text(path: str, content: str) -> None:
|
|
1409
|
-
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
1410
|
-
with open(path, "w") as fh:
|
|
1411
|
-
fh.write(content)
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
# Note: `prepare` command has been removed; configuration now prepares TOML
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
def run(
|
|
1418
|
-
config: str | None = None,
|
|
1419
|
-
batch_size: int | None = None,
|
|
1420
|
-
group_size: int | None = None,
|
|
1421
|
-
model: str | None = None,
|
|
1422
|
-
timeout: int = 600,
|
|
1423
|
-
dry_run: bool = False,
|
|
1424
|
-
) -> int:
|
|
1425
|
-
# Change to demo directory if stored
|
|
1426
|
-
demo_dir = demo_core.load_demo_dir()
|
|
1427
|
-
if demo_dir and os.path.isdir(demo_dir):
|
|
1428
|
-
os.chdir(demo_dir)
|
|
1429
|
-
print(f"Using demo directory: {demo_dir}")
|
|
1430
|
-
|
|
1431
|
-
env = demo_core.load_env()
|
|
1432
|
-
cwd_env_path = os.path.join(os.getcwd(), ".env")
|
|
1433
|
-
demo_core.load_dotenv_file(cwd_env_path)
|
|
1434
|
-
|
|
1435
|
-
synth_key = (env.synth_api_key or "").strip()
|
|
1436
|
-
if not synth_key:
|
|
1437
|
-
entered = input("Enter SYNTH_API_KEY (required): ").strip()
|
|
1438
|
-
if not entered:
|
|
1439
|
-
print("SYNTH_API_KEY is required.")
|
|
1440
|
-
return 1
|
|
1441
|
-
os.environ["SYNTH_API_KEY"] = entered
|
|
1442
|
-
demo_core.persist_api_key(entered)
|
|
1443
|
-
demo_core.persist_dotenv_values({"SYNTH_API_KEY": entered})
|
|
1444
|
-
env = demo_core.load_env()
|
|
1445
|
-
synth_key = (env.synth_api_key or "").strip()
|
|
1446
|
-
if not synth_key:
|
|
1447
|
-
print("SYNTH_API_KEY missing after persist.")
|
|
1448
|
-
return 1
|
|
1449
|
-
|
|
1450
|
-
if not env.dev_backend_url:
|
|
1451
|
-
print("Backend URL missing. Set DEV_BACKEND_URL or BACKEND_OVERRIDE.")
|
|
1452
|
-
return 1
|
|
1453
|
-
|
|
1454
|
-
try:
|
|
1455
|
-
env = _ensure_task_app_ready(env, synth_key, label="run")
|
|
1456
|
-
except RuntimeError as exc:
|
|
1457
|
-
print(exc)
|
|
1458
|
-
return 1
|
|
1459
|
-
|
|
1460
|
-
os.environ["ENVIRONMENT_API_KEY"] = env.env_api_key
|
|
1461
|
-
|
|
1462
|
-
import tomllib
|
|
1463
|
-
|
|
1464
|
-
try:
|
|
1465
|
-
cfg_path = _select_or_create_config(config, env)
|
|
1466
|
-
except FileNotFoundError as exc:
|
|
1467
|
-
print(exc)
|
|
1468
|
-
return 1
|
|
1469
|
-
|
|
1470
|
-
# Detect monorepo launcher and delegate if available (aligns with run_clustered.sh which works)
|
|
1471
|
-
launcher = "/Users/joshpurtell/Documents/GitHub/monorepo/tests/applications/math/rl/start_math_clustered.py"
|
|
1472
|
-
if os.path.isfile(launcher):
|
|
1473
|
-
backend_base = (
|
|
1474
|
-
env.dev_backend_url[:-4]
|
|
1475
|
-
if env.dev_backend_url.endswith("/api")
|
|
1476
|
-
else env.dev_backend_url
|
|
1477
|
-
)
|
|
1478
|
-
run_env = os.environ.copy()
|
|
1479
|
-
run_env["BACKEND_URL"] = backend_base
|
|
1480
|
-
run_env["SYNTH_API_KEY"] = env.synth_api_key
|
|
1481
|
-
run_env["TASK_APP_BASE_URL"] = env.task_app_base_url
|
|
1482
|
-
run_env["ENVIRONMENT_API_KEY"] = env.env_api_key
|
|
1483
|
-
run_env["RL_CONFIG_PATH"] = cfg_path
|
|
1484
|
-
# Optional: TRAINER_START_URL passthrough if already set in environment
|
|
1485
|
-
run_env["TRAINER_START_URL"] = run_env.get("TRAINER_START_URL", "")
|
|
1486
|
-
# Forward convenience knobs
|
|
1487
|
-
if batch_size is not None:
|
|
1488
|
-
run_env["RL_BATCH_SIZE"] = str(int(batch_size))
|
|
1489
|
-
if group_size is not None:
|
|
1490
|
-
run_env["RL_GROUP_SIZE"] = str(int(group_size))
|
|
1491
|
-
if model:
|
|
1492
|
-
run_env["RL_MODEL"] = model
|
|
1493
|
-
cmd = ["uv", "run", "python", launcher]
|
|
1494
|
-
print(f"Launching monorepo clustered runner: {' '.join(cmd)}")
|
|
1495
|
-
code = _popen_stream(cmd, env=run_env)
|
|
1496
|
-
if code != 0:
|
|
1497
|
-
print(f"Clustered runner exited with code {code}")
|
|
1498
|
-
# Actionable guidance for common auth issues
|
|
1499
|
-
try:
|
|
1500
|
-
base_url = backend_base.rstrip("/") + "/api"
|
|
1501
|
-
except Exception:
|
|
1502
|
-
base_url = backend_base
|
|
1503
|
-
sk = (env.synth_api_key or "").strip()
|
|
1504
|
-
ek = (env.env_api_key or "").strip()
|
|
1505
|
-
print("Hint: If backend responded 401, verify SYNTH_API_KEY for:", base_url)
|
|
1506
|
-
if sk:
|
|
1507
|
-
print(f" {_key_preview(sk, 'SYNTH_API_KEY')}")
|
|
1508
|
-
if ek:
|
|
1509
|
-
print(f" {_key_preview(ek, 'ENVIRONMENT_API_KEY')}")
|
|
1510
|
-
print(
|
|
1511
|
-
"Ensure the ENVIRONMENT_API_KEY you deployed with matches the task app and remains exported."
|
|
1512
|
-
)
|
|
1513
|
-
return code
|
|
1514
|
-
|
|
1515
|
-
# Fallback: legacy jobs API flow
|
|
1516
|
-
with open(cfg_path, "rb") as fh:
|
|
1517
|
-
inline_cfg = tomllib.load(fh)
|
|
1518
|
-
with open(cfg_path) as fh2:
|
|
1519
|
-
toml_text = fh2.read()
|
|
1520
|
-
if batch_size is not None:
|
|
1521
|
-
inline_cfg.setdefault("training", {})["batch_size"] = int(batch_size)
|
|
1522
|
-
if group_size is not None:
|
|
1523
|
-
inline_cfg.setdefault("training", {})["group_size"] = int(group_size)
|
|
1524
|
-
model_name = model or (inline_cfg.get("model", {}) or {}).get("name", "Qwen/Qwen3-0.6B")
|
|
1525
|
-
api = env.dev_backend_url.rstrip("/") + ("" if env.dev_backend_url.endswith("/api") else "/api")
|
|
1526
|
-
# Print backend and key preview before request for clearer diagnostics
|
|
1527
|
-
try:
|
|
1528
|
-
sk = (env.synth_api_key or "").strip()
|
|
1529
|
-
print(f"[run] Backend API: {api}")
|
|
1530
|
-
print(f"[run] {_key_preview(sk, 'SYNTH_API_KEY')}")
|
|
1531
|
-
except Exception:
|
|
1532
|
-
pass
|
|
1533
|
-
data_fragment: dict[str, Any] = {
|
|
1534
|
-
"model": model_name,
|
|
1535
|
-
"endpoint_base_url": env.task_app_base_url,
|
|
1536
|
-
"config": inline_cfg,
|
|
1537
|
-
"config_toml": toml_text,
|
|
1538
|
-
"config_source": "toml_inline",
|
|
1539
|
-
"metadata": {"source": "synth-ai rl_demo", "cwd": os.getcwd()},
|
|
1540
|
-
}
|
|
1541
|
-
if env.env_api_key:
|
|
1542
|
-
data_fragment["environment_api_key"] = env.env_api_key
|
|
1543
|
-
for k in ("training", "evaluation", "rollout", "topology", "vllm"):
|
|
1544
|
-
if isinstance(inline_cfg.get(k), dict):
|
|
1545
|
-
data_fragment[k] = inline_cfg[k]
|
|
1546
|
-
compute = {}
|
|
1547
|
-
if isinstance(inline_cfg.get("compute"), dict):
|
|
1548
|
-
if inline_cfg["compute"].get("gpu_type"):
|
|
1549
|
-
compute["gpu_type"] = str(inline_cfg["compute"]["gpu_type"]).upper()
|
|
1550
|
-
if inline_cfg["compute"].get("gpu_count"):
|
|
1551
|
-
compute["gpu_count"] = int(inline_cfg["compute"]["gpu_count"])
|
|
1552
|
-
if not compute:
|
|
1553
|
-
topo = inline_cfg.get("topology") or {}
|
|
1554
|
-
gshape = str(topo.get("gpu_type") or "")
|
|
1555
|
-
if ":" in gshape:
|
|
1556
|
-
t, c = gshape.split(":", 1)
|
|
1557
|
-
compute = {"gpu_type": t.upper(), "gpu_count": int(c)}
|
|
1558
|
-
body: dict[str, Any] = {
|
|
1559
|
-
"job_type": "rl",
|
|
1560
|
-
"data": data_fragment,
|
|
1561
|
-
}
|
|
1562
|
-
if compute:
|
|
1563
|
-
body["compute"] = compute
|
|
1564
|
-
code, js = _http(
|
|
1565
|
-
"POST",
|
|
1566
|
-
api + "/rl/jobs",
|
|
1567
|
-
headers={
|
|
1568
|
-
"Content-Type": "application/json",
|
|
1569
|
-
"Authorization": f"Bearer {env.synth_api_key}",
|
|
1570
|
-
},
|
|
1571
|
-
body=body,
|
|
1572
|
-
)
|
|
1573
|
-
if code not in (200, 201) or not isinstance(js, dict):
|
|
1574
|
-
print("Job create failed:", code)
|
|
1575
|
-
print(f"Backend: {api}")
|
|
1576
|
-
try:
|
|
1577
|
-
if isinstance(js, dict):
|
|
1578
|
-
print(json.dumps(js, indent=2))
|
|
1579
|
-
else:
|
|
1580
|
-
print(str(js))
|
|
1581
|
-
except Exception:
|
|
1582
|
-
print(str(js))
|
|
1583
|
-
print("Request body was:\n" + json.dumps(body, indent=2))
|
|
1584
|
-
try:
|
|
1585
|
-
auth_preview = _key_preview(env.synth_api_key or "", "SYNTH_API_KEY (auth)")
|
|
1586
|
-
print(f"[run] {auth_preview}")
|
|
1587
|
-
except Exception:
|
|
1588
|
-
pass
|
|
1589
|
-
try:
|
|
1590
|
-
data_block = body.get("data") if isinstance(body, dict) else None
|
|
1591
|
-
env_key_body = ""
|
|
1592
|
-
if isinstance(data_block, dict):
|
|
1593
|
-
env_key_body = str(data_block.get("environment_api_key") or "")
|
|
1594
|
-
if env_key_body:
|
|
1595
|
-
print(f"[run] {_key_preview(env_key_body, 'environment_api_key (body)')}")
|
|
1596
|
-
except Exception:
|
|
1597
|
-
pass
|
|
1598
|
-
try:
|
|
1599
|
-
current_env_key = env.env_api_key or ""
|
|
1600
|
-
if current_env_key:
|
|
1601
|
-
print(f"[run] {_key_preview(current_env_key, 'ENVIRONMENT_API_KEY (current)')}")
|
|
1602
|
-
except Exception:
|
|
1603
|
-
pass
|
|
1604
|
-
if isinstance(js, dict):
|
|
1605
|
-
detail = js.get("detail")
|
|
1606
|
-
if isinstance(detail, dict):
|
|
1607
|
-
try:
|
|
1608
|
-
sent_key = detail.get("sent_key")
|
|
1609
|
-
if isinstance(sent_key, str):
|
|
1610
|
-
print(
|
|
1611
|
-
f"[run] Backend detail.sent_key {_key_preview(sent_key, 'detail.sent_key')}"
|
|
1612
|
-
)
|
|
1613
|
-
except Exception:
|
|
1614
|
-
pass
|
|
1615
|
-
try:
|
|
1616
|
-
sent_keys = detail.get("sent_keys")
|
|
1617
|
-
if isinstance(sent_keys, list | tuple):
|
|
1618
|
-
previews = []
|
|
1619
|
-
for idx, val in enumerate(sent_keys):
|
|
1620
|
-
if isinstance(val, str):
|
|
1621
|
-
previews.append(_key_preview(val, f"detail.sent_keys[{idx}]"))
|
|
1622
|
-
if previews:
|
|
1623
|
-
joined = "; ".join(previews)
|
|
1624
|
-
print(f"[run] Backend detail.sent_keys previews: {joined}")
|
|
1625
|
-
except Exception:
|
|
1626
|
-
pass
|
|
1627
|
-
try:
|
|
1628
|
-
key_prefix = detail.get("sent_key_prefix")
|
|
1629
|
-
if isinstance(key_prefix, str):
|
|
1630
|
-
print(f"[run] Backend detail.sent_key_prefix={key_prefix}")
|
|
1631
|
-
except Exception:
|
|
1632
|
-
pass
|
|
1633
|
-
try:
|
|
1634
|
-
health_url = detail.get("health_url")
|
|
1635
|
-
if isinstance(health_url, str):
|
|
1636
|
-
print(f"[run] Backend detail.health_url={health_url}")
|
|
1637
|
-
except Exception:
|
|
1638
|
-
pass
|
|
1639
|
-
# Extra hints for auth failures
|
|
1640
|
-
try:
|
|
1641
|
-
sk = (env.synth_api_key or "").strip()
|
|
1642
|
-
if int(code) == 401 or (
|
|
1643
|
-
isinstance(js, dict)
|
|
1644
|
-
and any(isinstance(v, str) and "Invalid API key" in v for v in js.values())
|
|
1645
|
-
):
|
|
1646
|
-
base_url = env.dev_backend_url
|
|
1647
|
-
print(
|
|
1648
|
-
"Hint: HTTP 401 Unauthorized from backend. Verify SYNTH_API_KEY for:", base_url
|
|
1649
|
-
)
|
|
1650
|
-
if sk:
|
|
1651
|
-
print(f" {_key_preview(sk, 'SYNTH_API_KEY')}")
|
|
1652
|
-
print(
|
|
1653
|
-
"Ensure the ENVIRONMENT_API_KEY and OPENAI_API_KEY used for deployment remain valid."
|
|
1654
|
-
)
|
|
1655
|
-
except Exception:
|
|
1656
|
-
pass
|
|
1657
|
-
return 2
|
|
1658
|
-
job_id = js.get("job_id") or js.get("id") or ""
|
|
1659
|
-
if not job_id:
|
|
1660
|
-
print("Job id missing in response:", js)
|
|
1661
|
-
print("Request body was:\n" + json.dumps(body, indent=2))
|
|
1662
|
-
return 2
|
|
1663
|
-
print("JOB_ID:", job_id)
|
|
1664
|
-
# Original behavior: start job and stream status/events until terminal
|
|
1665
|
-
_http(
|
|
1666
|
-
"POST",
|
|
1667
|
-
api + f"/rl/jobs/{job_id}/start",
|
|
1668
|
-
headers={"Authorization": f"Bearer {env.synth_api_key}"},
|
|
1669
|
-
)
|
|
1670
|
-
# Inform the user immediately that the job has started and where to track it
|
|
1671
|
-
print("Your job is running. Visit usesynth.ai to view its progress")
|
|
1672
|
-
since = 0
|
|
1673
|
-
terminal = {"succeeded", "failed", "cancelled", "error", "completed"}
|
|
1674
|
-
last_status = ""
|
|
1675
|
-
start_t = time.time()
|
|
1676
|
-
while True:
|
|
1677
|
-
sc, sj = _http("GET", api + f"/learning/jobs/{job_id}")
|
|
1678
|
-
status = (sj.get("status") if isinstance(sj, dict) else "") if sc == 200 else ""
|
|
1679
|
-
if status and status != last_status:
|
|
1680
|
-
last_status = status
|
|
1681
|
-
print("status →", status)
|
|
1682
|
-
if status and status.lower() in terminal:
|
|
1683
|
-
print("FINAL:", status)
|
|
1684
|
-
break
|
|
1685
|
-
ec, ej = _http(
|
|
1686
|
-
"GET",
|
|
1687
|
-
api + f"/orchestration/jobs/{job_id}/events?since_seq={since}&limit=200",
|
|
1688
|
-
)
|
|
1689
|
-
if ec == 200 and isinstance(ej, dict):
|
|
1690
|
-
events = ej.get("events") or ej.get("data") or []
|
|
1691
|
-
for e in events:
|
|
1692
|
-
seq = int(e.get("seq") or 0)
|
|
1693
|
-
if seq <= since:
|
|
1694
|
-
continue
|
|
1695
|
-
since = seq
|
|
1696
|
-
typ = str(e.get("type") or e.get("event_type") or "").lower()
|
|
1697
|
-
msg = e.get("message") or e.get("msg") or ""
|
|
1698
|
-
if typ in (
|
|
1699
|
-
"rl.eval.started",
|
|
1700
|
-
"rl.eval.summary",
|
|
1701
|
-
"rl.train.step",
|
|
1702
|
-
"rl.metrics",
|
|
1703
|
-
"rl.performance.metrics",
|
|
1704
|
-
):
|
|
1705
|
-
print(f"[{seq}] {typ}: {msg}")
|
|
1706
|
-
mc, mj = _http("GET", api + f"/learning/jobs/{job_id}/metrics?after_step=-1&limit=50")
|
|
1707
|
-
if mc == 200 and isinstance(mj, dict):
|
|
1708
|
-
pts = mj.get("points") or []
|
|
1709
|
-
for p in pts:
|
|
1710
|
-
name = p.get("name")
|
|
1711
|
-
if name == "eval.reward_mean":
|
|
1712
|
-
print(f"metric eval.reward_mean step={p.get('step')} value={p.get('value')}")
|
|
1713
|
-
break
|
|
1714
|
-
if time.time() - start_t > (timeout or 600):
|
|
1715
|
-
print("Timeout waiting for terminal state.")
|
|
1716
|
-
break
|
|
1717
|
-
time.sleep(2)
|
|
1718
|
-
return 0
|