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.
Files changed (399) hide show
  1. freesolo_flash_dev-1.0.73/.env.example +97 -0
  2. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/CONTRIBUTING.md +7 -0
  3. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/PKG-INFO +45 -46
  4. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/README.md +44 -45
  5. freesolo_flash_dev-1.0.73/SELF_HOSTING.md +245 -0
  6. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/loader.py +8 -1
  7. freesolo_flash_dev-1.0.73/flash/providers/_auth.py +18 -0
  8. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_worker.py +7 -2
  9. freesolo_flash_dev-1.0.73/flash/providers/preflight.py +162 -0
  10. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/__init__.py +10 -2
  11. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/slots.py +9 -2
  12. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/weight_cache_preload.py +22 -6
  13. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/__init__.py +47 -10
  14. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/lifecycle.py +31 -16
  15. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/deploy.py +37 -5
  16. freesolo_flash_dev-1.0.73/flash/serve/urls.py +53 -0
  17. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/_internal_client.py +10 -2
  18. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/_runtime.py +1 -1
  19. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/app.py +1 -1
  20. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/auth.py +37 -2
  21. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/billing_retry.py +8 -4
  22. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/db.py +70 -0
  23. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/environment_registry.py +6 -0
  24. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/envs.py +7 -1
  25. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/projects.py +8 -1
  26. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/reconcile.py +9 -5
  27. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/repo_cleanup.py +26 -12
  28. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/pyproject.toml +2 -2
  29. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/scripts/scrub_history.sh +94 -5
  30. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/conftest.py +23 -1
  31. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cancel_remote.py +7 -0
  32. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_jobs.py +16 -10
  33. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_opd_resume_safety.py +14 -2
  34. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_orchestrator_flash.py +1 -1
  35. freesolo_flash_dev-1.0.73/tests/test_preflight.py +246 -0
  36. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_projects.py +48 -0
  37. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_repo_cleanup.py +1 -1
  38. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runmgmt.py +44 -7
  39. freesolo_flash_dev-1.0.73/tests/test_server_standalone.py +728 -0
  40. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_warmstart_cross_repo.py +3 -1
  41. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_weight_cache.py +33 -1
  42. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/uv.lock +1 -1
  43. freesolo_flash_dev-1.0.72/.env.example +0 -58
  44. freesolo_flash_dev-1.0.72/flash/providers/_auth.py +0 -10
  45. freesolo_flash_dev-1.0.72/flash/providers/preflight.py +0 -65
  46. freesolo_flash_dev-1.0.72/flash/serve/urls.py +0 -26
  47. freesolo_flash_dev-1.0.72/tests/test_preflight.py +0 -173
  48. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.dockerignore +0 -0
  49. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  50. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  51. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  52. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  53. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/dependabot.yml +0 -0
  54. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/auto-rebake.yml +0 -0
  55. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/bake-kernel-cache.yml +0 -0
  56. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/ci.yml +0 -0
  57. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/main-source-guard.yml +0 -0
  58. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/notify-tests-repo.yml +0 -0
  59. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/publish-dev.yml +0 -0
  60. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/publish-image.yml +0 -0
  61. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/publish.yml +0 -0
  62. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/version-parity.yml +0 -0
  63. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.github/workflows/worker-image.yml +0 -0
  64. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/.gitignore +0 -0
  65. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/CODE_OF_CONDUCT.md +0 -0
  66. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/Dockerfile +0 -0
  67. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/Dockerfile.worker +0 -0
  68. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/LICENSE +0 -0
  69. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/NOTICE +0 -0
  70. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/SECURITY.md +0 -0
  71. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/build/kernel_cache/.gitignore +0 -0
  72. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/build/kernel_cache/.keep +0 -0
  73. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/Dockerfile.kernelcache +0 -0
  74. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/Dockerfile.kernelcache.relayer +0 -0
  75. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/bake_kernel_cache.py +0 -0
  76. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/bake_pod_entry.py +0 -0
  77. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/kernel_fingerprint.py +0 -0
  78. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/docker/make_rp_handler.py +0 -0
  79. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/__init__.py +0 -0
  80. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/_channel.py +0 -0
  81. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/_fileio.py +0 -0
  82. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/_logging.py +0 -0
  83. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/_update_check.py +0 -0
  84. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/adapter_artifacts.py +0 -0
  85. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/catalog.py +0 -0
  86. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/TRAINING.md +0 -0
  87. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/__init__.py +0 -0
  88. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/__main__.py +0 -0
  89. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/_tty.py +0 -0
  90. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/commands.py +0 -0
  91. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/env_eval.py +0 -0
  92. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/env_setup.py +0 -0
  93. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/env_test.py +0 -0
  94. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/envpush.py +0 -0
  95. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/render.py +0 -0
  96. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/traces.py +0 -0
  97. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cli/training_doc.py +0 -0
  98. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/__init__.py +0 -0
  99. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/config.py +0 -0
  100. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/http.py +0 -0
  101. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/runtime_secrets.py +0 -0
  102. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/client/specs.py +0 -0
  103. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/__init__.py +0 -0
  104. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/analytical.py +0 -0
  105. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/facts.py +0 -0
  106. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/spec.py +0 -0
  107. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/cost/types.py +0 -0
  108. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/diagnostics.py +0 -0
  109. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/__init__.py +0 -0
  110. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/accounting.py +0 -0
  111. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/multiturn_reward_scoring.py +0 -0
  112. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/recipe.py +0 -0
  113. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/reward_profile.py +0 -0
  114. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/steps.py +0 -0
  115. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/structured_outputs.py +0 -0
  116. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/vram.py +0 -0
  117. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/__init__.py +0 -0
  118. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/__main__.py +0 -0
  119. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/_pkg.py +0 -0
  120. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/adapter.py +0 -0
  121. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/backend_common.py +0 -0
  122. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/decoding.py +0 -0
  123. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/finalize.py +0 -0
  124. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/grpo.py +0 -0
  125. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/grpo_multiturn.py +0 -0
  126. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/grpo_plugin.py +0 -0
  127. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/heartbeat.py +0 -0
  128. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/hf.py +0 -0
  129. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/kernel_warmup.py +0 -0
  130. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/lora.py +0 -0
  131. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/multiturn_glue.py +0 -0
  132. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd.py +0 -0
  133. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_gkd.py +0 -0
  134. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_multiturn.py +0 -0
  135. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_plugin.py +0 -0
  136. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_structured.py +0 -0
  137. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/opd_train.py +0 -0
  138. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/packing.py +0 -0
  139. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/__init__.py +0 -0
  140. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/attn.py +0 -0
  141. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/diagnostics.py +0 -0
  142. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/lifecycle.py +0 -0
  143. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/liger.py +0 -0
  144. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/loraplus.py +0 -0
  145. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/perf/memory.py +0 -0
  146. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/rl.py +0 -0
  147. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/rl_train.py +0 -0
  148. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/rng.py +0 -0
  149. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/rollout_samples.py +0 -0
  150. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/sft.py +0 -0
  151. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/sft_train.py +0 -0
  152. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/teacher.py +0 -0
  153. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/tokenizer_align.py +0 -0
  154. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker/wandb_log.py +0 -0
  155. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/engine/worker_entrypoint.py +0 -0
  156. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/__init__.py +0 -0
  157. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/adapter.py +0 -0
  158. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/archive.py +0 -0
  159. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/archive_policy.py +0 -0
  160. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/base.py +0 -0
  161. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/evaluations.py +0 -0
  162. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/pull.py +0 -0
  163. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/envs/registry.py +0 -0
  164. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/lora_rank.py +0 -0
  165. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/multimodal.py +0 -0
  166. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/opd_retry_contract.py +0 -0
  167. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/opd_validation.py +0 -0
  168. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/__init__.py +0 -0
  169. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_deadline.py +0 -0
  170. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_hf_artifacts.py +0 -0
  171. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_hf_retry.py +0 -0
  172. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_http.py +0 -0
  173. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_instance.py +0 -0
  174. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_instance_bootstrap.py +0 -0
  175. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_instance_poll.py +0 -0
  176. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_instance_provider.py +0 -0
  177. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/_poll.py +0 -0
  178. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/allocator.py +0 -0
  179. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/base.py +0 -0
  180. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/__init__.py +0 -0
  181. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/api.py +0 -0
  182. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/auth.py +0 -0
  183. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/gpus.py +0 -0
  184. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
  185. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/jobs/builders.py +0 -0
  186. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/preflight.py +0 -0
  187. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/lambdalabs/pricing.py +0 -0
  188. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/realized.py +0 -0
  189. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/api.py +0 -0
  190. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/auth.py +0 -0
  191. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/cost.py +0 -0
  192. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/gpus.py +0 -0
  193. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/jobs.py +0 -0
  194. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/keys.py +0 -0
  195. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/preflight.py +0 -0
  196. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/pricing.py +0 -0
  197. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/train/__init__.py +0 -0
  198. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/runpod/train/endpoints.py +0 -0
  199. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/__init__.py +0 -0
  200. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/api.py +0 -0
  201. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/auth.py +0 -0
  202. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/jobs/__init__.py +0 -0
  203. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/jobs/builders.py +0 -0
  204. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/preflight.py +0 -0
  205. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/providers/vast/pricing.py +0 -0
  206. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/py.typed +0 -0
  207. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/checkpoints.py +0 -0
  208. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/deploy.py +0 -0
  209. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/runner/verified_revisions.py +0 -0
  210. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/schema/__init__.py +0 -0
  211. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/schema/fields.py +0 -0
  212. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/__init__.py +0 -0
  213. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/export.py +0 -0
  214. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/preflight.py +0 -0
  215. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/serve/pricing.py +0 -0
  216. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/__init__.py +0 -0
  217. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/__main__.py +0 -0
  218. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/_deps.py +0 -0
  219. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/_locks.py +0 -0
  220. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/billing.py +0 -0
  221. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/checkpoints.py +0 -0
  222. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/__init__.py +0 -0
  223. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/envs.py +0 -0
  224. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/meta.py +0 -0
  225. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/runs.py +0 -0
  226. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/routes/serving.py +0 -0
  227. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/server/run_registry.py +0 -0
  228. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/spec.py +0 -0
  229. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/flash/thinking.py +0 -0
  230. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/infisical-entrypoint.sh +0 -0
  231. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/scripts/build_dev_dist.py +0 -0
  232. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/__init__.py +0 -0
  233. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/_helpers/__init__.py +0 -0
  234. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/_helpers/runner.py +0 -0
  235. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/_helpers/specs.py +0 -0
  236. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/_helpers/vast.py +0 -0
  237. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/fixtures/math_eval.jsonl +0 -0
  238. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/fixtures/math_train.jsonl +0 -0
  239. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/__init__.py +0 -0
  240. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/conftest.py +0 -0
  241. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/test_lambda_live.py +0 -0
  242. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/test_runpod_live.py +0 -0
  243. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/live/test_vast_live.py +0 -0
  244. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_accounting_coverage.py +0 -0
  245. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_agent_flash_cli_contract.py +0 -0
  246. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_algorithms.py +0 -0
  247. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_allocator.py +0 -0
  248. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_async_uploads.py +0 -0
  249. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_backend_common.py +0 -0
  250. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_backend_jobspec_contract.py +0 -0
  251. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_base_model_provenance.py +0 -0
  252. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_billing_retry.py +0 -0
  253. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_catalog_consistency.py +0 -0
  254. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_charge_pricing.py +0 -0
  255. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_checkpoints.py +0 -0
  256. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_commands.py +0 -0
  257. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_commands_coverage.py +0 -0
  258. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_credential_shadowing.py +0 -0
  259. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_errors.py +0 -0
  260. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_estimate.py +0 -0
  261. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_gpus_flag.py +0 -0
  262. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_help.py +0 -0
  263. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_main_coverage.py +0 -0
  264. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_managed.py +0 -0
  265. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_render_coverage.py +0 -0
  266. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_render_theme.py +0 -0
  267. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_traces.py +0 -0
  268. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cli_wandb_warning.py +0 -0
  269. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_client.py +0 -0
  270. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_client_server_integration.py +0 -0
  271. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_client_stream_reads.py +0 -0
  272. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_config_overrides.py +0 -0
  273. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_controlled_experiment_repairs.py +0 -0
  274. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_analytical.py +0 -0
  275. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_equation.py +0 -0
  276. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_estimate.py +0 -0
  277. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_hardware.py +0 -0
  278. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_models.py +0 -0
  279. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_cost_rewards.py +0 -0
  280. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_deploy_latency.py +0 -0
  281. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_dev_channel.py +0 -0
  282. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_disk_gb.py +0 -0
  283. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_endpoint_name.py +0 -0
  284. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_cache_evict.py +0 -0
  285. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_delete.py +0 -0
  286. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_download.py +0 -0
  287. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_download_api.py +0 -0
  288. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_evaluations.py +0 -0
  289. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_no_install.py +0 -0
  290. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_publish.py +0 -0
  291. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_pull.py +0 -0
  292. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_pull_coverage.py +0 -0
  293. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_pull_loader_coverage.py +0 -0
  294. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_pull_managed_control_plane.py +0 -0
  295. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_push.py +0 -0
  296. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_rate_limit_resolve.py +0 -0
  297. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_ref_pinning.py +0 -0
  298. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_env_test.py +0 -0
  299. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_envs_coverage.py +0 -0
  300. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_export.py +0 -0
  301. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_flash_mvp.py +0 -0
  302. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_flash_worker.py +0 -0
  303. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_flashinfer_cache_dirs.py +0 -0
  304. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_github_urlopen_retry.py +0 -0
  305. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_gpu_type_single_field.py +0 -0
  306. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_gpus.py +0 -0
  307. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_grpo_mask_aware.py +0 -0
  308. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_grpo_params.py +0 -0
  309. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_grpo_resident_sizing.py +0 -0
  310. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_health_liveness.py +0 -0
  311. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_hf_retry.py +0 -0
  312. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_idle_endpoint_reaper.py +0 -0
  313. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_instance_bootstrap_coverage.py +0 -0
  314. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_internal_client.py +0 -0
  315. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_kernel_cache.py +0 -0
  316. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_kernel_fingerprint.py +0 -0
  317. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_kv_util.py +0 -0
  318. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_lambda_api_coverage.py +0 -0
  319. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_lambda_runner.py +0 -0
  320. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_logging.py +0 -0
  321. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_login_perms.py +0 -0
  322. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_lora_rank_coverage.py +0 -0
  323. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_lora_rank_preflight.py +0 -0
  324. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_managed_config_fields.py +0 -0
  325. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_managed_hf_repo.py +0 -0
  326. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_metrics_schema_agent_contract.py +0 -0
  327. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_mig_guard.py +0 -0
  328. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_multi_gpu_gate.py +0 -0
  329. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_multimodal_input_grads.py +0 -0
  330. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_multimodal_training.py +0 -0
  331. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_named_reward_metrics.py +0 -0
  332. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_oom_escalate_gpu.py +0 -0
  333. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_opd.py +0 -0
  334. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_opd_train.py +0 -0
  335. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_open_model_policy.py +0 -0
  336. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_packing.py +0 -0
  337. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_packing_coverage.py +0 -0
  338. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_poll_helpers.py +0 -0
  339. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_provider_preflight_coverage.py +0 -0
  340. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_provider_routing.py +0 -0
  341. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_provider_teardown_robustness.py +0 -0
  342. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_providers_symmetry.py +0 -0
  343. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_realized_cost.py +0 -0
  344. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_resolve_params_b.py +0 -0
  345. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_resume_on_retry.py +0 -0
  346. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_reward_profile.py +0 -0
  347. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_rl_train.py +0 -0
  348. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_rollout_samples.py +0 -0
  349. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runpod_api_delete.py +0 -0
  350. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runpod_key_fingerprint.py +0 -0
  351. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runpod_key_waterfall.py +0 -0
  352. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_runpod_slots.py +0 -0
  353. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serve.py +0 -0
  354. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serve_reasoning_content.py +0 -0
  355. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_api.py +0 -0
  356. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_app_coverage.py +0 -0
  357. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_auth_singleflight.py +0 -0
  358. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_billing.py +0 -0
  359. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_checkpoints_coverage.py +0 -0
  360. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_db.py +0 -0
  361. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_envs_coverage.py +0 -0
  362. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_server_locks_coverage.py +0 -0
  363. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serving_context_preflight.py +0 -0
  364. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serving_contract.py +0 -0
  365. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serving_pricing_coverage.py +0 -0
  366. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_serving_schema_coverage.py +0 -0
  367. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_chunked_nll.py +0 -0
  368. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_example_selection.py +0 -0
  369. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_gc_off.py +0 -0
  370. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_max_context.py +0 -0
  371. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_sft_train.py +0 -0
  372. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_spec_and_validation.py +0 -0
  373. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_step_metrics.py +0 -0
  374. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_structured_outputs.py +0 -0
  375. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_thinking_config.py +0 -0
  376. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_train_context_preflight.py +0 -0
  377. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_training_controls.py +0 -0
  378. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_update_check.py +0 -0
  379. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_api.py +0 -0
  380. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_api_coverage.py +0 -0
  381. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_offers.py +0 -0
  382. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_provider_coverage.py +0 -0
  383. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vast_runner.py +0 -0
  384. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_verified_revisions.py +0 -0
  385. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_verifiers.py +0 -0
  386. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_version.py +0 -0
  387. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vl_warmstart_adapter_keys.py +0 -0
  388. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_vram_architecture.py +0 -0
  389. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_wandb_link.py +0 -0
  390. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_wandb_log_coverage.py +0 -0
  391. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_wandb_naming.py +0 -0
  392. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_warmstart_adapter_download.py +0 -0
  393. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_warmstart_error_attribution.py +0 -0
  394. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_dryrun.py +0 -0
  395. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_hardexit.py +0 -0
  396. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_image.py +0 -0
  397. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_init_heartbeat.py +0 -0
  398. {freesolo_flash_dev-1.0.72 → freesolo_flash_dev-1.0.73}/tests/test_worker_stack.py +0 -0
  399. {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.72
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
- It does **not** contain everything needed to stand up an equivalent service from scratch.
91
- The following are Freesolo-operated and not part of this repository:
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
- | Component | Where it lives |
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
- If you are evaluating Flash, the honest summary is: **use it against the hosted service**,
100
- or **read and modify the training/provider code**, which is self-contained and the most
101
- reusable part of the repository. Running your own end-to-end copy of the service is
102
- possible but requires replacing the components above — see [Self-hosting](#self-hosting).
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, but read this first — it is an operator deployment,
246
- not a one-command install.
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
- `flash-server` then fails fast at startup unless all of the following are present (see
256
- `flash/providers/preflight.py` and `.env.example`). Note it reads the PROCESS
257
- environment, so load your `.env` (`set -a && . ./.env && set +a`) rather than relying on
258
- the file being present:
259
-
260
- - `RUNPOD_API_KEY` — **two or more distinct** RunPod account keys, comma-separated. A
261
- single-account pool cannot reap or fail over across accounts, so the preflight rejects
262
- it.
263
- - `LAMBDA_API_KEY` — Lambda Cloud API key.
264
- - `HF_TOKEN` — write access to the dataset repos flash creates for artifacts. The repo is
265
- assigned by the control plane and scoped to the environment, so runs sharing an
266
- environment share a repo, each under its own prefix.
267
- - `FREESOLO_INTERNAL_KEY` — control-plane authentication. Requests presenting this key
268
- authenticate as a single service identity with no network call, which is the path to use
269
- if you are not integrating with Freesolo identity.
270
- - `GITHUB_TOKEN` — access to the managed environment repository.
271
-
272
- Beyond credentials, three seams point at Freesolo services and would need replacing for a
273
- fully independent deployment:
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
- It does **not** contain everything needed to stand up an equivalent service from scratch.
32
- The following are Freesolo-operated and not part of this repository:
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
- | Component | Where it lives |
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
- If you are evaluating Flash, the honest summary is: **use it against the hosted service**,
41
- or **read and modify the training/provider code**, which is self-contained and the most
42
- reusable part of the repository. Running your own end-to-end copy of the service is
43
- possible but requires replacing the components above — see [Self-hosting](#self-hosting).
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, but read this first — it is an operator deployment,
187
- not a one-command install.
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
- `flash-server` then fails fast at startup unless all of the following are present (see
197
- `flash/providers/preflight.py` and `.env.example`). Note it reads the PROCESS
198
- environment, so load your `.env` (`set -a && . ./.env && set +a`) rather than relying on
199
- the file being present:
200
-
201
- - `RUNPOD_API_KEY` — **two or more distinct** RunPod account keys, comma-separated. A
202
- single-account pool cannot reap or fail over across accounts, so the preflight rejects
203
- it.
204
- - `LAMBDA_API_KEY` — Lambda Cloud API key.
205
- - `HF_TOKEN` — write access to the dataset repos flash creates for artifacts. The repo is
206
- assigned by the control plane and scoped to the environment, so runs sharing an
207
- environment share a repo, each under its own prefix.
208
- - `FREESOLO_INTERNAL_KEY` — control-plane authentication. Requests presenting this key
209
- authenticate as a single service identity with no network call, which is the path to use
210
- if you are not integrating with Freesolo identity.
211
- - `GITHUB_TOKEN` — access to the managed environment repository.
212
-
213
- Beyond credentials, three seams point at Freesolo services and would need replacing for a
214
- fully independent deployment:
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
- return os.environ.get("GITHUB_TOKEN")
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