freesolo-flash-dev 1.0.72__tar.gz → 1.0.73__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-1.0.73/.env.example +97 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/CONTRIBUTING.md +7 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/PKG-INFO +45 -46
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/README.md +44 -45
- freesolo_flash_dev-1.0.73/SELF_HOSTING.md +245 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/loader.py +8 -1
- freesolo_flash_dev-1.0.73/flash/providers/_auth.py +18 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_worker.py +7 -2
- freesolo_flash_dev-1.0.73/flash/providers/preflight.py +162 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/__init__.py +10 -2
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/slots.py +9 -2
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/weight_cache_preload.py +22 -6
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/__init__.py +47 -10
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/lifecycle.py +31 -16
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/deploy.py +37 -5
- freesolo_flash_dev-1.0.73/flash/serve/urls.py +53 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/_internal_client.py +10 -2
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/_runtime.py +1 -1
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/app.py +1 -1
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/auth.py +37 -2
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/billing_retry.py +8 -4
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/db.py +70 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/environment_registry.py +6 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/envs.py +7 -1
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/projects.py +8 -1
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/reconcile.py +9 -5
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/repo_cleanup.py +26 -12
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/pyproject.toml +2 -2
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/scripts/scrub_history.sh +94 -5
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/conftest.py +23 -1
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cancel_remote.py +7 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_jobs.py +16 -10
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_opd_resume_safety.py +14 -2
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_orchestrator_flash.py +1 -1
- freesolo_flash_dev-1.0.73/tests/test_preflight.py +246 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_projects.py +48 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_repo_cleanup.py +1 -1
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runmgmt.py +44 -7
- freesolo_flash_dev-1.0.73/tests/test_server_standalone.py +728 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_warmstart_cross_repo.py +3 -1
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_weight_cache.py +33 -1
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/uv.lock +1 -1
- freesolo_flash_dev-1.0.72/.env.example +0 -58
- freesolo_flash_dev-1.0.72/flash/providers/_auth.py +0 -10
- freesolo_flash_dev-1.0.72/flash/providers/preflight.py +0 -65
- freesolo_flash_dev-1.0.72/flash/serve/urls.py +0 -26
- freesolo_flash_dev-1.0.72/tests/test_preflight.py +0 -173
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.dockerignore +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/dependabot.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/auto-rebake.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/bake-kernel-cache.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/notify-tests-repo.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/worker-image.yml +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.gitignore +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/CODE_OF_CONDUCT.md +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/Dockerfile +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/LICENSE +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/NOTICE +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/SECURITY.md +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/Dockerfile.kernelcache +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/Dockerfile.kernelcache.relayer +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/_channel.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/_logging.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/adapter_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/catalog.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/TRAINING.md +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/_tty.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/commands.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/env_eval.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/env_setup.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/env_test.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/envpush.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/render.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/traces.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/training_doc.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/config.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/http.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/multiturn_reward_scoring.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/reward_profile.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/steps.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/adapter.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/backend_common.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/grpo_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/grpo_plugin.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/hf.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/lora.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/multiturn_glue.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_gkd.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_multiturn.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_plugin.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_structured.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_train.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/rl.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/rl_train.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/rng.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/sft_train.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/teacher.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/tokenizer_align.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker_entrypoint.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/adapter.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/archive.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/archive_policy.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/evaluations.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/pull.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/lora_rank.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/multimodal.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/opd_retry_contract.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/opd_validation.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_deadline.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_hf_artifacts.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_instance_poll.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_instance_provider.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/api.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/auth.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/jobs/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/jobs/builders.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/preflight.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/pricing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/py.typed +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/preflight.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/spec.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/thinking.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/_helpers/vast.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/test_vast_live.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_accounting_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_async_uploads.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_backend_common.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_base_model_provenance.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_charge_pricing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_checkpoints.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_commands_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_credential_shadowing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_gpus_flag.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_help.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_main_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_render_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_render_theme.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_traces.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_wandb_warning.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_client.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_client_stream_reads.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_controlled_experiment_repairs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_deploy_latency.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_cache_evict.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_delete.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_download.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_download_api.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_evaluations.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_no_install.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_pull.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_pull_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_pull_loader_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_pull_managed_control_plane.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_ref_pinning.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_test.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_export.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_flashinfer_cache_dirs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_gpu_type_single_field.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_grpo_resident_sizing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_health_liveness.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_hf_retry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_instance_bootstrap_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_internal_client.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_kernel_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_lambda_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_lora_rank_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_lora_rank_preflight.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_managed_config_fields.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_multi_gpu_gate.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_multimodal_input_grads.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_multimodal_training.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_named_reward_metrics.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_oom_escalate_gpu.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_opd.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_opd_train.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_packing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_provider_preflight_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_reward_profile.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_rl_train.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_rollout_samples.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serve_reasoning_content.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_app_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_auth_singleflight.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_checkpoints_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_envs_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_locks_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serving_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serving_pricing_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serving_schema_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_chunked_nll.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_example_selection.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_gc_off.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_max_context.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_train.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_step_metrics.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_structured_outputs.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_train_context_preflight.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_training_controls.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_api.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_api_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_offers.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_provider_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_runner.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_verified_revisions.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_verifiers.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_version.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vl_warmstart_adapter_keys.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vram_architecture.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_wandb_link.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_wandb_log_coverage.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_warmstart_adapter_download.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_warmstart_error_attribution.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_thinking.py +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Flash control plane (operator-side). Copy to .env and fill in.
|
|
2
|
+
# Provider credentials live ONLY here — clients never see them and authenticate
|
|
3
|
+
# with their API key.
|
|
4
|
+
#
|
|
5
|
+
# Everything under "required" is checked by `flash/providers/preflight.py` at
|
|
6
|
+
# startup; `flash-server` refuses to serve if any of them is missing. Settings
|
|
7
|
+
# that only DEGRADE the plane (a single-account RunPod pool, no GITHUB_TOKEN)
|
|
8
|
+
# warn at startup instead of blocking it.
|
|
9
|
+
#
|
|
10
|
+
# Self-hosting? Read SELF_HOSTING.md first - the short version is the two lines
|
|
11
|
+
# below, and it is a much smaller list than this file suggests:
|
|
12
|
+
#
|
|
13
|
+
# FLASH_STANDALONE=1
|
|
14
|
+
# FREESOLO_INTERNAL_KEY=$(openssl rand -hex 32)
|
|
15
|
+
#
|
|
16
|
+
# IMPORTANT: `flash-server` does NOT read this file. It reads the process
|
|
17
|
+
# environment, so copying it to .env is not by itself enough — load it:
|
|
18
|
+
#
|
|
19
|
+
# set -a && . ./.env && set +a && flash-server # shell
|
|
20
|
+
# docker run --env-file .env ... # docker
|
|
21
|
+
|
|
22
|
+
# --- required: GPU substrate (AT LEAST ONE of the three) ---
|
|
23
|
+
# Flash allocates across RunPod, Lambda, and Vast. Configure the ones you have an
|
|
24
|
+
# account with; a provider whose key is unset is simply never considered, and the
|
|
25
|
+
# allocator ranks candidates only on the substrates you configured. One is enough
|
|
26
|
+
# to run. The preflight fails only when ALL THREE are missing.
|
|
27
|
+
#
|
|
28
|
+
# RunPod: one key, or several comma-separated for multi-account failover. A
|
|
29
|
+
# single-account pool works but cannot fail over or reap across accounts, so the
|
|
30
|
+
# preflight warns.
|
|
31
|
+
RUNPOD_API_KEY=
|
|
32
|
+
# Lambda Cloud API key.
|
|
33
|
+
LAMBDA_API_KEY=
|
|
34
|
+
# Vast.ai API key.
|
|
35
|
+
VAST_API_KEY=
|
|
36
|
+
|
|
37
|
+
# --- required: artifacts ---
|
|
38
|
+
# HuggingFace token with write access to the dataset repos flash creates for artifacts
|
|
39
|
+
# (code upload + streamed checkpoints/adapters). The repo is assigned by the control
|
|
40
|
+
# plane and scoped to the ENVIRONMENT, so runs sharing an environment share a repo and
|
|
41
|
+
# each run lands under its own prefix. It is not a user-authored field: the TOML parser
|
|
42
|
+
# rejects a [train] hf_repo set by hand.
|
|
43
|
+
HF_TOKEN=
|
|
44
|
+
# The HuggingFace user or org those artifact repos are created under. Defaults to
|
|
45
|
+
# Freesolo's namespace, which a self-hoster's token cannot write to - so on a
|
|
46
|
+
# self-hosted plane SET THIS to a namespace your HF_TOKEN owns, or every run fails at
|
|
47
|
+
# the code upload before training starts.
|
|
48
|
+
# FLASH_HF_NAMESPACE=your-hf-username
|
|
49
|
+
|
|
50
|
+
# --- required: control-plane auth ---
|
|
51
|
+
# The plane's own auth key. On a self-hosted (FLASH_STANDALONE=1) deployment this is
|
|
52
|
+
# the ONLY credential the plane accepts and is therefore the entire trust boundary -
|
|
53
|
+
# generate a high-entropy value and treat it like a root password:
|
|
54
|
+
#
|
|
55
|
+
# export FREESOLO_INTERNAL_KEY=$(openssl rand -hex 32)
|
|
56
|
+
#
|
|
57
|
+
# On a managed deployment it is the shared internal key that maps to a single service
|
|
58
|
+
# identity without a network call, alongside per-user keys verified against
|
|
59
|
+
# {FREESOLO_BASE_URL}/api/auth/verify.
|
|
60
|
+
FREESOLO_INTERNAL_KEY=
|
|
61
|
+
|
|
62
|
+
# --- optional: self-hosting ---
|
|
63
|
+
# Run without a Freesolo backend. Off by default. With it set, the plane stops calling
|
|
64
|
+
# out for project/environment/billing validation and trusts FREESOLO_INTERNAL_KEY as a
|
|
65
|
+
# single-tenant operator credential; external bearer tokens are REJECTED rather than
|
|
66
|
+
# accepted unverified. Single tenant - see SELF_HOSTING.md before enabling.
|
|
67
|
+
# FLASH_STANDALONE=1
|
|
68
|
+
|
|
69
|
+
# --- optional ---
|
|
70
|
+
# Server token for the environment repository. Without it, environments hosted in a
|
|
71
|
+
# private GitHub repo cannot be fetched; environments in public GitHub repos still work,
|
|
72
|
+
# so this warns at startup rather than blocking it. (A local directory is never a valid
|
|
73
|
+
# environment source - the GPU worker fetches the environment itself.)
|
|
74
|
+
GITHUB_TOKEN=
|
|
75
|
+
# The OPD teacher credential (injected into the worker for opd jobs only). NOT covered
|
|
76
|
+
# by the startup preflight: an opd run submitted without it still allocates and BILLS a
|
|
77
|
+
# GPU, then fails inside the worker before the first teacher request. Set it before
|
|
78
|
+
# running opd; sft and grpo do not use it.
|
|
79
|
+
FIREWORKS_API_KEY=
|
|
80
|
+
# Where to verify user keys. Defaults to https://api.freesolo.co when unset. Ignored
|
|
81
|
+
# under FLASH_STANDALONE=1, which verifies nothing over the network.
|
|
82
|
+
# FREESOLO_BASE_URL=
|
|
83
|
+
# Adapter serving is delegated to a multi-LoRA serving app (a Modal app that serves
|
|
84
|
+
# every adapter on one GPU per base model, scaling to zero when idle).
|
|
85
|
+
# `flash deploy`/`undeploy`/`chat` register/deregister/chat against it. Defaults to the
|
|
86
|
+
# hosted URL when unset; point it at your own deployment to self-host serving.
|
|
87
|
+
#
|
|
88
|
+
# Under FLASH_STANDALONE=1 there is NO default: those three commands error out until this
|
|
89
|
+
# is set. Every serving request carries FREESOLO_INTERNAL_KEY, which on a self-hosted
|
|
90
|
+
# plane is the credential controlling that plane, so falling back to the hosted URL would
|
|
91
|
+
# send it to a service the operator does not run. Training never uses this.
|
|
92
|
+
#
|
|
93
|
+
# LEFT COMMENTED DELIBERATELY. The standalone guard rejects an UNSET value, so a template
|
|
94
|
+
# that assigned the hosted URL would satisfy it and hand the plane's root credential to
|
|
95
|
+
# serve.freesolo.co on the first deploy -- the exact leak the guard exists to stop. Set it
|
|
96
|
+
# to YOUR serving deployment; the managed plane gets the hosted URL from the code default.
|
|
97
|
+
# FREESOLO_SERVING_URL=https://serve.freesolo.co
|
|
@@ -81,6 +81,13 @@ this repository have one, and it is the main reason the history is readable.
|
|
|
81
81
|
Do not add tool-generated trailers (co-author lines for AI assistants, session links, or
|
|
82
82
|
"generated with" footers) to commits.
|
|
83
83
|
|
|
84
|
+
That rule governs new commits only. Commits already in this history carry such trailers,
|
|
85
|
+
plus a build box that committed under an internal hostname. `scripts/scrub_history.sh`
|
|
86
|
+
rewrites both out of every ref and refuses to print publication instructions unless the
|
|
87
|
+
residual counts reach zero. It has to run on a fresh mirror clone **before** the
|
|
88
|
+
repository is made public: rewriting afterwards accomplishes nothing, because the old
|
|
89
|
+
shas stay reachable through forks, caches, and the GitHub API.
|
|
90
|
+
|
|
84
91
|
## Code style
|
|
85
92
|
|
|
86
93
|
- Ruff is the formatter and linter; its configuration lives in `pyproject.toml`. Run
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.73
|
|
4
4
|
Summary: Flash — managed LoRA post-training (SFT/GRPO/OPD) 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
|
|
@@ -87,19 +87,21 @@ This repository contains:
|
|
|
87
87
|
- the GPU provider substrate (`flash/providers/`) — pricing, allocation, submit/poll,
|
|
88
88
|
- the environment loading machinery (`flash/envs/`).
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
The training path is self-hostable end to end: with `FLASH_STANDALONE=1`, one GPU provider
|
|
91
|
+
key, and a HuggingFace token, you can run SFT, GRPO, and on-policy distillation on your own
|
|
92
|
+
hardware budget with no Freesolo backend involved. See
|
|
93
|
+
**[SELF_HOSTING.md](SELF_HOSTING.md)**.
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
| ----------------------- | ----------------------------------------------------- |
|
|
95
|
-
| Identity and API keys | `api.freesolo.co` — verifies keys, owns projects/orgs |
|
|
96
|
-
| Multi-LoRA serving | `serve.freesolo.co` — `flash/serve/` is a thin client |
|
|
97
|
-
| Managed environment hub | a private repository of published environments |
|
|
95
|
+
Two components stay Freesolo-operated and are not in this repository:
|
|
98
96
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
| Component | Where it lives | Self-hosted equivalent |
|
|
98
|
+
| --------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
99
|
+
| Multi-tenant identity | `api.freesolo.co` - verifies keys, owns projects/orgs | `FLASH_STANDALONE=1` runs single-tenant on your own operator key |
|
|
100
|
+
| Multi-LoRA serving | `serve.freesolo.co` - `flash/serve/` is a thin client | adapters land in your HuggingFace repos; serve them with any LoRA-capable stack |
|
|
101
|
+
|
|
102
|
+
So there are three honest ways to use Flash: **against the hosted service**, **self-hosted
|
|
103
|
+
against your own GPU accounts**, or as **training and provider code to read and modify**,
|
|
104
|
+
which is self-contained and the most reusable part of the repository.
|
|
103
105
|
|
|
104
106
|
## Using the hosted service
|
|
105
107
|
|
|
@@ -242,44 +244,41 @@ model — in short, **pull requests go into `dev`**.
|
|
|
242
244
|
|
|
243
245
|
## Self-hosting
|
|
244
246
|
|
|
245
|
-
You can run your own control plane
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
The control plane needs the `server` extra — the base install above is client-only and
|
|
249
|
-
`flash-server` will refuse to start without it:
|
|
247
|
+
You can run your own control plane against your own GPU accounts, with no Freesolo backend
|
|
248
|
+
involved. **[SELF_HOSTING.md](SELF_HOSTING.md) is the full guide**; the short version:
|
|
250
249
|
|
|
251
250
|
```bash
|
|
252
|
-
pip install 'freesolo-flash[server]'
|
|
251
|
+
pip install 'freesolo-flash[server]' # the base install is client-only
|
|
252
|
+
|
|
253
|
+
export FLASH_STANDALONE=1
|
|
254
|
+
export FREESOLO_INTERNAL_KEY=$(openssl rand -hex 32)
|
|
255
|
+
export HF_TOKEN=hf_...
|
|
256
|
+
export FLASH_HF_NAMESPACE=your-hf-username # a namespace your HF_TOKEN can write to
|
|
257
|
+
export RUNPOD_API_KEY=... # or LAMBDA_API_KEY, or VAST_API_KEY
|
|
258
|
+
|
|
259
|
+
flash-server --host 0.0.0.0 --port 8080
|
|
253
260
|
```
|
|
254
261
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
fully
|
|
274
|
-
|
|
275
|
-
1. **User authentication.** Unknown bearer tokens are verified against
|
|
276
|
-
`{FREESOLO_BASE_URL}/api/auth/verify` (`flash/server/auth.py`). Only the internal-key
|
|
277
|
-
path works without the Freesolo backend.
|
|
278
|
-
2. **Environments.** Publishing and managed-slug loading target a private environment
|
|
279
|
-
repository (`flash/server/envs.py`, `flash/envs/loader.py`).
|
|
280
|
-
3. **Serving.** `flash/serve/` is a client for the Freesolo multi-LoRA serving app; point
|
|
281
|
-
it elsewhere with `FREESOLO_SERVING_URL`, but this repository does not include a
|
|
282
|
-
serving backend.
|
|
262
|
+
You need **one** of RunPod, Lambda, or Vast - not all three. Providers whose key is unset
|
|
263
|
+
are never considered, and the allocator only proposes GPU classes it can actually
|
|
264
|
+
provision. Startup fails only when all three are missing.
|
|
265
|
+
|
|
266
|
+
`FLASH_STANDALONE=1` is what makes this work: it stops the plane calling out for project,
|
|
267
|
+
environment, and billing validation, and trusts `FREESOLO_INTERNAL_KEY` as a single-tenant
|
|
268
|
+
operator credential. External bearer tokens are rejected rather than accepted unverified.
|
|
269
|
+
A standalone plane is **single-tenant** - whoever holds that key can spend your GPU budget,
|
|
270
|
+
so keep it off untrusted networks. See
|
|
271
|
+
[the security model](SELF_HOSTING.md#the-security-model).
|
|
272
|
+
|
|
273
|
+
Two seams remain Freesolo-operated and are not part of this repository:
|
|
274
|
+
|
|
275
|
+
1. **Multi-tenant identity.** Real per-user keys and org ownership need a backend serving
|
|
276
|
+
the `/api/auth/verify` contract in `flash/server/auth.py`, pointed at by
|
|
277
|
+
`FREESOLO_BASE_URL`. Standalone mode is single-tenant instead.
|
|
278
|
+
2. **Serving.** `flash/serve/` is a client for a multi-LoRA serving app; point it elsewhere
|
|
279
|
+
with `FREESOLO_SERVING_URL`. Training, checkpoint streaming, and adapter export are
|
|
280
|
+
fully self-hostable - adapters land in your own HuggingFace repos and can be served by
|
|
281
|
+
any stack that loads LoRA adapters.
|
|
283
282
|
|
|
284
283
|
The GPU worker image is public and can be pulled directly. It is published under an
|
|
285
284
|
explicit CUDA tag, not `latest`:
|
|
@@ -28,19 +28,21 @@ This repository contains:
|
|
|
28
28
|
- the GPU provider substrate (`flash/providers/`) — pricing, allocation, submit/poll,
|
|
29
29
|
- the environment loading machinery (`flash/envs/`).
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
The training path is self-hostable end to end: with `FLASH_STANDALONE=1`, one GPU provider
|
|
32
|
+
key, and a HuggingFace token, you can run SFT, GRPO, and on-policy distillation on your own
|
|
33
|
+
hardware budget with no Freesolo backend involved. See
|
|
34
|
+
**[SELF_HOSTING.md](SELF_HOSTING.md)**.
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
| ----------------------- | ----------------------------------------------------- |
|
|
36
|
-
| Identity and API keys | `api.freesolo.co` — verifies keys, owns projects/orgs |
|
|
37
|
-
| Multi-LoRA serving | `serve.freesolo.co` — `flash/serve/` is a thin client |
|
|
38
|
-
| Managed environment hub | a private repository of published environments |
|
|
36
|
+
Two components stay Freesolo-operated and are not in this repository:
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
| Component | Where it lives | Self-hosted equivalent |
|
|
39
|
+
| --------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
40
|
+
| Multi-tenant identity | `api.freesolo.co` - verifies keys, owns projects/orgs | `FLASH_STANDALONE=1` runs single-tenant on your own operator key |
|
|
41
|
+
| Multi-LoRA serving | `serve.freesolo.co` - `flash/serve/` is a thin client | adapters land in your HuggingFace repos; serve them with any LoRA-capable stack |
|
|
42
|
+
|
|
43
|
+
So there are three honest ways to use Flash: **against the hosted service**, **self-hosted
|
|
44
|
+
against your own GPU accounts**, or as **training and provider code to read and modify**,
|
|
45
|
+
which is self-contained and the most reusable part of the repository.
|
|
44
46
|
|
|
45
47
|
## Using the hosted service
|
|
46
48
|
|
|
@@ -183,44 +185,41 @@ model — in short, **pull requests go into `dev`**.
|
|
|
183
185
|
|
|
184
186
|
## Self-hosting
|
|
185
187
|
|
|
186
|
-
You can run your own control plane
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
The control plane needs the `server` extra — the base install above is client-only and
|
|
190
|
-
`flash-server` will refuse to start without it:
|
|
188
|
+
You can run your own control plane against your own GPU accounts, with no Freesolo backend
|
|
189
|
+
involved. **[SELF_HOSTING.md](SELF_HOSTING.md) is the full guide**; the short version:
|
|
191
190
|
|
|
192
191
|
```bash
|
|
193
|
-
pip install 'freesolo-flash[server]'
|
|
192
|
+
pip install 'freesolo-flash[server]' # the base install is client-only
|
|
193
|
+
|
|
194
|
+
export FLASH_STANDALONE=1
|
|
195
|
+
export FREESOLO_INTERNAL_KEY=$(openssl rand -hex 32)
|
|
196
|
+
export HF_TOKEN=hf_...
|
|
197
|
+
export FLASH_HF_NAMESPACE=your-hf-username # a namespace your HF_TOKEN can write to
|
|
198
|
+
export RUNPOD_API_KEY=... # or LAMBDA_API_KEY, or VAST_API_KEY
|
|
199
|
+
|
|
200
|
+
flash-server --host 0.0.0.0 --port 8080
|
|
194
201
|
```
|
|
195
202
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
fully
|
|
215
|
-
|
|
216
|
-
1. **User authentication.** Unknown bearer tokens are verified against
|
|
217
|
-
`{FREESOLO_BASE_URL}/api/auth/verify` (`flash/server/auth.py`). Only the internal-key
|
|
218
|
-
path works without the Freesolo backend.
|
|
219
|
-
2. **Environments.** Publishing and managed-slug loading target a private environment
|
|
220
|
-
repository (`flash/server/envs.py`, `flash/envs/loader.py`).
|
|
221
|
-
3. **Serving.** `flash/serve/` is a client for the Freesolo multi-LoRA serving app; point
|
|
222
|
-
it elsewhere with `FREESOLO_SERVING_URL`, but this repository does not include a
|
|
223
|
-
serving backend.
|
|
203
|
+
You need **one** of RunPod, Lambda, or Vast - not all three. Providers whose key is unset
|
|
204
|
+
are never considered, and the allocator only proposes GPU classes it can actually
|
|
205
|
+
provision. Startup fails only when all three are missing.
|
|
206
|
+
|
|
207
|
+
`FLASH_STANDALONE=1` is what makes this work: it stops the plane calling out for project,
|
|
208
|
+
environment, and billing validation, and trusts `FREESOLO_INTERNAL_KEY` as a single-tenant
|
|
209
|
+
operator credential. External bearer tokens are rejected rather than accepted unverified.
|
|
210
|
+
A standalone plane is **single-tenant** - whoever holds that key can spend your GPU budget,
|
|
211
|
+
so keep it off untrusted networks. See
|
|
212
|
+
[the security model](SELF_HOSTING.md#the-security-model).
|
|
213
|
+
|
|
214
|
+
Two seams remain Freesolo-operated and are not part of this repository:
|
|
215
|
+
|
|
216
|
+
1. **Multi-tenant identity.** Real per-user keys and org ownership need a backend serving
|
|
217
|
+
the `/api/auth/verify` contract in `flash/server/auth.py`, pointed at by
|
|
218
|
+
`FREESOLO_BASE_URL`. Standalone mode is single-tenant instead.
|
|
219
|
+
2. **Serving.** `flash/serve/` is a client for a multi-LoRA serving app; point it elsewhere
|
|
220
|
+
with `FREESOLO_SERVING_URL`. Training, checkpoint streaming, and adapter export are
|
|
221
|
+
fully self-hostable - adapters land in your own HuggingFace repos and can be served by
|
|
222
|
+
any stack that loads LoRA adapters.
|
|
224
223
|
|
|
225
224
|
The GPU worker image is public and can be pulled directly. It is published under an
|
|
226
225
|
explicit CUDA tag, not `latest`:
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Self-hosting Flash
|
|
2
|
+
|
|
3
|
+
Run your own Flash control plane against your own GPU accounts, with no Freesolo backend
|
|
4
|
+
involved.
|
|
5
|
+
|
|
6
|
+
This is an operator deployment, not a one-command install: you supply the GPU credentials,
|
|
7
|
+
you hold the auth key, and you decide which of the three providers to use. What it gets
|
|
8
|
+
you is the whole training path - SFT, GRPO, and on-policy distillation on verl with
|
|
9
|
+
colocated vLLM rollouts, the allocator, the stall watchdog, checkpoint streaming, and
|
|
10
|
+
endpoint GC - pointed at hardware you pay for directly.
|
|
11
|
+
|
|
12
|
+
## What you need
|
|
13
|
+
|
|
14
|
+
Two credentials and at least one GPU account:
|
|
15
|
+
|
|
16
|
+
| | |
|
|
17
|
+
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
18
|
+
| **One GPU provider** | a RunPod, Lambda, **or** Vast account. One is enough. |
|
|
19
|
+
| `HF_TOKEN` | a HuggingFace token with **write** access. Flash streams code, checkpoints, and adapters through HuggingFace dataset repos, so every run needs it whichever provider you use. |
|
|
20
|
+
| `FLASH_HF_NAMESPACE` | the HuggingFace user or org those repos are created under - **set this to one your `HF_TOKEN` can write to.** It defaults to Freesolo's namespace, which you cannot write to. |
|
|
21
|
+
| `FREESOLO_INTERNAL_KEY` | the key your clients present to your plane. Generate it yourself. |
|
|
22
|
+
|
|
23
|
+
Everything else is optional.
|
|
24
|
+
|
|
25
|
+
## Quickstart
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install 'freesolo-flash[server]' # the base install is client-only
|
|
29
|
+
|
|
30
|
+
export FLASH_STANDALONE=1
|
|
31
|
+
export FREESOLO_INTERNAL_KEY=$(openssl rand -hex 32)
|
|
32
|
+
export HF_TOKEN=hf_...
|
|
33
|
+
export FLASH_HF_NAMESPACE=your-hf-username # where run artifacts are created
|
|
34
|
+
export RUNPOD_API_KEY=... # or LAMBDA_API_KEY, or VAST_API_KEY
|
|
35
|
+
|
|
36
|
+
flash-server --host 0.0.0.0 --port 8080
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Then point a client at it:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
flash login --api-url http://your-plane:8080 --api-key "$FREESOLO_INTERNAL_KEY"
|
|
43
|
+
flash train run.toml
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Every run config needs a top-level `project` uuid - it groups runs and is required in
|
|
47
|
+
standalone mode too (see [project ids](#what-flashstandalone1-does)). Any uuid works
|
|
48
|
+
on a standalone plane, so you can pick one once and reuse it:
|
|
49
|
+
|
|
50
|
+
```toml
|
|
51
|
+
project = "11111111-1111-4111-8111-111111111111"
|
|
52
|
+
model = "Qwen/Qwen3.5-4B"
|
|
53
|
+
algorithm = "sft"
|
|
54
|
+
|
|
55
|
+
[environment]
|
|
56
|
+
id = "github:your-org/your-repo@main:path/to/env"
|
|
57
|
+
|
|
58
|
+
[train]
|
|
59
|
+
epochs = 1
|
|
60
|
+
max_examples = 1000
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`flash-server` reads the **process** environment, not `.env`. If you keep credentials in a
|
|
64
|
+
file, load it: `set -a && . ./.env && set +a && flash-server`, or
|
|
65
|
+
`docker run --env-file .env ...`. Copy `.env.example` to start from a documented template.
|
|
66
|
+
|
|
67
|
+
## Environments
|
|
68
|
+
|
|
69
|
+
An environment is the Python package defining your task - dataset, rollout, reward. Point
|
|
70
|
+
`[environment] id` at any GitHub repository you control:
|
|
71
|
+
|
|
72
|
+
| Form | Resolves to |
|
|
73
|
+
| --------------------------------------------- | ------------------------------------------------------------ |
|
|
74
|
+
| `github:owner/repo@ref:path/to/env` | that repo at that ref. **Use this when self-hosting.** |
|
|
75
|
+
| `https://github.com/owner/repo/tree/ref/path` | the same thing, in browser-URL form. |
|
|
76
|
+
| `namespace/name` | Freesolo's managed hub (`freesolo-co/environment-hub`) only. |
|
|
77
|
+
|
|
78
|
+
A bare `namespace/name` slug is **not** a generic shorthand - it always resolves against
|
|
79
|
+
Freesolo's hub, so a self-hosted plane should use the explicit `github:` form. `ref` may be
|
|
80
|
+
a branch, tag, or commit sha; pin a sha if you want runs to be reproducible.
|
|
81
|
+
|
|
82
|
+
Public repos work without credentials, subject to GitHub's unauthenticated rate limit. Set
|
|
83
|
+
`GITHUB_TOKEN` for private repos. `flash env push` publishes to the managed hub and is not
|
|
84
|
+
part of a self-hosted deployment.
|
|
85
|
+
|
|
86
|
+
**A local directory is not a supported environment source.** The GPU worker fetches the
|
|
87
|
+
environment itself, so it needs a source it can reach; an `[environment] path` is rejected
|
|
88
|
+
at submit. Push your environment to a GitHub repository (public or private with
|
|
89
|
+
`GITHUB_TOKEN`) and reference it with the `github:` form above.
|
|
90
|
+
|
|
91
|
+
## Choosing providers
|
|
92
|
+
|
|
93
|
+
Flash allocates across RunPod, Lambda, and Vast. **Configure the ones you have; the rest
|
|
94
|
+
are simply never considered.** There is no requirement to hold all three, and no
|
|
95
|
+
placeholder value to set for the ones you skip.
|
|
96
|
+
|
|
97
|
+
| Provider | Variable | Notes |
|
|
98
|
+
| -------- | ---------------- | --------------------------------------------------------------- |
|
|
99
|
+
| RunPod | `RUNPOD_API_KEY` | One key, or several comma-separated for multi-account failover. |
|
|
100
|
+
| Lambda | `LAMBDA_API_KEY` | |
|
|
101
|
+
| Vast | `VAST_API_KEY` | |
|
|
102
|
+
|
|
103
|
+
The allocator ranks candidate GPU classes only on the substrates you configured, so a
|
|
104
|
+
plane with just `VAST_API_KEY` set allocates on Vast and never proposes a class it cannot
|
|
105
|
+
provision. Startup fails only when **all three** are missing.
|
|
106
|
+
|
|
107
|
+
A single RunPod key works. It logs a warning at startup because a one-account pool cannot
|
|
108
|
+
ride out that account's quota or credit exhaustion by moving to another - an availability
|
|
109
|
+
property, not a correctness one. Runs still allocate, and idle endpoints are still reaped
|
|
110
|
+
within the account you configured.
|
|
111
|
+
|
|
112
|
+
## What `FLASH_STANDALONE=1` does
|
|
113
|
+
|
|
114
|
+
Flash's managed deployment keeps organizations, projects, and billing in a Freesolo SaaS
|
|
115
|
+
backend, and the plane validates against it on every run. A self-hoster has no such
|
|
116
|
+
backend - without this flag the plane resolves `api.freesolo.co`, the validation call
|
|
117
|
+
fails, and **every run is rejected 503**. The flag is what makes self-hosting a supported
|
|
118
|
+
configuration rather than an unreachable one.
|
|
119
|
+
|
|
120
|
+
With it set:
|
|
121
|
+
|
|
122
|
+
- **`FREESOLO_INTERNAL_KEY` is the only credential the plane accepts.** External bearer
|
|
123
|
+
tokens are rejected, not accepted unverified - there is no backend to verify them
|
|
124
|
+
against, and treating "cannot verify" as "accept" would turn a self-hosted plane into an
|
|
125
|
+
open one.
|
|
126
|
+
- **Project ids are taken as given.** They are still required and still validated for
|
|
127
|
+
shape, so runs stay grouped; what is skipped is the ownership check against an org
|
|
128
|
+
directory that does not exist here.
|
|
129
|
+
- **Environment mirror validation is skipped.** The environment package itself is still
|
|
130
|
+
resolved and authorized normally.
|
|
131
|
+
- **Backend reporting is off** - billing precheck and charge, realized-cost
|
|
132
|
+
reconciliation, checkpoint registration, the shared RunPod slot store, and the hosted
|
|
133
|
+
artifact GC sweep. Otherwise these would send your operator key to `api.freesolo.co`
|
|
134
|
+
(and, for the GC, `serve.freesolo.co`) and log a warning per run or per startup.
|
|
135
|
+
|
|
136
|
+
> **RunPod endpoint concurrency is not capped by Flash**, on a self-hosted plane or a
|
|
137
|
+
> managed one. The slot store and the in-process semaphore behind it are both claimed from
|
|
138
|
+
> a code path the live deploy no longer uses, so neither enforces the intended 58-endpoint
|
|
139
|
+
> ceiling; `flash/providers/runpod/train/endpoints.py` documents this at the constant. If
|
|
140
|
+
> you expect many concurrent runs, cap them upstream of Flash or raise the worker quota on
|
|
141
|
+
> your RunPod account - otherwise a large enough burst hits RunPod's account limit and the
|
|
142
|
+
> excess deploys fail there.
|
|
143
|
+
|
|
144
|
+
### The security model
|
|
145
|
+
|
|
146
|
+
**A standalone plane is single-tenant.** It cannot distinguish organizations, so anyone
|
|
147
|
+
holding `FREESOLO_INTERNAL_KEY` can submit runs, read any run's status and logs, and spend
|
|
148
|
+
your GPU budget. Treat that key like a root password: generate it with
|
|
149
|
+
`openssl rand -hex 32` (or equivalent), never commit it, and rotate it if it leaks.
|
|
150
|
+
|
|
151
|
+
Rotating is safe: a standalone plane records run ownership against a fixed single-tenant
|
|
152
|
+
owner, not against the key's value, so runs started under the old key stay listed,
|
|
153
|
+
inspectable, and cancellable under the new one. The old key stops working immediately.
|
|
154
|
+
|
|
155
|
+
The same applies when you turn `FLASH_STANDALONE` on for a state directory that already
|
|
156
|
+
has runs in it: the single-tenant owner adopts them, so they stay listed and cancellable
|
|
157
|
+
rather than becoming invisible. This is safe only because standalone is single-tenant -
|
|
158
|
+
there is one principal, so every run in that store is already yours. Do not point a
|
|
159
|
+
standalone plane at the state directory of a **multi-tenant** deployment: it has no way to
|
|
160
|
+
tell whose runs those were, and it will treat all of them as the operator's.
|
|
161
|
+
|
|
162
|
+
Do not expose a standalone plane to untrusted callers. Put it on a private network, behind
|
|
163
|
+
a VPN, or behind an authenticating reverse proxy. If you need real multi-tenancy - separate
|
|
164
|
+
organizations, per-user keys, project ownership enforcement - you need an identity backend
|
|
165
|
+
serving the `/api/auth/verify` contract in `flash/server/auth.py`, and you should run
|
|
166
|
+
without `FLASH_STANDALONE` and set `FREESOLO_BASE_URL` to point at it.
|
|
167
|
+
|
|
168
|
+
## Optional pieces
|
|
169
|
+
|
|
170
|
+
| Variable | Effect if unset |
|
|
171
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
172
|
+
| `GITHUB_TOKEN` | Environments in **private** GitHub repos cannot be fetched and `flash env push` is unavailable. Environments in **public** GitHub repos still work. Warns at startup. |
|
|
173
|
+
| `FIREWORKS_API_KEY` | On-policy distillation (`opd`) runs fail inside the worker, after allocating and billing a GPU. Not covered by the startup preflight - set it before running opd. `sft` and `grpo` do not use it. |
|
|
174
|
+
| `FREESOLO_SERVING_URL` | In standalone mode `flash deploy`/`undeploy`/`chat` **refuse to run** rather than send your plane's key to Freesolo's serving app. Training is unaffected. See below. |
|
|
175
|
+
|
|
176
|
+
## Serving
|
|
177
|
+
|
|
178
|
+
`flash/serve/` is a **client** for a multi-LoRA serving app (a Modal app that serves every
|
|
179
|
+
adapter on one GPU per base model, scaling to zero when idle). This repository does not
|
|
180
|
+
include that serving backend.
|
|
181
|
+
|
|
182
|
+
Training, checkpoint streaming, and adapter export are fully self-hostable and do not
|
|
183
|
+
depend on it. Your trained adapters land in your own HuggingFace repos and can be served
|
|
184
|
+
by any stack that loads LoRA adapters - vLLM, TGI, or your own. Point `FREESOLO_SERVING_URL`
|
|
185
|
+
at a compatible deployment if you want `flash deploy` and `flash chat` to work end to end.
|
|
186
|
+
|
|
187
|
+
On a standalone plane those three commands **error out** until you set it, rather than
|
|
188
|
+
falling back to the hosted default. Every serving request carries `FREESOLO_INTERNAL_KEY`,
|
|
189
|
+
and on your plane that key is what grants full control of it - so the fallback would hand
|
|
190
|
+
your plane's credential to a service you do not operate. Export the adapter and serve it
|
|
191
|
+
yourself if you do not run a compatible backend.
|
|
192
|
+
|
|
193
|
+
The catalog reports a `serving.serve_model_id` per model - the pre-quantized FP8 checkpoint
|
|
194
|
+
Freesolo's serving app loads, and most of those repos are private. They are **informational
|
|
195
|
+
only**: nothing in the training path reads them, so they cannot block a run. If you stand up
|
|
196
|
+
your own serving backend, quantize the base model yourself (or serve it unquantized) rather
|
|
197
|
+
than expecting to pull those repo names.
|
|
198
|
+
|
|
199
|
+
## The worker image
|
|
200
|
+
|
|
201
|
+
The GPU worker image is public and pulls directly. It is published under an explicit CUDA
|
|
202
|
+
tag, not `latest`:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
docker pull ghcr.io/freesolo-co/flash-worker:cu128
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Verifying your setup
|
|
209
|
+
|
|
210
|
+
`flash-server` runs a preflight at startup and refuses to serve if it cannot run a job.
|
|
211
|
+
The rule is "enough to run a job", not "everything Freesolo runs in production":
|
|
212
|
+
configuration that only degrades an optional capability warns instead of blocking boot.
|
|
213
|
+
|
|
214
|
+
It fails on:
|
|
215
|
+
|
|
216
|
+
- no GPU provider configured (all three keys missing) - the error names every acceptable
|
|
217
|
+
way out
|
|
218
|
+
- `HF_TOKEN` missing
|
|
219
|
+
- `FREESOLO_INTERNAL_KEY` missing
|
|
220
|
+
|
|
221
|
+
It warns on a single-account RunPod pool and a missing `GITHUB_TOKEN`, then logs the
|
|
222
|
+
providers it resolved:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
GPU provider(s) configured: vast
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
That line is the quickest confirmation your credentials were picked up. Then submit a
|
|
229
|
+
small run and watch it allocate.
|
|
230
|
+
|
|
231
|
+
## Troubleshooting
|
|
232
|
+
|
|
233
|
+
**Every run is rejected 503 with "project validation is unavailable".** `FLASH_STANDALONE`
|
|
234
|
+
is not set, so the plane is trying to reach a Freesolo backend. Set it to `1`.
|
|
235
|
+
|
|
236
|
+
**`401` on every request.** In standalone mode only `FREESOLO_INTERNAL_KEY` is accepted.
|
|
237
|
+
Confirm the client is sending that exact value (`flash login --api-key ...`), with no
|
|
238
|
+
trailing newline.
|
|
239
|
+
|
|
240
|
+
**Startup says no GPU provider is configured** but you set a key. The value must be
|
|
241
|
+
non-empty and non-whitespace. For RunPod specifically, a value of `","` parses to zero
|
|
242
|
+
usable accounts.
|
|
243
|
+
|
|
244
|
+
**Runs fail to allocate on a class you expected.** The allocator only proposes classes on
|
|
245
|
+
configured providers. Check the `GPU provider(s) configured:` startup line.
|
|
@@ -230,7 +230,14 @@ def _is_safe_github_path_parts(parts: list[str] | tuple[str, ...]) -> bool:
|
|
|
230
230
|
|
|
231
231
|
|
|
232
232
|
def _github_token() -> str | None:
|
|
233
|
-
|
|
233
|
+
"""The GitHub token, or ``None`` when unset OR blank.
|
|
234
|
+
|
|
235
|
+
Blank must collapse to ``None``, not fall through as a truthy string: a whitespace-only
|
|
236
|
+
GITHUB_TOKEN would otherwise build ``Authorization: Bearer <whitespace>``, and GitHub REJECTS a
|
|
237
|
+
malformed credential rather than treating the request as anonymous - so a public repo that
|
|
238
|
+
loads fine with no token at all would fail with one that is merely blank.
|
|
239
|
+
"""
|
|
240
|
+
return (os.environ.get("GITHUB_TOKEN") or "").strip() or None
|
|
234
241
|
|
|
235
242
|
|
|
236
243
|
def _is_commit_sha(value: str) -> bool:
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Shared operator-credential helpers for the GPU providers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def load_provider_key(env_var: str) -> str | None:
|
|
9
|
+
"""Provider API key from ``env_var`` (operator configuration), or None when unset OR blank.
|
|
10
|
+
|
|
11
|
+
Whitespace-stripped, and a whitespace-only value reads as unset. This is the single point
|
|
12
|
+
every instance provider loads its key through, so ``is_configured()``, the startup preflight
|
|
13
|
+
and the outbound API calls all agree about what "configured" means. Without the strip, a key
|
|
14
|
+
that is only whitespace (a stray newline in an env file) makes the provider advertise itself,
|
|
15
|
+
the preflight pass on it as the plane's only substrate, and every allocation then fail on an
|
|
16
|
+
unusable credential. Matches how the RunPod key pool and ``internal_key()`` normalize.
|
|
17
|
+
"""
|
|
18
|
+
return (os.environ.get(env_var) or "").strip() or None
|