freesolo-flash-dev 0.2.30__tar.gz → 0.2.32__tar.gz
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.
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/bake-kernel-cache.yml +9 -2
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/Dockerfile.worker +1 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/PKG-INFO +25 -21
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/README.md +19 -17
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docker/bake_kernel_cache.py +60 -3
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docker/bake_pod_entry.py +27 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/catalog.py +79 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cli/__init__.py +5 -3
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cli/commands.py +13 -10
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cli/render.py +26 -15
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cli/training_doc.py +63 -15
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cost/__init__.py +2 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cost/analytical.py +30 -12
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cost/facts.py +6 -2
- freesolo_flash_dev-0.2.32/flash/cost/spec.py +248 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cost/types.py +28 -5
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/accounting.py +6 -2
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/__init__.py +9 -2
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/adapter.py +22 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/decoding.py +35 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/lora.py +115 -9
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/rl.py +13 -2
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/envs/adapter.py +255 -7
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/envs/registry.py +3 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/_instance.py +3 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/_instance_bootstrap.py +119 -13
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/base.py +31 -19
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/__init__.py +2 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/jobs/__init__.py +12 -3
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/jobs/builders.py +2 -2
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/pricing.py +4 -5
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/__init__.py +2 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/jobs.py +3 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/pricing.py +3 -2
- freesolo_flash_dev-0.2.32/flash/providers/runpod/train/__init__.py +165 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/train/deps.py +3 -2
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/train/endpoints.py +122 -13
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/runner/__init__.py +53 -6
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/runner/deploy.py +37 -14
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/runner/lifecycle.py +26 -40
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/schema/__init__.py +10 -2
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/serve/deploy.py +86 -72
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/serve/export.py +56 -6
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/_locks.py +1 -13
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/_runtime.py +26 -54
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/app.py +1 -15
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/billing.py +13 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/environment_registry.py +9 -4
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/routes/envs.py +11 -3
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/routes/runs.py +37 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/routes/serving.py +33 -32
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/pyproject.toml +8 -6
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/conftest.py +0 -11
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_allocator.py +5 -5
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cancel_remote.py +2 -32
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_catalog_consistency.py +73 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cli_commands.py +26 -8
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cli_estimate.py +130 -13
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cli_render_theme.py +13 -15
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_client.py +11 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_config_overrides.py +5 -6
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cost_analytical.py +27 -11
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cost_equation.py +6 -4
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cost_estimate.py +6 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cost_hardware.py +16 -6
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_disk_gb.py +1 -2
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_env_publish.py +91 -5
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_env_pull.py +253 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_export.py +102 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_flash_mvp.py +1 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_flash_worker.py +88 -9
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_gpus.py +22 -18
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_grpo_params.py +9 -7
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_grpo_sleep_gate.py +3 -3
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_jobs.py +108 -54
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_lambda_runner.py +89 -4
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_managed_hf_repo.py +31 -10
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_mig_guard.py +3 -3
- freesolo_flash_dev-0.2.32/tests/test_orchestrator_flash.py +550 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_packing.py +1 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_provider_routing.py +34 -34
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_provider_teardown_robustness.py +4 -4
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_providers_symmetry.py +6 -6
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_resume_on_retry.py +4 -4
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_runmgmt.py +29 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_serve.py +127 -77
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_server_api.py +265 -21
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_server_billing.py +49 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_serving_contract.py +5 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_spec_and_validation.py +14 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_verifiers.py +47 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_vl_warmstart_recombine.py +196 -16
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_weight_cache.py +1 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_worker_init_heartbeat.py +7 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_worker_stack.py +1 -1
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_worker_thinking.py +20 -5
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/uv.lock +12 -8
- freesolo_flash_dev-0.2.30/flash/cost/spec.py +0 -110
- freesolo_flash_dev-0.2.30/flash/providers/runpod/train/__init__.py +0 -62
- freesolo_flash_dev-0.2.30/flash/server/repo_cleanup.py +0 -296
- freesolo_flash_dev-0.2.30/tests/test_orchestrator_flash.py +0 -232
- freesolo_flash_dev-0.2.30/tests/test_repo_cleanup.py +0 -513
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.dockerignore +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.env.example +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.gitignore +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/Dockerfile +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/LICENSE +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-style/README.md +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-style/generate.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-style/index.html +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-style/preview.png +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-style/themed-errors.png +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-theme/README.md +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-theme/before-after-dark.png +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-theme/before-after-light.png +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-theme/gallery-dark.png +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-theme/gallery-light.png +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-theme/help-dark.png +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/cli-theme/help-light.png +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/docs/kernel-cache.md +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/_channel.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/_logging.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/client/config.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/client/http.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/gpu_setup.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/lambdalabs/train.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/preload.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/py.typed +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/_internal_client.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/db.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/flash/spec.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_b200_rollout_opt.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_version.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_vl_weight_sync.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/tests/test_worker_image.py +0 -0
{freesolo_flash_dev-0.2.30 → freesolo_flash_dev-0.2.32}/.github/workflows/bake-kernel-cache.yml
RENAMED
|
@@ -76,16 +76,23 @@ jobs:
|
|
|
76
76
|
gpu_type_id: "NVIDIA RTX A6000",
|
|
77
77
|
allowed_cuda: "",
|
|
78
78
|
}
|
|
79
|
+
# sm89 (Ada): warm on the L40S -- a DATACENTER Ada card with reliable secure-cloud capacity --
|
|
80
|
+
# instead of the consumer RTX 4090 (scarce/cold on secure cloud, where the bake pod often never
|
|
81
|
+
# finished pulling the ~20GB image before the deadline). The cache is sm-keyed, so an L40S-warmed
|
|
82
|
+
# sm89 cache is valid on every sm89 card (4090/L40/L4). NB: verify the exact RunPod gpuTypeId.
|
|
79
83
|
- {
|
|
80
84
|
sm: sm89,
|
|
81
85
|
arch: "8.9",
|
|
82
|
-
gpu_type_id: "NVIDIA
|
|
86
|
+
gpu_type_id: "NVIDIA L40S",
|
|
83
87
|
allowed_cuda: "",
|
|
84
88
|
}
|
|
89
|
+
# sm90 (Hopper): warm on the H200 (141GB, sm90) -- better secure-cloud capacity than the
|
|
90
|
+
# heavily-contended H100 80GB HBM3 (which cold-pull-stalled the bake). Same sm90, so the cache
|
|
91
|
+
# is valid on every H100/H200. H200 is in flash's validated GPU catalog (providers/base.py).
|
|
85
92
|
- {
|
|
86
93
|
sm: sm90,
|
|
87
94
|
arch: "9.0",
|
|
88
|
-
gpu_type_id: "NVIDIA
|
|
95
|
+
gpu_type_id: "NVIDIA H200",
|
|
89
96
|
allowed_cuda: "",
|
|
90
97
|
}
|
|
91
98
|
# Blackwell needs CUDA-13 hosts to JIT its PTX (matches min_cuda_for in the provider). Bake
|
|
@@ -63,7 +63,7 @@ RUN pip install --no-cache-dir \
|
|
|
63
63
|
"tilelang==0.1.11" \
|
|
64
64
|
"apache-tvm-ffi==0.1.11" \
|
|
65
65
|
"hf_transfer" \
|
|
66
|
-
"freesolo>=0.2.
|
|
66
|
+
"freesolo>=0.2.52" \
|
|
67
67
|
"runpod"
|
|
68
68
|
# Gated-DeltaNet (Qwen3.5/3.6) runs on flash-linear-attention's Triton kernels. On consumer cards
|
|
69
69
|
# (Ampere/Ada/Blackwell) the Triton path is correct. On Hopper (sm90) fla's GDN chunk_bwd is
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.32
|
|
4
4
|
Summary: Flash — managed LoRA post-training (SFT/GRPO) for Freesolo environments, driven by the `flash` CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/freesolo-co/flash
|
|
6
6
|
Project-URL: Repository, https://github.com/freesolo-co/flash
|
|
@@ -18,19 +18,20 @@ Requires-Python: <3.13,>=3.11
|
|
|
18
18
|
Provides-Extra: dev
|
|
19
19
|
Requires-Dist: datasets>=2.19; extra == 'dev'
|
|
20
20
|
Requires-Dist: fastapi; extra == 'dev'
|
|
21
|
-
Requires-Dist: freesolo>=0.2.
|
|
21
|
+
Requires-Dist: freesolo>=0.2.52; extra == 'dev'
|
|
22
22
|
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
23
23
|
Requires-Dist: huggingface-hub>=0.34; extra == 'dev'
|
|
24
24
|
Requires-Dist: mypy>=1.13.0; extra == 'dev'
|
|
25
25
|
Requires-Dist: pytest>=9.0.3; extra == 'dev'
|
|
26
26
|
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
27
27
|
Requires-Dist: runpod-flash; extra == 'dev'
|
|
28
|
+
Requires-Dist: transformers<5.11,>=5.6; extra == 'dev'
|
|
28
29
|
Requires-Dist: uvicorn; extra == 'dev'
|
|
29
30
|
Provides-Extra: gpu
|
|
30
31
|
Requires-Dist: accelerate>=1.4; extra == 'gpu'
|
|
31
32
|
Requires-Dist: bitsandbytes>=0.49; extra == 'gpu'
|
|
32
33
|
Requires-Dist: datasets>=2.19; extra == 'gpu'
|
|
33
|
-
Requires-Dist: freesolo>=0.2.
|
|
34
|
+
Requires-Dist: freesolo>=0.2.52; extra == 'gpu'
|
|
34
35
|
Requires-Dist: huggingface-hub>=0.34; extra == 'gpu'
|
|
35
36
|
Requires-Dist: peft>=0.19; extra == 'gpu'
|
|
36
37
|
Requires-Dist: torch==2.10.0; extra == 'gpu'
|
|
@@ -40,24 +41,26 @@ Requires-Dist: vllm==0.19.1; extra == 'gpu'
|
|
|
40
41
|
Provides-Extra: server
|
|
41
42
|
Requires-Dist: datasets>=2.19; extra == 'server'
|
|
42
43
|
Requires-Dist: fastapi; extra == 'server'
|
|
43
|
-
Requires-Dist: freesolo>=0.2.
|
|
44
|
+
Requires-Dist: freesolo>=0.2.52; extra == 'server'
|
|
44
45
|
Requires-Dist: httpx>=0.27; extra == 'server'
|
|
45
46
|
Requires-Dist: huggingface-hub>=0.34; extra == 'server'
|
|
46
47
|
Requires-Dist: runpod-flash; extra == 'server'
|
|
48
|
+
Requires-Dist: transformers<5.11,>=5.6; extra == 'server'
|
|
47
49
|
Requires-Dist: uvicorn; extra == 'server'
|
|
48
50
|
Description-Content-Type: text/markdown
|
|
49
51
|
|
|
50
52
|
# Flash
|
|
51
53
|
|
|
52
|
-
Managed LoRA post-training service: SFT and GRPO on managed
|
|
53
|
-
The allocator picks the cheapest validated
|
|
54
|
+
Managed LoRA post-training service: SFT and GRPO on managed Flash GPUs.
|
|
55
|
+
The allocator picks the cheapest validated managed GPU class that fits the run.
|
|
54
56
|
|
|
55
57
|
## Scope
|
|
56
58
|
|
|
57
59
|
- `flash train <cfg.toml>` / control-plane `POST /runs` — submit a training job;
|
|
58
60
|
one dedicated GPU per run, supervised server-side (stall watchdog, bounded
|
|
59
61
|
auto-retry resuming from the last streamed checkpoint, endpoint GC).
|
|
60
|
-
- `flash deploy`, `flash chat` — serving for trained adapters
|
|
62
|
+
- `flash checkpoints`, `flash deploy`, `flash chat` — serving for trained adapters,
|
|
63
|
+
including deployable intermediate RL checkpoints.
|
|
61
64
|
- **Freesolo SDK environments.** Every run names a Freesolo environment id.
|
|
62
65
|
Scaffold `environment.py` plus `datasets/train.jsonl`, upload `.` or another
|
|
63
66
|
folder with `flash env push --name <name> <folder>`, then reference the
|
|
@@ -68,21 +71,22 @@ The allocator picks the cheapest validated RunPod GPU class that fits the run.
|
|
|
68
71
|
## Layout
|
|
69
72
|
|
|
70
73
|
- `flash/catalog.py` — curated model catalog (Qwen3 dense supported tier;
|
|
71
|
-
Qwen3.5/3.6 experimental tier)
|
|
72
|
-
|
|
74
|
+
Qwen3.5/3.6 experimental tier), VRAM-fit sizing, and each model's `thinking`
|
|
75
|
+
capability (opt-in reasoning mode `thinking = true`)
|
|
73
76
|
- `flash/schema.py`, `flash/spec.py` — TOML → `JobSpec`
|
|
74
77
|
- `flash/runner.py` — server-side run supervisor (durable job handle,
|
|
75
78
|
retries, cost guard, endpoint GC)
|
|
76
|
-
- `flash/providers/` —
|
|
79
|
+
- `flash/providers/` — managed GPU substrate code (pricing, GPU classes, durable
|
|
77
80
|
submit/poll, preflight) behind the `base.Provider` protocol, with an
|
|
78
|
-
`allocator.py` that picks the cheapest fitting class
|
|
81
|
+
`allocator.py` that picks the cheapest fitting managed GPU class
|
|
79
82
|
- `flash/engine/` — the on-GPU worker (TRL + colocated vLLM rollouts) and the
|
|
80
83
|
shared recipe; SFT targets and RL rewards route through the active environment
|
|
81
84
|
(task-specific grading lives with its example, not in the engine)
|
|
82
85
|
- `flash/envs/` — environment machinery: registry and the adapter that loads
|
|
83
86
|
Freesolo SDK environments onto the worker's interface
|
|
84
87
|
- `flash env setup` — scaffold a starter local Freesolo env, `datasets/train.jsonl`,
|
|
85
|
-
|
|
88
|
+
ready-to-run configs, and a `TRAINING.md` playbook with common failure modes and
|
|
89
|
+
mitigations
|
|
86
90
|
- `flash/serve/`, `flash/server/` — adapter serving and the FastAPI control
|
|
87
91
|
plane (run operator-side via the separate `flash-server` command)
|
|
88
92
|
- `Dockerfile` — the control-plane image (used by the repo docker-compose)
|
|
@@ -99,11 +103,11 @@ uv run flash --help
|
|
|
99
103
|
uv run flash-server # control plane (operator-side, run once)
|
|
100
104
|
```
|
|
101
105
|
|
|
102
|
-
The control plane owns
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
knob and not an operator-wide env var. Clients authenticate with their freesolo API key
|
|
106
|
+
The control plane owns infrastructure credentials plus the shared `HF_TOKEN`.
|
|
107
|
+
The artifact repo is platform-managed and environment-scoped (runs for the same environment share
|
|
108
|
+
one private `Freesolo-Co/flashrun-<environment>-<hash>` repo, written by the operator `HF_TOKEN`);
|
|
109
|
+
Flash uploads code under content-addressed prefixes and only reuses completed snapshots. The repo is
|
|
110
|
+
not a user knob and not an operator-wide env var. Clients authenticate with their freesolo API key
|
|
107
111
|
(`flash login`).
|
|
108
112
|
|
|
109
113
|
## Release channels
|
|
@@ -173,10 +177,10 @@ Use `choices[0].message.content` for the generated text. The run id is the adapt
|
|
|
173
177
|
for serving. If the run is not deployed yet, `/v1/runs/<run_id>/chat` returns `409`
|
|
174
178
|
with a hint to deploy first.
|
|
175
179
|
|
|
176
|
-
Operators can also call the
|
|
177
|
-
The default serving
|
|
178
|
-
operators can point Flash at another
|
|
179
|
-
Use that same base URL when calling the
|
|
180
|
+
Operators can also call the serving backend directly after the adapter is registered.
|
|
181
|
+
The default serving backend is `https://clado-ai--freesolo-lora-serving.modal.run`, and
|
|
182
|
+
operators can point Flash at another backend by setting `FREESOLO_SERVING_URL`.
|
|
183
|
+
Use that same base URL when calling the backend directly; pass the run id as `model`:
|
|
180
184
|
|
|
181
185
|
```bash
|
|
182
186
|
export FREESOLO_SERVING_URL=https://clado-ai--freesolo-lora-serving.modal.run
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
# Flash
|
|
2
2
|
|
|
3
|
-
Managed LoRA post-training service: SFT and GRPO on managed
|
|
4
|
-
The allocator picks the cheapest validated
|
|
3
|
+
Managed LoRA post-training service: SFT and GRPO on managed Flash GPUs.
|
|
4
|
+
The allocator picks the cheapest validated managed GPU class that fits the run.
|
|
5
5
|
|
|
6
6
|
## Scope
|
|
7
7
|
|
|
8
8
|
- `flash train <cfg.toml>` / control-plane `POST /runs` — submit a training job;
|
|
9
9
|
one dedicated GPU per run, supervised server-side (stall watchdog, bounded
|
|
10
10
|
auto-retry resuming from the last streamed checkpoint, endpoint GC).
|
|
11
|
-
- `flash deploy`, `flash chat` — serving for trained adapters
|
|
11
|
+
- `flash checkpoints`, `flash deploy`, `flash chat` — serving for trained adapters,
|
|
12
|
+
including deployable intermediate RL checkpoints.
|
|
12
13
|
- **Freesolo SDK environments.** Every run names a Freesolo environment id.
|
|
13
14
|
Scaffold `environment.py` plus `datasets/train.jsonl`, upload `.` or another
|
|
14
15
|
folder with `flash env push --name <name> <folder>`, then reference the
|
|
@@ -19,21 +20,22 @@ The allocator picks the cheapest validated RunPod GPU class that fits the run.
|
|
|
19
20
|
## Layout
|
|
20
21
|
|
|
21
22
|
- `flash/catalog.py` — curated model catalog (Qwen3 dense supported tier;
|
|
22
|
-
Qwen3.5/3.6 experimental tier)
|
|
23
|
-
|
|
23
|
+
Qwen3.5/3.6 experimental tier), VRAM-fit sizing, and each model's `thinking`
|
|
24
|
+
capability (opt-in reasoning mode `thinking = true`)
|
|
24
25
|
- `flash/schema.py`, `flash/spec.py` — TOML → `JobSpec`
|
|
25
26
|
- `flash/runner.py` — server-side run supervisor (durable job handle,
|
|
26
27
|
retries, cost guard, endpoint GC)
|
|
27
|
-
- `flash/providers/` —
|
|
28
|
+
- `flash/providers/` — managed GPU substrate code (pricing, GPU classes, durable
|
|
28
29
|
submit/poll, preflight) behind the `base.Provider` protocol, with an
|
|
29
|
-
`allocator.py` that picks the cheapest fitting class
|
|
30
|
+
`allocator.py` that picks the cheapest fitting managed GPU class
|
|
30
31
|
- `flash/engine/` — the on-GPU worker (TRL + colocated vLLM rollouts) and the
|
|
31
32
|
shared recipe; SFT targets and RL rewards route through the active environment
|
|
32
33
|
(task-specific grading lives with its example, not in the engine)
|
|
33
34
|
- `flash/envs/` — environment machinery: registry and the adapter that loads
|
|
34
35
|
Freesolo SDK environments onto the worker's interface
|
|
35
36
|
- `flash env setup` — scaffold a starter local Freesolo env, `datasets/train.jsonl`,
|
|
36
|
-
|
|
37
|
+
ready-to-run configs, and a `TRAINING.md` playbook with common failure modes and
|
|
38
|
+
mitigations
|
|
37
39
|
- `flash/serve/`, `flash/server/` — adapter serving and the FastAPI control
|
|
38
40
|
plane (run operator-side via the separate `flash-server` command)
|
|
39
41
|
- `Dockerfile` — the control-plane image (used by the repo docker-compose)
|
|
@@ -50,11 +52,11 @@ uv run flash --help
|
|
|
50
52
|
uv run flash-server # control plane (operator-side, run once)
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
The control plane owns
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
knob and not an operator-wide env var. Clients authenticate with their freesolo API key
|
|
55
|
+
The control plane owns infrastructure credentials plus the shared `HF_TOKEN`.
|
|
56
|
+
The artifact repo is platform-managed and environment-scoped (runs for the same environment share
|
|
57
|
+
one private `Freesolo-Co/flashrun-<environment>-<hash>` repo, written by the operator `HF_TOKEN`);
|
|
58
|
+
Flash uploads code under content-addressed prefixes and only reuses completed snapshots. The repo is
|
|
59
|
+
not a user knob and not an operator-wide env var. Clients authenticate with their freesolo API key
|
|
58
60
|
(`flash login`).
|
|
59
61
|
|
|
60
62
|
## Release channels
|
|
@@ -124,10 +126,10 @@ Use `choices[0].message.content` for the generated text. The run id is the adapt
|
|
|
124
126
|
for serving. If the run is not deployed yet, `/v1/runs/<run_id>/chat` returns `409`
|
|
125
127
|
with a hint to deploy first.
|
|
126
128
|
|
|
127
|
-
Operators can also call the
|
|
128
|
-
The default serving
|
|
129
|
-
operators can point Flash at another
|
|
130
|
-
Use that same base URL when calling the
|
|
129
|
+
Operators can also call the serving backend directly after the adapter is registered.
|
|
130
|
+
The default serving backend is `https://clado-ai--freesolo-lora-serving.modal.run`, and
|
|
131
|
+
operators can point Flash at another backend by setting `FREESOLO_SERVING_URL`.
|
|
132
|
+
Use that same base URL when calling the backend directly; pass the run id as `model`:
|
|
131
133
|
|
|
132
134
|
```bash
|
|
133
135
|
export FREESOLO_SERVING_URL=https://clado-ai--freesolo-lora-serving.modal.run
|
|
@@ -66,15 +66,19 @@ def main() -> int:
|
|
|
66
66
|
ap = argparse.ArgumentParser(description="offload the kernel-cache warmup to a RunPod GPU")
|
|
67
67
|
ap.add_argument("--arch", required=True, help="TORCH_CUDA_ARCH_LIST target, e.g. 9.0")
|
|
68
68
|
ap.add_argument("--sm", required=True, help="sm tag, e.g. sm90 (must match the produced cache)")
|
|
69
|
-
ap.add_argument(
|
|
69
|
+
ap.add_argument(
|
|
70
|
+
"--gpu-type-id", required=True, help="RunPod gpuTypeId, e.g. 'NVIDIA H100 80GB HBM3'"
|
|
71
|
+
)
|
|
70
72
|
ap.add_argument("--image", default="ghcr.io/freesolo-co/flash-worker:cu128")
|
|
71
73
|
ap.add_argument("--out", default="build/kernel_cache")
|
|
72
74
|
# the warm pod only pulls the ~20GB image + writes the cache (no model download), so keep this
|
|
73
75
|
# modest -- an over-large ask shrinks the eligible host pool and trips "machine does not have the
|
|
74
76
|
# resources" on scarce classes (e.g. Blackwell sm120 on secure cloud).
|
|
75
77
|
ap.add_argument("--container-disk-gb", type=int, default=60)
|
|
76
|
-
ap.add_argument("--deadline-min", type=int, default=
|
|
77
|
-
ap.add_argument(
|
|
78
|
+
ap.add_argument("--deadline-min", type=int, default=90)
|
|
79
|
+
ap.add_argument(
|
|
80
|
+
"--run-id", default="", help="unique suffix for the temp repo (default: time+uuid)"
|
|
81
|
+
)
|
|
78
82
|
ap.add_argument(
|
|
79
83
|
"--allowed-cuda",
|
|
80
84
|
default="",
|
|
@@ -189,6 +193,59 @@ def main() -> int:
|
|
|
189
193
|
shutil.move(s, d)
|
|
190
194
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
191
195
|
rc = _verify(args.out, args.sm)
|
|
196
|
+
else:
|
|
197
|
+
# Non-success (timeout / pod_died): the pod-side out/ (STARTED marker, warmup.log) lives in
|
|
198
|
+
# the temp dataset the `finally` below deletes, so pull + print it FIRST. out/STARTED present
|
|
199
|
+
# = the warmup entrypoint ran (a timeout then means it hung / was slow); STARTED absent is
|
|
200
|
+
# AMBIGUOUS -- either the pod ran the wrong entrypoint, or the best-effort STARTED upload
|
|
201
|
+
# failed while the warmup is still running (the pod log disambiguates). warmup.log is only
|
|
202
|
+
# uploaded AFTER the warmup process returns, so it's present only if the warmup
|
|
203
|
+
# finished/was killed, not on a pure mid-run hang.
|
|
204
|
+
log(f"outcome={outcome}: pulling pod-side out/ for diagnostics before cleanup")
|
|
205
|
+
try:
|
|
206
|
+
dbg = os.path.join(args.out, ".dbg")
|
|
207
|
+
snapshot_download(
|
|
208
|
+
repo_id=repo,
|
|
209
|
+
repo_type="dataset",
|
|
210
|
+
allow_patterns=["out/**"],
|
|
211
|
+
local_dir=dbg,
|
|
212
|
+
token=token,
|
|
213
|
+
)
|
|
214
|
+
src = os.path.join(dbg, "out")
|
|
215
|
+
if os.path.isdir(src) and os.listdir(src):
|
|
216
|
+
started = os.path.isfile(os.path.join(src, "STARTED"))
|
|
217
|
+
log(f"warmup entrypoint ran (out/STARTED present): {started}")
|
|
218
|
+
for root, _, files in os.walk(src):
|
|
219
|
+
for f in sorted(files):
|
|
220
|
+
p = os.path.join(root, f)
|
|
221
|
+
log(f" out/{os.path.relpath(p, src)} ({os.path.getsize(p)} b)")
|
|
222
|
+
wl = os.path.join(src, "warmup.log")
|
|
223
|
+
if os.path.isfile(wl):
|
|
224
|
+
log("--- warmup.log tail (last 60 lines) ---")
|
|
225
|
+
with open(wl, errors="replace") as wlf:
|
|
226
|
+
for line in wlf.read().splitlines()[-60:]:
|
|
227
|
+
log(f" | {line}")
|
|
228
|
+
else:
|
|
229
|
+
log(
|
|
230
|
+
"no warmup.log (warmup never returned -> mid-run hang or still running at deadline)"
|
|
231
|
+
)
|
|
232
|
+
else:
|
|
233
|
+
# Ambiguous: out/STARTED is uploaded best-effort BEFORE warmup, and the cache tree
|
|
234
|
+
# only lands AFTER warmup returns. So an empty out/ means EITHER the entrypoint
|
|
235
|
+
# never ran (wrong CMD / docker_args) OR the STARTED upload failed while warmup is
|
|
236
|
+
# still mid-run. The pod retries that upload 3x, so a dropped marker is unlikely and
|
|
237
|
+
# wrong-entrypoint is the probable cause -- but don't assert it. The only proof is
|
|
238
|
+
# the pod's OWN console (its "[bake] uploaded out/STARTED" / WARNING lines), which
|
|
239
|
+
# this helper can't fetch (pod terminated below) -> read it in the RunPod dashboard.
|
|
240
|
+
log(
|
|
241
|
+
"pod produced NO out/ -> warmup entrypoint probably never ran "
|
|
242
|
+
"(wrong CMD / docker_args); the only other cause is a failed out/STARTED "
|
|
243
|
+
"upload mid-run (unlikely, it retries 3x) -- confirm via the pod console "
|
|
244
|
+
"in the RunPod dashboard (this CI log does not capture pod stdout)"
|
|
245
|
+
)
|
|
246
|
+
shutil.rmtree(dbg, ignore_errors=True)
|
|
247
|
+
except Exception as e:
|
|
248
|
+
log(f"diagnostic fetch failed (ignore): {str(e)[:160]}")
|
|
192
249
|
finally:
|
|
193
250
|
if pod_id:
|
|
194
251
|
try:
|
|
@@ -28,6 +28,33 @@ def main() -> int:
|
|
|
28
28
|
arch = os.environ.get("BAKE_ARCH", "")
|
|
29
29
|
api = HfApi(token=token)
|
|
30
30
|
|
|
31
|
+
# Upload a STARTED marker FIRST -- before the code download / chalk install / warmup -- so a CI-side
|
|
32
|
+
# timeout can tell whether this entrypoint even ran. Present on a timeout = the warmup started (so it
|
|
33
|
+
# hung or was slow); absent = the pod ran the wrong entrypoint, OR this upload itself failed while
|
|
34
|
+
# the warmup is still running. Retry a few times so a transient HF blip doesn't drop the marker and
|
|
35
|
+
# make the helper misread a slow run as a wrong entrypoint.
|
|
36
|
+
started_uploaded = False
|
|
37
|
+
for attempt in range(3):
|
|
38
|
+
try:
|
|
39
|
+
api.upload_file(
|
|
40
|
+
path_or_fileobj=io.BytesIO(f"started arch={arch}\n".encode()),
|
|
41
|
+
path_in_repo="out/STARTED",
|
|
42
|
+
repo_id=repo,
|
|
43
|
+
repo_type="dataset",
|
|
44
|
+
)
|
|
45
|
+
started_uploaded = True
|
|
46
|
+
print("[bake] uploaded out/STARTED", flush=True)
|
|
47
|
+
break
|
|
48
|
+
except Exception as e:
|
|
49
|
+
# keep the "out/STARTED" token in the line so it greps the same as the success/WARNING lines
|
|
50
|
+
print(f"[bake] out/STARTED upload attempt {attempt + 1}/3 failed: {e}", flush=True)
|
|
51
|
+
if attempt < 2: # no point sleeping after the last attempt
|
|
52
|
+
time.sleep(3)
|
|
53
|
+
if not started_uploaded:
|
|
54
|
+
# The marker never landed; warn loudly so a later "no out/STARTED" is read as upload-failed,
|
|
55
|
+
# not as a wrong-entrypoint run.
|
|
56
|
+
print("[bake] WARNING: out/STARTED never uploaded; warmup still proceeds", flush=True)
|
|
57
|
+
|
|
31
58
|
# the flash code the helper uploaded (upload_code -> code/flash); run the warmup from it.
|
|
32
59
|
snapshot_download(
|
|
33
60
|
repo_id=repo,
|
|
@@ -29,6 +29,18 @@ DEFAULT_GPU = "RTX 5090"
|
|
|
29
29
|
_DEFAULT_VOCAB_SIZE = 248_320
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class ServingCapacity:
|
|
34
|
+
gpu: str
|
|
35
|
+
max_loras: int
|
|
36
|
+
max_lora_rank: int
|
|
37
|
+
max_model_len: int
|
|
38
|
+
serve_model_id: str = ""
|
|
39
|
+
max_num_seqs: int = 0
|
|
40
|
+
max_num_batched_tokens: int = 0
|
|
41
|
+
gpu_memory_utilization: float = 0.0
|
|
42
|
+
|
|
43
|
+
|
|
32
44
|
@dataclass(frozen=True)
|
|
33
45
|
class ModelInfo:
|
|
34
46
|
id: str
|
|
@@ -61,6 +73,10 @@ class ModelInfo:
|
|
|
61
73
|
notes: str = ""
|
|
62
74
|
# 0 = platform default (64 GB) suffices. Runner raises gpu.disk_gb to at least this.
|
|
63
75
|
min_disk_gb: int = 0
|
|
76
|
+
# Deployment capacity of the external freesolo multi-LoRA serving app. This is separate from
|
|
77
|
+
# Flash's training GPU recommendation above; serving uses Modal/vLLM and sizes hot LoRA buffers
|
|
78
|
+
# by max_loras x max_lora_rank at engine init.
|
|
79
|
+
serving: ServingCapacity | None = None
|
|
64
80
|
# "none" / "hybrid" (Qwen3-style) / "always" (can't disable) / "unknown" (open-model policy)
|
|
65
81
|
thinking: str = "none"
|
|
66
82
|
vocab_size: int = _DEFAULT_VOCAB_SIZE
|
|
@@ -79,7 +95,20 @@ class ModelInfo:
|
|
|
79
95
|
hidden_size: int = 0
|
|
80
96
|
|
|
81
97
|
def to_dict(self) -> dict[str, Any]:
|
|
82
|
-
|
|
98
|
+
data = asdict(self)
|
|
99
|
+
serving = data.get("serving")
|
|
100
|
+
if serving is None:
|
|
101
|
+
data.pop("serving", None)
|
|
102
|
+
else:
|
|
103
|
+
for key in (
|
|
104
|
+
"serve_model_id",
|
|
105
|
+
"max_num_seqs",
|
|
106
|
+
"max_num_batched_tokens",
|
|
107
|
+
"gpu_memory_utilization",
|
|
108
|
+
):
|
|
109
|
+
if serving.get(key) in ("", 0, 0.0, None):
|
|
110
|
+
serving.pop(key, None)
|
|
111
|
+
return data
|
|
83
112
|
|
|
84
113
|
|
|
85
114
|
DEFAULT_MODEL = "Qwen/Qwen3.5-4B"
|
|
@@ -94,6 +123,7 @@ MODELS: dict[str, ModelInfo] = {
|
|
|
94
123
|
algos=("sft", "grpo"),
|
|
95
124
|
min_vram_gb=12,
|
|
96
125
|
recommended_gpu="RTX 4090",
|
|
126
|
+
serving=ServingCapacity(gpu="L4", max_loras=16, max_lora_rank=64, max_model_len=32768),
|
|
97
127
|
thinking="hybrid",
|
|
98
128
|
notes="On-device class SLM (131k ctx); standard Llama architecture.",
|
|
99
129
|
),
|
|
@@ -106,6 +136,7 @@ MODELS: dict[str, ModelInfo] = {
|
|
|
106
136
|
algos=("sft", "grpo"),
|
|
107
137
|
min_vram_gb=12,
|
|
108
138
|
recommended_gpu="RTX 4090",
|
|
139
|
+
serving=ServingCapacity(gpu="L4", max_loras=16, max_lora_rank=64, max_model_len=32768),
|
|
109
140
|
thinking="hybrid",
|
|
110
141
|
notes="Smallest Qwen3.5; cheap smoke/dev runs with the modern arch.",
|
|
111
142
|
),
|
|
@@ -118,6 +149,7 @@ MODELS: dict[str, ModelInfo] = {
|
|
|
118
149
|
algos=("sft", "grpo"),
|
|
119
150
|
min_vram_gb=16,
|
|
120
151
|
recommended_gpu="RTX 4090",
|
|
152
|
+
serving=ServingCapacity(gpu="L4", max_loras=16, max_lora_rank=64, max_model_len=32768),
|
|
121
153
|
thinking="hybrid",
|
|
122
154
|
),
|
|
123
155
|
"Qwen/Qwen3.5-4B": ModelInfo(
|
|
@@ -129,6 +161,15 @@ MODELS: dict[str, ModelInfo] = {
|
|
|
129
161
|
algos=("sft", "grpo"),
|
|
130
162
|
min_vram_gb=32,
|
|
131
163
|
recommended_gpu="RTX 5090",
|
|
164
|
+
serving=ServingCapacity(
|
|
165
|
+
gpu="L4",
|
|
166
|
+
serve_model_id="lovedheart/Qwen3.5-4B-FP8",
|
|
167
|
+
max_loras=64,
|
|
168
|
+
max_lora_rank=32,
|
|
169
|
+
max_model_len=8192,
|
|
170
|
+
max_num_seqs=8,
|
|
171
|
+
gpu_memory_utilization=0.98,
|
|
172
|
+
),
|
|
132
173
|
thinking="hybrid",
|
|
133
174
|
notes="Current-gen 4B. GRPO uses the sleep-mode memory recipe (hybrid arch needs "
|
|
134
175
|
"extra engine state-cache); fused DeltaNet kernels ship in the default stack.",
|
|
@@ -145,6 +186,15 @@ MODELS: dict[str, ModelInfo] = {
|
|
|
145
186
|
grpo_min_vram_gb=80,
|
|
146
187
|
quant="bf16",
|
|
147
188
|
recommended_gpu="A100 PCIe",
|
|
189
|
+
serving=ServingCapacity(
|
|
190
|
+
gpu="L4",
|
|
191
|
+
serve_model_id="lovedheart/Qwen3.5-9B-FP8",
|
|
192
|
+
max_loras=44,
|
|
193
|
+
max_lora_rank=32,
|
|
194
|
+
max_model_len=8192,
|
|
195
|
+
max_num_seqs=8,
|
|
196
|
+
gpu_memory_utilization=0.98,
|
|
197
|
+
),
|
|
148
198
|
thinking="hybrid",
|
|
149
199
|
notes="bf16 LoRA. ~19 GB of weights; SFT fits a 48 GB card, while colocated GRPO "
|
|
150
200
|
"(two bf16 copies + KV + the 248k-vocab fp32 logits) needs an 80 GB-class card "
|
|
@@ -174,6 +224,16 @@ MODELS: dict[str, ModelInfo] = {
|
|
|
174
224
|
sleep_unsupported=True,
|
|
175
225
|
quant="bf16",
|
|
176
226
|
recommended_gpu="H200",
|
|
227
|
+
serving=ServingCapacity(
|
|
228
|
+
gpu="A100-80GB",
|
|
229
|
+
serve_model_id="Qwen/Qwen3.6-35B-A3B-FP8",
|
|
230
|
+
max_loras=12,
|
|
231
|
+
max_lora_rank=32,
|
|
232
|
+
max_model_len=8192,
|
|
233
|
+
max_num_seqs=8,
|
|
234
|
+
max_num_batched_tokens=4096,
|
|
235
|
+
gpu_memory_utilization=0.98,
|
|
236
|
+
),
|
|
177
237
|
thinking="hybrid",
|
|
178
238
|
min_disk_gb=200,
|
|
179
239
|
notes="MoE (35B total / ~3B active), bf16 LoRA. SFT runs on the 141 GB H200 (the ~70 GB "
|
|
@@ -199,6 +259,24 @@ def get_model(model_id: str) -> ModelInfo:
|
|
|
199
259
|
) from exc
|
|
200
260
|
|
|
201
261
|
|
|
262
|
+
def serving_lora_rank_cap(model: str | ModelInfo | None) -> int | None:
|
|
263
|
+
"""Return the model's serving LoRA rank cap, or None when Flash has no local cap.
|
|
264
|
+
|
|
265
|
+
Serving capacity is model-specific: small serving models currently allow rank 64, while larger
|
|
266
|
+
serving paths can cap at rank 32. Unknown/open-policy models intentionally return None instead
|
|
267
|
+
of inheriting a global fallback.
|
|
268
|
+
"""
|
|
269
|
+
if isinstance(model, ModelInfo):
|
|
270
|
+
info = model
|
|
271
|
+
elif isinstance(model, str) and model.strip():
|
|
272
|
+
info = MODELS.get(model.strip())
|
|
273
|
+
else:
|
|
274
|
+
info = None
|
|
275
|
+
if info is None or info.serving is None:
|
|
276
|
+
return None
|
|
277
|
+
return int(info.serving.max_lora_rank)
|
|
278
|
+
|
|
279
|
+
|
|
202
280
|
def vocab_size_for(model_id: str) -> int:
|
|
203
281
|
"""Curated vocab_size for a model, or the safe default for open-model-policy entries."""
|
|
204
282
|
info = MODELS.get(model_id)
|
|
@@ -66,7 +66,7 @@ _HELP_GROUPS: list[tuple[str, list[tuple[str, str]]]] = [
|
|
|
66
66
|
"catalog",
|
|
67
67
|
[
|
|
68
68
|
("models", "list supported base models"),
|
|
69
|
-
("gpus", "list managed GPU classes with
|
|
69
|
+
("gpus", "list managed GPU classes with estimated $/hr"),
|
|
70
70
|
],
|
|
71
71
|
),
|
|
72
72
|
(
|
|
@@ -226,7 +226,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
226
226
|
models = sub.add_parser("models", help="list supported base models")
|
|
227
227
|
models.set_defaults(func=cmd_models)
|
|
228
228
|
|
|
229
|
-
gpus = sub.add_parser("gpus", help="list managed GPU classes with
|
|
229
|
+
gpus = sub.add_parser("gpus", help="list managed GPU classes with estimated $/hr")
|
|
230
230
|
gpus.set_defaults(func=cmd_gpus)
|
|
231
231
|
|
|
232
232
|
env = sub.add_parser("env", help="manage Freesolo environments")
|
|
@@ -268,7 +268,9 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
268
268
|
env_pull.set_defaults(func=cmd_env_pull)
|
|
269
269
|
|
|
270
270
|
env_delete = env_sub.add_parser("delete", help="delete a published Freesolo environment")
|
|
271
|
-
env_delete.add_argument(
|
|
271
|
+
env_delete.add_argument(
|
|
272
|
+
"env_id", help="the Freesolo environment id to delete, e.g. you/your-env"
|
|
273
|
+
)
|
|
272
274
|
env_delete.add_argument(
|
|
273
275
|
"-y",
|
|
274
276
|
"--yes",
|
|
@@ -236,8 +236,8 @@ def cmd_env_setup(args) -> int:
|
|
|
236
236
|
"[train]\n"
|
|
237
237
|
"steps = 150\n"
|
|
238
238
|
"lora_rank = 32\n"
|
|
239
|
-
"# GPU and
|
|
240
|
-
"# the cheapest fitting class
|
|
239
|
+
"# GPU and HF artifacts are managed automatically by the platform: the GPU is\n"
|
|
240
|
+
"# the cheapest fitting managed class, and artifacts live in a private environment-scoped repo.\n"
|
|
241
241
|
)
|
|
242
242
|
sft = Path("configs/sft.toml")
|
|
243
243
|
if not sft.exists():
|
|
@@ -248,8 +248,8 @@ def cmd_env_setup(args) -> int:
|
|
|
248
248
|
"[train]\n"
|
|
249
249
|
"epochs = 1\n"
|
|
250
250
|
"lora_rank = 32\n"
|
|
251
|
-
"# GPU and
|
|
252
|
-
"# the cheapest fitting class
|
|
251
|
+
"# GPU and HF artifacts are managed automatically by the platform: the GPU is\n"
|
|
252
|
+
"# the cheapest fitting managed class, and artifacts live in a private environment-scoped repo.\n"
|
|
253
253
|
)
|
|
254
254
|
training = Path("TRAINING.md")
|
|
255
255
|
if not training.exists():
|
|
@@ -280,7 +280,7 @@ def cmd_models(args) -> int:
|
|
|
280
280
|
|
|
281
281
|
|
|
282
282
|
def cmd_gpus(args) -> int:
|
|
283
|
-
"""List
|
|
283
|
+
"""List validated managed GPU classes, VRAM, and estimated $/hr."""
|
|
284
284
|
from flash.providers.base import GPU_INFO
|
|
285
285
|
from flash.providers.runpod.pricing import static_rates as runpod_static_rates
|
|
286
286
|
|
|
@@ -290,7 +290,7 @@ def cmd_gpus(args) -> int:
|
|
|
290
290
|
)
|
|
291
291
|
tip = (
|
|
292
292
|
"Tip: GPU class selection is fully automatic — the submit-time allocator always picks the\n"
|
|
293
|
-
"cheapest validated
|
|
293
|
+
"cheapest validated managed class that fits the model, so you don't pin a GPU type."
|
|
294
294
|
)
|
|
295
295
|
if render.styled():
|
|
296
296
|
rows = [(info.name, info.vram_gb, runpod_rates.get(info.name)) for info in infos]
|
|
@@ -300,7 +300,7 @@ def cmd_gpus(args) -> int:
|
|
|
300
300
|
def fmt_rate(v: float | None) -> str:
|
|
301
301
|
return f"{v:>10.2f}" if v else f"{'-':>10}"
|
|
302
302
|
|
|
303
|
-
print(f"{'gpu':<16}{'vram':>6}{'
|
|
303
|
+
print(f"{'gpu':<16}{'vram':>6}{'$/hr':>11}")
|
|
304
304
|
for info in infos:
|
|
305
305
|
runpod_rate = runpod_rates.get(info.name)
|
|
306
306
|
print(f"{info.name:<16}{info.vram_gb:>5}G{fmt_rate(runpod_rate):>11}")
|
|
@@ -338,7 +338,11 @@ def cmd_env_list(args) -> int:
|
|
|
338
338
|
|
|
339
339
|
|
|
340
340
|
def _cmd_train_cost(args) -> int:
|
|
341
|
-
"""
|
|
341
|
+
"""`flash train --cost`: print the pre-flight USD cost for the config and exit (no submit).
|
|
342
|
+
|
|
343
|
+
Catalog-only and deterministic; SFT uses the actual local training-token count when the env
|
|
344
|
+
and tokenizer are importable. An uncapped SFT run must be able to count the env's train split,
|
|
345
|
+
otherwise it errors instead of guessing a dataset size."""
|
|
342
346
|
from flash.cost import estimate_cost
|
|
343
347
|
|
|
344
348
|
spec = spec_from_file(
|
|
@@ -479,8 +483,7 @@ def cmd_runs(args) -> int:
|
|
|
479
483
|
spec = r.get("spec") or {}
|
|
480
484
|
model = spec.get("model", "")
|
|
481
485
|
algorithm = str(spec.get("algorithm") or "-").upper()
|
|
482
|
-
|
|
483
|
-
where = f"{gpu}@{provider}" if provider else gpu
|
|
486
|
+
where = render._run_gpu(spec, r.get("remote") or {})
|
|
484
487
|
print(
|
|
485
488
|
f"{r['run_id']:<32} {r['state']:<11} {algorithm:<5} "
|
|
486
489
|
f"{r.get('cost_usd', 0.0):>8.4f} {where:<22} {model}"
|